Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save fiskhandlarn/f6f86c99e59f62d72ac2ce10be12dc1a to your computer and use it in GitHub Desktop.
Save fiskhandlarn/f6f86c99e59f62d72ac2ce10be12dc1a to your computer and use it in GitHub Desktop.
PHP - Wordpress - Search - wordpress custom search function that encompasses ACF/advanced custom fields and taxonomies and split expression before request. I updated this original script with better documentation and XSS / SQL injection support.
<?php
/*
##############################
########### Search ###########
##############################
Included are steps to help make this script easier for other to follow
All you have to do is add custom ACF post types into Step 1 and custom taxonomies into Step 10
I also updated this work to include XSS and SQL injection projection
[list_searcheable_acf list all the custom fields we want to include in our search query]
@return [array] [list of custom fields]
*/
// Define list of ACF fields you want to search through - do NOT include taxonomies here
function list_searcheable_acf(){
$list_searcheable_acf = array( "your",
"acf",
"non-repeater",
"field-names",
"here",
"repeater" => array( "repeater-sub-field1",
"repeater-sub-field2" )
);
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] $search [the initial "where" part of the search query]
* @param [object] $wp_query []
* @return [query-part/string] $search [the "where" part of the search query as we customized]
* modified from gist: https://gist.github.com/FutureMedia/9581381/73afa809f38527d57f4213581eeae6a8e5a1340a
* 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 and Sjouw for comment cleanup
*/
function advanced_custom_search( $search, $wp_query ) {
global $wpdb;
if ( empty( $search )) {
return $search;
}
// 1- get search expression
$terms_raw = $wp_query->query_vars[ 's' ];
// 2- check search term for XSS attacks
$terms_xss_cleared = strip_tags($terms_raw);
// 3- do another check for SQL injection, use WP esc_sql
$terms = esc_sql($terms_xss_cleared);
// 4- explode search expression to get search terms
$exploded = explode( ' ', $terms );
if( $exploded === FALSE || count( $exploded ) == 0 ) {
$exploded = array( 0 => $terms );
}
// 5- setup search variable as a string
$search = '';
// 6- get searcheable_acf, a list of advanced custom fields you want to search content in
$list_searcheable_acf = list_searcheable_acf();
// 7- get custom table prefixes, thanks to Brian Douglas @bmdinteractive on github for this improvement
$table_prefix = $wpdb->prefix;
// 8- search through tags, inject each into SQL query
foreach( $exploded as $tag ) {
$search .= "
AND (
(".$table_prefix."posts.post_title LIKE '%$tag%')
OR (".$table_prefix."posts.post_excerpt LIKE '%$tag%')
OR (".$table_prefix."posts.post_content LIKE '%$tag%')
".
// 9- Adds to $search DB data from custom post types
"OR EXISTS (
SELECT * FROM ".$table_prefix."postmeta
WHERE post_id = ".$table_prefix."posts.ID
AND (";
// 9b - reads through $list_searcheable_acf array to see which custom post types you want to include in the search string
$metaStatements = array();
foreach ($list_searcheable_acf as $key => $searcheable_acf) {
if ( is_array( $searcheable_acf ) ) {
foreach ( $searcheable_acf as $repeater_acf ) {
array_push( $metaStatements, "(meta_key LIKE '" . $key . "_%_" . $repeater_acf . "' AND meta_value LIKE '%$tag%')" );
}
}
else {
array_push( $metaStatements, "(meta_key = '" . $searcheable_acf . "' AND meta_value LIKE '%$tag%')" );
}
}
$search .= join( $metaStatements, "\n OR " );
$search .= ")
)".
// 10- Adds to $search DB data from comments
"OR EXISTS (
SELECT * FROM ".$table_prefix."comments
WHERE comment_post_ID = ".$table_prefix."posts.ID
AND comment_content LIKE '%$tag%'
)".
// 11 - Adds to $search DB data from taxonomies
"OR EXISTS (
SELECT * FROM ".$table_prefix."terms
INNER JOIN ".$table_prefix."term_taxonomy
ON ".$table_prefix."term_taxonomy.term_id = ".$table_prefix."terms.term_id
INNER JOIN ".$table_prefix."term_relationships
ON ".$table_prefix."term_relationships.term_taxonomy_id = ".$table_prefix."term_taxonomy.term_taxonomy_id".
// 11b- Add custom taxonomies here
" WHERE (
taxonomy = 'your'
OR taxonomy = 'custom'
OR taxonomy = 'taxonomies'
OR taxonomy = 'here'
)
AND object_id = ".$table_prefix."posts.ID
AND ".$table_prefix."terms.name LIKE '%$tag%'
)".
")"; // closes $search
} // closes foreach
return $search;
} // closes function advanced_custom_search
// 12- use add_filter to put advanced_custom_search into the posts_search results
add_filter( 'posts_search', 'advanced_custom_search', 500, 2 );
@jserrao
Copy link

