Obtener todas las categorías y publicaciones en esas categorías

24 feb 2012, 23:23:38
Vistas: 60K
Votos: 7

Estoy buscando una solución que me permita imprimir lo siguiente:

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

EDICIÓN

Estoy buscando algo que solo requiera una consulta a la base de datos. Por lo tanto, si tienes un foreach en tu código seguido de un new WP_Query, eso no es lo que estoy buscando (planeo poner esto en la página de inicio de mi sitio web).

3
Comentarios

votado negativo porque tu requerimiento convierte esto de una pregunta sobre WordPress a un problema de ordenamiento en php.

Michael Michael
25 feb 2012 13:29:37

Por favor revisa mi respuesta. Extremadamente rápida y eficiente. Mira las estadísticas que he añadido en mi respuesta

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

¿Qué tal esto? <?php $erer = wp_list_categories('orderby=name&title_li=&show_count=1'); var_dump($erer); ?> Puedes entender cómo usar HTML y CSS entonces.

Vishwa Vishwa
16 oct 2018 07:14:33
Todas las respuestas a la pregunta 8
3
20

EDITAR REVISIÓN NÚMERO 2

Nunca había tocado la API de Transients, hasta hoy cuando vi la respuesta de @MikeSchinkel en esta publicación. Esto me inspiró a revisitar este post nuevamente. Después de algunas pruebas, llegué a lo siguiente:

  • El tiempo de ejecución bajó de ~0.07 segundos a ~0.002 segundos

  • El tiempo de consulta a la base de datos se redujo aproximadamente a la mitad

  • Con el transient, solo se ejecutan 2 consultas a la base de datos

Cómo funciona el código (solo voy a discutir los cambios del código original de REVISIÓN):

PASO 1

Necesitamos guardar el valor de $q en un transient, este es el valor que contiene la lista de categorías con títulos de posts.

PASO 2

Primero debemos verificar si existe un transient, y si no existe, crearlo. Si el transient existe, recuperar su información.

PASO 3

Esta información ahora se pasa a través de un bucle foreach para imprimir la lista con nombres de categorías y títulos de posts.

PASO 4

Actualmente, el transient se actualizará cada doce horas. Esto se puede ajustar según tus necesidades. Sin embargo, el transient deberá eliminarse y recrearse cada vez que cambie el estado de un post. Esto podría ser de borrador a publicado, un nuevo post publicado o un post que se envía a la papelera. Para hacer esto, debes usar delete_transient que se enganchará a transition_post_status, el cual se activará cada vez que cambie el estado de un post.

Aquí está el código completo:

En tu functions.php

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

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

En tu plantilla donde necesitas mostrar tu 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; // Crear un array con los nombres de categorías y títulos de posts
    }


    /* Restaurar los datos originales 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>';
    }


?>

REVISIÓN

Recientemente encontré una solución muy ligera que es mucho más rápida que las otras soluciones posibles. En mi sitio de prueba obtengo un tiempo total de generación de solo ~0.07 segundos y solo 6 consultas a la base de datos según Query Monitor, mientras que los otros métodos me dan un tiempo de generación de ~0.35 segundos y 50 consultas adicionales a la base de datos.

Aquí hay un desglose de mi método:

PASO 1

Primero necesitas crear una consulta personalizada con WP_Query para recuperar todos los posts publicados.

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

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

    while ( $query->have_posts() ) { 

    }

    /* Restaurar los datos originales del Post */
    wp_reset_postdata();

PASO 2

Usando get_the_category, recupera una lista de todas las categorías a las que pertenece un post.

$categories = get_the_category();

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

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

        }

PASO 3

Asigna variables al título del post y a las categorías del post.

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

y

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

PASO 4

Combina estas dos variables para formar un array multidimensional.

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

Para ver qué está pasando en el array, simplemente haz un var_dump.

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

PASO 5

Usando bucles foreach, crea tu lista de posts ordenada por categoría.

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

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

¡TODO JUNTO AHORA!

