YAOTW Reading Time
A WordPress must-use plugin that adds a "Reading time" Elementor Dynamic Tag, plus a shortcode fallback. No dependencies, nothing stored in the options table.
by YAOTW · github.com/mroaydryao/yaotw-reading-time · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/mroaydryao/yaotw-reading-time/archive/refs/heads/main.zipA WordPress must-use plugin that adds a "Reading time" Elementor Dynamic Tag, plus a shortcode fallback. No dependencies, nothing stored in the options table.
Installation
Drop yaotw-reading-time.php straight into /wp-content/mu-plugins/.
wp-content/
mu-plugins/
yaotw-reading-time.php
Must-use plugins are only loaded from the root of mu-plugins, never from a subdirectory. There is no activation step and no way to deactivate it from the admin: the file is live as soon as it is present.
Create the mu-plugins directory if it does not exist yet.
Usage
Dynamic Tag (Elementor Pro)
On any text field (Heading, Text Editor, Icon Box, Post Info and so on), click the database icon, then YAOTW → Temps de lecture.
Works inside a Single Post template and inside a Loop Item: the tag resolves the post currently being iterated.
The tag exposes a single setting, Mots par minute (default 200, the average French reading speed). The label is in French, matching the editor language of the sites this plugin was written for. Change the esc_html__() strings, or load a translation against the yaotw-reading-time text domain.
Prefix, suffix and fallback are not re-implemented: use Elementor's own Advanced section on the tag (Before / After / Fallback). Declaring controls with those IDs collides with \Elementor\Core\DynamicTags\Tag, which applies them around the tag output on its own, and the text ends up printed twice.
The tag renders the bare number, so Before: "Reading time: " and After: " min" give Reading time: 12 min. When the post has no countable content the tag renders nothing, which lets Elementor fall back to the Fallback value.
Shortcode
[yaotw_reading_time]
[yaotw_reading_time wpm="220" before="Reading time: " after=" minutes"]
[yaotw_reading_time post_id="42"]
In PHP
$minutes = yaotw_reading_time_get(); // current post, 200 wpm
$minutes = yaotw_reading_time_get( 42, 220 ); // post 42, 220 wpm
How caching works
The word count is stored in post meta (_yaotw_reading_time_words), not the number of minutes. That way the "words per minute" setting stays editable in Elementor without regenerating anything.
The meta is written the first time each post is read, so no migration script is needed. It is deleted on save_post and on elementor/editor/after_save.
Filters
yaotw_reading_time_content
Changes the text being analysed. Useful when the content does not live in post_content (ACF fields, Elementor-only content).
add_filter( 'yaotw_reading_time_content', function( $content, $post_id ) {
if ( '' === trim( $content ) ) {
$content = get_post_meta( $post_id, '_elementor_data', true );
}
return $content;
}, 10, 2 );
yaotw_reading_time_minutes
Adjusts the final result, for instance to add padding for image-heavy posts.
add_filter( 'yaotw_reading_time_minutes', function( $minutes, $count, $post_id, $wpm ) {
return $minutes;
}, 10, 4 );
Known limitation
The word count reads post_content. For a post built with Elementor, that field holds the rendered HTML and the result is reliable. For fully dynamic content (ACF, widgets with no static text), post_content may be empty and the tag returns the fallback value. Use the yaotw_reading_time_content filter in that case.
CSS
The shortcode outputs a <span class="yaotw-reading-time">. The Dynamic Tag outputs plain text, so style the widget that carries it.
.yaotw-reading-time {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 0.875rem;
opacity: 0.75;
}
Requirements
- WordPress 6.0+
- PHP 7.4+
- Elementor 3.5+ for the Dynamic Tag (the
elementor/dynamic_tags/registerhook replaces the olderregister_tags) - Elementor Pro to select the tag in the UI
The shortcode and the PHP function work without Elementor.
License
GPL-2.0-or-later