Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
PHP - Wordpress - Search - wordpress custom search function that encompasses ACF/advanced custom fields and taxonomies and split expression before request
<?php
/**
* [list_searcheable_acf list all the custom fields we want to include in our search query]
* @return [array] [list of custom fields]
*/
function list_searcheable_acf(){
$list_searcheable_acf = array("title", "sub_title", "excerpt_short", "excerpt_long", "xyz", "myACF");
return $list_searcheable_acf;
}
/**
* [advanced_custom_search search that encompasses ACF/advanced custom fields and taxonomies and split expression before request]
* @param [query-part/string] $where [the initial "where" part of the search query]
* @param [object] $wp_query []
* @return [query-part/string] $where [the "where" part of the search query as we customized]
* see https://vzurczak.wordpress.com/2013/06/15/extend-the-default-wordpress-search/
* credits to Vincent Zurczak for the base query structure/spliting tags section
*/
function advanced_custom_search( $where, &$wp_query ) {
global $wpdb;
if ( empty( $where ))
return $where;
// get search expression
$terms = $wp_query->query_vars[ 's' ];
// explode search expression to get search terms
$exploded = explode( ' ', $terms );
if( $exploded === FALSE || count( $exploded ) == 0 )
$exploded = array( 0 => $terms );
// reset search in order to rebuilt it as we whish
$where = '';
// get searcheable_acf, a list of advanced custom fields you want to search content in
$list_searcheable_acf = list_searcheable_acf();
foreach( $exploded as $tag ) :
$where .= "
AND (
(wp_posts.post_title LIKE '%$tag%')
OR (wp_posts.post_content LIKE '%$tag%')
OR EXISTS (
SELECT * FROM wp_postmeta
WHERE post_id = wp_posts.ID
AND (";
foreach ($list_searcheable_acf as $searcheable_acf) :
if ($searcheable_acf == $list_searcheable_acf[0]):
$where .= " (meta_key LIKE '%" . $searcheable_acf . "%' AND meta_value LIKE '%$tag%') ";
else :
$where .= " OR (meta_key LIKE '%" . $searcheable_acf . "%' AND meta_value LIKE '%$tag%') ";
endif;
endforeach;
$where .= ")
)
OR EXISTS (
SELECT * FROM wp_comments
WHERE comment_post_ID = wp_posts.ID
AND comment_content LIKE '%$tag%'
)
OR EXISTS (
SELECT * FROM wp_terms
INNER JOIN wp_term_taxonomy
ON wp_term_taxonomy.term_id = wp_terms.term_id
INNER JOIN wp_term_relationships
ON wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id
WHERE (
taxonomy = 'post_tag'
OR taxonomy = 'category'
OR taxonomy = 'myCustomTax'
)
AND object_id = wp_posts.ID
AND wp_terms.name LIKE '%$tag%'
)
)";
endforeach;
return $where;
}
add_filter( 'posts_search', 'advanced_custom_search', 500, 2 );
@blorence

This comment has been minimized.

Copy link

blorence commented Sep 5, 2013

This is fantastic, thanks!

@ktryndchrs

This comment has been minimized.

Copy link

ktryndchrs commented Oct 21, 2013

Thank you :)

@swashcap

This comment has been minimized.

Copy link

swashcap commented Nov 3, 2013

This is super! Works like a charm.

@unwrittendevin

This comment has been minimized.

Copy link

unwrittendevin commented Nov 8, 2013

This worked awesome for me! I wonder if it would be worth the investment in time to make it a plugin so it's more available to all users?

@ptitepalou

This comment has been minimized.

Copy link

ptitepalou commented Nov 27, 2013

Thanxxxxx very much ! I was on this problem since 1 week and I was about to get crazyyy ! Thank you again :)

@ptitepalou

This comment has been minimized.

Copy link

ptitepalou commented Nov 28, 2013

I still have a problem with this search. I have a field where you can type your departement number (in France, it's like a region, an area). When I search content which has department #80 for example, it lists many posts that don't have any number "80" in it. So, what's going on ? I tried deleting lines 62 to 80 but it doesn't change anything ; and also deleting parts on lines 54 and 56 (deleting meta_key part)
What should I do ?

@smeric

This comment has been minimized.

Copy link

smeric commented Dec 11, 2013

Thanx for sharing this :)

