Ottieni tutte le categorie e i post in quelle categorie

24 feb 2012, 23:23:38
Visualizzazioni: 60K
Voti: 7

Sto cercando una soluzione che mi permetta di stampare quanto segue:

Cat 1        Cat 2        Cat 3
 Post 1       Post 1       Post 1
 Post 2       Post 2       Post 2
 Post 3                    Post 3
                           Post 4

MODIFICA

Sto cercando qualcosa che richieda una sola query al database! Quindi se nel tuo codice hai un foreach seguito da un new WP_Query, non è quello che sto cercando (ho intenzione di inserire questo nella homepage del mio sito).

3
Commenti

votato negativamente perché la tua richiesta trasforma questa domanda su WordPress in un problema di ordinamento PHP.

Michael Michael
25 feb 2012 13:29:37

Per favore guarda la mia risposta. Estremamente veloce ed efficiente. Vedi le statistiche che ho aggiunto nella mia risposta

Pieter Goosen Pieter Goosen
7 set 2014 16:51:40

Che ne dici di questo? <?php $erer = wp_list_categories('orderby=name&title_li=&show_count=1'); var_dump($erer); ?> Puoi capire come usare HTML e CSS poi.

Vishwa Vishwa
16 ott 2018 07:14:33
Tutte le risposte alla domanda 8
3
20

REVISIONE NUMERO 2

Non avevo mai utilizzato la Transient API, fino a oggi quando ho visto la risposta di @MikeSchinkel in questo post. Questo mi ha ispirato a rivedere nuovamente questo articolo. Dopo alcuni test, ho ottenuto i seguenti risultati:

  • Il tempo di esecuzione è sceso da ~0.07 secondi a ~0.002 secondi

  • Il tempo delle query al database si è ridotto circa della metà

  • Con il transient, vengono eseguite solo 2 query al database

Come funziona il codice (discuterò solo le modifiche rispetto al codice originale della REVISIONE):

PASSO 1

Dobbiamo salvare il valore di $q in un transient, questo è il valore che contiene l'elenco delle categorie con i titoli dei post.

PASSO 2

Per prima cosa dobbiamo verificare se esiste un transient, e se non esiste, crearlo. Se il transient esiste, recuperiamo le sue informazioni.

PASSO 3

Queste informazioni vengono poi passate attraverso un ciclo foreach per stampare l'elenco con i nomi delle categorie e i titoli dei post.

PASSO 4

Attualmente, il transient verrà aggiornato ogni dodici ore. Questo intervallo può essere modificato in base alle esigenze. Tuttavia, il transient dovrà essere eliminato e ricreato ogni volta che lo stato di un post cambia. Questo può accadere quando un post passa da bozza a pubblicato, quando viene pubblicato un nuovo post o quando un post viene spostato nel cestino. Per fare ciò, è necessario utilizzare delete_transient che verrà agganciato a transition_post_status, che verrà attivato ogni volta che lo stato di un post cambia.

Ecco il codice completo:

Nel tuo functions.php

add_action( 'transition_post_status', 'publish_new_post', 10, 3 );

function publish_new_post() {
   delete_transient( 'category_list' );
}

Nel tuo template dove vuoi visualizzare l'elenco

<?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; // Crea un array con i nomi delle categorie e i titoli dei post
    }


    /* Ripristina i dati originali del post */
    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>';
    }


?>

REVISIONE

Recentemente ho trovato una soluzione molto leggera che è molto più veloce rispetto alle altre soluzioni proposte. Sul mio sito di test ottengo un tempo di generazione totale di soli ~0.07 secondi e solo 6 query al database secondo Query Monitor, mentre gli altri metodi mi danno un tempo di generazione di ~0.35 secondi e 50 query extra al database.

Ecco una spiegazione del mio metodo:

PASSO 1

Per prima cosa devi creare una query personalizzata con WP_Query per recuperare tutti i post pubblicati

$args = array( 
        'posts_per_page' => -1
    );

    $query = new WP_Query($args);   
    $q = array();

    while ( $query->have_posts() ) { 

    }

    /* Ripristina i dati originali del post */
    wp_reset_postdata();

PASSO 2

Utilizzando get_the_category, recupera un elenco di tutte le categorie a cui appartiene un post.

$categories = get_the_category();

        foreach ( $categories as $key=>$category ) {

            $b = '<a href="' . get_category_link( $category ) . '">' . $category->name . '</a>';    

        }

