एक साथ दो प्रश्नों को कैसे मर्ज करें


10

मैं पहले छवियों के साथ पदों को दिखाने के बाद एक श्रेणी में पदों का आदेश देने की कोशिश कर रहा हूं और फिर बिना छवियों के पिछले पोस्ट करता हूं। मैं दो प्रश्नों को चलाकर ऐसा करने में कामयाब रहा हूं और अब मैं दो प्रश्नों को एक साथ मिलाना चाहता हूं।

मेरे पास निम्नलिखित हैं:

<?php
$loop = new WP_Query( array('meta_key' => '_thumbnail_id', 'cat' => 1 ) );
$loop2 = new WP_Query( array('meta_key' => '', 'cat' => 1 ) );
$mergedloops = array_merge($loop, $loop2);

while($mergedloops->have_posts()): $mergedloops->the_post(); ?>

लेकिन जब मैं पृष्ठ देखने और देखने की कोशिश करता हूं तो मुझे निम्नलिखित त्रुटि मिलती है:

 Fatal error: Call to a member function have_posts() on a non-object in...

मैंने तब array_merge को किसी ऑब्जेक्ट में डालने की कोशिश की, लेकिन मुझे निम्नलिखित त्रुटि मिली:

Fatal error: Call to undefined method stdClass::have_posts() in...

मैं इस त्रुटि को कैसे ठीक कर सकता हूं?

जवाबों:


8

एक एकल क्वेरी

इस बारे में थोड़ा और सोचा और एक मौका है कि आप एक एकल / मुख्य क्वेरी के साथ जा सकते हैं। या दूसरे शब्दों में: जब आप डिफ़ॉल्ट के साथ काम कर सकते हैं तो दो अतिरिक्त प्रश्नों की आवश्यकता नहीं है। और यदि आप एक डिफ़ॉल्ट के साथ काम नहीं कर सकते हैं, तो आपको क्वेरी को विभाजित करने के लिए कितने लूप के लिए एक एकल क्वेरी से अधिक की आवश्यकता नहीं होगी।

आवश्यक शर्तें

पहले आपको एक pre_get_postsफ़िल्टर के अंदर आवश्यक मान सेट करने की आवश्यकता है (जैसा कि मेरे अन्य उत्तर में दिखाया गया है) । आप की संभावना है posts_per_pageऔर सेट करेंगे cat। उदाहरण के बिना pre_get_posts-Filter:

$catID = 1;
$catQuery = new WP_Query( array(
    'posts_per_page' => -1,
    'cat'            => $catID,
) );
// Add a headline:
printf( '<h1>%s</h1>', number_format_i18n( $catQuery->found_posts )
    .__( " Posts filed under ", 'YourTextdomain' )
    .get_cat_name( $catID ) );

एक आधार का निर्माण

अगली चीज़ जो हमें चाहिए वह है एक छोटा सा कस्टम प्लगइन (या functions.phpअगर इसे अपडेट या थीम में बदलाव के दौरान इधर-उधर ले जाने का मन नहीं है, तो इसे अपनी फ़ाइल में डाल दें ):

<?php
/**
 * Plugin Name: (#130009) Merge Two Queries
 * Description: "Merges" two queries by using a <code>RecursiveFilterIterator</code> to divide one main query into two queries
 * Plugin URl:  http://wordpress.stackexchange.com/questions/130009/how-to-merge-two-queries-together
 */

class ThumbnailFilter extends FilterIterator implements Countable
{
    private $wp_query;

    private $allowed;

    private $counter = 0;

    public function __construct( Iterator $iterator, WP_Query $wp_query )
    {
        NULL === $this->wp_query AND $this->wp_query = $wp_query;

        // Save some processing time by saving it once
        NULL === $this->allowed
            AND $this->allowed = $this->wp_query->have_posts();

        parent::__construct( $iterator );
    }

    public function accept()
    {
        if (
            ! $this->allowed
            OR ! $this->current() instanceof WP_Post
        )
            return FALSE;

        // Switch index, Setup post data, etc.
        $this->wp_query->the_post();

        // Last WP_Post reached: Setup WP_Query for next loop
        $this->wp_query->current_post === $this->wp_query->query_vars['posts_per_page'] -1
            AND $this->wp_query->rewind_posts();

        // Doesn't meet criteria? Abort.
        if ( $this->deny() )
            return FALSE;

        $this->counter++;
        return TRUE;
    }

