Supplemental Engine
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_Post
s. 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.
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:
- The
<input>
name
used issearchwp
- The
form
action
is pointing tosite_url( 'search-results/' )
. That means that if your site URL isexample.com
this form will redirect toexample.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:
- Executing the search
- Outputting the search form (again)
- Displaying results
- 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.