Legg til Post Type Arkiv Lenker til Menyen

En vanlig forespørsel, spesielt for de som har opprettet egendefinerte innleggstyper som "Nyheter" eller "Hendelser", er å legge til en kobling til arkivsiden for posttypen deres på navigasjonsmenyen. For øyeblikket kan dette imidlertid bare gjøres ved å legge inn postadressen for arkiv av posttype manuelt. Bortsett fra å være ganske inelegant, har denne løsningen noen ulemper: det virker ikke alltid som «nåværende», hvis du endrer din permalinkstruktur, kan det ødelegge lenken, manuelt å legge til nettadressene er kjedelig og lenken vises ikke som " nåværende "når på et innlegg av den post typen.

I denne opplæringen vil jeg vise deg hvordan du lager et plugin som lager en meta-boks på din utseende -> menyside som lar deg legge til arkivlister i posttype. Disse koblingene lider ikke av ulempene nevnt ovenfor.


Trinn 1 Opprette et plugin

Dette pluginet vil bli kalt 'My Post Type Archive Links', og til det formål skal du først opprette en mappe som heter my-post-typearkiv-koblinger under din / Wp-content / plugins / mappe, og inne som lager en fil my-post-type-arkiv-links.php. Denne filen er den viktigste pluginfilen. Vi skal pakke det inn i en klasse - dette er rett og slett slik at vi ikke trenger å bekymre oss for våre funksjonsnavn i sammenheng med WordPress eller andre plugins: vi må bare sørge for at klassenavnet vårt er unikt. Legg til følgende til my-post-type-arkiv-links.php

  Menyside for å legge til posttype arkivlenker Forfatter: Stephen Harris Forfatter URI: http://profiles.wordpress.org/users/stephenh1988/ * / class My_Post_Type_Archive_Link // Alt skal gå her My_Post_Type_Archive_Link :: load (); ?>

Alt i denne opplæringen vil sitte inne i den klassen.


Trinn 2 Laster inn pluggen

Når pluginfilen er lastet, vil den branne klassemetoden laste(). Denne metoden vil være ansvarlig for å legge til handlinger og filtre på ulike WordPress-kroker. Vi går gjennom hver av dem i de påfølgende trinnene, men det gir også et nyttig sammendrag. Legg til følgende metode i vår klasse:

 offentlig funksjon last () // Hook funksjon for å legge metaboxet til menysiden add_action ('admin_init', array (__ KLASS __, 'add_meta_box'))); // Javascript for metakassen add_action ('admin_enqueue_scripts', array (__ KLASS __, 'metabox_script')); // Ajax tilbakeringing for å lage menyelement og legge til i menyen add_action ('wp_ajax_my-add-post-type-arkiv-linker', array (__CLASS__, 'ajax_add_post_type')); // Tilord menyelementet riktig url add_filter ('wp_setup_nav_menu_item', array (__ KLASSE __, 'setup_archive_item')); // Lag posttype arkivlänk 'nåværende' add_filter ('wp_nav_menu_objects', array (__ KLASS __, 'maybe_make_current')); 

La oss oppsummere hva hver av disse delene gjør:

  1. Legg til en meta-boks - Ganske selvforklarende. Den krokede funksjonen vil være ansvarlig for å legge til meta-boksen.
  2. Enqueue JavaScript - Vi bruker admin_enqueue_scripts krok for å benytte vår JavaScript-fil. Vår JavaScript, når "Add to menu" er klikket, vil utløse en AJAX-forespørsel.
  3. AJAX tilbakeringing - Denne funksjonen er ansvarlig for håndtering av AJAX-forespørselen ovenfor. Det vil lage menyelementene og legge dem til på menyen.
  4. Menyelement oppsett - Dette sikrer at når arkivlenken vises på menyen, peker den riktig på posttypens arkiv.
  5. Kanskje gjør nåværende - Når en meny vises, sendes elementene gjennom et filter, så sørger vi for at klassen 'gjeldende menypost'legges til den aktuelle posttypekoblingen.

Trinn 3 Legge til metaboxet

Først definerer vi vår add_meta_box metode, som bare kaller WordPress-funksjonen add_meta_box (). Detaljer om denne funksjonen har blitt dekket mange ganger før, men hvis du er usikker, kan du lese den på Codex-sidene.

 offentlig funksjon add_meta_box () add_meta_box ('post-type-arkiver', __ ('Posttyper', 'My-post-type-arkiv-linker'), array (__ KLASS __, 'metabox'), 'nav-menyer' , 'side', 'lav'); 

