Como classificar postagens em uma taxonomia do WordPress
Publicados: 2020-12-18Até agora, Nelio publicou vários plugins no repositório WordPress.org. Alguns deles são totalmente gratuitos e oferecem soluções elegantes para problemas comuns, como, por exemplo, o Nelio Maps, que permite inserir um mapa do Google em suas páginas ou posts criados com o Gutenberg, e o Nelio Compare Images, que permite inserir um bloco para, como o nome sugere, comparar duas imagens lado a lado. Também publicamos alguns plugins premium que nos ajudam a pagar as contas: Nelio Content e Nelio A/B Testing.
Se você der uma olhada em nosso site, verá que nossos dois plugins premium ocupam um lugar de destaque, pois ambos têm algumas páginas de destino e preços e ambos têm uma base de conhecimento relacionada, onde os usuários podem encontrar a resposta para suas perguntas. Hoje falaremos sobre como criamos as páginas de documentação do Nelio A/B Testing e do Nelio Content e o que tivemos que fazer para classificar as perguntas como quisermos.
Como criar tipos de postagem personalizados no WordPress
Primeiro, vamos criar um tipo de postagem personalizado para acompanhar todas as perguntas que nossa base de conhecimento conterá. Você pode ver o resultado na captura de tela a seguir, onde há uma instância desse novo tipo de postagem para a base de conhecimento do Nelio A/B Testing:

Para criar um tipo de postagem personalizado, tudo o que você precisa fazer é usar a função register_post_type do WordPress da seguinte maneira:
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' );e voilá! Você já deve saber que existem plugins como Advanced Custom Fields que ajudam você a criar e personalizar a interface de um tipo de postagem personalizado, mas eu não recomendo necessariamente implementar um exemplo tão simples.
A propósito, se você está se perguntando onde esse snippet deve ser colocado, não perca nosso tutorial sobre como personalizar o WordPress com plugins personalizados.
Como criar uma nova taxonomia para organizar o conteúdo
Nossa base de conhecimento está organizada em “Tópicos” e “Palavras-chave”, como você pode ver na captura de tela a seguir:

Tópicos e palavras-chave são equivalentes às categorias e tags que você tem por padrão nas postagens do WordPress. Vamos nos concentrar apenas no primeiro, pois o último é exatamente o mesmo.
Como você já pode imaginar, um Tópico é uma taxonomia personalizada que criamos para nosso tipo de conteúdo personalizado. Para adicionar uma nova taxonomia a um tipo de postagem do WordPress, basta usar a função register_taxonomy da seguinte forma:
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' ); A função é bastante simples de usar. Primeiro, você nomeia a taxonomia ( nab_topic em nosso exemplo). Em seguida, você especifica o(s) tipo(s) de postagem com o qual está relacionado (só temos um: nab_help ). Por fim, você adiciona mais alguns argumentos para personalizar a taxonomia. O resultado é uma nova taxonomia com a qual criar os Tópicos concretos que precisamos para categorizar as perguntas em nossa base de conhecimento:

Como classificar as postagens em uma taxonomia
Agora que temos uma taxonomia personalizada e podemos adicionar perguntas a cada tópico que criamos, como classificamos essas perguntas em um tópico específico? Bem, temo que teremos que codificar um pouco…
Dando uma olhada no banco de dados
O WordPress e seus relacionamentos com suas postagens são armazenados em quatro tabelas de banco de dados diferentes:
-
wp_termsinclui todos os termos que você cria dentro de uma determinada taxonomia. Por exemplo, em nossa taxonomia de tópicos , temos termos como Perguntas gerais , Compatibilidade e Pagamentos e cobrança . -
wp_termmetanos ajuda a armazenar dados adicionais relacionados a cada termo. É bastante semelhante aowp_postmeta. -
wp_term_taxonomyrelaciona cada termo emwp_termsà sua taxonomia de definição. Assim, por exemplo, esta tabela acompanha o fato de que o termo General Question é na verdade uma instância da taxonomianab_topic. -
wp_term_relationshipsrelaciona cada termo (term_taxonomy_id) aos posts que ele “contém” (object_id). Por exemplo, esta tabela nos diz que a pergunta sobre o que é Nelio A/B Testing é uma pergunta geral (e é por isso que a pergunta aparece ao navegar pelo tópico).
O WordPress 2.5 adicionou um novo campo numérico na tabela wp_term_relationships , term_order , que nos permite especificar a posição que um determinado elemento ocupa dentro da taxonomia. Isso soa como o candidato que estávamos procurando para classificar nossas perguntas dentro do nosso tópico ... mas há um problema: até onde posso dizer, o WordPress não oferece um mecanismo padrão para (1) definir o valor do campo term_order e ( 2) use-o para classificar as postagens dentro de uma determinada taxonomia. Vamos consertar isso!
Como usar o campo term_order para classificar as postagens incluídas em uma taxonomia
Vamos supor que conseguimos de alguma forma definir os valores term_order desejados que queremos, como você pode ver na captura de tela a seguir:

