Obține toate categoriile și articolele din acele categorii
Caut o soluție care să-mi permită să afișez următoarele:
Cat 1 Cat 2 Cat 3
Post 1 Post 1 Post 1
Post 2 Post 2 Post 2
Post 3 Post 3
Post 4
EDIT
Caut ceva care va necesita doar o singură interogare în baza de date! Deci dacă aveți un foreach
în codul vostru urmat de un new WP_Query
atunci nu este ceea ce caut (intenționez să pun acest cod pe pagina principală a site-ului meu).
EDIT REVIZUIT NR. 2
Nu am folosit niciodată Transient API, până astăzi când am văzut răspunsul lui @MikeSchinkel în acest articol. Acest lucru m-a inspirat să revizuiesc din nou acest post. După câteva teste, am ajuns la următoarele concluzii:
Timpul de execuție a scăzut de la ~0,07 secunde la ~0,002 secunde
Timpul de interogare a bazei de date a scăzut cu aproximativ jumătate
Cu transient, sunt executate doar 2 interogări la baza de date
Cum funcționează codul (Voi discuta doar modificările față de codul original din REVIZUIRE):
PASUL 1
Trebuie să salvăm valoarea lui $q
într-un transient, aceasta fiind valoarea care conține lista de categorii cu titlurile postărilor.
PASUL 2
Mai întâi verificăm dacă există un transient, iar dacă nu există, îl creăm. Dacă transientul există, preluăm informațiile din el.
PASUL 3
Aceste informații sunt apoi parcurse printr-un loop foreach
pentru a afișa lista cu numele categoriilor și titlurile postărilor.
PASUL 4
În prezent, transientul va fi actualizat la fiecare 12 ore. Această perioadă poate fi ajustată în funcție de nevoile dumneavoastră. Totuși, transientul va trebui șters și recreat de fiecare dată când statusul unei postări se schimbă. Acest lucru se poate întâmpla când o postare trece de la draft la publicat, când se publică o postare nouă sau când o postare este mutată la gunoi. Pentru a face acest lucru, trebuie să folosiți delete_transient
care va fi legat de transition_post_status
, acțiune care va fi declanșată de fiecare dată când statusul unei postări se schimbă.
Iată codul complet:
În fișierul functions.php
add_action( 'transition_post_status', 'publish_new_post', 10, 3 );
function publish_new_post() {
delete_transient( 'category_list' );
}
În template-ul unde doriți să afișați lista
<?php
if ( false === ( $q = get_transient( 'category_list' ) ) ) {
$args = array(
'posts_per_page' => -1
);
$query = new WP_Query($args);
$q = array();
while ( $query->have_posts() ) {
$query->the_post();
$a = '<a href="'. get_permalink() .'">' . get_the_title() .'</a>';
$categories = get_the_category();
foreach ( $categories as $key=>$category ) {
$b = '<a href="' . get_category_link( $category ) . '">' . $category->name . '</a>';
}
$q[$b][] = $a; // Creăm un array cu numele categoriilor și titlurile postărilor
}
/* Restaurăm datele originale ale postării */
wp_reset_postdata();
set_transient( 'category_list', $q, 12 * HOUR_IN_SECONDS );
}
foreach ($q as $key=>$values) {
echo $key;
echo '<ul>';
foreach ($values as $value){
echo '<li>' . $value . '</li>';
}
echo '</ul>';
}
?>
REVIZUIRE
Recent am găsit o soluție foarte ușoară care este mult mai rapidă decât alte soluții posibile. Pe site-ul meu de test, obțin un timp total de generare de doar ~0,07 secunde și doar 6 interogări la baza de date conform Query Monitor, în timp ce alte metode oferă un timp de generare de ~0,35 secunde și 50 de interogări suplimentare.
Iată o prezentare detaliată a metodei mele:
PASUL 1
Mai întâi trebuie să creați o interogare personalizată cu WP_Query
pentru a prelua toate postările publicate.
$args = array(
'posts_per_page' => -1
);
$query = new WP_Query($args);
$q = array();
while ( $query->have_posts() ) {
}
/* Restaurăm datele originale ale postării */
wp_reset_postdata();
PASUL 2
Folosind get_the_category
, preluați o listă cu toate categoriile cărora aparține o postare.
$categories = get_the_category();
foreach ( $categories as $key=>$category ) {
$b = '<a href="' . get_category_link( $category ) . '">' . $category->name . '</a>';
}
PASUL 3
Atribuiți variabile pentru titlul postării și categoriile postării
$a = '<a href="'. get_permalink() .'">' . get_the_title() .'</a>';
și
$b = '<a href="' . get_category_link( $category ) . '">' . $category->name . '</a>';
PASUL 4
Combinați aceste două variabile pentru a forma un array multidimensional
$q[$b][] = $a;
Pentru a vedea ce se întâmplă în array, pur și simplu faceți un var_dump
?><pre><?php var_dump($q); ?></pre><?php
PASUL 5
Folosind loop-uri foreach
, creați lista de postări sortate pe categorii
foreach ($q as $key=>$values) {
echo $key;
echo '<ul>';
foreach ($values as $value){
echo '<li>' . $value . '</li>';
}
echo '</ul>';
}
TOATE ÎMPREUNĂ ACUM!
Iată codul complet
<?php
$args = array(
'posts_per_page' => -1
);
$query = new WP_Query($args);
$q = array();
while ( $query->have_posts() ) {
$query->the_post();
$a = '<a href="'. get_permalink() .'">' . get_the_title() .'</a>';
$categories = get_the_category();
foreach ( $categories as $key=>$category ) {
$b = '<a href="' . get_category_link( $category ) . '">' . $category->name . '</a>';
}
$q[$b][] = $a; // Creăm un array cu numele categoriilor și titlurile postărilor
}
/* Restaurăm datele originale ale postării */
wp_reset_postdata();
foreach ($q as $key=>$values) {
echo $key;
echo '<ul>';
foreach ($values as $value){
echo '<li>' . $value . '</li>';
}
echo '</ul>';
}
?>

