it-swarm-es.com

¿Usar WP_Query para consultar varias categorías con publicaciones limitadas por categoría?

Tengo 3 categorías con cada 15 publicaciones, quiero hacer UNA consulta a la base de datos y traer solo 5 primeras publicaciones para cada categoría, ¿cómo puedo hacerlo?

$q = new WP_Query(array( 'post__in' => array(2,4,8), 'posts_per_page' => **FIRST_5_OF_EACH_CAT** ));

En caso de que no sea posible, ¿qué es más eficiente, obtener todas las publicaciones para la categoría principal y recorrerlas o crear 3 consultas diferentes?

10
Amit

Lo que desea es posible pero requerirá que profundice en SQL, que me gusta evitar siempre que sea posible (no porque no lo sepa, soy un desarrollador avanzado de SQL, sino porque en WordPress desea para usar la API siempre que sea posible para minimizar futuros problemas de compatibilidad relacionados con futuros cambios potenciales en la estructura de la base de datos.)

SQL con un operador UNION es una posibilidad

Para usar SQL, lo que necesita es un operador UNION en su consulta, algo como esto, suponiendo que las babosas de su categoría son "category-1", "category-1" y "category-3":

SELECT * FROM wp_posts WHERE ID IN (
  SELECT tr.object_id
  FROM wp_terms t 
  INNER JOIN wp_term_taxonomy tt ON t.term_id = tt.term_id
  INNER JOIN wp_term_relationships tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
  WHERE tt.taxonomy='category' AND t.slug='category-1'
  LIMIT 5

  UNION

  SELECT tr.object_id
  FROM wp_terms t 
  INNER JOIN wp_term_taxonomy tt ON t.term_id = tt.term_id
  INNER JOIN wp_term_relationships tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
  WHERE tt.taxonomy='category' AND t.slug='category-2'
  LIMIT 5

  UNION

  SELECT tr.object_id
  FROM wp_terms t 
  INNER JOIN wp_term_taxonomy tt ON t.term_id = tt.term_id
  INNER JOIN wp_term_relationships tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
  WHERE tt.taxonomy='category' AND t.slug='category-3'
  LIMIT 5
)

Puede usar SQL UNION con un posts_join Filter

Usando lo anterior, puede simplemente hacer la llamada directamente o puede usar un gancho de filtro posts_join como se muestra a continuación; note que estoy usando un PHP heredoc así que asegúrese de que el SQL; esté al ras de la izquierda. También tenga en cuenta que utilicé una var global para permitirle definir las categorías fuera del gancho al enumerar las categorías de las barras en una matriz. Puede colocar este código en un complemento o en el archivo functions.php de su tema:

<?php
global $top_5_for_each_category_join;
$top_5_for_each_category_join = array('category-1','category-2','category-3');
add_filter('posts_join','top_5_for_each_category_join',10,2);
function top_5_for_each_category_join($join,$query) {
  global $top_5_for_each_category_join;
  $unioned_selects = array();
  foreach($top_5_for_each_category_join as $category) {
    $unioned_selects[] =<<<SQL
SELECT object_id
FROM wp_terms t
INNER JOIN wp_term_taxonomy tt ON t.term_id = tt.term_id
INNER JOIN wp_term_relationships tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
WHERE tt.taxonomy='category' AND t.slug='{$category}'
LIMIT 5
SQL;
  }
  $unioned_selects = implode("\n\nUNION\n\n",$unioned_selects);
  return $join . " INNER JOIN ($unioned_selects) categories ON wp_posts.ID=categories.object_id " ;
}

Pero puede haber efectos secundarios

Por supuesto, el uso de los enlaces de modificación de consultas como posts_join siempre invita a los efectos secundarios, ya que actúan globalmente en las consultas y, por lo tanto, generalmente es necesario envolver sus modificaciones en una if que solo la use cuando sea necesario y los criterios a los que se puede realizar la prueba pueden ser difíciles.

¿Centrarse en la optimización en su lugar?

Sin embargo, asumo que su pregunta está relacionada con más sobre la optimización que sobre la posibilidad de hacer una consulta entre los 5 primeros 3 tiempos, ¿verdad? Si ese es el caso, entonces tal vez hay otras opciones que utilizan la API de WordPress?

¿Es mejor utilizar la API de Transients para el almacenamiento en caché?

Supongo que tus publicaciones no cambiarán tan a menudo, ¿correcto? ¿Qué sucede si acepta los tres (3) resultados de consultas periódicamente y luego almacena en caché los resultados utilizando la API Transients ? Obtendrás un código mantenible y un gran rendimiento; un poco mejor que la consulta UNION anterior porque WordPress almacenará las listas de publicaciones como una matriz serializada en un registro de la tabla wp_options.

Puede tomar el siguiente ejemplo y colocarlo en la raíz de su sitio web como test.php para probar esto:

<?php

$timeout = 4; // 4 hours
$categories = array('category-1','category-2','category-3');

include "wp-load.php";
$category_posts = get_transient('top5_posts_per_category');
if (!is_array($category_posts) || count($category_posts)==0) {
  echo "Hello Every {$timeout} hours!";
  $category_posts = array();
  foreach($categories as $category) {
    $posts = get_posts("post_type=post&numberposts=5&taxonomy=category&term={$category}");
    foreach($posts as $post) {
      $category_posts[$post->ID] = $post;
    }
  }
  set_transient('top5_posts_per_category',$category_posts,60*60*$timeout);
}
header('Content-Type:text/plain');
print_r($category_posts);

Resumen

Mientras que sí, puede hacer lo que solicitó utilizando una consulta SQL UNION y el enganche de filtro posts_join que probablemente sea mejor ofrecer utilizando el almacenamiento en caché con el API de Transients en su lugar.

¿Espero que esto ayude?

15
MikeSchinkel

WP_Query() no admite algo como First X For Each Cat . En lugar de WP_Query() puede usar get_posts() en cada una de sus categorías, por decir tres veces:

<?php
$posts      = array():
$categories = array(2,4,8);
foreach($categories as $cat) {
  $posts[] = get_posts('numberposts=5&offset=1&category='.$cat);
}
?>

$posts ahora contiene las primeras cinco publicaciones para cada categoría.

1
hakre

No conozco una manera de obtener las primeras cinco publicaciones para cada una de las categorías en una sola consulta. Si alguna vez va a tener solo 45 publicaciones, entonces el acceso más eficiente a una base de datos y obtener sus cinco publicaciones para cada categoría es probablemente el método más eficiente. Sin embargo, golpear la base de datos tres veces y combinar los resultados no es algo malo.

0
Bernard Chen