jserrao commented Dec 16, 2016

Nice work - we ought to turn this into a repo. Seems like the interest is high.

@paperrobots
Copy link

Error on line 110. Need a space before WHERE. Otherwise works great!

@felthy
Copy link

felthy commented Apr 30, 2017

I've just forked and refactored to use $wpdb->prepare() and $wpdb->esc_like() instead of manually escaping the input.

@Garconis
Copy link

@paperrobots is correct. This didn't work when the chunk of code regarding Taxonomies was there. Adding the space (as @felthy also did in their version) fixes the issue.

@Christian-CFP
Copy link

I get this error:
Warning: Parameter 2 to advanced_custom_search() expected to be a reference, value given in /wp-includes/class-wp-hook.php on line 286

@fiskhandlarn
Copy link
Author

@paperrobots Sorry about that, there should of course be a space there. (I missed that when I rewrote https://gist.github.com/jserrao/d8b20a6c5c421b9d2a51#file-custom-search-acf-wordpress-php-L103 to remove the php comment inside the SQL.)

@Christian-CFP I just noticed this when revisiting the old project that uses this gist. This is not allowed as of PHP 5.4 (and shouldn't have been needed in the first place). Fixed this now.

@MilenFrom
Copy link

Works perfectly.

Thanks!

@CrisWoler
Copy link

Could it be this?

array_push( $metaStatements, "(meta_key LIKE '" . $key . "_%_" . $repeater_acf . "' AND meta_value LIKE '%$tag%')" );
array_push( $metaStatements, "(meta_key LIKE '" . $key . "_%_" . $group_acf . "' AND meta_value LIKE '%$tag%')" );

For search inside "groups" in AFC? (otherwise it doesn't return any content in my case).

@ac0ua
Copy link

ac0ua commented Jul 8, 2020

Could someone please give me an example of how this works?

$return_array = advanced_custom_search("12345", $WP_query);
//nothing comes out
print_r($return_array);

//spits out a query but I don't understand where to go from here.
echo $WP_query;

//where do I put the $WP_query?
echo WP_Query($WP_query);

@fiskhandlarn
Copy link
Author

@ac0ua Not sure what you're trying to achieve, but $wp_query is supplied by the filter: https://gist.github.com/fiskhandlarn/f6f86c99e59f62d72ac2ce10be12dc1a#file-custom-search-acf-wordpress-php-L125

@ac0ua
Copy link

ac0ua commented Jul 12, 2020

@fiskhandlarn
names of custom fields
$list_searcheable_acf = array( "services_short_description", "header_basic_heading", "header_basic_subhead", "menu_items" => array( "menu_item", "menu_submenu", "submenu_items" ), );

I am also using the MAMP stack for MACs, I say this because I am used to XXAMP sometimes there are obscure security setting that may get in my way.

Sorry I am new to WP and I feel like I am trying to do something advanced. Okay so the SQL query is returned by "advanced_custom_search("ac0ua", $WP_Query);"

togenter when I use this URL.com/search/?search=ac0ua (The URL was originally setup to use 's' but s was not working for me. I used 'search' instead query_var.)

Okay I got this far I have an

  • SQL query
  • the query has a bunch of lines with "LIKE %acoua%"
  • all my custom fields in the array and are showing up in the returned SQL

Where is this query designed to run? I have tried to use phpmyadmin by selecting my DB and clicking the SQL tab and pasting it into the textarea, but I get an error.

Unrecognized statement type. (near "AND" at position 0)

@fiskhandlarn
Copy link
Author

@ac0ua
I haven't used this gist in a couple of years so I'm not sure if the resulting SQL is correct with current WP version and/or any plugins you may be using. Maybe there is a plugin with active development that solves this wanted behaviour nowadays?
The resulting SQL is run by WP itself, but if the SQL statement is malformed it won't work. I would start by analyzing the whole SQL statement (i.e. echo $search just before it's returned). Good luck. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment