Menggunakan WP_Query ke Query Beberapa Kategori dengan Posting Terbatas Per Kategori?


10

Saya memiliki 3 kategori dengan masing-masing 15 posting, saya ingin melakukan SATU permintaan ke db hanya membawa 5 posting pertama untuk setiap kategori, bagaimana saya bisa melakukannya?

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

Jika tidak memungkinkan, apa yang lebih efisien, mendapatkan semua posting untuk kategori induk dan mengulanginya atau membuat 3 pertanyaan berbeda?


Bagaimana Anda ingin mereka dipesan?
MikeSchinkel

baru-baru ini diterbitkan .. jadi terbaru 5 dari kategori A, barang terbaru dari Kategori B dll.
Amit

Oke, lihat jawaban saya di bawah ini
MikeSchinkel

Jawaban:


16

Apa yang Anda inginkan adalah mungkin tetapi akan meminta Anda mempelajari SQL yang ingin saya hindari kapan pun memungkinkan (bukan karena saya tidak mengetahuinya, saya adalah pengembang SQL tingkat lanjut, tetapi karena di WordPress Anda ingin menggunakan API bila memungkinkan untuk meminimalkan masalah kompatibilitas di masa depan terkait dengan perubahan struktur basis data potensial di masa depan.)

SQL dengan UNIONOperator adalah Kemungkinan

Untuk menggunakan SQL yang Anda butuhkan adalah UNIONoperator dalam kueri Anda, sesuatu seperti ini dengan asumsi siput kategori Anda "category-1", "category-1"dan "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
)

Anda dapat menggunakan SQL UNION dengan posts_joinFilter

Dengan menggunakan di atas Anda bisa langsung melakukan panggilan atau Anda dapat menggunakan posts_joinhook filter seperti berikut; perhatikan saya menggunakan PHP heredoc jadi pastikan SQL;flush kiri. Juga perhatikan saya menggunakan var global untuk memungkinkan Anda mendefinisikan kategori di luar hook dengan mendaftar siput kategori dalam array. Anda dapat meletakkan kode ini di plugin atau di functions.phpfile tema Anda :

<?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 " ;
}

Tapi Bisa Ada Efek Samping

Tentu saja menggunakan kait modifikasi permintaan seperti posts_joinselalu mengundang efek samping karena mereka bertindak secara global pada permintaan dan dengan demikian Anda biasanya perlu membungkus modifikasi Anda dalam ifyang hanya menggunakannya ketika diperlukan dan kriteria apa untuk menguji bisa rumit.

Berfokuslah pada Optimasi?

Namun, saya berasumsi bahwa pertanyaan Anda lebih menyangkut optimasi daripada tentang kemampuan melakukan permintaan 5 kali 3 teratas, bukan? Jika demikian, mungkin ada opsi lain yang menggunakan WordPress API?

Lebih baik Menggunakan API Transien untuk Caching?

Saya menganggap posting Anda tidak akan sering berubah, benar? Bagaimana jika Anda menerima tiga (3) permintaan klik secara berkala dan kemudian cache hasilnya menggunakan API Transients ? Anda akan mendapatkan kode yang dapat dipelihara dan kinerja hebat; sedikit lebih baik daripada UNIONpermintaan di atas karena WordPress akan menyimpan daftar posting sebagai array serial dalam satu catatan wp_optionstabel.

Anda dapat mengambil contoh berikut dan memasukkannya ke root situs web Anda test.phpuntuk mengujinya:

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

Ringkasan

Sementara ya Anda bisa melakukan apa yang Anda minta menggunakan UNIONkueri SQL dan posts_joinkait filter yang mungkin lebih baik Anda tawarkan menggunakan caching dengan Transients API .

Semoga ini membantu?


2
Caching melalui transien adalah hal yang baik untuk mengurangi dampak pada situs.
hakre

1
@ Mike ide bagus untuk menggunakan Transients.
Chris_O

@ Mike, jika saya tinggal di benua Anda, saya akan mengambil kelas dengan Anda! Terima kasih lagi!
Amit

@Amit: LOL! :-)
MikeSchinkel

1
bisakah Anda juga menyimpan transient tanpa batas waktu dan kemudian membilasnya di save_post? ada contoh yang baik (menggunakan kait edit_term) dalam codex
helgatheviking

1

WP_Query()tidak mendukung sesuatu seperti First X For Each Cat . Alih-alih WP_Query()Anda dapat menggunakan get_posts()pada masing-masing kategori Anda, jadi katakan tiga kali:

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

$posts sekarang berisi lima posting pertama untuk setiap kategori.


bukankah itu 3 hit ke db? Saya ingin tahu apakah Anda dapat melakukannya dalam 1 hit karena saya pikir itu lebih efisien.
Amit

baik itu untuk apa db, kan? meminta data dari itu. db dibuat untuk hal-hal seperti itu. mungkin lebih cepat daripada menjalankan kueri sql rumit yang Anda minta. jangan takut untuk menggunakan barang-barang itu. jika merusak situs Anda, laporkan di sini.
hakre

mm .. mengerti, saya tidak tahu banyak tentang efisiensi php / mysql / db (ingin membaca lebih lanjut), yakin lebih sedikit hit lebih baik dan kemudian parsing hasilnya sendiri.
Amit

1
baik, benar, umumnya lebih banyak lebih dan lebih sedikit lebih sedikit. Tapi coba dan uji dulu. Semakin "lunak" perangkat lunak Anda, semakin besar potensi yang dimilikinya untuk optimisasi. Jadi lebih baik belajar sambil bekerja, karena pada akhirnya Anda akan menulis perangkat lunak yang lebih baik lebih cepat dan lebih baik menulis perangkat lunak lebih cepat.
hakre

0

Saya tidak tahu cara untuk mendapatkan lima posting pertama untuk masing-masing kategori dalam satu permintaan. Jika Anda hanya akan memiliki 45 posting, lalu tekan database sekali dan dapatkan lima posting Anda untuk setiap kategori mungkin merupakan pendekatan yang paling efisien. Memukul database tiga kali dan menggabungkan hasilnya bukanlah hal yang buruk.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.