From 06f27ddf7399126499ce8873c12e87025600cf8c Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Sun, 18 Sep 2022 12:21:33 +0900 Subject: [PATCH] Add new "Post Time To Read" block --- docs/reference-guides/core-blocks.md | 9 ++ lib/blocks.php | 1 + packages/block-library/package.json | 2 + packages/block-library/src/index.js | 2 + .../src/post-time-to-read/block.json | 21 ++++ .../src/post-time-to-read/edit.js | 96 +++++++++++++++++++ .../src/post-time-to-read/icon.js | 15 +++ .../src/post-time-to-read/index.js | 17 ++++ .../src/post-time-to-read/index.php | 57 +++++++++++ 9 files changed, 220 insertions(+) create mode 100644 packages/block-library/src/post-time-to-read/block.json create mode 100644 packages/block-library/src/post-time-to-read/edit.js create mode 100644 packages/block-library/src/post-time-to-read/icon.js create mode 100644 packages/block-library/src/post-time-to-read/index.js create mode 100644 packages/block-library/src/post-time-to-read/index.php diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index 87d57f14f0872..ba0a8eceafa26 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -575,6 +575,15 @@ Post terms. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages - **Supports:** color (background, gradients, link, text), typography (fontSize, lineHeight), ~~html~~ - **Attributes:** prefix, separator, suffix, term, textAlign +## Post Time To Read + +Time to read the post. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/post-time-to-read)) + +- **Name:** core/post-time-to-read +- **Category:** theme +- **Supports:** ~~html~~ +- **Attributes:** minutesToRead, textAlign + ## Post Title Displays the title of a post, page, or any other content-type. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/post-title)) diff --git a/lib/blocks.php b/lib/blocks.php index 842ff6a6ec093..8aa5dbe712487 100644 --- a/lib/blocks.php +++ b/lib/blocks.php @@ -89,6 +89,7 @@ function gutenberg_reregister_core_block_types() { 'post-featured-image.php' => 'core/post-featured-image', 'post-navigation-link.php' => 'core/post-navigation-link', 'post-terms.php' => 'core/post-terms', + 'post-time-to-read.php' => 'core/post-time-to-read', 'post-title.php' => 'core/post-title', 'query.php' => 'core/query', 'post-template.php' => 'core/post-template', diff --git a/packages/block-library/package.json b/packages/block-library/package.json index a09436c899382..504888b4a7b6d 100644 --- a/packages/block-library/package.json +++ b/packages/block-library/package.json @@ -44,6 +44,7 @@ "@wordpress/date": "file:../date", "@wordpress/deprecated": "file:../deprecated", "@wordpress/dom": "file:../dom", + "@wordpress/editor": "file:../editor", "@wordpress/element": "file:../element", "@wordpress/hooks": "file:../hooks", "@wordpress/html-entities": "file:../html-entities", @@ -57,6 +58,7 @@ "@wordpress/server-side-render": "file:../server-side-render", "@wordpress/url": "file:../url", "@wordpress/viewport": "file:../viewport", + "@wordpress/wordcount": "file:../wordcount", "change-case": "^4.1.2", "classnames": "^2.3.1", "colord": "^2.7.0", diff --git a/packages/block-library/src/index.js b/packages/block-library/src/index.js index 88d2c26f02403..a505e66d1e841 100644 --- a/packages/block-library/src/index.js +++ b/packages/block-library/src/index.js @@ -82,6 +82,7 @@ import * as postFeaturedImage from './post-featured-image'; import * as postNavigationLink from './post-navigation-link'; import * as postTemplate from './post-template'; import * as postTerms from './post-terms'; +import * as postTimeToRead from './post-time-to-read'; import * as postTitle from './post-title'; import * as preformatted from './preformatted'; import * as pullquote from './pullquote'; @@ -195,6 +196,7 @@ const getAllBlocks = () => postTerms, postNavigationLink, postTemplate, + postTimeToRead, queryPagination, queryPaginationNext, queryPaginationNumbers, diff --git a/packages/block-library/src/post-time-to-read/block.json b/packages/block-library/src/post-time-to-read/block.json new file mode 100644 index 0000000000000..d5f9f657b67f9 --- /dev/null +++ b/packages/block-library/src/post-time-to-read/block.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "core/post-time-to-read", + "title": "Post Time To Read", + "category": "theme", + "description": "Time to read the post.", + "textdomain": "default", + "usesContext": [ "postType", "postId" ], + "attributes": { + "textAlign": { + "type": "string" + }, + "minutesToRead": { + "type": "number" + } + }, + "supports": { + "html": false + } +} diff --git a/packages/block-library/src/post-time-to-read/edit.js b/packages/block-library/src/post-time-to-read/edit.js new file mode 100644 index 0000000000000..14f95452cf798 --- /dev/null +++ b/packages/block-library/src/post-time-to-read/edit.js @@ -0,0 +1,96 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + +/** + * WordPress dependencies + */ +import { + AlignmentControl, + BlockControls, + store as blockEditorStore, + useBlockProps, +} from '@wordpress/block-editor'; +import { store as editorStore } from '@wordpress/editor'; +import { useDispatch, useSelect } from '@wordpress/data'; +import { useEffect } from '@wordpress/element'; +import { _x, _n, __, sprintf } from '@wordpress/i18n'; +import { count as wordCount } from '@wordpress/wordcount'; + +/** + * Average reading rate - based on average taken from + * https://irisreading.com/average-reading-speed-in-various-languages/ + * (Characters/minute used for Chinese rather than words). + */ +const AVERAGE_READING_RATE = 189; + +function PostTimeToReadEdit( { attributes, setAttributes } ) { + const { textAlign, minutesToRead } = attributes; + + const content = useSelect( + ( select ) => select( editorStore ).getEditedPostAttribute( 'content' ), + [] + ); + + const { __unstableMarkNextChangeAsNotPersistent } = + useDispatch( blockEditorStore ); + + /* + * translators: If your word count is based on single characters (e.g. East Asian characters), + * enter 'characters_excluding_spaces' or 'characters_including_spaces'. Otherwise, enter 'words'. + * Do not translate into your own language. + */ + const wordCountType = _x( 'words', 'Word count type. Do not translate!' ); + + useEffect( () => { + const newMinutesToRead = Math.round( + wordCount( content, wordCountType ) / AVERAGE_READING_RATE + ); + // This is required to keep undo working and not create 2 undo steps + // for the content change. + __unstableMarkNextChangeAsNotPersistent(); + setAttributes( { + minutesToRead: content ? newMinutesToRead : undefined, + } ); + }, [ content ] ); + + let minutesToReadString = __( 'There is no content.' ); + + if ( minutesToRead !== undefined ) { + minutesToReadString = + minutesToRead !== 0 + ? sprintf( + /* translators: %d is the number of minutes the post will take to read. */ + _n( + 'You can read this post in %d minute.', + 'You can read this post in %d minutes.', + minutesToRead + ), + minutesToRead + ) + : __( 'You can read this post less than a minute.' ); + } + + const blockProps = useBlockProps( { + className: classnames( { + [ `has-text-align-${ textAlign }` ]: textAlign, + } ), + } ); + + return ( + <> + + { + setAttributes( { textAlign: nextAlign } ); + } } + /> + +

