WordPress 管理员搜索:扩展结果

已发表: 2021-01-20

有时在网站上查找内容可能很困难。 作为 WordPress 管理员,越容易找到您想要的内容就越好。 值得庆幸的是,WordPress 在您将使用的大多数管理屏幕(例如帖子屏幕)上都提供了搜索功能。 尽管此搜索功能很好,但它仍然在许多方面受到限制。

例如,如果您在帖子管理屏幕中搜索帖子,默认情况下,搜索功能将在帖子标题、帖子摘录和帖子内容中查找搜索查询文本,然后返回这些结果。 但是,如果您想使用与自定义字段相关的关键字进行搜索怎么办? 此信息不包含在管理员帖子列表表搜索结果中,这可能会令人沮丧。

在之前的文章中,我们学习了如何在我们的帖子类型中添加自定义字段。 让我们看看如何在搜索结果中包含自定义字段。

在管理屏幕搜索中扩展搜索查询

在我们关于自定义字段的工作示例中,我们在其中一个帖子中创建了一个名为“source”的自定义字段并插入了一个 URL 值。

如果您进入帖子列表并在搜索栏中使用这些“来源”值之一,您将不会得到任何结果,因为 WordPress 在默认情况下搜索时根本不查看自定义字段。

为了改变这一点,我们需要扩展 WordPress 为搜索功能提供的原始钩子。 我们必须扩展的钩子是pre_get_posts ,它包含在wp-includes/class-wp-query.php文件中get_posts函数内的第 1779 行附近。

WordPress 查询

每次您访问页面时,无论是在前视图还是管理区域,都会执行一系列代码脚本,以创建与您的请求相对应的WP_Query对象及其属性。

让我们创建一些查询属性输出的临时视图,以了解在每种情况下WP_Query对象中发生的变化。

为了在执行之前查看查询,我们将在pre_get_posts操作挂钩中附加打印。 pre_get_posts过滤器在创建查询变量对象之后触发,但在实际查询运行之前。

在活动主题的functions.php文件中插入这段代码:

 add_action( 'pre_get_posts', 'print_query' ); function print_query( ) { print_r ( $GLOBALS['wp_query']->query ); echo "<hr>"; print_r ( $GLOBALS['wp_query']->query_vars ); echo "<hr>"; }

现在,如果您访问 Posts 管理屏幕, queryquery_var的输出将打印在顶部。

要更轻松地查看代码,您可以将其复制并粘贴到免费的在线 PHP 美化器中。

$GLOBALS['wp_query']->query数组(先出)将如下所示:

 Array ( [order] => [orderby] => [post_type] => post [posts_per_page] => 20 [post_status] => [perm] => )

例如,在帖子管理屏幕中进行搜索时,数组输出将更改,包括搜索字符串。 例如,如果我们搜索“wordpress.org”,它将如下所示:

 Array ( [m] => 0 [cat] => 0 [s] => wordpress.org [paged] => 1 [order] => [orderby] => [post_type] => post [posts_per_page] => 20 [post_status] => [perm] => )

组装代码

记住以上信息我们将插入正确的代码来实现我们需要的搜索功能。 为此,请返回活动主题的functions.php并删除您刚才在上一步中插入的代码。 然后插入下面的代码:

 add_action( 'pre_get_posts', 'extend_admin_search' ); function extend_admin_search( $query ) { $post_type = 'post'; $custom_fields = array("source",); if( ! is_admin() ) return; if ( $query->query['post_type'] != $post_type ) return; $search_term = $query->query_vars['s']; $query->query_vars['s'] = ''; if ( $search_term != '' ) { $meta_query = array( 'relation' => 'OR' ); foreach( $custom_fields as $custom_field ) { array_push( $meta_query, array( 'key' => $custom_field, 'value' => $search_term, 'compare' => 'LIKE' )); } $query->set( 'meta_query', $meta_query ); }; }

下一步是将$post_type$custom_fields变量更改为适用于您的要求的值。 让我们看看我们在代码中做了什么。

  • $post_type = 'post'; – 在这里我们定义我们要搜索的帖子类型。
  • $custom_fields = array("source",); – 在这里我们定义我们想要搜索的自定义字段。

因为我们正在使用pre_get_posts钩子,所以在我们的代码中确保我们在正确的页面上应用我们的自定义搜索扩展是很重要的。 Τo 告诉 WordPress 在特定条件下显示我们的代码,我们使用一些条件标签。

  • if ( ! is_admin() ) return; 条件确保如果我们不在管理区域,我们的任何代码都不会执行。
  • if ( $query->query['post_type'] != $post_type )检查我们是否在$post_type变量中定义的帖子类型上工作。 在我们的例子中, post .
  • $search_term = $query->query_vars['s']; 是我们将搜索字符串保存在变量中,然后我们再次将其设置为空$query->query_vars['s'] = ''; 否则它将找不到任何东西。

现在,有了这些更新,如果您刷新上次搜索,您将获得正确的结果。 在我们的例子中,我们在结果中看到“帖子 1”帖子,其中包括“来源”自定义字段条目:“https://dev. wordpress.org /reference/functions/add_post_meta/'。

改进 wordpress 管理员搜索

在前视图搜索中扩展搜索查询

现在我们已经“修复”了我们的管理员搜索,我们可以继续改进我们的前端搜索功能,以便我们的网站用户也可以搜索自定义字段。

与以前管理员搜索不会为自定义字段生成任何结果的方式相同,前端搜索也无法返回任何自定义字段的结果。

