我当前的查询:
$args = array(
'post_type' => 'post',
's' => $query,
'meta_query' => array(
array(
'key' => 'speel',
'value' => $query,
'compare' => 'LIKE'
)
)
);
$search = new WP_Query( $args )
...
这会返回与搜索查询和元查询都匹配的帖子,但我也希望它还返回与其中任何一个匹配的帖子。
有什么想法吗?
#1 楼
我一直在寻找解决这个问题的方法。数组合并不是行之有效的方法,尤其是当查询很复杂并且您将来必须能够添加到元查询时。简单来说,美丽的解决方案是将'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)
评论
这是正确的方法
–佐罗克斯
16年8月12日在17:20
太棒了,这对我来说非常有效。很好的解决方案!谢谢!
–法比亚诺
17年9月23日15:56
这是一个查询,而不是搜索。如果您有可在搜索中使用的插件,那么它将无法正常工作。我错了吗?
– marek.m
17-10-30在9:57
@ marek.m,您需要自定义插件(可能使用过滤器(如果可用))以添加元查询。
– FooBar
20年1月21日在20:09
#2 楼
通过使用此答案的修改版本,可以减少大量代码。$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 );
评论
这对我来说很棒(特别是因为我需要使用WP_Query而不是get_posts)。我确实必须将您的post_count行修改为:$ result-> post_count = count($ result-> posts);因为否则我只会得到1个结果。
–GreatBlakes
2015年5月27日13:21
#3 楼
我遇到了同样的问题,对于我的新网站,我刚刚添加了一个新的元“标题”: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;
您如何看待这种解决方法?
评论
这实际上还不错,但是在您开始添加内容之前,您需要重新保存所有现有帖子或开始使用它。
– Berend
16 Dec 6'在11:55
@Berend您可能编写了一个函数,该函数获取所有帖子并循环遍历它们,从而更新每个帖子的post_meta。将其包含在自定义模板或函数中,运行一次,然后将其丢弃。
–满贯
18年5月23日在6:13
有史以来最好的响应:没有手动的SQL转换,没有额外的可见数据...非常感谢!
–jeanmatthieud
20-11-19在10:22
#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');
现在您可以按(标题,内容,专有内容)或(元字段)或(两者)进行搜索。
#5 楼
根据Nick Perkins的建议,我不得不像这样合并两个查询:$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;
评论
如果没有在2016年合并,这仍然不可能吗?我正在通过pre_get_posts编辑搜索查询,因此这实际上不是一个选择...
–火车头病
16-2-9在8:24
@trainoasis我不这么认为。自最近2个小时以来,我一直在尝试它,而Google搜索将我带到了这里。
– Umair Khan Jadoon
16年11月5日,10:40
#6 楼
嗯,这是一种hack,但是可以。您需要添加posts_clauses过滤器。此过滤器功能检查自定义字段“ speel”中是否存在任何查询词,其余查询保持不变。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);
#7 楼
上述所有解决方案仅在speel元关键字中存在匹配项时才返回结果。如果您在其他地方获得了结果,但在该字段中没有,您将一无所获。没有人想要。需要左联接。以下将创建一个。
$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);
#8 楼
对我来说完美的下一个代码: $search_word = $_GET['id'];
$data['words'] = trim(urldecode($search_word));
$q1 = new WP_Query( array(
'post_type' => array('notas', 'productos'),
'posts_per_page' => -1,
's' => $search_word
));
$q2 = new WP_Query( array(
'post_type' => array('notas', 'productos'),
'posts_per_page' => -1,
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'subtitulo',
'value' => $search_word,
'compare' => 'LIKE'
),
array(
'key' => 'thumbnail_bajada',
'value' => $search_word,
'compare' => 'LIKE'
)
)
));
$result = new WP_Query();
$result->posts = array_unique( array_merge( $q1->posts, $q2->posts ), SORT_REGULAR );
$result->post_count = count( $result->posts );
#9 楼
我找不到找到可以在帖子标题,描述和/或一个或多个元数据中混合使用的多个关键字的解决方案,因此我在搜索功能中添加了自己的内容。所有您要添加的内容function.php中的以下代码,每当我们在WP_Query()中使用's'参数并且希望它也搜索一个或多个时,您只需添加一个's_meta_keys'参数,该参数是元数组您要在其中搜索的键:
/************************************************************************\
|** **|
|** Allow WP_Query() search function to look for multiple keywords **|
|** in metas in addition to post_title and post_content **|
|** **|
|** By rAthus @ Arkanite **|
|** Created: 2020-08-18 **|
|** Updated: 2020-08-19 **|
|** **|
|** Just use the usual 's' argument and add a 's_meta_keys' argument **|
|** containing an array of the meta(s) key you want to search in :) **|
|** **|
|** Example : **|
|** **|
|** $args = array( **|
|** 'numberposts' => -1, **|
|** 'post_type' => 'post', **|
|** 's' => $MY_SEARCH_STRING, **|
|** 's_meta_keys' => array('META_KEY_1','META_KEY_2'); **|
|** 'orderby' => 'date', **|
|** 'order' => 'DESC', **|
|** ); **|
|** $posts = new WP_Query($args); **|
|** **|
\************************************************************************/
add_action('pre_get_posts', 'my_search_query'); // add the special search fonction on each get_posts query (this includes WP_Query())
function my_search_query($query) {
if ($query->is_search() and $query->query_vars and $query->query_vars['s'] and $query->query_vars['s_meta_keys']) { // if we are searching using the 's' argument and added a 's_meta_keys' argument
global $wpdb;
$search = $query->query_vars['s']; // get the search string
$ids = array(); // initiate array of martching post ids per searched keyword
foreach (explode(' ',$search) as $term) { // explode keywords and look for matching results for each
$term = trim($term); // remove unnecessary spaces
if (!empty($term)) { // check the the keyword is not empty
$query_posts = $wpdb->prepare("SELECT * FROM {$wpdb->posts} WHERE post_status='publish' AND ((post_title LIKE '%%%s%%') OR (post_content LIKE '%%%s%%'))", $term, $term); // search in title and content like the normal function does
$ids_posts = [];
$results = $wpdb->get_results($query_posts);
if ($wpdb->last_error)
die($wpdb->last_error);
foreach ($results as $result)
$ids_posts[] = $result->ID; // gather matching post ids
$query_meta = [];
foreach($query->query_vars['s_meta_keys'] as $meta_key) // now construct a search query the search in each desired meta key
$query_meta[] = $wpdb->prepare("meta_key='%s' AND meta_value LIKE '%%%s%%'", $meta_key, $term);
$query_metas = $wpdb->prepare("SELECT * FROM {$wpdb->postmeta} WHERE ((".implode(') OR (',$query_meta)."))");
$ids_metas = [];
$results = $wpdb->get_results($query_metas);
if ($wpdb->last_error)
die($wpdb->last_error);
foreach ($results as $result)
$ids_metas[] = $result->post_id; // gather matching post ids
$merged = array_merge($ids_posts,$ids_metas); // merge the title, content and meta ids resulting from both queries
$unique = array_unique($merged); // remove duplicates
if (!$unique)
$unique = array(0); // if no result, add a "0" id otherwise all posts wil lbe returned
$ids[] = $unique; // add array of matching ids into the main array
}
}
if (count($ids)>1)
$intersected = call_user_func_array('array_intersect',$ids); // if several keywords keep only ids that are found in all keywords' matching arrays
else
$intersected = $ids[0]; // otherwise keep the single matching ids array
$unique = array_unique($intersected); // remove duplicates
if (!$unique)
$unique = array(0); // if no result, add a "0" id otherwise all posts wil lbe returned
unset($query->query_vars['s']); // unset normal search query
$query->set('post__in',$unique); // add a filter by post id instead
}
}
示例用法:
$search= "kewords to search";
$args = array(
'numberposts' => -1,
'post_type' => 'post',
's' => $search,
's_meta_keys' => array('short_desc','tags');
'orderby' => 'date',
'order' => 'DESC',
);
$posts = new WP_Query($args);
本示例将在文章标题,说明和元键中查找关键字“要搜索的关键词” short_desc'和'tags'。
关键字可以在一个或多个文件中找到,以任何顺序,它将返回任何在任何指定字段中包含所有关键字的帖子。
您可以如果您希望所有搜索查询都包含这些元键,请强行将搜索包含在功能中的元键列表中,并消除多余的麻烦:)
希望对您有所帮助谁遇到过我遇到的同样的问题!
#10 楼
这是一个很棒的解决方案,但是您需要修复一件事。当您调用“ post__in”时,您需要设置一个ID数组,而$ unique是一个数组。
示例:
$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
));
#11 楼
@ satbir-kira答案很好用,但只会搜索meta和文章标题。如果您希望它搜索元,标题和内容,则为修改后的版本。 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']
替换为您的搜索值#12 楼
这是另一种方法,只需使用“ posts_where_request”过滤器更改请求即可。除了('s AND'meta_query')=>('s'OR'meta_query')以外,所有内容仍将是默认值。AND ( ((posts.post_title LIKE 'Lily') OR (posts.post_excerpt LIKE 'Lily') OR (posts.post_content LIKE 'Lily')) )
AND ( ( postmeta.meta_key = 'author' AND postmeta.meta_value LIKE 'Lily' ) )
=>
AND (
( ( postmeta.meta_key = 'author' AND postmeta.meta_value LIKE 'Lily' ) )
OR
((posts.post_title LIKE 'Lily') OR (posts.post_excerpt LIKE 'Lily') OR (posts.post_content LIKE 'Lily'))
)
这是代码
function edit_request_wp_query( $where ) {
global $wpdb;
if ( strpos($where, $wpdb->postmeta.'.meta_key') && strpos($where, $wpdb->posts.'.post_title') ) {
$string = $where;
$index_meta = index_argument_in_request($string, $wpdb->postmeta.'.meta_key', $wpdb->postmeta.'.meta_value');
$meta_query = substr($string, $index_meta['start'], $index_meta['end']-$index_meta['start']);
$string = str_replace( $meta_query, '', $string );
$meta_query = ltrim($meta_query, 'AND').' OR ';
$index_s = index_argument_in_request($string, $wpdb->posts.'.post_title');
$insert_to = strpos($string, '(', $index_s['start'])+1;
$string = substr_replace($string, $meta_query, $insert_to, 0);
$where = $string;
}
return $where;
}
add_filter('posts_where_request', 'edit_request_wp_query');
function index_argument_in_request($string, $key_start, $key_end = '') {
if (!$key_end) $key_end = $key_start;
$index_key_start = strpos($string, $key_start);
$string_before = substr($string, 0, $index_key_start);
$index_start = strrpos($string_before, 'AND');
$last_index_key = strrpos($string, $key_end);
$index_end = strpos($string, 'AND', $last_index_key);
return ['start' => $index_start, 'end' => $index_end];
}
评论
仅使用一个搜索查询就无法实现您想做的事情。您将需要分别运行两个查询,然后将它们合并在一起。在其他答案中对此进行了描述。它应该帮助您进行操作。 wordpress.stackexchange.com/questions/55519/…