Drupal 7 - Taxonomy terms hierarchy hook function - drupal

As you know there is an admin page for setting up hierarchy of terms by dragging it, which can be found on admin/structure/taxonomy/your_vocabulary. Underneath the table there are two buttons "Save" and "Reset to alphabetical". Now I need to interact with those sumbits by using some hook but I've no idea how to do it. I've already tried hook_taxonomy_term_presave() and hook_taxonomy_term_update(), but those are definitely not appropriate. Any ideas how to hook it?

You can do all your stuff by adding additional callback in submit.
e.g:
/**
* Implements hook_form_FORM_ID_alter().
*/
function hook_form_taxonomy_form_vocabulary_alter(&$form) {
$form['#submit'][] = 'my_function';
}
function my_function(&$form, &$form_state) {
// Do something ..
}

Related

How I can print all variable of a hook in drupal 8?

I'm very new in Drupal 8 and I have issue now with hook. Mainly I though that I don't clearly understand structure and hook definition in Drupal 8.
So my main problem is that I have some hook to interact with main menu (add custom class name to ul, li and link, a tag). I can do it by changing template file and now try to do it with any hook.
Although I found that some hook relating to menu ex. hook_contextual_links_alter (link: https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Menu%21menu.api.php/function/hook_contextual_links_alter/8.9.x).
At the end of this hook we have the code related:
function hook_contextual_links_alter(array &$links, $group, array $route_parameters) {
if ($group == 'menu') {
// Dynamically use the menu name for the title of the menu_edit contextual
// link.
$menu = \Drupal::entityTypeManager()
->getStorage('menu')
->load($route_parameters['menu']);
$links['menu_edit']['title'] = t('Edit menu: #label', [
'#label' => $menu
->label(),
]);
}
}
So I have installed devel module with kint function and in my .theme file and try:
function hook_contextual_links_alter(array &$links, $group, array $route_parameters) {
kint($links);
}
and then reload my Home page but nothing showed. But I can get some information about other like:
function eg_learn_theme_suggestions_page_alter(&$suggestions, $variables) {
kint($suggestions);
}
So what happens here? Can you help to explain if how I can print the variable of this hook (in .theme file) and the site page to see the printing variable?
In general when I found a hook, how I can print there array and check it in website?
There are some problems about your approach:
When implementing a hook, you must replace "hook" with the module name/theme name where you put the hook function inside. For example, if you want implement hook_contextual_links_alter in your_custom module, it becomes your_custom_contextual_links_alter().
Not all hook can be implemented in the theme. Some hook can only be implemented in modules (in .module file). You can read more here.
In your case, I think hook_preprocess_menu would be more suitable. You can implement it in your custom theme like this:
function <your_theme_name>_preprocess_menu(&$variables) {
if ($variables['menu_name'] == 'main') {
kint($variables);
}
}

Silverstripe 4 - Adding a FormAction via getCMSFields

