WP_query (), query_posts () और pre_get_posts का उपयोग कब करें


159

मैंने कल @ nacin की You Query को नहीं पढ़ा और इसे एक क्वेरी खरगोश छेद के नीचे भेजा गया। कल से पहले, मैं query_posts()अपनी सभी क्वेरी आवश्यकताओं के लिए (गलत तरीके से) उपयोग कर रहा था । अब मैं उपयोग करने के बारे में थोड़ा समझदार हूं WP_Query(), लेकिन अभी भी कुछ ग्रे क्षेत्र हैं।

मुझे लगता है कि मुझे यकीन है कि पता है:

अगर मैं पृष्ठ पर कहीं भी अतिरिक्त छोरों को बना रहा हूं - साइडबार में, पाद लेख में, किसी भी प्रकार के "संबंधित पोस्ट", आदि - मैं उपयोग करना चाहता हूं WP_Query()। मैं बिना किसी नुकसान के एक ही पृष्ठ पर बार-बार उपयोग कर सकता हूं। (सही?)।

मुझे पक्का पता नहीं है

  1. जब मैं @ nacin pre_get_posts बनाम का उपयोग करते हैं WP_Query()? क्या मुझे pre_get_postsअब सब कुछ के लिए उपयोग करना चाहिए ?
  2. जब मैं एक टेम्प्लेट पृष्ठ में लूप को संशोधित करना चाहता हूं - तो मैं कहता हूं कि मैं एक टैक्सोनॉमी संग्रह पृष्ठ को संशोधित करना चाहता हूं - क्या मैं if have_posts : while have_posts : the_postभाग को हटा देता हूं और अपना खुद का लिखता हूं WP_Query()? या क्या मैं pre_get_postsअपने फ़ंक्शन का उपयोग करके आउटपुट को संशोधित करता हूं। पी पी फ़ाइल?

tl; डॉ

Tl; डॉ। नियम मैं इस से आकर्षित करना चाहते हैं:

  1. कभी का उपयोग query_postsअब और
  2. एक ही पृष्ठ पर कई क्वेरीज़ चलाते समय, उपयोग करें WP_Query()
  3. लूप को संशोधित करते समय, यह __________________ करें।

किसी भी ज्ञान के लिए धन्यवाद

टेरी

पीएस: मैंने देखा और पढ़ा है: आपको WP_Query बनाम क्वेरी_पोस्ट () बनाम गेट_पोस्ट () का उपयोग कब करना चाहिए? जो एक और आयाम जोड़ता है - get_posts। लेकिन pre_get_postsसभी के साथ सौदा नहीं करता है ।



@saltcod, अब अलग है, वर्डप्रेस विकसित हुआ, मैंने यहां स्वीकृत उत्तर की तुलना में कुछ टिप्पणियां जोड़ीं ।
प्रोस्टी डेसी

जवाबों:


145

आपका कहना सही है:

कभी का उपयोग query_postsअब और

pre_get_posts

pre_get_postsकिसी भी क्वेरी को बदलने के लिए एक फिल्टर है । इसका उपयोग अक्सर केवल 'मुख्य क्वेरी' को बदलने के लिए किया जाता है:

add_action('pre_get_posts','wpse50761_alter_query');
function wpse50761_alter_query($query){

      if( $query->is_main_query() ){
        //Do something to main query
      }
}

(मैं भी जांच करेगा कि is_admin()रिटर्न झूठी -। हालांकि यह निरर्थक हो सकता है)। मुख्य टेम्प्लेट आपके टेम्प्लेट में इस प्रकार दिखाई देता है:

if( have_posts() ):
    while( have_posts() ): the_post();
       //The loop
    endwhile;
endif;

यदि आप कभी भी इस लूप को संपादित करने की आवश्यकता महसूस करते हैं - उपयोग pre_get_posts। यानी यदि आप उपयोग करने के लिए लुभाते हैं query_posts()- pre_get_postsइसके बजाय उपयोग करें ।

