This string, meta_value LIKE '%user-input-value%'"
, contains percentage wilcards (%
) that indicate that we're looking for a row where meta_value
column contains user-input-value
as part of its value.
$wpdb->prepare
converts them into hashes, and the MySQL server gets something like this: meta_value LIKE '{399038939300d2c307c53b29a166ee90101da7b2aba7978a898694010bf1bfe6}user-input-value{399038939300d2c307c53b29a166ee90101da7b2aba7978a898694010bf1bfe6}'
. Naturally, I was getting no results!
The wpdb::prepare page reads, 'Literal percentage signs (%) in the query string must be written as %%. Percentage wildcards (for example, to use in LIKE syntax) must be passed via a substitution argument containing the complete LIKE string, these cannot be inserted directly in the query string. Also see wpdb::esc_like().'
So, the LIKE
part must be prepared like this (example from the wpdb::esc_like() page):
$wild = '%';
$find = 'only 43% of planets';
$like = $wild . $wpdb->esc_like( $find ) . $wild;
$sql = $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_content LIKE %s", $like );
Where $wpdb->esc_like()
should go before $wpdb->prepare()
.
And if one wants to replace percentage wildcard placeholders manually, they should use $wpdb->remove_placeholder_escape() after $wpdb->prepare()
.
I ended up with this code, which worked:
$key = 'user-input-key';
$value = 'user-input-value';
$value = '%' . $wpdb->esc_like($value) . '%';
$query = "SELECT * FROM {$wpdb->prefix}postmeta WHERE meta_key=%s AND meta_value LIKE %s";
$prepared_query = $wpdb->prepare($query, array($key,$value));
$prepared_query = $wpdb->remove_placeholder_escape($prepared_query);
$query = $wpdb->get_results($prepared_query);