Usando o WP_Query para consultar várias categorias com postagens limitadas por categoria?

10

Eu tenho 3 categorias com cada 15 posts, eu quero fazer uma consulta para o db trazendo apenas 5 primeiros posts para cada categoria, como eu posso fazer isso?

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

Caso isso não seja possível, o que é mais eficiente, obtendo todas as postagens para a categoria pai e passando por elas ou criando 3 consultas diferentes?

    
por Amit 25.08.2010 / 22:28

3 respostas

15

O que você quer é possível, mas vai exigir que você se aprofunde no SQL que eu gostaria de evitar sempre que possível (não porque eu não saiba, eu sou um desenvolvedor de SQL avançado, mas porque no WordPress, você deseja usar a API sempre que possível para minimizar futuros problemas de compatibilidade relacionados a possíveis mudanças futuras na estrutura do banco de dados.

SQL com um operador UNION é uma possibilidade

Para usar o SQL, você precisa de um operador UNION em sua consulta, algo como isto, supondo que suas slugs de categoria sejam "category-1" , "category-1" e "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
)

Você pode usar o SQL UNION com um filtro posts_join

Usando as opções acima, você pode fazer a chamada diretamente ou usar o gancho de filtro posts_join da seguinte maneira; note que estou usando um PHP heredoc , portanto, certifique-se de que SQL; está à esquerda. Observe também que usei um var global para permitir que você defina as categorias fora do gancho listando as slugs de categoria em um array. Você pode colocar esse código em um plug-in ou no arquivo functions.php do seu 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 " ;
}

Mas pode haver efeitos colaterais

É claro que usar os ganchos de modificação de consulta como posts_join sempre solicita efeitos colaterais, pois eles agem globalmente nas consultas e, portanto, você geralmente precisa incluir as modificações em um if que só usa quando necessário e quais critérios teste para pode ser complicado.

Concentre-se na otimização em vez disso?

No entanto, suponho que sua pergunta esteja relacionada com mais sobre otimização do que com a possibilidade de fazer uma consulta top 5 de tempo 3, certo? Se for esse o caso, então talvez haja outras opções que usam a API do WordPress?

Melhor usar a API de transientes para cache?

Suponho que suas postagens não serão alteradas com frequência, correto? E se você aceitar a consulta de três (3) ocorrências periodicamente e, em seguida, armazenar os resultados em cache usando a API de transientes ? Você terá um código de fácil manutenção e ótimo desempenho; um pouco melhor que a consulta UNION acima porque o WordPress armazenará as listas de posts como um array serializado em um registro da tabela wp_options .

Você pode usar o seguinte exemplo e inserir a raiz do seu site como test.php para testar:

<?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);

Resumo

Embora você possa fazer o que solicitou usando uma consulta UNION do SQL e o gancho do filtro posts_join , provavelmente é melhor oferecer o uso do armazenamento em cache com a API de transientes em vez disso.

Espero que isso ajude?

    
por MikeSchinkel 26.08.2010 / 00:23
1

WP_Query() não suporta algo como Primeiro X para cada gato . Em vez de WP_Query() , você pode usar get_posts() em cada uma de suas categorias, por assim dizer, três vezes:

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

$posts agora contém os primeiros cinco posts para cada categoria.

    
por hakre 25.08.2010 / 22:54
0

Não conheço uma maneira de obter as cinco primeiras postagens para cada uma das categorias em uma única consulta. Se você tiver apenas 45 postagens, bater no banco de dados uma vez e obter seus cinco posts para cada categoria é provavelmente a abordagem mais eficiente. Bater o banco de dados três vezes e combinar os resultados não é uma coisa ruim.

    
por Bernard Chen 25.08.2010 / 22:38