    public function deny()
    {
        return ! has_post_thumbnail( $this->current()->ID );
    }

    public function count()
    {
        return $this->counter;
    }
}

यह प्लगइन एक काम करता है: यह PHP SPL (स्टैंडर्ड PHP लाइब्रेरी) और इसके इंटरफेस और इटरेटर का उपयोग करता है। अब FilterIteratorहमें जो मिला है वह हमें अपने लूप से आइटम को आसानी से हटाने की अनुमति देता है। यह PHP SPL फ़िल्टर Iterator का विस्तार करता है इसलिए हमें सब कुछ सेट करने की आवश्यकता नहीं है। कोड अच्छी तरह से टिप्पणी की है, लेकिन यहाँ कुछ नोट कर रहे हैं:

  1. accept()या नहीं - विधि मापदंड है कि आइटम पाशन की अनुमति परिभाषित करने के लिए अनुमति देता है।
  2. उस पद्धति के अंदर जिसका हम उपयोग करते हैं WP_Query::the_post(), इसलिए आप अपनी टेम्पलेट फ़ाइलों के लूप में हर टेम्पलेट टैग का उपयोग कर सकते हैं।
  3. और साथ ही हम लूप की निगरानी कर रहे हैं और जब हम अंतिम आइटम पर पहुंचते हैं तो पोस्ट को रिवाइंड करते हैं। यह हमारी क्वेरी को रीसेट किए बिना लूप की अनंत मात्रा को लूप करने की अनुमति देता है।
  4. वहाँ एक कस्टम विधि है कि FilterIteratorऐनक का हिस्सा नहीं है deny():। यह विधि विशेष रूप से सुविधाजनक है क्योंकि इसमें केवल हमारी "प्रक्रिया या" -स्टेटमेंट नहीं है और हम वर्डप्रेस टेम्पलेट टैग से अलग कुछ भी जानने की आवश्यकता के बिना बाद की कक्षाओं में इसे आसानी से अधिलेखित कर सकते हैं।

कैसे करें लूप?

इस नए Iterator के साथ, हमें if ( $customQuery->have_posts() )और while ( $customQuery->have_posts() )अब और ज़रूरत नहीं है। हम एक साधारण foreachबयान के साथ जा सकते हैं क्योंकि हमारे लिए सभी आवश्यक चेक पहले से ही हैं। उदाहरण:

global $wp_query;
// First we need an ArrayObject made out of the actual posts
$arrayObj = new ArrayObject( $wp_query->get_posts() );
// Then we need to throw it into our new custom Filter Iterator
// We pass the $wp_query object in as second argument to keep track with it
$primaryQuery = new ThumbnailFilter( $arrayObj->getIterator(), $wp_query );

अंत में हमें डिफ़ॉल्ट foreachलूप से ज्यादा कुछ नहीं चाहिए । हम the_post()सभी टेम्प्लेट टैग को छोड़ भी सकते हैं और उपयोग भी कर सकते हैं । वैश्विक $postवस्तु हमेशा सिंक में रहेगी।

foreach ( $primaryQuery as $post )
{
    var_dump( get_the_ID() );
}

सहायक लूप

अब अच्छी बात यह है कि हर बाद के क्वेरी फ़िल्टर को संभालना काफी आसान है: बस deny()विधि को परिभाषित करें और आप अपने अगले लूप के लिए तैयार हैं। $this->current()हमेशा हमारे वर्तमान में पोस्ट किए गए पद की ओर इशारा करेगा।

class NoThumbnailFilter extends ThumbnailFilter
{
    public function deny()
    {
        return has_post_thumbnail( $this->current()->ID );
    }
}

जैसा कि हमने परिभाषित किया है कि अब हमारे deny()पास हर पोस्ट है जिसमें एक थंबनेल है, हम तब बिना किसी थंबनेल के सभी पोस्ट को तुरंत लूप कर सकते हैं:

foreach ( $secondaryQuery as $post )
{
    var_dump( get_the_title( get_the_ID() ) );
}

