-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[New Block] Add post time to read block (#43403)
* Add new "Post Time To Read" block * Add fixture * Update npm dependencies * Disallow multiple insert * Fix php lint error * Fix npm dependencies path * Remove unused context * Add a missing word in translate string * Don't use @wordpress/editor package * Don't store attribute * Fix npm dependencies * Fix: The block is broken in the post editor * Update the block icon * Add prefix and suffix * Server-side rendering implemented using dummy function * Update fixtures * Fix phpcs lint error * Implement word_count function * Remove some new lines on php * Fix regexp escape * convert float zero to int zero * Fix PHP lint error * Cursor isn't displayed in prefix and suffix input area * Calculate time only when content is changed * Capitalize when there is no prefix * Apply inline block style to editor only * Add Unit Test * Fix PHP Lint * Revert prefix/suffix * Change block title and description * Fix some unit tests * Show message when there is no content * Pass all PHP unit tests * Add @Covers to Unit Test class * Changed prefix from gutenberg_ to wp_ * Use dataProvider * Add render_callback function unit tests * Add function existence check * Show time only * Update PHP unit test * Mark as experimental * Move `wp_word_count()` function to `experimental` directory * Use new function `wp_get_word_count_type()` * fix lint error * Change namespace from `formatting` to `l10n`
- Loading branch information
Showing
19 changed files
with
677 additions
and
1 deletion.
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.
002be81
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.
Flaky tests detected in 002be81.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.
🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/4280625888
📝 Reported issues:
/test/e2e/specs/editor/blocks/navigation.spec.js