WP_Query

मुख्य प्रश्न एक महत्वपूर्ण उदाहरण है WP_Query object। वर्डप्रेस इसका उपयोग यह तय करने के लिए करता है कि किस टेम्पलेट का उपयोग करना है, उदाहरण के लिए, और url (जैसे पेजिंग) में पारित किए गए किसी भी तर्क को सभी उस WP_Queryऑब्जेक्ट के उदाहरण में चैनल करते हैं ।

द्वितीयक छोरों के लिए (जैसे साइड-बार, या 'संबंधित पोस्ट' सूचियों) में आप WP_Queryऑब्जेक्ट का अपना अलग उदाहरण बनाना चाहेंगे । उदाहरण के लिए

$my_secondary_loop = new WP_Query(...);
if( $my_secondary_loop->have_posts() ):
    while( $my_secondary_loop->have_posts() ): $my_secondary_loop->the_post();
       //The secondary loop
    endwhile;
endif;
wp_reset_postdata();

सूचना wp_reset_postdata();- इसका कारण यह है कि द्वितीयक लूप वैश्विक $postवैरिएबल को ओवरराइड करेगा जो 'वर्तमान पोस्ट' की पहचान करता है। यह अनिवार्य रूप से रीसेट करता है कि $postहम पर हैं।

get_posts ()

यह अनिवार्य रूप से एक WP_Queryवस्तु के एक अलग उदाहरण के लिए एक आवरण है । यह पोस्ट ऑब्जेक्ट की एक सरणी देता है। उपरोक्त लूप में उपयोग की जाने वाली विधियाँ अब आपके लिए उपलब्ध नहीं हैं। यह एक 'लूप' नहीं है, बस पोस्ट ऑब्जेक्ट की एक सरणी है।

<ul>
<?php
global $post;
$args = array( 'numberposts' => 5, 'offset'=> 1, 'category' => 1 );
$myposts = get_posts( $args );
foreach( $myposts as $post ) :  setup_postdata($post); ?>
    <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
<?php endforeach; wp_reset_postdata(); ?>
</ul>

आपके सवालों के जवाब में

  1. pre_get_postsअपनी मुख्य क्वेरी को बदलने के लिए उपयोग करें । WP_Queryटेम्पलेट पृष्ठों में द्वितीयक छोरों के लिए एक अलग ऑब्जेक्ट (विधि 2) का उपयोग करें ।
  2. यदि आप मुख्य लूप की क्वेरी को बदलना चाहते हैं, तो उपयोग करें pre_get_posts

तो क्या ऐसा कोई परिदृश्य है जब कोई सीधे WP_Query के बजाय get_posts () पर जाएगा?
urok93

@ ड़ार्टज़न - हाँ। उदाहरण के लिए कहो कि आपको शीर्ष पर चिपचिपा या चिपचिपा पदों की आवश्यकता नहीं है - इन उदाहरणों get_posts()में अधिक कुशल है।
स्टीफन हैरिस

लेकिन क्या यह एक अतिरिक्त क्वेरी नहीं जोड़ेगा जहाँ हम मुख्य क्वेरी को संशोधित करने के लिए बस pre_get_posts को संशोधित कर सकते हैं?
urok93

@drtanz - आप get_posts()मुख्य क्वेरी के लिए उपयोग नहीं करेंगे - इसके माध्यमिक प्रश्नों के लिए।
स्टीफन हैरिस

1
@StephenHarris Right =) यदि आप the_post का उपयोग करने के बजाय ऑब्जेक्ट पर next_post () का उपयोग करते हैं, तो आप वैश्विक क्वेरी पर कदम नहीं रखते हैं और बाद में wp_reset_postdata का उपयोग करने के लिए याद रखने की आवश्यकता नहीं है।
प्राइवेट

55

