web-dev-qa-db-de.com

Wie füge ich den Titel des übergeordneten Elements zum untergeordneten Navigationsmenü hinzu?

Hier ist eine einfache Ausgabe des Standard-Navigationsmenü-Markups:

<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>

Ich versuche, dem Abschnitt sub-menu den Titel des übergeordneten Elements hinzuzufügen. Also versuche ich dies zu erreichen:

<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>

Ich habe mich mit der Klasse Walker_Nav_Menu und ihren Methoden befasst. Die Methode, die für die Ausgabe des <ul> verantwortlich ist, ist die start_lvl-Methode, und ich kann keine Möglichkeit finden, das Objekt oder die ID des übergeordneten Elements abzurufen, um dessen Titel abzurufen. Hier ist der Inhalt dieser Funktion:

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}";
    }

Ist das möglich?

2
Jack Johansson

Ich glaube, dass wp_nav_menu() den Listenumbruch der obersten Ebene behandelt, so dass die start_lvl-Methode (nach meinem Verständnis) nur Untermenüelemente behandelt. Es gibt uns auch keinen Zugriff auf den $item, den wir benötigen, um den Elternteil zu erhalten.

Unten habe ich eine boolesche Variable eingerichtet, um zu verfolgen, ob wir unseren Titel anzeigen sollen oder nicht. Es behält auch HTML-Gültigkeit, Listen können nur Listenelemente enthalten, daher ist es möglicherweise besser, Listenelemente mit einer bestimmten Klasse zu formatieren. Der folgende Code stammt zu 90% aus dem Core WP_Nav_Menu Walker

Zuerst müssen wir unsere Variable einrichten:

class Title_Sub_Menus extends Walker_Nav_Menu {

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

    /* ... */

}

Als nächstes müssen wir unsere Schaltervariable immer dann einschalten, wenn ein neues Untermenü erstellt wird:

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

Hier wird es etwas knifflig. Soweit mir bekannt ist, werden Menüelement-Objekttitel nicht zusammen mit dem Element gespeichert, wenn sich der ursprüngliche Titel nicht geändert hat. Wenn der ursprüngliche Seitentitel "WordPress-Seite" lautet und Sie den Menüelementtitel nach dem Hinzufügen zum Menü in "WordPress" ändern, wird er im Menüelement gespeichert. Wir sollten auch gegen Bedingungen prüfen. Ein großes Lob an Alex Sancho Antwort.

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

Volle Klasse

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

Es scheint mir ein bisschen chaotisch/seltsam zu sein, es gibt keinen einfacheren oder einfacheren Weg, dies zu tun, so dass dies eine mögliche Lösung ist. Hoffentlich kommt jemand mit einer intuitiveren Lösung und Erklärung.

4
Howdy_McGee