झसे आज़माओ।

निम्न परीक्षण प्लगइन GitHub पर Gist के रूप में उपलब्ध है। बस इसे अपलोड और सक्रिय करें। यह loop_startकार्रवाई पर कॉलबैक के रूप में हर लूप किए गए पोस्ट की आईडी को आउटपुट / डंप करता है। इसका मतलब है कि आपके सेटअप, पोस्ट की संख्या और कॉन्फ़िगरेशन के आधार पर काफी थोड़ा आउटपुट मिल सकता है। कृपया कुछ एबॉर्ट स्टेटमेंट जोड़ें और var_dump()जो आप देखना चाहते हैं और जहां आप इसे देखना चाहते हैं, उसे अंत में बदल दें। यह सिर्फ अवधारणा का प्रमाण है।


6

हालांकि यह इस समस्या को हल करने के लिए (@ कैसर का जवाब है), सीधे सवाल का जवाब देने का सबसे अच्छा तरीका नहीं है, वास्तविक क्वेरी परिणामों में हो जाएगा $loop->postsऔर $loop2->posts, इसलिए ...

$mergedloops = array_merge($loop->posts, $loop2->posts);

... काम करना चाहिए, लेकिन आपको एक foreachलूप का उपयोग करने की आवश्यकता होगी न कि WP_Queryआधारित मानक लूप संरचना के रूप में विलय होने वाले प्रश्नों के रूप WP_Queryमें जो लूप के बारे में ऑब्जेक्ट "मेटा" डेटा को तोड़ देगा ।

आप यह भी कर सकते हैं:

$loop = new WP_Query( array('fields' => 'ids','meta_key' => '_thumbnail_id', 'cat' => 1 ) );
$loop2 = new WP_Query( array('fields' => 'ids','meta_key' => '', 'cat' => 1 ) );
$ids = array_merge($loop->posts, $loop2->posts);
$merged = new WP_Query(array('post__in' => $ids,'orderby' => 'post__in'));

बेशक, वे समाधान कई प्रश्नों का प्रतिनिधित्व करते हैं, यही वजह है कि @ कैसर इस तरह के मामलों के लिए बेहतर दृष्टिकोण है जहां WP_Queryतर्क को संभालना आवश्यक है।


3

वास्तव में वहाँ meta_query(या WP_Meta_Query) है - जो सरणी की एक सरणी लेता है - जहां आप _thumbnail_idपंक्तियों की खोज कर सकते हैं । यदि आप जांच करते हैं EXISTS, तो आप केवल उन्हीं को प्राप्त कर सकते हैं जिनके पास यह क्षेत्र है। इस catतर्क के साथ संयोजन करने पर , आपको केवल वे पोस्ट मिलेंगे, जिन्हें ID के साथ श्रेणी में असाइन किया गया है 1और जिसमें थंबनेल संलग्न है। आप तो उनके द्वारा आदेश हैं meta_value_num, तो आप वास्तव में उन्हें थंबनेल आईडी सबसे कम से उच्चतम करने के लिए आदेश देंगे (के रूप में के साथ कहा गया है orderऔर ASC)। valueजब आप मूल्य के EXISTSरूप में उपयोग करते हैं तो आपको निर्दिष्ट करने की आवश्यकता नहीं होती है compare

$thumbsUp = new WP_Query( array( 
    'cat'        => 1,
    'meta_query' => array( 
        array(
            'key'     => '_thumbnail_id',
            'compare' => 'EXISTS',
        ),
    ),
    'orderby'    => 'meta_value_num',
    'order'      => 'ASC',
) );

अब जब उन्हें ट्रूप किया जाता है, तो आप सभी आईडी एकत्र कर सकते हैं और सहायक क्वेरी के लिए एक विशेष विवरण में उनका उपयोग कर सकते हैं:

$postsWithThumbnails = array();
if ( $thumbsUp->have_posts() )
{
    while ( $thumbsUp->have_posts() )
    {
        $thumbsUp->the_post();

        // collect them
        $postsWithThumbnails[] = get_the_ID();

        // do display/rendering stuff here
    }
}