Goal:
I have a DataObject called "Event". This is in a managed_model for "EventsAdmin" (extending ModelAdmin). When editing an Event, I want a tab on the record called "Moderation" that has a few fields and two buttons: "Approve" and "Reject". These two buttons call an action each that performs relevant actions.
Event extends DataObject
public function getCMSFields() {
$fields = parent::getCMSFields();
$eventStatus = $fields->dataFieldByName("EventStatus")
->setTitle('Current Status')
->setDisabled(true);
$approveButton = FormAction::create('doApproveEvent', _t('SiteBlockAdmin.Approve', 'Approve'))
->setUseButtonTag(true)
->addExtraClass('btn-outline-success font-icon-check-mark-circle');
$rejectButton = FormAction::create('doRejectEvent', _t('SiteBlockAdmin.Reject', 'Reject'))
->setUseButtonTag(true)
->addExtraClass('btn-outline-danger font-icon-cancel-circled');
$fields->addFieldsToTab('Root.Moderation', [
$eventStatus,
$approveButton,
$rejectButton
]);
return $fields;
}
This displays the buttons just fine. But they don't do anything. So I am trying to work out how they can plug into action methods doApproveEvent and doRejectEvent (And where they should go)
I did find docs that led me to adding the buttons to the action bar at the bottom of the CMS page via updateFormActions(). But this isn't what I want as the other fields I am adding above the buttons are part of the Approve/Reject process. Here is the code for this method. This works fine barring the buttons are not in a logical place for the process I'm trying to create.
class CMSActionButtonExtension extends DataExtension
{
public function updateFormActions(FieldList $actions)
{
$record = $this->owner->getRecord();
if (!$record instanceof Event || !$record->exists()) {
return;
}
$approveButton = FormAction::create('doApproveEvent', _t('SiteBlockAdmin.Approve', 'Approve'))
->setUseButtonTag(true)
->addExtraClass('btn-outline-success font-icon-check-mark-circle');
$rejectButton = FormAction::create('doRejectEvent', _t('SiteBlockAdmin.Reject', 'Reject'))
->setUseButtonTag(true)
->addExtraClass('btn-outline-danger font-icon-cancel-circled');
$actions->push($approveButton);
$actions->push($rejectButton);
}
public function doApproveEvent($data, $form) {
$record = $this->owner->getRecord();
// Approve logic
}
public function doRejectEvent($data, $form) {
$record = $this->owner->getRecord();
// Reject logic
}
}
The above Extension is attached to GridFieldDetailForm_ItemRequest
extension.yml
SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest:
extensions:
- My\Namespace\CMSActionButtonExtension
Interestingly, if I have both sets of buttons on the page at the same time, the updateFormActions option works while my desired option still doesn't. Despite the buttons being of identical markup and sitting inside the exact same form tag. I assume that has something to do with how Silverstripe loads the main content panel and the DOM.
Any thoughts on achieving this? Anyone seen a button added to the main CMS panel in a module that I could take a look at? I found this post from 5 years ago, but it's for SS3 and the answer doesn't work for me.
Short answer:
you have to add custom FormActions through an Extension on the Controller that controls the form (or on the form itself
Long Answer:
A bit of background on how SilverStripe does forms:
Generally speaking, forms are always served through Controllers/RequestHandlers (they need to be accessible on some route, usually that's an Action on a Controller that is often named Form, EditForm, ItemEditoForm, ...).
Fields
Inside the CMS you rarely ever have to create your own form, that's done by the CMSs built in Controllers/RequestHandlers for the admin area (GridFieldDetailForm_ItemRequest in this case).
Basically (pseudo code here), what those controllers do is:
public function EditForm() {
$fields = $myCurrentlyEditingDataObject->getCMSFields();
$actions = ...;
$validator = ...;
$this->updateFormActions(&$actions);
$form = new Form('ItemRequestForm', $fields, $actions, $validator);
$this->updateItemEditForm(&$form); // or $this->updateEditForm()
return $form;
}
So, getCMSFields() and in some cases getCMSActions()/getCMSValidator() (not sure if those 2 are still used in SilverStripe 4.x), you can add things to the form, without ever seeing the form object.
Also, the getCMSFields() will always be put into the ``` section of the Form, that's why your button is somewhere in the middle with all the fields and not with the other actions.
Submission
When a form is submitted (eg to /admin/pages/edit/EditForm/265/field/NameOfMyGridField/item/542/ItemEditForm), it will call the action GridFieldDetailForm_ItemRequest->ItemEditForm() which returns the Form object where subsequently FormRequestHandler->httpSubmission() is called. This will then look at the submitted data to figure out what action was clicked (eg $_REQUEST['action_doApproveEvent']) and try to find that action.
The way it tries to find that, is checking if it itself has a method called doApproveEvent, if that fails, it will try Form->getController()->doApproveEvent() or something like that. In the case of a GridField, that controller is GridFieldDetailForm_ItemRequest which means it will try to call GridFieldDetailForm_ItemRequest->doApproveEvent()
So, that means DataObject->getCMSFields() lets you easily add FormFields (and FormActions) into your form body.
But it does not provide a means of adding a method to handle the submission.
That's why, for custom actions you need to modify the Controller (GridFieldDetailForm_ItemRequest in this case).
You are doing this by creating a Extension which you attached to GridFieldDetailForm_ItemRequest.
Any method in your Extension is added to the thing it's attached to, so if you add a method called updateFormActions, it will kind of become GridFieldDetailForm_ItemRequest->updateFormActions().
And if you recall from earlier, the controller will call $this->updateFormActions() during the creation of the form.
Additionally, as I explained earlier, when a FormAction is named doApproveEvent it will look for a GridFieldDetailForm_ItemRequest->doApproveEvent(), which now exists because you added it through that Extension.
So, in summary: you have to add custom FormActions through an Extension on the Controller that controls the form (or on the form itself
PS: the old post from
bummzack you linked to worked in 3.x, because the Controller in his example that created the form was an instance of LeftAndMain.

what is difference between action hook and filter hook in wordpress?

I read the action hook is use for call the functions and filter hook is use for filtering the content before save or display on website. Can you tell me the some working phases of project example where we use action and filter hook. So it will better to understand more.
Action: Doing new things. Ex. adding CSS and JS.
Filter: Doing something which is already in WordPress. Adding or removing some things. Assume adding some text after post content. It means doing something with WordPress.
Example code:
add_action('admin_menu','my_func',8,2);
function my_func($one, $two){
//Something here …
}
In short:
Filter Hook: used to modify (filter) a value
Action Hook: do something, right at this moment
Filter Hook Example:
$name = "Smith";
$gender = "female";
echo apply_filter('form_of_address', $name, $gender );
// somewhere else
add_filter( 'form_of_address', function( $name, $gender ) {
if ( "female" == $gender ) {
$name = "Mrs. " . $name;
} else if ( "male" == $gender ) {
$name = "Mr. " . $name;
}
return $name
}, 10, 2 );
You want to know what the difference is between an action and filter event (hook).
Let's start with understanding what a hook or event is in WordPress.
What is a Hook (Event)?
Through the Plugin API, WordPress provides us with the means to run our code when events happen.
Programs run in a specific order from top to bottom. Line 1 runs and then line 2 and so on. As WordPress loads in files, each of those run and so on.
As the web page request is processed, WordPress Core is running the lines of code and doing stuff. But what if you need to run your code at a certain point in the request cycle? For example, let's say you want to change the post's byline from the default of the theme. Using a filter event (hook), you gain:
access to the actual value or HTML before it's sent out to the browser
the ability to change that value or HTML
the ability to run other code at a specific point in the web page request cycle.
Why are there hooks (events)?
WordPress runs out of the box without our custom themes or plugins. But the Plugin API gives you and I as well as all developers the means to customize, change the default behavior, and extend WordPress.
It lets us run our code when we need to, i.e. at specific points in the web page request cycle.
Pre-registration
For our code to run, we need to pre-register our callback, which is the function or method that we want to run at that specific point. You use add_action() to pre-register an action event callback. You use add_filter() to pre-register a filter event callback.
When you pre-register your callback, it's being added into a registration lookup table, which is an array.
Then when the event fires, your callback and all the others are called in order. You set the order using the priority parameter. The argument(s) are passed to your callback. Then your method or function runs.
Here's a video that explains the big picture of this process and the why of it.
Action vs. Filter
A filter event (hook) allows you to filter the return value. It gives you (and all the other registered callbacks) the ability to filter, which means change the value.
Think about that. Let's say you want to change the "read more" link. Maybe you want it to say "Continue reading" and maybe you want it to be a button instead of a just a hyperlink. The filter allows you:
to receive the current value
change it to what you want
send it back by returning it
That new value is then passed along to all the other registered callbacks and then eventually returned to the line of code that fired the event.
Action Event
The action event (hook) is the same as a filter except that the value is not returned.
The event is fired, such as init or plugins_loaded. The pre-registered callbacks are called in order and any arguments are passed to each one. Your function or method is called. You can run your code.
It gives you the means to do something at a specific point in the web page request cycle.
Wrap it Up
Think about the power of the event management system. If you need to run something say right after all of the plugins have loaded, you pre-register to the plugins_loaded event name. When Core fires the event by doing do_action( 'plugins_loaded' );, your code will run too.
Filter and Action events (hooks) let you run your code at a specific point in the web page request cycle.
The Difference
Filter events (hooks) let you filter or change the value before it's processed. Action events do not let filter.
How do you fire an event?
For action events, you can use do_action( 'event_name' ) or do_action_ref_array( 'event_name', $args ).
For filter events, you can use apply_filters( 'event_name', $value_to_filter ) or apply_filters( 'event_name', $args );
Examples
Let's say you want to add a styling class attribute to the post. You can pre-register to the post_class event name. You'll receive an array of classes.
add_filter( 'post_class', 'add_my_class_attribute_to_post_class' );
/**
* Add styling class to the post class.
*
* #since 1.0.0
*
* #param array $classes
*
* #return array
*/
function add_my_class_attribute_to_post_class( array $classes ) {
$classes[] = 'some-class-attribute';
return $classes;
}
What if you wanted to add a styling class to the front page's body.
add_filter( 'body_class', 'add_front_page_to_body_class' );
/**
* Add the class attribute "front-page" to the body classes.
*
* #since 1.0.0
*
* #param array $classes
*
* #return array
*/
function add_front_page_to_body_class( array $classes ) {
$classes[] = 'front-page';
return $classes;
}
Notice how you're changing the value and then returning it back.

After submit action in form_alter

i need to insert data in my tables after user creation. I think to use hook_form_alter() for $form_id == "user_register" but I don't know how to say "after you created user, do this."
How can I do it in hook_form_alter()?
You can add custom submit handler to forms like this.
function hook_form_user_register_alter(&$form, &$form_state) {
// ...
$form['#submit'][] = 'yourModule_user_register_submit';
}
function yourModule_user_register_submit($form, &$form_state) {
// do what you want to do after registration
}
I'd also recommend to use Drupal's Triggers & Actions to achieve this. AFAIK there was a bug with one of the triggers that fire after user registration. Don't know if that has been fixed.

remove "profile" admin-menu from administrative panel

I am using WordPress, and I want to remove "profile" menu-option completely
Any one is having idea how can I achieve this?
Thanks
For the sake of completeness, here's how to do it programmatically...
// Run the function on admin_init
add_action('admin_init', 'remove_profile_menu');
// Removal function
function remove_profile_menu() {
global $wp_roles;
// Remove the menu. Syntax is `remove_submenu_page($menu_slug, $submenu_slug)`
remove_submenu_page('users.php', 'profile.php');
/* Remove the capability altogether. Syntax is `remove_cap($role, $capability)`
* 'Read' is the only capability subscriber has by default, and allows access
* to the Dashboard and Profile page. You can also remove from a specific user
* like this:
* $user = new WP_User(null, $username);
* $user->remove_cap($capability);
*/
$wp_roles->remove_cap('subscriber', 'read');
}
I know this is late but I just stumbled on this and thought I would add to it. That does remove the sub-menu profile menu item but does not remove the menu profile item. For someone like me who has created a completely custom profile page, I don't want my users to access the profile.php page at all. So this code will work for that:
function remove_profile_menu() {
remove_submenu_page('users.php', 'profile.php');
remove_menu_page('profile.php');
}
add_action('admin_menu', 'remove_profile_menu');
And if you only want to do this for certain capabilities....use this code:
function remove_profile_menu() {
// Only the Admin can see the profile menu
if(!current_user_can('update_core')) {
remove_submenu_page('users.php', 'profile.php');
remove_menu_page('profile.php');
}
}
add_action('admin_menu', 'remove_profile_menu');
You can use the current_user_can() function to determine who you want to see the menu items.
Profiless plugin does that on the subscriber-level.
If you wish to do that for other groups, you should probably use it in combination with Capability manager plugin.

Resources