PASSO 3

Assegna delle variabili al titolo del post e alle categorie del post

$a = '<a href="'. get_permalink() .'">' . get_the_title() .'</a>';

e

$b = '<a href="' . get_category_link( $category ) . '">' . $category->name . '</a>';    

PASSO 4

Combina queste due variabili per formare un array multidimensionale

$q[$b][] = $a;

Per vedere cosa succede nell'array, puoi fare un var_dump

?><pre><?php var_dump($q); ?></pre><?php

PASSO 5

Utilizzando cicli foreach, crea il tuo elenco di post ordinati per categoria

foreach ($q as $key=>$values) {
    echo $key;

    echo '<ul>';
        foreach ($values as $value){
            echo '<li>' . $value . '</li>';
        }
    echo '</ul>';
}

TUTTO INSIEME ORA!

Ecco il codice completo

<?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; // Crea un array con i nomi delle categorie e i titoli dei post
    }

    /* Ripristina i dati originali del post */
    wp_reset_postdata();

    foreach ($q as $key=>$values) {
        echo $key;

        echo '<ul>';
            foreach ($values as $value){
                echo '<li>' . $value . '</li>';
            }
        echo '</ul>';
    }

?>
29 mag 2014 21:09:05
Commenti

perché le altre categorie sono duplicate?

winresh24 winresh24
15 mar 2020 05:57:51

Come posso farlo con un custom post type?

winresh24 winresh24
15 mar 2020 06:55:26

