如何获取仅基于菜单结构的页面导航?

时间:2019-01-05 作者:hal

我想获取当前页面所有父级的路径。类似于面包屑的东西,但只用于菜单中列出的页面。

例如,如果我有以下结构:

L Menu
    L Sub menu
        L Current page
    L Sub menu 2
L Menu 2
我想获得:

Menu >> Sub Menu >> Current page
我正在使用WordPress 5.0.2。我尝试了各种插件,但它们只显示当前页面,而不显示整个路径。

如何解决此问题?

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

这个wp_get_nav_menu_items 函数将为给定菜单提供一个菜单项对象数组。这些对象包含特定于该唯一菜单项的混合数据,以及菜单项所引用的帖子/页面/链接数据。您可以使用此菜单项数组查找当前页面,然后检查该项的父字段以使每个父项都处于循环中。

这里有一个例子,可以帮助您实现这一目标。通过呼叫使用它wpd_nav_menu_breadcrumbs( \'your menu\' ) 在模板中。阅读评论,看看每个部分都发生了什么。

// helper function to find a menu item in an array of items
function wpd_get_menu_item( $field, $object_id, $items ){
    foreach( $items as $item ){
        if( $item->$field == $object_id ) return $item;
    }
    return false;
}

function wpd_nav_menu_breadcrumbs( $menu ){
    // get menu items by menu id, slug, name, or object
    $items = wp_get_nav_menu_items( $menu );
    if( false === $items ){
        echo \'Menu not found\';
        return;
    }
    // get the menu item for the current page
    $item = wpd_get_menu_item( \'object_id\', get_queried_object_id(), $items );
    if( false === $item ){
        return;
    }
    // start an array of objects for the crumbs
    $menu_item_objects = array( $item );
    // loop over menu items to get the menu item parents
    while( 0 != $item->menu_item_parent ){
        $item = wpd_get_menu_item( \'ID\', $item->menu_item_parent, $items );
        array_unshift( $menu_item_objects, $item );
    }
    // output crumbs
    $crumbs = array(); 
    foreach( $menu_item_objects as $menu_item ){
        $link = \'<a href="%s">%s</a>\';
        $crumbs[] = sprintf( $link, $menu_item->url, $menu_item->title );
    }
    echo join( \' > \', $crumbs );
}
*免责声明:未经严格测试,使用风险自负

SO网友:JacobTheDev

@Milo的代码是一个很好的基线,但我遇到了两个问题:

它依赖于外观下指定的菜单名称→ 菜单。如果此名称发生更改,还需要在主题文件中进行更新我已经更新了代码,并进行了以下改进:

添加了另一个助手函数,该函数根据提供的位置检索菜单名称。这将阻止我列出的第一个问题

  • 在可能的情况下添加了类型转换功能
  • 添加了特定分隔符和类的功能
  • 返回值,而不是重复值(更容易进行条件检查)
    • /**
       * Retrieve a menu title from the database given the location the menu is assigned to
       *
       * @param string $location  Menu location
       *
       * @return string  The name of the menu
       */
      function wpse324751_get_menu_title(string $location): string {
          $menu_name = "";
      
          $locations = get_nav_menu_locations();
      
          if (isset($locations[$location]) && $menu = get_term($locations[$location], "nav_menu")) {
              $menu_name = $menu->name;
          }
      
          return $menu_name;
      }
      
      /**
       * Filter through an array of menu items to locate one specific item
       *
       * @param string $field
       * @param integer $object_id
       * @param array $items
       * @return WP_Post|bool
       */
      function wpse324751_get_menu_item(string $field, int $object_id, array $items) {
          foreach ($items as $item) {
              if (intval($item->$field) === $object_id) return $item;
          }
      
          return false;
      }
      
      /**
       * Display breadcrumbs based on a given menu
       *
       * @param string $menu_location
       * @param string $separator
       * @param string $class
       * @return string
       */
      function wpse324751_nav_menu_breadcrumbs(string $menu_location, string $separator = "&#8250;", string $class = ""): string {
          /**
           * Locate all menu items of the provided menu
           */
          $items = wp_get_nav_menu_items(wpse324751_get_menu_title($menu_location));
      
          /**
           * If no items exist, return empty
           */
          if ($items === false) {
              trigger_error("A menu at location \'" . sanitize_text_field($menu_location) . "\' could not be located.", E_USER_WARNING);
              return "";
          }
      
          /**
           * Locate the menu item for the viewed page
           */
          $item = wpse324751_get_menu_item("object_id", get_queried_object_id(), $items);
      
          /**
           * If no viewed item could be located, return empty
           */
          if ($item === false){
              return "";
          }
      
          /**
           * Store an array of items to construct the breadcrumb
           */
          $menu_item_objects = [$item];
      
          /**
           * Locate all parents of the viewed item
           */
          while (intval($item->menu_item_parent) !== 0) {
              $item = wpse324751_get_menu_item("ID", $item->menu_item_parent, $items);
              $menu_item_objects[] = $item;
          }
      
          /**
           * Initialize array to store breadcrumbs
           */
          $breadcrumbs = [];
      
          /**
           * Convert menu items to links and store them in the array
           */
          foreach($menu_item_objects as $menu_item) {
              $breadcrumbs[] = sprintf("<a class=\'text__link link\' href=\'%s\'>%s</a>", $menu_item->url, $menu_item->title);
          }
      
          /**
           * Return the breadcrumbs
           */
          return "<p class=\'" . esc_attr(trim("text {$class}")) . "\'>" . join(" {$separator} ", array_reverse($breadcrumbs)) . "</p>";
      }
      

    相关推荐

    Can I make plugins required?

    我正在开发自己的Wordpress主题,将用于多个客户端。它有一个主题选项页面,这样我每次都可以轻松自定义网站,但我也会在我制作的每个网站上使用一些插件(如SEO插件、安全性等)。有没有办法让它们成为“必需的”,这样我就可以得到这些插件的列表,这样当我在新网站上安装主题时就不必在插件目录中找到它们了?