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/projects/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.