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


10

Eu tenho 3 categorias com cada 15 postagens, quero fazer UMA consulta ao banco de dados trazendo apenas 5 primeiras postagens para cada categoria, como 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, obter todas as postagens da categoria pai e percorrer todas elas ou criar 3 consultas diferentes?


Como você quer que eles sejam pedidos?
MikeSchinkel

publicado recentemente .. tão 5 mais recentes da categoria A, coisas mais recentes da categoria B etc.
Amit

Ok, veja minha resposta abaixo
MikeSchinkel

Respostas:


16

O que você deseja é possível, mas exigirá que você mergulhe no SQL, que eu gosto de evitar sempre que possível (não porque eu não o conheça, sou um desenvolvedor avançado de SQL, mas porque no WordPress você deseja usar a API sempre que possível para minimizar futuros problemas de compatibilidade relacionados a possíveis alterações na estrutura do banco de dados.)

SQL com um UNIONoperador é uma possibilidade

Para usar o SQL que você precisa é de um UNIONoperador em sua consulta, algo como isto assumindo suas lesmas categoria são "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 posts_joinfiltro

Usando o acima, você pode simplesmente fazer a chamada diretamente ou pode usar um posts_joingancho de filtro da seguinte maneira; note que estou usando um heredoc PHP, portanto, certifique-se de que ele SQL;esteja nivelado à esquerda. Observe também que usei uma var global para permitir que você defina as categorias fora do gancho, listando as lesmas de categoria em uma matriz. Você pode colocar esse código em um plug-in ou no functions.phparquivo 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_joinsempre convida a efeitos colaterais, pois eles agem globalmente em consultas e, portanto, você geralmente precisa agrupar suas modificações de uma maneira ifque só a use quando necessário e que critério testar pode ser complicado.

Concentre-se na otimização?

No entanto, suponho que sua pergunta esteja mais relacionada à otimização do que à possibilidade de fazer uma consulta das cinco principais vezes, certo? Se for esse o caso, talvez haja outras opções que usam a API do WordPress?

Melhor usar a API de transientes para cache?

Presumo que suas postagens não sejam alteradas com frequência, correto? E se você aceitar a consulta de três (3) resultados periodicamente e depois armazenar em cache os resultados usando a API Transients ? Você obterá código sustentável e ótimo desempenho; um pouco melhor que a UNIONconsulta acima, porque o WordPress armazenará as listas de postagens como uma matriz serializada em um registro da wp_optionstabela.

Você pode pegar o exemplo a seguir e soltar na raiz do seu site como test.phppara testar isso:

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

Sumário

Embora sim, você pode fazer o que pediu usando uma UNIONconsulta SQL e o posts_joingancho de filtro. Provavelmente, é melhor oferecer o armazenamento em cache com a API Transients .

Espero que isto ajude?


2
O armazenamento em cache por transientes é uma boa coisa para reduzir o impacto no site.
hakre

11
@ Mike ótima idéia de usar os transientes.
Chris_O

@ Mike, se eu estivesse morando no seu continente, teria tido aulas com você! obrigado novamente!
Amit

@Amit: LOL! :-)
MikeSchinkel

11
você também pode salvar o transitório indefinidamente e liberá-lo em save_post? há um bom exemplo (usando gancho edit_term) no códice
helgatheviking

1

WP_Query()não suporta algo como o 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 as cinco primeiras postagens para cada categoria.


não é que 3 hits para o db? Eu queria saber se você pode fazer isso em 1 hit, porque eu pensei que é mais eficiente.
Amit

bem, é para isso que serve o db, certo? consultar os dados dele. o banco de dados é feito para essas coisas. provavelmente é mais rápido do que executar uma consulta SQL complicada que você está solicitando. não tenha medo de usar as coisas. se quebrar o seu site, denuncie-o aqui.
hakre

mm .. entendi, eu não sei muito sobre a eficiência do php / mysql / db (gostaria de ler mais), tinha certeza de que menos acessos são melhores e, em seguida, analiso o resultado pessoalmente.
Amit

11
bem, verdade, geralmente mais é mais e menos é menos. Mas tente e teste primeiro. Quanto mais ruim o seu software, maior o potencial para otimização. Então, aprenda melhor fazendo, porque, no final, você escreverá um software melhor mais rapidamente e melhor escreverá um software mais rápido.
hakre

0

Não sei como obter as cinco primeiras postagens para cada uma das categorias em uma única consulta. Se você tiver apenas 45 postagens, acessar o banco de dados uma vez e obter suas cinco postagens para cada categoria é provavelmente a abordagem mais eficiente. Atingir o banco de dados três vezes e combinar os resultados não é uma coisa ruim.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.