Añadir elementos de menú dinámicamente usando wp_nav_menu_objects

4 mar 2014, 18:59:36
Vistas: 15.5K
Votos: 2

En mi navegación principal, quiero que cada página de nivel superior tenga una lista de sus subpáginas. Así que creé un código que añade elementos de menú dinámicamente a la navegación principal. Esto funciona solo en el primer nivel de subpáginas. Puedes ver que comenté el código que va al segundo nivel porque mostraba esos enlaces en el nivel principal. No sé por qué no funciona en el segundo nivel. ¿Podría ser que no podemos asignar un elemento de menú a un elemento de menú padre generado dinámicamente?

Se ve así:

add_filter( 'wp_nav_menu_objects', 'epc_wp_nav_menu_items', 10, 2 );
function epc_wp_nav_menu_items($items, $args) {
    if ($args->theme_location == 'primary') {
        $menu_order = 10000;
        $menu_order2 = 20000;
        global $wpdb;
        global $post;
        $post_id = 0;       
        if($post){
            $post_id = $post->ID;
        }

        foreach($items as $item){
            $pageChildren = $wpdb->get_results("SELECT post_title, ID FROM wp_posts WHERE post_parent = ".$item->object_id." AND post_status = 'publish' AND post_type='page' ORDER BY menu_order", 'OBJECT' );
            foreach($pageChildren as $child){
                $menu_order++;
                $new_item = epc_add_menu_item($post_id, $menu_order, $item, $child);
                $items[] = (object)$new_item;
                /*
                $pageChildrenSecondLevel = $wpdb->get_results("SELECT post_title, ID FROM wp_posts WHERE post_parent = ".$child->ID." AND post_status = 'publish' AND post_type='page' ORDER BY menu_order", 'OBJECT' );
                foreach($pageChildrenSecondLevel as $child2){
                    $menu_order2++;
                    $new_item2 = epc_add_menu_item($post_id, $menu_order2, $new_item, $child2);
                    $items[] = (object)$new_item2;
                }
                */
            }
        }
    }
    return $items;
}

function epc_add_menu_item($post_id, $menu_order, $item, $child){
                $new_item = new stdClass;
                $new_item->ID = $menu_order;
                $new_item->menu_item_parent = $item->ID;
                $new_item->url = get_permalink( $child->ID );
                $new_item->title = $child->post_title;
                $new_item->menu_order = $menu_order;
                $new_item->object_id = $child->ID;
                $new_item->post_parent = $item->object_id;
                $classes = 'menu-item';
                $classes .= ' menu-item-parent-' . $item->ID;
                $classes .= ' menu-item-type-post_type';
                $classes .= ' menu-item-object-page';
                if($post_id == $child->ID){
                    $classes .= ' current-menu-item';
                    $classes .= ' page-item';
                    $classes .= ' page-item-' . $child->ID ;
                    $classes .= ' current_page_item';
                }   
                $new_item->classes = $classes;
                return $new_item;
}
1
Comentarios

Lo que describes suena muy complicado para un filtro simple. Creo que deberías considerar seriamente usar un Walker personalizado. Mira: http://wordpress.stackexchange.com/search?q=user%3A21376+extends+Walker_Nav_Menu

s_ha_dum s_ha_dum
5 mar 2014 04:01:51
Todas las respuestas a la pregunta 3
0

También debes especificar el campo db_id para el elemento padre del menú:

function epc_add_menu_item( $post_id, $menu_order, $item, $child ) {
    ...
    $new_item->db_id = $menu_order;
    ...
}

Como nota adicional, los elementos de menú que tienen hijos también deben tener la clase menu-item-has-children.

14 abr 2016 19:38:02
0

Usa esta clase personalizada para mostrar el submenú:

class Wp_Sublevel_Walker extends Walker_Nav_Menu {

    function start_lvl(&$output, $depth = 0, $args = array()) {
        $indent = str_repeat("\t", $depth);
        $output .= "\n$indent<ul class='submenu'>\n";
    }

    function end_lvl(&$output, $depth = 0, $args = array()) {
        $indent = str_repeat("\t", $depth);
        $output .= "$indent</ul>\n";
    }

}
5 ago 2016 13:07:18
0

Si tus entradas de menú personalizadas están basadas en publicaciones, categorías u otros objetos de WordPress, puedes usar wp_setup_nav_menu_item(objeto_WP) para obtener un objeto de elemento de menú.

$item=wp_setup_nav_menu_item(get_post());

Ese objeto tendrá la mayoría de la información configurada correctamente, pero no toda la información está presente. Todavía necesitamos establecer algunas de las propiedades en el elemento. Necesitamos establecer el elemento padre del menú, si quieres que esté en el nivel superior asígnale el valor 0.

$item->menu_item_parent = $parentitem->ID;

Para que un elemento tenga hijos, necesitas asignar un db_id, pero este DEBE ser el ID del objeto de WordPress, no funcionará (o al menos no logré que funcionara) con ningún otro valor. Así que necesitamos establecerlo:

$item->db_id = get_the_ID();

Si tu entrada actual tendrá hijos, agregas menu-has-children a la variable de clases. Nota que también agrego otras clases (css) requeridas para mi tema.

$item->classes = array("menu-item", "menu-item-type-post_type", "menu-item-object-page", "menu-item-has-children");

Puedes crear tu propio elemento personalizado creando el ítem como describí arriba y luego modificando $item->title y $item->url pero manteniendo los IDs. Solo asegúrate de que el ID sea único en el nivel del menú (no verifiqué si necesita ser único en todo el menú).

(Para otros como yo que encontraron este hilo mientras intentaban crear un menú personalizado: El orden del menú debe ser tal que el padre esté seguido directamente por sus hijos).

15 ene 2021 23:32:22