ReadMarker helps visitors understand and control their reading experience. Show estimated reading time and word count, add reading progress, and let readers adjust text size and reading width.
Configure automatic output or place reading information yourself with shortcodes and the ReadMarker block. All features are free, with no account or paid upgrade required.
Progress, Reader Controls, and Reading Position Memory require JavaScript. Themes must include the standard WordPress footer hook for their scripts to load.
By default, ReadMarker shows reading time before the content of individual posts, using the Simple style and 200 WPM. Word count, progress, Reader Controls, and Reading Position Memory are off. Pages and other public content types can be enabled in Display Rules.
The ReadMarker admin menu contains:
In ReadMarker Settings, choose whether reading information appears before or after content, in a Custom Selector target, or only where you place it manually. Choose a reading-information style and whether to show word count.
Enable Reading Progress separately and choose a display mode. Top Bar is the default selection. Fixed progress displays are separate from automatic reading-information placement; choosing Manual only does not disable them. Inline Reading Progress follows the automatic placement setting instead.
For a starting configuration, confirm and apply a preset. Save any other pending edits first. You can adjust the saved settings afterward.
Reset to Defaults restores the global settings. It does not delete individual post overrides or clear browser-saved reader preferences and reading positions.
Choose one of these twelve displays in ReadMarker Settings:
Progress follows the reader’s position in the article. Scrolling backward updates the display accordingly. Remaining time and Countdown are scroll-based estimates, not timers. Estimated Finish Time updates with reading progress rather than ticking continuously.
Inline Reading Progress requires automatic reading information and Reading Progress to be enabled. Before content places it at the beginning inside the article wrapper; After content places it at the end. Custom Selector uses the configured target. Manual only prevents automatic inline output. Progress shortcodes and blocks can still be placed explicitly.
Progress indicators use accessible labels and progressbar semantics where appropriate, without announcing every update. Display styles include reduced-motion and forced-colors support.
ReadMarker Settings includes six presets, in this order:
Presets change automatic reading-information visibility, word-count visibility, placement, progress activation, and the selected progress display. They preserve WPM, content-type rules, reading-information style, progress color and height, selector text, Reader Controls, position memory, and per-post overrides.
The Active label reflects the saved settings that a preset controls. Changing one of those values can remove the match; changing an unrelated setting does not. Applying a preset requires confirmation.
Optional Reader Controls provide a Reading Options button with Text Size, Reading Width, and Reset Preferences. Text size ranges from 80% to 140%; width ranges from 80% to 120%. Both default to 100%. Width remains limited by the surrounding theme layout.
Place controls above the article, below it, or with reading information. If reading information is absent, With Reading Info falls back above the article. Choose desktop and mobile visibility and whether the panel initially opens collapsed or expanded.
Readers use normal buttons and keyboard navigation. Escape closes the panel and returns focus to Reading Options. Clicking outside can close it without taking focus from another control. The button shows non-default preferences; panel open/closed state is not saved.
Preferences are saved in browser local storage and contain only a record version, text size, and reading width. If storage is unavailable, controls still work for the current page. Reset Preferences restores 100% for both values. Saved preferences still apply when the interface is hidden by its desktop/mobile setting.
Presentation changes refresh reading progress. Word count, WPM, and total estimated reading time do not change. Theme-specific typography and content added after page initialization may not scale uniformly.
Reading Position Memory is optional and off by default. It stores an article identifier, progress fraction, update time, and record version in browser local storage, scoped to the site and article. It does not create server-side reading history.
A saved position at or beyond 10% can offer Continue and Dismiss on a later visit. Continuing requires a click; ReadMarker does not automatically scroll on page load. Dismiss leaves the saved position available for a future visit. Completing an article removes its saved position. Records older than 30 days are ignored and removed when revisited.
Browser storage can be blocked or cleared. If it is unavailable, the page remains usable without position memory.
Open ReadMarker Shortcodes for the reference and Copy buttons. Shortcodes use the current eligible article; they do not accept a post ID.
[readmarker]
Displays reading information using the effective style and visibility settings. If reading time and word count are both hidden, it produces no reading-information output.
[readmarker_time]
[readmarker_time format=”short”]
[readmarker_time format=”long”]
The default is short. Long format includes the reading-time label.
[readmarker_words]
[readmarker_words label=”true”]
[readmarker_words label=”false”]
The label is shown by default. Use false for the number alone.
[readmarker_progress]
[readmarker_progress show_percentage=”true”]
[readmarker_progress show_percentage=”false”]
The percentage is shown by default. This shortcode does not enable a fixed progress display or position memory.
[readmarker_remaining]
[readmarker_remaining format=”natural”]
[readmarker_remaining format=”short”]
[readmarker_remaining format=”clock”]
[readmarker_remaining format=”detailed”]
Natural is the default. Clock uses a time display; the other formats provide different text representations of the estimate.
Unsupported attributes are ignored and invalid values use safe defaults. Explicit shortcodes can work when automatic reading information is disabled, including a per-post Disable ReadMarker selection. Content-type rules and protected contexts still apply. Reading-information shortcodes suppress duplicate automatic reading information.
Progress and remaining-time shortcodes require an article rendered through the normal WordPress content flow. Arbitrary template locations or late insertion outside that flow may not provide a usable article target.
Insert the ReadMarker block (readmarker/readmarker) from the Widgets category. Its content types are Reading Time, Word Count, Progress, Remaining Time, and Combined.
The editor preview is illustrative. The published block is rendered from the current article and follows the same eligibility and progress requirements as shortcodes.
Select which public content types can use ReadMarker. Posts are enabled by default; pages and public custom post types are optional. Attachments and non-public content types are excluded.
Automatic output is limited to the main article on its individual page. It is excluded from archives, excerpts, feeds, previews, password-locked content, admin pages, REST/JSON and AJAX responses, and secondary queries such as related-post lists. Individual overrides cannot bypass these protections.
Eligible content has a ReadMarker panel in the editor:
Overrides do not enable globally disabled features. Explicit shortcodes and blocks remain available subject to Display Rules. Custom Selector overrides use the same shared selector configured globally.
Choose Custom Selector as the automatic position to place output inside a matching page element. Set Target CSS Selector in the Advanced section of ReadMarker Settings. This shared field is also available for per-post Custom Selector placement, even when the global position is Before or After content.
Use a valid CSS selector for an element supplied by your theme, such as .single-post .post-header. ReadMarker appends output to the first matching element without replacing its contents. An empty, invalid, or missing target produces no fallback placement.
The target normally needs to exist when the page initializes. JavaScript and the theme’s WordPress footer hook are required. Reader Controls use their own placement setting rather than this selector.
ReadMarker uses no analytics, telemetry, cookies, external APIs, remote reporting, or server-side reading history. Global configuration and per-post overrides are stored in the WordPress database.
Reader Controls preferences and optional reading-position records stay in browser local storage as described above. They are not sent to a ReadMarker service. Clipboard actions on the Shortcodes page copy text locally without storing or sending it.
Uninstalling ReadMarker retains global settings and per-post overrides for a later reinstall. It does not delete content or clear browser-saved reader preferences and reading positions.
Estimates use saved article text. Content generated by shortcodes, dynamic blocks, or reusable/synced content is not expanded for word counting. Images do not add reading time. Word counting is primarily English-oriented, and estimates are not measurements of an individual reader’s speed.
ReadMarker wraps the article for progress-related features. Themes relying on direct-child selectors or special wide-block layouts may need compatibility checks. Missing or ambiguous article targets disable the enhancement instead of choosing an unrelated element.
ReadMarker was previously named ReadFlow. Existing readflow shortcodes and readflow/readflow blocks remain supported; use the ReadMarker names for new content. Global settings, per-post overrides, and browser-saved preferences and positions retain their original storage identifiers. No data migration is required.
The previous readflow_loaded and readflow_can_display hooks, ReadFlow JavaScript interfaces, and readflow:placement-ready, readflow:content-presentation-changed, and readflow:progress events remain supported. New integrations should use the corresponding ReadMarker/readmarker names and subscribe to one event name rather than both.
The plugin uses PHP, JavaScript, and CSS without a build step. Settings defaults and validation are centralized. An internal schema version supports legacy migrations; current settings are not rewritten on every read. Future-version settings are read compatibly without automatic downgrading. Explicit saves and resets use the installed schema.
Admin changes require the existing capability and nonce checks. Integrations should preserve Display Rules and per-post protections rather than bypassing them.
For targets added after initialization, window.ReadMarker.placement.retry() explicitly retries Custom Selector placement. It returns true when output is already placed or placement succeeds, and false otherwise. Alternatively, dispatch readmarker:placement-ready on document to request a retry after adding the target. Repeated retries do not duplicate output; there is no automatic polling.
Reader Controls emits a lightweight DOM CustomEvent after changed preferences are applied:
document.addEventListener('readmarker:content-presentation-changed', function () {
// React to ReadMarker article presentation changes.
});
Its detail contains only reason: reader-controls or reset, with no user or article data. Unchanged values do not emit it. Storage failure does not prevent the event. Listening is optional; the existing progress system already refreshes in response.
Run tools/package.ps1 from PowerShell to build .release/readmarker.zip. The package includes only the runtime PHP, block metadata/editor script, local assets, translations, readme, and uninstall handler. Tests, tools, reports, local configuration, and generated artifacts remain in the development tree and are excluded from the ZIP.
With Plugin Check installed, run its normal checks against the extracted ZIP before release. For static checks without a runtime drop-in, use wp eval-file tools/plugin-check.php readmarker. Replace readmarker with an extracted package directory to audit that package. This helper does not replace browser/runtime compatibility testing.
The PHP CLI suite uses the surrounding WordPress core with in-memory fixtures. Run it from this plugin directory within a WordPress installation:
php tests/display-test.php
This includes the calculator and other PHP regression suites. It does not connect to the site’s database or change saved settings.
Run every JavaScript suite with Node.js. In PowerShell:
Get-ChildItem tests/*-test.js | ForEach-Object {
node $_.FullName
if ($LASTEXITCODE -ne 0) { throw "JavaScript test failed" }
}
JavaScript tests use DOM doubles. They do not replace real-browser checks of layout, keyboard behavior, clipboard permissions, or theme compatibility. Test those separately on a local or staging site.