Deretter definerer vi meta-box-tilbakeringingsfunksjonen som er ansvarlig for visning av metaboxens indre:

 offentlig funksjon metabox () global $ nav_menu_selected_id; // Få posttyper $ post_types = get_post_types (array ('public' => true, '_ builtin' => false), 'object');?>  

value =""name =" add-post-type-meny-element "/>

Denne metoden får rett og slett alle offentlige tilpassede posttyper med get_post_types () og deretter sløyer seg gjennom dem for å lage en liste med avmerkingsbokser. Hver avkrysningsboks har navnet på posttypen som sin verdi. I neste trinn legger vi til noe javascript som vil bli utløst når en bruker klikker på knappen "Legg til i menyen".


Trinn 4 JavaScript

Vi ønsker bare å benytte vår JavaScript på utseende -> Meny admin siden. Vi har brukt admin_enqueue_scripts krok som brenner bare på admin sider og passerer sidens krok som et argument. Kroken for Utseende -> Menysiden er nav-menus.php. Etter enqueueing vårt skript vi bruker wp_localize_script for å gjøre nonce tilgjengelig i vår JavaScript. Vi inkluderer den i AJAX-forespørselen for å bekrefte at handlingen var ment.

 offentlig funksjon metabox_script ($ hook) if ('nav-menus.php'! = $ hook) returnere; // På utseende> Menyside, enqueue script: wp_enqueue_script ('min-post-type-arkiv-linker_metabox', plugins_url ('/ metabox.js', __FILE__), array ('jquery')); // Legg til ikke-variabel wp_localize_script ('my-post-type-archive-links_metabox', 'MyPostTypeArchiveLinks', array ('nonce' => wp_create_nonce ('min-add-post-type-arkiv-linker')); 

I forrige trinn ble "Add to Menu" -knappen gitt ID-en sende-post-type-arkiv. Vi bruker nå jQuery til å målrette den knappen, og når du klikker, sender du en AJAX-forespørsel for å opprette menyelementet og legge det til i menyen. Følgende er den eneste delen av denne opplæringen som lever utenfor vår klasse. Det skal gå i en fil som heter metabox.js, i vår plugin-mappe.

 jQuery (dokument) .ready (funksjon ($) $ ('# send-post-type-arkiver'). klikk (funksjon (hendelse) event.preventDefault (); / * Hent avkrysningsbokser * / var postTypes = [ ]; $ ('# posttype arkiv-sjekkliste li: merket'). hver (funksjon () postTypes.push ($ (dette) .val ());); / * Send merkede posttyper med vår handling, og ikke-* / $ .post (ajaxurl, handling: "min-add-post-type-arkivkoblinger", posttypearchive_nonce: MyPostTypeArchiveLinks.nonce, post_types: postTypes, / * AJAX returnerer html for å legge til i menyen * / funksjon (svar) $ ('# meny for redigering'). legge til (svar););));

Legg merke til nettadressen vi sender forespørselen til: ajaxurl. Vi har ikke definert det hvor som helst. Det er en global variabel satt av WordPress bare på admin side som peker til siden som WordPress bruker til å håndtere AJAX-forespørsler. Når send-knappen klikkes, blir navnene på de merkede posttypene, en unik handling og ikke alle sendt til denne nettadressen. Når WordPress mottar forespørselen, utløser den wp_ajax_my-add-post-type-arkiv-koblinger kroken. Nonce er en sikkerhetsforanstaltning for å bekrefte at handlingen var ment.


Trinn 5 AJAX-tilbakeringingen

Vi definerer nå AJAX tilbakeringingsfunksjonen ajax_add_post_type.

 offentlig funksjon ajax_add_post_type () if (! current_user_can ('edit_theme_options')) dø ('- 1'); check_ajax_referer ('min-add-post-type-arkiv-koblinger', 'posttypearchive_nonce'); require_once ABSPATH. 'WP-admin / includes / nav-menu.php'; hvis (tomt ($ _ POST ['post_types'])) avslutte; // Lag menyelementer og lagre IDer i array $ item_ids = array (); foreach ((array) $ _POST ['post_types'] som $ post_type) $ post_type_obj = get_post_type_object ($ post_type); hvis (! $ post_type_obj) fortsett; $ menu_item_data = array ('meny-item-title' => esc_attr ($ post_type_obj-> etiketter-> navn), 'menypunkttype' => 'post_type_archiv', 'menypunkt-objekt' => esc_attr $ post_type), 'menu-item-url' => get_post_type_archive_link ($ post_type)); // Samle varenes ID-er. $ item_ids [] = wp_update_nav_menu_item (0, 0, $ menu_item_data);  // Hvis det oppstod en feil, dør her hvis (is_wp_error ($ item_ids)) dør ('- 1'); // Sett opp menyelementer foreach ((array) $ item_ids som $ menu_item_id) $ menu_obj = get_post ($ menu_item_id); hvis (! tomt ($ menu_obj-> ID)) $ menu_obj = wp_setup_nav_menu_item ($ menu_obj); $ menu_obj-> label = $ menu_obj-> tittel; // ikke vise "(ventende)" i ajax-lagt elementer $ menu_items [] = $ menu_obj;  // Dette får HTML til å returnere det til menyen hvis (! Tomt ($ menu_items)) $ args = array ('after' => ", 'before' =>", 'link_after' => " 'link_before' => ", 'walker' => ny Walker_Nav_Menu_Edit); ekko walk_nav_menu_tree ($ menu_items, 0, (object) $ args);  // Endelig ikke glem å avslutte exit; 