छोरों के लिए दो अलग-अलग संदर्भ हैं:

  • मुख्य लूप जो URL अनुरोध के आधार पर होता है और टेम्प्लेट लोड होने से पहले संसाधित होता है
  • द्वितीयक लूप जो किसी अन्य तरीके से होते हैं, जिसे टेम्पलेट फ़ाइलों से या अन्यथा कहा जाता है

इसके साथ समस्या query_posts()यह है कि यह द्वितीयक लूप है जो मुख्य होने की कोशिश करता है और बुरी तरह विफल रहता है। इस प्रकार यह मौजूद है भूल जाओ।

मुख्य लूप को संशोधित करने के लिए

  • उपयोग न करें query_posts()
  • चेक के pre_get_postsसाथ फिल्टर का उपयोग $query->is_main_query()करें
  • बारी-बारी से requestफ़िल्टर का उपयोग करें (थोड़ा बहुत ऊपर इतना बेहतर है)

सेकेंडरी लूप चलाने के लिए

का उपयोग करें new WP_Queryया get_posts()जो बहुत अधिक विनिमेय हैं (बाद वाले पूर्व के लिए पतली आवरण है)।

साफ करना

उपयोग करें wp_reset_query()यदि आपने सीधे query_posts()वैश्विक के साथ प्रयोग किया या गड़बड़ किया है $wp_query- तो आपको लगभग कभी भी ज़रूरत नहीं होगी।

wp_reset_postdata()यदि आपने वैश्विक उपयोग किया है the_post()या setup_postdata()गड़बड़ किया है $postऔर पोस्ट-संबंधित चीजों की प्रारंभिक स्थिति को पुनर्स्थापित करने की आवश्यकता है, तो इसका उपयोग करें ।


3
रार्स्ट का मतलब थाwp_reset_postdata()
ग्रेगरी

23

query_posts($query)उदाहरण के लिए, उपयोग करने के लिए वैध परिदृश्य हैं :

  1. आप किसी पृष्ठ पर (पृष्ठ टेम्पलेट का उपयोग करके) पोस्ट या कस्टम-पोस्ट के प्रकार की सूची प्रदर्शित करना चाहते हैं

  2. आप उन पदों के लिए काम करना चाहते हैं

अब आप आर्काइव टेम्पलेट का उपयोग करने के बजाय इसे पृष्ठ पर क्यों दिखाना चाहेंगे?

  1. यह एक व्यवस्थापक (आपके ग्राहक?) के लिए अधिक सहज है - वे पृष्ठ को 'पेज' में देख सकते हैं

  2. इसे मेनू में जोड़ना बेहतर है (पृष्ठ के बिना, उन्हें सीधे यूआरएल जोड़ना होगा)

  3. यदि आप टेम्पलेट पर अतिरिक्त सामग्री (टेक्स्ट, पोस्ट थंबनेल, या कोई कस्टम मेटा सामग्री) प्रदर्शित करना चाहते हैं, तो आप इसे आसानी से पृष्ठ से प्राप्त कर सकते हैं (और यह सब ग्राहक के लिए और भी अधिक समझ में आता है)। देखें कि क्या आपने एक आर्काइव टेम्पलेट का उपयोग किया है, आपको या तो अतिरिक्त सामग्री को हार्डकोड करना होगा या उदाहरण के लिए थीम / प्लगइन विकल्प का उपयोग करना होगा (जो इसे ग्राहक के लिए कम सहज बनाता है)

यहां एक सरलीकृत उदाहरण कोड है (जो आपके पृष्ठ टेम्पलेट पर होगा - जैसे पृष्ठ-पृष्ठ-की-पोस्टपेफ):

/**
 * Template Name: Page of Posts
 */

while(have_posts()) { // original main loop - page content
  the_post();
  the_title(); // title of the page
  the_content(); // content of the page
  // etc...
}

// now we display list of our custom-post-type posts

// first obtain pagination parametres
$paged = 1;
if(get_query_var('paged')) {
  $paged = get_query_var('paged');
} elseif(get_query_var('page')) {
  $paged = get_query_var('page');
}