理想情况下,我们希望用户能够搜索这些字段。 在此示例中,我们的一篇文章中有一个自定义的“来源”字段,该字段当前包含 URL“https://dev.wordpress.org/reference/functions/add_post_meta/”。 如果用户搜索“wordpress.org”,则此帖子应显示在结果中。 让我们看看如何做到这一点。

所需的代码

再次前往您的functions.php 文件并复制您之前粘贴的代码。 现在,将其直接粘贴到该代码下方(因此您在functions.php中有此代码的两个副本) 现在,将第二批代码中的函数名称更改为类似于extend_front_search的名称。 它应该如下所示:

 add_action( 'pre_get_posts', 'extend_admin_search' ); function extend_admin_search( $query ) { $post_type = 'post'; $custom_fields = array("source",); if( ! is_admin() ) return; if ( $query->query['post_type'] != $post_type ) return; $search_term = $query->query_vars['s']; $query->query_vars['s'] = ''; if ( $search_term != '' ) { $meta_query = array( 'relation' => 'OR' ); foreach( $custom_fields as $custom_field ) { array_push( $meta_query, array( 'key' => $custom_field, 'value' => $search_term, 'compare' => 'LIKE' )); } $query->set( 'meta_query', $meta_query ); }; }

接下来,我们需要删除if ( $query->query['post_type'] != $post_type ) return; 健康)状况。

 add_action( 'pre_get_posts', 'extend_front_search' ); function extend_front_search( $query ) { $post_type = 'post'; $custom_fields = array("source",); if( is_admin() ) return; $search_term = $query->query_vars['s']; $query->query_vars['s'] = ''; if ( $search_term != '' ) { $meta_query = array( 'relation' => 'OR' ); foreach( $custom_fields as $custom_field ) { array_push( $meta_query, array( 'key' => $custom_field, 'value' => $search_term, 'compare' => 'LIKE' )); } $query->set( 'meta_query', $meta_query ); }; }

我们只需要维护条件if( is_admin() ) return; 确保代码仅适用于前端,我们很高兴。

另一种策略

扩展 WordPress 搜索以包含自定义字段的另一种方法是更改​​ SQL 查询。

WP_Query类通过将其分解为wp-includes/class-wp-query.php文件的第 2897 行所描述的部分来帮助您。

 $clauses = (array) apply_filters_ref_array( 'posts_clauses_request', array( compact( $pieces ), &$this ) ); $where = isset( $clauses['where'] ) ? $clauses['where'] : ''; $groupby = isset( $clauses['groupby'] ) ? $clauses['groupby'] : ''; $join = isset( $clauses['join'] ) ? $clauses['join'] : ''; $orderby = isset( $clauses['orderby'] ) ? $clauses['orderby'] : ''; $distinct = isset( $clauses['distinct'] ) ? $clauses['distinct'] : ''; $fields = isset( $clauses['fields'] ) ? $clauses['fields'] : ''; $limits = isset( $clauses['limits'] ) ? $clauses['limits'] : '';

正如我们之前在自定义字段文章中提到的,所有自定义字段数据都存储在数据库中的“postmeta”表中,默认情况下该表不包含在 WordPress 搜索中。 所以我们的第一步是使用下面的代码连接这两个表

 function join_meta_table( $join ) { global $wpdb; if ( is_search() ) { $join .=' LEFT JOIN '.$wpdb->postmeta. ' ON '. $wpdb->posts . '..post_id '; } return $join; } add_filter('posts_join', 'join_meta_table' );

我们当然使用了posts_join钩子,因为它过滤了查询的 JOIN 子句。

接下来,我们将使用posts_where挂钩来更改查询的 WHERE 部分以满足我们的需要。

 function modify_where_clause( $where ) { global $pagenow, $wpdb; if ( is_search() ) { $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 ); } return $where; } add_filter( 'posts_where', 'modify_where_clause' );

最后但同样重要的是,我们需要防止重复。 为此,我们使用过滤查询的 DISTINCT 子句的posts_distinct挂钩。

 function prevent_duplicates( $where ) { global $wpdb; if ( is_search() ) { return "DISTINCT"; } return $where; } add_filter( 'posts_distinct', 'prevent_duplicates' );

现在让我们看看如果我们搜索“wordpress.org”字符串在前端会发生什么。

前端的wordpress搜索

不出所料,这次的结果是正确的。 WordPress 搜索结果发现“post 1”,因为它包含值为“https://dev”的“源”字段。 wordpress.org /reference/functions/add_post_meta/

WordPress 搜索结果中的自定义帖子类型

您可能想要做的另一件事是使自定义帖子类型可搜索(如果您不确定如何创建自定义帖子类型,请确保在此处查看我们的文章)。

假设我们创建了一个名为“books”的自定义帖子类型,我们希望这个帖子类型出现在搜索结果中。 这次我们不必重新创建 SQL 查询,只需在pre_get_posts钩子中重新定义帖子类型,如下所示。 代码必须再次放置在functions.php文件中。

 function tg_include_custom_post_types_in_search_results( $query ) { if ( $query->is_main_query() && $query->is_search() && ! is_admin() ) { $query->set( 'post_type', array( 'post', 'books' ) ); } } add_action( 'pre_get_posts', 'tg_include_custom_post_types_in_search_results' );

我们在这里所做的是将要包含在搜索结果中的所需帖子类型作为参数添加到post_type挂钩。

如果您想排除一种类型,只需将其从数组中删除即可。

结论

改进 WordPress 网站上的搜索确实很有帮助,并且可以节省大量时间。 对于您的最终用户来说,他们可以搜索自定义帖子类型和自定义字段也很重要。 希望上面的说明能让您深入了解如何在您自己的网站上实现这一目标。