Una richiesta comune, in particolare per coloro che hanno creato tipi di post personalizzati come "News" o "Eventi", consiste nell'aggiungere un collegamento alla loro pagina di archivio del tipo di post nel loro menu di navigazione. Attualmente, tuttavia, questo può essere fatto solo inserendo manualmente l'URL dell'archivio del tipo di post. Oltre ad essere abbastanza poco elegante, questa soluzione ha alcuni inconvenienti: non appare sempre come "corrente", se cambi la tua struttura permalink potrebbe interrompere il link, aggiungere manualmente gli URL è noioso e il link non appare come ' corrente 'quando su un post di quel tipo di messaggio.
In questo tutorial ti mostrerò come produrre un plug-in che crea una meta-box sulla tua Aspetto -> Pagina menu che ti consente di aggiungere collegamenti all'archivio di tipo post. Questi collegamenti non soffrono degli inconvenienti sopra menzionati.
Questo plugin si chiamerà 'My Post Type Archive Links' e, a tale scopo, prima creerai una cartella chiamata my-post-tipo-archivio-link sotto il tuo / Wp-content / plugins / cartella e all'interno che creano un file my-post-tipo-archivio-links.php. Questo file è il file plugin principale. Lo avvolgeremo in una classe - questo è semplicemente così non dobbiamo preoccuparci dei nostri nomi di funzioni che si scontrano con WordPress o altri plugin: abbiamo semplicemente bisogno di assicurarci che il nostro nome di classe sia unico. Aggiungi il seguente a my-post-tipo-archivio-links.php
Pagina del menu per aggiungere collegamenti all'archivio di tipo post Autore: Stephen Harris Autore URI: http://profiles.wordpress.org/users/stephenh1988/ * / class My_Post_Type_Archive_Link // Tutto andrà qui My_Post_Type_Archive_Link :: load (); ?>
Tutto in questo tutorial siederà all'interno di quella classe.
Quando viene caricato il file del plugin, verrà generato il metodo di classe caricare()
. Questo metodo sarà responsabile dell'aggiunta di azioni e filtri su vari hook di WordPress. Analizzeremo ciascuno di essi nei passaggi successivi, ma fornirà anche un utile sommario. Aggiungi il seguente metodo alla nostra classe:
funzione pubblica load () // Funzione Hook per aggiungere il metabox alla pagina Menu add_action ('admin_init', array (__ CLASS __, 'add_meta_box')); // Javascript per la meta box add_action ('admin_enqueue_scripts', array (__ CLASS __, 'metabox_script')); // callback Ajax per creare voci di menu e aggiungerlo al menu add_action ('wp_ajax_my-add-post-type-archive-links', array (__CLASS__, 'ajax_add_post_type')); // Assegna l'elemento del menu l'url appropriato add_filter ('wp_setup_nav_menu_item', array (__ CLASS __, 'setup_archive_item')); // Crea il collegamento all'archivio del tipo di post 'corrente' add_filter ('wp_nav_menu_objects', array (__ CLASS __, 'maybe_make_current'));
Riassumiamo cosa stanno facendo ognuna di queste parti:
admin_enqueue_scripts
aggancia per accodare il nostro file JavaScript. Il nostro JavaScript, quando si fa clic su "aggiungi al menu", attiverà una richiesta AJAX.corrente-menu-item
'viene aggiunto al link del tipo di post appropriato.Per prima cosa definiamo il nostro add_meta_box
metodo, che chiama semplicemente la funzione WordPress add_meta_box ()
. I dettagli di questa funzione sono stati trattati molte volte in precedenza, ma se non sei sicuro di poterlo leggere nelle pagine del Codex.
funzione pubblica add_meta_box () add_meta_box ('post-type-archives', __ ('Post Types', 'my-post-type-archive-links'), array (__ CLASS __, 'metabox'), 'nav-menus' , 'laterale', 'basso');
Successivamente definiamo la funzione di callback della meta-box che è responsabile della visualizzazione degli interni del metabox:
funzione pubblica metabox () global $ nav_menu_selected_id; // Ottieni i tipi di post $ post_types = get_post_types (array ('public' => true, '_ builtin = = false),' object ');?>
value =""name =" add-post-type-menu-item "/>
Questo metodo ottiene semplicemente tutti i tipi di post pubblici personalizzati con get_post_types ()
e quindi scorre attraverso di loro per creare un elenco di checkbox. Ogni casella di controllo ha il nome del tipo di post come valore. Nel prossimo passaggio aggiungiamo alcuni javascript che verranno attivati quando un utente fa clic sul pulsante "Aggiungi al menu".
Vogliamo solo accodare il nostro JavaScript su Aspetto -> Pagina di amministrazione del menu. Abbiamo usato il admin_enqueue_scripts
hook che si attiva solo sulle pagine di amministrazione e passa l'hook della pagina come argomento. Il gancio per l'aspetto -> la pagina del menu è nav-menus.php. Dopo aver accodato il nostro script, usiamo wp_localize_script
per rendere il nonce disponibile nel nostro JavaScript. Lo includiamo nella richiesta AJAX per aiutare a verificare che l'azione fosse intesa.
funzione pubblica metabox_script ($ hook) if ('nav-menus.php'! = $ hook) return; // On Appearance> Pagina menu, script di accodamento: wp_enqueue_script ('my-post-type-archive-links-metabox', plugins_url ('/ metabox.js', __FILE__), array ('jquery')); // Aggiungi variabile nonce wp_localize_script ('my-post-type-archive-links_metabox', 'MyPostTypeArchiveLinks', array ('nonce' => wp_create_nonce ('my-add-post-type-archive-links'))));
Nel passaggio precedente il pulsante "Aggiungi al menu" ha ricevuto l'ID inviare post-type-archivio
. Ora usiamo jQuery per selezionare quel pulsante e, quando cliccato, invia una richiesta AJAX per creare la voce di menu e aggiungerla al menu. Quanto segue è l'unica parte di questo tutorial che vive al di fuori della nostra classe. Dovrebbe andare in un file chiamato metabox.js, all'interno della nostra cartella plug-in.
jQuery (document) .ready (function ($) $ ('# submit-post-type-archives'). click (function (event) event.preventDefault (); / * Ottieni caselle spuntate * / var postTypes = [ ]; $ ('# post-tipo-archive-checklist li: checked'). each (function () postTypes.push ($ (this) .val ());); / * Invia i tipi di post controllati con i nostri action, e nonce * / $ .post (ajaxurl, action: "my-add-post-tipo-archivio-link", posttypearchive_nonce: MyPostTypeArchiveLinks.nonce, post_types: postTypes, / * AJAX restituisce html da aggiungere al menu * / function (response) $ ('# menu-to-edit'). append (risposta););));
Si noti l'URL che inviamo la richiesta a: ajaxurl
. Non l'abbiamo definito da nessuna parte. È una variabile globale impostata da WordPress solo dal lato dell'amministratore che punta alla pagina che WordPress usa per gestire le richieste AJAX. Quando si fa clic sul pulsante di invio, i nomi dei tipi di post controllati, un'azione unica e nonce vengono tutti inviati a questo URL. Quando WordPress riceve la richiesta attiva il post-tipo-archive-link wp_ajax_my-add-
gancio. Il nonce è una precauzione di sicurezza per aiutare a verificare che l'azione fosse intesa.
Ora definiamo la funzione di callback AJAX ajax_add_post_type
.
funzione pubblica ajax_add_post_type () if (! current_user_can ('edit_theme_options')) die ('- 1'); check_ajax_referer ('my-add-post-type-archive-links', 'posttypearchive_nonce'); require_once ABSPATH. 'Wp-admin / include / nav-menu.php'; if (empty ($ _ POST ['post_types'])) exit; // Crea voci di menu e archivia ID nella matrice $ item_ids = array (); foreach ((array) $ _POST ['post_types'] come $ post_type) $ post_type_obj = get_post_type_object ($ post_type); se (! $ post_type_obj) continua; $ menu_item_data = array ('menu-item-title' => esc_attr ($ post_type_obj-> etichette-> nome), 'menu-item-type' => 'post_type_archive', 'menu-item-object' => esc_attr ( $ post_type), 'menu-item-url' => get_post_type_archive_link ($ post_type)); // Raccogli gli ID degli articoli. $ item_ids [] = wp_update_nav_menu_item (0, 0, $ menu_item_data); // Se c'è un errore muore qui se (is_wp_error ($ item_ids)) muore ('- 1'); // Imposta gli elementi del menu foreach ((array) $ item_ids come $ menu_item_id) $ menu_obj = get_post ($ menu_item_id); if (! empty ($ menu_obj-> ID)) $ menu_obj = wp_setup_nav_menu_item ($ menu_obj); $ menu_obj-> label = $ menu_obj-> title; // non mostra "(in sospeso)" in oggetti aggiunti ajax $ menu_items [] = $ menu_obj; // Questo ottiene l'HTML per restituirlo al menu if (! Empty ($ menu_items)) $ args = array ('after' => ", 'before' =>", 'link_after' => ", 'link_before' => ", 'walker' => nuovo Walker_Nav_Menu_Edit); echo walk_nav_menu_tree ($ menu_items, 0, (oggetto) $ args); // Finalmente non dimenticare di uscire dall'uscita;
Passiamo un po 'alla volta questa callback alla volta. Per prima cosa controlliamo i permessi dell'utente, verificiamo il nonce e carichiamo il file nav-menu.php pagina (abbiamo bisogno di alcune funzioni).
if (! current_user_can ('edit_theme_options')) die ('- 1'); check_ajax_referer (, 'posttypearchive_nonce' 'il mio post-type-archivio-Links-'); require_once ABSPATH. 'Wp-admin / include / nav-menu.php'; if (empty ($ _ POST ['post_types'])) exit;
Creiamo quindi una voce di menu per ogni tipo di post selezionato. Per prima cosa controlliamo il tipo di messaggio che abbiamo ricevuto verificando il valore restituito da get_post_type_object ()
. Possiamo ottenere il collegamento all'archivio con la funzione get_post_type_archive_link ()
Le voci di menu sono di fatto post di tipo "nav_menu_item
'con post meta incorporato, compresi i campi relativi a'url
','genere
' e 'oggetto
'. Gli oggetti 'genere
'è normalmente'costume
','post_type
' o 'tassonomia
'- ma dovremo impostare il suo valore a'post_type_archive
'. Gli oggetti 'oggetto
"il valore meta è normalmente utilizzato solo per le voci di"post_type
' o 'tassonomia
'digita e fa riferimento al tipo di post o alla tassonomia a cui fa riferimento il link. Lo useremo per memorizzare il tipo di post del link di archivio.
// Crea voci di menu e archivia ID nella matrice $ item_ids = array (); foreach ((array) $ _POST ['post_types'] come $ post_type) $ post_type_obj = get_post_type_object ($ post_type); se (! $ post_type_obj) continua; $ menu_item_data = array ('menu-item-title' => esc_attr ($ post_type_obj-> etichette-> nome), 'menu-item-type' => 'post_type_archive', 'menu-item-object' => esc_attr ( $ post_type), 'menu-item-url' => get_post_type_archive_link ($ post_type)); // Raccogli gli ID degli articoli. $ item_ids [] = wp_update_nav_menu_item (0, 0, $ menu_item_data); // Se c'è un errore muore qui se (is_wp_error ($ item_ids)) muore ('- 1');
Successivamente, semplicemente generiamo l'HTML che verrà aggiunto al menu. Noi usiamo il $ item_ids
array per ottenere una serie di voci di menu e passare questo a una classe Walker WordPress per fare il duro lavoro per noi.
// Imposta gli elementi del menu foreach ((array) $ item_ids come $ menu_item_id) $ menu_obj = get_post ($ menu_item_id); if (! empty ($ menu_obj-> ID)) $ menu_obj = wp_setup_nav_menu_item ($ menu_obj); $ menu_obj-> label = $ menu_obj-> title; // non mostra "(in sospeso)" in oggetti aggiunti ajax $ menu_items [] = $ menu_obj; // Questo ottiene l'HTML per restituirlo al menu if (! Empty ($ menu_items)) $ args = array ('after' => ", 'before' =>", 'link_after' => ", 'link_before' => ", 'walker' => nuovo Walker_Nav_Menu_Edit); echo walk_nav_menu_tree ($ menu_items, 0, (oggetto) $ args); // Finalmente non dimenticare di uscire dall'uscita;
Sfortunatamente, a causa di un bug con WordPress, se il tipo del tuo articolo non è "tassonomia
','costume
' o 'post_type
'l'URL viene rimosso. Per contrastare questo, quando un 'post_type_archive
'link viene utilizzato in un menu, aggiungiamo manualmente l'URL. Ciò assicura anche che il link dell'archivio sia 'aggiornato' (nel caso in cui la struttura del permalink sia stata cambiata).
public function setup_archive_item ($ menu_item) if ($ menu_item-> type! = 'post_type_archive') restituisce $ menu_item; $ post_type = $ menu_item-> oggetto; $ menu_item-> url = get_post_type_archive_link ($ post_type); return $ menu_item;
Infine, dobbiamo rendere l'elemento 'corrente' quando siamo nella pagina appropriata. Voglio che il link all'archivio del tipo di post venga evidenziato come corrente se ci troviamo in quella pagina di archivio o se visualizziamo un singolo post di quel tipo. Per fare questo controllo:
is_post_type_archive ()
is_singular ()
Per rendere attuale l'oggetto, dobbiamo semplicemente aggiungere corrente-menu-item
alle classi dell'articolo in cui sono archiviate $ Item-> classi
. Quindi dobbiamo scorrere i suoi genitori nel menu e aggiungere le classi current_item_parent
e current_item_ancestor
. Diamo un'occhiata a ciascun bit individualmente:
Passiamo in rassegna ciascuno degli elementi nel menu:
funzione pubblica forse_make_current ($ items) foreach ($ items as $ item) // Qui è dove controlliamo la voce return $ items;
Se l'oggetto non è 'post_type_archive
"o se lo è, ma non vogliamo che sia" attuale ", saltiamo semplicemente sull'elemento successivo. Ricorda che per i nostri link di archivio, il tipo di post è memorizzato come oggetto dell'oggetto. Quindi dentro per ciascuno
ciclo continuo:
if ('post_type_archive'! = $ item-> type) continua; $ post_type = $ oggetto-> oggetto; se (! is_post_type_archive ($ post_type) &&! is_singular ($ post_type)) continua;
Se vogliamo renderlo attuale, gli diamo la classe appropriata e poi prendiamo i suoi genitori nel menu. I genitori di una voce di menu sono memorizzati come post meta con la meta chiave _menu_item_menu_item_parent
.
// Crea articolo corrente $ item-> current = true; $ item-> classes [] = 'current-menu-item'; // Ottieni gli antenati della voce di menu: $ _anc_id = (int) $ item-> db_id; $ Active_ancestor_item_ids = array (); while (($ _anc_id = get_post_meta ($ _anc_id, '_menu_item_menu_item_parent', true)) &&! in_array ($ _anc_id, $ active_ancestor_item_ids)) $ active_ancestor_item_ids [] = $ _anc_id;
Quindi passiamo in rassegna le voci del menu e forniamo ai genitori e agli antenati "attuali" le classi appropriate.
// Passare in rassegna gli oggetti e fornire agli antenati e ai genitori la classe appropriata foreach ($ items as $ key => $ parent_item) $ classes = (array) $ parent_item-> classes; // Se la voce di menu è genitore if ($ parent_item-> db_id == $ item-> menu_item_parent) $ classes [] = 'current-menu-parent'; $ articoli [$ chiave] -> current_item_parent = true; // Se la voce di menu è un antenato se (in_array (intval ($ parent_item-> db_id), $ active_ancestor_item_ids)) $ classes [] = 'current-menu-ancestor'; $ items [$ key] -> current_item_ancestor = true; $ items [$ key] -> classes = array_unique ($ classes);
Mettendo insieme quella funzione:
funzione pubblica forse_make_current ($ items) foreach ($ items as $ item) if ('post_type_archive'! = $ item-> type) continua; $ post_type = $ oggetto-> oggetto; se (! is_post_type_archive ($ post_type) &&! is_singular ($ post_type)) continua; // Crea articolo corrente $ item-> current = true; $ item-> classes [] = 'current-menu-item'; // Ottieni gli antenati della voce di menu: $ _anc_id = (int) $ item-> db_id; $ Active_ancestor_item_ids = array (); while (($ _anc_id = get_post_meta ($ _anc_id, '_menu_item_menu_item_parent', true)) &&! in_array ($ _anc_id, $ active_ancestor_item_ids)) $ active_ancestor_item_ids [] = $ _anc_id; // Effettua il ciclo attraverso gli antenati e dai loro foreach classe 'antenato' o 'genitore' ($ items come $ key => $ parent_item) $ classes = (array) $ parent_item-> classes; // Se la voce di menu è genitore if ($ parent_item-> db_id == $ item-> menu_item_parent) $ classes [] = 'current-menu-parent'; $ articoli [$ chiave] -> current_item_parent = true; // Se la voce di menu è un antenato se (in_array (intval ($ parent_item-> db_id), $ active_ancestor_item_ids)) $ classes [] = 'current-menu-ancestor'; $ items [$ key] -> current_item_ancestor = true; $ items [$ key] -> classes = array_unique ($ classes); restituisce $ articoli;
Non resta che andare alla pagina di amministrazione dei plug-in e attivare il plug-in.
C'è sempre spazio per il miglioramento. Ad esempio, con un po 'di jQuery è possibile aggiungere un link' Seleziona tutto 'sotto le caselle di controllo o visualizzare un simbolo' caricamento 'mentre AJAX è in fase di elaborazione. Ora questo plugin non è la soluzione più semplice, ma funziona bene ed evita le insidie della semplice aggiunta di un collegamento personalizzato. Il plug-in di cui sopra nella sua interezza può essere trovato sul mio GitHub. Se avete commenti o suggerimenti, sentitevi liberi di lasciare un commento o contattarmi via Twitter.