खोज क्वेरी ('s') के साथ मेटा क्वेरी ('मेटा_क्वरी') का उपयोग करना


25

एक ऐसी खोज का निर्माण करने की कोशिश करना जो न केवल चूक (शीर्षक, सामग्री आदि) को खोजे बल्कि एक विशिष्ट कस्टम फ़ील्ड भी बनाए।

मेरी वर्तमान क्वेरी:

$args = array(
  'post_type' => 'post',
  's' => $query,
  'meta_query' => array(
     array(
       'key' => 'speel',
       'value' => $query,
       'compare' => 'LIKE'
     )
   )
);

$search = new WP_Query( $args )
...

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

कोई विचार?


जो आप करना चाहते हैं वह केवल एक खोज क्वेरी का उपयोग करके संभव नहीं है। आपको दोनों प्रश्नों को अलग-अलग चलाने और फिर उन्हें एक साथ मर्ज करने की आवश्यकता होगी। यह इस अन्य उत्तर में वर्णित किया गया है। यह आपको एक हाथ देना चाहिए कि यह कैसे करना है। wordpress.stackexchange.com/questions/55519/…
निक पर्किंस

जवाबों:


20

मैं इस समस्या के समाधान के लिए घंटों खोज रहा हूं। ऐरे मर्ज जाने का तरीका नहीं है, खासकर जब प्रश्न जटिल होते हैं और आपको भविष्य में मेटा प्रश्नों को जोड़ने में सक्षम होना चाहिए। जो समाधान सरल रूप से सुंदर है है, उसे 's' में बदलना है, जिससे खोज शीर्षक और मेटा फ़ील्ड दोनों की अनुमति मिलती है।

add_action( 'pre_get_posts', function( $q )
{
    if( $title = $q->get( '_meta_or_title' ) )
    {
        add_filter( 'get_meta_sql', function( $sql ) use ( $title )
        {
            global $wpdb;

            // Only run once:
            static $nr = 0; 
            if( 0 != $nr++ ) return $sql;

            // Modified WHERE
            $sql['where'] = sprintf(
                " AND ( %s OR %s ) ",
                $wpdb->prepare( "{$wpdb->posts}.post_title like '%%%s%%'", $title),
                mb_substr( $sql['where'], 5, mb_strlen( $sql['where'] ) )
            );

            return $sql;
        });
    }
});

उपयोग:

$meta_query = array();
$args = array();
$search_string = "test";

$meta_query[] = array(
    'key' => 'staff_name',
    'value' => $search_string,
    'compare' => 'LIKE'
);
$meta_query[] = array(
    'key' => 'staff_email',
    'value' => $search_string,
    'compare' => 'LIKE'
);

//if there is more than one meta query 'or' them
if(count($meta_query) > 1) {
    $meta_query['relation'] = 'OR';
}

// The Query
$args['post_type'] = "staff";
$args['_meta_or_title'] = $search_string; //not using 's' anymore
$args['meta_query'] = $meta_query;



$the_query = new WP_Query($args)

यह सही तरीका है,
Zorox

शानदार, यह मेरे लिए बहुत अच्छा काम किया। महान समाधान! धन्यवाद!
फैबियानो

यह एक खोज नहीं बल्कि एक क्वेरी है। यदि आपके पास खोज पर काम करने वाले प्लगइन्स हैं, तो यह काम नहीं करता है। क्या मै गलत हु?
marek.m

5

इस उत्तर के संशोधित संस्करण का उपयोग करके बहुत सारे कोड को कम किया जा सकता है ।

$q1 = new WP_Query( array(
    'post_type' => 'post',
    'posts_per_page' => -1,
    's' => $query
));

$q2 = new WP_Query( array(
    'post_type' => 'post',
    'posts_per_page' => -1,
    'meta_query' => array(
        array(
           'key' => 'speel',
           'value' => $query,
           'compare' => 'LIKE'
        )
     )
));

$result = new WP_Query();
$result->posts = array_unique( array_merge( $q1->posts, $q2->posts ), SORT_REGULAR );
$result->post_count = count( $result->posts );

यह मेरे लिए बहुत अच्छा काम करता था (खासकर जब से मुझे get_posts के बजाय WP_Query का उपयोग करने की आवश्यकता थी)। मुझे आपके पोस्ट_काउंट लाइन को संशोधित करने की आवश्यकता थी: $result->post_count = count( $result->posts );क्योंकि मुझे केवल 1 परिणाम मिल रहा था अन्यथा।
ग्रेटब्लैक

