Skip to content

Commit

Permalink
Categories List block: Add dropdown for taxonomies (WordPress#65272)
Browse files Browse the repository at this point in the history
Add a new `taxonomy` attribute to the Categories List block, and a dropdown to the block inspector to set that attribute. For backwards compatibility, the attribute defaults to `category`. Furthermore, rename the block to "Terms List".

Unlinked contributors: MikeB8s, sophiegyo.

Co-authored-by: ockham <[email protected]>
Co-authored-by: fabiankaegy <[email protected]>
Co-authored-by: gziolo <[email protected]>
Co-authored-by: Julianoe <[email protected]>
Co-authored-by: celloexpressions <[email protected]>
Co-authored-by: skorasaurus <[email protected]>
Co-authored-by: ms-studio <[email protected]>
Co-authored-by: ndiego <[email protected]>
Co-authored-by: justintadlock <[email protected]>
Co-authored-by: swissspidy <[email protected]>
Co-authored-by: joedolson <[email protected]>
Co-authored-by: coreyworrell <[email protected]>
Co-authored-by: jasmussen <[email protected]>
  • Loading branch information
14 people authored Sep 17, 2024
1 parent 6722990 commit 7f9c340
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 44 deletions.
6 changes: 3 additions & 3 deletions docs/reference-guides/core-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,14 @@ A calendar of your site’s posts. ([Source](https://github.com/WordPress/gutenb
- **Supports:** align, color (background, link, text), interactivity (clientNavigation), typography (fontSize, lineHeight)
- **Attributes:** month, year

## Categories List
## Terms List

Display a list of all categories. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/categories))
Display a list of all terms of a given taxonomy. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/categories))

- **Name:** core/categories
- **Category:** widgets
- **Supports:** align, interactivity (clientNavigation), spacing (margin, padding), typography (fontSize, lineHeight), ~~html~~
- **Attributes:** displayAsDropdown, label, showEmpty, showHierarchy, showLabel, showOnlyTopLevel, showPostCounts
- **Attributes:** displayAsDropdown, label, showEmpty, showHierarchy, showLabel, showOnlyTopLevel, showPostCounts, taxonomy

## Code

