问题描述

我想将搜索限制在英语+数字上使用的字符。原因是查看最慢的查询 mysql 日志我发现大多数来自阿拉伯,俄罗斯和汉字的搜索,所以我想跳过它们并显示一个错误信息。

最佳解决方案

此解决方案通过应用正则表达式来过滤搜索字符串,该正则表达式仅匹配 Common 和 Latin Unicode 脚本中的字符。


匹配拉丁字符与正则表达式

我只是 had my mind blown over at Stack Overflow 。事实证明,正则表达式具有匹配整个 Unicode 类别的 a mechanism,包括用于指定整个 Unicode “scripts” 的值,每个对应于不同写入系统中使用的字符组。

这是通过使用 p meta-character,后跟大括号中的 Unicode 类别标识符完成的,因此 [p{Common}p{Latin}]Latin or Common scripts 中的单个字符匹配 – 其中包括标点符号,数字和杂项符号。

作为 @Paul ‘Sparrow Hawk’ Biron points outu pattern modifier flag 应设置在正则表达式的末尾,以便 PHP 的 PCRE 功能将主题字符串视为 UTF-8 Unicode 编码。

所有在一起的模式

/^[p{Latin}p{Common}]+$/u

将匹配由拉丁文和通用 Unicode 脚本中的一个或多个字符组成的整个字符串。


过滤搜索字符串

拦截搜索字符串的好地方是在 WordPress 执行查询之前立即触发的 pre_get_posts 操作。更加小心,这也可以使用 request 滤波器完成。

function wpse261038_validate_search_characters( $query ) {
  // Leave admin, non-main query, and non-search queries alone
  if( is_admin() || !$query->is_main_query() || !$query->is_seach() )
    return;

  // Check if the search string contains only Latin/Common Unicode characters
  $match_result = preg_match( '/^[p{Latin}p{Common}]+$/u', $query->get( 's' ) );

  // If the search string only contains Latin/Common characters, let it continue
  if( 1 === $match_result )
    return;

  // If execution reaches this point, the search string contains non-Latin characters
  //TODO: Handle non-Latin search strings
  //TODO: Set up logic to display error message
}

add_action( 'pre_get_posts', 'wpse261038_validate_search_characters' );

响应不允许的搜索

一旦确定一个搜索字符串包含 non-Latin 字符,您可以使用 WP_Query::set()来修改查询,通过更改它的名称为 query vars – 从而影响 WordPress 后续编写和执行的 SQL 查询。

最相关的查询变量大概如下:

  • s 是与搜索字符串对应的查询变量。将其设置为 null 或空字符串 ('') 将导致 WordPress 不再将查询视为搜索 – 通常会导致存档模板显示站点的所有帖子或 front-page,具体取决于其他的值查询变量。然而,将其设置为单个空格 (' ') 将导致 WordPress 将其识别为搜索,从而尝试显示 search.php 模板。

  • page_id 可用于将用户引导到您选择的特定页面。

  • post__in 可以将查询限制为特定的帖子选择。通过将其设置为具有不可能的帖子 ID 的数组,it can serve as a measure to ensure that the query returns absolutely nothing

考虑到上述情况,您可以执行以下操作,以便通过加载 search.php 模板来响应不正确的搜索结果:

function wpse261038_validate_search_characters( $query ) {
  // Leave admin, non-main query, and non-search queries alone
  if( is_admin() || !$query->is_main_query() || !$query->is_seach() )
    return;

  // Check if the search string contains only Latin/Common Unicode characters
  $match_result = preg_match( '/^[p{Latin}p{Common}]+$/u', $query->get( 's' ) );

  // If the search string only contains Latin/Common characters, let it continue
  if( 1 === $match_result )
    return;

  $query->set( 's', ' ' ); // Replace the non-latin search with an empty one
  $query->set( 'post__in', array(0) ); // Make sure no post is ever returned

  //TODO: Set up logic to display error message
}

add_action( 'pre_get_posts', 'wpse261038_validate_search_characters' );

显示错误

实际显示错误消息的方式在很大程度上取决于您的应用程序和主题的能力 – 有很多方法可以完成。如果您的主题在其搜索模板中调用 get_search_form(),则最简单的解决方案可能是使用 pre_get_search_form 动作钩子在搜索表单上方输出错误:

function wpse261038_validate_search_characters( $query ) {
  // Leave admin, non-main query, and non-search queries alone
  if( is_admin() || !$query->is_main_query() || !$query->is_seach() )
    return;

  // Check if the search string contains only Latin/Common Unicode characters
  $match_result = preg_match( '/^[p{Latin}p{Common}]+$/u', $query->get( 's' ) );

  // If the search string only contains Latin/Common characters, let it continue
  if( 1 === $match_result )
    return;

  $query->set( 's', ' ' ); // Replace the non-latin search with an empty one
  $query->set( 'post__in', array(0) ); // Make sure no post is ever returned

  add_action( 'pre_get_search_form', 'wpse261038_display_search_error' );
}

add_action( 'pre_get_posts', 'wpse261038_validate_search_characters' );

function wpse261038_display_search_error() {
  echo '<div class="notice notice-error"><p>Your search could not be completed as it contains characters from non-Latin alphabets.<p></div>';
}

显示错误消息的其他一些可能性包括:

  • 如果您的站点使用可以显示 「flash」 或 「modal」 消息的 JavaScript(或者您自己添加这些功能),则添加一个逻辑来在设置特定变量时显示 page-load 上的消息,然后添加一个 wp_enqueue_script 钩子一个大于排列该 JavaScript 的 $priority,并使用 wp_localize_script()将该变量设置为包含错误消息。

  • 使用 wp_redirect()将用户发送到您选择的 URL(此方法需要额外的页面加载) 。

  • 设置一个 PHP 变量或调用一个方法,它将通知您的主题/插件有关错误,以便它可以在适当的时候显示。

  • s 查询变量设置为''而不是' ',并使用 page_id 代替 post__in,以返回您选择的页面。

  • 使用 loop_start 钩子将含有错误的假 WP_Post 对象注入到查询结果中 – 这绝对是一个丑陋的黑客,可能不符合您的特定主题,但它具有抑制”No Results” 消息的潜在可能的副作用。

  • 使用 template_include 过滤器挂钩,在您的主题或插件中显示您的错误,使用自定义的模板交换搜索模板。

没有检查有关的主题,很难确定你应该采用哪条路线。

参考文献

注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。