Title: build_query_vars_from_query_block
Published: July 20, 2021
Last modified: August 20, 2026

---

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

## In this article

 * [Description](https://developer.wordpress.org/reference/functions/build_query_vars_from_query_block/?output_format=md#description)
 * [Parameters](https://developer.wordpress.org/reference/functions/build_query_vars_from_query_block/?output_format=md#parameters)
 * [Return](https://developer.wordpress.org/reference/functions/build_query_vars_from_query_block/?output_format=md#return)
 * [Source](https://developer.wordpress.org/reference/functions/build_query_vars_from_query_block/?output_format=md#source)
 * [Hooks](https://developer.wordpress.org/reference/functions/build_query_vars_from_query_block/?output_format=md#hooks)
 * [Related](https://developer.wordpress.org/reference/functions/build_query_vars_from_query_block/?output_format=md#related)
 * [Changelog](https://developer.wordpress.org/reference/functions/build_query_vars_from_query_block/?output_format=md#changelog)
 * [User Contributed Notes](https://developer.wordpress.org/reference/functions/build_query_vars_from_query_block/?output_format=md#user-contributed-notes)

[ Back to top](https://developer.wordpress.org/reference/functions/build_query_vars_from_query_block/?output_format=md#wp--skip-link--target)

Helper function that constructs a [WP_Query](https://developer.wordpress.org/reference/classes/wp_query/)
args array from a `Query` block properties.

## 󠀁[Description](https://developer.wordpress.org/reference/functions/build_query_vars_from_query_block/?output_format=md#description)󠁿

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

## 󠀁[Parameters](https://developer.wordpress.org/reference/functions/build_query_vars_from_query_block/?output_format=md#parameters)󠁿

 `$block`[WP_Block](https://developer.wordpress.org/reference/classes/wp_block/)
required

Block instance.

`$page`intrequired

Current query’s page.

## 󠀁[Return](https://developer.wordpress.org/reference/functions/build_query_vars_from_query_block/?output_format=md#return)󠁿

 array Returns the constructed [WP_Query](https://developer.wordpress.org/reference/classes/wp_query/)
arguments.

## 󠀁[Source](https://developer.wordpress.org/reference/functions/build_query_vars_from_query_block/?output_format=md#source)󠁿

    ```php
    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 beforehand 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;
    			} elseif ( 'exclude' === $block->context['query']['sticky'] ) {
    				$query['post__not_in'] = array_merge( $query['post__not_in'], $sticky );
    			} elseif ( 'ignore' === $block->context['query']['sticky'] ) {
    				$query['ignore_sticky_posts'] = 1;
    			}
    		}
    		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 ( ! empty( $block->context['query']['excludeCurrent'] ) ) {
    			$current_post_id = get_the_ID();
    			if ( $current_post_id ) {
    				$query['post__not_in'][] = $current_post_id;
    			}
    		}
    		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'] ) && is_array( $block->context['query']['taxQuery'] ) ) {
    			$tax_query_input = $block->context['query']['taxQuery'];
    			$tax_query       = array();
    			// If there are keys other than include/exclude, it's the old
    			// format e.g. "taxQuery":{"category":[4]}
    			if ( ! empty( array_diff( array_keys( $tax_query_input ), array( 'include', 'exclude' ) ) ) ) {
    				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,
    						);
    					}
    				}
    			} else {
    				// This is the new format e.g. "taxQuery":{"include":{"category":[4]},"exclude":{"post_tag":[5]}}

    				// Helper function to build tax_query conditions from taxonomy terms.
    				$build_conditions = static function ( $terms, string $operator = 'IN' ): array {
    					$terms      = (array) $terms;
    					$conditions = array();
    					foreach ( $terms as $taxonomy => $tax_terms ) {
    						if ( ! empty( $tax_terms ) && is_taxonomy_viewable( $taxonomy ) ) {
    							$conditions[] = array(
    								'taxonomy'         => $taxonomy,
    								'terms'            => array_filter( array_map( 'intval', $tax_terms ) ),
    								'operator'         => $operator,
    								'include_children' => false,
    							);
    						}
    					}
    					return $conditions;
    				};

    				// Separate exclude from include terms.
    				$exclude_terms = isset( $tax_query_input['exclude'] ) && is_array( $tax_query_input['exclude'] )
    					? $tax_query_input['exclude']
    					: array();
    				$include_terms = isset( $tax_query_input['include'] ) && is_array( $tax_query_input['include'] )
    					? $tax_query_input['include']
    					: array();

    				$tax_query = array_merge(
    					$build_conditions( $include_terms ),
    					$build_conditions( $exclude_terms, 'NOT IN' )
    				);
    			}

    			if ( ! empty( $tax_query ) ) {
    				// Merge with any existing `tax_query` conditions.
    				$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_unique( 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 );
    }
    ```

[View all references](https://developer.wordpress.org/reference/files/wp-includes/blocks.php/)
[View on Trac](https://core.trac.wordpress.org/browser/tags/7.1/src/wp-includes/blocks.php#L2820)
[View on GitHub](https://github.com/WordPress/wordpress-develop/blob/7.1/src/wp-includes/blocks.php#L2820-L3072)

## 󠀁[Hooks](https://developer.wordpress.org/reference/functions/build_query_vars_from_query_block/?output_format=md#hooks)󠁿

 [apply_filters( ‘query_loop_block_query_vars’, array $query, WP_Block $block, int $page )](https://developer.wordpress.org/reference/hooks/query_loop_block_query_vars/)

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

## 󠀁[Related](https://developer.wordpress.org/reference/functions/build_query_vars_from_query_block/?output_format=md#related)󠁿

| Uses | Description | 
| [is_taxonomy_viewable()](https://developer.wordpress.org/reference/functions/is_taxonomy_viewable/)`wp-includes/taxonomy.php` |

Determines whether a taxonomy is considered “viewable”.

  | 
| [is_post_type_viewable()](https://developer.wordpress.org/reference/functions/is_post_type_viewable/)`wp-includes/post.php` |

Determines whether a post type is considered “viewable”.

  | 
| [get_the_ID()](https://developer.wordpress.org/reference/functions/get_the_id/)`wp-includes/post-template.php` |

Retrieves the ID of the current item in the WordPress Loop.

  | 
| [is_post_type_hierarchical()](https://developer.wordpress.org/reference/functions/is_post_type_hierarchical/)`wp-includes/post.php` |

Determines whether the post type is hierarchical.

  | 
| [get_post_format_slugs()](https://developer.wordpress.org/reference/functions/get_post_format_slugs/)`wp-includes/post-formats.php` |

Retrieves the array of post format slugs.

  | 
| [absint()](https://developer.wordpress.org/reference/functions/absint/)`wp-includes/load.php` |

Converts a value to non-negative integer.

  | 
| [apply_filters()](https://developer.wordpress.org/reference/functions/apply_filters/)`wp-includes/plugin.php` |

Calls the callback functions that have been added to a filter hook.

  | 
| [get_option()](https://developer.wordpress.org/reference/functions/get_option/)`wp-includes/option.php` |

Retrieves an option value based on an option name.

  |

[Show 3 more](https://developer.wordpress.org/reference/functions/build_query_vars_from_query_block/?output_format=md#)
[Show less](https://developer.wordpress.org/reference/functions/build_query_vars_from_query_block/?output_format=md#)

## 󠀁[Changelog](https://developer.wordpress.org/reference/functions/build_query_vars_from_query_block/?output_format=md#changelog)󠁿

| Version | Description | 
| [7.1.0](https://developer.wordpress.org/reference/since/7.1.0/) | Added support for the `excludeCurrent` property in query. | 
| [7.0.0](https://developer.wordpress.org/reference/since/7.0.0/) | Updated `taxQuery` structure. | 
| [6.7.0](https://developer.wordpress.org/reference/since/6.7.0/) | Added support for the `format` property in query. | 
| [6.1.0](https://developer.wordpress.org/reference/since/6.1.0/) | Added `query_loop_block_query_vars` filter and `parents` support in query. | 
| [5.8.0](https://developer.wordpress.org/reference/since/5.8.0/) | Introduced. |

## 󠀁[User Contributed Notes](https://developer.wordpress.org/reference/functions/build_query_vars_from_query_block/?output_format=md#user-contributed-notes)󠁿

 1.  [Skip to note 2 content](https://developer.wordpress.org/reference/functions/build_query_vars_from_query_block/?output_format=md#comment-content-7500)
 2.   [Mrinal Haque](https://profiles.wordpress.org/mrinal013/)  [  6 months ago  ](https://developer.wordpress.org/reference/functions/build_query_vars_from_query_block/#comment-7500)
 3. [You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fbuild_query_vars_from_query_block%2F%23comment-7500)
    Vote results for this note: 0[You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fbuild_query_vars_from_query_block%2F%23comment-7500)
 4. It’s also used in Query Total block.
 5.  [Log in to add feedback](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fbuild_query_vars_from_query_block%2F%3Freplytocom%3D7500%23feedback-editor-7500)

You must [log in](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fbuild_query_vars_from_query_block%2F)
before being able to contribute a note or feedback.