1

In a Twenty Thirteen child theme I append a menu item (a link to /player-number page template, where the number is different for each user and represents her or his id in a game database) using the wp_nav_menu_items hook:

function my_nav_menu_items( $items ) {
    $profile = sprintf('<li id="menu-item-32" 
        class="menu-item menu-item-type-custom 
        menu-item-object-custom menu-item-32">
        <a href="/player-%d/#navbar">Profile</a></li>', 
        42); // 42 is just a placeholder here, representing user id

    return $items . $profile;
}

add_filter( 'wp_nav_menu_items', 'my_nav_menu_items' );

And that item is visible and clickable in the primary-menu, but for some reason it is never highlighted (apologies for non-english text in the screenshot):

website screenshot

I.e. when I click at any other menu entry - it changes its color to reddish one and the font slant to italics:

highlighted menu item

But the last menu item does not do that, why?

UPDATE:

The wp_nav_menu_objects filter seems to be more suitable for the task of adding a menu item and I have tried using it in my /wp-content/themes/twentythirteen-child/functions.php file:

function my_nav_menu_objects( $sorted_menu_items ) 
{
    $link = array (
        'title'            => 'Profile',
        'menu_item_parent' => 0,
        'ID'               => 32,
        'url'              => '/player-42',
    );
    $sorted_menu_items[] = (object) $link;
    error_log(print_r($sorted_menu_items, TRUE));
    return $sorted_menu_items;
}

add_filter( 'wp_nav_menu_objects', 'my_nav_menu_objects' );

but it suffers the same problem: the menu item is added, but it is not highlighted (the CSS style current-menu-item for that is missing) when selected.

UPDATE 2:

Also I have tried adding a menu item called "Profile" manually and then searching and replacing its url with the following code:

function my_nav_menu_objects( $sorted_menu_items )
{
    foreach ( $sorted_menu_items as $item ) {
            error_log(print_r($item, TRUE));

            if ( $item->title == 'Profile' ) {
                $item->url = '/player-42';
                break;
            }
    }

    return $sorted_menu_items;
}

add_filter( 'wp_nav_menu_objects', 'my_nav_menu_objects' );

with the same effect (the URL has changed, but CSS highlighting is missing, when that URL is selected).

2
  • 1
    I just curious why you create dynamic of navigation menu for profile page, is it base on current user id when logged-in? or base on page url with player id?
    – Jevuska
    Commented Apr 12, 2016 at 2:14
  • Yes, the link /player-ID is dynamic and based on the current user id, but I think it is not really relevant for my question: How to add a menu item using the wp_nav_menu_items filter - so that it works properly (i.e. the focus works)? Commented Apr 12, 2016 at 9:15

3 Answers 3

1

@AlexanderFarber, there are many way to attach attribute class under wp_nav_menu link. I agree with @Sumit, adding page links in Appearance > Menu WordPress take care of current-menu-item class or current_page_item class. Also, this way is best practice to handle your nav menu in the future.

Create dynamic link in wp_nav_menu

Since your question related to this answer, then you have a Page with player as slug. My approach, after I add those page as menu in Appearance > Menu ( then change label with 'Profile' ), I will use filter nav_menu_link_attributes to make this page have dynamic link. As your question, you use current user id to make it dynamics. Take a look this sample code, say 7 is post/page ID as target:

add_filter( 'nav_menu_link_attributes', function( $atts, $item, $args, $depth )
{
    // check our nav_menu
    if ( is_object( $args ) && is_object( $item ) && 'primary-menu' == $args->menu_id )
    {
        $post_id = 7; // Define Post or Page ID
        $user    = wp_get_current_user();
        if ( 0 < $user->ID && $post_id == $item->object_id )
            $atts['href'] = esc_url( user_trailingslashit( untrailingslashit( $item->url ) . '-' . $user->ID ) );
    }
    return $atts;
} 10, 4 );

You need to check which menu before you make change, since your filter will effect another menu in the same page. By this approach you don't get trouble in attribute ( class or id theme css related ) of the current page.

