Search Results Grouped by Post Types in Bricks

Updated on 08 Oct 2024

This Pro tutorial provides the steps to arrange the search results by specified post types in a Bricks site.

We shall register a custom query type called “My Post Types” so the outer query loops through an array of our desired post types. Then add an inner query that loops through all the posts of the outer loop’s post type.

Step 1

Go to Bricks → Templates.

Add a new template named say, “Search Results” of the type “Search results”.

Edit it with Bricks.

Apply a template condition like this:

Add a Section having this H2 heading:

Search results for: {url_parameter:s}

Step 2

Add the following in child theme‘s functions.php or a code snippets plugin:

<?php
/**
 * Custom query type and related functions for Bricks builder
 */

/**
 * Add a new "My Post Types" query type
 *
 * @param array $control_options The existing control options
 * @return array The modified control options
 */
add_filter( 'bricks/setup/control_options', function ( array $control_options ): array {
    $control_options['queryTypes']['bl_my_post_types'] = esc_html__( 'My Post Types', 'your-textdomain' );
    return $control_options;
} );

/**
 * Run new query if the 'bl_my_post_types' option is selected
 *
 * @param array        $results   The query results
 * @param BricksQuery $query_obj The query object
 * @return array The modified query results
 */
add_filter( 'bricks/query/run', function ( array $results, BricksQuery $query_obj ): array {
    if ( $query_obj->object_type !== 'bl_my_post_types' ) {
        return $results;
    }

    // Set your post types here
    $results = [ 'post', 'page', 'group-program' ];

    return $results;
}, 10, 2 );

if ( ! function_exists( 'bl_get_looping_post_type' ) ) {
	/**
	* Get the post type of the current looping query
	*
	* @return string The current post type or 'post' as default
	*/
	function bl_get_looping_post_type(): string {
		$looping_query_id = BricksQuery::is_any_looping();

		if ( $looping_query_id && BricksQuery::get_query_object_type( $looping_query_id ) === 'bl_my_post_types' ) {
			return BricksQuery::get_loop_object( $looping_query_id );
		}

		return 'post';
	}
}

/**
 * Get the post type's plural label of the current looping query.
 *
 * @return string The plural label of the current post type.
 */
function bl_get_post_type_plural_label(): string {
    $post_type = bl_get_looping_post_type();
    $post_type_object = get_post_type_object( $post_type );

    return $post_type_object->labels->name ?? '';
}

/**
 * Modify query variables for a specific Bricks element.
 *
 * @param array  $query_vars The current query variables.
 * @param array  $settings   The element settings.
 * @param string $element_id The element ID.
 * @return array The modified query variables.
 */
add_filter( 'bricks/posts/query_vars', function ( array $query_vars, array $settings, string $element_id ): array {
    if ( $element_id === 'tbojwp' ) {
        $query_vars['post_type'] = bl_get_looping_post_type();
    }

    return $query_vars;
}, 10, 3 );

In the

$results = [ 'post', 'page', 'group-program' ];

specify your desired post types in the order in which you want them to be shown.

If you want all registered custom post types and to be used instead of manually specifying them, create a custom function by adding the following in child theme‘s functions.php (w/o the opening PHP tag) or a code snippets plugin:

<?php

/**
 * Get all registered public post types.
 *
 * @return array An array of public post type names.
 */
function bl_get_public_post_types() : array {
    $args = [
        'public'   => true,
        '_builtin' => false
    ];
    
    $custom_types = get_post_types( $args, 'names', 'and' );
    $builtin_types = [ 'post', 'page' ];

    return array_merge( $builtin_types, $custom_types );
}

Whitelist the bl_get_public_post_types function.

Ex.:

<?php 

add_filter( 'bricks/code/echo_function_names', function() {
  return [
    'bl_get_public_post_types'
  ];
} );

You should also add other functions (native or custom) being used in your Bricks instance besides bl_slugify_section_title. This can be checked at Bricks → Settings → Custom code by clicking the Code review button.

More info on whitelisting can be found here.

Then replace

$results = [ 'post', 'page', 'group-program' ];

with

$results = bl_get_public_post_types();

Step 3

Whitelist the bl_get_post_type_plural_label function.

Ex.:

<?php 

add_filter( 'bricks/code/echo_function_names', function() {
  return [
    'bl_get_post_type_plural_label'
  ];
} );

You should also add any other functions (native or custom) being used in your Bricks instance in addition to bl_get_post_type_plural_label. This can be checked at Bricks → Settings → Custom code by clicking the Code review button.

More info on whitelisting can be found here.

Step 4

Back to editing the search results template, copy this JSON and paste the Section from our dev site below the existing Section.

Note the Bricks ID of the inner query loop block (Post Query Block) and replace rznmsk in

if ( $element_id === 'rznmsk'  ) {

from Step 2 with it.

Ensure that the outer query loop’s type is set to “My Post Types”.

That’s it!

You can now do a test search or visit a search results page in your site at a URL like

https://example.com/?s=lorem

Update on 23 May 2024

If you would like to style each post type block separately, follow these steps.

Whitelist bl_get_looping_post_type function.

Add this data attribute to the outer query loop element:

data-post-type

{echo:bl_get_looping_post_type}

Inspect the blocks on the front end with your browser’s dev tools and you should see something like this:

Now you can target your post-specific block with custom CSS like this:

[data-post-type="post"] {
    background: #fff;
    padding: 4rem;
}

Reference

https://wordpress.stackexchange.com/a/271030