A suggestion : you may replace all defaults wp_ tables prefix with $wpdb->prefix for the function to work with custom prefixed WordPress installs...

@EdnilsonRobert

This comment has been minimized.

Copy link

EdnilsonRobert commented Sep 18, 2014

Amazing!!!

@coryetzkorn

This comment has been minimized.

Copy link

coryetzkorn commented Nov 10, 2014

So great! Tried a bunch of plugins including Relevanssi and Search Everything, but this worked much better and is a much more elegant solution. Thank you for sharing!

@yratof

This comment has been minimized.

Copy link

yratof commented Mar 3, 2015

How can you call this in? I'm a little confused to what $where should be

@squaremunkey

This comment has been minimized.

Copy link

squaremunkey commented Mar 24, 2015

This is great thank you for sharing.
How would you add (ACF) relationship functionality to the wp_search? i.e. search "the godfather" result 'Al Pacino'. Because in custom post_type actor there is a relationship field called film (post_type film) or vise versa.

@Losams

This comment has been minimized.

Copy link

Losams commented Jun 18, 2015

Thanks, i upgraded this to change the wp_ with $wpdb->prefix to be a little more dynamic. Can't pull request a gist but great job.

@atomic-devteam

This comment has been minimized.

Copy link

atomic-devteam commented Jul 27, 2015

Great work Charles! @smeric Sébastien thanks for posting. DB prefix was my problem.

@andrifile

This comment has been minimized.

Copy link

andrifile commented Jul 30, 2015

Thanks! Good job.

@pdechery

This comment has been minimized.

Copy link

pdechery commented Jul 30, 2015

This is fantastic. Many thanks!

@jevgen

This comment has been minimized.

Copy link

jevgen commented Aug 21, 2015

thank you for sharing!

@circoambulante

This comment has been minimized.

Copy link

circoambulante commented Sep 25, 2015

Thanks!

@commwork

This comment has been minimized.

Copy link

commwork commented Nov 12, 2015

wow!!!!! one plugin less :)

@erickolivares

This comment has been minimized.

Copy link

erickolivares commented Nov 13, 2015

legit! thanks!!

@jayetan

This comment has been minimized.

Copy link

jayetan commented Dec 6, 2015

Works Perfectly!

@padjoo

This comment has been minimized.

Copy link

padjoo commented Dec 23, 2015

Nice one, thanks!

Make sure to escape each $tag though as it's currently open to SQL injection! ( Line 43: $tag = esc_sql($wpdb->esc_like($tag)); )

@afgarcia86

This comment has been minimized.

Copy link

afgarcia86 commented Dec 30, 2015

Amazing! Thanks :shipit:

@DenisDov

This comment has been minimized.

Copy link

DenisDov commented Jan 12, 2016

put this code in functions.php?

@spencersmb

This comment has been minimized.

Copy link

spencersmb commented Jan 12, 2016

wow - inspires me to learn how to code better- amazing piece of coding skills here.

@LPGhatguy

This comment has been minimized.

Copy link

LPGhatguy commented Mar 3, 2016

You seriously need to escape your inputs, this isn't safe to use as-is and is vulnerable to SQL injection.

In sharing this vulnerable gist you've opened up a bunch of sites to SQL injection, and that's definitely bad.

@lasoupedjour

This comment has been minimized.

Copy link

lasoupedjour commented Mar 4, 2016

incredible!! just added some escape to prevent sql injection!

@jserrao

This comment has been minimized.

Copy link

jserrao commented Mar 13, 2016

