Drupal programmatically adding an item to a menu - drupal

I wish to conditionally add an item to a menu. I have a custom module and a menu called "links". How would I add an item to a menu in my module code?

You need to implement hook_menu in your module. Example:
<?php
function mymodule_menu() {
$items['mymodule/links'] = array(
'title' => 'Links',
'page callback' => 'mymodule_links_page',
'access arguments' => array('access content'),
'type' => MENU_SUGGESTED_ITEM,
);
return $items;
}
?>
The 'type' => MENU_SUGGESTED_ITEM, part makes it optional, so it can be enabled by the end user - is that what you meant with "conditionally"? If not, please explain what kind of "conditionally" you're looking for.

Or you can use the 'type' => MENU_NORMAL_ITEM, since it is enabled by default, but can be disabled any time. This of course depends on your preferences. See http://api.drupal.org/api/drupal/includes--menu.inc/group/menu/7 for further reference.
Another good thing to know when using module defined menu items in custom menus might be how to programmatically create the menu you want to use so that everything is created "out of the box". Simply add a mymodule.install-file where you put the following code:
<?php
function mymodule_install() {
$menu = array(
'menu_name' => 'links',
'title' => 'My Custom Links',
'description' => 'Descriptive text.',
);
menu_save($menu);
}
?>
If you have an uninstall function, don't forget to not only deactivate the module, but also to uninstall it. Reenable the module, flush your caches and the menu item should be there!

You can dynamically show or hide a menu item based on a condition ( access callback ).
Here is an example from https://drupal.org/project/examples:
<?php
function mymodule_menu() {
$items = array();
$items['my-menu-item'] = array(
'title' => 'My Menu',
'description' => 'My description',
'page callback' => 'my_page_link_callback_function_name',
'access callback' => 'can_the_user_see_this_item',
'expanded' => TRUE,
'weight' => -100,
'menu_name' => 'primary-links',
);
return $items;
}
// Here we determine if the user can or can not see the item.
function can_the_user_see_this_item(){
if (MY_CONDITION){
return TRUE;
}
else {
return FALSE;
}
}

The menu system is cached, so you can't add or remove menu items as you please based on user, page viewed, custom logic etc. That is you can't do it without having to clear the menu cache which would cause a severe performance hit.
What you could do, to create this effect is to create some custom logic to define the access control on the menu item. Since Drupal hides menu items that users doesn't have access to, you could under certain circumstances deny permission to hide the menu item. This is a bit hackish solution.
Another solution which I would prefer, would be to use js or css to hide or show the menu. You could dynamically add/remove a class on the body to determine if the menu item should be shown or not. This would quickly become unmanagable if you need several of these kind of menu items, however.

Use menu_link_save() function
Saves a menu link.
After calling this function, rebuild the menu cache using menu_cache_clear_all().
Parameters
$item: An associative array representing a menu link item, with elements:
link_path: (required) The path of the menu item, which should be normalized first by calling drupal_get_normal_path() on it.
link_title: (required) Title to appear in menu for the link.
menu_name: (optional) The machine name of the menu for the link. Defaults to 'navigation'.
weight: (optional) Integer to determine position in menu. Default is 0.
expanded: (optional) Boolean that determines if the item is expanded.
options: (optional) An array of options, see l() for more.
mlid: (optional) Menu link identifier, the primary integer key for each menu link. Can be set to an existing value, or to 0 or NULL to insert a new link.
plid: (optional) The mlid of the parent.
router_path: (optional) The path of the relevant router item.
$existing_item: Optional, the current record from the {menu_links} table as an array.
$parent_candidates: Optional array of menu links keyed by mlid. Used by _menu_navigation_links_rebuild() only.
Return value
The mlid of the saved menu link, or FALSE if the menu link could not be saved.

Related

Drupal 7: Make a custom module create a menu item in the user menu

Just like the title says. If you add an item to the hook_menu function and declare it of type 'MENU_NORMAL_ITEM' it shows up in the navigation menu. Is there a way to create an item there that shows up in the user menu?
See the drupal documentation for the hook_menu function. with your custom menu items you can declare 'menu_name', and you pass the name of the menu you want your item added to. In your case it would be 'user-menu':
<?php
function mymodule_menu(){
$items['mymodulepath'] = array(
'title' => 'My Module User Item',
'type' => MENU_NORMAL_ITEM,
'menu_name' => 'user-menu',
);
return $items;
}

Wordpress - Remove submenu from custom post type