अब आप अपनी दूसरी क्वेरी जोड़ सकते हैं। wp_reset_postdata()यहाँ कोई ज़रूरत नहीं है - चर में सब कुछ है और मुख्य क्वेरी नहीं है।

$noThumbnails = new WP_Query( array(
    'cat'          => 1,
    'post__not_in' => $postsWithThumbnails
) );
// Loop through this posts

बेशक आप बहुत होशियार हो सकते हैं और pre_get_postsमुख्य क्वेरी को बर्बाद न करने के लिए बस एसक्यूएल स्टेटमेंट को बदल सकते हैं । आप $thumbsUpएक pre_get_postsफिल्टर कॉलबैक के अंदर पहली क्वेरी ( ऊपर) कर सकते हैं ।

add_filter( 'pre_get_posts', 'wpse130009excludeThumbsPosts' );
function wpse130009excludeThumbsPosts( $query )
{
    if ( $query->is_admin() )
        return $query;

    if ( ! $query->is_main_query() )
        return $query;

    if ( 'post' !== $query->get( 'post_type' ) )
        return $query;

    // Only needed if this query is for the category archive for cat 1
    if (
        $query->is_archive() 
        AND ! $query->is_category( 1 )
    )
        return $query;

    $query->set( 'meta_query', array( 
        array(
            'key'     => '_thumbnail_id',
            'compare' => 'EXISTS',
        ),
    ) );
    $query->set( 'orderby', 'meta_value_num' );

    // In case we're not on the cat = 1 category archive page, we need the following:
    $query->set( 'category__in', 1 );

    return $query;
}

इसने मुख्य क्वेरी को बदल दिया है, इसलिए हम केवल उन पोस्टों को प्राप्त करेंगे जिनके पास थंबनेल संलग्न है। अब हम कर सकते हैं (जैसा कि ऊपर दिए गए 1 क्वेरी में दिखाया गया है) मुख्य लूप के दौरान आईडी एकत्र करते हैं और फिर एक दूसरी क्वेरी जोड़ते हैं जो बाकी पोस्ट (एक थंबनेल के बिना) प्रदर्शित करता है।

इसके अलावा आप और भी स्मार्ट हो सकते हैं posts_clausesऔर मेटा मान द्वारा सीधे क्वेरी को बदल सकते हैं और संशोधित कर सकते हैं । इस उत्तर पर एक नज़र डालें क्योंकि वर्तमान एक प्रारंभिक बिंदु है।


3

एक बार में सभी पोस्ट प्राप्त करने के लिए आपको जो चाहिए वह वास्तव में एक तीसरी क्वेरी है। फिर आप पदों को वापस नहीं करने के लिए अपने पहले दो प्रश्नों को बदलते हैं, लेकिन केवल एक प्रारूप में पोस्ट आईडी जो आप के साथ काम कर सकते हैं।

'fields'=>'ids'पैरामीटर एक प्रश्न वास्तव में पोस्ट आईडी नंबर से मेल खाते की एक सरणी लौट कर देगा। लेकिन हम संपूर्ण क्वेरी ऑब्जेक्ट नहीं चाहते हैं, इसलिए हम इसके लिए get_posts का उपयोग करते हैं।

सबसे पहले, हमें जिस पोस्ट आईडी की आवश्यकता है, उसे प्राप्त करें:

$imageposts = get_posts( array('fields'=>'ids', 'meta_key' => '_thumbnail_id', 'cat' => 1 ) );
$nonimageposts = get_posts( array('fields'=>'ids', 'meta_key' => '', 'cat' => 1 ) );

$ imageposts और $ nonimageposts अब दोनों पोस्ट आईडी नंबरों की एक सरणी होगी, इसलिए हम उन्हें मर्ज करते हैं

$mypostids = array_merge( $imageposts, $nonimageposts );

डुप्लिकेट आईडी नंबर हटा दें ...

$mypostids = array_unique( $mypostids );

अब, निर्दिष्ट क्रम में वास्तविक पोस्ट प्राप्त करने के लिए एक प्रश्न करें:

$loop = new WP_Query( array('post__in' => $mypostids, 'ignore_sticky_posts' => true, 'orderby' => 'post__in' ) );

$ लूप वेरिएबल अब आपके पोस्ट के साथ एक WP_Query ऑब्जेक्ट है।


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