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.
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
.
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)?
First off, if only WordPress doesn't escape the %
characters in the value
(i.e. 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
.
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.
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.
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:
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
. E.g.
/*
* 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;