Aquí está el código 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; // Crear un array con los nombres de categorías y títulos de posts
    }

    /* Restaurar los datos originales 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 may 2014 21:09:05
Comentarios

¿por qué se duplican otras categorías?

winresh24 winresh24
15 mar 2020 05:57:51

¿Cómo puedo hacerlo con un tipo de publicación personalizado?

winresh24 winresh24
15 mar 2020 06:55:26

@Pieter-Goosen ¡Excelente código! En lugar de usar un <ul>, quiero usar una plantilla de un archivo. Intenté incluir el archivo en el `foreach ($values as $value) {include(template.php);} pero luego establece los nombres de las publicaciones como título de la página, en lugar de los títulos de las publicaciones. ¿Alguna idea de cómo puedo solucionar esto?

harvey harvey
19 abr 2020 10:06:55
0

Quería compartir mi solución que derivé de esta pregunta que tenía. Esto almacena en caché la consulta para las categorías y también almacena en caché las publicaciones, incluyendo el contenido de cada publicación, en cada categoría. La primera vez que se llena la caché hay consultas normales a la base de datos, pero una vez llenas, se sirven las categorías y publicaciones en caché, por lo que no hay más consultas a la base de datos.

// API de Transients para todas las categorías y todas las publicaciones
$query_categories = get_transient('cached_categories');
if ( false === $query_categories){
    $args_cat = array(
        // ordenar por nombre de categoría ascendente
        'orderby' => 'name',
        'order' => 'ASC',
        // obtener solo categorías de nivel superior
        'parent' => 0
    );
    // En lugar de almacenar en caché una WP Query, almaceno 'get_categories()'.
    $query_categories = get_categories($args_cat);
    // var_dump($query_categories);
    set_transient('cached_categories', $query_categories, DAY_IN_SECONDS );
}

// Consulta de publicaciones completas
// si hay categorías con publicaciones
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 ){

            // Consultar todas las publicaciones por slug dentro de cada categoría
            $args_category_posts = array(
                'post_type' => 'post',
                // El slug y nombre de la categoría los obtenemos del foreach sobre todas las categorías
                'category_name' => $category->slug
            );

            // Aquí almaceno en caché la WP_Query, aunque esto se ejecuta para todas las categorías.
            // Debido a esto, se usa '$category->slug' para servir una cadena y no un objeto.
            $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
            }
        } // fin del bucle
    } // fin del foreach
wp_reset_postdata() ;
} // fin del if hay categorías con publicaciones
25 jun 2017 00:00:39
0

Aquí está mi solución para obtener las categorías y las publicaciones dentro de esas categorías como un solo resultado.

Mi ejemplo está basado en la taxonomía de categoría de tipo de publicación personalizada document_category y el tipo de publicación personalizada documents. Pero estoy seguro de que captarás la idea.

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

Prueba ahora este código

$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 jul 2018 10:50:31
7
-1

Puedes usar esto... Establece la cantidad de publicaciones que necesites...

También lo he puesto todo dentro de un div, para que puedas hacer la estructura y el diseño que buscas.

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

    foreach ($allcats as $cat) :
        $args = array(
            'posts_per_page' => 3, // establece el número de publicaciones por categoría aquí
            '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 'No hay publicaciones en: '.$cat->name;                
        endif; 
        wp_reset_query();
    endforeach; 
?>

Espero que esto ayude.

25 feb 2012 00:30:41
Comentarios

Gracias, pero toma el ejemplo de digamos 10 categorías. En ese caso, tu código genera 11 consultas SQL. Estoy buscando 1 sola consulta SQL. Lo mejor probablemente sería obtener todas las publicaciones, ordenadas por categoría, pero no sé cómo hacerlo (no encontré order_by = cat en el codex) !?

Ben Ben
25 feb 2012 01:12:55

no creo que importe en absoluto si son 10 categorías o 20... (lo probé con 20) a menos que estés intentando cargar un número enorme de publicaciones, lo cual en cualquier caso podría ralentizar la carga de la página... pruébalo - verás que es muy fluido - intentar reorganizar después de cargar por categorías significaría construir un código enorme y en su mayoría inútil (en mi humilde opinión :) )

Sagive Sagive
25 feb 2012 01:33:35

No es así, solo necesitas modificar ligeramente la salida (es decir, cerrar la lista para la categoría n y comenzar la lista para la categoría n+1) cada vez que una publicación tenga una categoría diferente a la de la publicación anterior... Mucho más simple que bombardear tu pobre base de datos con 20+ consultas por carga de página... (en mi humilde opinión :)

Ben Ben
25 feb 2012 02:04:14

Creo que estaríamos preguntando lo mismo a la base de datos pero solo ordenando los resultados de manera diferente en la salida... No veo la diferencia... Además - es una consulta lógica... "dame el primer * de esta categoría"... "dame el primer * de esa categoría" en lugar de darme ese post, otra vez, otra vez, otra vez... Es la misma forma pero estoy extrayendo los datos como los necesito... A menos que me equivoque..

Sagive Sagive
25 feb 2012 02:37:18

La diferencia está en el número de consultas a la base de datos. Una grande vs muchas pequeñas... ;)

Ben Ben
25 feb 2012 03:11:51

Mmm... no sé - no lo entiendo a ese nivel... Me refiero a cómo WordPress actúa en esta consulta... Pero lo intenté y creo que funciona bastante rápido. Espero al menos haber acortado el camino hacia tu solución deseada. ;)

Sagive Sagive
25 feb 2012 03:21:28

O(n) ineficiente

S.. S..
29 abr 2018 20:47:01
Mostrar los 2 comentarios restantes
1
-1

He construido algo para mí que uso bastante, aquí está el código, puedes usar slugs, ids o el objeto de término en el array $categories, si quieres obtener todas las categorías puedes usar get_terms(), y alimentarlo con un montón de objetos de término, pero ten cuidado, no hay tratamiento de jerarquía en este código.

$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
        // Añade cualquier otro argumento que se ajuste a tus necesidades
    );
    $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->the_post() ) {
            $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
Comentarios

O(n2) ineficiente

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

No probado, pero uno de los enfoques más simples que probaría es el siguiente:

<?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
Comentarios

El mismo problema que el código de Sagive

Ben Ben
25 feb 2012 01:13:19

Ok. No hay forma de hacer una sola consulta. Cargar cualquier página de WordPress tiene múltiples consultas de por sí, antes de añadir código personalizado. Todas las consultas integradas usan la clase WPDB. La única forma de hacerlo en una sola consulta es con tu propio SQL transaccional o haciendo que WPDB sea una clase padre de otra clase para este propósito y llamándola de esa manera.

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

Ten en cuenta que get_all_category_ids(); ahora está obsoleto

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

O(n) ineficiente

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

Si estás buscando un plugin, List Category Posts podría funcionar para ti.

Para una consulta, echa un vistazo a get_posts

24 feb 2012 23:48:04
Comentarios

o esto también: http://codex.wordpress.org/Function_Reference/get_all_category_ids

jasonflaherty jasonflaherty
24 feb 2012 23:48:17

Gracias, pero eso no ayuda.

Ben Ben
25 feb 2012 00:09:17