I created a custom post type named portfolio with tag taxonomy support.
Since WP does not make a difference between post tags and custom post type tags, I created a menu item Taxonomy under which I want to put categories and post tags. I managed to create the the menu and submenus, and also remove category and post tags from the Post menu, but i didn't manage to remove Post Tags from the custom post type menu.
I tried:
remove_submenu_page( 'edit.php?post_type=portfolio', 'edit-tags.php?taxonomy=post_tag&post_type=portfolio' );
You can use remove_submenu_page() - the trick however is to get the slug exactly right, to do this the easiest way is to dump the global $submenu and check for the menu_slug and submenu_slug.
global $submenu;
var_dump($submenu);
This will give you the array of menus, the top level key is the menu_slug and then the correct submenu_slug can be found in the element 2 of the nested arrays.
So if I had a custom post type called "my_events" and I wanted to remove the tags menu from it, my original menu structure would look like this
...
'edit.php?post_type=my_events' =>
array
5 =>
array
0 => string 'All Events' (length=10)
1 => string 'edit_posts' (length=10)
2 => string 'edit.php?post_type=my_events' (length=28)
10 =>
array
0 => string 'Add New' (length=7)
1 => string 'edit_posts' (length=10)
2 => string 'post-new.php?post_type=my_events' (length=32)
15 =>
array
0 => string 'Tags' (length=4)
1 => string 'manage_categories' (length=17)
2 => string 'edit-tags.php?taxonomy=post_tag&post_type=my_events' (length=55)
...
From this you can see that the menu_slug is 'edit.php?post_type=my_events' and the submenu slug for the tags menu is 'edit-tags.php?taxonomy=post_tag&post_type=my_events'.
So the remove function call would be:
remove_submenu_page('edit.php?post_type=my_events', 'edit-tags.php?taxonomy=post_tag&post_type=my_events');
Note that the submenu slug is html encoded so the ampersand is now & - this is probably that thing that has made it hard for people to work out from first principles what the slug name should be.
This is a bit dirty, but it works:
add_action('admin_menu', 'remove_niggly_bits');
function remove_niggly_bits() {
global $submenu;
unset($submenu['edit.php?post_type=portfolio'][11]);
}
I'm not sure exactly which key number you'll want to remove. Best way to find that is to do:
add_action('admin_menu', 'remove_niggly_bits');
function remove_niggly_bits() {
global $submenu;
//unset($submenu['edit.php?post_type=portfolio'][11]);
print_r($submenu); exit;
}
Everything will break when you load the admin area until you remove that line, but it'll show you the structure and which key you need.
It might be better to just use the 'show_ui' => false.
function car_brand_init() {
// new taxonomy named merk
register_taxonomy(
'merk',
'lease_fop',
array(
'label' => __( 'Merken' ),
'rewrite' => array( 'slug' => 'merken' ),
'update_count_callback' => '_update_post_term_count',
// use this to hide from menu
'show_ui' => false,
'capabilities' => array(
'assign_terms' => 'edit_guides',
'edit_terms' => 'publish_guides'
)
)
);
}
add_action( 'init', 'car_brand_init' );
To build on the answer from benz001:
No need to do the var dump to get the slug right. This worked for me.
remove_submenu_page('edit.php?post_type=POST_TYPE', 'edit-tags.php?taxonomy=TAXONOMY_SLUG&post_type=POST_TYPE')
First argument, replace POST_TYPE with what you see in your URL field at the top of the browser when viewing archive in back end.
Second Argument: Left click on the submenu you want to remove, copy the link, remove the last forward slash and everything to the left of it. Replace the & with &
Second arg example below.
1 Copy and paste submenu link
http://yourwebsite.com/wp-admin/edit-tags.php?taxonomy=your_custom_taxonomy&post_type=your_custom_post
2 Remove last forward slash and everything left of it.
edit-tags.php?taxonomy=your_custom_taxonomy&post_type=your_custom_post
3 Replace the & with the HTML entity &
/edit-tags.php?taxonomy=your_custom_taxonomy&post_type=your_custom_post

Help for custom menu

