কিভাবে দুটি প্রশ্নের একসাথে একত্রিত করতে হয়


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...

আমি তখন কোনও বস্তুতে অ্যারে_মার্জ করার চেষ্টা করেছি, তবে আমি নিম্নলিখিত ত্রুটি পেয়েছি:

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

আমি কীভাবে এই ত্রুটিটি ঠিক করতে পারি?

উত্তর:


8

একটি একক জিজ্ঞাসা

এই সম্পর্কে আরও কিছুটা ভেবেছিলেন এবং এমন একটি সুযোগ রয়েছে যে আপনি একটি একক / মূল প্রশ্নের সাথে যেতে পারেন। বা অন্য কথায়: আপনি যখন ডিফল্টটির সাথে কাজ করতে পারেন তখন দুটি অতিরিক্ত প্রশ্নের প্রয়োজন নেই। এবং যদি আপনি কোনও ডিফল্ট সাথে কাজ করতে না পারেন তবে আপনি কোয়েরিটি কতগুলি লুপটি বিভক্ত করতে চান তা বিবেচনা করেই আপনার একক কোয়েরির চেয়ে বেশি প্রয়োজন হবে না।

পূর্বশর্ত

প্রথমে আপনাকে pre_get_postsফিল্টারটির মধ্যে প্রয়োজনীয় মানগুলি সেট করতে হবে (আমার অন্যান্য উত্তরে দেখানো হয়েছে) । সেখানে আপনি সম্ভবত সেট posts_per_pageএবং catpre_get_postsফিল্টার ছাড়াই উদাহরণ :

$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;
    }
}

এই প্লাগইনটি একটি কাজ করে: এটি পিএইচপি এসপিএল (স্ট্যান্ডার্ড পিএইচপি গ্রন্থাগার) এবং এর ইন্টারফেস এবং আইট্রেটারগুলি ব্যবহার করে। আমরা এখন যা পেয়েছি তা হ'ল FilterIteratorআমাদের লুপ থেকে আইটেমগুলি সুবিধামত সরানোর অনুমতি দেয়। এটি পিএইচপি এসপিএল ফিল্টার আইট্রেটারকে প্রসারিত করে যাতে আমাদের সবকিছু সেট করার দরকার নেই। কোডটি ভালভাবে মন্তব্য করা হয়েছে তবে এখানে কয়েকটি নোট রয়েছে:

  1. accept()বা না - পদ্ধতি মানদণ্ড ঐ আইটেমটির লুপিং অনুমতি নির্ধারণ করতে দেয়।
  2. সেই পদ্ধতির অভ্যন্তরে আমরা ব্যবহার করি WP_Query::the_post(), যাতে আপনি কেবল আপনার টেম্পলেট ফাইল লুপে প্রতিটি টেম্পলেট ট্যাগ ব্যবহার করতে পারেন।
  3. এবং পাশাপাশি আমরা শেষ আইটেমে পৌঁছানোর পরে লুপটি পর্যবেক্ষণ করছি এবং পোস্টগুলিকে রিওয়াইন্ড করছি। এটি আমাদের ক্যোয়ারীটি পুনরায় সেট না করে লুপ ট্রাফকে অসীম পরিমাণে লুপের অনুমতি দেয়।
  4. সেখানে যে অংশ নয় একটি কাস্টম পদ্ধতি FilterIteratorচশমা: deny()। এই পদ্ধতিটি বিশেষত সুবিধাজনক কারণ এটিতে কেবল আমাদের "প্রক্রিয়া বা না" স্টেস্টমেন্ট রয়েছে এবং আমরা ওয়ার্ডপ্রেস টেম্পলেট ট্যাগগুলি বাদে কোনও কিছু না জানার পরে পরবর্তী ক্লাসে সহজেই এটিকে ওভাররাইট করতে পারি।

কীভাবে লুপ করবেন?

এই নতুন ইটারেটর সঙ্গে, আমরা প্রয়োজন হবে না 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() ) );
}

এটা পরীক্ষা করো.

নিম্নলিখিত পরীক্ষার প্লাগইনটি গিস্টহাবের উপর গিস্ট হিসাবে উপলব্ধ। কেবল এটি আপলোড এবং সক্রিয় করুন। এটি 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যুক্তিটির সাথে এটি একত্রিত করে, আপনি কেবলমাত্র সেই পোস্টগুলি পাবেন যা আইডির সাথে বিভাগে বরাদ্দ করা হয়েছে 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'পরামিতি একটি ক্যোয়ারী আসলে পোস্ট ID নম্বর মিলে একটি অ্যারের আসতে হবে। তবে আমরা পুরো ক্যোয়ারী অবজেক্টটি চাই না, সুতরাং এর পরিবর্তে আমরা get_posts ব্যবহার করি।

প্রথমে আমাদের প্রয়োজনীয় পোস্ট আইডিগুলি পান:

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

$ ইমেজপোস্ট এবং $ ননিমেজপোস্টগুলি উভয়ই এখন পোস্ট আইডি সংখ্যার একটি অ্যারে হবে, তাই আমরা সেগুলি মার্জ করে দেব

$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 অবজেক্ট।


এর জন্য ধন্যবাদ. এটি একটি লুপ কাঠামো এবং জটিল জটিল পৃষ্ঠা গণনার জন্য সর্বনিম্ন জটিল সমাধান হিসাবে দেখা গেছে।
জে নিলি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.