Skip to content

Commit

Permalink
Add Custom Post Types support in Query block (#25903)
Browse files Browse the repository at this point in the history
* Add Custom Post Types support in Query block

* exclude current entity from results properly

* add comment about the single useEffect for changing query property(object)

* remove pagination from default template

* minor changes
  • Loading branch information
ntsekouras authored Oct 8, 2020
1 parent ed07732 commit c1390e0
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 38 deletions.
9 changes: 8 additions & 1 deletion packages/block-library/src/query-loop/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@ export default function QueryLoopEdit( {
perPage,
offset,
categoryIds,
postType,
tagIds = [],
order,
orderBy,
author,
search,
exclude,
} = {},
queryContext,
},
Expand All @@ -57,10 +59,13 @@ export default function QueryLoopEdit( {
if ( search ) {
query.search = search;
}
if ( exclude?.length ) {
query.exclude = exclude;
}
return {
posts: select( 'core' ).getEntityRecords(
'postType',
'post',
postType,
query
),
blocks: select( 'core/block-editor' ).getBlocks( clientId ),
Expand All @@ -77,6 +82,8 @@ export default function QueryLoopEdit( {
clientId,
author,
search,
postType,
exclude,
]
);

Expand Down
6 changes: 6 additions & 0 deletions packages/block-library/src/query-loop/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ function render_block_core_query_loop( $attributes, $content, $block ) {
);

if ( isset( $block->context['query'] ) ) {
if ( isset( $block->context['query']['postType'] ) ) {
$query['post_type'] = $block->context['query']['postType'];
}
if ( isset( $block->context['query']['exclude'] ) ) {
$query['post__not_in'] = $block->context['query']['exclude'];
}
if ( isset( $block->context['query']['perPage'] ) ) {
$query['offset'] = ( $block->context['query']['perPage'] * ( $page - 1 ) ) + $block->context['query']['offset'];
}
Expand Down
7 changes: 6 additions & 1 deletion packages/block-library/src/query/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,24 @@
"perPage": null,
"pages": 1,
"offset": 0,
"postType": "post",
"categoryIds": [],
"tagIds": [],
"order": "desc",
"orderBy": "date",
"author": "",
"search": ""
"search": "",
"exclude": []
}
}
},
"providesContext": {
"queryId": "queryId",
"query": "query"
},
"usesContext": [
"postId"
],
"supports": {
"html": false
}
Expand Down
17 changes: 14 additions & 3 deletions packages/block-library/src/query/edit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ import QueryProvider from './query-provider';
import QueryInspectorControls from './query-inspector-controls';
import { DEFAULTS_POSTS_PER_PAGE } from '../constants';

const TEMPLATE = [ [ 'core/query-loop' ], [ 'core/query-pagination' ] ];
const TEMPLATE = [ [ 'core/query-loop' ] ];
export default function QueryEdit( {
attributes: { queryId, query },
context: { postId },
setAttributes,
} ) {
const instanceId = useInstanceId( QueryEdit );
Expand All @@ -32,11 +33,21 @@ export default function QueryEdit( {
+getSettings().postsPerPage || DEFAULTS_POSTS_PER_PAGE,
};
}, [] );
// Changes in query property (which is an object) need to be in the same callback,
// because updates are batched after the render and changes in different query properties
// would cause to overide previous wanted changes.
useEffect( () => {
const newQuery = {};
if ( postId && ! query.exclude?.length ) {
newQuery.exclude = [ postId ];
}
if ( ! query.perPage && postsPerPage ) {
updateQuery( { perPage: postsPerPage } );
newQuery.perPage = postsPerPage;
}
if ( Object.keys( newQuery ).length ) {
updateQuery( newQuery );
}
}, [ query.perPage ] );
}, [ query.perPage, query.exclude, postId ] );
// We need this for multi-query block pagination.
// Query parameters for each block are scoped to their ID.
useEffect( () => {
Expand Down
118 changes: 86 additions & 32 deletions packages/block-library/src/query/edit/query-inspector-controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ import {
QueryControls,
TextControl,
FormTokenField,
SelectControl,
} 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 { useEffect, useState, useCallback, useMemo } from '@wordpress/element';

/**
* Internal dependencies
Expand All @@ -25,23 +26,70 @@ import { getTermsInfo } from '../utils';
import { MAX_FETCHED_TERMS } from '../constants';

export default function QueryInspectorControls( { query, setQuery } ) {
const { order, orderBy, author: selectedAuthorId } = query;
const { authorList, 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 ),
authorList: getEntityRecords( 'root', 'user', { per_page: -1 } ),
};
}, [] );

const { order, orderBy, author: selectedAuthorId, postType } = query;
const [ showCategories, setShowCategories ] = useState( true );
const [ showTags, setShowTags ] = useState( true );
const { authorList, categories, tags, postTypes } = useSelect(
( select ) => {
const { getEntityRecords, getPostTypes } = select( 'core' );
const termsQuery = { per_page: MAX_FETCHED_TERMS };
const _categories = getEntityRecords(
'taxonomy',
'category',
termsQuery
);
const _tags = getEntityRecords(
'taxonomy',
'post_tag',
termsQuery
);
const excludedPostTypes = [ 'attachment' ];
const filteredPostTypes = getPostTypes()?.filter(
( { viewable, slug } ) =>
viewable && ! excludedPostTypes.includes( slug )
);
return {
categories: getTermsInfo( _categories ),
tags: getTermsInfo( _tags ),
authorList: getEntityRecords( 'root', 'user', {
per_page: -1,
} ),
postTypes: filteredPostTypes,
};
},
[]
);
const postTypesTaxonomiesMap = useMemo( () => {
if ( ! postTypes?.length ) return;
return postTypes.reduce( ( accumulator, type ) => {
accumulator[ type.slug ] = type.taxonomies;
return accumulator;
}, {} );
}, [ postTypes ] );
useEffect( () => {
if ( ! postTypesTaxonomiesMap ) return;
const postTypeTaxonomies = postTypesTaxonomiesMap[ postType ];
setShowCategories( postTypeTaxonomies.includes( 'category' ) );
setShowTags( postTypeTaxonomies.includes( 'post_tag' ) );
}, [ postType, postTypesTaxonomiesMap ] );
const postTypesSelectOptions = useMemo(
() =>
( postTypes || [] ).map( ( { labels, slug } ) => ( {
label: labels.singular_name,
value: slug,
} ) ),
[ postTypes ]
);
const onPostTypeChange = ( newValue ) => {
const updateQuery = { postType: newValue };
if ( ! postTypesTaxonomiesMap[ newValue ].includes( 'category' ) ) {
updateQuery.categoryIds = [];
}
if ( ! postTypesTaxonomiesMap[ newValue ].includes( 'post_tag' ) ) {
updateQuery.tagIds = [];
}
setQuery( updateQuery );
};
// Handles categories and tags changes.
const onTermsChange = ( terms, queryProperty ) => ( newTermValues ) => {
const termIds = newTermValues.reduce( ( accumulator, termValue ) => {
Expand All @@ -65,20 +113,14 @@ export default function QueryInspectorControls( { query, setQuery } ) {
}, [ querySearch, onChangeDebounced ] );
return (
<InspectorControls>
<PanelBody title={ __( 'Sorting and filtering' ) }>
<QueryControls
{ ...{ order, orderBy, selectedAuthorId, authorList } }
onOrderChange={ ( value ) => setQuery( { order: value } ) }
onOrderByChange={ ( value ) =>
setQuery( { orderBy: value } )
}
onAuthorChange={ ( value ) =>
setQuery( {
author: value !== '' ? +value : undefined,
} )
}
<PanelBody title={ __( 'Filtering and Sorting' ) }>
<SelectControl
options={ postTypesSelectOptions }
value={ postType }
label={ __( 'Post Type' ) }
onChange={ onPostTypeChange }
/>
{ categories?.terms?.length > 0 && (
{ showCategories && categories?.terms?.length > 0 && (
<FormTokenField
label={ __( 'Categories' ) }
value={ ( query.categoryIds || [] ).map(
Expand All @@ -91,7 +133,7 @@ export default function QueryInspectorControls( { query, setQuery } ) {
onChange={ onCategoriesChange }
/>
) }
{ tags?.terms?.length > 0 && (
{ showTags && tags?.terms?.length > 0 && (
<FormTokenField
label={ __( 'Tags' ) }
value={ ( query.tagIds || [] ).map( ( tagId ) => ( {
Expand All @@ -102,6 +144,18 @@ export default function QueryInspectorControls( { query, setQuery } ) {
onChange={ onTagsChange }
/>
) }
<QueryControls
{ ...{ order, orderBy, selectedAuthorId, authorList } }
onOrderChange={ ( value ) => setQuery( { order: value } ) }
onOrderByChange={ ( value ) =>
setQuery( { orderBy: value } )
}
onAuthorChange={ ( value ) =>
setQuery( {
author: value !== '' ? +value : undefined,
} )
}
/>
<TextControl
label={ __( 'Search' ) }
value={ querySearch }
Expand Down
4 changes: 3 additions & 1 deletion packages/e2e-tests/fixtures/blocks/core__query.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
"perPage": null,
"pages": 1,
"offset": 0,
"postType": "post",
"categoryIds": [],
"tagIds": [],
"order": "desc",
"orderBy": "date",
"author": "",
"search": ""
"search": "",
"exclude": []
}
},
"innerBlocks": [],
Expand Down

0 comments on commit c1390e0

Please sign in to comment.