Description
Semantic Journey answers questions about your content that conventional analytics answers badly or not at all: what does this content experience look like for real readers, and did they reach the actions that matter to you? Not how many events fired, how long sessions lasted, or how you compare to a benchmark.
It is a plain-language, privacy-first alternative to conventional analytics for editorial teams, built around a fixed contract:
- Semantic, not mechanical. “Readers reached the end”, never “scroll depth exceeded 80%”.
- Understandable without training. No analytics vocabulary, no dashboards that require interpretation skills.
- Outcome-first language. Progress, completion, confidence, clarity, friction. Never metrics, events, rates, or funnels.
- Privacy-first by design. No personal data, no identifiers, no cookies, no user tracking, nothing sent to third parties.
- Aggregate-only signals. No sessions, no individuals, no cross-page journeys, no behavioral profiling.
- Liftable by default. Every module is self-contained and works independently of any other plugin.
Semantic Journey works on any public post type, not only posts and pages: products, portfolio items, or any custom post type your site uses.
Reader Progress (module 1)
The reference implementation of the contract above. Reader Progress reports four fixed milestones for each piece of content:
- Started Reading. The reader began engaging with the main content.
- Reached the Middle. The reader progressed through roughly half of the content.
- Read Most. The reader consumed the large majority of the content (more forgiving than strict completion).
- Reached the End. The reader reached the conclusion.
Detection is content-relative, using IntersectionObserver against the primary content container, never scroll events, scroll percentages, time-on-page, or mouse movement. Milestones fire at most once per page view and are recorded as counts only: no per-event timestamps, no session or user identity of any kind.
Decision Point (module 2)
A Decision Point marks the moment a reader reached a site-owner-defined action: a “Buy Now” button, a survey link, a phone number. Unlike Reader Progress’s four fixed milestones, Decision Point labels are yours to define, and a Decision Point can be reached more than once per page view since each click is a genuine, separate signal.
Four ways to mark a Decision Point, in order of precedence:
- A
data-sj-decision="Label"attribute added to any element, for precise control from your theme or page builder. - Phone number links (
tel:), email links (mailto:), and text message links (sms:), all detected automatically with no configuration. - An admin-defined CSS selector rule (Settings > Decision Point), matching any element, not only links. This is the option for AJAX-submitted forms, Add to Cart buttons, or anything a page builder generates without a real link underneath it.
- An admin-defined URL pattern rule (Settings > Decision Point), for marking real links by address without touching a template.
Decision Point data appears as additional columns on the same Reports screen as Reader Progress, and in the same CSV export, built dynamically from whichever labels actually have data in the selected time window.
Reports
A dedicated Reports screen shows, for any content item, how many readers started, reached the middle, read most, or reached the end, over a 7/30/90-day window, plus a column for each Decision Point label with data in that window, with search, column sorting, and a CSV export. The four Reader Progress columns use plain-language milestone names; there are no rates, percentages, or scores to interpret.
Copy prompt for your LLM
The Reports screen can build a plain-text summary of exactly what is currently displayed (the full filtered set, not just the current page) for you to paste into an LLM of your choice, if you want a plain-English interpretation of the counts. This plugin does not send this text anywhere itself, there is no outbound link and no third-party integration; it copies to your clipboard only, and where you paste it afterward is entirely your own choice. The built-in instructions ask the LLM not to invent rates or percentages and not to assert a definite cause for any pattern, matching this plugin’s own approach to the same data.
On the post editor
A small sidebar box on the post/page edit screen (and any other trackable post type) confirms whether Reader Progress and Decision Point are recording for that piece of content, showing 30-day counts for each, with a link straight to the filtered Reports screen. Read-only, no fields to fill in.
On the Posts and Pages list, and the Dashboard
A Semantic Journey column on the Posts/Pages list table (and any other trackable post type) gives an at-a-glance summary without opening each item. A small Dashboard widget shows the top 5 pieces of content by readers reaching the end, over the last 7 days.
Privacy and external services
This plugin does not send any data to third-party services. All data collected by Reader Progress stays in your own WordPress database, in a dedicated table, as aggregate daily counts. Nothing is shared externally, and no cookies or personal identifiers are used at any point.
For developers
Other plugins can integrate with Semantic Journey through a small, stable public API (see includes/functions.php):
semantic_journey_is_module_enabled( string $module, $context = null ): boolsemantic_journey_reader_progress_get_summary( int $content_id, int $days = 30 ): arraysemantic_journey_decision_point_get_summary( int $content_id, int $days = 30 ): array- the
semantic_journey_module_enabledfilter, for applying your own licensing or per-post rules on top of the site-level toggle.
Semantic Journey itself has no concept of licensing, plans, or host-specific gating; that interpretation belongs entirely to the integrating plugin.
Screenshots


