Adicionar programaticamente um menu de Navegação e itens de menu

41

Por meio das funções da API, desejo definir um novo menu de navegação , selecioná-lo no tema atual e inserir algumas páginas como itens de menu. Isso deve ser feito, por exemplo, em uma ativação de tema.

Por meio de um processo (moderadamente doloroso) de engenharia reversa, o banco de dados insere e atualiza após a configuração manual do menu e dos itens de Navegação. estou criando:

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');
}

Isso parece funcionar, mas:

  • é uma maneira robusta e elegante de fazer isso?
  • Estou perdendo algo totalmente óbvio que faria tudo isso em uma linha de código?
julien_c
fonte

Respostas:

43

Eu posso estar entendendo mal você, mas por que não usar wp_create_nav_menu()?

Por exemplo, é isso que faço para criar um menu personalizado do BuddyPress quando detecto a BP como ativa:

    $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
fonte
Eu não sabia sobre essa função. Sim, acho que isso tornará o código acima muito mais curto. Acho que devo ir além do Codex e mergulhar no código real, pois acho que as funções da API geralmente são, como neste caso, muito baixas. Obrigado!
21712
@julien_c se isso for resolvido, marque-o como tal para permitir que aqueles que vierem depois de você se beneficiem da sua experiência aqui.
mor7ifer
Eu só quero testá-lo na vida real, então tenho certeza de que faz o que quero. Vou lembrar de marcá-lo como resolvido assim que terminar!
21712
3
Se você ver funções úteis como estes que não estão no códice, é uma boa idéia para adicioná-los (yay wiki) = p
Tom J Nowell
Desculpe, demorei tanto tempo para verificar se funcionava no meu caso. Resposta aceita! Além disso, você está definindo itens de menu de links personalizados. Adicionei uma resposta abaixo para definir links de página (que serão mais robustos às alterações de URL, por exemplo).
21712
12

Como complemento ao analisador do ZaMoose, veja como você criaria um item de menu "Tipo de página " (não um item " 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'));

Supondo que você conheça apenas a página lesada, por exemplo.

julien_c
fonte
9

Tenho alguns problemas com a resposta aceita - isso não está errado, mas postarei meu próprio código abaixo, que considero que pode ter um resultado melhor para algumas pessoas, já que tive a mesma pergunta, mas queria fazer o mesmo coisa com menos código.

Primeiro, o código acima cria itens de navegação do tipo "URL", o que é bom para algumas pessoas, mas eu quero vincular a PAGES, não URLs, porque esse é um recurso importante das navegações do WordPress e os clientes inevitavelmente movem as coisas para que eu nunca use o URL tipo de item de navegação.

Além disso, apenas uma matriz plana de filhos é tratada pelo código publicado. Eu criei uma função para declarar recursivamente os novos itens de navegação, armazenando os metadados retornados (principalmente o ID após serem criados no loop) e um parâmetro para aceitar filhos.

Basta editar $nav_items_to_adde o restante é tratado recursivamente. Existem 3 chaves necessárias em cada matriz. Primeiro, a chave da matriz é a lesma, assim 'shop' => array( ... )como o que você deseja para uma página com a lesma shop. ['title']é a maneira como o item de navegação será identificado no front end. pathé o caminho para a página dentro da hierarquia de páginas do WordPress; portanto, isso é idêntico à lesma se a página for um pai de nível superior e, se shopfosse filha home, seria 'path' => 'home/shop'.

A última chave opcional da matriz é ['parent']onde você pode declarar outra chave na matriz como pai da atual. É importante observar que os itens são adicionados recursivamente, para que o pai precise existir antes de tentar criar um filho. Isso significa que a declaração deve acontecer para o item de navegação pai antes de ser filho.

    $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
fonte
2

Para adicionar um item de menu programaticamente. você pode conectar ao wp_nav_menu_itemsfiltro. coloque o código abaixo em seu tema functions.php para adicionar o item de menu Login / Logout no menu principal. 'Primário' é o nome / ID do menu 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
fonte