@Pieter-Goosen Codice eccellente! Invece di usare un <ul>, voglio usare un template da un file. Ho provato a includere il file nel `foreach ($values as $value) {include(template.php);} ma poi imposta i nomi dei post come titolo della pagina, invece dei titoli dei post. Hai qualche idea su come posso risolvere?

harvey harvey
19 apr 2020 10:06:55
0

Volevo solo aggiungere la mia soluzione derivata da questa domanda che avevo. Questo codice memorizza nella cache la query per le categorie e anche i post, incluso il contenuto dei post, in ogni categoria. La prima volta che la cache viene riempita ci sono normali query al database, tuttavia una volta riempita vengono servite le categorie e i post memorizzati nella cache, quindi nessun'altra query al database.

// API Transients per tutte le categorie e tutti i post
$query_categories = get_transient('cached_categories');
if ( false === $query_categories){
    $args_cat = array(
        // ordina per nome categoria ascendente
        'orderby' => 'name',
        'order' => 'ASC',
        // ottieni solo categorie di primo livello
        'parent' => 0
    );
    // Invece di memorizzare una WP Query, memorizzo 'get_categories()'.
    $query_categories = get_categories($args_cat);
    // var_dump($query_categories);
    set_transient('cached_categories', $query_categories, DAY_IN_SECONDS );
}

// Query completa dei post
// se ci sono categorie con post
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 ){

            // Query tutti i post per slug all'interno di ogni categoria
            $args_category_posts = array(
                'post_type' => 'post',
                // Lo slug della categoria e il nome della categoria ottenuti dal foreach su tutte le categorie
                'category_name' => $category->slug
            );

            // Qui memorizzo la WP_Query, anche se viene eseguita per tutte le categorie.
            // Per questo motivo viene utilizzato '$category->slug' per servire una stringa e non un oggetto.
            $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
            }
        } // fine loop
    } // fine foreach
wp_reset_postdata() ;
} // fine se ci sono categorie con post
25 giu 2017 00:00:39
0

Ecco la mia soluzione per ottenere le categorie e i post all'interno di quelle categorie come un unico risultato.

Il mio esempio si basa sulla tassonomia personalizzata per le categorie document_category e il tipo di post personalizzato documents. Ma sono sicuro che capirai il concetto.

$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;
7 apr 2020 15:12:08
0

prova ora questo codice

$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();
10 lug 2018 10:50:31
7
-1

Puoi usare questo... Imposta il numero di articoli che ti servono...

Inoltre ho inserito tutto all'interno di un div, così puoi creare la struttura e il design che desideri.

<?php  
    $allcats = get_categories('child_of=0'); 

    foreach ($allcats as $cat) :
        $args = array(
            'posts_per_page' => 3, // imposta qui il numero di articoli per categoria
            '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 'Nessun articolo pubblicato in:'.$cat->name;                
        endif; 
        wp_reset_query();
    endforeach; 
?>

Spero che questo ti sia utile.

25 feb 2012 00:30:41
Commenti

Grazie, ma prendiamo l'esempio di 10 categorie. In quel caso il tuo codice causa 11 query SQL. Sto cercando di ottenere 1 sola query SQL. La soluzione migliore sarebbe probabilmente ottenere tutti i post, ordinati per categoria, ma non so come fare (non ho trovato order_by = cat nel codex) !?

Ben Ben
25 feb 2012 01:12:55

Non credo cambi molto se sono 10 categorie o 20... (l'ho provato con 20) a meno che tu non stia cercando di caricare un numero enorme di post che in ogni caso potrebbe rallentare il caricamento della pagina... provalo - vedrai che è molto fluido - cercare di riorganizzare dopo il caricamento per categorie significherebbe creare un codice enorme e per lo più inutile (secondo la mia umile opinione :) )

Sagive Sagive
25 feb 2012 01:33:35

In realtà non è così, basta modificare leggermente l'output (cioè chiudere la lista per la cat n e aprirne una nuova per la cat n+1) ogni volta che un post ha una categoria diversa da quella del post precedente... Molto più semplice che bombardare il povero database con 20+ query per ogni caricamento di pagina... (secondo la mia umile opinione :)

Ben Ben
25 feb 2012 02:04:14

Penso che stiamo chiedendo la stessa cosa al database ma solo ordinando i risultati in modo diverso all'output... non vedo la differenza... inoltre - è una query logica... "dammi il primo * da questa categoria"... "dammi il primo * da quella categoria" invece di darmi quel post, ancora, ancora, ancora... è lo stesso modo ma sto estraendo i dati nel modo di cui ho bisogno... a meno che non mi sbagli..

Sagive Sagive
25 feb 2012 02:37:18

La differenza è nel numero di query al database. Una grande vs tante piccole... ;)

Ben Ben
25 feb 2012 03:11:51

mmh.. non so - non lo capisco a questo livello.. voglio dire, il modo in cui WordPress gestisce questa query.. ma. ho provato e penso che funzioni molto velocemente. Spero almeno di aver abbreviato il percorso verso la soluzione che desideravi. ;)

Sagive Sagive
25 feb 2012 03:21:28

O(n) inefficiente

S.. S..
29 apr 2018 20:47:01
Mostra i restanti 2 commenti
1
-1

Ho creato qualcosa per me che uso molto spesso, ecco il codice, puoi usare slug, ID o l'oggetto term nell'array $categories. Se vuoi ottenere tutte le categorie puoi usare get_terms() e passargli un insieme di oggetti term, ma fai attenzione, questo codice non gestisce la gerarchia.

$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
        // Aggiungi altri argomenti secondo le tue esigenze
    );
    $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>';
25 feb 2012 00:32:56
Commenti

O(n2) inefficiente

S.. S..
29 apr 2018 20:47:57
4
-1

Non testato, ma uno degli approcci più semplici che proverei è il seguente:

<?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();
    }
?>
25 feb 2012 00:54:00
Commenti

Stesso problema del codice di Sagive

Ben Ben
25 feb 2012 01:13:19

Ok. Non c'è modo di eseguire una singola query. Il caricamento di qualsiasi pagina in WordPress comporta già molteplici query di default, prima ancora di aggiungere codice personalizzato. Tutte le query integrate utilizzano la classe WPDB. L'unico modo per farlo con una singola query è utilizzare il tuo transact SQL personalizzato o rendere WPDB una classe genitore di un'altra classe appositamente per questo scopo e chiamarla in quel modo.

Neil Davidson Neil Davidson
4 mar 2012 02:14:04

Nota che get_all_category_ids(); è ora deprecato

Pieter Goosen Pieter Goosen
6 gen 2015 10:16:03

O(n) inefficiente

S.. S..
29 apr 2018 20:47:27
2
-2

se stai cercando un plugin, List Category Posts potrebbe fare al caso tuo.

Per una query, dai un'occhiata a get_posts

24 feb 2012 23:48:04
Commenti

o anche questo: http://codex.wordpress.org/Function_Reference/get_all_category_ids

jasonflaherty jasonflaherty
24 feb 2012 23:48:17

Grazie, ma non è d'aiuto.

Ben Ben
25 feb 2012 00:09:17