-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[New Block] Add post time to read block #43403
Merged
Merged
Changes from all commits
Commits
Show all changes
47 commits
Select commit
Hold shift + click to select a range
5e7d7b3
Add new "Post Time To Read" block
t-hamano ed2b796
Add fixture
t-hamano cc6493c
Update npm dependencies
t-hamano f07c8c7
Disallow multiple insert
t-hamano 49bff6f
Fix php lint error
t-hamano 7e9f093
Fix npm dependencies path
t-hamano 56a8e31
Remove unused context
t-hamano 805a6bb
Add a missing word in translate string
t-hamano 06eb280
Don't use @wordpress/editor package
t-hamano d22901f
Don't store attribute
t-hamano b2c90d6
Fix npm dependencies
t-hamano efb3580
Fix: The block is broken in the post editor
t-hamano 094db1d
Update the block icon
t-hamano 9c1e8d6
Add prefix and suffix
t-hamano 088b96e
Server-side rendering implemented using dummy function
t-hamano 9862171
Update fixtures
t-hamano 87ed8b7
Fix phpcs lint error
t-hamano fa55d92
Implement word_count function
t-hamano 2197d61
Remove some new lines on php
t-hamano 4b6e097
Fix regexp escape
t-hamano 72f6947
convert float zero to int zero
t-hamano 757aa2a
Fix PHP lint error
t-hamano 912e454
Cursor isn't displayed in prefix and suffix input area
t-hamano 6cbca51
Calculate time only when content is changed
t-hamano 8e065cc
Capitalize when there is no prefix
t-hamano 46fb033
Apply inline block style to editor only
t-hamano faaaf9e
Add Unit Test
t-hamano fa9566a
Fix PHP Lint
t-hamano 9785f99
Revert prefix/suffix
t-hamano 4bd3ab3
Change block title and description
t-hamano e3f6b6e
Fix some unit tests
t-hamano 1fa5255
Show message when there is no content
t-hamano b986d3a
Pass all PHP unit tests
t-hamano a0612ad
Add @covers to Unit Test class
t-hamano 3909d6e
Changed prefix from gutenberg_ to wp_
t-hamano 907945f
Use dataProvider
t-hamano 7dc6e19
Add render_callback function unit tests
t-hamano c00d014
Add function existence check
t-hamano ca36549
Show time only
t-hamano a8e2884
Update PHP unit test
t-hamano e3417d8
Mark as experimental
t-hamano a27741f
Move `wp_word_count()` function to `experimental` directory
t-hamano 39a840b
Use new function `wp_get_word_count_type()`
t-hamano e673723
fix lint error
t-hamano a0547c9
Merge branch 'trunk' into add/block-post-time-to-read
t-hamano b5a361a
Merge branch 'trunk' into add/block-post-time-to-read
t-hamano ebc1d03
Change namespace from `formatting` to `l10n`
t-hamano File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
<?php | ||
/** | ||
* PHP and WordPress configuration compatibility functions for the Gutenberg | ||
* editor plugin changes related to i18n. | ||
* | ||
* @package gutenberg | ||
*/ | ||
|
||
/** | ||
* Override core's wp_get_word_count_type() introduced in WordPress 6.2. | ||
* Originally, get_word_count_type() method of the WP_Locale class is executed, | ||
* but the process is simulated here. | ||
* | ||
* This function should not be backported to core. | ||
*/ | ||
if ( ! function_exists( 'wp_get_word_count_type' ) ) { | ||
/** | ||
* Retrieves the word count type based on the locale. | ||
* | ||
* @return string Locale-specific word count type. | ||
*/ | ||
function wp_get_word_count_type() { | ||
$word_count_type = _x( 'words', 'Word count type. Do not translate!', 'gutenberg' ); | ||
|
||
// Check for valid types. | ||
if ( 'characters_excluding_spaces' !== $word_count_type && 'characters_including_spaces' !== $word_count_type ) { | ||
// Defaults to 'words'. | ||
$word_count_type = 'words'; | ||
} | ||
return $word_count_type; | ||
} | ||
} | ||
|
||
if ( ! function_exists( 'wp_word_count' ) ) { | ||
/** | ||
* Count words or characters in a provided text string. | ||
* | ||
* @param string $text Text to count elements in. | ||
* @param string $type The type of count. Accepts 'words', 'characters_excluding_spaces', or 'characters_including_spaces'. | ||
* @param array $settings { | ||
* Optional. Array of arguments used to overrides for settings. | ||
* | ||
* @type string $html_regexp Optional. Regular expression to find HTML elements. | ||
* @type string $html_comment_regexp Optional. Regular expression to find HTML comments. | ||
* @type string $space_regexp Optional. Regular expression to find irregular space | ||
* characters. | ||
* @type string $html_entity_regexp Optional. Regular expression to find HTML entities. | ||
* @type string $connector_regexp Optional. Regular expression to find connectors that | ||
* split words. | ||
* @type string $remove_regexp Optional. Regular expression to find remove unwanted | ||
* characters to reduce false-positives. | ||
* @type string $astral_regexp Optional. Regular expression to find unwanted | ||
* characters when searching for non-words. | ||
* @type string $words_regexp Optional. Regular expression to find words by spaces. | ||
* @type string $characters_excluding_spaces_regexp Optional. Regular expression to find characters which | ||
* are non-spaces. | ||
* @type string $characters_including_spaces_regexp Optional. Regular expression to find characters | ||
* including spaces. | ||
* @type array $shortcodes Optional. Array of shortcodes that should be removed | ||
* from the text. | ||
* } | ||
* @return int The word or character count. | ||
*/ | ||
function wp_word_count( $text, $type, $settings = array() ) { | ||
$defaults = array( | ||
'html_regexp' => '/<\/?[a-z][^>]*?>/i', | ||
'html_comment_regexp' => '/<!--[\s\S]*?-->/', | ||
'space_regexp' => '/ | /i', | ||
'html_entity_regexp' => '/&\S+?;/', | ||
'connector_regexp' => "/--|\x{2014}/u", | ||
'remove_regexp' => "/[\x{0021}-\x{0040}\x{005B}-\x{0060}\x{007B}-\x{007E}\x{0080}-\x{00BF}\x{00D7}\x{00F7}\x{2000}-\x{2BFF}\x{2E00}-\x{2E7F}]/u", | ||
'astral_regexp' => "/[\x{010000}-\x{10FFFF}]/u", | ||
'words_regexp' => '/\S\s+/u', | ||
'characters_excluding_spaces_regexp' => '/\S/u', | ||
'characters_including_spaces_regexp' => "/[^\f\n\r\t\v\x{00AD}\x{2028}\x{2029}]/u", | ||
'shortcodes' => array(), | ||
); | ||
|
||
$count = 0; | ||
|
||
if ( ! $text ) { | ||
return $count; | ||
} | ||
|
||
$settings = wp_parse_args( $settings, $defaults ); | ||
|
||
// If there are any shortcodes, add this as a shortcode regular expression. | ||
if ( is_array( $settings['shortcodes'] ) && ! empty( $settings['shortcodes'] ) ) { | ||
$settings['shortcodes_regexp'] = '/\\[\\/?(?:' . implode( '|', $settings['shortcodes'] ) . ')[^\\]]*?\\]/'; | ||
} | ||
|
||
// Sanitize type to one of three possibilities: 'words', 'characters_excluding_spaces' or 'characters_including_spaces'. | ||
if ( 'characters_excluding_spaces' !== $type && 'characters_including_spaces' !== $type ) { | ||
$type = 'words'; | ||
} | ||
|
||
$text .= "\n"; | ||
|
||
// Replace all HTML with a new-line. | ||
$text = preg_replace( $settings['html_regexp'], "\n", $text ); | ||
|
||
// Remove all HTML comments. | ||
$text = preg_replace( $settings['html_comment_regexp'], '', $text ); | ||
|
||
// If a shortcode regular expression has been provided use it to remove shortcodes. | ||
if ( ! empty( $settings['shortcodes_regexp'] ) ) { | ||
$text = preg_replace( $settings['shortcodes_regexp'], "\n", $text ); | ||
} | ||
|
||
// Normalize non-breaking space to a normal space. | ||
$text = preg_replace( $settings['space_regexp'], ' ', $text ); | ||
|
||
if ( 'words' === $type ) { | ||
// Remove HTML Entities. | ||
$text = preg_replace( $settings['html_entity_regexp'], '', $text ); | ||
|
||
// Convert connectors to spaces to count attached text as words. | ||
$text = preg_replace( $settings['connector_regexp'], ' ', $text ); | ||
|
||
// Remove unwanted characters. | ||
$text = preg_replace( $settings['remove_regexp'], '', $text ); | ||
} else { | ||
// Convert HTML Entities to "a". | ||
$text = preg_replace( $settings['html_entity_regexp'], 'a', $text ); | ||
|
||
// Remove surrogate points. | ||
$text = preg_replace( $settings['astral_regexp'], 'a', $text ); | ||
} | ||
|
||
// Match with the selected type regular expression to count the items. | ||
preg_match_all( $settings[ $type . '_regexp' ], $text, $matches ); | ||
|
||
if ( $matches ) { | ||
return count( $matches[0] ); | ||
} | ||
|
||
return $count; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
{ | ||
"$schema": "https://schemas.wp.org/trunk/block.json", | ||
"apiVersion": 2, | ||
"__experimental": true, | ||
"name": "core/post-time-to-read", | ||
"title": "Time To Read", | ||
"category": "theme", | ||
"description": "Show minutes required to finish reading the post.", | ||
"textdomain": "default", | ||
"usesContext": [ "postId", "postType" ], | ||
"attributes": { | ||
"textAlign": { | ||
"type": "string" | ||
} | ||
}, | ||
"supports": { | ||
"html": false, | ||
"multiple": false | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import classnames from 'classnames'; | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { _x, _n, sprintf } from '@wordpress/i18n'; | ||
import { useMemo } from '@wordpress/element'; | ||
import { | ||
AlignmentControl, | ||
BlockControls, | ||
useBlockProps, | ||
} from '@wordpress/block-editor'; | ||
import { __unstableSerializeAndClean } from '@wordpress/blocks'; | ||
import { useEntityProp, useEntityBlockEditor } from '@wordpress/core-data'; | ||
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, context } ) { | ||
const { textAlign } = attributes; | ||
const { postId, postType } = context; | ||
|
||
const [ contentStructure ] = useEntityProp( | ||
'postType', | ||
postType, | ||
'content', | ||
postId | ||
); | ||
|
||
const [ blocks ] = useEntityBlockEditor( 'postType', postType, { | ||
id: postId, | ||
} ); | ||
|
||
const minutesToReadString = useMemo( () => { | ||
// Replicates the logic found in getEditedPostContent(). | ||
let content; | ||
if ( contentStructure instanceof Function ) { | ||
content = contentStructure( { blocks } ); | ||
} else if ( blocks ) { | ||
// If we have parsed blocks already, they should be our source of truth. | ||
// Parsing applies block deprecations and legacy block conversions that | ||
// unparsed content will not have. | ||
content = __unstableSerializeAndClean( blocks ); | ||
} else { | ||
content = contentStructure; | ||
} | ||
|
||
/* | ||
* 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!' | ||
); | ||
|
||
const minutesToRead = Math.max( | ||
1, | ||
Math.round( | ||
wordCount( content, wordCountType ) / AVERAGE_READING_RATE | ||
) | ||
); | ||
|
||
return sprintf( | ||
/* translators: %d is the number of minutes the post will take to read. */ | ||
_n( '%d minute', '%d minutes', minutesToRead ), | ||
minutesToRead | ||
); | ||
}, [ contentStructure, blocks ] ); | ||
|
||
const blockProps = useBlockProps( { | ||
className: classnames( { | ||
[ `has-text-align-${ textAlign }` ]: textAlign, | ||
} ), | ||
} ); | ||
|
||
return ( | ||
<> | ||
<BlockControls group="block"> | ||
<AlignmentControl | ||
value={ textAlign } | ||
onChange={ ( nextAlign ) => { | ||
setAttributes( { textAlign: nextAlign } ); | ||
} } | ||
/> | ||
</BlockControls> | ||
<p { ...blockProps }>{ minutesToReadString }</p> | ||
</> | ||
); | ||
} | ||
|
||
export default PostTimeToReadEdit; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { SVG, Path } from '@wordpress/components'; | ||
|
||
export default ( | ||
<SVG | ||
xmlns="http://www.w3.org/2000/svg" | ||
width="24" | ||
height="24" | ||
viewBox="0 0 24 24" | ||
> | ||
<Path d="M12 3c-5 0-9 4-9 9s4 9 9 9 9-4 9-9-4-9-9-9zm0 16.5c-4.1 0-7.5-3.4-7.5-7.5S7.9 4.5 12 4.5s7.5 3.4 7.5 7.5-3.4 7.5-7.5 7.5zM12 7l-1 5c0 .3.2.6.4.8l4.2 2.8-2.7-4.1L12 7z" /> | ||
</SVG> | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 } ); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a follow-up PR once this is merged, it'd be good to consider what design tools this needs. There are some tracking issues for design tool consistency - https://github.com/WordPress/gutenberg/issues?q=is%3Aopen+is%3Aissue+label%3A%22%5BFeature%5D+Design+Tools%22+label%3A%22%5BType%5D+Tracking+Issue%22.