For those of you stumbling into this script via Google, I reworked it to include XSS and SQL injection attack protection (via PHP's strip_tags() and WP's esc_sql(), respectively. I also improved the conditional notation to use brackets and added in some comments to help you understand how to use / modify it for your own ACF-powered WP site: https://gist.github.com/jserrao/d8b20a6c5c421b9d2a51

@kuloyants

This comment has been minimized.

Copy link

kuloyants commented Apr 10, 2016

AMAZING. Thanks

@MelanieMenard

This comment has been minimized.

Copy link

MelanieMenard commented Apr 14, 2016

@charleslouis and @jserrao: Thank you both for this, seriously! I had a plugin conflict with 'searchwp' and using your code instead worked perfectly (I credited you in the theme). All the best!

@opus13

This comment has been minimized.

Copy link

opus13 commented Jun 11, 2016

Is there a way to search the (user) type subfield in a repeater?

@bsebastian86

This comment has been minimized.

Copy link

bsebastian86 commented Aug 30, 2016

Would really love to know how to include Repeater fields in this.

@jolora

This comment has been minimized.

Copy link

jolora commented Nov 17, 2016

Brilliant. Thank you!

@squarecandy

This comment has been minimized.

Copy link

squarecandy commented May 4, 2017

Perfect - thank you so much!!!

@gbiorczyk-mateusz

This comment has been minimized.

Copy link

gbiorczyk-mateusz commented Jun 16, 2017

If someone is looking for a solution to this problem is to recommend the plugin:
https://wordpress.org/plugins/acf-better-search/

This plugin adds to default WordPress search engine the ability to search by content from selected fields of Advanced Custom Fields plugin.

Everything works automatically, no need to add any additional code.

@grisza12

This comment has been minimized.

Copy link

grisza12 commented Sep 11, 2017

How to use this script for get_posts()?
// It works for this $wp_query->found_posts; // but I wanna to get smth like this $posts = get_posts( array( 'post_type' => 'cpt', 'numberposts' => - 1, // ... 'order' => 'asc', 's' => get_search_query(), ) );

@janchimugica

This comment has been minimized.

Copy link

janchimugica commented Apr 6, 2018

Amazing, thanks! One thing I'd add is $wpdb->prefix to the query in case of custom database prefixes :)

@alimoshen

This comment has been minimized.

Copy link

alimoshen commented Apr 6, 2018

Great code! Thanks for sharing with me @janchimugica!

@Leland

This comment has been minimized.

Copy link

Leland commented Jul 26, 2018

Note that the original query WordPress sends includes AND (wp_posts.post_password = '')

...and this query does not. So you'll want to re-add that, unless you want protected posts to be included as well.

@nalagg

This comment has been minimized.

Copy link

nalagg commented Aug 5, 2018

issues after upgrading to php7.2; Warning: Parameter 2 to advanced_custom_search() expected to be a reference, value given in wp-includes/class-wp-hook.php

@mattwills8

This comment has been minimized.

Copy link

mattwills8 commented Oct 2, 2018

issues after upgrading to php7.2; Warning: Parameter 2 to advanced_custom_search() expected to be a reference, value given in wp-includes/class-wp-hook.php

As far as I can see you can remove the & in front of $wp_query on line 21. It doesnt need to be passed by reference since it isnt actually being modified, we're just extracting the search term. For me that removes the warning and still works fine :)

@GaiaGonen

This comment has been minimized.

Copy link

GaiaGonen commented Apr 10, 2019

Amazing. Thank you

@stefanhar

This comment has been minimized.

Copy link

stefanhar commented May 16, 2019

Slim version where we don't reset the $where query:

add_filter( 'posts_search', 'search_suggestions_custom_search', 500, 2 );
function custom_search_function( $where, $wp_query ) {
    if ( empty( $where )) {
      return $where;
    }

    // get search expression
    $terms = $wp_query->query_vars['s'];

    // explode search expression to get search terms
    $exploded = explode(' ', $terms);
    if( $exploded === FALSE || count($exploded) === 0 ) {
      $exploded = array( 0 => $terms );
    }

    foreach( $exploded as $tag ) {
        $where .= " OR EXISTS (
          SELECT * FROM wp_terms
            INNER JOIN wp_term_taxonomy ON wp_term_taxonomy.term_id = wp_terms.term_id
            INNER JOIN wp_term_relationships ON wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id
            WHERE taxonomy = 'myCustomTax' AND object_id = wp_posts.ID AND wp_terms.name LIKE '%$tag%'
        )";
    }
    return $where;
}
@Boldairdev

This comment has been minimized.

Copy link

Boldairdev commented Jul 19, 2019

Nifty piece of code, thank you, and thank you @jserrao for the mods to escape the inputs cleanly, and although it's 6 years old, still works like a charm :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.