4

मैंने @Stabir Kira को थोड़ा सा उत्तर दिया है

function wp78649_extend_search( $query ) {
    $search_term = filter_input( INPUT_GET, 's', FILTER_SANITIZE_NUMBER_INT) ?: 0;
    if (
        $query->is_search
        && !is_admin()
        && $query->is_main_query()
        && //your extra condition
    ) {
        $query->set('meta_query', [
            [
                'key' => 'meta_key',
                'value' => $search_term,
                'compare' => '='
            ]
        ]);

        add_filter( 'get_meta_sql', function( $sql )
        {
            global $wpdb;

            static $nr = 0;
            if( 0 != $nr++ ) return $sql;

            $sql['where'] = mb_eregi_replace( '^ AND', ' OR', $sql['where']);

            return $sql;
        });
    }
    return $query;
}
add_action( 'pre_get_posts', 'wp78649_extend_search');

अब आप (शीर्षक, सामग्री, अंश) या (मेटा फ़ील्ड) या (दोनों) द्वारा खोज सकते हैं।


3

के अनुसार निक पर्किन्स ' सुझाव, मैं इतना की तरह दो प्रश्नों को मर्ज करने के लिए किया था:

$q1 = get_posts(array(
        'fields' => 'ids',
        'post_type' => 'post',
        's' => $query
));

$q2 = get_posts(array(
        'fields' => 'ids',
        'post_type' => 'post',
        'meta_query' => array(
            array(
               'key' => 'speel',
               'value' => $query,
               'compare' => 'LIKE'
            )
         )
));

$unique = array_unique( array_merge( $q1, $q2 ) );

$posts = get_posts(array(
    'post_type' => 'posts',
    'post__in' => $unique,
    'post_status' => 'publish',
    'posts_per_page' => -1
));

if( $posts ) : foreach( $posts as $post ) :
     setup_postdata($post);

     // now use standard loop functions like the_title() etc.     

enforeach; endif;

1
क्या 2016 में विलय के बिना यह अभी भी संभव नहीं है? मैं खोज क्वेरी को pre_get_posts के माध्यम से संपादित कर रहा हूं, इसलिए यह वास्तव में एक विकल्प नहीं है ...
ट्रैविनासिस

@trainoasis मुझे ऐसा नहीं लगता। मैं पिछले 2 घंटे से यह कोशिश कर रहा हूं और मुझे यहां एक Google खोज मिली।
उमैर खान जादौन

2

वैसे इसकी हैक की तरह है लेकिन यह काम करता है। आपको posts_clauses फ़िल्टर जोड़ना होगा। किसी भी क्वेरी शब्द के लिए यह फ़िल्टर फ़ंक्शन चेक कस्टम फ़ील्ड "स्पेल" में मौजूद है और शेष क्वेरी बरकरार है।

function custom_search_where($pieces) {

    // filter for your query
    if (is_search() && !is_admin()) {

        global $wpdb;

        $keywords = explode(' ', get_query_var('s'));
        $query = "";
        foreach ($keywords as $word) {

            // skip possible adverbs and numbers
            if (is_numeric($word) || strlen($word) <= 2) 
                continue;

            $query .= "((mypm1.meta_key = 'speel')";
            $query .= " AND (mypm1.meta_value  LIKE '%{$word}%')) OR ";
        }

        if (!empty($query)) {
            // add to where clause
            $pieces['where'] = str_replace("(((wp_posts.post_title LIKE '%", "( {$query} ((wp_posts.post_title LIKE '%", $pieces['where']);

            $pieces['join'] = $pieces['join'] . " INNER JOIN {$wpdb->postmeta} AS mypm1 ON ({$wpdb->posts}.ID = mypm1.post_id)";
        }
    }
    return ($pieces);
}
add_filter('posts_clauses', 'custom_search_where', 20, 1);

2

मेरे पास एक ही समस्या थी, मेरी नई साइट के लिए मैंने एक नया मेटा "शीर्षक" जोड़ा:

functions.php

add_action('save_post', 'title_to_meta');

function title_to_meta($post_id)
{
    update_post_meta($post_id, 'title', get_the_title($post_id)); 
}

और फिर .. बस कुछ ऐसा जोड़ें:

$sub = array('relation' => 'OR');

$sub[] = array(
    'key'     => 'tags',
    'value'   => $_POST['q'],
    'compare' => 'LIKE',
);

$sub[] = array(
    'key'     => 'description',
    'value'   => $_POST['q'],
    'compare' => 'LIKE',
);

