Skip to content
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 47 commits into from
Feb 27, 2023
Merged

Conversation

t-hamano
Copy link
Contributor

@t-hamano t-hamano commented Aug 19, 2022

Close #42542

Note: The latest status is summarized in this comment.

What?

This PR adds a new "Post Time To Read" block.

For now, I'm keeping implementation to a minimum. If it makes sense to incorporate this block, I would like to work on additional implementation.

Why?

With #41611, "Time to read" has been added to the Detail panel.
By using the same information in the block, the site owner can tell visitors in advance how long it will take to finish reading.

Implementation Details

Calculation of time to read

The time required indicated by the block must match the "Time to read" in the Details panel. This PR uses the same @wordpress/wordcount package to calculate.

The count method of this package is very powerful and supports word-by-word or character-by-character calculations. The calculation criteria can be controlled by the translation function, so the time required can be calculated appropriately according to the site language:

/*
* 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!' );

This block stores only the calculated time (minutesToRead) in the attribute and outputs the appropriate string through dynamic rendering.

@update: Time is no longer stored as an attribute since time is now computed by dynamic rendering.

Why dynamic rendering?

When the block was saved as static markup by using __(), the block could be broken if the site language is changed, as mentioned in #43050.
Therefore, We need to use the translation function on the server side.

About demerit

The biggest disadvantage of this implementation is that time is stored as attributes. The time displayed on the front end is updated only when the post is saved.

This means that it will not work properly in templates such as single.html or in query loops. This issue is similar to what was mentioned in #29739 when the TOC block was rebuilt with static markup.

@update: Time is now fully computed by dynamic rendering. Therefore, it works not only in the post editor, but also in the site editor templates.

Testing Instructions

First, try using this block on gutenberg.run.

http://gutenberg.run/43403

Next steps and suggestions

If it makes sense to bundle this block, I would like to proceed with this PR according to the following steps and suggestions.

Add E2E tests

We will need to check that the correct attributes (minutesToRead) have been saved after inserting content of any length.

Add block supports

As discussed in #43241, we need to add all the necessary block support to address Design Tooling Consistency.

Add filter hook

The time string should be displayed appropriately depending on the language of the site, but it might make sense to provide hooks such as the following:

$minutes_to_read_string = apply_filters( 'block_core_post_time_to_read_render_string', $minutes_to_read_string );

✅ Create a block icon (Done)

I could not find a suitable icon from the @wordpress/icons package, so I created a temporary icon.
Need help from designers to improve this icon or create a completely new icon 🙏

@update: As this comment states, @jasmussen provided the icons 🎉

✅ Server-side time calculation (Done)

As mentioned earlier, this block will only work on a single post.

Many consumers will probably want to place the block in a template such as single.html. To do so, I think we would need to implement the exact same logic on the server side as @wordpress/count does.

Screenshots or screencast

editor_1
editor_2
front

@github-actions
Copy link

github-actions bot commented Aug 19, 2022

Size Change: +577 B (0%)

Total Size: 1.33 MB

Filename Size Change
build/block-library/index.min.js 200 kB +577 B (0%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 993 B
build/annotations/index.min.js 2.78 kB
build/api-fetch/index.min.js 2.27 kB
build/autop/index.min.js 2.15 kB
build/blob/index.min.js 483 B
build/block-directory/index.min.js 7.2 kB
build/block-directory/style-rtl.css 1.04 kB
build/block-directory/style.css 1.04 kB
build/block-editor/content-rtl.css 4.11 kB
build/block-editor/content.css 4.1 kB
build/block-editor/default-editor-styles-rtl.css 403 B
build/block-editor/default-editor-styles.css 403 B
build/block-editor/index.min.js 195 kB
build/block-editor/style-rtl.css 14.4 kB
build/block-editor/style.css 14.4 kB
build/block-library/blocks/archives/editor-rtl.css 61 B
build/block-library/blocks/archives/editor.css 60 B
build/block-library/blocks/archives/style-rtl.css 90 B
build/block-library/blocks/archives/style.css 90 B
build/block-library/blocks/audio/editor-rtl.css 150 B
build/block-library/blocks/audio/editor.css 150 B
build/block-library/blocks/audio/style-rtl.css 122 B
build/block-library/blocks/audio/style.css 122 B
build/block-library/blocks/audio/theme-rtl.css 138 B
build/block-library/blocks/audio/theme.css 138 B
build/block-library/blocks/avatar/editor-rtl.css 116 B
build/block-library/blocks/avatar/editor.css 116 B
build/block-library/blocks/avatar/style-rtl.css 91 B
build/block-library/blocks/avatar/style.css 91 B
build/block-library/blocks/block/editor-rtl.css 305 B
build/block-library/blocks/block/editor.css 305 B
build/block-library/blocks/button/editor-rtl.css 587 B
build/block-library/blocks/button/editor.css 587 B
build/block-library/blocks/button/style-rtl.css 628 B
build/block-library/blocks/button/style.css 627 B
build/block-library/blocks/buttons/editor-rtl.css 337 B
build/block-library/blocks/buttons/editor.css 337 B
build/block-library/blocks/buttons/style-rtl.css 332 B
build/block-library/blocks/buttons/style.css 332 B
build/block-library/blocks/calendar/style-rtl.css 239 B
build/block-library/blocks/calendar/style.css 239 B
build/block-library/blocks/categories/editor-rtl.css 84 B
build/block-library/blocks/categories/editor.css 83 B
build/block-library/blocks/categories/style-rtl.css 100 B
build/block-library/blocks/categories/style.css 100 B
build/block-library/blocks/code/editor-rtl.css 53 B
build/block-library/blocks/code/editor.css 53 B
build/block-library/blocks/code/style-rtl.css 121 B
build/block-library/blocks/code/style.css 121 B
build/block-library/blocks/code/theme-rtl.css 124 B
build/block-library/blocks/code/theme.css 124 B
build/block-library/blocks/columns/editor-rtl.css 108 B
build/block-library/blocks/columns/editor.css 108 B
build/block-library/blocks/columns/style-rtl.css 406 B
build/block-library/blocks/columns/style.css 406 B
build/block-library/blocks/comment-author-avatar/editor-rtl.css 125 B
build/block-library/blocks/comment-author-avatar/editor.css 125 B
build/block-library/blocks/comment-content/style-rtl.css 92 B
build/block-library/blocks/comment-content/style.css 92 B
build/block-library/blocks/comment-template/style-rtl.css 199 B
build/block-library/blocks/comment-template/style.css 198 B
build/block-library/blocks/comments-pagination-numbers/editor-rtl.css 123 B
build/block-library/blocks/comments-pagination-numbers/editor.css 121 B
build/block-library/blocks/comments-pagination/editor-rtl.css 222 B
build/block-library/blocks/comments-pagination/editor.css 209 B
build/block-library/blocks/comments-pagination/style-rtl.css 235 B
build/block-library/blocks/comments-pagination/style.css 231 B
build/block-library/blocks/comments-title/editor-rtl.css 75 B
build/block-library/blocks/comments-title/editor.css 75 B
build/block-library/blocks/comments/editor-rtl.css 840 B
build/block-library/blocks/comments/editor.css 839 B
build/block-library/blocks/comments/style-rtl.css 637 B
build/block-library/blocks/comments/style.css 636 B
build/block-library/blocks/cover/editor-rtl.css 612 B
build/block-library/blocks/cover/editor.css 613 B
build/block-library/blocks/cover/style-rtl.css 1.57 kB
build/block-library/blocks/cover/style.css 1.56 kB
build/block-library/blocks/embed/editor-rtl.css 293 B
build/block-library/blocks/embed/editor.css 293 B
build/block-library/blocks/embed/style-rtl.css 410 B
build/block-library/blocks/embed/style.css 410 B
build/block-library/blocks/embed/theme-rtl.css 138 B
build/block-library/blocks/embed/theme.css 138 B
build/block-library/blocks/file/editor-rtl.css 300 B
build/block-library/blocks/file/editor.css 300 B
build/block-library/blocks/file/style-rtl.css 265 B
build/block-library/blocks/file/style.css 265 B
build/block-library/blocks/file/view.min.js 353 B
build/block-library/blocks/freeform/editor-rtl.css 2.44 kB
build/block-library/blocks/freeform/editor.css 2.44 kB
build/block-library/blocks/gallery/editor-rtl.css 984 B
build/block-library/blocks/gallery/editor.css 988 B
build/block-library/blocks/gallery/style-rtl.css 1.55 kB
build/block-library/blocks/gallery/style.css 1.55 kB
build/block-library/blocks/gallery/theme-rtl.css 122 B
build/block-library/blocks/gallery/theme.css 122 B
build/block-library/blocks/group/editor-rtl.css 654 B
build/block-library/blocks/group/editor.css 654 B
build/block-library/blocks/group/style-rtl.css 57 B
build/block-library/blocks/group/style.css 57 B
build/block-library/blocks/group/theme-rtl.css 78 B
build/block-library/blocks/group/theme.css 78 B
build/block-library/blocks/heading/style-rtl.css 76 B
build/block-library/blocks/heading/style.css 76 B
build/block-library/blocks/html/editor-rtl.css 332 B
build/block-library/blocks/html/editor.css 333 B
build/block-library/blocks/image/editor-rtl.css 830 B
build/block-library/blocks/image/editor.css 829 B
build/block-library/blocks/image/style-rtl.css 652 B
build/block-library/blocks/image/style.css 652 B
build/block-library/blocks/image/theme-rtl.css 137 B
build/block-library/blocks/image/theme.css 137 B
build/block-library/blocks/latest-comments/style-rtl.css 357 B
build/block-library/blocks/latest-comments/style.css 357 B
build/block-library/blocks/latest-posts/editor-rtl.css 213 B
build/block-library/blocks/latest-posts/editor.css 212 B
build/block-library/blocks/latest-posts/style-rtl.css 478 B
build/block-library/blocks/latest-posts/style.css 478 B
build/block-library/blocks/list/style-rtl.css 88 B
build/block-library/blocks/list/style.css 88 B
build/block-library/blocks/media-text/editor-rtl.css 266 B
build/block-library/blocks/media-text/editor.css 263 B
build/block-library/blocks/media-text/style-rtl.css 507 B
build/block-library/blocks/media-text/style.css 505 B
build/block-library/blocks/more/editor-rtl.css 431 B
build/block-library/blocks/more/editor.css 431 B
build/block-library/blocks/navigation-link/editor-rtl.css 716 B
build/block-library/blocks/navigation-link/editor.css 715 B
build/block-library/blocks/navigation-link/style-rtl.css 115 B
build/block-library/blocks/navigation-link/style.css 115 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 299 B
build/block-library/blocks/navigation-submenu/editor.css 299 B
build/block-library/blocks/navigation/editor-rtl.css 2.13 kB
build/block-library/blocks/navigation/editor.css 2.14 kB
build/block-library/blocks/navigation/style-rtl.css 2.22 kB
build/block-library/blocks/navigation/style.css 2.2 kB
build/block-library/blocks/navigation/view-modal.min.js 2.81 kB
build/block-library/blocks/navigation/view.min.js 447 B
build/block-library/blocks/nextpage/editor-rtl.css 395 B
build/block-library/blocks/nextpage/editor.css 395 B
build/block-library/blocks/page-list/editor-rtl.css 376 B
build/block-library/blocks/page-list/editor.css 376 B
build/block-library/blocks/page-list/style-rtl.css 175 B
build/block-library/blocks/page-list/style.css 175 B
build/block-library/blocks/paragraph/editor-rtl.css 174 B
build/block-library/blocks/paragraph/editor.css 174 B
build/block-library/blocks/paragraph/style-rtl.css 279 B
build/block-library/blocks/paragraph/style.css 281 B
build/block-library/blocks/post-author/style-rtl.css 175 B
build/block-library/blocks/post-author/style.css 176 B
build/block-library/blocks/post-comments-form/editor-rtl.css 96 B
build/block-library/blocks/post-comments-form/editor.css 96 B
build/block-library/blocks/post-comments-form/style-rtl.css 501 B
build/block-library/blocks/post-comments-form/style.css 501 B
build/block-library/blocks/post-date/style-rtl.css 61 B
build/block-library/blocks/post-date/style.css 61 B
build/block-library/blocks/post-excerpt/editor-rtl.css 71 B
build/block-library/blocks/post-excerpt/editor.css 71 B
build/block-library/blocks/post-excerpt/style-rtl.css 134 B
build/block-library/blocks/post-excerpt/style.css 134 B
build/block-library/blocks/post-featured-image/editor-rtl.css 586 B
build/block-library/blocks/post-featured-image/editor.css 584 B
build/block-library/blocks/post-featured-image/style-rtl.css 318 B
build/block-library/blocks/post-featured-image/style.css 318 B
build/block-library/blocks/post-navigation-link/style-rtl.css 153 B
build/block-library/blocks/post-navigation-link/style.css 153 B
build/block-library/blocks/post-template/editor-rtl.css 99 B
build/block-library/blocks/post-template/editor.css 98 B
build/block-library/blocks/post-template/style-rtl.css 282 B
build/block-library/blocks/post-template/style.css 282 B
build/block-library/blocks/post-terms/style-rtl.css 96 B
build/block-library/blocks/post-terms/style.css 96 B
build/block-library/blocks/post-title/style-rtl.css 100 B
build/block-library/blocks/post-title/style.css 100 B
build/block-library/blocks/preformatted/style-rtl.css 103 B
build/block-library/blocks/preformatted/style.css 103 B
build/block-library/blocks/pullquote/editor-rtl.css 135 B
build/block-library/blocks/pullquote/editor.css 135 B
build/block-library/blocks/pullquote/style-rtl.css 326 B
build/block-library/blocks/pullquote/style.css 325 B
build/block-library/blocks/pullquote/theme-rtl.css 167 B
build/block-library/blocks/pullquote/theme.css 167 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 122 B
build/block-library/blocks/query-pagination-numbers/editor.css 121 B
build/block-library/blocks/query-pagination/editor-rtl.css 221 B
build/block-library/blocks/query-pagination/editor.css 211 B
build/block-library/blocks/query-pagination/style-rtl.css 288 B
build/block-library/blocks/query-pagination/style.css 284 B
build/block-library/blocks/query-title/style-rtl.css 63 B
build/block-library/blocks/query-title/style.css 63 B
build/block-library/blocks/query/editor-rtl.css 463 B
build/block-library/blocks/query/editor.css 463 B
build/block-library/blocks/quote/style-rtl.css 222 B
build/block-library/blocks/quote/style.css 222 B
build/block-library/blocks/quote/theme-rtl.css 223 B
build/block-library/blocks/quote/theme.css 226 B
build/block-library/blocks/read-more/style-rtl.css 132 B
build/block-library/blocks/read-more/style.css 132 B
build/block-library/blocks/rss/editor-rtl.css 149 B
build/block-library/blocks/rss/editor.css 149 B
build/block-library/blocks/rss/style-rtl.css 289 B
build/block-library/blocks/rss/style.css 288 B
build/block-library/blocks/search/editor-rtl.css 165 B
build/block-library/blocks/search/editor.css 165 B
build/block-library/blocks/search/style-rtl.css 409 B
build/block-library/blocks/search/style.css 406 B
build/block-library/blocks/search/theme-rtl.css 114 B
build/block-library/blocks/search/theme.css 114 B
build/block-library/blocks/separator/editor-rtl.css 146 B
build/block-library/blocks/separator/editor.css 146 B
build/block-library/blocks/separator/style-rtl.css 234 B
build/block-library/blocks/separator/style.css 234 B
build/block-library/blocks/separator/theme-rtl.css 194 B
build/block-library/blocks/separator/theme.css 194 B
build/block-library/blocks/shortcode/editor-rtl.css 474 B
build/block-library/blocks/shortcode/editor.css 474 B
build/block-library/blocks/site-logo/editor-rtl.css 489 B
build/block-library/blocks/site-logo/editor.css 489 B
build/block-library/blocks/site-logo/style-rtl.css 203 B
build/block-library/blocks/site-logo/style.css 203 B
build/block-library/blocks/site-tagline/editor-rtl.css 86 B
build/block-library/blocks/site-tagline/editor.css 86 B
build/block-library/blocks/site-title/editor-rtl.css 116 B
build/block-library/blocks/site-title/editor.css 116 B
build/block-library/blocks/site-title/style-rtl.css 57 B
build/block-library/blocks/site-title/style.css 57 B
build/block-library/blocks/social-link/editor-rtl.css 184 B
build/block-library/blocks/social-link/editor.css 184 B
build/block-library/blocks/social-links/editor-rtl.css 674 B
build/block-library/blocks/social-links/editor.css 673 B
build/block-library/blocks/social-links/style-rtl.css 1.4 kB
build/block-library/blocks/social-links/style.css 1.39 kB
build/block-library/blocks/spacer/editor-rtl.css 332 B
build/block-library/blocks/spacer/editor.css 332 B
build/block-library/blocks/spacer/style-rtl.css 48 B
build/block-library/blocks/spacer/style.css 48 B
build/block-library/blocks/table/editor-rtl.css 433 B
build/block-library/blocks/table/editor.css 433 B
build/block-library/blocks/table/style-rtl.css 651 B
build/block-library/blocks/table/style.css 650 B
build/block-library/blocks/table/theme-rtl.css 157 B
build/block-library/blocks/table/theme.css 157 B
build/block-library/blocks/tag-cloud/style-rtl.css 251 B
build/block-library/blocks/tag-cloud/style.css 253 B
build/block-library/blocks/template-part/editor-rtl.css 404 B
build/block-library/blocks/template-part/editor.css 404 B
build/block-library/blocks/template-part/theme-rtl.css 101 B
build/block-library/blocks/template-part/theme.css 101 B
build/block-library/blocks/text-columns/editor-rtl.css 95 B
build/block-library/blocks/text-columns/editor.css 95 B
build/block-library/blocks/text-columns/style-rtl.css 166 B
build/block-library/blocks/text-columns/style.css 166 B
build/block-library/blocks/verse/style-rtl.css 99 B
build/block-library/blocks/verse/style.css 99 B
build/block-library/blocks/video/editor-rtl.css 552 B
build/block-library/blocks/video/editor.css 555 B
build/block-library/blocks/video/style-rtl.css 179 B
build/block-library/blocks/video/style.css 179 B
build/block-library/blocks/video/theme-rtl.css 139 B
build/block-library/blocks/video/theme.css 139 B
build/block-library/classic-rtl.css 179 B
build/block-library/classic.css 179 B
build/block-library/common-rtl.css 1.11 kB
build/block-library/common.css 1.11 kB
build/block-library/editor-elements-rtl.css 75 B
build/block-library/editor-elements.css 75 B
build/block-library/editor-rtl.css 11.6 kB
build/block-library/editor.css 11.6 kB
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/reset-rtl.css 478 B
build/block-library/reset.css 478 B
build/block-library/style-rtl.css 12.7 kB
build/block-library/style.css 12.7 kB
build/block-library/theme-rtl.css 698 B
build/block-library/theme.css 703 B
build/block-serialization-default-parser/index.min.js 1.13 kB
build/block-serialization-spec-parser/index.min.js 2.83 kB
build/blocks/index.min.js 51 kB
build/components/index.min.js 207 kB
build/components/style-rtl.css 11.7 kB
build/components/style.css 11.7 kB
build/compose/index.min.js 12.4 kB
build/core-data/index.min.js 16.2 kB
build/customize-widgets/index.min.js 12.2 kB
build/customize-widgets/style-rtl.css 1.41 kB
build/customize-widgets/style.css 1.41 kB
build/data-controls/index.min.js 663 B
build/data/index.min.js 8.58 kB
build/date/index.min.js 40.4 kB
build/deprecated/index.min.js 518 B
build/dom-ready/index.min.js 336 B
build/dom/index.min.js 4.72 kB
build/edit-post/classic-rtl.css 571 B
build/edit-post/classic.css 571 B
build/edit-post/index.min.js 34.8 kB
build/edit-post/style-rtl.css 7.53 kB
build/edit-post/style.css 7.52 kB
build/edit-site/index.min.js 65.5 kB
build/edit-site/style-rtl.css 9.96 kB
build/edit-site/style.css 9.95 kB
build/edit-widgets/index.min.js 17.3 kB
build/edit-widgets/style-rtl.css 4.55 kB
build/edit-widgets/style.css 4.55 kB
build/editor/index.min.js 45.7 kB
build/editor/style-rtl.css 3.54 kB
build/editor/style.css 3.53 kB
build/element/index.min.js 4.95 kB
build/escape-html/index.min.js 548 B
build/format-library/index.min.js 7.27 kB
build/format-library/style-rtl.css 557 B
build/format-library/style.css 556 B
build/hooks/index.min.js 1.66 kB
build/html-entities/index.min.js 454 B
build/i18n/index.min.js 3.79 kB
build/is-shallow-equal/index.min.js 535 B
build/keyboard-shortcuts/index.min.js 1.79 kB
build/keycodes/index.min.js 1.94 kB
build/list-reusable-blocks/index.min.js 2.14 kB
build/list-reusable-blocks/style-rtl.css 865 B
build/list-reusable-blocks/style.css 865 B
build/media-utils/index.min.js 2.99 kB
build/notices/index.min.js 977 B
build/plugins/index.min.js 1.95 kB
build/preferences-persistence/index.min.js 2.23 kB
build/preferences/index.min.js 1.35 kB
build/primitives/index.min.js 960 B
build/priority-queue/index.min.js 1.52 kB
build/private-apis/index.min.js 940 B
build/react-i18n/index.min.js 702 B
build/react-refresh-entry/index.min.js 8.44 kB
build/react-refresh-runtime/index.min.js 7.31 kB
build/redux-routine/index.min.js 2.75 kB
build/reusable-blocks/index.min.js 2.26 kB
build/reusable-blocks/style-rtl.css 265 B
build/reusable-blocks/style.css 265 B
build/rich-text/index.min.js 10.8 kB
build/server-side-render/index.min.js 2.09 kB
build/shortcode/index.min.js 1.52 kB
build/style-engine/index.min.js 1.53 kB
build/token-list/index.min.js 650 B
build/url/index.min.js 3.69 kB
build/vendors/inert-polyfill.min.js 2.48 kB
build/vendors/react-dom.min.js 41.8 kB
build/vendors/react.min.js 4.02 kB
build/viewport/index.min.js 1.09 kB
build/warning/index.min.js 280 B
build/widgets/index.min.js 7.31 kB
build/widgets/style-rtl.css 1.18 kB
build/widgets/style.css 1.18 kB
build/wordcount/index.min.js 1.06 kB

compressed-size-action

@gziolo gziolo added the New Block Suggestion for a new block label Aug 19, 2022
@t-hamano t-hamano self-assigned this Aug 24, 2022
@t-hamano t-hamano changed the title [WIP] [Try] Add post time to read block Sep 18, 2022
@t-hamano t-hamano marked this pull request as ready for review September 18, 2022 06:00
@t-hamano t-hamano requested a review from bph September 18, 2022 06:00
@bph
Copy link
Contributor

bph commented Sep 21, 2022

That's a fun block! Thank you.

I added it to the single post via the post editor.

Screen Shot 2022-09-21 at 16 25 21

For my test, I also wanted to use it on my home page with the post grid, now I got different values:
The site editor show "no content' for the block.
Screen Shot 2022-09-21 at 16 26 01

On the front end is shows "less than a minute" which is obviously different from the 9 min on the single post.

Screen Shot 2022-09-21 at 16 26 17

There is also a missing 'in' there: "You can read this post in less than a minute"

Maybe there is a way to get the value stored in the post_meta table so it can be used like any other post_meta information, like post_date, or post_author.

@t-hamano t-hamano added the Needs Technical Feedback Needs testing from a developer perspective. label Sep 22, 2022
@t-hamano
Copy link
Contributor Author

Thank you for the review, @bph !

There is also a missing 'in' there: "You can read this post in less than a minute"

Fixed 👍

Maybe there is a way to get the value stored in the post_meta table so it can be used like any other post_meta information, like post_date, or post_author.

I would like to hear from the developers if it is possible to add new meta information when saving the post and if this would have any significant impact. Also, when someone moves from the classic editor to Gutenberg, there will be no meta information initially.

I will ask for feedback once in the editor chat.

Copy link
Contributor

@talldan talldan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work here ❤️

packages/block-library/src/post-time-to-read/edit.js Outdated Show resolved Hide resolved
packages/block-library/src/post-time-to-read/edit.js Outdated Show resolved Hide resolved
Comment on lines 66 to 67
'You can read this post in %d minute.',
'You can read this post in %d minutes.',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the text could be configurable, as it's unlikely to suit everyone. I'm not sure if there are any other blocks that have a way to configure text where there's a variable involved though. That seems like a challenge!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially considered introducing a prefix and suffix like core/post-terms.

time-to-read

However, a common string would not cover all cases of singular and plural, or all cases where the time required is less than a minute.

I also considered the following sidebar setting, but this is complicated 🤔

settings

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought the easiest way to start might be just a prefix, and making the unit of time an implicit part of the text that can't be changed. The only confusing thing would be how internationalization works. User entered text can't be localized at the moment, but the 'minute' or 'minutes' would be. 🤔

Lets see if we can get some assistance from a designer on this particular matter (cc @WordPress/gutenberg-design).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the block should just print the time, then if you want a prefix/suffix you can place it in a Row alongside Paragraphs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the block should just print the time, then if you want a prefix/suffix you can place it in a Row alongside Paragraphs?

Yes, I think such an approach is possible.

However, given that the core/post-terms block has a prefix/suffix, I think the current approach makes sense. Also, if this block displayed only time, adding a prefix or suffix would create multiple paragraphs. I think it should consist of a single paragraph, including prefixes and suffixes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point.

The only confusing thing would be how internationalization works. User entered text can't be localized at the moment

If the prefix/suffix had a placeholder, would that be localized? If so I believe that would solve any issues?

Copy link
Contributor Author

@t-hamano t-hamano Oct 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the prefix/suffix had a placeholder, would that be localized? If so I believe that would solve any issues?

Yes, the prefix/suffix placeholder will be localized as you can see here.

However, the prefix/suffix with text entered are stored as attributes and aren't localized.
Therefore, for example, if you enter prefix / suffix in English and switch to a language other than English, only the time will be localized and the correct text will not be generated.
In early versions, there was an implementation to make all paragraphs subject to localization, without prefix/suffix. However, this would be inconvenient because the user wouldn't be able to change the text. (This may be solved by introducing filter hooks.)

packages/block-library/package.json Outdated Show resolved Hide resolved
@t-hamano
Copy link
Contributor Author

Thank you for the review, @talldan !
I would like to correct the points you have commented on.

My head is telling me there would be two main tasks:

Make the block entirely dynamic
Port wordCount to PHP (or use existing code if there's already an equivalent word count PHP funciton).

Yes, I think this is a major point. I think it would be ideal to implement this block as a dynamic block and work in a template (or in a query loop block). However, as far as I know, there is no function like @wordpress/count in the WordPress core.

If it were to be implemented in PHP, I think the following step would be a good idea, what do you think?

  • Implement the complete logic within the Time To Read callback function
  • Backport this function to the WordPress core (could be a function like the_time_to_read( $str ) or get_the_time_to_read( $str ))
  • Replace the logic in render_callback with this function backported into the WordPress core
@talldan
Copy link
Contributor

talldan commented Sep 30, 2022

If it were to be implemented in PHP, I think the following step would be a good idea, what do you think?

Yep, something like that sounds great. You can implement the function in the lib/compat/wordpress-6.2 folder (no folder exists at the moment, but feel free to create one). This is the folder that will contain all the code that needs to be backported for WordPress 6.2. Functions implemented in this file typically have the gutenberg_ prefix, which is then removed for the core version of the function when backporting. The new file can be required in the lib/load.php file. It is good to get an idea of the where the function will be added to in the core codebase and leave that in a comment. Possibly functions.php as that has some related code like the human_readable_duration function, but I'm no expert about this kind of thing.

An alternative is to implement everything in the block's index.php file, but one thing to note is that the backporting process is different. The php files in the block library package are automatically copied to the core codebase, there's no manual backport. Because of that you won't be able to use the gutenberg prefix as that would be copied to core, so it can be a bit of a problematic way to implement additional PHP functions.

@t-hamano
Copy link
Contributor Author

t-hamano commented Oct 3, 2022

Thank you for the review, @talldan !

Make the block entirely dynamic
Port wordCount to PHP (or use existing code if there's already an equivalent word count PHP funciton).

Yes, this is probably the biggest problem here.
In the WordPress core, wp-includes/formatting.php seems to be relevant, but there doesn't seem to be an alternative function for wordCount, so I think we'll have to create a completely new function.
This is complicated, but I'm willing to give it a shot 👍

@talldan talldan added the Needs Design Feedback Needs general design feedback. label Oct 3, 2022
@jasmussen
Copy link
Contributor

This is a fun little utility block! I took it for a spin:

time to read

It works well. The crash happens most easily if you select the block and press Enter, though it happened also seemingly a bit at random. Got this in the console:

react-dom.min.js?ver=6.1-beta2-54366:141 TypeError: text.replace is not a function
    at stripTags (stripTags.js:10:14)
    at index.js:76:30
    at Array.reduce (<anonymous>)
    at countWords (index.js:76:4)
    at count (index.js:124:11)
    at edit.js:48:14
    at Tj (react-dom.min.js?ver=6.1-beta2-54366:179:399)
    at unstable_runWithPriority (react.min.js?ver=6.1-beta2-54366:24:26)
    at Za (react-dom.min.js?ver=6.1-beta2-54366:73:8)
    at Ra (react-dom.min.js?ver=6.1-beta2-54366:178:368)

The icon looks pretty good. I suspect a clock is useful enough that more blocks, or even parts of the UI could have this. But since it seems appropriate for the block at hand, let's use it! You can probably add it to the icon library, though. The metrics were pretty good, but here's a new version that matches similar circle icons:
Screenshot 2022-10-03 at 12 28 07

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24" xml:space="preserve"><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" style="fill:#1e1e1e"/></svg>

Let me know if that works for you.

Question regarding this conversation: instead of including the full text of "This post can be read in n minutes", which runs into translation and theoretically even post type challenges, could we literally output only the time to read? I.e.

  • 3 minutes
  • 1 minute

Perhaps even with a toggle to choose between the full minutes and the shorter m (3m, etc), the idea being you could type out any text you like in a paragraph, reducing the burden on this block. I realize that opens a conversation on blocks vs. inline blocks, and how it remains tricky to create a horizontal row of post meta (a la #26899).

On the other hand, that appears to be partially handled by prefix/suffixes also (#40559), so perhaps that route is the way to go after all? Something to consider.

@paaljoachim
Copy link
Contributor

I too received a "This block has encountered an error and cannot be previewed." error.
With a similar console error code. I added the block with the forward slash. / The error was seen right after adding the block.
Good to see that it can only be added once to any post/page (?).

@t-hamano
Copy link
Contributor Author

t-hamano commented Oct 3, 2022

Thanks for the feedback, @jasmussen, @paaljoachim!
I have fixed the problem of broken blocks in the post editor.

@talldan
I have found the logic to retrieve the current (unsaved) content without using the core/editor package.

// 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;
}

Both the post editor and the site editor will retrieve the content correctly.

@t-hamano
Copy link
Contributor Author

t-hamano commented Oct 3, 2022

@jasmussen
I have replaced the icon. I think it works very well!

icon_preview

@t-hamano
Copy link
Contributor Author

t-hamano commented Oct 3, 2022

I have added the prefix and suffix.

preview

At least in English, I believe that any variation can produce the correct sentence. I think there might be no problem if this text is properly translated:

? sprintf(
/* translators: %d is the number of minutes the post will take to read. */
_n( '%d minute', '%d minutes', minutesToRead ),
minutesToRead
)
: __( 'less than a minute' );