Por padrão, o WordPress ignora este campo e as postagens não são classificadas no front-end. É por isso que as três perguntas mostradas na captura de tela acima não estão classificadas corretamente.
Felizmente, podemos facilmente dizer ao WordPress para usar o campo para classificar as postagens por ele. Basta usar o filtro posts_orderby para ajustar a consulta que recupera os posts pertencentes a um determinado termo para que inclua uma solicitação de classificação:
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 ); } Tudo o que o snippet anterior faz é verificar se estamos consultando uma determinada taxonomia (no nosso caso, nab_topic ) e, quando o fazemos, adicionamos uma ORDER BY na consulta para que o resultado final seja ordenado pelo valor do Atributo term_order encontrado na tabela $wpdb->term_relationships :


Implementação de uma interface de usuário para ordenar o conteúdo de uma taxonomia
Finalmente, só temos uma coisa a fazer. Na seção anterior, presumimos que de alguma forma poderíamos definir o valor correto no campo term_order . Mas como? Existe uma tela ou opção em algum lugar para definir esse valor de maneira amigável? Que eu saiba, não existe. Mas podemos criar um.
Na minha opinião, a melhor solução para este problema seria ter uma UI que me permitisse selecionar a taxonomia que eu quero ordenar, e então arrastar e soltar todas as questões para estabelecer sua ordem. Algo assim, vá:

Para alcançar o efeito desejado devemos implementar os seguintes passos:
- Registre uma nova página no painel do WordPress
- Implemente a função que irá renderizar o seletor de taxonomia e os posts dentro da taxonomia selecionada
- Adicione um pequeno snippet de JavaScript para que a interface do usuário seja responsiva
- Crie um novo retorno de chamada para salvar o pedido resultante assim que terminarmos de classificar as postagens
Você pode tornar essa interface tão complicada quanto quiser, usando a nova pilha de desenvolvimento do WordPress. Mas hoje vou delinear uma solução rápida e suja que faz o trabalho.
Como eu estava dizendo, a primeira coisa é cadastrar a página onde vamos colocar a interface. Podemos fazer isso facilmente com a função add_submenu_page durante a ação 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' ) } ); O método render_question_sorter também é extremamente simples:
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>'; } Como você pode ver, nós simplesmente recuperamos todos os termos na taxonomia nab_topic e então contamos com três funções auxiliares para (1) renderizar o seletor, (2) renderizar as perguntas em cada categoria e (3) adicionar um pequeno script para fazer tudo dinâmico.
Renderizar o seletor é tão fácil quanto iterar sobre cada termo e renderizar uma 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>'; }Para renderizar as perguntas que temos em cada termo da taxonomia, lançamos uma consulta ao banco de dados e iteramos por todas elas:
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>'; } Observe que esta função renderiza um div que usa o slug do $term atual como seu ID, agrupa as perguntas em outro elemento div e, finalmente, inclui um botão Salvar . Todos esses detalhes serão úteis quando finalmente renderizarmos o script que conecta nosso aplicativo.
Assim que tudo estiver pronto, simplesmente precisamos adicionar um pouco de magia JavaScript. Em particular, essa interface de usuário rápida e suja requer dois scripts ( jquery e jquery-ui ) para implementar a funcionalidade de arrastar e soltar e, em seguida, o seguinte trecho de 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 ); } } } )() À primeira vista, o trecho anterior pode parecer complicado. Mas eu prometo: não é. Primeiro, tornamos nossas perguntas “classificáveis” usando a função sortable do jQuery UI. Em seguida, adicionamos um ouvinte ao nosso componente select que mostra/oculta o conjunto apropriado de perguntas usando uma função auxiliar. Por fim, adicionamos os ouvintes de click aos nossos botões Salvar para que, quando o usuário clicar neles, a ordem em que as perguntas são classificadas seja armazenada no banco de dados.
Como você pode ver, salvar esse novo pedido é feito por meio de uma solicitação AJAX, o que significa que precisamos implementar sua contraparte de retorno de chamada 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(); }E é isso! Bem fácil, hein?
Resumindo
O WordPress não oferece um mecanismo padrão para classificar postagens dentro de uma determinada taxonomia. Mas tudo bem! Podemos implementar um por conta própria: tudo o que precisamos fazer para classificar as postagens em uma taxonomia do WordPress é definir o campo term_order na tabela de banco de dados term_relationships e, em seguida, estender o WordPress com o filtro posts_orderby para que ele use esse campo.
Por fim, descrevemos uma interface de usuário simples para preencher facilmente o campo term_order arrastando e soltando as postagens incluídas em uma determinada taxonomia.
Espero que você tenha gostado deste tutorial e, se gostou, compartilhe com seus amigos e colegas. E, como sempre, se você tiver alguma dúvida, deixe-a na seção de comentários abaixo e ficarei feliz em abordá-la.
Imagem em destaque por Steve Johnson no Unsplash.