// query posts and replace the main query (page) with this one (so the pagination works)
query_posts(array('post_type' => 'my_post_type', 'post_status' => 'publish', 'paged' => $paged));

// pagination
next_posts_link();
previous_posts_link();

// loop
while(have_posts()) {
  the_post();
  the_title(); // your custom-post-type post's title
  the_content(); // // your custom-post-type post's content
}

wp_reset_query(); // sets the main query (global $wp_query) to the original page query (it obtains it from global $wp_the_query variable) and resets the post data

// So, now we can display the page-related content again (if we wish so)
while(have_posts()) { // original main loop - page content
  the_post();
  the_title(); // title of the page
  the_content(); // content of the page
  // etc...
}

अब, पूरी तरह से स्पष्ट होने के लिए, हम query_posts()यहां भी उपयोग WP_Queryकरने से बच सकते हैं और इसके बजाय उपयोग कर सकते हैं - जैसे:

// ...

global $wp_query;
$wp_query = new WP_Query(array('your query vars here')); // sets the new custom query as a main query

// your custom-post-type loop here

wp_reset_query();

// ...

लेकिन, हम ऐसा क्यों करेंगे जब हमारे पास इसके लिए इतना अच्छा सा फंक्शन उपलब्ध होगा?


1
ब्रायन, इसके लिए धन्यवाद। मैं आपके द्वारा वर्णित परिदृश्य पर एक पृष्ठ पर काम करने के लिए pre_get_posts प्राप्त करने के लिए संघर्ष कर रहा हूं: ग्राहक को कस्टम फ़ील्ड / सामग्री को जोड़ने की आवश्यकता है जो अन्यथा एक संग्रह पृष्ठ होगा, इसलिए एक "पृष्ठ" बनाने की आवश्यकता है; ग्राहक को मेनू मेनू में जोड़ने के लिए कुछ देखने की जरूरत है, क्योंकि एक कस्टम लिंक जोड़ने से उन्हें बच जाता है; आदि + मुझसे!
होगी

2
वह भी "pre_get_posts" का उपयोग करके किया जा सकता है। मैंने एक कस्टम क्रम में और कस्टम फ़िल्टर के साथ अपने कस्टम पोस्ट प्रकारों को सूचीबद्ध करने के लिए "स्थिर फ्रंट पेज" किया। यह पृष्ठ भी पृष्ठांकित है। यह देखने के लिए कि यह कैसे काम करता है, इस प्रश्न को देखें: wordpress.stackexchange.com/questions/30851/… तो संक्षेप में, query_posts का उपयोग करने के लिए अभी भी अधिक वैध परिदृश्य नहीं है;)
2ndkauboy

1
क्योंकि "यह ध्यान दिया जाना चाहिए कि किसी पृष्ठ पर मुख्य क्वेरी को बदलने के लिए इसका उपयोग करने से पृष्ठ लोडिंग समय में वृद्धि हो सकती है, सबसे खराब स्थिति में काम की मात्रा को दोगुना करने या अधिक करने की आवश्यकता होती है। जबकि उपयोग करने में आसान है, फ़ंक्शन भी भ्रम की संभावना है। और बाद में समस्याएं। " स्रोत कोड x.wordpress.org/Function_Reference/query_posts
क्लाउडीयू क्रींगा

इनका उत्तर सभी प्रकार का गलत है। आप कस्टम पोस्ट प्रकार के समान URL वाले WP में "पेज" बना सकते हैं। ईजी यदि आपका सीपीटी केले है, तो आप उसी URL के साथ केले नामक पेज प्राप्त कर सकते हैं। तब आप siteurl.com/bananas के साथ अंत करेंगे। जब तक आपके पास अपने थीम फ़ोल्डर में संग्रह-केले हैं। तब तक वह उस पृष्ठ के बजाय टेम्पलेट और "ओवरराइड" का उपयोग करेगा। जैसा कि अन्य टिप्पणियों में से एक में कहा गया है, इस "विधि" का उपयोग WP के लिए दो बार कार्यभार बनाता है, इस प्रकार कभी भी उपयोग नहीं किया जाना चाहिए।
हाइब्रिड वेब देव