Answer related your code

Yes I know you need to add custom link by filter wp_nav_menu_items and add class attribute for the current page, almost the same with your answer. Since it related to Page, I use current_page_item as class attribute that match with css TwentyThirteen to make highlight of item nav menu.

add_filter( 'wp_nav_menu_items', 'my_nav_menu_items', 10, 2 );
function my_nav_menu_items( $items, $args )
{
    if ( is_object( $args ) && 'primary-menu' == $args->menu_id )
    {
            $user         = wp_get_current_user();
            $with_user_id = ( 0 != $user->ID ) ? '-' . $user->ID : '';
            
            $post_id      = 7; // Post or Page ID
            $class        = ( is_page( $post_id ) ) ? 'current_page_item' : '';
            
            $items .= sprintf( '<li id="menu-item-32" class="menu-item menu-item-type-custom 
            menu-item-object-custom %1$s menu-item-32"><a href="%2$s">%3$s</a></li>',
                sanitize_html_class( $class ),
                esc_url( user_trailingslashit( untrailingslashit( get_page_link( $post_id ) ) . $with_user_id  ) ),
                __( 'Profile', 'textdomain' )
            );
    }
    return $items;
}

You can tweak the code to adjust with your current project. I hope this helps.

0

The other pages show a 'current menu item' css state:

.nav-menu .current_page_item > a, .nav-menu .current_page_ancestor > a, .nav-menu .current-menu-item > a, .nav-menu .current-menu-ancestor > a {
   color: #bc360a;
   font-style: italic;

This page is showing as 'page-id-32'. If that corresponds to the page in the menu it should show the 'current page item' css. Otherwise you need to get the class 'current-menu-item' in the css somehow when you are on that page. For instance, if you change:

sprintf('<li id="menu-item-32" 
    class="menu-item menu-item-type-custom 
    menu-item-object-custom menu-item-32">

to

sprintf('<li id="menu-item-32" 
    class="menu-item menu-item-type-custom 
    menu-item-object-custom current-menu-item">

It will do the job, but I think that would show as 'always' the current page.

4
  • Thanks for taking the time to answer, but IMHO this is not the solution for my problem. Obviously the highlighting CSS is not selected, but the question is how to solve it properly in Wordpress (i.e. maybe some method call is missing - to tell Wordpress, that a menu item has been added and thus the menu length has increased by +1) Commented Apr 11, 2016 at 12:34
  • @AlexanderFarber If you want in WordPress way then go with WordPress way by adding page links in Appearance > Menu WordPress take care of current-menu-item class. Currently your menu item is custom and WordPress can not detect custom links because custom link can be a # or external link. For adding pages link there is already a WordPress way!
    – Sumit
    Commented Apr 11, 2016 at 18:22
  • No, there must be a better way and I'll search for it in the Wordress source code... I can not add this menu manually in Appearance > Menu, because it is a dynamic link to the player-ID page template and should point to the users own player profile page /player-ID (i.e. the numeric id is different for each user). Commented Apr 11, 2016 at 18:38
  • 2
    @AlexanderFarber, I think you should add your question before to the context question here :), and to solve your issue It just create condition by get_query_var, you can var_dump $wp via global $wp inside your function to see your query_vars. Then add class current_page_item by condition statement.
    – Jevuska
    Commented Apr 11, 2016 at 19:22
0

Here is my own solution - in the /wp-content/themes/twentythirteen-child/functions.php file add the current-menu-item CSS style if the page slug is player:

function my_nav_menu_items( $items ) 
{
    $profile = sprintf('<li class="menu-item 
        menu-item-type-custom 
        menu-item-object-custom 
        %s"><a href="/player-%d/#navbar">Profile</a></li>', 
        ( is_page( 'player' ) ? 'current-menu-item' : '' ),
        42);
    return $items . $profile;
}

add_filter( 'wp_nav_menu_items', 'my_nav_menu_items' );

A more specific page check would be: is_page( array ( 42, 'player' ) )

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.