Without prefix and suffix

without_prefix_suffix

With prefix and suffix

with_prefix_suffix

@t-hamano t-hamano changed the title [Try] Add post time to read block Oct 4, 2022
@t-hamano t-hamano changed the title Add post time to read block Oct 4, 2022
@t-hamano
Copy link
Contributor Author

t-hamano commented Oct 4, 2022

@talldan
I was able to implement wordcount in PHP 😊

Perhaps the original logic is here:
https://github.com/WordPress/wordpress-develop/blob/2648a5f984b8abf06872151898e3a61d3458a628/src/js/_enqueues/wp/utils/word-count.js

This is probably what @wordpress/wordcount was implemented based on (Actually, the logic is exactly the same.).
I think it would be better to get a review from the core team on this new function implemented in PHP, what do you think?

@t-hamano
Copy link
Contributor Author

t-hamano commented Oct 4, 2022

@bph
This block now also works in the site editor 🚀 I would be happy to test it when you have time.

@paaljoachim
Copy link
Contributor

Retesting using
http://gutenberg.run/43403

I see this:

Screenshot 2022-10-04 at 22 16 51

Prefix "less than a minute" Suffix.

Should Suffix be with a small s?

I added a prefix of "It will take" and the Suffix "to read this text."
Screenshot 2022-10-04 at 22 19 18

