Cómo seleccionar publicaciones con etiquetas/categorías específicas en WordPress

5 minutos de lectura

avatar de usuario
yoavf

Esta es una pregunta muy específica con respecto a mysql como se implementó en WordPress.

Estoy tratando de desarrollar un complemento que muestre (seleccione) publicaciones que tengan ‘etiquetas‘ y pertenecen a ‘ específicoscategorías‘ (ambos múltiples)

Me dijeron que es imposible debido a la forma en que se almacenan las categorías y las etiquetas:

  1. wp_posts contiene una lista de publicaciones, cada publicación tiene un “ID”
  2. wp_terms contiene una lista de términos (tanto categorías como etiquetas). Cada término tiene un TERM_ID
  3. wp_term_taxonomy tiene una lista de términos con sus TERM_ID y tiene una definición de taxonomía para cada uno de ellos (ya sea una categoría o una etiqueta)
  4. wp_term_relationships tiene asociaciones entre términos y publicaciones

¿Cómo puedo unirme a las mesas para obtener todas las publicaciones con etiquetas “Nuclear”? y ¿”Ofertas” que también pertenecen a la categoría “Categoría1”?

avatar de usuario
eric

Te malentendí. Pensé que querías Nuclear o Deals. Lo siguiente debería darle solo Nuclear y Ofertas.

select p.*
from wp_posts p, wp_terms t, wp_term_taxonomy tt, wp_term_relationship tr,
wp_terms t2, wp_term_taxonomy tt2, wp_term_relationship tr2
wp_terms t2, wp_term_taxonomy tt2, wp_term_relationship tr2

where p.id = tr.object_id and t.term_id = tt.term_id and tr.term_taxonomy_id = tt.term_taxonomy_id

and p.id = tr2.object_id and t2.term_id = tt2.term_id and tr2.term_taxonomy_id = tt2.term_taxonomy_id

and p.id = tr3.object_id and t3.term_id = tt3.term_id and tr3.term_taxonomy_id = tt3.term_taxonomy_id

and (tt.taxonomy = 'category' and tt.term_id = t.term_id and t.name="Category1")
and (tt2.taxonomy = 'post_tag' and tt2.term_id = t2.term_id and t2.name="Nuclear")
and (tt3.taxonomy = 'post_tag' and tt3.term_id = t3.term_id and t3.name="Deals")

avatar de usuario
eric

Prueba esto:

select p.*
from wp_posts p, 
wp_terms t, wp_term_taxonomy tt, wp_term_relationship tr
wp_terms t2, wp_term_taxonomy tt2, wp_term_relationship tr2

where p.id = tr.object_id
and t.term_id = tt.term_id
and tr.term_taxonomy_id = tt.term_taxonomy_id

and p.id = tr2.object_id
and t2.term_id = tt2.term_id
and tr2.term_taxonomy_id = tt2.term_taxonomy_id

and (tt.taxonomy = 'category' and tt.term_id = t.term_id and t.name="Category1")
and (tt2.taxonomy = 'post_tag' and tt2.term_id = t2.term_id and t2.name in ('Nuclear', 'Deals'))

Esencialmente, estoy empleando 2 copias de las tablas secundarias pertinentes: términos, term_taxonomy y term_relationship. Una copia aplica la restricción ‘Categoría 1’, la otra la restricción ‘Nuclear’ o ‘Deals’.

Por cierto, ¿qué tipo de proyecto es este con publicaciones sobre acuerdos nucleares? ¿Estás tratando de incluirnos en alguna lista del gobierno? 😉

  • Esta es una solución fantástica.

    – Lenín Zapata

    25 de junio de 2019 a las 6:17

Qué estructura de base de datos asquerosa.

De todos modos, haría algo como esto (tenga en cuenta que prefiero EXISTS a las uniones, pero puede volver a escribirlas como uniones si lo desea; la mayoría de los analizadores de consultas las colapsarán en el mismo plan de consulta de todos modos). Puede que tenga que hacer algunos malabarismos adicionales de una forma u otra para que funcione…

SELECT *
  FROM wp_posts p
 WHERE EXISTS( SELECT *
                 FROM wp_term_relationship tr
                WHERE tr.object_id = p.id
                  AND EXISTS( SELECT *
                                FROM wp_term_taxonomy tt
                               WHERE tt.term_taxonomy_id = tr.term_taxonomy_id
                                 AND tt.taxonomy         = 'category'
                                 AND EXISTS( SELECT *
                                               FROM wp_terms t
                                              WHERE t.term_id = tt.term_id
                                                AND t.name    = "Category1" 
                                           )
                            )
                  AND EXISTS( SELECT *
                                FROM wp_term_taxonomy tt
                               WHERE tt.term_taxonomy_id = tr.term_taxonomy_id
                                 AND tt.taxonomy         = 'post_tag'
                                 AND EXISTS( SELECT *
                                               FROM wp_terms t
                                              WHERE t.term_id = tt.term_id
                                                AND t.name    = "Nuclear" 
                                           )
                                 AND EXISTS( SELECT *
                                               FROM wp_terms t
                                              WHERE t.term_id = tt.term_id
                                                AND t.name    = "Deals" 
                                           )
                            )
            )

avatar de usuario
scott gottreu

Así que probé ambas opciones en mi base de datos de WordPress. Busqué la categoría “Tecnología” en mis publicaciones con las etiquetas “Perl” Y “Programación”.

Eric funcionó una vez que agregué una coma faltante en la declaración de selección inicial. Devolvió 3 registros. El problema es que la sección que busca “post_tag” en realidad funciona como una opción OR. Una de mis publicaciones solo tenía una etiqueta, no ambas. También sería bueno hacer el SELECT DISTINCT.

Probé la versión de Matt, pero seguía devolviendo un juego vacío. Puedo tratar de “hacer malabarismos” con eso.

Gracias @Eric, ¡funciona! Solo algunas correcciones de código para futuras referencias:

  • las primeras declaraciones seleccionadas pierden una coma después de wp_term_relationship tr2
  • En la misma declaración de selección se debe cambiar lo siguiente:
wp_terms t2, wp_term_taxonomy tt2, wp_term_relationship 

tr2

debiera ser

wp_terms t3, wp_term_taxonomy tt3, wp_term_relationship 

tr3

Realmente una gran respuesta … me ayudó mucho …

gran bcoz. ¡Me dio un enfoque básico para construir mi consulta compleja!

una pequeña corrección, para usuarios listos como yo 🙂

“wp_term_relationship” dará ‘no existe error’ .. use wp_term_relationships ya que es el nombre correcto de la tabla.

gracias eric

¿Ha sido útil esta solución?