build_query_vars_from_query_block( WP_Block $block, int $page ): array

Helper function that constructs a WP_Query args array from a Query block properties.

Description

It’s used in Query Loop, Query Pagination Numbers and Query Pagination Next blocks.

Parameters

$blockWP_Blockrequired
Block instance.
$pageintrequired
Current query’s page.

Return

array Returns the constructed WP_Query arguments.

Source

function build_query_vars_from_query_block( $block, $page ) {
	$query = array(
		'post_type'    => 'post',
		'order'        => 'DESC',
		'orderby'      => 'date',
		'post__not_in' => array(),
		'tax_query'    => array(),
	);

	if ( isset( $block->context['query'] ) ) {
		if ( ! empty( $block->context['query']['postType'] ) ) {
			$post_type_param = $block->context['query']['postType'];
			if ( is_post_type_viewable( $post_type_param ) ) {
				$query['post_type'] = $post_type_param;
			}
		}
		if ( isset( $block->context['query']['sticky'] ) && ! empty( $block->context['query']['sticky'] ) ) {
			$sticky = get_option( 'sticky_posts' );
			if ( 'only' === $block->context['query']['sticky'] ) {
				/*
				 * Passing an empty array to post__in will return have_posts() as true (and all posts will be returned).
				 * Logic should be used before hand to determine if WP_Query should be used in the event that the array
				 * being passed to post__in is empty.
				 *
				 * @see https://core.trac.wordpress.org/ticket/28099
				 */
				$query['post__in']            = ! empty( $sticky ) ? $sticky : array( 0 );
				$query['ignore_sticky_posts'] = 1;
			} else {
				$query['post__not_in'] = array_merge( $query['post__not_in'], $sticky );
			}
		}
		if ( ! empty( $block->context['query']['exclude'] ) ) {
			$excluded_post_ids     = array_map( 'intval', $block->context['query']['exclude'] );
			$excluded_post_ids     = array_filter( $excluded_post_ids );
			$query['post__not_in'] = array_merge( $query['post__not_in'], $excluded_post_ids );
		}
		if (
			isset( $block->context['query']['perPage'] ) &&
			is_numeric( $block->context['query']['perPage'] )
		) {
			$per_page = absint( $block->context['query']['perPage'] );
			$offset   = 0;

			if (
				isset( $block->context['query']['offset'] ) &&
				is_numeric( $block->context['query']['offset'] )
			) {
				$offset = absint( $block->context['query']['offset'] );
			}

			$query['offset']         = ( $per_page * ( $page - 1 ) ) + $offset;
			$query['posts_per_page'] = $per_page;
		}
		// Migrate `categoryIds` and `tagIds` to `tax_query` for backwards compatibility.
		if ( ! empty( $block->context['query']['categoryIds'] ) || ! empty( $block->context['query']['tagIds'] ) ) {
			$tax_query_back_compat = array();
			if ( ! empty( $block->context['query']['categoryIds'] ) ) {
				$tax_query_back_compat[] = array(
					'taxonomy'         => 'category',
					'terms'            => array_filter( array_map( 'intval', $block->context['query']['categoryIds'] ) ),
					'include_children' => false,
				);
			}
			if ( ! empty( $block->context['query']['tagIds'] ) ) {
				$tax_query_back_compat[] = array(
					'taxonomy'         => 'post_tag',
					'terms'            => array_filter( array_map( 'intval', $block->context['query']['tagIds'] ) ),
					'include_children' => false,
				);
			}
			$query['tax_query'] = array_merge( $query['tax_query'], $tax_query_back_compat );
		}
		if ( ! empty( $block->context['query']['taxQuery'] ) ) {
			$tax_query = array();
			foreach ( $block->context['query']['taxQuery'] as $taxonomy => $terms ) {
				if ( is_taxonomy_viewable( $taxonomy ) && ! empty( $terms ) ) {
					$tax_query[] = array(
						'taxonomy'         => $taxonomy,
						'terms'            => array_filter( array_map( 'intval', $terms ) ),
						'include_children' => false,
					);
				}
			}
			$query['tax_query'] = array_merge( $query['tax_query'], $tax_query );
		}
		if ( ! empty( $block->context['query']['format'] ) && is_array( $block->context['query']['format'] ) ) {
			$formats = $block->context['query']['format'];
			/*
			 * Validate that the format is either `standard` or a supported post format.
			 * - First, add `standard` to the array of valid formats.
			 * - Then, remove any invalid formats.
			 */
			$valid_formats = array_merge( array( 'standard' ), get_post_format_slugs() );
			$formats       = array_intersect( $formats, $valid_formats );

			/*
			 * The relation needs to be set to `OR` since the request can contain
			 * two separate conditions. The user may be querying for items that have
			 * either the `standard` format or a specific format.
			 */
			$formats_query = array( 'relation' => 'OR' );

			/*
			 * The default post format, `standard`, is not stored in the database.
			 * If `standard` is part of the request, the query needs to exclude all post items that
			 * have a format assigned.
			 */
			if ( in_array( 'standard', $formats, true ) ) {
				$formats_query[] = array(
					'taxonomy' => 'post_format',
					'field'    => 'slug',
					'operator' => 'NOT EXISTS',
				);
				// Remove the `standard` format, since it cannot be queried.
				unset( $formats[ array_search( 'standard', $formats, true ) ] );
			}
			// Add any remaining formats to the formats query.
			if ( ! empty( $formats ) ) {
				// Add the `post-format-` prefix.
				$terms           = array_map(
					static function ( $format ) {
						return "post-format-$format";
					},
					$formats
				);
				$formats_query[] = array(
					'taxonomy' => 'post_format',
					'field'    => 'slug',
					'terms'    => $terms,
					'operator' => 'IN',
				);
			}

			/*
			 * Add `$formats_query` to `$query`, as long as it contains more than one key:
			 * If `$formats_query` only contains the initial `relation` key, there are no valid formats to query,
			 * and the query should not be modified.
			 */
			if ( count( $formats_query ) > 1 ) {
				// Enable filtering by both post formats and other taxonomies by combining them with `AND`.
				if ( empty( $query['tax_query'] ) ) {
					$query['tax_query'] = $formats_query;
				} else {
					$query['tax_query'] = array(
						'relation' => 'AND',
						$query['tax_query'],
						$formats_query,
					);
				}
			}
		}

		if (
			isset( $block->context['query']['order'] ) &&
				in_array( strtoupper( $block->context['query']['order'] ), array( 'ASC', 'DESC' ), true )
		) {
			$query['order'] = strtoupper( $block->context['query']['order'] );
		}
		if ( isset( $block->context['query']['orderBy'] ) ) {
			$query['orderby'] = $block->context['query']['orderBy'];
		}
		if (
			isset( $block->context['query']['author'] )
		) {
			if ( is_array( $block->context['query']['author'] ) ) {
				$query['author__in'] = array_filter( array_map( 'intval', $block->context['query']['author'] ) );
			} elseif ( is_string( $block->context['query']['author'] ) ) {
				$query['author__in'] = array_filter( array_map( 'intval', explode( ',', $block->context['query']['author'] ) ) );
			} elseif ( is_int( $block->context['query']['author'] ) && $block->context['query']['author'] > 0 ) {
				$query['author'] = $block->context['query']['author'];
			}
		}
		if ( ! empty( $block->context['query']['search'] ) ) {
			$query['s'] = $block->context['query']['search'];
		}
		if ( ! empty( $block->context['query']['parents'] ) && is_post_type_hierarchical( $query['post_type'] ) ) {
			$query['post_parent__in'] = array_filter( array_map( 'intval', $block->context['query']['parents'] ) );
		}
	}

	/**
	 * Filters the arguments which will be passed to `WP_Query` for the Query Loop Block.
	 *
	 * Anything to this filter should be compatible with the `WP_Query` API to form
	 * the query context which will be passed down to the Query Loop Block's children.
	 * This can help, for example, to include additional settings or meta queries not
	 * directly supported by the core Query Loop Block, and extend its capabilities.
	 *
	 * Please note that this will only influence the query that will be rendered on the
	 * front-end. The editor preview is not affected by this filter. Also, worth noting
	 * that the editor preview uses the REST API, so, ideally, one should aim to provide
	 * attributes which are also compatible with the REST API, in order to be able to
	 * implement identical queries on both sides.
	 *
	 * @since 6.1.0
	 *
	 * @param array    $query Array containing parameters for `WP_Query` as parsed by the block context.
	 * @param WP_Block $block Block instance.
	 * @param int      $page  Current query's page.
	 */
	return apply_filters( 'query_loop_block_query_vars', $query, $block, $page );
}

Hooks

apply_filters( ‘query_loop_block_query_vars’, array $query, WP_Block $block, int $page )

Filters the arguments which will be passed to WP_Query for the Query Loop Block.

Changelog

VersionDescription
6.7.0Added support for the format property in query.
6.1.0Added query_loop_block_query_vars filter and parents support in query.
5.8.0Introduced.

User Contributed Notes

You must log in before being able to contribute a note or feedback.