Cum să sortați postările într-o taxonomie WordPress
Publicat: 2020-12-18Până acum Nelio a publicat mai multe plugin-uri în depozitul WordPress.org. Unele dintre ele sunt complet gratuite și oferă soluții elegante la probleme comune, cum ar fi, de exemplu, Nelio Maps, care vă permite să inserați o hartă Google în paginile sau postările create cu Gutenberg și Nelio Compare Images, care vă permite să inserați un bloc pentru, după cum sugerează și numele, să compare două imagini una lângă alta. De asemenea, am publicat câteva plugin-uri premium care ne ajută să plătim facturile: Nelio Content și Nelio A/B Testing.
Dacă aruncați o privire pe site-ul nostru, veți vedea că cele două plugin-uri premium ale noastre ocupă un loc proeminent, deoarece ambele au câteva pagini de destinație și prețuri și ambele au o bază de cunoștințe aferentă unde utilizatorii pot găsi răspunsul la întrebările lor. Astăzi vom vorbi despre cum am creat paginile de documentație pentru Nelio A/B Testing și Nelio Content și despre ce a trebuit să facem pentru a sorta întrebările după bunul plac.
Cum să creați tipuri de postări personalizate în WordPress
Mai întâi, să creăm un tip de postare personalizat pentru a ține evidența tuturor întrebărilor pe care le va conține baza noastră de cunoștințe. Puteți vedea rezultatul în următoarea captură de ecran, unde există o instanță a acestui nou tip de postare pentru baza de cunoștințe a Nelio A/B Testing:

