SearchWP

Supplemental Engine

Table of Contents

SearchWP allows for the setup of any number of Engines, each with their own individual configuration. This segmentation facilitates multiple customized implementations of search throughout your site.

The only limitation of the Default Engine is that its Sources must be based on WP_Post objects. That’s because WordPress core assumes search results to fit within The Loop and The Loop is made up of WP_Posts. WP_Post objects are used for Posts, Pages, Media, and Custom Post Types. That covers a lot!

SearchWP also facilitates searching custom Sources, however. In order to fully take advantage of that you will need to setup and implement a Supplemental Engine.

Setup

Setting up a Supplemental Engine follows the same process as the Default Engine, but in this case all Sources are made available to you, not only those based on WP_Post.

Create a new Supplemental Engine by clicking the Add New button on the Engines tab of the SearchWP settings screen.

Screenshot pointing out the Add New Engine button

Add a Supplemental Engine by clicking 'Add New'

Once the new Engine has been added you can customize the Sources, Attributes, and Rules to your liking.

After you’ve saved your Engine(s) SearchWP will evaluate whether the Index needs to be rebuilt and provide a notice if so.

The last setup step will be to note the Engine name which is different than the label. The name sits next to the Engine label in a monospaced font. The name is how the Engine is referenced in code later on.

Form

Setting up a search form for your Supplemental Engine involves creating an <input> with a different name than s, as that name will trigger a native WordPress search.

Something like this will work to start with:

<form role="search" method="get" class="search-form"
action="<?php echo site_url( 'search-results/' ); ?>">
<label>
<span class="screen-reader-text">
<?php echo _x( 'Search for:', 'label' ) ?>
</span>
<input type="search" class="search-field"
name="searchwp"
placeholder="<?php echo esc_attr_x( 'Search...', 'placeholder' ) ?>"
value="<?php echo isset( $_GET['searchwp'] ) ? esc_attr( $_GET['searchwp'] ) : '' ?>"
title="<?php echo esc_attr_x( 'Search for:', 'label' ) ?>" />
</label>
<input type="submit" class="search-submit"
value="<?php echo esc_attr_x( 'Search', 'submit button' ) ?>" />
</form>

There are two things to note about this snippet:

  1. The <input> name used is searchwp
  2. The form action is pointing to site_url( 'search-results/' ). That means that if your site URL is example.com this form will redirect to example.com/search-results/ upon submission. This guide assumes the URL points to a Page you have created for the purpose of displaying Supplemental Engine results.

That’s it! That starter form aligns closely with the default output from WordPress’ get_search_form() which is likely supported by your theme. If it’s not, it can be styled like any other form on your site.

Results

When you create your search form it has an action that points to a URL designated as the Page to display your results. To pull in results from SearchWP we will first create a custom Page Template.

Here’s a starter template we can work with:

