Categories
How To

Search Options for Custom Post Data

Searching custom meta data in WordPress isn’t default. And that is sad.

I use CMB2 to add in a bunch of custom meta data for my posts on a site. Seeing as I’m using it to allow layouts and formats to be consistent, it’s not surprising that I’ve chosen to split out my data like that. In another world, maybe it would be done differently, but this works.

Except that search sucks. WordPress doesn’t search custom post meta out of the box which just kills me. That meant all the data I stored in for names and dates was never getting searched. There are two ‘easy’ solutions for this at least.

Ew. I know. But ew. Since I’m using Genesis as my theme, it’s not super hard, just a little weird. Assuming you already have a Custom Search Engine set up, and you’re using Genesis, here’s what to do next.

First I added this into my functions-site.php (note: I made a functions-site.php file so I can easily update my functions.php file on the rare occasion I need to update the child theme – it’s really rare – but also so I always know what’s me and what was Genesis):

/* Google Custom Search Engine */
add_filter( 'genesis_search_form', 'helf_search_form', 10, 4);
function helf_search_form( $form, $search_text, $button_text, $label ) {
    $onfocus = " onfocus=\"if (this.value == '$search_text') {this.value = '';}\"";
    $onblur = " onblur=\"if (this.value == '') {this.value = '$search_text';}\"";
    $form = '<form method="get" class="searchform search-form" action="' . home_url() . '/search" >' . $label . '
<input type="text" value="' . esc_attr( $search_text ) . '" name="q" class="s search-input"' . $onfocus . $onblur . ' /><input type="submit" class="searchsubmit search-submit" value="' . esc_attr( $button_text ) . '" /></form>';
    return $form;
}

Then I made a custom page template thanks to Rick Duncan:

<?php
/*
 * Template Name: Google Custom Search Engine
 *
 * This file adds the Google SERP template to our Genesis Child Theme.
 *
 * @author     Rick R. Duncan
 * @link       http://www.rickrduncan.com
 * @license    http://www.opensource.org/licenses/gpl-license.php GPL v2.0 (or later)
 *
 */

//* Force Full-Width Layout
add_filter( 'genesis_pre_get_option_site_layout', '__genesis_return_full_width_content' );

//* Add Noindex tag to the page
add_action( 'genesis_meta', 'lez_noindex_page' );
function lez_noindex_page() {
	echo '<meta name="robots" content="noindex, follow">';
}

//* Insert Google CSE code into <head> section of webpage
add_action( 'genesis_meta', 'lez_google_cse_meta', 15 );
function lez_google_cse_meta() { ?>

	<script>
	  (function() {
	    var cx = '017016624276440630536:tpoclrwnxyy';
	    var gcse = document.createElement('script');
	    gcse.type = 'text/javascript';
	    gcse.async = true;
	    gcse.src = 'https://cse.google.com/cse.js?cx=' + cx;
	    var s = document.getElementsByTagName('script')[0];
	    s.parentNode.insertBefore(gcse, s);
	  })();
	</script><?php
}
//* Add custom body class
add_filter( 'body_class', 'lez_add_body_class' );
function lez_add_body_class( $classes ) {

   $classes[] = 'google-cse';
   return $classes;

}
//* Remove standard Genesis loop and insert our custom page content
remove_action( 'genesis_loop', 'genesis_do_loop' );
add_action( 'genesis_loop', 'lez_custom_content' );
function lez_custom_content() { ?>

	<div itemtype="http://schema.org/SearchResultsPage" itemscope="itemscope">
		<header class="entry-header">
			<h1 itemprop="headline">
    			<?php echo get_the_title($ID); ?>
    		</h1>
    	</header>
    	<div class="entry-content" itemprop="text">
    		<?php echo get_the_content();
    		//* Obtain querystring value if present and display on-screen
			if ((isset($_REQUEST['q'])) && (!empty($_REQUEST['q']))) {
    			$query= $_REQUEST['q'];
    			echo '<strong>You Searched For:</strong> <em>'.$query.'</em>';
			}
			else {
				echo 'Please enter a search phrase.';
			}
			if ( is_active_sidebar( 'google-cse' ) ) {
				dynamic_sidebar( 'google-cse' );
			}
			?>
    		<gcse:searchresults-only></gcse:searchresults-only>
    	</div>
    </div>

<?php }
genesis();

Finally I added a page called “Search Results” and assigned it this template. Done. Google, who searches the whole page content, will get everything. It just looks like Google.

Top ↑

Having WordPress search your Custom Post Meta Having WordPress search your Custom Post Meta

This was surprisingly annoying, but not as hard as all that. Adam Balee wrote Search WordPress by Custom Fields without a Plugin which, I know, is ‘without a plugin’ and sort of silly, but I put that in as an MU plugin and it worked perfectly!

<?php
/**
 * Extend WordPress search to include custom fields
 *
 * http://adambalee.com
 */

/**
 * Join posts and postmeta tables
 *
 * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_join
 */
function cf_search_join( $join ) {
    global $wpdb;

    if ( is_search() ) {    
        $join .=' LEFT JOIN '.$wpdb->postmeta. ' ON '. $wpdb->posts . '.ID = ' . $wpdb->postmeta . '.post_id ';
    }
    
    return $join;
}
add_filter('posts_join', 'cf_search_join' );

/**
 * Modify the search query with posts_where
 *
 * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_where
 */
function cf_search_where( $where ) {
    global $pagenow, $wpdb;
   
    if ( is_search() ) {
        $where = preg_replace(
            "/\(\s*".$wpdb->posts.".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
            "(".$wpdb->posts.".post_title LIKE $1) OR (".$wpdb->postmeta.".meta_value LIKE $1)", $where );
    }

    return $where;
}
add_filter( 'posts_where', 'cf_search_where' );

/**
 * Prevent duplicates
 *
 * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_distinct
 */
function cf_search_distinct( $where ) {
    global $wpdb;

    if ( is_search() ) {
        return "DISTINCT";
    }

    return $where;
}
add_filter( 'posts_distinct', 'cf_search_distinct' );

This is not the most efficient search, I know. But it works and gets my data where it’s needed.

2 replies on “Search Options for Custom Post Data”

I’ve given up on default search. I mostly use either SearchWP or Elasticsearch, which both obviously add a cost to a site, but they work really well for what they do.

One neat thing about SearchWP is that it keeps its own index, and has an interface to change the weight specific meta fields get in search. I use it for book data, so we have the title and ISBN (academics search that way) weighted higher. I imagine you could use it for character or actor name to make it useful for your searchers. ^_^

Comments are closed.