I want to add a button for a responsive dropdown in a wordpress menu, which I can trigger with javascript.
For that I need a custom link with an icon or something like that after the a-tag but inside the li-tag.
How can I check a menuitem if it has a submenu and add a custom a-tag inside?
I've tried the walker and add_filter function, but it doesn't work.
Can anybody help me?
Thanks
If you add this to your function.php file, it will add class dropdown to all the parent menus with children (submenus). Then you can target .dropdown with javascript.
function menu_set_dropdown( $sorted_menu_items, $args ) {
$last_top = 0;
foreach ( $sorted_menu_items as $key => $obj ) {
// it is a top lv item?
if ( 0 == $obj->menu_item_parent ) {
// set the key of the parent
$last_top = $key;
} else {
$sorted_menu_items[$last_top]->classes['dropdown'] = 'dropdown';
}
}
return $sorted_menu_items;
}
add_filter( 'wp_nav_menu_objects', 'menu_set_dropdown', 10, 2 );
Related
I was trying to add a specific class to the admin section. I created a new top-level menu page and now I want to add a specific class to this top-level menu and its submenu items.
What I have tried so far is that I used WP_Screen to get the data of the current screen.
If I check the submenu page and I did var_dump(get_current_screen()). It shows every detail.
But now the case is that If I use get_current_screen() with admin_body_class why it doesn't work.
As far as I know, the hook is early called before the submenu page details are loaded.
Now I want to ask, how it is possible to check if the submenu has a specific parent base,
Here is the code that I tried so far.
add_filter('admin_body_class', 'tw_admin_body_class');
function tw_admin_body_class( $classes ) {
$screen = get_current_screen();
var_dump($screen);
if ( $screen->parent_base == 'tw-top' ) {
return $classes . ' raashid';
}
}
But parent_base is set to null. Any idea how to add class to submenu pages if it is under the specific yop-level menu.
It worked by using the Id option.
Here is the working option.
add_filter( 'admin_body_class', 'my_admin_body_class' );
function my_admin_body_class( $classes ) {
$screen = get_current_screen();
$classes .= ' raashid';
if ( get_plugin_page_hook( 'tw-top', '' ) === $screen->id ) {
return $classes;
}
}
I'm adding a search box and a "Join Email List" button to the top of a wordpress main menu. The search box appears as expected, but the email button shows up within the menu's UL -- which I can compensate for with positioning, in the full menu, but it hides the button completely when the responsive mobile menu appears. Not sure how to get it out of the UL properly.
I found that if you require the email button as an external file, it will appear outside the UL -- but that also causes a "1" to appear before the main menu in the NON-mobile version. Puzzling...
Here's my code, with both the string method and require method shown (commented out).
add_filter('wp_nav_menu_items','add_search_box_to_menu', 10, 2);
function add_search_box_to_menu( $items, $args ) {
if( $args->theme_location == 'main-nav-menu' ) {
$search_form = get_search_form();
// $email_button = require_once('emailbutton.php');
$email_button = '<button id="btn_emaillist">Join Our Email List</button>';
$items = $search_form . $email_button . $items;
}
return $items;
}
You can see this live at http://example.wdev05.com/. How can I make the button appear outside the UL so that it's visible in both desktop & mobile, without any strange side effects?
wp_nav_menu_items will add content inside UL.
use wp_nav_menu filter to insert content outside ul
function _wp_nav_m_filter( $nav, $args ) {
if( $args->theme_location == 'main-nav-menu' ) {
$search_form = get_search_form( false ); // do not echo the form
$search_form .= '<button id="btn_emaillist">Join Our Email List</button>';
return $search_form . $nav;
}
return $nav;
}
add_filter('wp_nav_menu', '_wp_nav_m_filter', 10, 2);
checkout https://core.trac.wordpress.org/browser/tags/4.5/src/wp-includes/nav-menu-template.php#L451
I am using a custom Walker function to customise the display of a menu in Wordpress.
To go one step forward I would like to have a different HTML markup for submenus with more than X elements.
Is there a way I can check the number of elements for a given item within the start_el function of the Walker Walker_Nav_Menu?
It's not the simplest thing using the Walker class, so I thought of a solution using DOMDocument to parse the menu HTML and count the submenus children after the menu has been built (using the wp_nav_menu_{$menu->slug}_items filter):
add_filter( 'wp_nav_menu_{MENU_SLUG}_items', function( $items, $args ) {
$dom = new DOMDocument();
$dom->loadHTML($items);
// get the .sub-menu elements
$submenus = $dom->getElementsByTagName('ul');
// for each one if it has children add a class
// like has-{num}-children
foreach ($submenus as $ul) {
if($ul->hasChildNodes()) {
// number of child nodes divided by 2
// to exclude the text nodes
$numChildren = $ul->childNodes->length / 2;
$class = "has-$numChildren-children";
$ul->setAttribute(
'class', $ul->getAttribute('class') . ' ' . $class
);
}
}
// save the changes
$html = $dom->saveHtml($dom->documentElement);
// remove html and body tags added by $dom->loadHTML
$items = preg_replace('~</?(html|body)>~', '', $html);
return $items;
}, 10, 2);
This should add a class has-{num}-children to every submenu with children (where {num} is the number of children), so that you can target whatever you want.
It can be easily changed to apply the class only to the submenus with a minimum number of children.
Remember to change {MENU_SLUG} with the slug of your menu.
I just want to know how to add a specific class to the "home" link in wordpress.
Actually all the li has something like class="page_item page-item-XXXXX" where XXXXX is a number but the "home" link has no class.
Can I fix that ?
thanks
You can add custom classes to menu items using the following in your functions.php
add_filter('nav_menu_css_class', 'fkp_special_nav_class', 10, 2);
function fkp_special_nav_class($classes, $item)
{
if($item->title == 'Home or what ever'){
$classes[] = 'myCusomClass';
}
return $classes;
}
Add following code in your functions.php
add_filter('nav_menu_css_class' , 'add_extra_class' , 10 , 2);
function add_extra_class($classes, $item){
if($item->title == 'Home'){ // In this case your Home page's title should be 'Home'
$classes[] = 'my_home_class';
}
return $classes;
}
Under Pages menu in Wordpress Admin page, I got this layout:
Pages
Edit (url: edit-pages.php)
Add New (url: page-new.php)
Special Pages (url: edit-pages.php?special-pages=true)
as you can see, I've added a new submenu item called Special Pages which is pretty much a link to to Edit page with custom filter. Because Wordpress use file name to identify and highlight the submenu item, so whenever I click on Special Pages, the Edit submenu item is selected. Is there anyway to force Wordpress to select Special Pages menu item instead?
Cheers
better solution:
add_filter('parent_file', 'my_plugin_select_submenu');
function my_plugin_select_submenu($file) {
global $plugin_page;
if ('__my-current-submenu-slug__' == $plugin_page) {
$plugin_page = '__my-submenu-slug-to-select__';
}
return $file;
}
To further clarify Ken Vu's answer, edit the global variables $submenu_file and $parent_file. E.g., to highlight your page:
global $submenu_file;
$submenu_file = "edit-pages.php?special-pages=true";
If you need to change the top-level item highlighted, use $parent_file. E.g., highlight the "Writing" setting page:
global $parent_file;
global $submenu_file;
$parent_file = 'options-general.php';
$submenu_file = 'options-writing.php';
Solution: use $submenu_file variable
$submenu_file = "edit-pages.php?special-pages=true"
Thanks Ken Vu and Jonathan Brinley. Using your answers, I finally got the highlighting of my admin menu to work properly. As I struggled a bit to get it to work, I though I would post the entire result here, so other people can find it more easily :
The idea is to call the parent_file filter (undocumented, as many Wordpress parts unfornatunately). In my case, I was adding a custom menu instead of the default generated when creating a custom post type.
In my custom post code, I call the add_meta_boxes action. Within this hook, I issue my call to the parent_file filter :
add_filter('parent_file', array(&$this, 'highlight_admin_menu'));
_
Then this is how my hightlight_admin_menu function looks like :
function highlight_admin_menu($some_slug){
global $parent_file;
$parent_file = 'post.php?post=149&action=edit';
return $parent_file;
}
_
This got my menu to highlight properly. Try playing around with you own code to know where to issue the add_filter('parent_file', ...) code. Find a bit of code executed only on that particular page load, but soon enough that it is still possible to modify the $parent_file variable.
I hope this helps!
For changing the highlighted menu item for a submenu item, the proper filter is submenu_file.
add_filter('submenu_file', 'menuBold');
static function menuBold($submenu_file)
{
if ( checkProperPage($_GET) ) {
// The address of the link to be highlighted
return 'post-new?post_type=foobar&foo=bar';
}
// Don't change anything
return $submenu_file;
}
The check happens in WP's ~/wp-admin/menu-header.php file on line 194 (Wordpress 4.5.3):
if ( isset( $submenu_file ) ) {
if ( $submenu_file == $sub_item[2] )
$class[] = 'current';
...
}
You can modify this code to work for you. You can change both parent and submenu with that. Tested code.
function change_active_parent($submenu_file)
{
global $parent_file;
$zone = 'edit-tags.php?taxonomy=zone&post_type=product';
$storefront = 'edit-tags.php?taxonomy=storefront&post_type=product';
$container = 'edit-tags.php?taxonomy=container&post_type=product';
if (esc_html($zone) == $submenu_file) {
$parent_file = 'parent';
$submenu_file = $zone;
}
elseif (esc_html($storefront) == $submenu_file) {
$parent_file = 'parent';
$submenu_file = $storefront;
}
elseif (esc_html($container) == $submenu_file) {
$parent_file = 'parent';
$submenu_file = $container;
}
return $submenu_file;
}
add_filter( 'submenu_file', 'change_active_parent' );
Use the load-{$page_hook} action hook and modify the necessary globals:
/**
* For giggles, lets make an admin page that is not "in the menu" to play with.
*/
add_action('admin_menu', 'mort1305_admin_menu');
function mort1305_admin_menu() {
add_submenu_page(
NULL,
'Page Title',
'',
'administrator',
'my_slug',
'mort1305_page_content'
);
}
/**
* The menu item to highlight and the submenu item to embolden.
*/
add_action('load-admin_page_my_slug', 'mort1305_on_page_load');
function mort1305_on_page_load(){
global $plugin_file, $submenu_file, $title;
$plugin_page = 'slug-of-menu-item-to-be-highlighted';
$submenu_file = 'slug-of-submenu-item-to-be-bold';
foreach($submenu[NULL] as $submenu_arr) {
if($submenu_arr[2] === 'test_page_slug') {
$title = $submenu_arr[3];
break;
}
}
}
/**
* Page content to display.
*/
function mort_1305_page_content() {
echo This is the '. get_admin_page_title() .' page. The slug of my parent is '. get_admin_page_parent() .'.';
}