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.

Leave a Reply

Your email address will not be published. Required fields are marked *