Result on the frontend.
Screenshot 2022-10-04 at 22 21 18

Backend text says:
"It will take less than a minute to read this text."

Frontend text says:
"It will take 0 minutes to read this text."

The same backend text should also be seen on the frontend.

@t-hamano
Copy link
Contributor Author

I have fixed the lint error. It was simply an omission to update tsconfig.json 😅 It appears that the performance test failure is not due to this PR, but is being investigated in #48138.

@talldan
Copy link
Contributor

talldan commented Feb 27, 2023

Do you think this is ready to merge now @t-hamano?

@t-hamano
Copy link
Contributor Author

@talldan
I think this PR is ready to merge.

✅ Merged the latest trunk and it is working as expected
✅ It works as expected with WordPress 6.0, which is supported by the Gutenberg plugin

However, I found that wp_get_word_count_type(), introduced in WordPress 6.2, belongs to the l10n category. Therefore, in ebc1d03, I have taken the following actions:

  • Merge lib/experimental/formatting.php into lib/experimental/l10n.php
  • Rename phpunit/formatting-test.php to phpunit/l10n-test.php
@talldan
Copy link
Contributor

talldan commented Feb 27, 2023

Thanks for all your work on this, tests are green so I'll merge it 👍

@talldan talldan merged commit 002be81 into trunk Feb 27, 2023
@talldan talldan deleted the add/block-post-time-to-read branch February 27, 2023 09:00
@github-actions github-actions bot added this to the Gutenberg 15.3 milestone Feb 27, 2023
@bph
Copy link
Contributor

