如何根据URL向导航li添加类?

时间:2021-06-02 作者:moodyjive

我正在尝试添加一个。当位于特定url上时,li的当前菜单项类/投资组合/quot;。我可以通过jQuery实现这一点:

jQuery(document).ready(function( $ ) {
  var loc = window.location.href; // returns the full URL
  if(/portfolio/.test(loc)) {
    $(\'#menu-item-33\').addClass(\'current-menu-item\');
  }
});
然而,我想用PHP。这就是我目前的情况:

function add_class_to_specific_menu_items( $atts, $item, $args ) {
    // check if the item is set to target="_blank"
    if ( $item->url == \'/portfolio/\' ) {
      // add the desired attributes:
      $atts[\'class\'] = \'current-menu-item\';
    }
    return $atts;
}
add_filter( \'nav_menu_link_attributes\', \'add_class_to_specific_menu_items\', 10, 3 );
不确定这是否可行和/或我是否可以让它将类添加到特定的li“#菜单项-33

3 个回复
最合适的回答,由SO网友:Fabian Mossberg 整理而成

Here is the solution.

To set it up:

Paste the following at the bottom of the file functions.php in the folder of your current theme.

Edit by the in the code`

$when_on_one_of_these_page_slugs should be an array of strings. The strings are the slugs of the pages on where you want the rule to kick in. The script will kick in the rule if you are on:

  • One of these slugs.
  • A child of any of these slugs.

Edit by the in the code:

$change_these_nav_menu_items should be a list of menu item id\'s, of the item you want to look selected, when the rule kicks in.

You can find the ID of the menu in dev tools by right clicking on the menu item and choose "inspect element". You will see the source code of the generated page, and you will find the item ID in the <li> tag wrapping the <a> of the item you inspected.

enter image description here

/**
 * Makes specific menu item look active when visiting a certain page
 *
 * @param array $wp_nav_meny Array of items from a WP Nav Menu.
 *
 * @return array modified array of WP Nave Menu items.
 * @see https://wordpress.stackexchange.com/questions/389050/how-can-i-add-a-class-to-a-nav-li-depending-on-url
 */
function make_x_active_when_on_y( array $wp_nav_meny ) {


    //  Set an array of page slug (strings) to trigger the rule.
    $when_on_one_of_these_page_slugs = array( \'portfolio\', \'add-any-slug-that-should-trigger-the-rule\');
    //  Set an array menu item id\'s (ints) to apply the rule to.
    $change_these_nav_menu_items = array( 33, 999);

    // Get the ID\'s of the pages we added in the setting.
    $post_ids_to_trigger_rule = wp_list_pluck(array_map(\'get_page_by_path\',  $when_on_one_of_these_page_slugs ), \'ID\');
    // Get all the ancestors of the page we are curently visiting.
    $ancestors_of_current_page = get_post_ancestors(get_queried_object_id());
    // Add the current page into the array of ancestors.
    array_push($ancestors_of_current_page, get_the_ID());

    $new_menu = array();

    // Loop through the nav menu items.
    foreach ( $wp_nav_meny as $menu_item ) {
        /*
         * If the ID of the current page, or any of it\'s ancestors,
         * exists in the array of ID\'s that should trigger the rule,
         * AND
         * The current item ID in the loop, is in the array if nav menu
         * item id\'s that sould get the "current-menu-item" class.
         */
        if ( array_intersect($post_ids_to_trigger_rule, $ancestors_of_current_page) && in_array( (int) $menu_item->ID, $change_these_nav_menu_items, true ) ) {
            $menu_item->classes[] = \'current-menu-item\';
        }
        $new_menu[] = $menu_item;
    }
    return $new_menu;
}
add_filter( \'wp_nav_menu_objects\', \'make_x_active_when_on_y\' );

How it works

When you visit a page that has the slug you set at the , or a page that has that page as an ancestor, then the rule kick in.

The rule is that the menu item that you set at will have the class current-menu-item.

Below you can see a recording of the result.

This is a completely fresh installation of WordPress 5.7.2, running PHP 7.4.1. No plugins installed. The theme is twentytwentyone (the ones that is shipped with WordPress).

My config looked like this:

$when_on_one_of_these_page_slugs = array( \'portfolio\'); // The slug of my portfolio page.
$change_these_nav_menu_items = array( 24 ); // The item ID of my "A link to Google"-menu item.

In action

SO网友:Ejaz UL Haq

尝试以下经过测试的解决方案他们正在工作100% 因为两种解决方案都基于wp过滤器挂钩wp_get_nav_menu_items 在以下情况下执行wp_get_nav_menu_items() 函数被调用。

Solution 01: 通过比较菜单项添加CSS类ID

function add_class_to_specific_menu_items( $items, $menu, $args ){
    foreach ( $items as $index => $menu_item ){
        // conditional statement to compare the menu-item id
        if( $menu_item->ID == 33 ){
              // conditional statement to check the current url is same
              if( get_permalink() == $menu_item->url ){
                  $menu_item->classes[] = \'current-menu-item\';
              }     
        }
    }
  return $items;
}
add_filter(\'wp_get_nav_menu_items\', \'add_class_to_specific_menu_items\', 10, 3);
Solution 02: 通过比较菜单项添加CSS类URL

function add_class_to_specific_menu_items( $items, $menu, $args ){
    foreach ( $items as $index => $menu_item ){
        // conditional statement to compare the menu-item URL
        if( $menu_item->url ==  get_site_url().\'/portfolio/\' ){
               $menu_item->classes[] = \'current-menu-item\';
        }
    }
  return $items;
}
add_filter(\'wp_get_nav_menu_items\', \'add_class_to_specific_menu_items\', 10, 3);

SO网友:Mort 1305

@modyjive--@ejaz ul haq给出的答案与您给出的PHP代码一致。您的PHP代码尝试添加current-menu-item 类以定位包含/portfolio/ 他们的HREF属性中的URL。您的代码不太正确,所以@ejaz ul haq对其进行了修复,以便提供所表示的效果。但是,我将您的问题解释为不同的意思:您希望将提供的JavaScript功能转换为WordPress支持的功能。如果这是你想要的,这是我的答案。

我们首先确定JS的功能:

jQuery(document).ready(function( $ ) {                    // When the page loads,
    var loc = window.location.href;                       // save the current URL
    if(/portfolio/.test(loc)) {                           // and check if it contains \'/portfolio/\'.
        $(\'#menu-item-33\').addClass(\'current-menu-item\'); // If so, add `current-menu-item` to the class list of all elements with id="menu-item-33"
    }
});
很快,我们遇到了一个问题:您的JS将添加current-menu-item 到具有id="menu-item-33" 属性因此,它将在后端和前端发生,在某些您甚至不知道存在的地方也会发生。我要冒险一试,但我猜你在用nav_menu_link_attributes 可能是因为你想操纵打印在前端的导航菜单?如果是这样的话,让我们深入WordPress文档,看看这些文档是如何打印出来的。(我在下面的文本中提供了链接,您可以继续;如果您不熟悉跟踪WordPress代码,现在是您学习的机会。)

首先,我们找出一个起点。您使用了nav_menu_link_attributes 胡克,让我们从这里开始。从reference guide, 据了解,这个钩子是在/wp-includes/class-walker-nav-menu.php 文件根据header notes of the hook, nav_menu_link_attributes "E;过滤应用于菜单项的锚元素的HTML属性"E;锚元素(<a>) 位于列表项元素内部(<li>). JavaScript表示要将类添加到列表项元素,而不是锚点。如果我们向上滚动到line 170, 我们可以看到列表项添加到输出流的位置。该行如下所示:

$output .= $indent . \'<li\' . $id . $class_names . \'>\';
我们可以看到lines 167 and 168 哪里$id 已生成并打开lines 153 and 154 哪里$class_names 已生成。通过钩住nav_menu_css_class 过滤器(第153行),我们可以缩小$class_names 变量,然后将其输出到<li> 第170行的开始标签,我相信这就是你想要的!根据WordPress reference, 这个nav_menu_css_class 挂钩“;过滤应用于菜单项列表项元素的CSS类"E;是的,这就是你的JS所做的,所以我们在正确的轨道上。

那么,我们开始吧:

function add_class_to_specific_menu_items($classes, $item, $args, $depth){
    global $wp;
    $loc = add_query_arg($wp->query_vars, home_url($wp->request)); // Save the current URL (like you did in your JS)
    if(stripos($loc, \'/portfolio/\') !== NULL                       // and check if it contains `/portfolio/`  (like you did in your JS).
    && $item->ID === 33                                            // Also check that this is menu item #33  (like what you did in your JS, but limit only to navigation menus)
    ) {
        $classes[] = \'current-menu-item\';                          // and if so, add the desired class to the list item (like you did in your JS).
    }
    // No matter what, return the $classes array or we\'ll break things when navigation menus are output.
    return $classes;
}
add_filter(\'nav_menu_css_class\', \'add_class_to_specific_menu_items\', 10, 4);
该喝杯啤酒了(希望你能点击已回答的复选标记upvote,然后给我你的赏金)。

相关推荐

WP_Query filters

这个问题可能看起来很愚蠢,但我真的没有找到有用的链接。我正在尝试做一个简单的查询,在这里我选择了最近的10篇文章,我希望能够在循环中只显示这10篇文章中的1篇我的代码看起来像 // Query latest 10 records $the_query = new WP_Query( array( \'post_type\' => \'post\', \"order\" => \"DESC\", \'posts_per_page