Wordpress - 过滤搜索查询以排除 postmeta 值
Posted
技术标签:
【中文标题】Wordpress - 过滤搜索查询以排除 postmeta 值【英文标题】:Wordpress - Filter search query to exclude postmeta value 【发布时间】:2021-10-29 23:34:14 【问题描述】:在我的 wordpress 网站中,我使用pre_get_posts
过滤器来自定义我的网站搜索查询。在函数文件中,我有以下内容。
现在我的问题是,我使用 FieldManager 添加了一个名为 hide_from_search_results
的自定义元字段,该字段现在包含在我的 wp_postmeta
表中,值为 0 或 1 整数。但是,并非所有帖子/页面都会设置此字段。我需要添加条件以不显示任何将此设置为 1 的内容。
首先我加入了wp_posts
和wp_postmeta
表,如下所示:
function cf_search_join( $join )
global $wpdb;
if ( is_search() && !is_admin() )
$join .=' LEFT JOIN '.$wpdb->postmeta. ' ON '. $wpdb->posts . '.ID = ' . $wpdb->postmeta . '.post_id ';
return $join;
add_filter('posts_join', 'cf_search_join' );
然后我按帖子 ID 对结果进行分组:
function cf_posts_groupby($groupby)
global $wpdb;
if (is_search() && !is_admin())
return $wpdb->posts . '.' . 'ID';
return $groupby;
add_filter( 'posts_groupby', 'cf_posts_groupby' );
使用posts_where
修改搜索查询,例如从结果中排除图片:
function cf_search_where( $where )
global $pagenow, $wpdb;
if ( is_search() && !is_admin() )
$where = preg_replace(
"/\(\s*".$wpdb->posts.".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
"(".$wpdb->posts.".post_title LIKE $1) OR (".$wpdb->postmeta.".meta_value LIKE $1)", $where );
$where .= ' AND ' . $wpdb->posts . '.post_mime_type != "image/jpeg"';
return $where;
add_filter( 'posts_where', 'cf_search_where' );
我最后使用pre_get_posts
更改查询以包含某些帖子类型并仅显示已发布:
function cf_posts_query( $query )
if ( is_search() && !is_admin() )
if (isset($_GET['post_types']))
$query->set('post_type', $_GET['post_types']);
else
$query->set('post_type', ['page']);
$query->set( 'post_status', array( 'publish', 'inherit' ) );
return $query;
add_filter( 'pre_get_posts', 'cf_posts_query' );
我尝试将以下内容添加到我的cf_posts_query
$query->set( 'meta_query', array(
array(
'key' => 'hide_from_search_results',
'compare' => '!=',
'value' => 1
)
));
但是得到以下错误:
WordPress database error: [Not unique table/alias: 'wp_postmeta']
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) LEFT JOIN wp_postmeta ON wp_posts.ID = wp_postmeta.post_id WHERE 1=1 AND wp_posts.ID NOT IN (4440,4436) AND (((wp_posts.post_title LIKE '%coron%') OR (wp_postmeta.meta_value LIKE '%coron%') OR (wp_posts.post_excerpt LIKE '%coron%') OR (wp_posts.post_content LIKE '%coron%'))) AND ( ( wp_postmeta.meta_key = 'hide_from_search_results' AND wp_postmeta.meta_value != '1' ) ) AND wp_posts.post_type = 'page' AND ((wp_posts.post_status = 'publish' OR wp_posts.post_status = 'inherit')) AND wp_posts.post_mime_type != "image/jpeg" GROUP BY wp_posts.ID ORDER BY wp_posts.post_title LIKE '%coron%' DESC, wp_posts.post_date DESC LIMIT 0, 20
WordPress database error: [Not unique table/alias: 'wp_postmeta']
SELECT wp_posts.* FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) LEFT JOIN wp_postmeta ON wp_posts.ID = wp_postmeta.post_id WHERE 1=1 AND wp_posts.post_name IN ('search') AND wp_posts.ID NOT IN (4440,4436) AND ( 0 = 1 ) AND ( ( wp_postmeta.meta_key = 'hide_from_search_results' AND wp_postmeta.meta_value != '1' ) ) AND wp_posts.post_type = 'page' AND ((wp_posts.post_status = 'publish' OR wp_posts.post_status = 'inherit')) AND wp_posts.post_mime_type != "image/jpeg" GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC
或者,我尝试在我的 cf_search_where
函数中添加这个
$where .= ' AND (' . $wpdb->postmeta . '.meta_key != "hide_from_search_results") OR (' . $wpdb->postmeta . '.meta_key == "hide_from_search_results" AND ' . $wpdb->postmeta . '.meta_value == 1)';
但是得到:
WordPress database error: [You have an error in your SQL syntax; check the manual that corresponds to your mysql server version for the right syntax to use near '== "hide_from_search_results" AND wp_postmeta.meta_value == "1") AND wp_posts.po' at line 1]
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts LEFT JOIN wp_postmeta ON wp_posts.ID = wp_postmeta.post_id WHERE 1=1 AND wp_posts.ID NOT IN (4440,4436) AND (((wp_posts.post_title LIKE '%coron%') OR (wp_postmeta.meta_value LIKE '%coron%') OR (wp_posts.post_excerpt LIKE '%coron%') OR (wp_posts.post_content LIKE '%coron%'))) AND wp_posts.post_type = 'page' AND ((wp_posts.post_status = 'publish' OR wp_posts.post_status = 'inherit')) AND (wp_postmeta.meta_key != "hide_from_search_results") OR (wp_postmeta.meta_key == "hide_from_search_results" AND wp_postmeta.meta_value == "1") AND wp_posts.post_mime_type != "image/jpeg" GROUP BY wp_posts.ID ORDER BY wp_posts.post_title LIKE '%coron%' DESC, wp_posts.post_date DESC LIMIT 0, 20
WordPress database error: [You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '== "hide_from_search_results" AND wp_postmeta.meta_value == "1") AND wp_posts.po' at line 3]
SELECT wp_posts.* FROM wp_posts LEFT JOIN wp_postmeta ON wp_posts.ID = wp_postmeta.post_id WHERE 1=1 AND wp_posts.post_name IN ('search') AND wp_posts.ID NOT IN (4440,4436) AND ( 0 = 1 ) AND wp_posts.post_type = 'page' AND ((wp_posts.post_status = 'publish' OR wp_posts.post_status = 'inherit')) AND (wp_postmeta.meta_key != "hide_from_search_results") OR (wp_postmeta.meta_key == "hide_from_search_results" AND wp_postmeta.meta_value == "1") AND wp_posts.post_mime_type != "image/jpeg" GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC
【问题讨论】:
【参考方案1】:不知道为什么要编写自己的sql
语句和查询。我会尽可能避免编写自己的sql
查询,因为这些自定义sql
查询可能会使您容易受到slq
攻击。在您确实必须编写自己的sql
查询的情况下,请考虑使用$wpdb->prepare
。但是,我总是使用wp_query
。
也不确定您是否将meta_values
存储为整数或字符串。我假设它们是字符串。
话虽如此,您可以通过多种方式设置meta_query
:
例如,如果您为所有 posts
和 pages
设置了此值,您可以尝试这样做:
$query->set( 'meta_query', array(
array(
'key' => 'hide_from_search_results',
'value' => '0'
)
));
您可以尝试的另一种解决方案(这个解决方案有望解决您的问题):
$query->set( 'meta_query', array(
array(
'key' => 'hide_from_search_results',
'value' => array( '1' ),
'compare' => 'NOT IN'
)
));
老实说,由于那些自定义的sql
查询,您的问题很难重现,而且您的meta_value
类型并不清楚它是整数还是字符串,因此您可能需要尝试meta_query
的不同组合。如果我的回答没有满足您的需求,那么以下链接将是开始尝试 meta_query
的不同组合的好地方:
meta_query documentation
更新
如果您的 meta_value
是一个整数,那么您必须从您的值中删除“引号”。
$query->set( 'meta_query', array(
array(
'key' => 'hide_from_search_results',
'value' => array( 1 ),
'compare' => 'NOT IN'
)
));
或者
$query->set( 'meta_query', array(
array(
'key' => 'hide_from_search_results',
'value' => 1,
'compare' => '!=',
'type'=>'numeric'
)
));
【讨论】:
谢谢。该值是一个整数(我已经更新了我原来的问题)。我已经尝试过您的代码,但它仍然会给出WordPress database error: [Not unique table/alias: 'wp_postmeta']
的错误,或者如果我在 cf_search_join
函数中添加表别名,则它根本不返回任何结果(尽管没有引发错误)
好的!刚刚更新了我的答案。请试一试!
不幸的是,仍然有相同的结果,搜索要么抛出表别名错误,要么不返回具有表别名的结果。
这些错误是意料之中的。就像我说的那样,自定义sql
查询可能会引发各种令人讨厌的错误和漏洞,从长远来看,这会使您的代码难以维护,从而使您的生活更加艰难。话虽如此,您在评论中提到的错误与表别名有关。所以考虑使用$wpdb->prefixpostmeta
而不是wp_postmeta
。看看这是否会调试你的代码。以上是关于Wordpress - 过滤搜索查询以排除 postmeta 值的主要内容,如果未能解决你的问题,请参考以下文章