web-dev-qa-db-fra.com

"Postes collants" pour chaque catégorie (archive.php)

J'ai besoin d'avoir la capacité d'avoir des posts collants pour chaque catégorie. Le moyen le plus simple de faire cela semblait être de simplement créer deux boucles sur la page. Voici ce que j'ai écrit:

<?php
//Custom "sticky" loop
$sticky_posts = new WP_Query(array(
    'post__in' => get_option('sticky_posts')
));

if ($sticky_posts->have_posts()) :
    while ($sticky_posts->have_posts()) : $sticky_posts->the_post();

        get_template_part('post-formats/content', 'sticky');

    endwhile; endif;

// CLEAR DATA
wp_reset_postdata();

if (have_posts()) : 
// Normal loop

while (have_posts()) : the_post(); 

    $format = get_post_format();
    if (false === $format) {
        $format = 'standard';
    }
    get_template_part('post-formats/content', $format);

endwhile; 

Malheureusement, cela ne fonctionne pas comme prévu:

  1. Cela place les articles collés au sommet de TOUTES les catégories, qu’ils appartiennent ou non à cette catégorie.
  2. Le plus étrange de tous: S'il n'y a pas de messages collés à, tous les messages sont affichés par la boucle "collante" - et ensuite répétés ci-dessous par la boucle normale. Bizarre!

Qu'est ce que j'ai mal fait? Je me rends compte que les messages collés apparaîtront deux fois (une fois au sommet et à nouveau dans leur postition normale), mais à part cela, qu'est-ce qui cause ces problèmes? : - /

2
Django Reinhardt

Pour compléter ceci, voici ce que j'ai dit dans les commentaires en réponse à la question posée

Juste pour expliquer rapidement, WP_Query échoue de façon catastrophique dans certains cas où des tableaux vides sont passés à certains de ses paramètres, au lieu de renvoyer également un tableau vide comme on pouvait s'y attendre, WP_Query renvoie tous les articles. En ce qui concerne l’obtention des correctifs corrects, comme je l’ai déjà dit, vous devez obtenir l’ID de la catégorie actuelle et l’utiliser pour filtrer les posts collants. N'oubliez pas qu'avec votre approche, vous devez supprimer les posts collants de la requête principale, sinon vous obtiendrez des doublons.

Comme solution alternative utilisant des crochets et des filtres sur la requête principale et utilisant une question similaire/réponse , voici ce que j’ai trouvé: ( Le code est bien commenté pour pouvoir être suivi. CAVEAT : Ceci n’a pas été testé et nécessite au moins PHP 5.4+ )

function get_term_sticky_posts()
{
    // First check if we are on a category page, if not, return false
    if ( !is_category() )
        return false;

    // Secondly, check if we have stickies, return false on failure
    $stickies = get_option( 'sticky_posts' );

    if ( !$stickies )
        return false;

    // OK, we have stickies and we are on a category page, continue to execute. Get current object (category) ID
    $current_object = get_queried_object_id();

    // Create the query to get category specific stickies, just get post ID's though
    $args = [
        'nopaging' => true,
        'post__in' => $stickies,
        'cat' => $current_object,
        'ignore_sticky_posts' => 1,
        'fields' => 'ids'
    ];
    $q = get_posts( $args );

    return $q;
}

add_action( 'pre_get_posts', function ( $q )
{
    if (    !is_admin() // IMPORTANT, make sure to target front end only
         && $q->is_main_query() // IMPORTANT, make sure we only target the main query
         && $q->is_category() // Only target category archives
    ) {
        // Check if our function to get term related stickies exists to avoid fatal errors
        if ( function_exists( 'get_term_sticky_posts' ) ) {
            // check if we have stickies
            $stickies = get_term_sticky_posts();

            if ( $stickies ) {
                // Remove stickies from the main query to avoid duplicates
                $q->set( 'post__not_in', $stickies );

                // Check that we add stickies on the first page only, remove this check if you need stickies on all paged pages
                if ( !$q->is_paged() ) {

                    // Add stickies via the the_posts filter
                    add_filter( 'the_posts', function ( $posts ) use ( $stickies )
                    {   
                        $term_stickies = get_posts( ['post__in' => $stickies, 'nopaging' => true] );

                        $posts = array_merge( $term_stickies, $posts );

                        return $posts;
                    }, 10, 1 );
                }
            }
        }
    }
});

QUELQUES NOTES:

  • Cela ne fonctionne qu'avec la taxonomie par défaut category. Le code peut être facilement modifié (veuillez le faire, modifiez-le selon vos besoins) pour utiliser toute taxonomie et ses termes correspondants.

  • Vous venez d'ajouter ceci à functions.php. Pas besoin de modifier vos fichiers de modèle ou d'utiliser des requêtes personnalisées. Tout ce dont vous avez besoin est la requête principale avec boucle par défaut

MODIFIER

Le code ci-dessus est maintenant testé et fonctionne sur Wordpress 4.2.1 et PHP 5.4+

3
Pieter Goosen

Je ne peux pas commenter la réponse de Pieter Goosen en raison de règles de réputation/-:

Le code actuel a un effet secondaire sur la version actuelle de wordpress 4.8 (mars 2018), il affiche des posts collants lors de l'accès à une page non existante, ce qui devrait générer une erreur 404. Comme "www.example.com/asd" où "asd" n'existe pas. Même problème, c'est "wp-admin". En effet, dans ce cas, "asd" ou "wp-admin" est enregistré dans $ q en tant que nom de catégorie, bien qu'il ne s'agisse pas d'une catégorie existante.

Solution: vérifiez si la catégorie transmise existe réellement en ajoutant la dernière ligne de ce code dans le code affiché ci-dessus:

if (    !is_admin() // IMPORTANT, make sure to target front end only
     && $q->is_main_query() // IMPORTANT, make sure we only target the main query
     && $q->is_category() // Only target category archives         
     && $q->is_tax(get_query_var ( 'category_name')) // Only target existing category names   
3
bz-mof

La réponse à ces deux problèmes était assez simple.

  1. Ajoutez simplement un argument à WP_Query pour le limiter à la catégorie actuelle
  2. Assurez-vous que WP_Query ne s'exécute pas sauf s'il y a des posts collants.

Ainsi:

<?php
// Get sticky posts
$sticky_ids = get_option( 'sticky_posts' );

// BEGIN Custom "sticky" loop

// If sticky posts found...
if(!empty($sticky_ids)) {
    $args = array(
        'post_type' => 'post',
        'category__in' => get_query_var('cat'), // Get current category only
        'post__in' => get_option('sticky_posts') // Get stickied posts
    );

    $sticky_posts = new WP_Query($args);

    if ($sticky_posts->have_posts()) :
        while ($sticky_posts->have_posts()) : $sticky_posts->the_post();

            get_template_part('post-formats/content', 'sticky');

    endwhile; endif;
// END Custom "sticky" loop

    // Reset post data ready for next loop
    wp_reset_postdata();
}

if (have_posts()) :

    /* Start the Loop */
    while (have_posts()) : the_post();

        $format = get_post_format();
        if (false === $format) {
            $format = 'standard';
        }
        get_template_part('post-formats/content', $format);

    endwhile; endif; ?>
2
Django Reinhardt