自定义wp_NAV_MENU输出(显示当前分支中顶级菜单元素的所有子元素)

时间:2013-10-13 作者:Marcin Bobowski

我想创建一个walker函数,或者以某种方式修改当前函数wp_nav_menus 因此,它可以生成自定义输出。让我们想象一下这种结构:

menu item 1
menu item 2
 submenu item a
 submenu item b
menu item 3
 submenu item c
 submenu item d
 submenu item e
最简单的部分是只在一个地方显示主菜单项(主菜单1、2、3),可以使用wp\\u nav\\u菜单完成,因此我们不需要对其进行编码。

问题是在其他地方显示当前主项的子菜单项。。。所以,如果用户在“菜单项1”页面上,则不会显示任何内容。如果用户位于“菜单项2”页面,我们的“新”自定义菜单将显示:

submenu item a
submenu item b
当用户位于上述两个页面(菜单项)中的任何一个页面上时,会呈现相同的菜单项。

当用户单击“菜单项3”并访问其目标页面时,他会看到子菜单项c、d、e,与单击任何子菜单项后看到的子菜单项相同。

如果菜单有第三级元素(以及更深层次的元素),自定义菜单应显示当前最顶层菜单元素的所有子元素,以及顶层元素本身(将列在第一位描述的站点顶部)

有没有办法创建这样的功能?

该想法接近于:Display a portion/branch of menu只是它需要是动态的,并显示当前菜单分支的子元素/顶部菜单分支元素的所有子元素(如果存在)。

好吧,我不能用get_ancestors, 因为它只适用于层次分类法,这里我们讨论的不是从帖子/页面层次结构创建的菜单,而是使用菜单编辑器。

SOLVED:似乎我能够通过几种方法创建正确的函数:

/**
 * The API function, just a wrap for wp_nav_menu adding filter first and removing after
 */ 
