【问题标题】:meta_query search names when they have middle initials - PHP, WordPressmeta_query 搜索具有中间首字母的名称 - PHP、WordPress
【发布时间】:2021-06-01 00:34:04
【问题描述】:

我必须构建一个搜索表单,在其中按全名(名字 + 中间名首字母 + 姓氏)搜索公司成员。所有名字都采用这种形式:John B. Doe

以下代码正在处理这些情况:John, John B., Doe, B., John B. Doe,但查询搜索无效:John Doe

 if (isset($_POST['search']) && $_POST['search'] != -1) {
    $args['meta_query']['name_search']['key'] = "_full_name";
    $args['meta_query']['name_search']['compare'] = "LIKE";
    $args['meta_query']['name_search']['value'] = $_POST['search'];
  }

我应该如何改进查询以便同时使用:姓名和姓氏 (John Doe) 以及姓名、姓氏和中间名首字母 (John B. Doe)?

【问题讨论】:

  • 实际上,WordPress 元查询支持REGEXP 作为compare 值。所以你可以使用正则表达式搜索。
  • @SallyCJ 我尝试使用 REGEXP 作为比较值,但它不起作用。
  • 您尝试使用的代码是什么?您没有使用与当前问题相同的value,是吗?我的意思是,请记住像.(“点”)这样的特殊字符需要正确转义。
  • @SallyCJ,我尝试将“LIKE”替换为“REGEXP”,并将其与代码的其他部分保持一致。
  • 好吧,难怪它不起作用..您需要提供一个有效的正则表达式模式,如John.*Doe 作为value。但是,如果“成员”指的是 WordPress 用户表 (wp_users) 中的用户,那么 WordPress 实际上会为每个用户添加两个自定义字段(first_namelast_name),因此您可以只使用这些字段字段,至于中间的首字母,您可以使用另一个字段,例如middle_initial,然后您只需使用 OR 关系查询这些字段..

标签: php wordpress search meta-key codex


【解决方案1】:

首先,如果只有 WordPress 不转义 value(即搜索关键字)中的 % 字符,您可以简单地将搜索关键字中的空格替换为 %,因此您会得到一个类似meta_value LIKE '%John%Doe%' 的子句,它会匹配John B. Doe

因此,因为搜索关键字中的 % 被转义(这是一件好事,顺便说一句),所以您可以改用 REGEXP(正则表达式搜索),然后用 .* 替换空格相当于LIKE 子句中的%

工作示例

在你的代码中替换这个:

$args['meta_query']['name_search']['compare'] = "LIKE";
$args['meta_query']['name_search']['value'] = $_POST['search'];

用这个:

// Build the regular expression pattern.
$list = preg_split( '/ +/', trim( $_POST['search'] ) );
$regex = implode( '.*', array_map( 'preg_quote', $list ) );

// Then set 'compare' to REGEXP and 'value' to the above pattern.
$args['meta_query']['name_search']['compare'] = 'REGEXP';
$args['meta_query']['name_search']['value'] = $regex;

在 WordPress 5.7.2 中经过尝试和测试,但请注意 MySQL reference manual 中的“非多字节安全”警告。

替代方案(与上述方案相同)

如果您想使用 LIKE 而不是 REGEXP,但又不想最终对同一键进行大量元查询,那么您可以:

使用三个搜索字段,即名字、姓氏和中间名首字母,以及三个元子句,每个搜索字段一个,但都将key 设置为_full_name。例如

/*
 * Assuming your form contains these:
    <input name="first_name">
    <input name="last_name">
    <input name="middle_initial">
 */

$name_search = array(
    'relation' => 'AND',
);

// * okay, this still uses 3 clauses, but it always would be just 3 clauses
foreach ( array( 'first_name', 'last_name', 'middle_initial' ) as $name ) {
    if ( ! empty( $_POST[ $name ] ) ) {
        $name_search[ $name ] = array(
            'key'     => '_full_name',
            'value'   => sanitize_text_field( $_POST[ $name ] ),
            'compare' => 'LIKE',
        );
    }
}

$args['meta_query']['name_search'] = $name_search;

【讨论】:

    【解决方案2】:

    我可以建议以下解决方案:

    $search = $_POST['search'];
    $words  = explode( $search, ' ' );
    $words  = array_filter(
        $words,
        function ( $word ) {
            return ! empty( trim( $word ) );
        }
    );
    
    foreach ( $words as $index => $word ) {
        $query_name          = "name_search_$index";
        $args['meta_query'][ $query_name ] = [
            'key'     => '_full_name',
            'value'   => $word,
            'compare' => 'LIKE',
        ];
    }
    

    代码说明:

    1. 我将搜索短语拆分为单词。单词是任何符号序列 空格之间
    2. 我删除了空格。如果您的搜索字符串是
      John Doe
      John Doe
       John Doe 
      ,则搜索结果应该相同。
    3. 我构建了多个查询。每个查询对应一个单词。如果您搜索 John Doe,则查询由 2 个查询构建。查询与字数一样重要。

    这个解决方案的问题:

    1. 字数太多就是查询太多。太多包含 LIKE 的查询太慢了。
    2. 搜索
      John Doe
      Doe John
      将得到相同的结果。单词的顺序对结果没有影响。

    我建议将此解决方案仅用作临时解决方案。 好的解决方案 - 正在使用全文搜索插件或编写全文搜索解决方案 你自己。有关全文搜索的更多详细信息,您可以在 MySQL 官方页面上找到: https://dev.mysql.com/doc/refman/8.0/en/fulltext-search.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-28
      • 2013-09-18
      • 1970-01-01
      • 1970-01-01
      • 2019-07-01
      • 1970-01-01
      相关资源
      最近更新 更多