<?php
/* Template Name: SearchWP Results */
global $post;
// Retrieve applicable query parameters.
$search_query = isset( $_GET['searchwp'] ) ? sanitize_text_field( $_GET['searchwp'] ) : null;
$search_page = isset( $_GET['swppg'] ) ? absint( $_GET['swppg'] ) : 1;
// Perform the search.
$search_results = [];
$search_pagination = '';
if ( ! empty( $search_query ) && class_exists( '\\SearchWP\\Query' ) ) {
$searchwp_query = new \SearchWP\Query( $search_query, [
'engine' => 'supplemental', // The Engine name.
'fields' => 'all', // Load proper native objects of each result.
'page' => $search_page,
] );
$search_results = $searchwp_query->get_results();
$search_pagination = paginate_links( array(
'format' => '?swppg=%#%',
'current' => $search_page,
'total' => $searchwp_query->max_num_pages,
) );
}
get_header(); ?>
<div id="primary" class="content-area">
<main id="main" class="site-main" role="main">
<header class="page-header">
<h1 class="page-title">
<?php if ( ! empty( $search_query ) ) : ?>
<?php printf( __( 'Search Results for: %s' ), esc_html( $search_query ) ); ?>
<?php else : ?>
SearchWP Supplemental Search
<?php endif; ?>
</h1>
<!-- BEGIN Supplemental Engine Search form -->
<form role="search" method="get" class="search-form"
action="<?php echo site_url( 'search-results/' ); ?>">
<label>
<span class="screen-reader-text">
<?php echo _x( 'Search for:', 'label' ) ?>
</span>
<input type="search" class="search-field"
name="searchwp"
placeholder="<?php echo esc_attr_x( 'Search...', 'placeholder' ) ?>"
value="<?php echo isset( $_GET['searchwp'] ) ? esc_attr( $_GET['searchwp'] ) : '' ?>"
title="<?php echo esc_attr_x( 'Search for:', 'label' ) ?>" />
</label>
<input type="submit" class="search-submit"
value="<?php echo esc_attr_x( 'Search', 'submit button' ) ?>" />
</form>
<!-- END Supplemental Engine Search form -->
</header>
<?php if ( ! empty( $search_query ) && ! empty( $search_results ) ) : ?>
<?php foreach ( $search_results as $search_result ) : ?>
<article class="page hentry search-result">
<?php
switch( get_class( $search_result ) ) {
case 'WP_Post':
$post = $search_result;
?>
<header class="entry-header"><h2 class="entry-title">
<a href="<?php echo get_permalink(); ?>"><?php the_title(); ?></a>
</h2></header>
<div class="entry-summary"><?php the_excerpt(); ?></div>
<?php
wp_reset_postdata();
break;
case 'WP_User':
?>
<header class="entry-header"><h2 class="entry-title">
<a href="<?php echo get_author_posts_url( $search_result->data->ID ); ?>">
<?php echo esc_html( $search_result->data->display_name ); ?>
</a>
</h2></header>
<div class="entry-summary">
<?php echo wp_kses_post( get_the_author_meta( 'description',
$search_result->data->ID ) ); ?>
</div>
<?php
break;
case 'WP_Term':
?>
<header class="entry-header">
<h2 class="entry-title">
<a href="<?php echo get_term_link( $search_result->term_id, $search_result->taxonomy ); ?>">
<?php echo esc_html( $search_result->name ); ?>
</a>
</h2>
<div class="entry-summary">
<?php echo esc_html( $search_result->description ); ?>
</div>
</header>
<?php
break;
}
?>
</article>
<?php endforeach; ?>
<?php if ( $searchwp_query->max_num_pages > 1 ) : ?>
<div class="navigation pagination" role="navigation">
<h2 class="screen-reader-text">Results navigation</h2>
<div class="nav-links"><?php echo wp_kses_post( $search_pagination ); ?></div>
</div>
<?php endif; ?>
<?php elseif ( ! empty( $search_query ) ) : ?>
<p>No results found, please search again.</p>
<?php endif; ?>
</main> <!-- .site-main -->
</div> <!-- .content-area -->
<?php get_footer(); ?>

Let’s break this starter template down into four sections:

  1. Executing the search
  2. Outputting the search form (again)
  3. Displaying results
  4. Displaying pagination

Lines 7-28 are responsible for retrieving the search query, executing the search, and populating our results array.

Lines 44-60 output the search form we made above

Lines 64-94 are responsible for the output our search results.

Notice on line 15 we instructed \SearchWP\Query to retrieve 'all' which ensures that results are returned as their original object type (e.g. WP_Post) as set up in the \SearchWP\Source.

Note: By default \SearchWP\Query will return an object containing the id, source, site, and relevance for each result. Setting the fields argument to 'all' tells \SearchWP\Query to replace that result with a native object from the Source itself. Alternatively, setting the fields argument to 'entries' will return an array of \SearchWP\Entry objects.

That means that Posts, Pages, Custom Post Types, and Media will come back as their original WP_Post objects. Users will come back as WP_User objects. Any additional Sources will return their native object as well.

Unlike working with The Loop, when working with a Supplemental Engine we need to determine what type of result we have before we output any data.

In this example we use a switch which works out nicely, because this demo Engine includes only Posts, Pages, and Users as Sources.

Note: If you instead want only the minimum amount of data returned with search results, you can omit the fields argument entirely. You will then need to use the result’s object properties to retrieve the data necessary to display your results.