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:

my_posts_omnisearch

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.

A simple plugin to run JetPack locally

We don’t need to modify the wp-config.php file as before with:

define ('JETPACK_DEV_DEBUG', true);

to run JetPack in the development mode.

By using the jetpack_development_mode filter described here, we can construct this simple plugin:

<?php
/**
 * Plugin Name: Run JetPack locally
 * Plugin URI:  https://github.com/birgire/run-jetpack-locally
 * Author:      birgire
 * Version:     0.0.3
 */

// Activate the development mode:
add_filter( 
    'jetpack_development_mode', 
    '__return_true', 
    PHP_INT_MAX 
);

to make your life easier 😉 and it’s available on GitHub.

This class method of the JetPack class contains the filter:

 
	/**
	 * Is Jetpack in development (offline) mode?
	 */
	public static function is_development_mode() {
		$development_mode = false;

		if ( defined( 'JETPACK_DEV_DEBUG' ) ) {
			$development_mode = JETPACK_DEV_DEBUG;
		}

		elseif ( site_url() && false === strpos( site_url(), '.' ) ) {
			$development_mode = true;
		}

		return apply_filters( 'jetpack_development_mode', $development_mode );
	}