bph commented Mar 7, 2023

I see that it was merged into the milestone 5.3 but I can't find it in the 5.3 RC1 changelog. Does this need to be backported to the Gutenberg RC or am I overlooking something? @richtabor @talldan ?

@t-hamano
Copy link
Contributor Author

t-hamano commented Mar 7, 2023

@bph
Perhaps it is hard to find because it is classified in the "Various" section.

changelog

@bph
Copy link
Contributor

bph commented Mar 7, 2023

Thank you so much! @t-hamano

@bph
Copy link
Contributor

bph commented Mar 8, 2023

@t-hamano thank you for all the hard work going through the various iterations. It's a great block.
I think it works well without the prefix and suffix complications.
I used it together with a paragraph block in my post template block and via the row block is displays fine after I added a block class and a custom CSS.
Once the design tools, specifically the typography controls are added it, is quite flexible.
Screenshot 2023-03-08 at 16 30 14

@richtabor richtabor added the [Block] Time to Read Affects the Time to Read Block label Mar 8, 2023
@t-hamano
Copy link
Contributor Author

I have opened a ticket to add the wp_word_count() function implemented in this PR to the core:
https://core.trac.wordpress.org/ticket/57987#ticket

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Block] Time to Read Affects the Time to Read Block Needs User Documentation Needs new user documentation New Block Suggestion for a new block