Pentru a crea un tip de postare personalizat, tot ce trebuie să faceți este să utilizați funcția WordPress register_post_type după cum urmează:
function nelio_add_help_type() { $labels = array( 'name' => __( 'Questions', 'nelio-help' ), 'singular_name' => __( 'Question', 'nelio-help' ), 'menu_name' => __( 'Testing's Help', 'nelio-help' ), 'all_items' => __( 'All Questions', 'nelio_help' ), 'add_new_item' => __( 'Add New Question', 'nelio_help' ), 'edit_item' => __( 'Edit Question', 'nelio_help' ), 'view_item' => __( 'View Question', 'nelio_help' ), ); register_post_type( 'nab_help', array( 'capability_type' => 'post', 'labels' => $labels, 'map_meta_cap' => true, 'menu_icon' => 'dashicons-welcome-learn-more', 'public' => true, 'show_in_rest' => true, 'supports' => [ 'title', 'editor', 'author' ], ) ); } add_action( 'init', 'nelio_add_help_type' );si voila! Poate știți deja că există plugin-uri precum Advanced Custom Fields care vă ajută să creați și să personalizați interfața unui tip de postare personalizat, dar nu vă recomand neapărat să implementați un exemplu atât de simplu.
Apropo, dacă vă întrebați unde ar trebui plasat acest fragment, nu ratați tutorialul nostru despre cum să personalizați WordPress cu pluginuri personalizate.
Cum să creați o nouă taxonomie pentru a organiza conținutul
Baza noastră de cunoștințe este organizată în „Subiecte” și „Cuvinte cheie”, așa cum puteți vedea în următoarea captură de ecran:

Subiectele și cuvintele cheie sunt echivalentul categoriilor și etichetelor pe care le aveți în mod implicit în postările WordPress. Să ne concentrăm doar pe primul, deoarece cel din urmă este exact același.
După cum vă puteți imagina deja, un subiect este o taxonomie personalizată pe care am creat-o pentru tipul nostru de conținut personalizat. Pentru a adăuga o nouă taxonomie la un tip de postare WordPress, trebuie pur și simplu să utilizați funcția register_taxonomy după cum urmează:
function nelio_add_help_taxonomy() { $labels = array( 'name' => __( 'Topics', 'nelio-help' ), 'singular_name' => __( 'Topic', 'nelio-help' ), 'menu_name' => __( 'Topics', 'nelio-help' ), 'all_items' => __( 'All Topics', 'nelio_help' ), /* ... */ ); register_taxonomy( 'nab_topic', [ 'nab_help' ], array( 'hierarchical' => true, 'label' => __( 'Topic', 'nelio-help' ), 'query_var' => true, 'show_admin_column' => false, 'show_ui' => true, 'show_in_rest' => true, ) ); } add_action( 'init', 'nelio_add_help_taxonomy' ); Funcția este destul de simplu de utilizat. Mai întâi, denumiți taxonomia ( nab_topic în exemplul nostru). Apoi specificați tipul (tipurile) de postare cu care se referă (avem doar unul: nab_help ). În cele din urmă, mai adăugați câteva argumente pentru a personaliza taxonomia. Rezultatul este o nouă taxonomie cu care să creăm subiectele concrete de care avem nevoie pentru a clasifica întrebările din baza noastră de cunoștințe:

Cum să sortați postările într-o taxonomie
Acum că avem o taxonomie personalizată și putem adăuga întrebări la fiecare subiect pe care îl creăm, cum sortăm acele întrebări într-un anumit subiect? Ei bine, mă tem că va trebui să codificăm puțin...
Aruncând o privire la baza de date
WordPress și relațiile lor cu postările tale sunt stocate în patru tabele diferite de baze de date:
-
wp_termsinclude toți termenii pe care îi creați într-o anumită taxonomie. De exemplu, în taxonomia subiectelor noastre, avem termeni precum Întrebări generale , Compatibilitate și Plăți și facturare . -
wp_termmetane ajută să stocăm date suplimentare legate de fiecare termen. Este destul de asemănător cuwp_postmeta. -
wp_term_taxonomyleagă fiecare termen dinwp_termscu taxonomia definitorie. Astfel, de exemplu, acest tabel ține evidența faptului că termenul Întrebare generală este de fapt o instanță a taxonomieinab_topic. -
wp_term_relationshipsraportează fiecare termen (term_taxonomy_id) la postările pe care le „conține” (object_id). De exemplu, acest tabel ne spune că întrebarea despre ce Nelio A/B Testing este o întrebare generală (și de aceea întrebarea apare când răsfoiți subiectul).
WordPress 2.5 a adăugat un nou câmp numeric în tabelul wp_term_relationships , term_order , care ne permite să specificăm poziția pe care o ocupă un anumit element în cadrul taxonomiei. Acesta pare candidatul pe care îl căutam pentru a ne sorta întrebările în cadrul subiectului nostru... dar există o captură: din câte îmi dau seama, WordPress nu oferă un mecanism standard pentru (1) defini valoarea câmpului term_order și ( 2) folosiți-l pentru a sorta de fapt postările într-o anumită taxonomie. Să reparăm asta!
Cum să utilizați câmpul term_order pentru a sorta postările incluse într-o taxonomie
Să presupunem că am reușit să setăm cumva valorile term_order dorite pe care le dorim, așa cum puteți vedea în următoarea captură de ecran:

În mod implicit, WordPress ignoră acest câmp și postările nu sunt sortate în front-end. De aceea, cele trei întrebări afișate în captura de ecran de mai sus nu sunt sortate corect.
Din fericire, putem spune cu ușurință WordPress să folosească câmpul pentru a sorta postările după el. Folosiți doar filtrul posts_orderby pentru a modifica interogarea care preia postările aparținând unui anumit termen, astfel încât să includă o solicitare de sortare:
add_filter( 'posts_orderby', 'nelio_sort_questions_in_topic', 99, 2 ); function nelio_sort_questions_in_topic( $orderby, $query ) { if ( ! nelio_is_topic_tax_query( $query ) ) return; global $wpdb; return "{$wpdb->term_relationships}.term_order ASC"; } function nelio_is_topic_tax_query( $query ) { if ( empty( $query->tax_query ) ) return; if ( empty( $query->tax_query->queries ) ) return; return in_array( $query->tax_query->queries[0]['taxonomy'], [ 'nab_topic' ], true ); } Tot ceea ce face fragmentul anterior este să verificăm dacă interogăm o anumită taxonomie (în cazul nostru, nab_topic ) și, atunci când o facem, adăugăm o clauză ORDER BY în interogare, astfel încât rezultatul final să fie ordonat după valoarea Atributul term_order găsit în $wpdb->term_relationships :


Implementarea unei interfețe cu utilizatorul pentru a ordona conținutul unei taxonomii
În sfârșit, mai avem un singur lucru de făcut. În secțiunea anterioară, am presupus că am putut seta cumva valoarea corectă în câmpul term_order . Dar cum? Există un ecran sau o opțiune undeva pentru a seta această valoare într-un mod ușor de utilizat? Din câte știu eu, nu există. Dar putem crea unul.
După părerea mea, cea mai bună soluție la această problemă ar fi să am o interfață de utilizare care să-mi permită să selectez taxonomia pe care vreau să o sortez și apoi să trageți și să plasați toate întrebările pentru a le stabili ordinea. Ceva de genul asta, du-te:

Pentru a obține efectul dorit, trebuie să implementăm următorii pași:
- Înregistrați o pagină nouă pe tabloul de bord WordPress
- Implementați funcția care va reda selectorul de taxonomie și postările din taxonomia selectată
- Adăugați un mic fragment JavaScript, astfel încât interfața de utilizare să fie receptivă
- Creați un nou apel invers pentru a salva comanda rezultată după ce am terminat de sortat postările
Puteți face această interfață cât de complicată doriți, folosind noua stivă de dezvoltare WordPress. Dar astăzi voi schița o soluție rapidă și murdară care face treaba.
După cum spuneam, primul lucru este să înregistrăm pagina în care vom pune interfața. Putem face acest lucru cu ușurință cu funcția add_submenu_page în timpul acțiunii admin_menu :
add_action( 'admin_menu', function() { add_submenu_page( 'edit.php?post_type=nab_help', 'Sort', 'Sort', 'edit_others_posts', 'nab-help-question-sorter', __NAMESPACE__ . '\render_question_sorter' ) } ); Metoda render_question_sorter este, de asemenea, extrem de simplă:
function render_question_sorter() { echo '<div class="wrap"><h1>Sort Questions</h1>'; $terms = get_terms( 'nab_topic' ); render_select( $terms ); foreach ( $terms as $term ) { render_questions_in_term( $term ); } render_script(); echo '</div>'; } După cum puteți vedea, pur și simplu recuperăm toți termenii din taxonomia nab_topic și apoi ne bazăm pe trei funcții auxiliare pentru (1) a reda selectorul, (2) a reda întrebările din fiecare categorie și (3) a adăuga un mic script pentru a face totul dinamic.
Redarea selectorului este la fel de ușoară ca iterarea fiecărui termen și redarea unei option :
function render_select( $terms ) { echo '<select>'; foreach ( $terms as $term ) { printf( '<option value="%s">%s</option>', esc_attr( $term->slug ), esc_html( $term->name ) ); } echo '</select>'; }Pentru a reda întrebările pe care le avem în fiecare termen al taxonomiei, lansăm o interogare în baza de date și iterăm prin toate:
function render_questions_in_term( $term ) { printf( '<div class="term-block" data-term->', esc_attr( $term->slug ), esc_attr( $term->term_id ) ); echo '<div class="sortable">' $query = new WP_Query( array( 'post_type' => 'nab_help', 'post_per_page' => -1, 'tax_query' => array( array( 'taxonomy' => 'nab_topic', 'field' => 'term_id', 'terms' => $term->term_id, 'orderby' => 'term_order', ), ), ) ); while ( $query->have_posts() ) { $query->the_post(); global $post; printf( '<div class="question" data-question->%s</div>', esc_attr( $post->ID ), esc_html( $post->post_title ) ); } echo '</div>'; printf( '<input type="button" data-term- value="%s" />', esc_attr( $term->term_id ), esc_attr( 'Save' ) ); echo '</div>'; } Rețineți că această funcție redă un div care folosește slug -ul actualului $term ca ID, grupează întrebările într-un alt element div și, în final, include un buton Salvare . Toate aceste detalii vor fi utile atunci când vom reda în sfârșit scriptul care conectează aplicația noastră.
Odată ce totul este gata, trebuie pur și simplu să adăugăm ceva magie JavaScript. În special, această interfață de utilizare rapidă și murdară necesită două script-uri ( jquery și jquery-ui ) pentru a implementa funcționalitatea de glisare și plasare și apoi următorul fragment JS:
( function() { // MAKE QUESTIONS SORTABLE $( '.sortable' ).sortable(); // TERM SELECTOR const select = document.getElementById( 'topic' ); const termBlocks = [ ...document.querySelectorAll( '.term-block' ) ]; select.addEventListener( 'change', showSelectedTermBlock ); // Helper function function showSelectedTermBlock() { /* ... */ } // SAVE BUTTONS [ ...document.querySelectorAll( '.term-block input[type="button"]' ) ].forEach( addButtonLogic ); // Helper function function addButtonLogic( button ) { const termId = button.getAttribute( 'data-term-id' ); button.addEventListener( 'click', () => { button.disabled = true; const selector = `div[data-term-] .question`; const ids = [ ...document.querySelectorAll( selector ) ] .map( ( question ) => question.getAttribute( 'data-question-id' ); $.ajax( { url: ajaxurl, method: 'POST', data: { action: 'nelio_save_tax_sorting', objectIds: ids, termId, }, } ).always( () => button.disable = false ); } } } )() La prima vedere, fragmentul anterior poate părea complicat. Dar promit: nu este. În primul rând, facem întrebările noastre „sortabile” utilizând funcția de sortable a jQuery UI. Apoi, adăugăm un ascultător la componenta noastră select care arată/ascunde setul adecvat de întrebări folosind o funcție de ajutor. În cele din urmă, adăugăm ascultătorii de click la butoanele noastre Salvare , astfel încât, atunci când utilizatorul face clic pe ei, ordinea în care sunt sortate întrebările să fie stocată în baza de date.
După cum puteți vedea, salvarea acestei noi comenzi se face printr-o solicitare AJAX, ceea ce înseamnă că trebuie să implementăm omologul său PHP callback:
add_action( 'wp_ajax_nelio_save_tax_sorting', __NAMESPACE__ . '\save_tax_sorting' ); function save_tax_sorting() { $term_id = isset( $_POST['termId'] ) ? absint( $_POST['termId'] : 0 ); if ( ! $term_id ) die(); $object_ids = isset( $_POST['objectIds'] ) ? $_POST['objectIds'] : []; if ( ! is_array( $object_ids ) || empty( $object_ids ) ) die(); $object_ids = array_values( array_map( 'absint', $object_ids ) ); global $wpdb; foreach ( $object_ids as $order => $object_id ) { $wpdb->update( $wpdb->term_relationships, array( 'term_order' => $order + 1 ), array( 'object_id' => $object_id, 'term_taxonomy_id' => $term_id, ), ); } die(); }Si asta e! Destul de ușor, nu?
În concluzie
WordPress nu oferă un mecanism implicit pentru a sorta postările într-o anumită taxonomie. Dar este in regula! Putem implementa unul singur: tot ce trebuie să facem pentru a sorta postările într-o taxonomie WordPress este să setăm câmpul term_order în tabelul bazei de date term_relationships și apoi să extindem WordPress cu filtrul posts_orderby , astfel încât să folosească câmpul respectiv.
În cele din urmă, am schițat o interfață simplă pentru a popula cu ușurință câmpul term_order prin glisarea și plasarea postărilor incluse într-o anumită taxonomie.
Sper că ți-a plăcut acest tutorial și, dacă ți-a plăcut, te rog să-l împărtășești prietenilor și colegilor tăi. Și, ca întotdeauna, dacă aveți întrebări, lăsați-le în secțiunea de comentarii de mai jos și voi fi bucuros să le răspund.
Imagine prezentată de Steve Johnson pe Unsplash.
