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

例如,如果您为所有 postspages 设置了此值,您可以尝试这样做:

$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 值的主要内容,如果未能解决你的问题,请参考以下文章

WordPress |帖子查询 |查询帖子类别以创建子类别过滤器并将其应用于我的函数文件中的 Ajax 过滤器

如何排除按钮被过滤?

Wordpress 搜索功能仅搜索帖子

PHP 从Wordpress搜索结果中排除帖子或页面

从Wordpress的搜索结果中排除特定类别

PHP 从Wordpress中的搜索结果中排除特定类别