La oss gå gjennom denne tilbakeringingen litt om gangen. Først sjekker vi brukerens tillatelser, verifiserer nonce og laster inn nav-menu.php side (vi trenger noen av funksjonene).

 hvis (! current_user_can ('edit_theme_options')) dør ('- 1'); check_ajax_referer ( 'min-add-post-type-arkiv-lenker', 'posttypearchive_nonce'); require_once ABSPATH. 'WP-admin / includes / nav-menu.php'; hvis (tomt ($ _ POST ['post_types'])) avslutte;

Vi lager deretter et menyelement for hver valgt posttype. Vi kontrollerer først posttypen vi mottok, ved å sjekke verdien returnert av get_post_type_object (). Vi kan hente arkivlenken med funksjonen get_post_type_archive_link ()

Menyelementer er faktisk innlegg av posttype 'nav_menu_item'med innebygd postmeta, inkludert felt relatert til'url','type'og'gjenstand'. Gjenstandene 'type'er normalt'tilpasset','post_type'eller'taksonomi'- men vi skal sette sin verdi til'post_type_archive'. Gjenstandene 'gjenstand'meta verdi brukes normalt bare til elementer av'post_type'eller'taksonomi'type og refererer til posttype eller taksonomi som linken refererer til. Vi bruker dette til å lagre posttypen for arkivlenken.

 // Lag menyelementer og lagre IDer i array $ item_ids = array (); foreach ((array) $ _POST ['post_types'] som $ post_type) $ post_type_obj = get_post_type_object ($ post_type); hvis (! $ post_type_obj) fortsett; $ menu_item_data = array ('meny-item-title' => esc_attr ($ post_type_obj-> etiketter-> navn), 'menypunkttype' => 'post_type_archiv', 'menypunkt-objekt' => esc_attr $ post_type), 'menu-item-url' => get_post_type_archive_link ($ post_type)); // Samle varenes ID-er. $ item_ids [] = wp_update_nav_menu_item (0, 0, $ menu_item_data);  // Hvis det oppstod en feil, dør her hvis (is_wp_error ($ item_ids)) dør ('- 1');

Deretter genererer vi bare HTML-koden som blir lagt til i menyen. Vi bruker $ ITEM_IDS array for å få en rekke menyelementer og sende dette til en WordPress walker-klasse for å gjøre det harde arbeidet for oss.

 // Sett opp menyelementer foreach ((array) $ item_ids som $ menu_item_id) $ menu_obj = get_post ($ menu_item_id); hvis (! tomt ($ menu_obj-> ID)) $ menu_obj = wp_setup_nav_menu_item ($ menu_obj); $ menu_obj-> label = $ menu_obj-> tittel; // ikke vise "(ventende)" i ajax-lagt elementer $ menu_items [] = $ menu_obj;  // Dette får HTML til å returnere det til menyen hvis (! Tomt ($ menu_items)) $ args = array ('after' => ", 'before' =>", 'link_after' => " 'link_before' => ", 'walker' => ny Walker_Nav_Menu_Edit); ekko walk_nav_menu_tree ($ menu_items, 0, (object) $ args);  // Endelig ikke glem å avslutte exit;

Trinn 6 Menyelementet

Dessverre, på grunn av en feil med WordPress, hvis varens type er ikke "taksonomi','tilpasset'eller'post_type'URL-adressen blir fjernet. For å motvirke dette, når en 'post_type_archive'lenken brukes i en meny, legger vi manuelt til URL-adressen. Dette sikrer også at arkivlenken er oppdatert (hvis din permalinkstruktur er endret).

 offentlig funksjon setup_archive_item ($ menu_item) hvis ($ menu_item-> type! = 'post_type_archive') returnere $ menu_item; $ post_type = $ menu_item-> objekt; $ menu_item-> url = get_post_type_archive_link ($ post_type); returner $ menu_item; 

