Interogare *doar* pentru articolele lipicioase (sticky)

16 sept. 2015, 22:21:27
Vizualizări: 22.2K
Voturi: 5

Am folosit următoarea interogare pentru a încerca să afișez doar articolele care sunt marcate ca sticky:

<?php
    $args = array(
        'post_type' => 'post',
        'posts_per_page' => 2,
        'post__in' => get_option('sticky_posts')
    );
?>

<?php query_posts($args); ?>
<?php if(have_posts()) : ?>

    <?php get_template_part('loop', 'feed-top-stories' ); ?>

<?php endif; ?>
<?php wp_reset_query(); ?>

În prezent nu am niciun articol setat ca sticky pe site. Ceea ce înseamnă că nu ar trebui să apară nimic în buclă. Cu toate acestea, am descoperit că afișa oricum 2 articole (chiar dacă nu erau sticky)

Apoi am trecut la un obiect WP_Query (așa cum mi s-a recomandat să evit query_posts() în trecut)

<?php

    $args = array(
            'post_type' => 'post',
            'post__in' => get_option( 'sticky_posts' ),
            'posts_per_page' => 2
    );

    $the_query = new WP_Query($args);

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

        get_template_part('loop', 'feed-top-stories' );

    endwhile; endif;

    wp_reset_postdata();

?>

Dar acum nu pare să funcționeze deloc, bucla pare să afișeze 2 articole, însă ambele sunt pagina care este vizualizată, în ciuda setării parametrului post_type

4
Comentarii

@PieterGoosen asta nu pare să rezolve problema mea... deși nu înțeleg cum ar putea ajuta ignorarea postărilor lipicioase?

User User
17 sept. 2015 00:13:51

Postările lipicioase sunt adăugate automat la interogare, așa că înțeleg de ce Pieter a sugerat să le ignorăm, având în vedere că tu le ceri explicit. Sugerez să verifici $the_query->request după ce rulează pentru a vedea SQL-ul generat, este posibil să ai un filtru care interferează incorect.

Milo Milo
17 sept. 2015 00:33:59

@Molo ah, am înțeles! Mulțumesc. Am încercat asta și, deși nu sunt expert în SQL, aș spune că cererea nu seamănă prea mult cu interogarea pe care încerc să o fac? (voi posta mai jos acest comentariu)

User User
17 sept. 2015 16:45:46

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') ORDER BY wp_posts.post_date DESC LIMIT 0, 2

User User
17 sept. 2015 16:45:54
Toate răspunsurile la întrebare 1
2
16

În prezent nu am postări setate ca lipicioase pe site. Ceea ce înseamnă că nu ar trebui să apară nimic în buclă.

Exact în acest punct greșești când transmiți un array gol la post__in. WordPress are câteva bug-uri stupide care nu au soluții adecvate și care probabil vor rămâne active mult timp. Acesta este unul dintre ele.

Când transmitem un array valid cu ID-uri de postări la post__in, obținem următoarea clauză SQL WHERE (NOTĂ: Toate testele sunt făcute pe o pagină)

AND wp_posts.ID IN (59,45) 
AND wp_posts.post_type = \'post\' 
AND (wp_posts.post_status = \'publish\' OR wp_posts.post_status = \'private\')

Acum, dacă nu avem postări lipicioase, transmitând astfel un array gol la post__in, se generează greșit următorul SQL deoarece parametrul post__in este văzut ca nefiind setat.

AND wp_posts.ID IN (59) 
AND wp_posts.post_type = \'post\' 
AND (wp_posts.post_status = \'publish\' OR wp_posts.post_status = \'private\')

Acesta este un eșec epic cu rezultate neașteptate. În funcție de parametrii transmiși, poți obține postări complet irelevante sau niciuna deloc.

De aceea ar trebui să validezi întotdeauna ceea ce transmiți la post__in dacă valorile transmise sunt un array dinamic, pentru a evita acest eșec epic.

O altă notă care poate părea fără sens, dacă ai nevoie doar să interoghezi postările lipicioase, setează întotdeauna ignore_sticky_posts la 1 (adevărat). Motivul este că, dacă ai nevoie să nu interoghezi toate postările lipicioase sau doar cele dintr-o anumită categorie, vei obține doar cele de care ai nevoie. Dacă nu ignori postările lipicioase, toate vor fi returnate indiferent de ce ai interogat (încă un bug stupid în opinia mea).

Poți rescrie codul astfel:

$stickies = get_option( 'sticky_posts' );
// Asigură-te că avem postări lipicioase pentru a evita rezultate neașteptate
if ( $stickies ) {
    $args = [
        'post_type'           => 'post',
        'post__in'            => $stickies,
        'posts_per_page'      => 2,
        'ignore_sticky_posts' => 1
    ];
    $the_query = new WP_Query($args);

    if ( $the_query->have_posts() ) { 
        while ( $the_query->have_posts() ) { 
            $the_query->the_post();

            get_template_part('loop', 'feed-top-stories' );

        }    
        wp_reset_postdata();    
    }
}
8 feb. 2016 20:31:36
Comentarii

"Doar o altă notă care poate să nu aibă sens deloc: dacă trebuie doar să interogați postări lipicioase (sticky), setați întotdeauna ignore_sticky_posts la 1 (adevărat). Motivul este că, dacă aveți nevoie să nu interogați toate postările lipicioase sau doar cele dintr-o anumită categorie, veți obține exact cele de care aveți nevoie. Dacă nu ignorați postările lipicioase, toate vor fi returnate indiferent de ce ați interogat (încă un bug stupid, după părerea mea)."

Și chiar dacă faceți asta, post__not_in devine oricum inutil.

lucian lucian
14 aug. 2016 14:22:51

Wow, acest lucru este extrem de util. Mulțumesc! Interogarea mea era pentru afișarea postărilor lipicioase în partea de sus a postărilor fiecărei categorii și părea să funcționeze bine până când am dat peste cazul în care nu existau postări lipicioase pe întreg site-ul. Sugestia ta de a folosi o condiție pentru get_option( 'sticky_posts’ ) a fost exact ceea ce aveam nevoie.

Joel Farris Joel Farris
18 nov. 2021 04:45:58