Aggiungere programmaticamente un menu di navigazione e le sue voci
Attraverso le funzioni API, voglio definire un nuovo menu di navigazione, selezionarlo nel tema corrente e poi inserire alcune Pagine come voci di menu. Questo deve essere fatto per esempio durante l'attivazione di un tema.
Attraverso un processo (moderatamente doloroso) di reverse engineering degli inserimenti e aggiornamenti del database dopo aver configurato manualmente il menu di navigazione e le voci, ho assemblato i seguenti passaggi, dove 'footer-nav' è lo slug ID del menu di navigazione che sto creando:
if (!term_exists('footer-nav', 'nav_menu')) {
$menu = wp_insert_term('Footer nav', 'nav_menu', array('slug' => 'footer-nav'));
// Seleziona questo menu nel tema corrente
update_option('theme_mods_'.get_current_theme(), array("nav_menu_locations" => array("primary" => $menu['term_id'])));
// Inserisce una nuova pagina
$page = wp_insert_post(array('post_title' => 'Blog',
'post_content' => '',
'post_status' => 'publish',
'post_type' => 'page'));
// Inserisce una nuova voce di menu
$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');
}
Questo sembra funzionare, ma:
- è un modo robusto ed elegante di farlo?
- mi sta sfuggendo qualcosa di totalmente ovvio che potrebbe fare tutto questo in una sola riga di codice?

Forse ti ho frainteso, ma perché non usare wp_create_nav_menu()
?
Ad esempio, questo è ciò che faccio per creare un menu personalizzato per BuddyPress quando rilevo che BP è attivo:
$menuname = $lblg_themename . ' BuddyPress Menu';
$bpmenulocation = 'lblgbpmenu';
// Il menu esiste già?
$menu_exists = wp_get_nav_menu_object( $menuname );
// Se non esiste, creiamolo.
if( !$menu_exists){
$menu_id = wp_create_nav_menu($menuname);
// Impostiamo i link predefiniti di BuddyPress e li aggiungiamo al 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'));
// Prendiamo le posizioni del tema e assegniamo il nostro menu appena creato
// alla posizione del menu BuddyPress.
if( !has_nav_menu( $bpmenulocation ) ){
$locations = get_theme_mod('nav_menu_locations');
$locations[$bpmenulocation] = $menu_id;
set_theme_mod( 'nav_menu_locations', $locations );
}

Non conoscevo questa funzione. Sì, immagino che renderà il codice sopra molto più breve. Suppongo che dovrei andare oltre il Codex e immergermi nel codice vero e proprio, dato che trovo che le funzioni dell'API siano spesso, come in questo caso, troppo di basso livello. Grazie!

@julien_c se il problema è risolto, segnalo come tale per permettere a chi verrà dopo di te di beneficiare della tua esperienza qui.

Voglio solo testarlo nella vita reale per essere sicuro che faccia ciò che voglio. Ricorderò di segnarlo come risolto non appena avrò finito!

Se trovi funzioni utili come queste che non sono presenti nel codex, è una buona idea aggiungerle (evviva il wiki) =p

Scusa se ci ho messo così tanto a verificare che funzionasse nel mio caso. Risposta accettata! Inoltre, tu stai definendo voci di menu come link personalizzati, ho aggiunto una risposta qui sotto per definire link a pagine (che saranno più robusti rispetto a cambiamenti di URL, ad esempio).

http://hookr.io/3.9.1/actions/do_action/wp_create_nav_menu/

Ho alcuni problemi con la risposta accettata - questo non significa che sia sbagliata, ma pubblicherò il mio codice qui sotto che secondo me potrebbe dare un risultato migliore per alcune persone, dato che avevo la stessa domanda ma volevo ottenere lo stesso risultato con meno codice.
Innanzitutto, il codice sopra crea elementi di navigazione di tipo "URL", il che va bene per alcuni, ma io voglio collegarmi a PAGINE, non a URL perché questa è una funzionalità importante delle navigazioni di WordPress e i clienti inevitabilmente spostano le cose, quindi non uso mai il tipo di elemento di navigazione URL.
Inoltre, il codice pubblicato gestisce solo un array piatto di elementi figli. Ho creato una funzione per dichiarare ricorsivamente i nuovi elementi di navigazione, memorizzando i loro metadati restituiti (principalmente l'ID dopo la creazione nel loop) e un parametro per accettare i figli.
Basta modificare $nav_items_to_add
e il resto viene gestito ricorsivamente. Ci sono 3 chiavi obbligatorie in ogni array. Innanzitutto, la chiave dell'array è lo slug, quindi 'shop' => array( ... )
è ciò che vuoi per una pagina con lo slug shop
. ['title']
è il modo in cui l'elemento di navigazione sarà etichettato nel front end. path
è il percorso della pagina all'interno della gerarchia delle pagine di WordPress, quindi è identico allo slug se la pagina è un genitore di primo livello, e se shop
fosse un figlio di home
allora sarebbe 'path' => 'home/shop'
.
L'ultima chiave opzionale dell'array è ['parent']
dove puoi dichiarare un'altra chiave nell'array come genitore di quella corrente. È importante notare che gli elementi vengono aggiunti ricorsivamente, quindi il genitore deve esistere prima di provare a creare un figlio. Ciò significa che la dichiarazione dovrebbe avvenire per l'elemento di navigazione genitore prima dei suoi figli.
$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' => 'Negozio',
'path' => 'shop',
),
'shop_l2' => array(
'title' => 'Negozio',
'path' => 'shop',
'parent' => 'shop',
),
'cart' => array(
'title' => 'Carrello',
'path' => 'shop/cart',
'parent' => 'shop',
),
'checkout' => array(
'title' => 'Pagamento',
'path' => 'shop/checkout',
'parent' => 'shop',
),
'my-account' => array(
'title' => 'Il Mio Account',
'path' => 'shop/my-account',
'parent' => 'shop',
),
'lost-password' => array(
'title' => 'Password Dimenticata',
'path' => 'shop/my-account/lost-password',
'parent' => 'my-account',
),
'edit-address' => array(
'title' => 'Modifica Il Mio Indirizzo',
'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')
);
}
}

Come complemento alla risposta di ZaMoose, ecco come creare una voce di menu di tipo "Pagina" (non una personalizzata):
wp_update_nav_menu_item($menu_id, 0, array('menu-item-title' => 'Chi siamo',
'menu-item-object' => 'page',
'menu-item-object-id' => get_page_by_path('about')->ID,
'menu-item-type' => 'post_type',
'menu-item-status' => 'publish'));
Supponendo che tu conosca solo lo slug della pagina, ad esempio.

Per aggiungere una voce di menu programmaticamente, puoi agganciarti al filtro wp_nav_menu_items
. Inserisci il codice qui sotto nel file functions.php del tuo tema per aggiungere una voce di login/logout nel menu principale. 'Primary' è il nome/ID del menu registrato.
/**
* Aggiunge una voce di login/logout nel menu principale.
* ====================================================
*/
add_filter( 'wp_nav_menu_items', 'lunchbox_add_loginout_link', 10, 2 );
function lunchbox_add_loginout_link( $items, $args ) {
/**
* Se il menu principale è impostato e l'utente è loggato.
*/
if ( is_user_logged_in() && $args->theme_location == 'primary' ) {
$items .= '<li><a href="'. wp_logout_url() .'">Logout</a></li>';
}
/**
* Altrimenti mostra la voce di login.
*/
elseif ( !is_user_logged_in() && $args->theme_location == 'primary' ) {
$items .= '<li><a href="'. site_url('wp-login.php') .'">Login</a></li>';
}
return $items;
}
