Jak sortować posty w ramach taksonomii WordPress
Opublikowany: 2020-12-18Do tej pory Nelio opublikował kilka wtyczek w repozytorium WordPress.org. Niektóre z nich są całkowicie bezpłatne i oferują eleganckie rozwiązania typowych problemów, takie jak np. Nelio Maps, która umożliwia wstawianie mapy Google na swoje strony lub posty utworzone za pomocą Gutenberga, oraz Nelio Compare Images, który umożliwia wstawianie blok do, jak sama nazwa wskazuje, porównania dwóch obrazów obok siebie. Opublikowaliśmy również kilka wtyczek premium, które pomagają nam płacić rachunki: Nelio Content i Nelio A / B Testing.
Jeśli spojrzysz na naszą witrynę, zobaczysz, że nasze dwie wtyczki premium zajmują ważne miejsce, ponieważ obie mają kilka stron docelowych i cenowych, a obie mają powiązaną bazę wiedzy, w której użytkownicy mogą znaleźć odpowiedzi na swoje pytania. Dzisiaj porozmawiamy o tym, jak stworzyliśmy strony dokumentacji dla Nelio A/B Testing i Nelio Content oraz o tym, co musieliśmy zrobić, aby uporządkować pytania według naszych upodobań.
Jak tworzyć niestandardowe typy postów w WordPress
Najpierw utwórzmy niestandardowy typ posta, aby śledzić wszystkie pytania, które będzie zawierać nasza baza wiedzy. Możesz zobaczyć wynik na poniższym zrzucie ekranu, na którym znajduje się instancja tego nowego typu postu dla bazy wiedzy Nelio A/B Testing:

Aby utworzyć niestandardowy typ posta, wystarczy użyć funkcji register_post_type w WordPressie w następujący sposób:
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' );i voila! Być może już wiesz, że istnieją wtyczki, takie jak Zaawansowane pola niestandardowe, które pomagają tworzyć i dostosowywać interfejs niestandardowych typów postów, ale niekoniecznie polecam zaimplementowanie tak prostego przykładu.
Przy okazji, jeśli zastanawiasz się, gdzie należy umieścić ten fragment, nie przegap naszego samouczka na temat dostosowywania WordPressa za pomocą niestandardowych wtyczek.
Jak stworzyć nową taksonomię w celu uporządkowania treści
Nasza baza wiedzy jest podzielona na „Tematy” i „Słowa kluczowe”, jak widać na poniższym zrzucie ekranu:

Tematy i słowa kluczowe są odpowiednikami kategorii i tagów, które masz domyślnie w postach WordPress. Skupmy się tylko na tym pierwszym, bo to drugie jest dokładnie takie samo.
Jak już możesz sobie wyobrazić, temat to niestandardowa taksonomia, którą stworzyliśmy dla naszego niestandardowego typu treści. Aby dodać nową taksonomię do typu posta WordPress, wystarczy użyć funkcji register_taxonomy w następujący sposób:
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' ); Funkcja jest dość prosta w użyciu. Najpierw nazwij taksonomię ( w naszym przykładzie nab_topic ). Następnie określasz typy postów, z którymi jest powiązany (mamy tylko jeden: nab_help ). Na koniec dodajesz kilka dodatkowych argumentów, aby dostosować taksonomię. Rezultatem jest nowa taksonomia, za pomocą której można stworzyć konkretne tematy , które musimy kategoryzować pytania w naszej bazie wiedzy:

Jak sortować posty w taksonomii
Teraz, gdy mamy niestandardową taksonomię i możemy dodawać pytania do każdego tworzonego przez nas tematu , jak posortować te pytania w ramach określonego tematu? Cóż, obawiam się, że będziemy musieli trochę kodować…
Spojrzenie na bazę danych
WordPress i jego relacje z Twoimi postami są przechowywane w czterech różnych tabelach bazy danych:
-
wp_termszawiera wszystkie terminy, które tworzysz w ramach określonej taksonomii. Na przykład w naszej taksonomii tematów znajdują się terminy takie jak Pytania ogólne , Zgodność oraz Płatności i rozliczenia . -
wp_termmetapomaga nam przechowywać dodatkowe dane związane z każdym terminem. Jest bardzo podobny dowp_postmeta. -
wp_term_taxonomywiąże każdy termin wwp_termsz jego definiującą taksonomią. Tak więc na przykład ta tabela śledzi fakt, że termin Pytanie ogólne jest w rzeczywistości instancją taksonomiinab_topic. -
wp_term_relationshipswiąże każdy termin (term_taxonomy_id) z postami, które „zawiera” (object_id). Na przykład ta tabela mówi nam, że pytanie o to, czym Testowanie Nelio A/B jest pytaniem ogólnym (i dlatego pojawia się podczas przeglądania tematu).
WordPress 2.5 dodał nowe pole numeryczne w tabeli wp_term_relationships , term_order , które pozwala nam określić pozycję, jaką dany element zajmuje w taksonomii. Brzmi to jak kandydat, którego szukaliśmy, aby uporządkować nasze pytania w ramach naszego tematu… ale jest pewien haczyk: o ile wiem, WordPress nie oferuje standardowego mechanizmu do (1) definiowania wartości pola term_order i ( 2) używać go do sortowania postów w ramach określonej taksonomii. Naprawmy to!
Jak używać pola term_order do sortowania postów zawartych w taksonomii?
Załóżmy, że byliśmy w stanie w jakiś sposób ustawić żądane wartości term_order , jak widać na poniższym zrzucie ekranu:

Domyślnie WordPress ignoruje to pole, a posty nie są sortowane w interfejsie użytkownika. Dlatego trzy pytania pokazane na powyższym zrzucie ekranu nie są odpowiednio posortowane.
Na szczęście możemy łatwo powiedzieć WordPressowi, aby używał tego pola do sortowania postów według niego. Po prostu użyj filtra posts_orderby , aby dostosować zapytanie, które pobiera posty należące do określonego terminu, tak aby zawierało żądanie sortowania:
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 ); } Wszystko, co robi poprzedni fragment, to sprawdzenie, czy wysyłamy zapytanie do określonej taksonomii (w naszym przypadku nab_topic ), a kiedy to robimy, dodajemy klauzulę ORDER BY w zapytaniu, dzięki czemu końcowy wynik jest uporządkowany według wartości Atrybut term_order znaleziony w tabeli $wpdb->term_relationships :


Implementacja interfejsu użytkownika do porządkowania zawartości taksonomii
Na koniec pozostaje nam tylko jedna rzecz do zrobienia. W poprzedniej sekcji założyliśmy, że jesteśmy w stanie jakoś ustawić poprawną wartość w polu term_order . Ale jak? Czy jest gdzieś ekran lub opcja, aby ustawić tę wartość w sposób przyjazny dla użytkownika? O ile wiem, nie ma. Ale możemy go stworzyć.
Moim zdaniem najlepszym rozwiązaniem tego problemu byłoby posiadanie interfejsu użytkownika, który pozwala mi wybrać taksonomię, którą chcę posortować, a następnie przeciągnąć i upuścić wszystkie pytania, aby ustalić ich kolejność. Coś takiego, idź:

Aby osiągnąć pożądany efekt musimy wykonać następujące kroki:
- Zarejestruj nową stronę na pulpicie WordPress
- Zaimplementuj funkcję, która wyrenderuje selektor taksonomii i posty w wybranej taksonomii
- Dodaj mały fragment kodu JavaScript, aby interfejs był responsywny
- Utwórz nowe wywołanie zwrotne, aby zapisać powstałe zamówienie, gdy skończymy sortować posty
Możesz uczynić ten interfejs tak skomplikowanym, jak tylko chcesz, korzystając z nowego stosu programistycznego WordPress. Ale dzisiaj przedstawię szybkie i brudne rozwiązanie, które załatwi sprawę.
Jak już mówiłem, pierwszą rzeczą jest zarejestrowanie strony, na której umieścimy interfejs. Możemy to łatwo zrobić za pomocą funkcji add_submenu_page podczas akcji 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 jest również niezwykle prosta:
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>'; } Jak widać, po prostu pobieramy wszystkie terminy z taksonomii nab_topic , a następnie polegamy na trzech funkcjach pomocniczych, aby (1) renderować selektor, (2) renderować pytania w każdej kategorii i (3) dodawać mały skrypt, aby wszystko dynamiczny.
Renderowanie selektora jest tak proste, jak iterowanie każdego terminu i renderowanie 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>'; }Aby wyświetlić pytania, które mamy w każdym z terminów taksonomii, uruchamiamy zapytanie do bazy danych i iterujemy przez wszystkie z nich:
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>'; } Zauważ, że ta funkcja renderuje div , który wykorzystuje slug bieżącego $term jako swój identyfikator, grupuje pytania w jeszcze innym elemencie div , a na końcu zawiera przycisk Zapisz . Wszystkie te szczegóły przydadzą się, gdy w końcu wyrenderujemy skrypt, który łączy naszą aplikację.
Gdy wszystko będzie gotowe, musimy po prostu dodać trochę magii JavaScript. W szczególności ten szybki i brudny interfejs użytkownika wymaga dwóch skryptów ( jquery i jquery-ui ) do zaimplementowania funkcji przeciągania i upuszczania, a następnie następującego fragmentu kodu 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 ); } } } )() Na pierwszy rzut oka poprzedni fragment może wydawać się skomplikowany. Ale obiecuję: tak nie jest. Po pierwsze, sprawiamy, że nasze pytania są „sortowalne” za pomocą funkcji sortable jQuery UI. Następnie do naszego select komponentu dodajemy słuchacza, który pokazuje/ukrywa odpowiedni zestaw pytań za pomocą funkcji pomocniczej. Na koniec dodajemy detektory click do naszych przycisków Zapisz , aby po ich kliknięciu przez użytkownika kolejność sortowania pytań była przechowywana w bazie danych.
Jak widać, zapisanie tego nowego zamówienia odbywa się za pomocą żądania AJAX, co oznacza, że musimy zaimplementować jego odpowiednik wywołania zwrotnego PHP:
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(); }I to wszystko! Całkiem łatwe, co?
W podsumowaniu
WordPress nie oferuje domyślnego mechanizmu sortowania postów w ramach określonej taksonomii. Ale jest dobrze! Możemy je zaimplementować sami: wszystko, co musimy zrobić, aby posortować posty w taksonomii WordPress, to ustawić pole term_order w tabeli bazy danych term_relationships , a następnie rozszerzyć WordPress o filtr posts_orderby , aby używał tego pola.
Na koniec przedstawiliśmy prosty interfejs użytkownika do łatwego wypełniania pola term_order poprzez przeciąganie i upuszczanie postów zawartych w określonej taksonomii.
Mam nadzieję, że podobał Ci się ten samouczek, a jeśli tak, podziel się nim ze znajomymi i współpracownikami. I jak zawsze, jeśli masz jakieś pytania, zostaw je w sekcji komentarzy poniżej, a chętnie się do nich odpowiem.
Polecane zdjęcie Steve'a Johnsona na Unsplash.