Installation
- Upload the
semantic-journeyfolder to/wp-content/plugins/, or install it via Plugins > Add New > Upload Plugin. - Activate Semantic Journey through the Plugins menu. Activation creates the
wp_reader_progress_dailyandwp_decision_points_dailytables and schedules their daily retention-purge events. - Go to Semantic Journey > Settings to confirm Reader Progress and Decision Point are enabled, set your retention windows, and optionally add Decision Point URL pattern rules.
- Visit Semantic Journey > Reports to see reader activity once readers have visited your content. No further configuration is required; Reader Progress and automatic tel:/mailto:/sms: link detection both work immediately after activation.
FAQ
-
Why did a reader’s milestone or click not get recorded?
-
The most common reason is that JavaScript or a required browser feature was unavailable, described elsewhere in this FAQ. One other case: each submission carries a short-lived security token, similar to how WordPress protects its own forms, which identifies nothing about the visitor but expires roughly a day after the page loaded. If a browser tab is left open far longer than that before a reader reaches a milestone, that one signal is silently not recorded rather than recorded against an expired token. This is intentional: a missing signal in that rare case is preferable to weakening the same check for every other visitor.
-
Does the Copy prompt for your LLM feature send my data anywhere?
-
No. It builds a plain-text summary and copies it to your clipboard only. There is no outbound link, no API call, and no third-party integration built into this feature. Whether you paste that text into an LLM afterward, and which one, is entirely your own separate choice.
-
Does this replace Google Analytics or a similar tool?
-
No. It answers a narrower, editorial question and is not a general-purpose analytics platform. It has no sessions, no user identity, and no cross-page journeys by design.
-
No. It stores no identifiers of any kind, and no data is shared with any third party.
-
What happens if a reader has JavaScript or IntersectionObserver disabled?
-
The module silently disables itself for that page view. No partial or misleading data is ever recorded.
-
How long is data kept?
-
90 days by default, on a rolling basis, configurable in Semantic Journey > Settings. Older rows are purged automatically once a day.
-
What happens to my data if I uninstall the plugin?
-
By default, nothing is removed, in case you are reinstalling or upgrading. If you want your data removed on uninstall, enable “Remove data on uninstall” in Settings first.
-
Can a Decision Point be reached more than once by the same visitor?
-
Yes. A Decision Point is a click on an action, not a reading milestone, so each click is counted, matching how a conversion or goal click is normally understood. This is a deliberate difference from Reader Progress’s four milestones, which each fire at most once per page view.
-
URL pattern rules only match real links (an element with an href). Many buttons, especially ones generated by page builders or ones that submit a form via AJAX, are not links at all. For those, use a CSS selector rule instead (Settings > Decision Point), which matches any element, or add a
data-sj-decision="Label"attribute directly to the button. If you configured a CSS selector rule and it still is not firing, check your browser’s console: an invalid selector is reported there rather than failing with no explanation at all. If the element is a phone number, email, or text message link, no rule is needed at all, those three are detected automatically. -
Does this work on a WordPress multisite network?
-
Yes. Activating network-wide sets up every existing site, and any site created afterward on a network-active install is set up automatically. Each site’s data stays separate; there is no cross-site rollup in the free version.
-
Does this affect my privacy policy?
-
Semantic Journey adds a short, accurate entry to Tools > Privacy > Policy Guide describing what it does: it does not collect personal data of any kind. You can include this text in your site’s privacy policy as-is or edit it to match your own wording.
Reviews
There are no reviews for this plugin.
Contributors & Developers
“Semantic Journey” is open source software. The following people have contributed to this plugin.
ContributorsTranslate “Semantic Journey” into your language.
Interested in development?
Browse the code, check out the SVN repository, or subscribe to the development log by RSS.
Changelog
1.7.1
- Email links (mailto:) and text message links (sms:) now join phone number links at the automatic, zero-configuration Decision Point detection tier.
1.7.0
- Added CSS selector rules to Decision Point (Settings > Decision Point): a fourth way to mark a Decision Point that works on any element, not only links. Closes a real gap for AJAX-submitted forms, Add to Cart buttons, and anything a page builder generates without a real href underneath it.
- Invalid CSS selector rules are now reported in the browser console rather than failing silently.
1.6.4
- Replaced an inline closure used to sanitize a settings checkbox with WordPress’s own rest_sanitize_boolean(), also fixing an edge case where the literal string “false” would have been treated as enabled.
1.6.3
- Fixed a CSV formula injection risk (CWE-1236) in the Reports CSV export: post titles and Decision Point labels are now protected against being interpreted as spreadsheet formulas when the exported file is opened. Found proactively, not from an external report.
- Added a UTF-8 BOM to the CSV export so non-ASCII characters display correctly in Excel.
1.6.2
- Both REST endpoints (Reader Progress, Decision Point) now require a nonce, verified server-side, in addition to remaining reachable by anonymous visitors as intended. This closes a gap where either endpoint could previously be scripted against directly with no prior reconnaissance at all. Identifies nothing about the visitor and requires no cookie or login state.
- Fixed a sanitization gap: a setting’s array keys were only cast to strings rather than sanitized.
- Corrected the Contributors field in this readme.
1.6.1
- Fixed an escaping issue in the Posts list column flagged by Plugin Check: output is now escaped once, correctly, at the actual point of output.
- Documented one read-only display-filter nonce warning introduced by the Copy prompt feature’s search handling.
1.6.0
- Added a branded admin page header shared across Reports and Settings.
- Added “Copy prompt for your LLM” on Reports: builds a plain-text summary of the currently filtered report for you to paste into an LLM of your choice. Copy only; this plugin sends nothing anywhere itself.
- Accessibility fixes found in a dedicated sweep: corrected two color combinations that measured below WCAG AA contrast thresholds, fixed a hidden field that was reachable by keyboard despite being visually and semantically hidden, added heading semantics and aria-current where state was previously conveyed by CSS class alone, and fixed a redundant image description that caused a double announcement.
- Updated Plugin URI and Support URI to semanticjourney.com.
1.5.1
- Fixed a bug where any module toggle not already known to the Settings screen was silently discarded on every write to the module-enabled setting, not just from the Settings form itself. This could have prevented a future module’s toggle from ever persisting.
1.5.0
- Fixed a scope mismatch: Reports and CSV export now cover every trackable post type (matching what the front-end script actually tracks), not just posts and pages. Sites with custom post types were having activity recorded but not shown.
- The editor box now shows Decision Point alongside Reader Progress.
- New Semantic Journey column on the Posts/Pages list table (and any other trackable post type).
- New Dashboard widget: top 5 content items by readers reaching the end, last 7 days.
- Multisite: network-wide activation now sets up every site; a site created later on a network-active install is set up automatically.
- Added a privacy policy content declaration under Tools > Privacy > Policy Guide.
1.4.1
- Addressed the first WordPress.org Plugin Check pass: documented justifications for read-only display-filter nonce warnings, the CSV export’s file-stream handling, and direct-query caching warnings, and removed an unused Domain Path header. No functional change.
1.4.0
- Added Decision Point, module 2 of Semantic Journey: site-owner-defined action clicks such as a Buy Now button, a survey link, or a phone number, marked via a data-sj-decision attribute, automatic tel: link detection, or an admin-defined URL pattern rule.
- Decision Point data appears as additional columns on the existing Reports screen and in CSV export, alongside the four Reader Progress milestones.
- The Reports screen’s underlying query was restructured so a post with only Decision Point activity and no Reader Progress data still appears; it would previously have been hidden.
1.3.0
- Added an editor sidebar meta box (Reader Progress) on the post/page edit screen, showing whether Reader Progress is recording for the current post and its 30-day milestone counts, with a link to the filtered Reports screen. Read-only; no fields, no derived score.
1.2.0
- Internal only, no user-facing change: retrofitted to the HDUK WordPress.org Plugin Development Standards v1.0. Classes renamed for prefix-length compliance, database layer consolidated into a single class with a private table getter, every direct database query documented with a phpcs:ignore justification, and the semantic_journey_module_enabled filter renamed from its earlier slash-namespaced form.
- Table name (wp_reader_progress_daily) is unchanged; data and settings from 1.1.0 carry over automatically.
1.1.0
- Added the Reports screen (Semantic Journey > Reports): a standard, sortable, searchable admin table of Reader Progress milestone counts per content item, with 7/30/90-day filters and CSV export.
- Reader Progress write path rewritten to use fully static, per-branch SQL for each milestone, so no column name is ever interpolated into a query.
- Menu restructured: Reports and Settings now live under a single top-level Semantic Journey menu.
1.0.0
- Initial standalone release. Semantic Journey extracted from the CQIP plugin into its own framework, with no dependency on any other plugin.
- Reader Progress rebuilt on a dedicated wp_reader_progress_daily table (previously post meta), with atomic increment writes and a configurable retention-purge cron.
- New generic semantic_journey_module_enabled filter allows any host product to integrate without a hard dependency.
- New Settings screen for module toggles, retention window, and uninstall data-removal preference.
