Nested Queries in Bricks – Posts Grouped by Published Years and Categories

In the past we showed how posts could be grouped by years in Bricks.

This Pro tutorial takes it further by grouping posts by categories which are further grouped by years.

The year headings will be dynamic – in the sense they will only be the ones in which there is at least 1 published post. Also, only the categories that contain at least 1 published post will be output.

Bricks offers unparalleled power when it comes to queries, not available in other systems/builders.

When done, the structure would look like this:

Step 1

Let us first create a custom query type called “Published Years” to which we feed in an array of all the years in which a post was published in descending order.

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

// Add new "Published Years" query loop type option in the dropdown.
add_filter( 'bricks/setup/control_options', function( $control_options ) {
	$control_options['queryTypes']['published_years'] = esc_html__( 'Published Years' );

	return $control_options;
} );

// Run new query if option selected.
add_filter( 'bricks/query/run', function( $results, $query_obj ) {
	if ( $query_obj->object_type !== 'published_years' ) {
		return $results;
	}
	
	// if option is selected, run our new query
	if ( $query_obj->object_type === 'published_years' ) {
		$results = bl_run_new_query_20230311();
	}
	
	return $results;
}, 10, 2 );

// Form an array of published years and return it.
function bl_run_new_query_20230311() {
	// WP_Query arguments
	$args = [
		'post_type' => [ 'post' ],
		'posts_per_page' => -1,
	];

	// the array to hold the published years, empty to begin with
	$years = [];

	// The Query
	$query = new WP_Query( $args );

	// The Loop
	if ( $query->have_posts() ) {
		while ( $query->have_posts() ) {
			$query->the_post();
		
			// get the current post's published year
			$year = get_the_date( 'Y' );
			
			// if the current post's published year is not in the years array, add it to the array
			if ( ! in_array( $year, $years ) ) {
				$years[] = $year;
			}
		}
	} else {
		// no posts found
	}

	// Restore original Post Data
	wp_reset_postdata();

	return $years;
}

// Function to get the published year of the current looping query.
function bl_get_looping_year() {
	$looping_query_id = BricksQuery::is_any_looping();
	
	if ( $looping_query_id && BricksQuery::get_query_object_type( $looping_query_id ) === 'published_years' ) {
		return BricksQuery::get_loop_object( $looping_query_id );
	}
	
	// return current year in 4 digit format
	return date( 'Y' );
}

Step 2

Edit a Page with Bricks.

Section’s json for copy and paste. Manual setup steps below.

Add a Section and inside its Container, a Block. Rename it to “Year Loop Block”.

Enable query loop.

Set the query type to “Published Years”.

Add a Heading inside the Block and rename it as “Year Heading”.

Set its text to:

{echo:bl_get_looping_year}

Add a Container at the same level below it and inside that a Block.

Rename the Block as “Category Loop Block”.

Enable query loop.

Query type: Terms → Categories (Post).
You can of course select any taxonomy here instead like a custom taxonomy.

Add a Heading inside and set its label to “Category Heading”.

For the text, search/select Term name from the dynamic data selector or type:

{term_name}

Add a Container at the same level below it.

Add a Block inside it and set its label to “Post Loop Block”.

Enable query loop.

Toggle “Query editor (PHP)” on and paste:

return [
	'year' => BricksQuery::get_query_for_element_id( 'wbihbf' )->loop_object,
	'cat' => BricksQuery::get_query_for_element_id( 'zwcvis' )->loop_object->term_id,
	'bricks_force_run' => true,
	'posts_per_page' => -1,
];

Change wbihbf to the Bricks ID of the Year Loop Block element.

Change zwcvis to the Bricks ID of the Category Loop Block element.

BricksQuery::get_query_for_element_id( 'wbihbf' )->loop_object

will always be the latest year (2023, in this case) as it is saved as a history in Bricks Query.

We are fixing this by adding this query parameter:

'bricks_force_run' => true

which was introduced in Bricks 1.9.2.

Add a Basic Text element inside the Post Loop Block and set its text to:


{post_date:d M Y} – <a href=»{post_url}»>{post_title}</a>

view raw

gistfile1.txt

hosted with ❤ by GitHub

Finally, let’s ensure that empty categories are not output.

Apply a dynamic data condition on the Category Loop Block like this:

Replace awjfwn with the Bricks ID of Post Loop Block element.