简体   繁体   English

具有中间首字母的 meta_query 搜索名称 - PHP、WordPress

[英]meta_query search names when they have middle initials - PHP, WordPress

I have to build a search form where I search members of the company by their Full Name (First Name + Middle Initial + Last Name).我必须建立一个搜索表单,在其中按全名(名字+中间名首字母+姓氏)搜索公司成员。 All the names are in this form: John B. Doe .所有的名字都采用这种形式: John B. Doe

The below code is working on these cases: John, John B., Doe, B., John B. Doe , but not working the query search is: John 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'];
  }

How should I improve the query in order to work with both: the name and surname (John Doe) and the name, surname plus the middle initial (John B. Doe)?我应该如何改进查询以便同时使用:姓名和姓氏 (John Doe) 以及姓名、姓氏和中间名首字母 (John B. Doe)?

First off, if only WordPress doesn't escape the % characters in the value (ie the search keyword), you could've simply replaced spaces in the search keyword with % , hence you'd get a clause like meta_value LIKE '%John%Doe%' which would match John B. Doe .首先,如果只有 WordPress 没有转义value中的%字符(即搜索关键字),你可以简单地将搜索关键字中的空格替换为% ,因此你会得到一个像meta_value LIKE '%John%Doe%'匹配John B. Doe

So because the % in the search keyword is being escaped (which is a good thing, BTW), then you can instead use REGEXP (regular expression search) and then replace the spaces with a .* which is equivalent to the % in a LIKE clause.因此,因为搜索关键字中的%被转义(这是一件好事,顺便说一句),所以您可以改用REGEXP (正则表达式搜索),然后用.*替换空格,这相当于LIKE中的%条款。

Working Example工作示例

Replace this in your code:在您的代码中替换它:

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

with this:有了这个:

// 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;

Tried & tested working in WordPress 5.7.2, but do take note of the "not multibyte safe" warning in the MySQL reference manual .在 WordPress 5.7.2 中进行了尝试和测试,但请注意MySQL 参考手册中的“非多字节安全”警告。

Alternate Solution (equivalent to the one above)替代解决方案(相当于上述一种)

If you want to use LIKE and not REGEXP , but don't want to end up with potentially lots of meta queries for the same key, then you can:如果您想使用LIKE而不是REGEXP ,但又不想对同一个键进行潜在的大量元查询,那么您可以:

Use three search fields, namely first name, last name, and middle initial, and three meta clauses, one for each search field, but all having key set to _full_name .使用三个搜索字段,即名字、姓氏和中间名首字母,以及三个元子句,每个搜索字段一个,但都将key设置为_full_name Eg例如

/*
 * 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;

I can suggest the following solution:我可以建议以下解决方案:

$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',
    ];
}

Code explanation:代码说明:

  1. I split search phrases into words.我将搜索短语拆分为单词。 Words are any sequence of symbols between spaces单词是空格之间的任何符号序列
  2. I remove spaces.我删除空格。 If your search string is如果您的搜索字符串是
    John Doe约翰·多伊
    or或者
    John Doe约翰·多伊
    or或者
    John Doe约翰·多伊
    The search result should be the same.搜索结果应该是一样的。
  3. I build multiple queries.我构建了多个查询。 Every query corresponds to a single word.每个查询对应一个单词。 If you search John Doe the query builds by 2 queries.如果您搜索 John Doe,则查询由 2 个查询构建。 Queries count as much as the number of words.查询与字数一样重要。

The problems with this solution:此解决方案的问题:

  1. Too many words are too many queries.太多的单词就是太多的查询。 Too many LIKE-containing queries are too slow.太多包含 LIKE 的查询太慢。
  2. You will get the same result for searching for您将获得相同的搜索结果
    John Doe约翰·多伊
    and
    Doe John美国能源部约翰
    . . The order of the words makes no difference to the result.单词的顺序对结果没有影响。

I recommend using this solution only as a temporary solution.我建议仅将此解决方案用作临时解决方案。 Good solution - is using Full-Text Search plugins or write Full-Text Search solution yourself.好的解决方案 - 使用全文搜索插件或自己编写全文搜索解决方案。 More details about FullText search you could find on MySQL official page: https://dev.mysql.com/doc/refman/8.0/en/fulltext-search.html More details about FullText search you could find on MySQL official page: https://dev.mysql.com/doc/refman/8.0/en/fulltext-search.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM