Skip to content

Commit

Permalink
Add tags support in Query block (#25005)
Browse files Browse the repository at this point in the history
* add tags support in Query block

* refactor + tests for getTermsInfo

* fetch more terms to show

* add typedefs and jsdoc at getTermsInfo

* fix add multiple terms

* set $query properly
  • Loading branch information
ntsekouras authored Sep 7, 2020
1 parent 6b95e0d commit 9ced21b
Show file tree
Hide file tree
Showing 11 changed files with 190 additions and 42 deletions.
21 changes: 21 additions & 0 deletions lib/compat.php
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,27 @@ function gutenberg_render_block_with_assigned_block_context( $pre_render, $parse
}
}

if ( isset( $wp_query->tax_query->queried_terms['post_tag'] ) ) {
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;

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.
*
Expand Down
12 changes: 10 additions & 2 deletions packages/block-library/src/query-loop/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
} ) {
Expand All @@ -31,6 +38,7 @@ export default function QueryLoopEdit( {
const query = {
offset: perPage ? perPage * ( page - 1 ) + offset : 0,
categories: categoryIds,
tags: tagIds,
order,
orderby: orderBy,
};
Expand All @@ -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(
Expand Down
4 changes: 4 additions & 0 deletions packages/block-library/src/query-loop/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -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'] );
}
Expand All @@ -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 = '';
Expand Down
1 change: 1 addition & 0 deletions packages/block-library/src/query/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"pages": 1,
"offset": 0,
"categoryIds": [],
"tagIds": [],
"order": "desc",
"orderBy": "date"
}
Expand Down
5 changes: 5 additions & 0 deletions packages/block-library/src/query/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const MAX_FETCHED_TERMS = 100;

export default {
MAX_FETCHED_TERMS,
};
88 changes: 49 additions & 39 deletions packages/block-library/src/query/edit/query-toolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,40 @@ import {
import { __ } from '@wordpress/i18n';
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, 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 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 ),
};
}, [] );

// Handles categories and tags changes.
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' );
const onTagsChange = onTermsChange( tags, 'tagIds' );

return (
<Toolbar>
<Dropdown
Expand Down Expand Up @@ -77,30 +85,32 @@ export default function QueryToolbar( { query, setQuery } ) {
setQuery( { offset: value ?? 0 } )
}
/>
{ categories && (
{ categories?.terms && (
<FormTokenField
label={ __( 'Categories' ) }
value={ query.categoryIds.map(
( categoryId ) => ( {
id: categoryId,
value:
categoriesMapById[ categoryId ]
categories.mapById[ categoryId ]
.name,
} )
) }
suggestions={ categories.map(
( category ) => category.name
suggestions={ categories.names }
onChange={ onCategoriesChange }
/>
) }
{ tags?.terms && (
<FormTokenField
label={ __( 'Tags' ) }
value={ ( query.tagIds || [] ).map(
( tagId ) => ( {
id: tagId,
value: tags.mapById[ tagId ].name,
} )
) }
onChange={ ( newCategoryNames ) => {
const categoryIds = newCategoryNames.map(
( categoryName ) =>
categoriesMapByName[ categoryName ]
?.id
);
if ( categoryIds.includes( undefined ) )
return;
setQuery( { categoryIds } );
} }
suggestions={ tags.names }
onChange={ onTagsChange }
/>
) }
</>
Expand Down
21 changes: 21 additions & 0 deletions packages/block-library/src/query/test/fixtures/index.js
Original file line number Diff line number Diff line change
@@ -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 };
30 changes: 30 additions & 0 deletions packages/block-library/src/query/test/utils.js
Original file line number Diff line number Diff line change
@@ -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' ] ),
} )
);
} );
} );
} );
47 changes: 47 additions & 0 deletions packages/block-library/src/query/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* 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<string, WPTerm>} mapById Object mapping with the term id as key and the term as value.
* @property {Object<string, WPTerm>} 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(
( accumulator, term ) => {
const { mapById, mapByName, names } = accumulator;
mapById[ term.id ] = term;
mapByName[ term.name ] = term;
names.push( term.name );
return accumulator;
},
{ mapById: {}, mapByName: {}, names: [] }
),
} );
1 change: 1 addition & 0 deletions packages/e2e-tests/fixtures/blocks/core__query.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"pages": 1,
"offset": 0,
"categoryIds": [],
"tagIds": [],
"order": "desc",
"orderBy": "date"
}
Expand Down
2 changes: 1 addition & 1 deletion packages/edit-site/src/components/editor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 ) =>
Expand Down

0 comments on commit 9ced21b

Please sign in to comment.