如何将父元素的标题添加到导航菜单的子元素中?

时间:2017-12-25 作者:Johansson

以下是默认导航菜单标记的简单输出:

<ul>
    <li><a>First Item</a>
        <ul class="sub-menu">
            <li><a>Some Child Item</a></li>
            <li><a>Some Child Item</a></li>
        </ul>
    </li>
    <li><a>Second Item</a></li>
    <li><a>Third Item</a></li>
</ul>
我正在尝试将父项的标题添加到sub-menu 部分因此,我正在努力实现这一目标:

<ul>
    <li><a>First Item</a>
        <ul class="sub-menu">
            <h3>First Item</h3> <!-- I\'m looking for this -->
            <li><a>Some Child Item</a></li>
            <li><a>Some Child Item</a></li>
        </ul>
    </li>
    <li><a>Second Item</a></li>
    <li><a>Third Item</a></li>
</ul>
我一直在研究Walker_Nav_Menu 类及其方法。负责输出<ul>start_lvl 方法,我找不到获取父元素的对象或ID以检索其标题的方法。以下是此函数的内容:

public function start_lvl( &$output, $depth = 0, $args = array() ) {
        if ( isset( $args->item_spacing ) && \'discard\' === $args->item_spacing ) {
            $t = \'\';
            $n = \'\';
        } else {
            $t = "\\t";
            $n = "\\n";
        }
        $indent = str_repeat( $t, $depth );

        // Default class.
        $classes = array( \'sub-menu\' );

        /**
         * Filters the CSS class(es) applied to a menu list element.
         *
         * @since 4.8.0
         *
         * @param array    $classes The CSS classes that are applied to the menu `<ul>` element.
         * @param stdClass $args    An object of `wp_nav_menu()` arguments.
         * @param int      $depth   Depth of menu item. Used for padding.
         */
        $class_names = join( \' \', apply_filters( \'nav_menu_submenu_css_class\', $classes, $args, $depth ) );
        $class_names = $class_names ? \' class="\' . esc_attr( $class_names ) . \'"\' : \'\';

        $output .= "{$n}{$indent}<ul$class_names>{$n}";
    }
有可能做到这一点吗?

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

我相信wp_nav_menu() 处理顶级列表换行,以便start_lvl 方法将只处理子菜单项(据我所知)。它也不能让我们访问$item 我们需要找到父母。

下面我设置了一个布尔变量来跟踪我们是否应该显示标题。它还可以保持HTML的有效性,列表只能包含列表项,因此最好使用特定的类来设置列表项的样式。以下代码90%取自Core WP_Nav_Menu Walker

首先,我们需要设置变量:

class Title_Sub_Menus extends Walker_Nav_Menu {

    /**
     * Track Whether to show parent title
     *
     * @var Boolean
     */
    private $show_parent_title = false;

    /* ... */

}
接下来,每当创建新的子菜单时,我们需要打开开关变量:

class Title_Sub_Menus extends Walker_Nav_Menu {

    /* ... */

    /**
     * Starts the list before the elements are added.
     *
     * @since 3.0.0
     *
     * @see Walker::start_lvl()
     *
     * @param string   $output Used to append additional content (passed by reference).
     * @param int      $depth  Depth of menu item. Used for padding.
     * @param stdClass $args   An object of wp_nav_menu() arguments.
     */
    public function start_lvl( &$output, $depth = 0, $args = array() ) {

        if ( isset( $args->item_spacing ) && \'discard\' === $args->item_spacing ) {
                $t = \'\';
                $n = \'\';
        } else {
                $t = "\\t";
                $n = "\\n";
        }

        $indent = str_repeat( $t, $depth );

        // Default class.
        $classes = array( \'sub-menu\' );

        // Enable Submenu Title
        $this->show_parent_title = true;

        /**
         * Filters the CSS class(es) applied to a menu list element.
         *
         * @since 4.8.0
         *
         * @param array    $classes The CSS classes that are applied to the menu `<ul>` element.
         * @param stdClass $args    An object of `wp_nav_menu()` arguments.
         * @param int      $depth   Depth of menu item. Used for padding.
         */
        $class_names = join( \' \', apply_filters( \'nav_menu_submenu_css_class\', $classes, $args, $depth ) );
        $class_names = $class_names ? \' class="\' . esc_attr( $class_names ) . \'"\' : \'\';
        $output .= "{$n}{$indent}<ul$class_names>{$n}";

    }

    /* ... */

} // END class Title_Sub_Menus
这就是事情变得有点棘手的地方。据我所知,如果菜单项对象标题没有从原始标题更改,则不会与该项一起保存。如果原始页面标题为“WordPress页面”,并且在将菜单项添加到菜单后将其标题更改为“WordPress”,则会将其保存到菜单项中。我们还应该对照条款进行检查。Kudos to Alex Sancho\'s answer.

Class Title_Sub_Menus extends Walker_Nav_Menu {

    /* ... */

    /**
     * Starts the element output.
     *
     * @since 3.0.0
     * @since 4.4.0 The {@see \'nav_menu_item_args\'} filter was added.
     *
     * @see Walker::start_el()
     *
     * @param string   $output Used to append additional content (passed by reference).
     * @param WP_Post  $item   Menu item data object.
     * @param int      $depth  Depth of menu item. Used for padding.
     * @param stdClass $args   An object of wp_nav_menu() arguments.
     * @param int      $id     Current item ID.
     */
    public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {

        // Maybe show parent title
        if( 0 === $depth && $this->show_parent_title ) {

            // Grab the title if the user HAS changed it from the original
            $title = get_the_title( $item->menu_item_parent );

            if( empty( $title ) ) {

                // Title is the original title, grab it from the original post or term.
                $object_id  = get_post_meta( $item->menu_item_parent, \'_menu_item_object_id\', true );
                $object     = get_post_meta( $item->menu_item_parent, \'_menu_item_object\',    true );
                $type       = get_post_meta( $item->menu_item_parent, \'_menu_item_type\',      true );

                if ( \'post_type\' === $type ) {
                    $title = get_post( $object_id )->post_title;
                } elseif ( \'taxonomy\' === $type) {
                    $title = get_term( $object_id, $object )->name;
                }

            }

            $output .= sprintf( \'<li class="parentTitle"><h3>%1$s</h3></li>\', $title ); // Display our title

            // Parent title displayed, turn off switch
            $this->show_parent_title = false;

        }

        /* ... */

    }

} // END class Title_Sub_Menus
全班
class Title_Sub_Menus extends Walker_Nav_Menu {

    /**
     * Track Whether to show parent title
     *
     * @var Boolean
     */
    private $show_parent_title = false;


    /**
     * Starts the list before the elements are added.
     *
     * @since 3.0.0
     *
     * @see Walker::start_lvl()
     *
     * @param string   $output Used to append additional content (passed by reference).
     * @param int      $depth  Depth of menu item. Used for padding.
     * @param stdClass $args   An object of wp_nav_menu() arguments.
     */
    public function start_lvl( &$output, $depth = 0, $args = array() ) {

        if ( isset( $args->item_spacing ) && \'discard\' === $args->item_spacing ) {
                $t = \'\';
                $n = \'\';
        } else {
                $t = "\\t";
                $n = "\\n";
        }

        $indent = str_repeat( $t, $depth );

        // Default class.
        $classes = array( \'sub-menu\' );

        $this->show_parent_title = true;

        /**
         * Filters the CSS class(es) applied to a menu list element.
         *
         * @since 4.8.0
         *
         * @param array    $classes The CSS classes that are applied to the menu `<ul>` element.
         * @param stdClass $args    An object of `wp_nav_menu()` arguments.
         * @param int      $depth   Depth of menu item. Used for padding.
         */
        $class_names = join( \' \', apply_filters( \'nav_menu_submenu_css_class\', $classes, $args, $depth ) );
        $class_names = $class_names ? \' class="\' . esc_attr( $class_names ) . \'"\' : \'\';
        $output .= "{$n}{$indent}<ul$class_names>{$n}";

    }


    /**
     * Starts the element output.
     *
     * @since 3.0.0
     * @since 4.4.0 The {@see \'nav_menu_item_args\'} filter was added.
     *
     * @see Walker::start_el()
     *
     * @param string   $output Used to append additional content (passed by reference).
     * @param WP_Post  $item   Menu item data object.
     * @param int      $depth  Depth of menu item. Used for padding.
     * @param stdClass $args   An object of wp_nav_menu() arguments.
     * @param int      $id     Current item ID.
     */
    public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {

        // Maybe show parent title
        if( 0 === $depth && $this->show_parent_title ) {

            $object_id  = get_post_meta( $item->menu_item_parent, \'_menu_item_object_id\', true );
            $object     = get_post_meta( $item->menu_item_parent, \'_menu_item_object\',    true );
            $type       = get_post_meta( $item->menu_item_parent, \'_menu_item_type\',      true );
            $title      = get_the_title( $item->menu_item_parent );

            if( empty( $title ) ) {

                if ( \'post_type\' == $type ) {
                    $title = get_post( $object_id )->post_title;
                } elseif ( \'taxonomy\' == $type) {
                    $title = get_term( $object_id, $object )->name;
                }

            }

            $output .= sprintf( \'<li class="parentTitle"><h3>%1$s</h3></li>\', $title ); // OR post_parent if dynamically generated
            $this->show_parent_title = false;

        }

        if ( isset( $args->item_spacing ) && \'discard\' === $args->item_spacing ) {
                $t = \'\';
                $n = \'\';
        } else {
                $t = "\\t";
                $n = "\\n";
        }

        $indent = ( $depth ) ? str_repeat( $t, $depth ) : \'\';
        $classes = empty( $item->classes ) ? array() : (array) $item->classes;
        $classes[] = \'menu-item-\' . $item->ID;

        /**
         * Filters the arguments for a single nav menu item.
         *
         * @since 4.4.0
         *
         * @param stdClass $args  An object of wp_nav_menu() arguments.
         * @param WP_Post  $item  Menu item data object.
         * @param int      $depth Depth of menu item. Used for padding.
         */
        $args = apply_filters( \'nav_menu_item_args\', $args, $item, $depth );
        /**
         * Filters the CSS class(es) applied to a menu item\'s list item element.
         *
         * @since 3.0.0
         * @since 4.1.0 The `$depth` parameter was added.
         *
         * @param array    $classes The CSS classes that are applied to the menu item\'s `<li>` element.
         * @param WP_Post  $item    The current menu item.
         * @param stdClass $args    An object of wp_nav_menu() arguments.
         * @param int      $depth   Depth of menu item. Used for padding.
         */
        $class_names = join( \' \', apply_filters( \'nav_menu_css_class\', array_filter( $classes ), $item, $args, $depth ) );
        $class_names = $class_names ? \' class="\' . esc_attr( $class_names ) . \'"\' : \'\';
        /**
         * Filters the ID applied to a menu item\'s list item element.
         *
         * @since 3.0.1
         * @since 4.1.0 The `$depth` parameter was added.
         *
         * @param string   $menu_id The ID that is applied to the menu item\'s `<li>` element.
         * @param WP_Post  $item    The current menu item.
         * @param stdClass $args    An object of wp_nav_menu() arguments.
         * @param int      $depth   Depth of menu item. Used for padding.
         */
        $id = apply_filters( \'nav_menu_item_id\', \'menu-item-\'. $item->ID, $item, $args, $depth );
        $id = $id ? \' id="\' . esc_attr( $id ) . \'"\' : \'\';
        $output .= $indent . \'<li\' . $id . $class_names .\'>\';
        $atts = array();
        $atts[\'title\']  = ! empty( $item->attr_title ) ? $item->attr_title : \'\';
        $atts[\'target\'] = ! empty( $item->target )     ? $item->target     : \'\';
        $atts[\'rel\']    = ! empty( $item->xfn )        ? $item->xfn        : \'\';
        $atts[\'href\']   = ! empty( $item->url )        ? $item->url        : \'\';
        /**
         * Filters the HTML attributes applied to a menu item\'s anchor element.
         *
         * @since 3.6.0
         * @since 4.1.0 The `$depth` parameter was added.
         *
         * @param array $atts {
         *     The HTML attributes applied to the menu item\'s `<a>` element, empty strings are ignored.
         *
         *     @type string $title  Title attribute.
         *     @type string $target Target attribute.
         *     @type string $rel    The rel attribute.
         *     @type string $href   The href attribute.
         * }
         * @param WP_Post  $item  The current menu item.
         * @param stdClass $args  An object of wp_nav_menu() arguments.
         * @param int      $depth Depth of menu item. Used for padding.
         */
        $atts = apply_filters( \'nav_menu_link_attributes\', $atts, $item, $args, $depth );
        $attributes = \'\';
        foreach ( $atts as $attr => $value ) {
                if ( ! empty( $value ) ) {
                        $value = ( \'href\' === $attr ) ? esc_url( $value ) : esc_attr( $value );
                        $attributes .= \' \' . $attr . \'="\' . $value . \'"\';
                }
        }
        /** This filter is documented in wp-includes/post-template.php */
        $title = apply_filters( \'the_title\', $item->title, $item->ID );
        /**
         * Filters a menu item\'s title.
         *
         * @since 4.4.0
         *
         * @param string   $title The menu item\'s title.
         * @param WP_Post  $item  The current menu item.
         * @param stdClass $args  An object of wp_nav_menu() arguments.
         * @param int      $depth Depth of menu item. Used for padding.
         */
        $title = apply_filters( \'nav_menu_item_title\', $title, $item, $args, $depth );
        $item_output = $args->before;
        $item_output .= \'<a\'. $attributes .\'>\';
        $item_output .= $args->link_before . $title . $args->link_after;
        $item_output .= \'</a>\';
        $item_output .= $args->after;
        /**
         * Filters a menu item\'s starting output.
         *
         * The menu item\'s starting output only includes `$args->before`, the opening `<a>`,
         * the menu item\'s title, the closing `</a>`, and `$args->after`. Currently, there is
         * no filter for modifying the opening and closing `<li>` for a menu item.
         *
         * @since 3.0.0
         *
         * @param string   $item_output The menu item\'s starting HTML output.
         * @param WP_Post  $item        Menu item data object.
         * @param int      $depth       Depth of menu item. Used for padding.
         * @param stdClass $args        An object of wp_nav_menu() arguments.
         */
        $output .= apply_filters( \'walker_nav_menu_start_el\', $item_output, $item, $depth, $args );
    }

} // END class Title_Sub_Menus
对我来说,这似乎有点混乱/奇怪,没有更简单或更直接的方法来做到这一点,所以这是一个可能的解决方案。希望有人能提供更直观的解决方案和解释。

结束

相关推荐

Making sub-menus exclusive

我真的不知道该怎么解释我在这里找的东西,我在这里找得太露骨了。在我的网站上,我有一个附带菜单,其中包含一系列子类别,每个子类别中都有一些项目。我想知道当我打开另一个子类别时,是否有办法关闭所有其他打开的子类别,例如:1. Animals ----A. Cats ----B. Dogs 2. People ----A. Samantha ----B. Daniel 当我按下“动物”时,我希望“人”关闭,反之亦