Expand Down
9 changes: 7 additions & 2 deletions packages/block-library/src/categories/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "core/categories",
"title": "Categories List",
"title": "Terms List",
"category": "widgets",
"description": "Display a list of all categories.",
"description": "Display a list of all terms of a given taxonomy.",
"keywords": [ "categories" ],
"textdomain": "default",
"attributes": {
"taxonomy": {
"type": "string",
"default": "category"
},
"displayAsDropdown": {
"type": "boolean",
"default": false
Expand Down
97 changes: 67 additions & 30 deletions packages/block-library/src/categories/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import clsx from 'clsx';
import {
PanelBody,
Placeholder,
SelectControl,
Spinner,
ToggleControl,
VisuallyHidden,
Expand All @@ -20,7 +21,7 @@ import {
RichText,
} from '@wordpress/block-editor';
import { decodeEntities } from '@wordpress/html-entities';
import { __ } from '@wordpress/i18n';
import { __, sprintf } from '@wordpress/i18n';
import { pin } from '@wordpress/icons';
import { useEntityRecords } from '@wordpress/core-data';

Expand All @@ -33,19 +34,33 @@ export default function CategoriesEdit( {
showEmpty,
label,
showLabel,
taxonomy: taxonomySlug,
},
setAttributes,
className,
} ) {
const selectId = useInstanceId( CategoriesEdit, 'blocks-category-select' );

const { records: allTaxonomies, isResolvingTaxonomies } = useEntityRecords(
'root',
'taxonomy'
);

const taxonomies = allTaxonomies?.filter( ( t ) => t.visibility.public );

const taxonomy = taxonomies?.find( ( t ) => t.slug === taxonomySlug );

const isHierarchicalTaxonomy =
! isResolvingTaxonomies && taxonomy?.hierarchical;

const query = { per_page: -1, hide_empty: ! showEmpty, context: 'view' };
if ( showOnlyTopLevel ) {
if ( isHierarchicalTaxonomy && showOnlyTopLevel ) {
query.parent = 0;
}

const { records: categories, isResolving } = useEntityRecords(
'taxonomy',
'category',
taxonomySlug,
query
);

Expand All @@ -66,7 +81,7 @@ export default function CategoriesEdit( {
! name ? __( '(Untitled)' ) : decodeEntities( name ).trim();

const renderCategoryList = () => {
const parentId = showHierarchy ? 0 : null;
const parentId = isHierarchicalTaxonomy && showHierarchy ? 0 : null;
const categoriesList = getCategoriesList( parentId );
return categoriesList.map( ( category ) =>
renderCategoryListItem( category )
Expand All @@ -82,27 +97,29 @@ export default function CategoriesEdit( {
{ renderCategoryName( name ) }
</a>
{ showPostCounts && ` (${ count })` }
{ showHierarchy && !! childCategories.length && (
<ul className="children">
{ childCategories.map( ( childCategory ) =>
renderCategoryListItem( childCategory )
) }
</ul>
) }
{ isHierarchicalTaxonomy &&
showHierarchy &&
!! childCategories.length && (
<ul className="children">
{ childCategories.map( ( childCategory ) =>
renderCategoryListItem( childCategory )
) }
</ul>
) }
</li>
);
};

const renderCategoryDropdown = () => {
const parentId = showHierarchy ? 0 : null;
const parentId = isHierarchicalTaxonomy && showHierarchy ? 0 : null;
const categoriesList = getCategoriesList( parentId );
return (
<>
{ showLabel ? (
<RichText
className="wp-block-categories__label"
aria-label={ __( 'Label text' ) }
placeholder={ __( 'Categories' ) }
placeholder={ taxonomy.name }
withoutInteractiveFormatting
value={ label }
onChange={ ( html ) =>
Expand All @@ -111,11 +128,17 @@ export default function CategoriesEdit( {
/>
) : (
<VisuallyHidden as="label" htmlFor={ selectId }>
{ label ? label : __( 'Categories' ) }
{ label ? label : taxonomy.name }
</VisuallyHidden>
) }
<select id={ selectId }>
<option>{ __( 'Select Category' ) }</option>
<option>
{ sprintf(
/* translators: %s: taxonomy's singular name */
__( 'Select %s' ),
taxonomy.labels.singular_name
) }
</option>
{ categoriesList.map( ( category ) =>
renderCategoryDropdownItem( category, 0 )
) }
Expand All @@ -133,7 +156,8 @@ export default function CategoriesEdit( {
{ renderCategoryName( name ) }
{ showPostCounts && ` (${ count })` }
</option>,
showHierarchy &&
isHierarchicalTaxonomy &&
showHierarchy &&
!! childCategories.length &&
childCategories.map( ( childCategory ) =>
renderCategoryDropdownItem( childCategory, level + 1 )
Expand Down Expand Up @@ -161,6 +185,21 @@ export default function CategoriesEdit( {
<TagName { ...blockProps }>
<InspectorControls>
<PanelBody title={ __( 'Settings' ) }>
{ Array.isArray( taxonomies ) && (
<SelectControl
__nextHasNoMarginBottom
__next40pxDefaultSize
label={ __( 'Taxonomy' ) }
options={ taxonomies.map( ( t ) => ( {
label: t.name,
value: t.slug,
} ) ) }
value={ taxonomySlug }
onChange={ ( selectedTaxonomy ) =>
setAttributes( { taxonomy: selectedTaxonomy } )
}
/>
) }
<ToggleControl
__nextHasNoMarginBottom
label={ __( 'Display as dropdown' ) }
Expand All @@ -182,19 +221,21 @@ export default function CategoriesEdit( {
checked={ showPostCounts }
onChange={ toggleAttribute( 'showPostCounts' ) }
/>
{ isHierarchicalTaxonomy && (
<ToggleControl
__nextHasNoMarginBottom
label={ __( 'Show only top level terms' ) }
checked={ showOnlyTopLevel }
onChange={ toggleAttribute( 'showOnlyTopLevel' ) }
/>
) }
<ToggleControl
__nextHasNoMarginBottom
label={ __( 'Show only top level categories' ) }
checked={ showOnlyTopLevel }
onChange={ toggleAttribute( 'showOnlyTopLevel' ) }
/>
<ToggleControl
__nextHasNoMarginBottom
label={ __( 'Show empty categories' ) }
label={ __( 'Show empty terms' ) }
checked={ showEmpty }
onChange={ toggleAttribute( 'showEmpty' ) }
/>
{ ! showOnlyTopLevel && (
{ isHierarchicalTaxonomy && ! showOnlyTopLevel && (
<ToggleControl
__nextHasNoMarginBottom
label={ __( 'Show hierarchy' ) }
Expand All @@ -205,16 +246,12 @@ export default function CategoriesEdit( {
</PanelBody>
</InspectorControls>
{ isResolving && (
<Placeholder icon={ pin } label={ __( 'Categories' ) }>
<Placeholder icon={ pin } label={ __( 'Terms' ) }>
<Spinner />
</Placeholder>
) }
{ ! isResolving && categories?.length === 0 && (
<p>
{ __(
'Your site does not have any posts, so there is nothing to display here at the moment.'
) }
</p>
<p>{ taxonomy.labels.no_terms }</p>
) }
{ ! isResolving &&
categories?.length > 0 &&
Expand Down
30 changes: 21 additions & 9 deletions packages/block-library/src/categories/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ function render_block_core_categories( $attributes, $content, $block ) {
static $block_id = 0;
++$block_id;

$taxonomy = get_taxonomy( $attributes['taxonomy'] );

$args = array(
'echo' => false,
'hierarchical' => ! empty( $attributes['showHierarchy'] ),
'orderby' => 'name',
'show_count' => ! empty( $attributes['showPostCounts'] ),
'taxonomy' => $attributes['taxonomy'],
'title_li' => '',
'hide_empty' => empty( $attributes['showEmpty'] ),
);
Expand All @@ -36,13 +39,20 @@ function render_block_core_categories( $attributes, $content, $block ) {
if ( ! empty( $attributes['displayAsDropdown'] ) ) {
$id = 'wp-block-categories-' . $block_id;
$args['id'] = $id;
$args['show_option_none'] = __( 'Select Category' );
$show_label = empty( $attributes['showLabel'] ) ? ' screen-reader-text' : '';
$default_label = __( 'Categories' );
$label_text = ! empty( $attributes['label'] ) ? $attributes['label'] : $default_label;
$wrapper_markup = '<div %1$s><label class="wp-block-categories__label' . $show_label . '" for="' . esc_attr( $id ) . '">' . $label_text . '</label>%2$s</div>';
$items_markup = wp_dropdown_categories( $args );
$type = 'dropdown';
$args['name'] = $taxonomy->query_var;
$args['value_field'] = 'slug';
$args['show_option_none'] = sprintf(
/* translators: %s: taxonomy's singular name */
__( 'Select %s' ),
$taxonomy->labels->singular_name
);

$show_label = empty( $attributes['showLabel'] ) ? ' screen-reader-text' : '';
$default_label = $taxonomy->label;
$label_text = ! empty( $attributes['label'] ) ? $attributes['label'] : $default_label;
$wrapper_markup = '<div %1$s><label class="wp-block-categories__label' . $show_label . '" for="' . esc_attr( $id ) . '">' . $label_text . '</label>%2$s</div>';
$items_markup = wp_dropdown_categories( $args );
$type = 'dropdown';

if ( ! is_admin() ) {
// Inject the dropdown script immediately after the select dropdown.
Expand All @@ -54,6 +64,8 @@ function render_block_core_categories( $attributes, $content, $block ) {
);
}
} else {
$args['show_option_none'] = $taxonomy->labels->no_terms;

$wrapper_markup = '<ul %1$s>%2$s</ul>';
$items_markup = wp_list_categories( $args );
$type = 'list';
Expand Down Expand Up @@ -92,8 +104,8 @@ function build_dropdown_script_block_core_categories( $dropdown_id ) {
( function() {
var dropdown = document.getElementById( '<?php echo esc_js( $dropdown_id ); ?>' );
function onCatChange() {
if ( dropdown.options[ dropdown.selectedIndex ].value > 0 ) {
location.href = "<?php echo esc_url( home_url() ); ?>/?cat=" + dropdown.options[ dropdown.selectedIndex ].value;
if ( dropdown.options[ dropdown.selectedIndex ].value !== -1 ) {
location.href = "<?php echo esc_url( home_url() ); ?>/?" + dropdown.name + '=' + dropdown.options[ dropdown.selectedIndex ].value;
}
}
dropdown.onchange = onCatChange;
Expand Down
1 change: 1 addition & 0 deletions test/integration/fixtures/blocks/core__categories.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"name": "core/categories",
"isValid": true,
"attributes": {
"taxonomy": "category",
"displayAsDropdown": false,
"showHierarchy": false,
"showPostCounts": false,
Expand Down

0 comments on commit 7f9c340

Please sign in to comment.