web-dev-qa-db-fra.com

WP_Query: Pourquoi post-it n'est pas le premier élément en boucle?

J'ai une boucle personnalisée WP_Query basée sur des variables meta_value:

$meta_cat = get_sub_field('category');
$posts = new WP_Query( array(
    'cat' => $meta_cat,
    'posts_per_page' => get_sub_field('recent_ppp'),
) );

Mais de toute façon, quand je vais faire un post collant, il n'est pas présenté comme le premier élément de la boucle while.

Je sais que ignore_sticky_posts est défini par défaut sur false, je ne changerai donc pas. Également essayé de regarder dans order_by documentation si une valeur est liée à post-it mais ça ne l’est pas.

Bien que le order_by => 'post__in' puisse être proche:

Conserver l'ordre de post-ID donné dans le tableau post__in

Mais quand je mets post__in => get_options('sticky_posts') only le post collant est affiché.

Est-ce même possible sans créer deux boucles personnalisées (une pour gérer les posts collants et l'autre pour les autres posts? Ce serait vraiment dommage, car toutes les catégories ne contiennent pas de posts collants.

5
ronnyrr

Si vous cherchez le code source dans lequel les stickies sont inclus, nous trouvons la condition suivante avant que WP_Query continue d'inclure les posts collants

if (    $this->is_home 
     && $page <= 1 
     && is_array($sticky_posts) 
     && !empty($sticky_posts)  
     && !$q['ignore_sticky_posts'] 
) {

Le grand joueur est la condition is_home. Les conditions à l'intérieur de WP_Query sont définies en fonction des arguments qui lui sont transmis, et non de la page sur laquelle la requête est exécutée. Étant donné que vous transmettez cat en tant qu'argument, is_home sera défini sur false et is_category sera défini sur true. Étant donné que is_home est défini sur false, la condition ci-dessus échoue et les correctifs ne sont pas inclus.

TRAVAUX POSSIBLES -  Non testé

Ce que nous pouvons faire est de définir manuellement is_home sur true via pre_get_posts. Tout ce que nous avons à faire est de passer 'wpse_is_home' => true, à votre instance personnalisée WP_Query

Ensuite, nous exécutons notre action pre_get_posts comme suit

add_action( 'pre_get_posts', function ( $q )
{
    if ( true === $q->get( 'wpse_is_home' ) ) 
        $q->is_home = true;
});

MODIFIER

Nous voudrions probablement seulement montrer des notes qui sont pertinentes pour la catégorie interrogée. Dans ce cas, nous devrions supprimer les stickies n’appartenant pas à la catégorie spécifique interrogée.

Nous pouvons essayer ce qui suit, toujours dans notre action pre_get_posts

add_action( 'pre_get_posts', function ( $q )
{
    remove_action( current_action(), __FUNCTION__ );

    if ( true !== $q->get( 'wpse_is_home' ) )
        return;

    // Make sure get_sub_field exists, if not, bail
    if ( !function_exists( 'get_sub_field' ) )
        return;

    // Lets query everything to keep code clean
    $meta_cat = get_sub_field( 'category' ); // Copied from your code
    $meta_cat = filter_var( $meta_cat, FILTER_VALIDATE_INT );
    // Make sure we have a value, if not, bail
    if ( !$meta_cat )
        return;

    $q->set( 'cat', $meta_cat );

    // Set pagination if recent_ppp exists
    $ppp = get_sub_field( 'recent_ppp');
    $ppp = filter_var( $ppp, FILTER_VALIDATE_INT );
    if ( $ppp )
        $q->set( 'posts_per_page', $ppp );      

    // Set is_home to true 
    $q->is_home = true;

    // Get all stickies
    $stickies = get_option( 'sticky_posts' );
    // Make sure we have stickies, if not, bail
    if ( !$stickies )
        return;

    // Query the stickies according to category
    $args = [
        'post__in'            => $stickies,
        'posts_per_page'      => -1,
        'ignore_sticky_posts' => 1, // Ignore stickies
        'cat'                 => $meta_cat,
        'orderby'             => 'post__in',
        'order'               => 'ASC',
        'fields'              => 'ids' // Get only post ID's
    ];
    $valid_sticky_ids = get_posts( $args );

    // Make sure we have valid ids
    if ( !$valid_sticky_ids ) {
        $q->set( 'post__not_in', $stickies );
        return;
    }

    // Remove these ids from the sticky posts array
    $invalid_ids = array_diff( $stickies, $valid_sticky_ids );

    // Check if we still have ids left in $invalid_ids
    if ( !$invalid_ids )
        return;

    // Lets remove these invalid ids from our query
    $q->set( 'post__not_in', $invalid_ids );
});

Avant d'exécuter notre requête personnalisée, nous devons nous assurer que get_sub_field existe et, plus important encore, que get_sub_field( 'category' ) est défini et valide. Cela évitera une défaillance catastrophique qui entraînera le retour de tous les messages, peu importe.

Votre WP_Query peut ressembler à quelque chose comme ceci car nous n'avons besoin que de transmettre 'wpse_is_home' => true:

if (    function_exists( 'get_sub_field' )
     && filter_var( get_sub_field( 'category' ), FILTER_VALIDATE_INT )
) {
    $args = [
        'wpse_is_home' => true
    ];
    $posts_array = new WP_Query( $args ); // DO NOT USE $posts

    // Run your loop as normal
}

DERNIÈRE MODIFICATION

Le code est testé et fonctionne comme prévu

4
Pieter Goosen