{ minutesToReadString }

+ + ); +} + +export default PostTimeToReadEdit; diff --git a/packages/block-library/src/post-time-to-read/icon.js b/packages/block-library/src/post-time-to-read/icon.js new file mode 100644 index 0000000000000..24c5dc2fae516 --- /dev/null +++ b/packages/block-library/src/post-time-to-read/icon.js @@ -0,0 +1,15 @@ +/** + * WordPress dependencies + */ +import { SVG, Path } from '@wordpress/components'; + +export default ( + + + +); diff --git a/packages/block-library/src/post-time-to-read/index.js b/packages/block-library/src/post-time-to-read/index.js new file mode 100644 index 0000000000000..95b379f55f0b3 --- /dev/null +++ b/packages/block-library/src/post-time-to-read/index.js @@ -0,0 +1,17 @@ +/** + * Internal dependencies + */ +import initBlock from '../utils/init-block'; +import metadata from './block.json'; +import edit from './edit'; +import icon from './icon'; + +const { name } = metadata; +export { metadata, name }; + +export const settings = { + icon, + edit, +}; + +export const init = () => initBlock( { name, metadata, settings } ); diff --git a/packages/block-library/src/post-time-to-read/index.php b/packages/block-library/src/post-time-to-read/index.php new file mode 100644 index 0000000000000..006db16efb8b7 --- /dev/null +++ b/packages/block-library/src/post-time-to-read/index.php @@ -0,0 +1,57 @@ +context['postId'] ) ) { + return ''; + } + + $minutes_to_read = ! empty( $attributes['minutesToRead'] ) ? (int) $attributes['minutesToRead'] : 0; + + $minutes_to_read_string = $minutes_to_read !== 0 + ? sprintf( + /* translators: %d is the number of minutes the post will take to read. */ + _n( + 'You can read this post in %d minute.', + 'You can read this post in %d minutes.', + $minutes_to_read + ), + $minutes_to_read + ) + : __( 'You can read this post less than a minute.' ); + + $align_class_name = empty( $attributes['textAlign'] ) ? '' : "has-text-align-{$attributes['textAlign']}"; + + $wrapper_attributes = get_block_wrapper_attributes( array( 'class' => $align_class_name ) ); + + return sprintf( + '

%2$s

', + $wrapper_attributes, + $minutes_to_read_string + ); +} + +/** + * Registers the `core/post-time-to-read` block on the server. + */ +function register_block_core_post_time_to_read() { + register_block_type_from_metadata( + __DIR__ . '/post-time-to-read', + array( + 'render_callback' => 'render_block_core_post_time_to_read', + ) + ); +} +add_action( 'init', 'register_block_core_post_time_to_read' );