A simple WordPress search using wp-routes and intercooler.js.
The requirements
I’m building on two required WordPress plugins.
The first one is wp-routes to have an easier route registration and handling in WordPress.
The second one is wp-intercooler to be able to use the intercooler.js JavaScript library on the page.
A template tag
I will output a search form on the page using a template tag and some parameters.
function mytheme_search(array $post_types = array('post','page')){
//the form markup
?>
<form role="search" method="get" class="search-form" ic-src="/search" ic-target="#content">
<label>
<span class="screen-reader-text"><?php echo _x( 'Search for:', 'label') ?></span>
<input type="search" class="search-field" placeholder="<?php echo esc_attr_x( 'Search …', 'placeholder') ?>" value="<?php echo get_search_query() ?>" name="s" 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' ) ?>" />
<?php wp_nonce_field('mytheme-search', 'auth') ?>
<?php foreach ($post_types as $post_type): ?>
<input type="hidden" name="post_type[]" value="<?php echo $post_type ?>">
<?php endforeach ?>
</form>
<?php
}
The form has no action
attribute as intercooler.js is replacing the usual request flow with an AJAX based one.
I’m telling intercooler.js to send GET
requests to the /search
address using the ic-src
attribute and that it will have to replace the content of the div#content
element with whatever HTML it gets back using the ic-target
attribute.
A loop rendering function
In my theme I will have a function responsible for the loop rendering, taken straight from the codex exmaple, that will render both the initial state and the response to later search queries
// file functions.php
function my_theme_the_loop(){
if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<div class="<?php post_class() ?>">
<h2><a href="<?php the_permalink(); ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><?php the_title(); ?></a></h2>
<small><?php the_time('F jS, Y'); ?> by <?php the_author_posts_link(); ?></small>
<div class="entry">
<?php the_content(); ?>
</div>
<p class="postmetadata"><?php _e( 'Posted in' ); ?> <?php the_category( ', ' ); ?></p>
</div> <!-- closes the first div box -->
<?php endwhile; else : ?>
<p><?php _e( 'Sorry, no posts matched your criteria.' ); ?></p>
<?php endif;
}
and will be used, as an example, in the main index.php
theme file
// file index.php
get_header();
<div id="#content">
<?php mytheme_search() ?>
<?php my_theme_the_loop() ?>
</div>
get_footer();
Of note here is that I’m rendering the search and the content area inside a div
marked with the content
id: this is the part that intercooler.js will replace on request.
Search route
Leveraging wp-routes I’m registering the /search
route mentioned above in the theme functions.php
file.
// functions.php file
add_action('wp-routes/register_routes', function (){
respond('GET', '/search', function(){
// verify the nonce
if(!wp_verify_nonce($_GET['auth'], 'my_theme-search')){
// bail
return;
}
// default the post types
if(empty($_GET['post_type'])){
$_GET['post_type'] = array('post', 'page');
}
$args = array(
'post_type' => $_GET['post_type'];
);
// maybe search args
if(!empty($_GET['s'])){
$args['s'] = $_GET['s'];
}
query_posts($args);
my_theme_the_loop();
});
});
The intercooler.js library expects some valid HTML; I’m using the same function I’ve used in the index to render the loop to render the search results and echo them.
The wp-routes plugin will buffer that output to return it as the the request result.
Whether there are posts matching the search or not a valid loop HTML will be placed by intercooler in the content part of the page.
The same principle can be applied to almost any interaction and the upcoming version will make interaction with WordPress a breeze.