Fixing the {hash} in WordPress LIKE queries.

Have you ever tried to search WordPress custom fields using a meta_query with 'LIKE' — and found that no results were returned, despite knowing the data existed? This was the situation that confronted me recently, and after a few hours I was beginning to wonder whether I’d totally lost my marbles or…well…is something weird happening behind the scenes?

I did my usual trick of sticking a lot of var_dump() and echo statements in, to allow me to inspect the generated SQL and see what was happening. And that’s when I saw it….

meta_value LIKE '{37e505e5...}print{37e505e5...}'

instead of the expected:

meta_value LIKE '%print%'

This is a subtle and frustrating quirk in how WordPress builds LIKE meta queries. In this post, we’ll explore why this happens, how to avoid or fix it, and provide clean workarounds you can rely on.

What’s Going On with {hash}?

Since WordPress 5.3, when you use a meta query with 'compare' => 'LIKE', WordPress automatically processes the value using:

$wpdb->esc_like( $value )

This function escapes any % or _ characters in your search term to protect against malformed SQL or injection.

But here’s the catch: if you manually add % wildcards or specify 'type' => 'CHAR', WordPress escapes the value and wraps it with a hash like:

LIKE '{somehash}search{somehash}'

Which is not a valid wildcard match and breaks your query. This is a nice way of stopping SQL injection hacks, but it can be a bit perplexing until you realise what’s happening!

Common Mistake That Triggers the Problem

This seemingly safe query causes the issue:

[
    'key'     => 'ew_serv_locations',
    'value'   => '%' . $search_term . '%',
    'compare' => 'LIKE',
    'type'    => 'CHAR'
]

WordPress sees your wildcard and overprotects it, producing SQL like:

meta_value LIKE '{hash}print{hash}'

Unfortunately, this can also happen without you manually putting the % characters in. Sometimes, it just happens and then we need to fix it….

The Fixes — How to Write LIKE Queries Safely

1. Let WordPress Handle the Wildcards

Don’t add % yourself — just pass the raw value:

[
    'key'     => 'ew_serv_locations',
    'value'   => $search_term,
    'compare' => 'LIKE'
]

This produces clean SQL:

meta_value LIKE '%print%'

2. Avoid 'type' => 'CHAR'

Unless you’re comparing numeric or date values, leave out the type. Adding it triggers the hash-protected escaping.

// Don't do this:
'type' => 'CHAR'

3. Don’t Manually Add Wildcards

// Wrong:
'value' => '%' . $search_term . '%'
// Right:
'value' => $search_term

What If You Need More Control?

If you want to combine multiple meta keys or search post titles and custom fields at once, use a custom posts_where filter:

add_filter('posts_where', 'gcs_raw_like_filter');

function gcs_raw_like_filter($where) 
{
    global $wpdb;
    $term = esc_sql( $wpdb->esc_like('print') );

    $where .= " AND (
        ({$wpdb->postmeta}.meta_key = 'ew_serv_locations' AND {$wpdb->postmeta}.meta_value LIKE '%$term%') OR
        ({$wpdb->postmeta}.meta_key = 'ew_serv_categories' AND {$wpdb->postmeta}.meta_value LIKE '%$term%')
    )";

    return $where;
});

As an aside, you may need to ensure that the JOIN on to the postmeta table. This can be done using the posts_join WordPress filter:

add_filter('posts_join', 'gcs_joinPOSTMETA_to_WPQuery');
function gcs_joinPOSTMETA_to_WPQuery($join) {
    global $wp_query, $wpdb;
    $join .= " LEFT JOIN $wpdb->postmeta ON $wpdb->posts.ID = $wpdb->postmeta.post_id ";    
    return $join;
}

Then remove the filter(s) after the query:

remove_filter('posts_where', 'gcs_raw_like_filter');
remove_filter('posts_where', 'gcs_joinPOSTMETA_to_WPQuery');

Debug Tip: View the Generated SQL

Add this after your query to inspect the raw SQL:

echo '<pre>' . esc_html( $query->request ) . '</pre>';

Or log it in your error log:

add_filter('query', function($sql) {
    error_log('[WP SQL] ' . $sql);
    return $sql;
});

Summary

ProblemSolution
LIKE '{hash}search{hash}'Don’t add % manually
'type' => 'CHAR' triggers escapingRemove type from your query
No results returnedUse a custom posts_where filter for control

Final Thoughts

The {hash} issue in WordPress LIKE queries is a great example of a “security feature” creating a developer trap. It’s obscure, under-documented, and only shows up when you’re doing complex search logic.

I hope that this article helps you if you also end up in hash-hell.

Happy querying.

Share this on Social Media
Scroll to Top