Skip to content

Commit

Permalink
Post Hierarchical Terms Block (WordPress#24091)
Browse files Browse the repository at this point in the history
Add a new Post Hierarchical Terms Block block with a single variation that displays the current post's categories, if any, in a list of links separated by a vertical bar.

The block already supports: text, background, link colors; font size, line height, and text alignment.
  • Loading branch information
Copons authored Aug 26, 2020
1 parent a36b3dd commit 132a01c
Show file tree
Hide file tree
Showing 12 changed files with 364 additions and 19 deletions.
39 changes: 20 additions & 19 deletions lib/blocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,25 +73,26 @@ function gutenberg_reregister_core_block_types() {
$block_names = array_merge(
$block_names,
array(
'post-author.php' => 'core/post-author',
'post-comment.php' => 'core/post-comment',
'post-comment-content.php' => 'core/post-comment-content',
'post-comments.php' => 'core/post-comments',
'post-comments-count.php' => 'core/post-comments-count',
'post-comments-form.php' => 'core/post-comments-form',
'post-content.php' => 'core/post-content',
'post-date.php' => 'core/post-date',
'post-excerpt.php' => 'core/post-excerpt',
'post-featured-image.php' => 'core/post-featured-image',
'post-tags.php' => 'core/post-tags',
'post-title.php' => 'core/post-title',
'query.php' => 'core/query',
'query-loop.php' => 'core/query-loop',
'query-pagination.php' => 'core/query-pagination',
'site-logo.php' => 'core/site-logo',
'site-tagline.php' => 'core/site-tagline',
'site-title.php' => 'core/site-title',
'template-part.php' => 'core/template-part',
'post-author.php' => 'core/post-author',
'post-comment.php' => 'core/post-comment',
'post-comment-content.php' => 'core/post-comment-content',
'post-comments.php' => 'core/post-comments',
'post-comments-count.php' => 'core/post-comments-count',
'post-comments-form.php' => 'core/post-comments-form',
'post-content.php' => 'core/post-content',
'post-date.php' => 'core/post-date',
'post-excerpt.php' => 'core/post-excerpt',
'post-featured-image.php' => 'core/post-featured-image',
'post-hierarchical-terms.php' => 'core/post-hierarchical-terms',
'post-tags.php' => 'core/post-tags',
'post-title.php' => 'core/post-title',
'query.php' => 'core/query',
'query-loop.php' => 'core/query-loop',
'query-pagination.php' => 'core/query-pagination',
'site-logo.php' => 'core/site-logo',
'site-tagline.php' => 'core/site-tagline',
'site-title.php' => 'core/site-title',
'template-part.php' => 'core/template-part',
)
);
}
Expand Down
2 changes: 2 additions & 0 deletions packages/block-library/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ import * as postCommentsForm from './post-comments-form';
import * as postDate from './post-date';
import * as postExcerpt from './post-excerpt';
import * as postFeaturedImage from './post-featured-image';
import * as postHierarchicalTerms from './post-hierarchical-terms';
import * as postTags from './post-tags';

/**
Expand Down Expand Up @@ -218,6 +219,7 @@ export const __experimentalRegisterExperimentalCoreBlocks =
postDate,
postExcerpt,
postFeaturedImage,
postHierarchicalTerms,
postTags,
]
: [] ),
Expand Down
26 changes: 26 additions & 0 deletions packages/block-library/src/post-hierarchical-terms/block.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "core/post-hierarchical-terms",
"category": "design",
"attributes": {
"term": {
"type": "string"
},
"textAlign": {
"type": "string"
}
},
"usesContext": [
"postId",
"postType"
],
"supports": {
"html": false,
"lightBlockWrapper": true,
"__experimentalFontSize": true,
"__experimentalColor": {
"gradients": true,
"linkColor": true
},
"__experimentalLineHeight": true
}
}
143 changes: 143 additions & 0 deletions packages/block-library/src/post-hierarchical-terms/edit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/**
* External dependencies
*/
import classnames from 'classnames';
import { find } from 'lodash';

/**
* WordPress dependencies
*/
import {
AlignmentToolbar,
BlockControls,
Warning,
__experimentalBlock as Block,
__experimentalBlockVariationPicker as BlockVariationPicker,
} from '@wordpress/block-editor';
import { Spinner } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import useHierarchicalTermLinks from './use-hierarchical-term-links';

export default function PostHierarchicalTermsEdit( {
attributes,
clientId,
context,
name,
setAttributes,
} ) {
const { term, textAlign } = attributes;
const { postId, postType } = context;

const { blockType, defaultVariation, variations } = useSelect(
( select ) => {
const {
getBlockVariations,
getBlockType,
getDefaultBlockVariation,
} = select( 'core/blocks' );

return {
blockType: getBlockType( name ),
defaultVariation: getDefaultBlockVariation( name, 'block' ),
variations: getBlockVariations( name, 'block' ),
};
},
[ clientId, name ]
);

const selectedTerm = useSelect(
( select ) => {
if ( ! term ) return {};
const taxonomies = select( 'core' ).getTaxonomies( {
per_page: -1,
} );
return (
find(
taxonomies,
( taxonomy ) =>
taxonomy.slug === term &&
taxonomy.hierarchical &&
taxonomy.visibility.show_ui
) || {}
);
},
[ term ]
);

const {
hierarchicalTermLinks,
isLoadingHierarchicalTermLinks,
} = useHierarchicalTermLinks( {
postId,
postType,
term: selectedTerm,
} );

const hasPost = postId && postType;
const hasHierarchicalTermLinks =
hierarchicalTermLinks && hierarchicalTermLinks.length > 0;

if ( ! hasPost ) {
return (
<Block.div>
<Warning>
{ __( 'Post Hierarchical Terms block: post not found.' ) }
</Warning>
</Block.div>
);
}

if ( ! term ) {
return (
<Block.div>
<BlockVariationPicker
icon={ blockType?.icon?.src }
label={ blockType?.title }
onSelect={ ( variation = defaultVariation ) => {
setAttributes( variation.attributes );
} }
variations={ variations }
/>
</Block.div>
);
}

return (
<>
<BlockControls>
<AlignmentToolbar
value={ textAlign }
onChange={ ( nextAlign ) => {
setAttributes( { textAlign: nextAlign } );
} }
/>
</BlockControls>
<Block.div
className={ classnames( {
[ `has-text-align-${ textAlign }` ]: textAlign,
} ) }
>
{ isLoadingHierarchicalTermLinks && <Spinner /> }

{ hasHierarchicalTermLinks &&
! isLoadingHierarchicalTermLinks &&
hierarchicalTermLinks.reduce( ( prev, curr ) => [
prev,
' | ',
curr,
] ) }

{ ! isLoadingHierarchicalTermLinks &&
! hasHierarchicalTermLinks &&
// eslint-disable-next-line camelcase
( selectedTerm?.labels?.no_terms ||
__( 'Term items not found.' ) ) }
</Block.div>
</>
);
}
20 changes: 20 additions & 0 deletions packages/block-library/src/post-hierarchical-terms/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import metadata from './block.json';
import edit from './edit';
import variations from './variations';

const { name } = metadata;
export { metadata, name };

export const settings = {
title: __( 'Post Hierarchical Terms' ),
variations,
edit,
};
56 changes: 56 additions & 0 deletions packages/block-library/src/post-hierarchical-terms/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php
/**
* Server-side rendering of the `core/post-hierarchical-terms` block.
*
* @package WordPress
*/

/**
* Renders the `core/post-hierarchical-terms` block on the server.
*
* @param array $attributes Block attributes.
* @param string $content Block default content.
* @param WP_Block $block Block instance.
* @return string Returns the filtered post hierarchical terms for the current post wrapped inside "a" tags.
*/
function render_block_core_post_hierarchical_terms( $attributes, $content, $block ) {
if ( ! isset( $block->context['postId'] ) || ! isset( $attributes['term'] ) ) {
return '';
}

$post_hierarchical_terms = get_the_terms( $block->context['postId'], $attributes['term'] );
if ( empty( $post_hierarchical_terms ) ) {
return '';
}

$align_class_name = empty( $attributes['textAlign'] ) ? '' : ' ' . "has-text-align-{$attributes['textAlign']}";

$terms_links = '';
foreach ( $post_hierarchical_terms as $term ) {
$terms_links .= sprintf(
'<a href="%1$s">%2$s</a> | ',
get_term_link( $term->term_id ),
esc_html( $term->name )
);
}
$terms_links = trim( $terms_links, ' | ' );

return sprintf(
'<div class="%1$s">%2$s</div>',
esc_attr( $align_class_name ),
$terms_links
);
}

/**
* Registers the `core/post-hierarchical-terms` block on the server.
*/
function register_block_core_post_hierarchical_terms() {
register_block_type_from_metadata(
__DIR__ . '/post-hierarchical-terms',
array(
'render_callback' => 'render_block_core_post_hierarchical_terms',
)
);
}
add_action( 'init', 'register_block_core_post_hierarchical_terms' );
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* External dependencies
*/
import { map } from 'lodash';

/**
* WordPress dependencies
*/
import { useEntityProp } from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';

export default function useHierarchicalTermLinks( { postId, postType, term } ) {
const { rest_base: restBase, slug } = term;

const [ hierarchicalTermItems ] = useEntityProp(
'postType',
postType,
restBase,
postId
);

const { hierarchicalTermLinks, isLoadingHierarchicalTermLinks } = useSelect(
( select ) => {
const { getEntityRecord } = select( 'core' );

let loaded = true;

const links = map( hierarchicalTermItems, ( itemId ) => {
const item = getEntityRecord( 'taxonomy', slug, itemId );

if ( ! item ) {
return ( loaded = false );
}

return (
<a key={ itemId } href={ item.link }>
{ item.name }
</a>
);
} );

return {
hierarchicalTermLinks: links,
isLoadingHierarchicalTermLinks: ! loaded,
};
},
[ hierarchicalTermItems ]
);

return { hierarchicalTermLinks, isLoadingHierarchicalTermLinks };
}
16 changes: 16 additions & 0 deletions packages/block-library/src/post-hierarchical-terms/variations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';

const variations = [
{
name: 'category',
title: __( 'Post Categories' ),
icon: 'category',
is_default: true,
attributes: { term: 'category' },
},
];

export default variations;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!-- wp:post-hierarchical-terms /-->
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[
{
"clientId": "_clientId_0",
"name": "core/post-hierarchical-terms",
"isValid": true,
"attributes": {},
"innerBlocks": [],
"originalContent": ""
}
]
Loading

0 comments on commit 132a01c

Please sign in to comment.