@Pieter-Goosen Cod excelent! În loc să folosesc un <ul>, vreau să folosesc un șablon dintr-un fișier. Am încercat să includ fișierul în `foreach ($values as $value) {include(template.php);} dar atunci setează numele postărilor ca titlu al paginii, în loc de titlurile postărilor. Ai vreo idee cum pot rezolva asta?

Am vrut doar să adaug soluția mea care a derivat din această întrebare pe care am avut-o. Acest cod cache-ază interogarea pentru categorii și de asemenea cache-ază articolele, inclusiv conținutul articolului, în fiecare categorie. Prima dată când cache-ul este populat, se fac interogări normale la baza de date, dar odată populat, categoriile și articolele cache-uite sunt servite, deci nu mai sunt necesare interogări la baza de date.
// API Transients pentru toate categoriile și toate articolele
$query_categories = get_transient('cached_categories');
if ( false === $query_categories){
$args_cat = array(
// ordonează după numele categoriei crescător
'orderby' => 'name',
'order' => 'ASC',
// obține doar categoriile de nivel superior
'parent' => 0
);
// În loc să cache-uiesc o interogare WP, cache-uiesc 'get_categories()'.
$query_categories = get_categories($args_cat);
// var_dump($query_categories);
set_transient('cached_categories', $query_categories, DAY_IN_SECONDS );
}
// Interogare completă pentru articole
// dacă există categorii populate cu articole
if (!empty ($query_categories) && !is_wp_error( $query_categories )) {
foreach ($query_categories as $category) {
// var_dump($category);
$query_category_posts = get_transient('cached_posts_' . $category->slug );
if ( false === $query_category_posts ){
// Interogare pentru toate articolele după slug în fiecare categorie
$args_category_posts = array(
'post_type' => 'post',
// Slug-ul categoriei și numele categoriei le obținem din foreach-ul peste toate categoriile
'category_name' => $category->slug
);
// Aici cache-uiesc WP_Query, deși acesta rulează pentru toate categoriile.
// Din această cauză, '$category->slug' este folosit pentru a servi un string și nu un obiect.
$query_category_posts = new WP_Query($args_category_posts);
set_transient( 'cached_posts_' . $category->slug , $query_category_posts, DAY_IN_SECONDS );
}
if ($query_category_posts->have_posts()) {
while ($query_category_posts->have_posts()) {
$query_category_posts->the_post(); ?>
<article class="<?php echo $category->slug ?>-article">
<h2 class="<?php echo $category->slug ?>-article-title">
<a href="<?php echo get_permalink() ?>"><?php echo get_the_title() ?></a>
</h2>
<p class="<?php echo $category->slug ?>-post-info">
<?php the_time('d. m. Y') ?>
</p>
<div <?php post_class() ?> >
<?php the_content(); ?>
</div>
</article> <?php
}
} // sfârșit buclă
} // sfârșit foreach
wp_reset_postdata() ;
} // sfârșit dacă există categorii populate cu articole

Iată soluția mea pentru obținerea categoriilor și a postărilor din acele categorii într-un singur rezultat.
Exemplul meu se bazează pe taxonomia personalizată a tipului de post document_category
și tipul de post personalizat documents
. Dar sunt sigur că vei înțelege ideea.
$result = [];
$categories = get_terms( [
'taxonomy' => 'document_category'
] );
foreach ( $categories as $index => $category ) {
$args = [
'post_type' => 'documents',
'posts_per_page' => - 1,
'public' => true,
'tax_query' => [
[
'taxonomy' => 'document_category',
'field' => 'term_id',
'terms' => $category->term_id,
'include_children' => true
]
]
];
$documents = get_posts( $args );
$result[ $index ]['category'] = $category;
$result[ $index ]['documents'] = $documents;
}
return $result;

încearcă acum acest cod
$cat_ids=array();
foreach (get_categories() as $cat)
{
array_push($cat_ids, $cat->cat_ID);
}
$the_query = new WP_Query(array('post_type'=>'post', array('category__and' => $cat_ids) ) );
if( $the_query->have_posts() ):
while ( $the_query->have_posts() ) : $the_query->the_post();
echo the_title();
endwhile;
endif;
wp_reset_query();

Poți folosi acest cod... Setează numărul de articole de care ai nevoie...
De asemenea, am încadrat totul într-un div, astfel încât să poți structura și designa după cum dorești.
<?php
$allcats = get_categories('child_of=0');
foreach ($allcats as $cat) :
$args = array(
'posts_per_page' => 3, // setează numărul de articole pe categorie aici
'category__in' => array($cat->term_id)
);
$customInCatQuery = new WP_Query($args);
if ($customInCatQuery->have_posts()) :
echo '<div>';
echo '<h3>'.$cat->name.'</h3>';
echo '<ul>';
while ($customInCatQuery->have_posts()) : $customInCatQuery->the_post(); ?>
<li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
<?php
endwhile;
echo '</ul></div>';
?>
<?php
else :
echo 'Nu există articole publicate în: '.$cat->name;
endif;
wp_reset_query();
endforeach;
?>
Sper că acest cod te ajută.

Mulțumesc, dar ia exemplul a să zicem 10 categorii. În acest caz, codul tău generează 11 interogări SQL. Eu caut o singură interogare SQL. Cel mai bine ar fi să obținem toate articolele, ordonate pe categorii, dar nu știu cum să fac asta (nu am găsit order_by = cat
în codex) !?

Nu cred că contează deloc dacă sunt 10 categorii sau 20... (am încercat cu 20) decât dacă încerci să încarci un număr foarte mare de articole, ceea ce în orice caz ar putea încetini încărcarea paginii... încearcă - vei vedea că merge foarte ușor - încercarea de a rearanja după încărcare pe categorii ar însemna să construiești un cod imens și în mare parte inutil (după umila mea părere :) )

Nu este așa, trebuie doar să modifici puțin output-ul (adică să închizi lista pentru categoria n și să începi lista pentru categoria n+1) de fiecare dată când un articol are o categorie diferită de articolul anterior... Mult mai simplu decât să bombardezi biata ta bază de date cu 20+ interogări pe încărcare de pagină... (după umila mea părere :)

Cred că am întreba baza de date aceeași întrebare, dar doar ordonând lucrurile diferit la ieșire... Nu văd diferența... Pe lângă asta - este o interogare logică... "dă-mi primul * din această categorie"... "dă-mi primul * din acea categorie" în loc să-mi dai acel post, din nou, din nou, din nou... Este același mod, dar extrag datele în felul de care am nevoie... Dacă nu mă înșel...

Diferența este numărul de interogări către baza de date. Una mare vs. multe mici... ;)

Hmm... nu știu - nu înțeleg atât de profund... Adică modul în care WordPress acționează la această interogare... Dar am încercat și cred că funcționează destul de rapid. Sper că măcar am scurtat drumul către soluția dorită de tine. ;)

Am construit ceva pentru mine pe care îl folosesc destul de des, iată codul, puteți folosi slug-uri, ID-uri sau obiectul termen în tabloul $categories
. Dacă doriți să obțineți toate categoriile, puteți folosi get_terms()
și să le introduceți cu o serie de obiecte termen, dar fiți atenți, nu există nicio tratare a ierarhiei în acest cod.
$categories = array( 1, 'slug', 3 );
echo '<ul>';
foreach($categories as $category) {
$term = ( is_numeric($category) || is_object($category) ? get_term( $category, 'category' ) : get_term_by( 'slug', $category, 'category' ) );
$args = array(
'cat' => $term->term_id
// Adăugați orice alte argumente pentru a se potrivi nevoilor dumneavoastră
);
$q = new WP_Query( $args );
if( $q->have_posts() ) {
echo '<li><a href="' . get_term_link( $term->term_id, 'category' ) . '">' . $term->name . '</a><ul>';
while( $q->have_posts() ) {
$q->the_post();
echo '<li><a href="' . get_permalink() . '">' . get_the_title() . '</a></li>';
}
echo '</ul></li>';
} else {
}
}
echo '</ul>';

Netestat, dar una dintre cele mai simple abordări pe care aș încerca-o este următoarea:
<?php
$category_ids = get_all_category_ids();
foreach ($category_ids as $values) {
$args = array('category' => $value);
$posts_array = get_posts( $args );
foreach ($posts_array as $post) : setup_postdata($post);
?>
<li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
<?php
endforeach;
wp_reset_query();
}
?>

Ok. Nu există nicio modalitate de a face o singură interogare. Încărcarea oricărei pagini în Wordpress implică mai multe interogări în mod implicit, înainte de a adăuga cod personalizat. Toate interogările încorporate folosesc clasa WPDB. Singura modalitate de a face acest lucru într-o singură interogare este folosind propriul t-SQL sau prin transformarea clasei WPDB într-o clasă părinte pentru o altă clasă în acest scop și apelând-o în acest mod.

dacă cauți un plugin, List Category Posts ar putea fi potrivit pentru tine.
Pentru o interogare, verifică get_posts

sau și asta: http://codex.wordpress.org/Function_Reference/get_all_category_ids
