Version 3.1.0
June 12, 2026
Added
- GraphQL support. A
readTimefield is now available on entry types in the GraphQL schema, returning aReadTimeobject type withseconds,minutes,hours, andhumanReadable. The resolver delegates to the existing read time service, so GraphQL and Twig report the same read time for a given entry, including content stored in Matrix, Neo, Vizy, and CKEditor fields. An optionalshowSecondsargument controls thehumanReadableoutput (#28). - An
outputLocalesetting to control the language of the human-readable read-time string (#20). Leave it empty to follow the current application language (unchanged default), set it tositeto format each element in its own site's language (consistent across CP, front-end, andresave/entrieson multi-site installs), or set a specific locale ID (e.g.de-DE) to force one language everywhere. Configurable in the plugin settings or viaconfig/read-time.php. Only the human-readable string is affected; numeric values are unchanged. - A
minimumReadTimesetting (in whole minutes). When greater than0, read times are rounded up to at least this many minutes, so sub-minute and empty content displays as e.g. "1 minute" instead of "less than a minute". Defaults to0, which preserves the existing behaviour. The floor is applied once when the service builds theTimeModel, so it is reflected consistently acrosshuman(),__toString(),seconds()/minutes()/hours(), the Twig function, and the Twig filter — and any other consumer of the returnedTimeModel. Can be set inconfig/read-time.php(#26). - Added comprehensive Pest test coverage for TimeModel, ReadTime service, and Settings model.
Fixed
- HTML markup is now stripped before content is word-counted, so read-time estimates are no longer inflated by tag names, attribute names, and attribute values such as URLs (#14). The fix is applied centrally in the word counter, so both the
readTimefilter (raw strings) andreadTime()(field-walking over rich-text fields like CKEditor) are corrected. Tags are replaced with whitespace (not removed) so words across tag boundaries stay separate, and HTML entities are decoded so counts as whitespace and&isn't counted as a word. Plain (non-HTML) text counts are unchanged. - The settings template referenced the wrong config filename (
reading-time.php) and translation category (reading-time); both are nowread-time, so the config-override warning points at the correct file.
Version 3.0.0
June 12, 2026
Craft 5 release. The 2.x line remains the Craft 4 line.
Added
- Craft 5 support. This release requires Craft CMS 5.0.0+ and PHP 8.2+ (#29).
- Vizy field support. Rich-text content is counted and Vizy blocks' nested fields are walked recursively.
- CKEditor field support. The editor's rich-text content is counted, plus the content of any entries embedded inside the field.
- A
RegisterFieldHandlersEventso other plugins/modules can add read time support for further field types. - An example config file at
config/read-time.php.
Changed
- Full rewrite. The counting and field-walking logic now lives in a dedicated
jalendport\readtime\services\ReadTimeservice, registered as a plugin component; the Twig extension is a thin wrapper that delegates to it. The nestedif/elsefield walking has been replaced with a single recursive routine that dispatches each field to a small, per-field-type handler, so adding a new field type is a localised change. - Matrix content is now counted correctly on Craft 5. Matrix was "entrified" in Craft 5 — blocks are now
craft\elements\Entryelements with their own field layouts — and their nested fields are walked accordingly. The previous code referenced the removedcraft\elements\MatrixBlockclass and silently miscounted entrified Matrix content. - Neo, Vizy, and CKEditor are treated as optional, soft dependencies — the plugin loads and computes read time on sites that don't have them installed.
- Modernised to the current Craft 5 plugin spec and Yii guidelines:
declare(strict_types=1), typed properties and signatures, aconfig()method for component registration, and a settings config model.
Removed
- Super Table support. Super Table does not exist for Craft 5, so it has been removed from the Craft 5 code path. Super Table support remains in the Craft 4 (2.x) line.
- The committed
composer.lockfile (a plugin must not commit a lock file); it is now ignored.
Version 2.1.0
June 12, 2026
Added
- Neo field support.
readTimenow calculates read time for content stored in Neo fields, both when a Neo field is passed directly to the function/filter and when an entry containing a Neo field is passed (#15). Original contribution by Matt Jones (@icreatestuff) in #21. Neo is treated as an optional, soft dependency — the plugin continues to load and compute read time on sites without Neo installed.
Version 2.0.0
June 12, 2026
Stable Craft 4 release.
Fixed
- Calling
readTimeon an entry containing Matrix or Super Table fields no longer throws a Twig error on Craft 4. The deprecatedFieldLayout::getFields()calls in the nested Matrix, Super Table, and Matrix-in-Super-Table loops are nowgetCustomFields()(#25). - Widened the exception handling in
readTimeFunction()to also catchcraft\errors\InvalidFieldException(thrown bygetFieldValue()), which previously could surface as an uncaught Twig error.
Version 2.0.0-beta.1
March 7, 2023
Added
- Initial Craft 4 release
Version 1.6.0
November 16, 2019
Transfer of ownership 👀
Version 1.5.0
February 21, 2019
Added
- Matrix field support
Version 1.4.0
July 31, 2018
Added
- Super Table support 🎉
Version 1.3.0
June 22, 2018
Added
- Format the time as a
DateInterval - Output the total seconds, minutes and hours
Changed
- Both the filter and function now return a
TimeModel
Version 1.2.1
June 19, 2018
Fixed
readTime()function now includes matrix fields when calculating the read time
Version 1.2.0
June 18, 2018
Added
- Calculate the read time of the whole entry based on it's field layout
Version 1.1.0
June 6, 2018
Changed
- Plugin name changed to
Read Time
Version 1.0.0
June 6, 2018
Added
- Initial release