diff --git a/lib/compat/wordpress-6.0/blocks.php b/lib/compat/wordpress-6.0/blocks.php
index 5b158cbc551a84..286ddc8d834c04 100644
--- a/lib/compat/wordpress-6.0/blocks.php
+++ b/lib/compat/wordpress-6.0/blocks.php
@@ -64,15 +64,40 @@ function gutenberg_build_query_vars_from_query_block( $block, $page ) {
$query['offset'] = ( $per_page * ( $page - 1 ) ) + $offset;
$query['posts_per_page'] = $per_page;
}
- if ( ! empty( $block->context['query']['categoryIds'] ) ) {
- $term_ids = array_map( 'intval', $block->context['query']['categoryIds'] );
- $term_ids = array_filter( $term_ids );
- $query['category__in'] = $term_ids;
+
+ // We need to migrate `categoryIds` and `tagIds` to `tax_query` for backwards compatibility.
+ if ( ! empty( $block->context['query']['categoryIds'] ) || ! empty( $block->context['query']['tagIds'] ) ) {
+ $tax_query = array();
+ if ( ! empty( $block->context['query']['categoryIds'] ) ) {
+ $tax_query[] = array(
+ 'taxonomy' => 'category',
+ 'terms' => $block->context['query']['categoryIds'],
+ 'include_children' => false,
+ );
+ }
+ if ( ! empty( $block->context['query']['tagIds'] ) ) {
+ $tax_query[] = array(
+ 'taxonomy' => 'post_tag',
+ 'terms' => $block->context['query']['tagIds'],
+ 'include_children' => false,
+ );
+ }
+ $query['tax_query'] = $tax_query;
}
- if ( ! empty( $block->context['query']['tagIds'] ) ) {
- $term_ids = array_map( 'intval', $block->context['query']['tagIds'] );
- $term_ids = array_filter( $term_ids );
- $query['tag__in'] = $term_ids;
+ if ( ! empty( $block->context['query']['taxQuery'] ) ) {
+ $query['tax_query'] = array();
+ foreach ( $block->context['query']['taxQuery'] as $taxonomy => $terms ) {
+ if ( ! empty( $terms ) ) {
+ $term_ids = array_map( 'intval', $terms );
+ $term_ids = array_filter( $term_ids );
+
+ $query['tax_query'][] = array(
+ 'taxonomy' => $taxonomy,
+ 'terms' => $terms,
+ 'include_children' => false,
+ );
+ }
+ }
}
if (
isset( $block->context['query']['order'] ) &&
diff --git a/packages/block-library/src/post-template/edit.js b/packages/block-library/src/post-template/edit.js
index 59a3e306dd247d..bcf4f909d6a8f0 100644
--- a/packages/block-library/src/post-template/edit.js
+++ b/packages/block-library/src/post-template/edit.js
@@ -69,9 +69,7 @@ export default function PostTemplateEdit( {
query: {
perPage,
offset,
- categoryIds = [],
postType,
- tagIds = [],
order,
orderBy,
author,
@@ -79,6 +77,7 @@ export default function PostTemplateEdit( {
exclude,
sticky,
inherit,
+ taxQuery,
} = {},
queryContext = [ { page: 1 } ],
templateSlug,
@@ -90,15 +89,37 @@ export default function PostTemplateEdit( {
const { posts, blocks } = useSelect(
( select ) => {
- const { getEntityRecords } = select( coreStore );
+ const { getEntityRecords, getTaxonomies } = select( coreStore );
const { getBlocks } = select( blockEditorStore );
+ const taxonomies = getTaxonomies( {
+ type: postType,
+ per_page: -1,
+ context: 'view',
+ } );
const query = {
offset: perPage ? perPage * ( page - 1 ) + offset : 0,
- categories: categoryIds,
- tags: tagIds,
order,
orderby: orderBy,
};
+ if ( taxQuery ) {
+ // We have to build the tax query for the REST API and use as
+ // keys the taxonomies `rest_base` with the `term ids` as values.
+ const builtTaxQuery = Object.entries( taxQuery ).reduce(
+ ( accumulator, [ taxonomySlug, terms ] ) => {
+ const taxonomy = taxonomies?.find(
+ ( { slug } ) => slug === taxonomySlug
+ );
+ if ( taxonomy?.rest_base ) {
+ accumulator[ taxonomy?.rest_base ] = terms;
+ }
+ return accumulator;
+ },
+ {}
+ );
+ if ( !! Object.keys( builtTaxQuery ).length ) {
+ Object.assign( query, builtTaxQuery );
+ }
+ }
if ( perPage ) {
query.per_page = perPage;
}
@@ -134,8 +155,6 @@ export default function PostTemplateEdit( {
perPage,
page,
offset,
- categoryIds,
- tagIds,
order,
orderBy,
clientId,
@@ -146,6 +165,7 @@ export default function PostTemplateEdit( {
sticky,
inherit,
templateSlug,
+ taxQuery,
]
);
const blockContexts = useMemo(
diff --git a/packages/block-library/src/query/block.json b/packages/block-library/src/query/block.json
index 050322deab1584..66844e3b45a343 100644
--- a/packages/block-library/src/query/block.json
+++ b/packages/block-library/src/query/block.json
@@ -17,15 +17,14 @@
"pages": 0,
"offset": 0,
"postType": "post",
- "categoryIds": [],
- "tagIds": [],
"order": "desc",
"orderBy": "date",
"author": "",
"search": "",
"exclude": [],
"sticky": "",
- "inherit": true
+ "inherit": true,
+ "taxQuery": null
}
},
"tagName": {
diff --git a/packages/block-library/src/query/deprecated.js b/packages/block-library/src/query/deprecated.js
index 34cb5da80f85e2..32a85c83a3a099 100644
--- a/packages/block-library/src/query/deprecated.js
+++ b/packages/block-library/src/query/deprecated.js
@@ -6,9 +6,85 @@ import { omit } from 'lodash';
/**
* WordPress dependencies
*/
-import { InnerBlocks } from '@wordpress/block-editor';
+import {
+ InnerBlocks,
+ useInnerBlocksProps,
+ useBlockProps,
+} from '@wordpress/block-editor';
+
+const migrateToTaxQuery = ( attributes ) => {
+ const { query } = attributes;
+ const newQuery = {
+ ...omit( query, [ 'categoryIds', 'tagIds' ] ),
+ };
+ if ( query.categoryIds?.length || query.tagIds?.length ) {
+ newQuery.taxQuery = {
+ category: !! query.categoryIds?.length
+ ? query.categoryIds
+ : undefined,
+ post_tag: !! query.tagIds?.length ? query.tagIds : undefined,
+ };
+ }
+ return {
+ ...attributes,
+ query: newQuery,
+ };
+};
const deprecated = [
+ // Version with `categoryIds and tagIds`.
+ {
+ attributes: {
+ queryId: {
+ type: 'number',
+ },
+ query: {
+ type: 'object',
+ default: {
+ perPage: null,
+ pages: 0,
+ offset: 0,
+ postType: 'post',
+ categoryIds: [],
+ tagIds: [],
+ order: 'desc',
+ orderBy: 'date',
+ author: '',
+ search: '',
+ exclude: [],
+ sticky: '',
+ inherit: true,
+ },
+ },
+ tagName: {
+ type: 'string',
+ default: 'div',
+ },
+ displayLayout: {
+ type: 'object',
+ default: {
+ type: 'list',
+ },
+ },
+ },
+ supports: {
+ align: [ 'wide', 'full' ],
+ html: false,
+ color: {
+ gradients: true,
+ link: true,
+ },
+ __experimentalLayout: true,
+ },
+ isEligible: ( { query: { categoryIds, tagIds } = {} } ) =>
+ categoryIds || tagIds,
+ migrate: migrateToTaxQuery,
+ save( { attributes: { tagName: Tag = 'div' } } ) {
+ const blockProps = useBlockProps.save();
+ const innerBlocksProps = useInnerBlocksProps.save( blockProps );
+ return
;
+ },
+ },
// Version with NO wrapper `div` element.
{
attributes: {
@@ -44,9 +120,10 @@ const deprecated = [
html: false,
},
migrate( attributes ) {
+ const withTaxQuery = migrateToTaxQuery( attributes );
return {
- ...omit( attributes, [ 'layout' ] ),
- displayLayout: attributes.layout,
+ ...omit( withTaxQuery, [ 'layout' ] ),
+ displayLayout: withTaxQuery.layout,
};
},
save() {
diff --git a/packages/block-library/src/query/edit/inspector-controls/index.js b/packages/block-library/src/query/edit/inspector-controls/index.js
index 4984434d42ac04..23bb0674f38b22 100644
--- a/packages/block-library/src/query/edit/inspector-controls/index.js
+++ b/packages/block-library/src/query/edit/inspector-controls/index.js
@@ -9,7 +9,6 @@ import { debounce } from 'lodash';
import {
PanelBody,
TextControl,
- FormTokenField,
SelectControl,
RangeControl,
ToggleControl,
@@ -17,17 +16,15 @@ import {
} from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { InspectorControls } from '@wordpress/block-editor';
-import { useSelect } from '@wordpress/data';
import { useEffect, useState, useCallback } from '@wordpress/element';
-import { store as coreStore } from '@wordpress/core-data';
/**
* Internal dependencies
*/
import OrderControl from './order-control';
import AuthorControl from './author-control';
-import { getEntitiesInfo, usePostTypes } from '../../utils';
-import { MAX_FETCHED_TERMS } from '../../constants';
+import TaxonomyControls from './taxonomy-controls';
+import { usePostTypes } from '../../utils';
const stickyOptions = [
{ label: __( 'Include' ), value: '' },
@@ -35,28 +32,6 @@ const stickyOptions = [
{ label: __( 'Only' ), value: 'only' },
];
-// Helper function to get the term id based on user input in terms `FormTokenField`.
-const getTermIdByTermValue = ( termsMappedByName, termValue ) => {
- // First we check for exact match by `term.id` or case sensitive `term.name` match.
- const termId = termValue?.id || termsMappedByName[ termValue ]?.id;
- if ( termId ) return termId;
- /**
- * Here we make an extra check for entered terms in a non case sensitive way,
- * to match user expectations, due to `FormTokenField` behaviour that shows
- * suggestions which are case insensitive.
- *
- * Although WP tries to discourage users to add terms with the same name (case insensitive),
- * it's still possible if you manually change the name, as long as the terms have different slugs.
- * In this edge case we always apply the first match from the terms list.
- */
- const termValueLower = termValue.toLocaleLowerCase();
- for ( const term in termsMappedByName ) {
- if ( term.toLocaleLowerCase() === termValueLower ) {
- return termsMappedByName[ term ].id;
- }
- }
-};
-
export default function QueryInspectorControls( {
attributes: { query, displayLayout },
setQuery,
@@ -69,64 +44,36 @@ export default function QueryInspectorControls( {
postType,
sticky,
inherit,
+ taxQuery,
} = query;
- const [ showCategories, setShowCategories ] = useState( true );
- const [ showTags, setShowTags ] = useState( true );
const [ showSticky, setShowSticky ] = useState( postType === 'post' );
const { postTypesTaxonomiesMap, postTypesSelectOptions } = usePostTypes();
- const { categories, tags } = useSelect( ( select ) => {
- const { getEntityRecords } = select( coreStore );
- const termsQuery = { per_page: MAX_FETCHED_TERMS };
- const _categories = getEntityRecords(
- 'taxonomy',
- 'category',
- termsQuery
- );
- const _tags = getEntityRecords( 'taxonomy', 'post_tag', termsQuery );
- return {
- categories: getEntitiesInfo( _categories ),
- tags: getEntitiesInfo( _tags ),
- };
- }, [] );
- useEffect( () => {
- if ( ! postTypesTaxonomiesMap ) return;
- const postTypeTaxonomies = postTypesTaxonomiesMap[ postType ];
- setShowCategories( postTypeTaxonomies.includes( 'category' ) );
- setShowTags( postTypeTaxonomies.includes( 'post_tag' ) );
- }, [ postType, postTypesTaxonomiesMap ] );
useEffect( () => {
setShowSticky( postType === 'post' );
}, [ postType ] );
const onPostTypeChange = ( newValue ) => {
const updateQuery = { postType: newValue };
- if ( ! postTypesTaxonomiesMap[ newValue ].includes( 'category' ) ) {
- updateQuery.categoryIds = [];
- }
- if ( ! postTypesTaxonomiesMap[ newValue ].includes( 'post_tag' ) ) {
- updateQuery.tagIds = [];
- }
+ // We need to dynamically update the `taxQuery` property,
+ // by removing any not supported taxonomy from the query.
+ const supportedTaxonomies = postTypesTaxonomiesMap[ newValue ];
+ const updatedTaxQuery = Object.entries( taxQuery || {} ).reduce(
+ ( accumulator, [ taxonomySlug, terms ] ) => {
+ if ( supportedTaxonomies.includes( taxonomySlug ) ) {
+ accumulator[ taxonomySlug ] = terms;
+ }
+ return accumulator;
+ },
+ {}
+ );
+ updateQuery.taxQuery = !! Object.keys( updatedTaxQuery ).length
+ ? updatedTaxQuery
+ : undefined;
+
if ( newValue !== 'post' ) {
updateQuery.sticky = '';
}
setQuery( updateQuery );
};
- // Handles categories and tags changes.
- const onTermsChange = ( terms, queryProperty ) => ( newTermValues ) => {
- const termIds = Array.from(
- newTermValues.reduce( ( accumulator, termValue ) => {
- const termId = getTermIdByTermValue(
- terms.mapByName,
- termValue
- );
- if ( termId ) accumulator.add( termId );
- return accumulator;
- }, new Set() )
- );
- setQuery( { [ queryProperty ]: termIds } );
- };
- const onCategoriesChange = onTermsChange( categories, 'categoryIds' );
- const onTagsChange = onTermsChange( tags, 'tagIds' );
-
const [ querySearch, setQuerySearch ] = useState( query.search );
const onChangeDebounced = useCallback(
debounce( () => {
@@ -136,42 +83,10 @@ export default function QueryInspectorControls( {
}, 250 ),
[ querySearch, query.search ]
);
-
useEffect( () => {
onChangeDebounced();
return onChangeDebounced.cancel;
}, [ querySearch, onChangeDebounced ] );
-
- // Returns only the existing term ids (categories/tags) in proper
- // format to be used in `FormTokenField`. This prevents the component
- // from crashing in the editor, when non existing term ids were provided.
- const getExistingTermsFormTokenValue = ( taxonomy ) => {
- const termsMapper = {
- category: {
- queryProp: 'categoryIds',
- terms: categories,
- },
- post_tag: {
- queryProp: 'tagIds',
- terms: tags,
- },
- };
- const requestedTerm = termsMapper[ taxonomy ];
- return ( query[ requestedTerm.queryProp ] || [] ).reduce(
- ( accumulator, termId ) => {
- const term = requestedTerm.terms.mapById[ termId ];
- if ( term ) {
- accumulator.push( {
- id: termId,
- value: term.name,
- } );
- }
- return accumulator;
- },
- []
- );
- };
-
return (
@@ -234,26 +149,7 @@ export default function QueryInspectorControls( {
{ ! inherit && (
- { showCategories && categories?.entities?.length > 0 && (
-
- ) }
- { showTags && tags?.entities?.length > 0 && (
-
- ) }
+
{
+ // First we check for exact match by `term.id` or case sensitive `term.name` match.
+ const termId = termValue?.id || termsMappedByName[ termValue ]?.id;
+ if ( termId ) return termId;
+ /**
+ * Here we make an extra check for entered terms in a non case sensitive way,
+ * to match user expectations, due to `FormTokenField` behaviour that shows
+ * suggestions which are case insensitive.
+ *
+ * Although WP tries to discourage users to add terms with the same name (case insensitive),
+ * it's still possible if you manually change the name, as long as the terms have different slugs.
+ * In this edge case we always apply the first match from the terms list.
+ */
+ const termValueLower = termValue.toLocaleLowerCase();
+ for ( const term in termsMappedByName ) {
+ if ( term.toLocaleLowerCase() === termValueLower ) {
+ return termsMappedByName[ term ].id;
+ }
+ }
+};
+
+function TaxonomyControls( { onChange, query } ) {
+ const taxonomies = useTaxonomies( query.postType );
+ const taxonomiesInfo = useSelect(
+ ( select ) => {
+ const { getEntityRecords } = select( coreStore );
+ const termsQuery = { per_page: MAX_FETCHED_TERMS };
+ const _taxonomiesInfo = taxonomies?.map( ( { slug, name } ) => {
+ const _terms = getEntityRecords( 'taxonomy', slug, termsQuery );
+ return {
+ slug,
+ name,
+ terms: getEntitiesInfo( _terms ),
+ };
+ } );
+ return _taxonomiesInfo;
+ },
+ [ taxonomies ]
+ );
+ const onTermsChange = ( taxonomySlug ) => ( newTermValues ) => {
+ const taxonomyInfo = taxonomiesInfo.find(
+ ( { slug } ) => slug === taxonomySlug
+ );
+ if ( ! taxonomyInfo ) return;
+ const termIds = Array.from(
+ newTermValues.reduce( ( accumulator, termValue ) => {
+ const termId = getTermIdByTermValue(
+ taxonomyInfo.terms.mapByName,
+ termValue
+ );
+ if ( termId ) accumulator.add( termId );
+ return accumulator;
+ }, new Set() )
+ );
+ const newTaxQuery = {
+ ...query.taxQuery,
+ [ taxonomySlug ]: termIds,
+ };
+ onChange( { taxQuery: newTaxQuery } );
+ };
+ // Returns only the existing term ids in proper format to be
+ // used in `FormTokenField`. This prevents the component from
+ // crashing in the editor, when non existing term ids were provided.
+ const getExistingTaxQueryValue = ( taxonomySlug ) => {
+ const taxonomyInfo = taxonomiesInfo.find(
+ ( { slug } ) => slug === taxonomySlug
+ );
+ if ( ! taxonomyInfo ) return [];
+ return ( query.taxQuery?.[ taxonomySlug ] || [] ).reduce(
+ ( accumulator, termId ) => {
+ const term = taxonomyInfo.terms.mapById[ termId ];
+ if ( term ) {
+ accumulator.push( {
+ id: termId,
+ value: term.name,
+ } );
+ }
+ return accumulator;
+ },
+ []
+ );
+ };
+ return (
+ <>
+ { !! taxonomiesInfo?.length &&
+ taxonomiesInfo.map( ( { slug, name, terms } ) => {
+ if ( ! terms?.names?.length ) {
+ return null;
+ }
+ return (
+
+ );
+ } ) }
+ >
+ );
+}
+
+export default TaxonomyControls;
diff --git a/packages/block-library/src/query/utils.js b/packages/block-library/src/query/utils.js
index f47921047d78cd..76a5465d365c71 100644
--- a/packages/block-library/src/query/utils.js
+++ b/packages/block-library/src/query/utils.js
@@ -55,16 +55,14 @@ export const getEntitiesInfo = ( entities ) => {
* @return {Object} The helper object related to post types.
*/
export const usePostTypes = () => {
- const { postTypes } = useSelect( ( select ) => {
+ const postTypes = useSelect( ( select ) => {
const { getPostTypes } = select( coreStore );
const excludedPostTypes = [ 'attachment' ];
const filteredPostTypes = getPostTypes( { per_page: -1 } )?.filter(
( { viewable, slug } ) =>
viewable && ! excludedPostTypes.includes( slug )
);
- return {
- postTypes: filteredPostTypes,
- };
+ return filteredPostTypes;
}, [] );
const postTypesTaxonomiesMap = useMemo( () => {
if ( ! postTypes?.length ) return;
@@ -84,6 +82,28 @@ export const usePostTypes = () => {
return { postTypesTaxonomiesMap, postTypesSelectOptions };
};
+/**
+ * Hook that returns the taxonomies associated with a specific post type.
+ *
+ * @param {string} postType The post type from which to retrieve the associated taxonomies.
+ * @return {Object[]} An array of the associated taxonomies.
+ */
+export const useTaxonomies = ( postType ) => {
+ const taxonomies = useSelect(
+ ( select ) => {
+ const { getTaxonomies } = select( coreStore );
+ const filteredTaxonomies = getTaxonomies( {
+ type: postType,
+ per_page: -1,
+ context: 'view',
+ } );
+ return filteredTaxonomies;
+ },
+ [ postType ]
+ );
+ return taxonomies;
+};
+
/**
* Recurses over a list of blocks and returns the first found
* Query Loop block's clientId.
diff --git a/packages/block-library/src/query/variations.js b/packages/block-library/src/query/variations.js
index 33c7291599df7d..1d60a062aa6068 100644
--- a/packages/block-library/src/query/variations.js
+++ b/packages/block-library/src/query/variations.js
@@ -20,8 +20,6 @@ const QUERY_DEFAULT_ATTRIBUTES = {
pages: 0,
offset: 0,
postType: 'post',
- categoryIds: [],
- tagIds: [],
order: 'desc',
orderBy: 'date',
author: '',
@@ -46,8 +44,6 @@ const variations = [
pages: 1,
offset: 0,
postType: 'post',
- categoryIds: [],
- tagIds: [],
order: 'desc',
orderBy: 'date',
author: '',
diff --git a/packages/e2e-tests/plugins/query-block.php b/packages/e2e-tests/plugins/query-block.php
index 46f9c363b32783..9ff20d97adee81 100644
--- a/packages/e2e-tests/plugins/query-block.php
+++ b/packages/e2e-tests/plugins/query-block.php
@@ -16,7 +16,7 @@
array(
'title' => __( 'Query Test 1', 'gutenberg' ),
'blockTypes' => array( 'core/query' ),
- 'content' => '
+ 'content' => '
@@ -28,7 +28,7 @@
array(
'title' => __( 'Query Test 2', 'gutenberg' ),
'blockTypes' => array( 'core/query' ),
- 'content' => '
+ 'content' => '
diff --git a/test/emptytheme/block-templates/index.html b/test/emptytheme/block-templates/index.html
index 464f1f429afd6d..74f7551f8bb495 100644
--- a/test/emptytheme/block-templates/index.html
+++ b/test/emptytheme/block-templates/index.html
@@ -1,6 +1,6 @@
-
+
diff --git a/test/integration/fixtures/blocks/core__query.json b/test/integration/fixtures/blocks/core__query.json
index 8fb8c81a1ccbc0..ff7d9fd4ea7677 100644
--- a/test/integration/fixtures/blocks/core__query.json
+++ b/test/integration/fixtures/blocks/core__query.json
@@ -9,15 +9,14 @@
"pages": 0,
"offset": 0,
"postType": "post",
- "categoryIds": [],
- "tagIds": [],
"order": "desc",
"orderBy": "date",
"author": "",
"search": "",
"exclude": [],
"sticky": "",
- "inherit": true
+ "inherit": true,
+ "taxQuery": null
},
"tagName": "div",
"displayLayout": {
diff --git a/test/integration/fixtures/blocks/core__query__deprecated-1.json b/test/integration/fixtures/blocks/core__query__deprecated-1.json
index a719f5442a3e79..64c3ffd94f0f60 100644
--- a/test/integration/fixtures/blocks/core__query__deprecated-1.json
+++ b/test/integration/fixtures/blocks/core__query__deprecated-1.json
@@ -9,8 +9,6 @@
"pages": 0,
"offset": 0,
"postType": "post",
- "categoryIds": [],
- "tagIds": [],
"order": "desc",
"orderBy": "date",
"author": "",
diff --git a/test/integration/fixtures/blocks/core__query__deprecated-1.serialized.html b/test/integration/fixtures/blocks/core__query__deprecated-1.serialized.html
index d763d85e404064..39f889cfae97e1 100644
--- a/test/integration/fixtures/blocks/core__query__deprecated-1.serialized.html
+++ b/test/integration/fixtures/blocks/core__query__deprecated-1.serialized.html
@@ -1,3 +1,3 @@
-
+
diff --git a/test/integration/fixtures/blocks/core__query__deprecated-2.html b/test/integration/fixtures/blocks/core__query__deprecated-2.html
new file mode 100644
index 00000000000000..1499f230ad9b80
--- /dev/null
+++ b/test/integration/fixtures/blocks/core__query__deprecated-2.html
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/test/integration/fixtures/blocks/core__query__deprecated-2.json b/test/integration/fixtures/blocks/core__query__deprecated-2.json
new file mode 100644
index 00000000000000..bab0b2facd9816
--- /dev/null
+++ b/test/integration/fixtures/blocks/core__query__deprecated-2.json
@@ -0,0 +1,56 @@
+[
+ {
+ "clientId": "_clientId_0",
+ "name": "core/query",
+ "isValid": true,
+ "attributes": {
+ "queryId": 19,
+ "query": {
+ "perPage": 3,
+ "pages": 0,
+ "offset": 0,
+ "postType": "post",
+ "order": "desc",
+ "orderBy": "date",
+ "author": "",
+ "search": "",
+ "exclude": [],
+ "sticky": "",
+ "inherit": false,
+ "taxQuery": {
+ "category": [ 3, 5 ],
+ "post_tag": [ 6 ]
+ }
+ },
+ "tagName": "div",
+ "displayLayout": {
+ "type": "list"
+ }
+ },
+ "innerBlocks": [
+ {
+ "clientId": "_clientId_0",
+ "name": "core/post-template",
+ "isValid": true,
+ "attributes": {},
+ "innerBlocks": [
+ {
+ "clientId": "_clientId_0",
+ "name": "core/post-title",
+ "isValid": true,
+ "attributes": {
+ "level": 2,
+ "isLink": false,
+ "rel": "",
+ "linkTarget": "_self"
+ },
+ "innerBlocks": [],
+ "originalContent": ""
+ }
+ ],
+ "originalContent": ""
+ }
+ ],
+ "originalContent": "
\n
"
+ }
+]
diff --git a/test/integration/fixtures/blocks/core__query__deprecated-2.parsed.json b/test/integration/fixtures/blocks/core__query__deprecated-2.parsed.json
new file mode 100644
index 00000000000000..ee38e4c7432788
--- /dev/null
+++ b/test/integration/fixtures/blocks/core__query__deprecated-2.parsed.json
@@ -0,0 +1,46 @@
+[
+ {
+ "blockName": "core/query",
+ "attrs": {
+ "queryId": 19,
+ "query": {
+ "perPage": 3,
+ "pages": 0,
+ "offset": 0,
+ "postType": "post",
+ "categoryIds": [ 3, 5 ],
+ "tagIds": [ 6 ],
+ "order": "desc",
+ "orderBy": "date",
+ "author": "",
+ "search": "",
+ "exclude": [],
+ "sticky": "",
+ "inherit": false
+ }
+ },
+ "innerBlocks": [
+ {
+ "blockName": "core/post-template",
+ "attrs": {},
+ "innerBlocks": [
+ {
+ "blockName": "core/post-title",
+ "attrs": {},
+ "innerBlocks": [],
+ "innerHTML": "",
+ "innerContent": []
+ }
+ ],
+ "innerHTML": "\n\n",
+ "innerContent": [ "\n", null, "\n" ]
+ }
+ ],
+ "innerHTML": "\n
\n
\n",
+ "innerContent": [
+ "\n
",
+ null,
+ "\n
\n"
+ ]
+ }
+]
diff --git a/test/integration/fixtures/blocks/core__query__deprecated-2.serialized.html b/test/integration/fixtures/blocks/core__query__deprecated-2.serialized.html
new file mode 100644
index 00000000000000..5804c54e577f14
--- /dev/null
+++ b/test/integration/fixtures/blocks/core__query__deprecated-2.serialized.html
@@ -0,0 +1,5 @@
+
+
+
+
+