Drupal 7 hook_menu() is confusing me; I have tried everything and I can't seem to get this to work.
What I need: In a custom module, I'd like to create a new menu, and add about four links to that menu. It sounds simple, but I am struggling. I've been able to create the menu itself using the $menu array in the .install file, but adding items to that menu doesn't make sense.
Code that is working:
$menu = array(
'menu_name' => 'project-menu',
'title' => $t('Project Menu'),
'description' => 'Project Menu',
);
menu_save($menu);
Code that isn't working:
$items = array();
$items['project-menu/%'] = array(
'title' => 'Test Link',
'page callback' => 'dc_project_page',
'page arguments' => array(1),
'access callback' => TRUE,
'type' => MENU_LOCAL_TASK,
);
return $items;
This is all in the dc_project.install file under the dc_project_menu() function. Hopefully I'm just doing something stupid, any and all help is extremely appreciated. Even just pointing to me to a module that does this cleanly as an example, thanks. I did look at the example project, haven't been able to get anything as far as adding links to my new menu working.
Passing to menu_save() the content of $items doesn't work because menu_save() accepts only an array containing menu_name, title, and description.
What you use in $items is an array describing the menu callbacks implemented by a module, and the definitions of the menu callbacks implemented by all the modules are not saved in "menu_custom" (the table used from menu_save()) but are cached in a Drupal cache table.
If you are trying to change the menu callbacks defined by another module, then you should implement hook_menu_alter(); otherwise, if you just want do define the menu callbacks of your module, you should implement hook_menu().
Both the hooks implementations (hook_menu() and hook_menu_alter()) must be in the module file (in your case, in dc_project.module), not in dc_project.install. Drupal doesn't load the installation file when it normally loads the enabled modules; it loads the installation file when a module is being updated (or installed), but it doesn't load it in other cases.
The code that saves the menu with menu_save() can be in the installation file, in the implementation of hook_install() or hook_update_N(). It could also be put in the implementation of hook_enable(); in that case, the code (which is executed when the module is enabled) should first verify the menu has not been already added. (hook_enable() and hook_disable() should be placed in the installation file.)

Overriding the user registration form in Drupal 6

