Agregar mediante programación un menú de navegación y elementos de menú

42

A través de las funciones de la API, quiero definir un nuevo menú de navegación , seleccionarlo en el tema actual y luego insertar algunas páginas como elementos del menú. Esto se debe hacer, por ejemplo, en la activación de un tema.

A través de un proceso (moderadamente doloroso) de ingeniería inversa, la base de datos se inserta y actualiza después de configurar manualmente el menú de navegación y los elementos, he reunido los siguientes pasos, donde 'footer-nav' es la identificación de la barra del menú de navegación I ' m creando:

if (!term_exists('footer-nav', 'nav_menu')) {

    $menu = wp_insert_term('Footer nav', 'nav_menu', array('slug' => 'footer-nav'));

    // Select this menu in the current theme
    update_option('theme_mods_'.get_current_theme(), array("nav_menu_locations" => array("primary" => $menu['term_id'])));

    // Insert new page
    $page = wp_insert_post(array('post_title' => 'Blog',
                                 'post_content' => '',
                                 'post_status' => 'publish',
                                 'post_type' => 'page'));

    // Insert new nav_menu_item
    $nav_item = wp_insert_post(array('post_title' => 'News',
                                     'post_content' => '',
                                     'post_status' => 'publish',
                                     'post_type' => 'nav_menu_item'));


    add_post_meta($nav_item, '_menu_item_type', 'post_type');
    add_post_meta($nav_item, '_menu_item_menu_item_parent', '0');
    add_post_meta($nav_item, '_menu_item_object_id', $page);
    add_post_meta($nav_item, '_menu_item_object', 'page');
    add_post_meta($nav_item, '_menu_item_target', '');
    add_post_meta($nav_item, '_menu_item_classes', 'a:1:{i:0;s:0:"";}');
    add_post_meta($nav_item, '_menu_item_xfn', '');
    add_post_meta($nav_item, '_menu_item_url', '');

    wp_set_object_terms($nav_item, 'footer-nav', 'nav_menu');
}

Esto parece funcionar, pero:

  • ¿Es una forma robusta y elegante de hacerlo?
  • ¿Me estoy perdiendo algo totalmente obvio que haría todo esto en una sola línea de código?
julien_c
fuente

Respuestas:

43

Podría estar malinterpretándote, pero ¿por qué no usarlo wp_create_nav_menu()?

Por ejemplo, esto es lo que hago para crear un menú personalizado de BuddyPress cuando detecto BP como activo:

    $menuname = $lblg_themename . ' BuddyPress Menu';
$bpmenulocation = 'lblgbpmenu';
// Does the menu exist already?
$menu_exists = wp_get_nav_menu_object( $menuname );

