Adding a section to the Omnisearch in Jetpack with a custom posts search
Let’s say we need to add an extra section to the Omnisearch in Jetpack with a custom posts search.
Like shown in this screenshot:
where I’ve moved the custom section to the top with:
/** * Move our 'My Posts' section to the top of the Omnisearch results page */ add_filter( 'omnisearch_results', function( $results, $search_term ) { $key = 'My Posts'; if( isset( $results[$key] ) ) { $tmp = $results[$key]; unset( $results[$key] ); return [ $key => $tmp ] + $results; } return $results; }, 99, 2 );
for better visibility.
Instead of extending the:
WP_List_Table
class, I prefer to extend the:
Jetpack_Omnisearch_Posts
class to simplify things, where we only need to override the search() method.
This is what we could start with, based on Jetpack_Omnisearch_Posts:
class My_Jetpack_Omnisearch_Posts extends Jetpack_Omnisearch_Posts { public function search( $results, $search_term ) { if( ! post_type_exists( $this->post_type ) ) return $results; parent::__construct(); $this->post_type_obj = get_post_type_object( $this->post_type ); // Custom posts query $args = [ 'post_type' => $this->post_type, 'posts_per_page' => apply_filters( 'omnisearch_num_results', 5 ), 'post_status' => 'any', 'suppress_filters' => false, 'meta_query' => [ [ 'key' => 'some_meta_key', 'value' => $search_term, 'compare' => 'LIKE' ] ] ]; $this->posts = get_posts( $args ); $this->prepare_items(); // Section's title $html = '<h2>My ' . esc_html( $this->post_type_obj->labels->name ) . '</h2>'; // Section's table output ob_start(); $this->display(); $html .= ob_get_clean(); $results[ $this->post_type_obj->labels->name ] = $html; return $results; } } // end class
But this doesn’t work for two reasons:
1) We need to take care of screen object, used in the display() method, namely this line:
$this->screen->render_screen_reader_content( 'heading_list' );
This screen object can be set in the constructor input, but Jetpack_Omnisearch_Posts only calls:
parent::__construct()
where the screen object is set to null by default.
One way around this is to set it as the current screen object:
$this->screen = get_current_screen();
2) Another thing is that we are overriding the post section’s results with:
$results[ $this->post_type_obj->labels->name ] = $html;
To avoid that, we need a unique custom key, like:
$results[ 'My ' . $this->post_type_obj->labels->name ] = $html;
This also generates the “jump to” link label.
So let’s rewrite the My_Jetpack_Omnisearch_Posts class accordingly and wrap it in a simple plugin (PHP 5.4+). We can use the omnisearch_add_providers hook to add our custom section:
<?php /** * Plugin Name: My Custom Omnisearch Section For Posts * Description: An example how to extend the Jetpack_Omnisearch_Posts class for a custom posts query * Plugin URI: https://xlino.com/adding-a-section-to-the-omnisearch-in-jetpack-with-a-custom-post-search/ * Author: Birgir Erlendsson (birgire) * Version: 1.0.1 */ add_action( 'omnisearch_add_providers', function() { if( class_exists( 'My_Jetpack_Omnisearch_Posts ' ) ) return; class My_Jetpack_Omnisearch_Posts extends Jetpack_Omnisearch_Posts { public function search( $results, $search_term ) { if( ! post_type_exists( $this->post_type ) ) return $results; parent::__construct(); $this->post_type_obj = get_post_type_object( $this->post_type ); // Custom posts query $args = [ 'post_type' => $this->post_type, 'posts_per_page' => apply_filters( 'omnisearch_num_results', 5 ), 'post_status' => 'any', 'suppress_filters' => false, 'meta_query' => [ [ 'key' => 'some_meta_key', 'value' => $search_term, 'compare' => 'LIKE' ] ] ]; $this->posts = get_posts( $args ); $this->prepare_items(); // Set the screen object. This is needed for the display() to work // because display() includes $this->screen->render_screen_reader_content( 'heading_list' ); // and Jetpack_Omnisearch_Posts only calls parent::__construct() and the 'screen' is null by default, $this->screen = get_current_screen(); // Section's title $html = '<h2>My ' . esc_html( $this->post_type_obj->labels->name ) . '</h2>'; // Section's table output ob_start(); $this->display(); $html .= ob_get_clean(); // We need to change the array key to avoid overriding existing post results $results[ 'My ' . $this->post_type_obj->labels->name ] = $html; return $results; } } // end class $obj = new My_Jetpack_Omnisearch_Posts ( 'post' ); } );
where you must adjust the custom query arguments $args to your needs.
If the Jetpack_Omnisearch_Posts class wouldn’t add a filter in the class constructor, it would make it easier to work with.