I want to be able to customise the user registration form in Drupal 6
I have found thousands of tutorials that show me how to override the structure in which you can output the form as a whole, but I want to move form elements around etc and I cant quite seem to see the best way to do this
To expand on Jeremy's answer, you're going to want to study Drupal's Form API and user_register(). In short, you build an associated array; each element in the array corresponds to one form element.
Each form element in the array is its own associated array. They can have a type: textfield, select menu, checkboxes, etc.: see the Form API reference for all the types.
Each form element can also have a weight: this is how you order elements around. Lower numbered weights show up before higher numbered weights in the form.
One of the element types available to you is fieldset: this is what will allow you to group elements together. When you use a fieldset, it creates a section of the form with its own weight values.
So, let's say you have a form with three fields: Name, Company, and E-mail address. The Name should show up first, Company second, E-mail address third. You could specify the form like so:
$form['name'] = array(
'#type' => 'textfield',
'#title' => t('Name'),
'#weight' => 1,
);
$form['company'] = array(
'#type' => 'textfield',
'#title' => t('Company'),
'#weight' => 2,
);
$form['email'] = array(
'#type' => 'textfield',
'#title' => t('E-mail address'),
'#weight' => 3,
);
Note the #weight key. If you wanted Company to appear after E-mail address, you'd set $form['company']['#weight'] to something higher than 3.
Now let's say you wanted to group Name and Company into a fieldset called Personal Information. Your form would now look something like this:
$form['personal'] = array(
'#type' => 'fieldset',
'#title' => t('Personal information'),
'#weight' => 1,
);
$form['personal']['name'] = array(
'#type' => 'textfield',
'#title' => t('Name'),
'#weight' => 1,
);
$form['personal']['company'] = array(
'#type' => 'textfield',
'#title' => t('Company'),
'#weight' => 2,
);
$form['email'] = array(
'#type' => 'textfield',
'#title' => t('E-mail address'),
'#weight' => 3,
);
Note that Name and Company are now array elements of $form['personal'].
If you want to make Name show up after Company in the fieldset, set its #weight higher than 2. Because the Name is now part of a fieldset that has a lower #weight than the E-mail address field, even if you set $form['personal']['name']['#weight'] to 4, it wouldn't make the Name show up after E-mail address.
So what you're going to attempt to do is use hook_form_alter() to alter the user_register form to change the weights of certain form elements, create your own fieldsets, and move certain form elements into your newly created fieldsets.
There are ways to do this within your theme, but I prefer creating a custom module for this. Create your custom module, and implement hook_form_alter():
function test_form_alter(&$form, $form_state, $form_id) {
if ($form_id === 'user_register') { // Only modify the user registration form
// Before you can get down to business, you need to figure out the
// structure of the user registration form. Use var_dump or kpr to dump
// the $form array.
// Note: if you want to use kpr on the user registration form, give
// anonymous permission to see devel information.
// kpr($form);
// Move Name field to after E-Mail field
$form['name']['#weight'] = 2;
$form['mail']['#weight'] = 1;
// Group Name and E-mail together into a fieldset
$form['personal_info'] = array(
'#type' => 'fieldset',
'#title' => t('Personal information'),
);
$form['personal_info']['name'] = $form['name'];
$form['personal_info']['mail'] = $form['mail'];
// The last block only copied the elements: unset the old ones.
unset($form['name']);
unset($form['mail']);
}
}
In more complex forms, moving things from one fieldset to another might yield unexpected results when submitting the form. This is because $form['name'] isn't the same as $form['group']['name'], which isn't the same as $form['other_group']['name']. You don't have to worry about that on the user_register form for the most part, but check out the handbook page on #tree and #parents for more information about this.
This covers modifying existing fields in the user registration form: if you want to add new fields, I highly recommend using Content Profile. If you want to create custom fields on your own, it's going to get a lot more complex as you're going to have to implement your own validate and submit handlers. Content Profile handles this for you: check out its README to see how to activate it for registration forms.
Using hook_form_alter you can do whatever you want with a form.
For example changing the weight can change the position on the page.
If you try:
MYMODULE_form_user_profile_form_alter(&$form, $form_state) {
// do your processing here
var_dump($form);
}
replacing MYMODULE with the name of your module.
You will see the structure of the form, you can change values in there to alter, labels weights descriptions etc.
In a module, first use hook_theme() , now assuming the name of your module is 'd6_forms' :
function d6_forms_theme() {
return array(
'user_register' => array(
'template' => 'templates/user-register-form',
'arguments' => array('form' => NULL),
),
);
}
This will make the user_register form look for a template, in the specified folder.
So make sure that in your module folder, there is a folder called 'templates', with a file 'user-register-form.tpl.php'.
You notice that in the hook_theme() , the extenstion of the template file ( .tpl.php ) is not supplied. That's normal, you don't need to specify it there.
Do make sure however, that the template has that extension, and that it's not just named 'user-register-form.php' !
In that template file, you have access to the $form variable , so print it there to see what fields are in there.
The devel module is recommened, since it's able to print big Drupal arrays in a fancy way ( using dpm() ).
If you do not have Devel module, or don't want to use it, this also works : <?php print '<pre>' . print_r($form, 1) . '</pre>'; ?>.
To print a field, just use <?php print drupal_render($form[field_name]); ?>, this will print the field and make sure that it works as intended.
So for example, if you want to print the 'name' field in the $form array, just use <?php print drupal_render($form['name']); ?>.
You don't have to print every field ! Just print the fields that you want to move somewhere ( which, with a basic Drupal register form, are about 3 : name, email & submit ).
To print all the remaining fields, just end your template with <?php print drupal_render($form); ?>.
It is important that you don't forget this, since the $form var contains stuff that is absolutely needed for your form to work ( like a token, etc .. ).
So good standard behaviour when templating a form, is to print that piece of code first at the bottom of your template.
This is an entire example of a small register form template, with some basic html :
<?php
// What is in that $form var ? To check, uncomment next line
// print '<pre>' . print_r($form, 1) . '</pre>';
?>
<div style="background-color:#ddd;padding:10px;">
<?php print drupal_render($form['name']); ?>
<?php print drupal_render($form['mail']); ?>
</div>
<div>
<?php print drupal_render($form['submit']); ?>
</div>
<?php print drupal_render($form); ?>
maybe this will help:
http://drupal.org/node/44910
You just need to Enable the Profile Module which would give access to place more fields in sign up form.
Go through this Simple Video tutorial which would be very helpful for beginners in Drupal .
http://planetghost.com/add_more_fields_to_sign_up

Drupal 6: how to display node with its local tasks tabs in menu item

In my case each user has a gallery. Gallery is a node. I'd like to hide default "Create content" menu and add custom menu link that links to user gallery.
function custom_menu() {
$items = array();
$items['galleries/editgallery'] = array(
'title' => 'Edit gallery',
'description' => 'edit gallery',
'page callback' => 'custom_edit_gallery',
'access callback' => 'custom_access_editgallery',
);
return $items;
}
function custom_edit_gallery (){
global $user;
$node = node_load ($user->gallerynid);
return node_page_view ($node);
}
But it doesn't show local tasks tabs(like "Edit" tab).
You would need to add them yourself.
With normal theming, you could create a custom template file or overwrite a theme function etc to add the tabs you want.
You could also do this within hook_menu, by using MENU_LOCAL_TASK and MENU_DEFAULT_LOCAL_TASK, see the api.

Resources