8

मैं फ़ंक्शंस से वर्डप्रेस क्वेरी को संशोधित करता हूं। पीपी:

//unfortunately, "IS_PAGE" condition doesn't work in pre_get_posts (it's WORDPRESS behaviour)
//so you can use `add_filter('posts_where', ....);`    OR   modify  "PAGE" query directly into template file

add_action( 'pre_get_posts', 'myFunction' );
function myFunction($query) {
    if ( ! is_admin() && $query->is_main_query() )  {
        if (  $query->is_category ) {
            $query->set( 'post_type', array( 'post', 'page', 'my_postType' ) );
            add_filter( 'posts_where' , 'MyFilterFunction_1' ) && $GLOBALS['call_ok']=1; 
        }
    }
}
function MyFilterFunction_1($where) {
   return (empty($GLOBALS['call_ok']) || !($GLOBALS['call_ok']=false)  ? $where :  $where . " AND ({$GLOBALS['wpdb']->posts}.post_name NOT LIKE 'Journal%')"; 
}

इस उदाहरण को देखने के लिए दिलचस्पी होगी, लेकिन कस्टम मेटा पर क्लॉज कहां है।
एंड्रयू वेल्च

6

वर्डप्रेस समय के साथ विकसित हुए और कुछ चीजें अब अलग हैं (पांच साल बाद)

pre_get_postsकिसी भी क्वेरी को बदलने के लिए एक फिल्टर है। इसका उपयोग अक्सर केवल 'मुख्य क्वेरी' को बदलने के लिए किया जाता है:

दरअसल एक्शन हुक है। फ़िल्टर नहीं, और यह किसी भी क्वेरी को प्रभावित करेगा।

मुख्य क्वेरी आपके टेम्प्लेट में दिखाई देती है:

if( have_posts() ):
    while( have_posts() ): the_post();
       //The loop
    endwhile;
endif;

दरअसल, यह भी सच नहीं है। फ़ंक्शन have_postsउस global $wp_queryऑब्जेक्ट को पुनरावृत्त करता है जो केवल मुख्य क्वेरी से संबंधित नहीं है । global $wp_query;द्वितीयक प्रश्नों के साथ भी बदलाव किया जा सकता है।

function have_posts() {
    global $wp_query;
    return $wp_query->have_posts();
}

get_posts ()

यह अनिवार्य रूप से WP_Query ऑब्जेक्ट के एक अलग उदाहरण के लिए एक आवरण है।

दरअसल, आजकल WP_Queryएक वर्ग है, इसलिए हमारे पास एक वर्ग का एक उदाहरण है।


निष्कर्ष निकालने के लिए: उस समय @StephenHarris ने लिखा था कि यह सब सच था, लेकिन समय के साथ वर्डप्रेस में चीजें बदल गई हैं।


तकनीकी रूप से, यह हुड के तहत सभी फिल्टर हैं, क्रियाएं केवल एक साधारण फिल्टर हैं। लेकिन आप यहां सही हैं, यह एक ऐसी कार्रवाई है जो संदर्भ द्वारा एक तर्क को पारित करती है, जो कि अधिक सरल कार्यों से भिन्न होती है।
मिलो

get_postsपोस्ट ऑब्जेक्ट की एक सरणी लौटाता है, ऑब्जेक्ट नहीं WP_Query, इसलिए यह वास्तव में अभी भी सही है। और WP_Queryहमेशा एक वर्ग, एक वर्ग = वस्तु का उदाहरण रहा है।
मिलो

धन्यवाद, @Milo, किसी कारण से सही है, जिसके लिए मैंने अपने सिर में मॉडल की देखरेख की थी।
प्रोस्टी डेसी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.