function filtered_nav_menu( $args = array() ) {
    $echo = isset($args[\'echo\']) ? (bool)$args[\'echo\'] : true;
    $args[\'echo\'] = false;
    add_filter( \'wp_nav_menu_objects\', \'gmfnv_filter\', 999 );
    $menu = wp_nav_menu( $args );
    remove_filter( \'wp_nav_menu_objects\', \'gmfnv_filter\', 999 );
    if ( $echo ) echo $menu;
    else return $menu;
}

/**
 * The filter callback, return the filtered elements
 */
function gmfnv_filter( $items ) {
    $found_top_parent_ID = false;
    foreach ($items as $item) {
        if ( ($item->menu_item_parent == 0 && $item->current_item_ancestor == 1) || ($item->menu_item_parent == 0 && $item->current == 1) ) {
            $found_top_parent_ID = $item->ID;
        }
    }
    $children  = submenu_get_children_ids( $found_top_parent_ID, $items );
    foreach ( $items as $key => $item ) {
        if ( ! in_array( $item->ID, $children ) )
            unset($items[$key]);
    }
    return $items;
}

/**
 * Helper function: return children of an element using wp_filter_object_list
 */
function submenu_get_children_ids( $id, $items ) {
    $ids = wp_filter_object_list( $items, array( \'menu_item_parent\' => $id ), \'and\', \'ID\' );
    foreach ( $ids as $id ) {
        $ids = array_merge( $ids, submenu_get_children_ids( $id, $items ) );
    }
    return $ids;
}
它的作用-它通过遍历每个$items元素并检查以下各项来搜索当前的分支顶部祖先:

($item->menu_item_parent == 0 && $item->current_item_ancestor == 1) || ($item->menu_item_parent == 0 && $item->current == 1)
这个条件必须由两部分组成,因为顶级菜单元素也可能是当前元素。

如果找到顶级$项,则函数submenu_get_children_ids 用于列出其所有子元素。

1 个回复
最合适的回答,由SO网友:gmazzap 整理而成

这个想法不是创建一个定制的助行器,而是更容易使用过滤器过滤项目wp_nav_menu_objects

此挂钩在中定义/wp-includes/nav-menu-templates.php 当触发时,它传递给与之挂钩的函数一个数组$sorted_menu_items 它包含正在打印的菜单的所有元素,如果函数更改该数组,添加或删除项目,则生成的菜单将被更改。

如果过滤器wp_nav_menu_objects 直接应用,all 菜单将被过滤,所以我认为最好创建a function that wrap wp_nav_menu 在调用之前添加筛选器wp_nav_menu 然后在之后将其删除:这样只会过滤想要的菜单。

筛选工作流循环所有经过的项目wp_nav_menu_objects 过滤器挂钩创建2个助手数组:一个只包含父ID,另一个包含以下项$itemid => $parentid
  • 在循环项目时,还要检查it项目url是否与当前url匹配,如果url不匹配,则只返回父项目,如果url匹配,则使用助手数组cretaed,返回所需的元素,代码是我为此编写的代码,使用5个函数,因此我创建了一个插件来包含所有这些内容,下面是代码:

    <?php
    /**
     * Plugin Name: Filtered Nav Menus
     * Author: Giuseppe  Mazzapica
     * Plugin URI: http://wordpress.stackexchange.com/questions/118720/
     * Author URI: http://wordpress.stackexchange.com/users/35541/
     */
    
    /**
     * The API function, just a wrap for wp_nav_menu adding filter first and removing after
     */ 
    function filtered_nav_menu( $args = array() ) {
      $echo = isset($args[\'echo\']) ? (bool)$args[\'echo\'] : true;
      $args[\'echo\'] = false;
      add_filter( \'wp_nav_menu_objects\', \'gmfnv_filter\', 999 );
      $menu = wp_nav_menu( $args );
      remove_filter( \'wp_nav_menu_objects\', \'gmfnv_filter\', 999 );
      if ( $echo ) echo $menu;
      else return $menu;
    }
    
    /**
     * The filter callback, return the filtered elements
     */
    function gmfnv_filter( $items ) {
      $found = false;
      $parents = $items_tree = $allowed = array();
      $all_items = $items;
      while ( ! empty( $items ) ) {
        $item = array_shift( $items );
        $items_tree[$item->ID] = $item->menu_item_parent;
        if ( (int) $item->menu_item_parent == 0 ) $parents[] = $item->ID;
        if ( isset($item->current) && $item->current ) $found = $item->ID;
      }
      if ( ! $found ) {
        $ids = $parents;
      } else {
        $tree = gmfnv_get_tree( $found, $all_items, $items_tree );
        $ids = array_merge( $parents, $tree );
      }
      foreach ( $all_items as $item ) {
        if ( in_array( $item->ID, $ids ) ) $allowed[] = $item;
      }
      return $allowed;
    }
    
    
    /**
     * Helper function: take the matched element if and the helper array and
     * return the item ancestors by gmfnv_get_parents,
     * and the children of these ancestors returned by gmfnv_get_parents
     * using gmfnv_get_parents
     */
    function gmfnv_get_tree( $test, $items, $tree ) {
      $parents = gmfnv_get_parents( $test, $items );
      $parents[] = $test;
      $n = array();
      foreach ( $parents as $parent ) {
        $n = array_merge( $n, gmfnv_get_childrens( $parent, $tree ) );
      }
      return array_unique( $n );
    }
    
    
    /**
     * Helper function: return ancestors of an element using the helper array
     */
    function gmfnv_get_parents( $test, $items ) {
      $parents = array();
      foreach( $items as $item ) {
          if (
            (isset($item->current_item_ancestor) && $item->current_item_ancestor)
            || (isset($item->current_item_ancestor) && $item->current_item_ancestor)
          ) $parents[] = $item->ID;
      }
      return $parents;
    }
    
    
    /**
     * Helper function: return children of an element using the helper array
     */
    function gmfnv_get_childrens( $test, $tree ) {
      $children = array();
      foreach ( $tree as $child => $parent ) {
        if ( $parent == $test ) $children[] = $child;
      }
      return $children;
    }
    
    如何创建包含此插件的文件并将其放入插件文件夹并激活。

    如果需要根据需要筛选菜单,请使用wp_nav_menu( $args ) 使用

    filtered_nav_menu( $args );
    
    免责声明提供的代码按原样提供,没有任何保证,但只是在PHP 5.4、WP 3.7上快速测试,激活了第二十个青少年主题,没有其他插件:在这种情况下有效。

  • 结束

    相关推荐

    如何禁用我的主机强制执行的插件(在u-plugins中)?

    我的主机制作了两个必需的插件,它们会在mu plugins文件夹下自动更新。有没有一种方法可以通过一些技巧来禁用它们,例如在我的本地插件文件夹下使用一个同名的插件文件夹,或者复制一些函数并使其为空?