// If it doesn't exist, let's create it.
if( !$menu_exists){
    $menu_id = wp_create_nav_menu($menuname);

    // Set up default BuddyPress links and add them to the menu.
    wp_update_nav_menu_item($menu_id, 0, array(
        'menu-item-title' =>  __('Home'),
        'menu-item-classes' => 'home',
        'menu-item-url' => home_url( '/' ), 
        'menu-item-status' => 'publish'));

    wp_update_nav_menu_item($menu_id, 0, array(
        'menu-item-title' =>  __('Activity'),
        'menu-item-classes' => 'activity',
        'menu-item-url' => home_url( '/activity/' ), 
        'menu-item-status' => 'publish'));

    wp_update_nav_menu_item($menu_id, 0, array(
        'menu-item-title' =>  __('Members'),
        'menu-item-classes' => 'members',
        'menu-item-url' => home_url( '/members/' ), 
        'menu-item-status' => 'publish'));

    wp_update_nav_menu_item($menu_id, 0, array(
        'menu-item-title' =>  __('Groups'),
        'menu-item-classes' => 'groups',
        'menu-item-url' => home_url( '/groups/' ), 
        'menu-item-status' => 'publish'));

    wp_update_nav_menu_item($menu_id, 0, array(
        'menu-item-title' =>  __('Forums'),
        'menu-item-classes' => 'forums',
        'menu-item-url' => home_url( '/forums/' ), 
        'menu-item-status' => 'publish'));

    // Grab the theme locations and assign our newly-created menu
    // to the BuddyPress menu location.
    if( !has_nav_menu( $bpmenulocation ) ){
        $locations = get_theme_mod('nav_menu_locations');
        $locations[$bpmenulocation] = $menu_id;
        set_theme_mod( 'nav_menu_locations', $locations );
    }
ZaMoose
fuente
No sabía sobre esta función. Sí, supongo que hará que el código anterior sea mucho más corto. Supongo que debería ir más allá del Codex y sumergirme en el código real, ya que encuentro que las funciones de la API a menudo, como en este caso, son de muy bajo nivel. ¡Gracias!
julien_c
@julien_c si esto se resuelve, márquelo como tal para permitir que los que vienen después de usted se beneficien de su experiencia aquí.
mor7ifer
Solo quiero probarlo en la vida real, así que estoy seguro de que hace lo que quiero. ¡Recordaré marcarlo como resuelto tan pronto como termine!
julien_c
3
Si ve funciones útiles como estas que no están en el códice, es una buena idea agregarlas (yay wiki) = p
Tom J Nowell
Lo siento, me tomó tanto tiempo comprobar que funcionó en mi caso. Respuesta aceptada! Además, está definiendo elementos de menú de enlaces personalizados , he agregado una respuesta a continuación para definir enlaces de página (que será más robusto a los cambios de URL, por ejemplo).
julien_c
12

Como complemento a la respuesta de ZaMoose, así es como crearía un elemento de menú "Tipo de página " (no uno " Personalizado "):

wp_update_nav_menu_item($menu_id, 0, array('menu-item-title' => 'About',
                                           'menu-item-object' => 'page',
                                           'menu-item-object-id' => get_page_by_path('about')->ID,
                                           'menu-item-type' => 'post_type',
                                           'menu-item-status' => 'publish'));

Asumiendo que solo conoces la babosa de la página, por ejemplo.

julien_c
fuente
9

Tengo algunos problemas con la respuesta aceptada, eso no lo hace incorrecto, pero publicaré mi propio código a continuación, que creo que podría tener un mejor resultado para algunas personas, ya que tenía la misma pregunta pero quería hacer lo mismo cosa con menos código.

Primero, el código anterior crea elementos de navegación de tipo "URL", lo cual está bien para algunas personas pero quiero vincular a PÁGINAS, no a URL porque esta es una característica importante de las navegaciones de WordPress y los clientes inevitablemente mueven las cosas para que nunca use la URL tipo de elemento de navegación.

Además, solo una matriz plana de niños es manejada por el código publicado. He creado una función para declarar recursivamente los nuevos elementos de navegación, almacenar sus metadatos devueltos (principalmente ID después de haber sido creados en el bucle) y un parámetro para aceptar hijos.

Solo edite $nav_items_to_addy el resto se maneja de forma recursiva. Hay 3 claves requeridas en cada matriz. Primero, la clave de la matriz es la babosa, por 'shop' => array( ... )lo que es lo que desea para una página con la babosa shop. ['title']es la forma en que se etiquetará el elemento de navegación en la parte frontal. pathes la ruta a la página dentro de la jerarquía de páginas de WordPress, por lo que es idéntica a la babosa si la página es un padre de nivel superior, y si shopfuera un hijo de homeentonces, lo sería 'path' => 'home/shop'.

La última clave de matriz opcional es ['parent']donde puede declarar otra clave en la matriz como la principal de la actual. Es importante tener en cuenta que los elementos se agregan de forma recursiva, por lo que el padre tiene que existir antes de intentar crear un hijo. Esto significa que la declaración debe ocurrir para el elemento de navegación principal antes de que sea secundario.

    $locations = get_nav_menu_locations();

    if (isset($locations['primary_navigation'])) {
        $menu_id = $locations['primary_navigation'];

        $new_menu_obj = array();

        $nav_items_to_add = array(
                'shop' => array(
                    'title' => 'Shop',
                    'path' => 'shop',
                    ),
                'shop_l2' => array(
                    'title' => 'Shop',
                    'path' => 'shop',
                    'parent' => 'shop',
                    ),
                'cart' => array(
                    'title' => 'Cart',
                    'path' => 'shop/cart',
                    'parent' => 'shop',
                    ),
                'checkout' => array(
                    'title' => 'Checkout',
                    'path' => 'shop/checkout',
                    'parent' => 'shop',
                    ),
                'my-account' => array(
                    'title' => 'My Account',
                    'path' => 'shop/my-account',
                    'parent' => 'shop',
                    ),
                'lost-password' => array(
                    'title' => 'Lost Password',
                    'path' => 'shop/my-account/lost-password',
                    'parent' => 'my-account',
                    ),
                'edit-address' => array(
                    'title' => 'Edit My Address',
                    'path' => 'shop/my-account/edit-address',
                    'parent' => 'my-account',
                    ),
            );

    foreach ( $nav_items_to_add as $slug => $nav_item ) {
        $new_menu_obj[$slug] = array();
        if ( array_key_exists( 'parent', $nav_item ) )
            $new_menu_obj[$slug]['parent'] = $nav_item['parent'];
        $new_menu_obj[$slug]['id'] = wp_update_nav_menu_item($menu_id, 0,  array(
                'menu-item-title' => $nav_item['title'],
                'menu-item-object' => 'page',
                'menu-item-parent-id' => $new_menu_obj[ $nav_item['parent'] ]['id'],
                'menu-item-object-id' => get_page_by_path( $nav_item['path'] )->ID,
                'menu-item-type' => 'post_type',
                'menu-item-status' => 'publish')
        );
    }

    }
Brian
fuente
2

Para agregar un elemento de menú mediante programación. Puedes enganchar para wp_nav_menu_itemsfiltrar. coloque el siguiente código en su tema functions.php para agregar un elemento de menú de inicio / cierre de sesión en el menú principal. 'Principal' es el nombre / id del menú registrado.

/**
 * Add login logout menu item in the main menu.
 * ===========================================
 */

add_filter( 'wp_nav_menu_items', 'lunchbox_add_loginout_link', 10, 2 );
function lunchbox_add_loginout_link( $items, $args ) {
    /**
     * If menu primary menu is set & user is logged in.
     */
    if ( is_user_logged_in() && $args->theme_location == 'primary' ) {
        $items .= '<li><a href="'. wp_logout_url() .'">Log Out</a></li>';
    }
    /**
     * Else display login menu item.
     */
    elseif ( !is_user_logged_in() && $args->theme_location == 'primary' ) {
        $items .= '<li><a href="'. site_url('wp-login.php') .'">Log In</a></li>';
    }
    return $items;
}
Aamer Shahzad
fuente