From b4d97c06b972da3d85f57c1bc114302a20055430 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Wed, 2 Sep 2020 15:06:08 +0300 Subject: [PATCH 1/6] add tags support in Query block --- lib/compat.php | 17 +++++ packages/block-library/src/query-loop/edit.js | 12 +++- .../block-library/src/query-loop/index.php | 4 ++ packages/block-library/src/query/block.json | 1 + .../src/query/edit/query-toolbar.js | 71 +++++++++++-------- packages/block-library/src/query/utils.js | 17 +++++ .../fixtures/blocks/core__query.json | 1 + .../edit-site/src/components/editor/index.js | 2 +- 8 files changed, 92 insertions(+), 33 deletions(-) create mode 100644 packages/block-library/src/query/utils.js diff --git a/lib/compat.php b/lib/compat.php index b5ad85956d068f..7325d5c493b8e6 100644 --- a/lib/compat.php +++ b/lib/compat.php @@ -418,6 +418,23 @@ function gutenberg_render_block_with_assigned_block_context( $pre_render, $parse } } + if ( isset( $wp_query->tax_query->queried_terms['post_tag'] ) ) { + $context['query'] = array( 'tagIds' => array() ); + + foreach ( $wp_query->tax_query->queried_terms['post_tag']['terms'] as $tag_slug_or_id ) { + $tag_ID = $tag_slug_or_id; + + if ( 'slug' === $wp_query->tax_query->queried_terms['post_tag']['field'] ) { + $tag = get_term_by( 'slug', $tag_slug_or_id, 'post_tag' ); + + if ( $tag ) { + $tag_ID = $tag->term_id; + } + } + $context['query']['tagIds'][] = $tag_ID; + } + } + /** * Filters the default context provided to a rendered block. * diff --git a/packages/block-library/src/query-loop/edit.js b/packages/block-library/src/query-loop/edit.js index 4f993327f191ff..06a7949a87e4db 100644 --- a/packages/block-library/src/query-loop/edit.js +++ b/packages/block-library/src/query-loop/edit.js @@ -19,7 +19,14 @@ const TEMPLATE = [ [ 'core/post-title' ], [ 'core/post-content' ] ]; export default function QueryLoopEdit( { clientId, context: { - query: { perPage, offset, categoryIds, order, orderBy } = {}, + query: { + perPage, + offset, + categoryIds, + tagIds = [], + order, + orderBy, + } = {}, queryContext, }, } ) { @@ -31,6 +38,7 @@ export default function QueryLoopEdit( { const query = { offset: perPage ? perPage * ( page - 1 ) + offset : 0, categories: categoryIds, + tags: tagIds, order, orderby: orderBy, }; @@ -46,7 +54,7 @@ export default function QueryLoopEdit( { blocks: select( 'core/block-editor' ).getBlocks( clientId ), }; }, - [ perPage, page, offset, categoryIds, order, orderBy, clientId ] + [ perPage, page, offset, categoryIds, tagIds, order, orderBy, clientId ] ); const blockContexts = useMemo( diff --git a/packages/block-library/src/query-loop/index.php b/packages/block-library/src/query-loop/index.php index 43ba6ce252ded0..45c1622627e290 100644 --- a/packages/block-library/src/query-loop/index.php +++ b/packages/block-library/src/query-loop/index.php @@ -32,6 +32,9 @@ function render_block_core_query_loop( $attributes, $content, $block ) { if ( isset( $block->context['query']['categoryIds'] ) ) { $query['category__in'] = $block->context['query']['categoryIds']; } + if ( isset( $block->context['query']['tagIds'] ) ) { + $query['tag__in'] = $block->context['query']['tagIds']; + } if ( isset( $block->context['query']['order'] ) ) { $query['order'] = strtoupper( $block->context['query']['order'] ); } @@ -42,6 +45,7 @@ function render_block_core_query_loop( $attributes, $content, $block ) { $query['posts_per_page'] = $block->context['query']['perPage']; } } + $posts = get_posts( $query ); $content = ''; diff --git a/packages/block-library/src/query/block.json b/packages/block-library/src/query/block.json index 2561ccbe1f844a..a4d39f0c7b3dda 100644 --- a/packages/block-library/src/query/block.json +++ b/packages/block-library/src/query/block.json @@ -12,6 +12,7 @@ "pages": 1, "offset": 0, "categoryIds": [], + "tagIds": [], "order": "desc", "orderBy": "date" } diff --git a/packages/block-library/src/query/edit/query-toolbar.js b/packages/block-library/src/query/edit/query-toolbar.js index b80e9a4f8a29cf..2453c7ca7112d6 100644 --- a/packages/block-library/src/query/edit/query-toolbar.js +++ b/packages/block-library/src/query/edit/query-toolbar.js @@ -12,32 +12,21 @@ import { import { __ } from '@wordpress/i18n'; import { postList } from '@wordpress/icons'; +/** + * Internal dependencies + */ +import { getTaxonomyInfo } from '../utils'; + export default function QueryToolbar( { query, setQuery } ) { - const { categories, categoriesMapById, categoriesMapByName } = useSelect( - ( select ) => { - const _categories = select( 'core' ).getEntityRecords( - 'taxonomy', - 'category' - ); - return { - categories: _categories, - ..._categories?.reduce( - ( acc, category ) => ( { - categoriesMapById: { - ...acc.categoriesMapById, - [ category.id ]: category, - }, - categoriesMapByName: { - ...acc.categoriesMapByName, - [ category.name ]: category, - }, - } ), - { categoriesMapById: {}, categoriesMapByName: {} } - ), - }; - }, - [] - ); + const { categories, tags } = useSelect( ( select ) => { + const { getEntityRecords } = select( 'core' ); + const _categories = getEntityRecords( 'taxonomy', 'category' ); + const _tags = getEntityRecords( 'taxonomy', 'post_tag' ); + return { + categories: getTaxonomyInfo( _categories ), + tags: getTaxonomyInfo( _tags ), + }; + }, [] ); return ( - { categories && ( + { categories?.terms && ( ( { id: categoryId, value: - categoriesMapById[ categoryId ] + categories.mapById[ categoryId ] .name, } ) ) } - suggestions={ categories.map( - ( category ) => category.name + suggestions={ categories.terms.map( + ( { name } ) => name ) } onChange={ ( newCategoryNames ) => { const categoryIds = newCategoryNames.map( ( categoryName ) => - categoriesMapByName[ categoryName ] + categories.mapByName[ categoryName ] ?.id ); if ( categoryIds.includes( undefined ) ) @@ -103,6 +92,28 @@ export default function QueryToolbar( { query, setQuery } ) { } } /> ) } + { tags?.terms && ( + ( { + id: tagId, + value: tags.mapById[ tagId ].name, + } ) + ) } + suggestions={ tags.terms.map( + ( { name } ) => name + ) } + onChange={ ( newTagNames ) => { + const tagIds = newTagNames.map( + ( tagName ) => + tags.mapByName[ tagName ]?.id + ); + if ( tagIds.includes( undefined ) ) return; + setQuery( { tagIds } ); + } } + /> + ) } ) } /> diff --git a/packages/block-library/src/query/utils.js b/packages/block-library/src/query/utils.js new file mode 100644 index 00000000000000..a006225196cbc1 --- /dev/null +++ b/packages/block-library/src/query/utils.js @@ -0,0 +1,17 @@ +// TODO jsdoc and tests +export const getTaxonomyInfo = ( terms ) => ( { + terms, + ...terms?.reduce( + ( acc, term ) => ( { + mapById: { + ...acc.mapById, + [ term.id ]: term, + }, + mapByName: { + ...acc.mapByName, + [ term.name ]: term, + }, + } ), + { mapById: {}, mapByName: {} } + ), +} ); diff --git a/packages/e2e-tests/fixtures/blocks/core__query.json b/packages/e2e-tests/fixtures/blocks/core__query.json index 9e2d6307436c15..e06e002a5a3141 100644 --- a/packages/e2e-tests/fixtures/blocks/core__query.json +++ b/packages/e2e-tests/fixtures/blocks/core__query.json @@ -9,6 +9,7 @@ "pages": 1, "offset": 0, "categoryIds": [], + "tagIds": [], "order": "desc", "orderBy": "date" } diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index 5758a7f2b8e9f1..4e4f40e6eea864 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -136,7 +136,7 @@ function Editor() { const blockContext = useMemo( () => ( { ...page?.context, - query: page?.context.query || { categoryIds: [] }, + query: page?.context.query || { categoryIds: [], tagIds: [] }, queryContext: [ page?.context.queryContext || { page: 1 }, ( newQueryContext ) => From c63bba1c3c5c2da9ad6f09e936561fef8d1eb824 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Wed, 2 Sep 2020 19:16:03 +0300 Subject: [PATCH 2/6] refactor + tests for getTermsInfo --- .../src/query/edit/query-toolbar.js | 46 ++++++++----------- .../src/query/test/fixtures/index.js | 21 +++++++++ .../block-library/src/query/test/utils.js | 30 ++++++++++++ packages/block-library/src/query/utils.js | 21 ++++----- 4 files changed, 79 insertions(+), 39 deletions(-) create mode 100644 packages/block-library/src/query/test/fixtures/index.js create mode 100644 packages/block-library/src/query/test/utils.js diff --git a/packages/block-library/src/query/edit/query-toolbar.js b/packages/block-library/src/query/edit/query-toolbar.js index 2453c7ca7112d6..7bd16afb99ad0d 100644 --- a/packages/block-library/src/query/edit/query-toolbar.js +++ b/packages/block-library/src/query/edit/query-toolbar.js @@ -15,7 +15,7 @@ import { postList } from '@wordpress/icons'; /** * Internal dependencies */ -import { getTaxonomyInfo } from '../utils'; +import { getTermsInfo } from '../utils'; export default function QueryToolbar( { query, setQuery } ) { const { categories, tags } = useSelect( ( select ) => { @@ -23,10 +23,22 @@ export default function QueryToolbar( { query, setQuery } ) { const _categories = getEntityRecords( 'taxonomy', 'category' ); const _tags = getEntityRecords( 'taxonomy', 'post_tag' ); return { - categories: getTaxonomyInfo( _categories ), - tags: getTaxonomyInfo( _tags ), + categories: getTermsInfo( _categories ), + tags: getTermsInfo( _tags ), }; }, [] ); + + // Handles categories and tags changes. + const onTermsChange = ( terms, queryProperty ) => ( newTermNames ) => { + const termIds = newTermNames.map( + ( name ) => terms.mapByName[ name ]?.id + ); + if ( termIds.includes( undefined ) ) return; + setQuery( { [ queryProperty ]: termIds } ); + }; + const onCategoriesChange = onTermsChange( categories, 'categoryIds' ); + const onTagsChange = onTermsChange( tags, 'tagIds' ); + return ( name - ) } - onChange={ ( newCategoryNames ) => { - const categoryIds = newCategoryNames.map( - ( categoryName ) => - categories.mapByName[ categoryName ] - ?.id - ); - if ( categoryIds.includes( undefined ) ) - return; - setQuery( { categoryIds } ); - } } + suggestions={ categories.names } + onChange={ onCategoriesChange } /> ) } { tags?.terms && ( @@ -101,17 +102,8 @@ export default function QueryToolbar( { query, setQuery } ) { value: tags.mapById[ tagId ].name, } ) ) } - suggestions={ tags.terms.map( - ( { name } ) => name - ) } - onChange={ ( newTagNames ) => { - const tagIds = newTagNames.map( - ( tagName ) => - tags.mapByName[ tagName ]?.id - ); - if ( tagIds.includes( undefined ) ) return; - setQuery( { tagIds } ); - } } + suggestions={ tags.names } + onChange={ onTagsChange } /> ) } diff --git a/packages/block-library/src/query/test/fixtures/index.js b/packages/block-library/src/query/test/fixtures/index.js new file mode 100644 index 00000000000000..c285343bf3db6e --- /dev/null +++ b/packages/block-library/src/query/test/fixtures/index.js @@ -0,0 +1,21 @@ +export const terms = [ + { + count: 2, + id: 4, + meta: [], + name: 'nba', + parent: 0, + slug: 'nba', + taxonomy: 'category', + }, + { + count: 0, + id: 11, + link: 'http://localhost:8888/?tag=featured', + name: 'featured', + slug: 'featured', + taxonomy: 'post_tag', + }, +]; + +export default { terms }; diff --git a/packages/block-library/src/query/test/utils.js b/packages/block-library/src/query/test/utils.js new file mode 100644 index 00000000000000..c7acb4b6110bae --- /dev/null +++ b/packages/block-library/src/query/test/utils.js @@ -0,0 +1,30 @@ +/** + * Internal dependencies + */ +import { terms } from './fixtures'; +import { getTermsInfo } from '../utils'; + +describe( 'Query block utils', () => { + describe( 'getTermsInfo', () => { + it( 'should return an empty object when no terms provided', () => { + expect( getTermsInfo() ).toEqual( { terms: undefined } ); + } ); + it( 'should return proper terms info object', () => { + expect( getTermsInfo( terms ) ).toEqual( + expect.objectContaining( { + mapById: expect.objectContaining( { + '4': expect.objectContaining( { name: 'nba' } ), + '11': expect.objectContaining( { + name: 'featured', + } ), + } ), + mapByName: expect.objectContaining( { + nba: expect.objectContaining( { id: 4 } ), + featured: expect.objectContaining( { id: 11 } ), + } ), + names: expect.arrayContaining( [ 'nba', 'featured' ] ), + } ) + ); + } ); + } ); +} ); diff --git a/packages/block-library/src/query/utils.js b/packages/block-library/src/query/utils.js index a006225196cbc1..d865ecea8ec41c 100644 --- a/packages/block-library/src/query/utils.js +++ b/packages/block-library/src/query/utils.js @@ -1,17 +1,14 @@ // TODO jsdoc and tests -export const getTaxonomyInfo = ( terms ) => ( { +export const getTermsInfo = ( terms ) => ( { terms, ...terms?.reduce( - ( acc, term ) => ( { - mapById: { - ...acc.mapById, - [ term.id ]: term, - }, - mapByName: { - ...acc.mapByName, - [ term.name ]: term, - }, - } ), - { mapById: {}, mapByName: {} } + ( accumulator, term ) => { + const { mapById, mapByName, names } = accumulator; + mapById[ term.id ] = term; + mapByName[ term.name ] = term; + names.push( term.name ); + return accumulator; + }, + { mapById: {}, mapByName: {}, names: [] } ), } ); From 21e689d123ae5a2c57ab149db94cc37aaba38e07 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Thu, 3 Sep 2020 13:07:17 +0300 Subject: [PATCH 3/6] fetch more terms to show --- packages/block-library/src/query/constants.js | 5 +++++ packages/block-library/src/query/edit/query-toolbar.js | 10 ++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 packages/block-library/src/query/constants.js diff --git a/packages/block-library/src/query/constants.js b/packages/block-library/src/query/constants.js new file mode 100644 index 00000000000000..311232afe3adcc --- /dev/null +++ b/packages/block-library/src/query/constants.js @@ -0,0 +1,5 @@ +export const MAX_FETCHED_TERMS = 100; + +export default { + MAX_FETCHED_TERMS, +}; diff --git a/packages/block-library/src/query/edit/query-toolbar.js b/packages/block-library/src/query/edit/query-toolbar.js index 7bd16afb99ad0d..6e57271402a62c 100644 --- a/packages/block-library/src/query/edit/query-toolbar.js +++ b/packages/block-library/src/query/edit/query-toolbar.js @@ -16,12 +16,18 @@ import { postList } from '@wordpress/icons'; * Internal dependencies */ import { getTermsInfo } from '../utils'; +import { MAX_FETCHED_TERMS } from '../constants'; export default function QueryToolbar( { query, setQuery } ) { const { categories, tags } = useSelect( ( select ) => { const { getEntityRecords } = select( 'core' ); - const _categories = getEntityRecords( 'taxonomy', 'category' ); - const _tags = getEntityRecords( 'taxonomy', 'post_tag' ); + const termsQuery = { per_page: MAX_FETCHED_TERMS }; + const _categories = getEntityRecords( + 'taxonomy', + 'category', + termsQuery + ); + const _tags = getEntityRecords( 'taxonomy', 'post_tag', termsQuery ); return { categories: getTermsInfo( _categories ), tags: getTermsInfo( _tags ), From 771fbaa48cf19eaf216ec0c2f7e1263071db8cfd Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Thu, 3 Sep 2020 13:44:33 +0300 Subject: [PATCH 4/6] add typedefs and jsdoc at getTermsInfo --- packages/block-library/src/query/utils.js | 35 ++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/query/utils.js b/packages/block-library/src/query/utils.js index d865ecea8ec41c..2e55a6b9365ced 100644 --- a/packages/block-library/src/query/utils.js +++ b/packages/block-library/src/query/utils.js @@ -1,4 +1,37 @@ -// TODO jsdoc and tests +/** + * WordPress term object from REST API. + * Categories ref: https://developer.wordpress.org/rest-api/reference/categories/ + * Tags ref: https://developer.wordpress.org/rest-api/reference/tags/ + * + * @typedef {Object} WPTerm + * @property {number} id Unique identifier for the term. + * @property {number} count Number of published posts for the term. + * @property {string} description HTML description of the term. + * @property {string} link URL of the term. + * @property {string} name HTML title for the term. + * @property {string} slug An alphanumeric identifier for the term unique to its type. + * @property {string} taxonomy Type attribution for the term. + * @property {Object} meta Meta fields + * @property {number} [parent] The parent term ID. + */ + +/** + * The object used in Query block that contains info and helper mappings + * from an array of WPTerm. + * + * @typedef {Object} QueryTermsInfo + * @property {WPTerm[]} terms The array of terms. + * @property {Object} mapById Object mapping with the term id as key and the term as value. + * @property {Object} mapByName Object mapping with the term name as key and the term as value. + * @property {string[]} names Array with the terms' names. + */ + +/** + * Returns a helper object with mapping from WPTerms. + * + * @param {WPTerm[]} terms The terms to extract of helper object. + * @return {QueryTermsInfo} The object with the terms information. + */ export const getTermsInfo = ( terms ) => ( { terms, ...terms?.reduce( From d440472a3bd63cf5731b67702cf0fd821bcf5c05 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Thu, 3 Sep 2020 15:38:49 +0300 Subject: [PATCH 5/6] fix add multiple terms --- .../block-library/src/query/edit/query-toolbar.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/block-library/src/query/edit/query-toolbar.js b/packages/block-library/src/query/edit/query-toolbar.js index 6e57271402a62c..d62a4a10b21106 100644 --- a/packages/block-library/src/query/edit/query-toolbar.js +++ b/packages/block-library/src/query/edit/query-toolbar.js @@ -35,11 +35,12 @@ export default function QueryToolbar( { query, setQuery } ) { }, [] ); // Handles categories and tags changes. - const onTermsChange = ( terms, queryProperty ) => ( newTermNames ) => { - const termIds = newTermNames.map( - ( name ) => terms.mapByName[ name ]?.id - ); - if ( termIds.includes( undefined ) ) return; + const onTermsChange = ( terms, queryProperty ) => ( newTermValues ) => { + const termIds = newTermValues.reduce( ( accumulator, termValue ) => { + const termId = termValue?.id || terms.mapByName[ termValue ]?.id; + if ( termId ) accumulator.push( termId ); + return accumulator; + }, [] ); setQuery( { [ queryProperty ]: termIds } ); }; const onCategoriesChange = onTermsChange( categories, 'categoryIds' ); From 8767e6c9161f8eea8d03d06ac8a4447fe913ed09 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Mon, 7 Sep 2020 11:45:02 +0300 Subject: [PATCH 6/6] set $query properly --- lib/compat.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/compat.php b/lib/compat.php index 7325d5c493b8e6..ee8676f11962b1 100644 --- a/lib/compat.php +++ b/lib/compat.php @@ -419,7 +419,11 @@ function gutenberg_render_block_with_assigned_block_context( $pre_render, $parse } if ( isset( $wp_query->tax_query->queried_terms['post_tag'] ) ) { - $context['query'] = array( 'tagIds' => array() ); + if ( isset( $context['query'] ) ) { + $context['query']['tagIds'] = array(); + } else { + $context['query'] = array( 'tagIds' => array() ); + } foreach ( $wp_query->tax_query->queried_terms['post_tag']['terms'] as $tag_slug_or_id ) { $tag_ID = $tag_slug_or_id;