$sub[] = array(
    'key'     => 'title',
    'value'   => $_POST['q'],
    'compare' => 'LIKE',
);

$params['meta_query'] = $sub;

आप इस समाधान के बारे में क्या सोचते हैं?


1
यह वास्तव में बुरा नहीं है, लेकिन आपको सभी मौजूदा पोस्ट को फिर से सहेजने या सामग्री जोड़ने से पहले इसका उपयोग शुरू करने की आवश्यकता है।
बेरेंड

@ आप शायद एक फ़ंक्शन लिख सकते हैं जो सभी पोस्ट को प्राप्त करता है और प्रत्येक के लिए पोस्ट_मेटा को अपडेट करके उनके माध्यम से लूप प्राप्त करता है। इसे कस्टम टेम्पलेट या फ़ंक्शन में शामिल करें, इसे एक बार चलाएं, फिर इसे छोड़ दें।
स्लैम

1

उपरोक्त सभी समाधान केवल तभी परिणाम देते हैं जब कोई मैच स्पेल मेटा कुंजी में मौजूद होता है। यदि आपके पास कहीं और परिणाम हैं, लेकिन इस क्षेत्र में नहीं तो आपको कुछ नहीं मिलेगा। कोई नहीं चाहता कि।

एक बाएं हाथ की जरूरत है। निम्नलिखित एक बनाएंगे।

           $meta_query_args = array(
              'relation' => 'OR',
              array(
                'key' => 'speel',
                'value' => $search_term,
                'compare' => 'LIKE',
              ),
              array(
                'key' => 'speel',
                'compare' => 'NOT EXISTS',
              ),
            );
            $query->set('meta_query', $meta_query_args);

0

यह एक महान समाधान है लेकिन आपको एक चीज को ठीक करने की आवश्यकता है। जब आप 'post__in' कहते हैं, तो आपको id की एक सरणी सेट करने की आवश्यकता होती है और $ अद्वितीय पोस्ट की एक सरणी होती है।

उदाहरण:

$q1 = get_posts(array(
        'fields' => 'ids',
        'post_type' => 'post',
        's' => $query
));

$q2 = get_posts(array(
        'fields' => 'ids',
        'post_type' => 'post',
        'meta_query' => array(
            array(
               'key' => 'speel',
               'value' => $query,
               'compare' => 'LIKE'
            )
         )
));

$unique = array_unique( array_merge( $q1->posts, $q2->posts ) );

$array = array(); //here you initialize your array

foreach($posts as $post)
{
    $array[] = $post->ID; //fill the array with post ID
}


$posts = get_posts(array(
    'post_type' => 'posts',
    'post__in' => $array,
    'post_status' => 'publish',
    'posts_per_page' => -1
));

0

@ सतबीर-कीरा जवाब बहुत अच्छा है, लेकिन यह केवल मेटा और पोस्ट शीर्षक के माध्यम से खोज करेगा। यदि आप इसे मेटा, शीर्षक और सामग्री के माध्यम से खोजना चाहते हैं, तो यहां संशोधित संस्करण है।

    add_action( 'pre_get_posts', function( $q )
    {
      if( $title = $q->get( '_meta_or_title' ) )
      {
        add_filter( 'get_meta_sql', function( $sql ) use ( $title )
        {
          global $wpdb;

          // Only run once:
          static $nr = 0;
          if( 0 != $nr++ ) return $sql;

          // Modified WHERE
          $sql['where'] = sprintf(
              " AND ( (%s OR %s) OR %s ) ",
              $wpdb->prepare( "{$wpdb->posts}.post_title like '%%%s%%'", $title),
              $wpdb->prepare( "{$wpdb->posts}.post_content like '%%%s%%'", $title),
              mb_substr( $sql['where'], 5, mb_strlen( $sql['where'] ) )
          );

          return $sql;
        });
      }
    });

और यहाँ इसका उपयोग है:

$args['_meta_or_title'] = $get['search']; //not using 's' anymore

$args['meta_query'] = array(
  'relation' => 'OR',
  array(
    'key' => '_ltc_org_name',
    'value' => $get['search'],
    'compare' => 'LIKE'
  ),
  array(
    'key' => '_ltc_org_school',
    'value' => $get['search'],
    'compare' => 'LIKE'
  ),
  array(
    'key' => '_ltc_district_address',
    'value' => $get['search'],
    'compare' => 'LIKE'
  )
);

$get['search']अपने खोज मूल्य से बदलें

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.