Trinn 7 Gjør Link Current

Til slutt må vi gjøre varen 'nåværende' når vi er på den aktuelle siden. Jeg vil at posttypen arkivkobling skal utheves som nåværende hvis vi er på arkivsiden, eller ser på et enkelt innlegg av den typen. For å gjøre dette, sjekker jeg:

  • is_post_type_archive ()
  • is_singular ()

For å gjøre varen oppdatert, må vi bare legge til gjeldende menypost til elementets klasser som er lagret i $ Element-> klasser. Vi må da gå gjennom foreldrene i menyen og legge til klassene current_item_parent og current_item_ancestor. La oss se på hver bit enkeltvis:

Vi løper gjennom hvert av elementene i menyen:

 offentlig funksjon maybe_make_current ($ items) foreach ($ elementer som $ item) // Dette er hvor vi sjekker varen returner $ elementer; 

Hvis varen ikke er av 'post_type_archive'eller hvis det er, men vi vil ikke at det skal gjøre det' nåværende ', hopper vi bare videre til neste gjenstand. Husk at for våre arkivkoblinger lagres posttypen som objektets objekt. Så inne i for hver løkke:

 hvis ('post_type_archive'! = $ item-> type) fortsett; $ post_type = $ item-> object; hvis (! is_post_type_archive ($ post_type) &&! is_singular ($ post_type)) fortsett;

Hvis vi ønsker å gjøre det nåværende, gir vi den den riktige klassen og tar deretter foreldrene sine i menyen. Et menyelements forelder er lagret som postmeta med metatast _menu_item_menu_item_parent.

 // Gjør vare gjeldende $ item-> current = true; $ item-> classes [] = 'nåværende meny-element'; // Få menyelementets forfedre: $ _anc_id = (int) $ item-> db_id; $ Active_ancestor_item_ids = array (); mens (($ _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; 

Vi løser deretter menyelementene og gir de aktuelle klassene foreldrene og forfedrene til det nåværende.

 // Gå gjennom elementene og gi forfedre og foreldre riktig klasse foreach ($ elementer som $ key => $ parent_item) $ classes = (array) $ parent_item-> klasser; // Hvis menyelementet er overordnet hvis ($ parent_item-> db_id == $ item-> menu_item_parent) $ classes [] = 'nåværende-meny-overordnet'; $ elementer [$ key] -> current_item_parent = true;  // Hvis menyelementet er en forfader hvis (in_array (intval ($ parent_item-> db_id), $ active_ancestor_item_ids)) $ classes [] = 'nåværende meny-forfader'; $ items [$ key] -> current_item_ancestor = true;  $ elementer [$ key] -> classes = array_unique ($ classes); 

Setter den funksjonen sammen:

 offentlig funksjon maybe_make_current ($ items) foreach ($ elementer som $ item) if ('post_type_archive'! = $ item-> type) fortsett; $ post_type = $ item-> object; hvis (! is_post_type_archive ($ post_type) &&! is_singular ($ post_type)) fortsett; // Gjør vare gjeldende $ item-> current = true; $ item-> classes [] = 'nåværende meny-element'; // Få menyelementets forfedre: $ _anc_id = (int) $ item-> db_id; $ Active_ancestor_item_ids = array (); mens (($ _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;  // Gå gjennom forfedre og gi dem forfedre eller foreldre klasse foreach ($ elementer som $ key => $ parent_item) $ classes = (array) $ parent_item-> klasser; // Hvis menyelementet er overordnet hvis ($ parent_item-> db_id == $ item-> menu_item_parent) $ classes [] = 'nåværende-meny-overordnet'; $ elementer [$ key] -> current_item_parent = true;  // Hvis menyelementet er en forfader hvis (in_array (intval ($ parent_item-> db_id), $ active_ancestor_item_ids)) $ classes [] = 'nåværende meny-forfader'; $ items [$ key] -> current_item_ancestor = true;  $ elementer [$ key] -> classes = array_unique ($ classes);  returnere $ elementer; 

Alt som gjenstår er å gå til plugins admin siden og aktivere plugin.


Konklusjon

Det er alltid rom for forbedring. For eksempel, med en bit av jQuery kan du legge til en "Velg alle" -linken under avmerkingsboksene eller vise et "lastesymbol" mens AJAX behandles. Nå er dette pluginet ikke den enkleste løsningen - men det fungerer bra og unngår fallgruvene ved å bare legge til en egendefinert lenke. Ovennevnte plugin i det hele finnes på min GitHub. Hvis du har kommentarer eller forslag, vær så snill å legge igjen en kommentar eller kontakt meg via Twitter.