¿Cómo agregar el título del elemento padre al hijo del menú de navegación?

2

Aquí hay una salida simple de la marca de menú de navegación predeterminada:

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

Estoy intentando agregar el título del elemento principal a la sección sub-menu . Por lo tanto, estoy tratando de lograr esto:

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

He estado indagando en la clase Walker_Nav_Menu y sus métodos. El método que es responsable de generar el <ul> es el método start_lvl , y no puedo encontrar una manera de agarrar el objeto o ID del elemento principal para recuperar su título. Aquí está el contenido de esta función:

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

¿Es posible hacer esto?

    
pregunta Jack Johansson 25.12.2017 - 21:05

1 respuesta

4

Creo que wp_nav_menu() maneja el ajuste de la lista de nivel superior por lo que el método start_lvl solo manejaría los elementos del submenú (según entiendo). Tampoco nos da acceso al $item que necesitamos para obtener el padre.

A continuación, he configurado una variable booleana para rastrear si deberíamos mostrar nuestro título o no. También mantiene el código HTML válido, las listas solo pueden contener elementos de lista, por lo que puede ser mejor diseñar elementos de lista con una clase específica. El código a continuación es el 90% tomado de Core WP_Nav_Menu Walker

Primero necesitamos configurar nuestra variable:

class Title_Sub_Menus extends Walker_Nav_Menu {

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

    /* ... */

}

A continuación, debemos activar nuestra variable de cambio cada vez que se cree un nuevo submenú:

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

Aquí es donde las cosas se ponen un poco difíciles. Por lo que sé, los títulos de los objetos del elemento del menú no se guardan con el elemento si no ha cambiado con respecto al título original. Si el título de la página original es "Página de WordPress" y cambia el título del elemento del menú a "WordPress" después de agregarlo al menú, se guarda en el elemento del menú. También deberíamos comprobar contra los términos. Felicitaciones a la respuesta de Alex Sancho.

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

Clase completa

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

Me parece un poco desordenado / extraño, no hay una forma más sencilla ni sencilla de hacerlo, por lo que esta es una posible solución. Esperemos que alguien venga con una solución y explicación más intuitivas.

    
respondido por el Howdy_McGee 26.12.2017 - 23:34

Lea otras preguntas en las etiquetas