{"id":328423,"date":"2026-06-21T08:11:48","date_gmt":"2026-06-21T08:11:48","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/cqi-referrer-attribution\/"},"modified":"2026-06-22T01:30:06","modified_gmt":"2026-06-22T01:30:06","slug":"cqi-referrer-attribution","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/cqi-referrer-attribution\/","author":23508691,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.4.2","stable_tag":"trunk","tested":"7.0","requires":"6.0","requires_php":"7.4","requires_plugins":null,"header_name":"CQI Referrer Attribution","header_author":"H D Fraser MSc","header_description":"Know where every visitor came from, including AI assistants like ChatGPT","assets_banners_color":"425167","last_updated":"2026-06-22 01:30:06","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/referrerattribution.com\/","header_author_uri":"https:\/\/thecontentframework.com\/","rating":0,"author_block_rating":0,"active_installs":0,"downloads":51,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.3.1":{"tag":"1.3.1","author":"hdfraser","date":"2026-06-21 08:11:30"}},"upgrade_notice":{"1.2.1":"<p>The Dashboard&#039;s Conversions and Conversion Rate cards have been replaced with AI Traffic Sessions. Both removed cards always showed zero on every site; this plugin has never included conversion tracking.<\/p>","1.2.0":"<p>If you previously enabled Delete on uninstall, re-check that setting after updating. Earlier versions saved this setting but did not act on it; this version makes it function correctly for the first time.<\/p>","1.0.0":"<p>Initial release.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3580414,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3580414,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3580414,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3580414,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.3.1"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3580414,"resolution":"1","location":"assets","locale":"","width":800,"height":545},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3580414,"resolution":"2","location":"assets","locale":"","width":800,"height":731},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3580414,"resolution":"3","location":"assets","locale":"","width":800,"height":724}},"screenshots":{"1":"Dashboard tab showing summary metric cards and the channel share pie chart.","2":"Reports tab with session log, filters, and CSV export.","3":"Settings tab showing retention, consent, and privacy configuration."}},"plugin_section":[],"plugin_tags":[256047,9067,40006,4131,268178],"plugin_category":[36],"plugin_contributors":[268179],"plugin_business_model":[],"class_list":["post-328423","plugin","type-plugin","status-publish","hentry","plugin_tags-ai-traffic","plugin_tags-attribution","plugin_tags-marketing-attribution","plugin_tags-referrer","plugin_tags-traffic-channels","plugin_category-analytics","plugin_contributors-hdfraser","plugin_committers-hdfraser"],"banners":{"banner":"https:\/\/ps.w.org\/cqi-referrer-attribution\/assets\/banner-772x250.png?rev=3580414","banner_2x":"https:\/\/ps.w.org\/cqi-referrer-attribution\/assets\/banner-1544x500.png?rev=3580414","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/cqi-referrer-attribution\/assets\/icon-128x128.png?rev=3580414","icon_2x":"https:\/\/ps.w.org\/cqi-referrer-attribution\/assets\/icon-256x256.png?rev=3580414","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/cqi-referrer-attribution\/assets\/screenshot-1.png?rev=3580414","caption":"Dashboard tab showing summary metric cards and the channel share pie chart."},{"src":"https:\/\/ps.w.org\/cqi-referrer-attribution\/assets\/screenshot-2.png?rev=3580414","caption":"Reports tab with session log, filters, and CSV export."},{"src":"https:\/\/ps.w.org\/cqi-referrer-attribution\/assets\/screenshot-3.png?rev=3580414","caption":"Settings tab showing retention, consent, and privacy configuration."}],"raw_content":"<!--section=description-->\n<p>Most analytics plugins guess where your traffic came from by running a script in the visitor's browser, after the page has already loaded, and after any ad blocker or privacy extension has had a chance to block it. CQI Referrer Attribution classifies every visit on the server, before the page is even sent, so the data is complete and the plugin adds no client-side JavaScript, no extra request, and no Core Web Vitals penalty.<\/p>\n\n<p>It also answers a question most attribution tools still miss: how much of your traffic is coming from AI assistants. ChatGPT, Gemini, Perplexity, Claude, Copilot, and a growing list of others now send real visitors. This plugin classifies that traffic as its own channel, not lumped into Direct or Referral where it disappears.<\/p>\n\n<p>Nine channels are detected automatically: AI Tools, Organic Search, Social Media, Email, Paid Search, Paid Display, Campaign, Referral, and Direct.<\/p>\n\n<p>This plugin is fully functional with no licence key, trial period, or usage limit of any kind.<\/p>\n\n<p><strong>AI Referrer Taxonomy<\/strong><\/p>\n\n<p>A built-in registry of AI assistant domains is used to classify AI-referred traffic. The default set includes ChatGPT, Google Gemini, Perplexity, Claude, Microsoft Copilot, Grok, Meta AI, and more. Entries can be added, edited, activated, deactivated, deleted, and exported as JSON.<\/p>\n\n<p><strong>Dashboard<\/strong><\/p>\n\n<p>A 30-day summary showing total sessions, session change versus the previous 30 days, AI traffic sessions and their share of total traffic, top channel, and a channel share pie chart.<\/p>\n\n<p><strong>Sessions log<\/strong><\/p>\n\n<p>The full Sessions report supports date range, channel, and source filters, pagination, and CSV export.<\/p>\n\n<p><strong>Consent-aware<\/strong><\/p>\n\n<p>When CQI Consent is active, attribution is only persisted after marketing consent is granted. Without consent, classification runs in memory only and no cookie or database row is written. The plugin operates in permissive mode when CQI Consent is not installed.<\/p>\n\n<p><strong>Privacy by design<\/strong><\/p>\n\n<p>No personal data is stored. Session tokens are HMAC-SHA256 hashes of an anonymized IP address (last octet zeroed) and the current date. Raw IP addresses are never written to disk. Token rotation is daily. The plugin is registered with the WordPress personal data export and erasure framework.<\/p>\n\n<p><strong>Excluded channels<\/strong><\/p>\n\n<p>Any channel can be excluded from the Dashboard summary, the channel share chart, and the Sessions report. This is most useful for removing Direct \/ Unknown from view so reports focus on traffic you can actually attribute and act on.<\/p>\n\n<p><strong>Path exclusions and bot filtering<\/strong><\/p>\n\n<p>A built-in guard silently drops requests to <code>\/robots.txt<\/code>, <code>\/sitemap.xml<\/code>, <code>\/xmlrpc.php<\/code>, <code>\/favicon.ico<\/code>, and other system paths before classification runs. Additional path prefixes can be added in Settings, one per line, to suppress noise from any crawlers or automated probes specific to your site.<\/p>\n\n<p><strong>Public PHP API<\/strong><\/p>\n\n<p>Two functions are available for use in themes and other plugins:<\/p>\n\n<ul>\n<li><code>cqip_attr_get_channel()<\/code>, returns the current visitor's channel slug<\/li>\n<li><code>cqip_attr_get_source()<\/code>, returns the full attribution array<\/li>\n<\/ul>\n\n<p>These function names are intentionally preserved from CQIP Site Services v1.8.0 for backward compatibility on sites migrating from that plugin.<\/p>\n\n<p><strong>Filter and action hooks<\/strong><\/p>\n\n<p>These hooks let other plugins extend this plugin's behaviour. They are not used by this plugin itself; they exist for add-ons such as CQI Referrer Attribution Pro.<\/p>\n\n<ul>\n<li><code>cqi_referrer_attribution_logo_url<\/code> (filter), the mark shown in the admin page header<\/li>\n<li><code>cqi_referrer_attribution_plugin_name<\/code> (filter), the page title shown in the admin page header<\/li>\n<li><code>cqi_ra_session_logged<\/code> (action), fires after each session is recorded, receives the new row's ID and data<\/li>\n<li><code>cqi_ra_admin_tabs<\/code> (action), fires inside the admin page's tab navigation, after the built-in tabs<\/li>\n<li><code>cqi_ra_unknown_tab_handled<\/code> (filter), fires when an unrecognized tab slug is requested, lets an add-on render its own tab body<\/li>\n<li><code>cqi_ra_sessions_view_filters<\/code> (filter), the Sessions report's query filters, before the session log is queried; also applied before CSV export runs<\/li>\n<li><code>cqi_ra_sessions_filter_bar<\/code> (action), fires inside the Sessions filter bar, after the built-in filter fields<\/li>\n<li><code>cqi_ra_sessions_table_header<\/code> (action), fires inside the Sessions table header row, after the built-in columns<\/li>\n<li><code>cqi_ra_sessions_table_row<\/code> (action), fires inside each Sessions table row, after the built-in columns, receives the row object<\/li>\n<li><code>cqi_ra_dashboard_log_id_in<\/code> (filter), restricts Dashboard metrics to a specific list of session row IDs<\/li>\n<\/ul>\n\n<h3>What is CQI?<\/h3>\n\n<p>CQI (Content Quality and Intelligence) is a methodology standard that is followed, not a technology stack. Implementations can exist for static PHP sites, WordPress, page generators, and other document management systems. Its purpose is to encourage structured content that benefits human and machine readers.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>cqi-referrer-attribution<\/code> folder to <code>\/wp-content\/plugins\/<\/code>.<\/li>\n<li>Activate the plugin through the Plugins menu in WordPress.<\/li>\n<li>Go to <strong>Attribution<\/strong> in the WordPress admin menu to view the Dashboard.<\/li>\n<\/ol>\n\n<p>No configuration is required after activation. Classification begins on the next front-end page request.<\/p>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20this%20plugin%20use%20javascript%20to%20track%20visitors%3F\"><h3>Does this plugin use JavaScript to track visitors?<\/h3><\/dt>\n<dd><p>No. Classification is entirely server-side. No tracking scripts are added to the front end.<\/p><\/dd>\n<dt id=\"does%20this%20plugin%20store%20personal%20data%3F\"><h3>Does this plugin store personal data?<\/h3><\/dt>\n<dd><p>No. Session tokens are one-way cryptographic hashes (HMAC-SHA256) of an anonymized IP address and the current date. Raw IP addresses are never stored. Tokens cannot be reversed to identify an individual.<\/p><\/dd>\n<dt id=\"i%20have%20cqip%20site%20services%20installed.%20can%20i%20run%20both%3F\"><h3>I have CQIP Site Services installed. Can I run both?<\/h3><\/dt>\n<dd><p>Not at the same time, if CQIP Site Services has its own Referrer Attribution module active. Both write to the same database tables, since this plugin was extracted from that module and preserves its table and option names for migration compatibility. If <code>CQIP_SS_ENABLE_REFERRER<\/code> is set to <code>true<\/code> in your <code>wp-config.php<\/code>, this plugin detects that and refuses to activate, showing an admin notice with the exact line to add to <code>wp-config.php<\/code> to resolve it. Existing attribution data carries over automatically once the conflict is resolved.<\/p><\/dd>\n<dt id=\"how%20does%20the%20ai%20channel%20work%3F\"><h3>How does the AI channel work?<\/h3><\/dt>\n<dd><p>When a visitor arrives via a referrer that matches an entry in the AI Referrer Taxonomy, the session is classified as the AI Tools channel. The matched platform name (e.g. \"ChatGPT\") is stored as the source. The default taxonomy includes 17 entries and can be edited from the AI Taxonomy tab.<\/p><\/dd>\n<dt id=\"will%20this%20work%20with%20gdpr%20%2F%20uk-gdpr%3F\"><h3>Will this work with GDPR \/ UK-GDPR?<\/h3><\/dt>\n<dd><p>The plugin does not store personal data and is registered with the WordPress personal data export and erasure framework. When CQI Consent is active, attribution is only persisted after marketing consent. As with any tool that processes visitor data, your own legal assessment of your site's practices is advisable.<\/p><\/dd>\n<dt id=\"what%20happens%20if%20a%20visitor%20does%20not%20have%20a%20referrer%3F\"><h3>What happens if a visitor does not have a referrer?<\/h3><\/dt>\n<dd><p>Visits with no referrer and no UTM parameters are classified as the <code>direct<\/code> channel.<\/p><\/dd>\n<dt id=\"can%20i%20remove%20direct%20%2F%20unknown%2C%20or%20any%20other%20channel%2C%20from%20reports%3F\"><h3>Can I remove Direct \/ Unknown, or any other channel, from reports?<\/h3><\/dt>\n<dd><p>Yes. Go to <strong>Attribution &gt; Settings &gt; Excluded channels<\/strong> and check any channels you want removed. Excluded channels are removed from the Dashboard summary cards, the channel share chart, and the Sessions report, including CSV export. This is commonly used to exclude Direct \/ Unknown so reports focus on attributable traffic.<\/p><\/dd>\n<dt id=\"what%20happens%20to%20my%20data%20if%20i%20delete%20the%20plugin%3F\"><h3>What happens to my data if I delete the plugin?<\/h3><\/dt>\n<dd><p>By default, nothing is removed. Your attribution data, settings, and AI taxonomy stay in the database in case you reinstall later. If you want a clean removal, enable <strong>Attribution &gt; Settings &gt; Data and Storage &gt; Delete data on uninstall<\/strong> before deleting the plugin. With that enabled, deleting the plugin permanently removes the attribution log, all plugin settings, and the AI taxonomy. This cannot be undone.<\/p><\/dd>\n<dt id=\"how%20do%20i%20stop%20bot%20probes%20and%20crawler%20noise%20appearing%20in%20the%20session%20log%3F\"><h3>How do I stop bot probes and crawler noise appearing in the session log?<\/h3><\/dt>\n<dd><p>Go to <strong>Attribution &gt; Settings &gt; Path Exclusions<\/strong>. Add one path prefix per line. Any request whose URL starts with a listed path is silently dropped before classification runs. Common entries are <code>\/robots.txt<\/code>, <code>\/sitemap.xml<\/code>, <code>\/feed\/<\/code>, and any path your monitoring tools or uptime checkers hit. The plugin also has a built-in guard that automatically excludes <code>\/xmlrpc.php<\/code>, <code>\/wp-cron.php<\/code>, <code>\/wp-signup.php<\/code>, <code>\/favicon.ico<\/code>, and other WordPress system paths regardless of your exclusion list.<\/p><\/dd>\n<dt id=\"what%20is%20the%20channel%20priority%20order%3F\"><h3>What is the channel priority order?<\/h3><\/dt>\n<dd><p>When more than one signal is present on a session, this priority order applies:<\/p>\n\n<ol>\n<li>UTM parameters (utm_medium determines email, social, paid search, paid display, or campaign)<\/li>\n<li>AI Referrer Taxonomy match<\/li>\n<li>Known search engine referrer (organic search)<\/li>\n<li>Known social platform referrer<\/li>\n<li>Referral (any other external domain with a referrer)<\/li>\n<li>Direct (no referrer, no UTM parameters)<\/li>\n<\/ol><\/dd>\n<dt id=\"how%20are%20paid%20search%20and%20paid%20display%20detected%3F\"><h3>How are Paid Search and Paid Display detected?<\/h3><\/dt>\n<dd><p>Both are detected from the <code>utm_medium<\/code> URL parameter, not from the referrer header. <code>utm_medium<\/code> set to <code>cpc<\/code> or <code>ppc<\/code> is classified as Paid Search. <code>utm_medium<\/code> set to <code>display<\/code> is classified as Paid Display. Any other <code>utm_medium<\/code> value is classified as Campaign.<\/p>\n\n<p>If your paid traffic does not carry UTM parameters, those sessions are classified by referrer instead, typically landing in Organic Search, Referral, or Direct depending on the source. Tagging every paid URL with UTM parameters is required for accurate Paid Search and Paid Display classification.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.4.2<\/h4>\n\n<ul>\n<li>Fixed: panel and card subtitle text (.cqi-ra-panel__sub, .cqi-ra-card__sub) used #9CA3AF on white, measured at 2.54:1 contrast, well short of the WCAG AA 4.5:1 minimum for body text. Changed to #6B7280, the colour already used for secondary text throughout the rest of this stylesheet, which measures 4.83:1.<\/li>\n<\/ul>\n\n<h4>1.4.1<\/h4>\n\n<ul>\n<li>Added: CQI_RA_DB::get_log_row_by_token(), a public method returning the most recent attribution log row for a session token, or null if none exists. Not used by this plugin itself; added for an add-on (CQI Referrer Attribution Pro) that needs to confirm real attribution exists for the current visitor before recording a conversion against it.<\/li>\n<\/ul>\n\n<h4>1.4.0<\/h4>\n\n<ul>\n<li>Added: CQI_RA_DB::get_daily_sessions(), a public method returning session counts grouped by day and channel. Not used by this plugin itself; added for an add-on (CQI Referrer Attribution Pro) building trend charts and reports that need day-by-day data rather than the period summaries CQI_RA_DB::get_dashboard_metrics() already provides.<\/li>\n<\/ul>\n\n<h4>1.3.3<\/h4>\n\n<ul>\n<li>Changed: refreshed the channel share chart's colour palette for the Organic Search, Social Media, Email, Paid Search, Paid Display, Campaign, and Referral channels. The previous set leaned muted and several adjacent slices were too close in hue to tell apart at a glance. AI Tools keeps its existing teal; Direct \/ Unknown stays neutral grey by design.<\/li>\n<\/ul>\n\n<h4>1.3.2<\/h4>\n\n<ul>\n<li>Added: the cqi_ra_sessions_view_filters hook, already applied to the on-screen Sessions report, is now also applied to CSV export. Add-ons that filter the Sessions view (for example, a tag filter) now apply consistently to both the table and the exported CSV. No effect on this plugin's own behaviour; the hook has no listeners unless an add-on is active.<\/li>\n<\/ul>\n\n<h4>1.3.1<\/h4>\n\n<ul>\n<li>Fixed: AI Taxonomy tab. Add, edit, toggle, delete, export, and reset all failed silently in the browser since the admin JavaScript had not been updated when the tab's markup was restyled. The JavaScript now matches the current markup throughout.<\/li>\n<li>Fixed: Reports tab CSV export ignored the on-screen date range and channel filter, since the export button read element IDs that no longer existed in the filter bar. CSV export now uses the same filters shown on screen.<\/li>\n<li>Removed: a leftover Conversions-view branch in the CSV export script, and an unreachable block of JavaScript referencing a white-label save feature that has no corresponding admin UI or AJAX handler in this plugin. Neither had any user-facing effect; both are gone.<\/li>\n<\/ul>\n\n<h4>1.3.0<\/h4>\n\n<ul>\n<li>Added: a set of extension hooks (cqi_ra_session_logged, cqi_ra_admin_tabs, cqi_ra_unknown_tab_handled, cqi_ra_sessions_view_filters, cqi_ra_sessions_filter_bar, cqi_ra_sessions_table_header, cqi_ra_sessions_table_row, cqi_ra_dashboard_log_id_in) for the separate CQI Referrer Attribution Pro add-on. None of these change this plugin's own behaviour; they have no effect when nothing is listening to them.<\/li>\n<\/ul>\n\n<h4>1.2.3<\/h4>\n\n<ul>\n<li>Fixed: corrected an oversized Upgrade Notice entry that exceeded the WordPress.org 300-character limit.<\/li>\n<li>Reverted uninstall.php variable names to the plugin's standard short-form prefix; the longer form tried in 1.2.2 did not change Plugin Check's output, since the underlying naming-convention check cannot be satisfied by any prefix declared inside the plugin itself.<\/li>\n<\/ul>\n\n<h4>1.2.2<\/h4>\n\n<ul>\n<li>Plugin Check compliance: renamed global-scope variables in uninstall.php to the full plugin-specific prefix and completed rule-code documentation for the two schema-change queries it runs.<\/li>\n<li>Plugin Check compliance: shortened the readme short description to fit the WordPress.org 150-character limit.<\/li>\n<\/ul>\n\n<h4>1.2.1<\/h4>\n\n<ul>\n<li>Fixed: removed the Conversions and Conversion Rate cards from the Dashboard. Both always read zero, since no conversion tracking exists in this plugin, and showing a permanently-zero metric was misleading.<\/li>\n<li>Added: AI Traffic Sessions card on the Dashboard, showing the session count and percentage of total traffic attributed to the AI Tools channel.<\/li>\n<\/ul>\n\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>Added: Excluded channels setting. Any channel, including Direct \/ Unknown, can now be removed from the Dashboard summary, the channel share chart, and the Sessions report, including CSV export.<\/li>\n<li>Added: uninstall.php now performs the Delete on uninstall action. Previously this setting had no effect; deleting the plugin never removed any data regardless of the setting.<\/li>\n<li>Fixed: removed two FAQ entries describing detection logic (GCLID\/MSCLKID click ID parameters, a nine-step priority order) that did not match the plugin's actual classification behaviour. Replaced with an accurate description of the real priority order and UTM-based paid channel detection.<\/li>\n<li>Fixed: removed references to a conversion log feature from the Settings tab and readme. No conversion tracking exists in this plugin.<\/li>\n<li>Removed: nine unused internal methods and associated dead CSS left over from features that are not part of this plugin, with no functional impact.<\/li>\n<li>Documentation: added FAQ coverage for the CQIP Site Services compatibility guard, the new Excluded channels setting, and the Delete on uninstall behaviour. Documented two previously unlisted filter hooks. Rewrote the plugin description to lead with the practical benefit of server-side classification and AI traffic detection.<\/li>\n<\/ul>\n\n<h4>1.1.2<\/h4>\n\n<ul>\n<li>Plugin Check compliance: renamed the licence management bootstrap function, its global variable, and three custom hook names to use the full plugin-specific prefix, resolving the remaining naming convention warnings. No functional change; internal identifiers only.<\/li>\n<\/ul>\n\n<h4>1.1.1<\/h4>\n\n<ul>\n<li>Plugin Check compliance: documented justification for WordPress core's own escaped insert API being flagged as a direct database call.<\/li>\n<li>Plugin Check compliance: completed database query documentation pass.<\/li>\n<li>Documented the plugin's naming prefix convention and the reasoning behind it for ongoing maintenance reference.<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Fixed: free tier no longer stops recording sessions once 30 rows accumulate. Free now records the full 30-day history, matching the existing 30-day prune schedule, so dashboard reports are accurate regardless of traffic volume.<\/li>\n<li>Fixed: the Sessions list label now correctly describes the 30-row list as a display limit, separate from the full 30-day reporting window.<\/li>\n<li>Added: Clear Attribution Log is now available on the free tier (previously Pro-only), giving free users a manual reset option.<\/li>\n<\/ul>\n\n<h4>1.0.12<\/h4>\n\n<ul>\n<li>Plugin Check compliance: restructured remaining multi-line database queries to single-line statements so compliance documentation is correctly associated with each query by automated review tools.<\/li>\n<li>Plugin Check compliance: completed full documentation pass across all direct database queries.<\/li>\n<\/ul>\n\n<h4>1.0.11<\/h4>\n\n<ul>\n<li>Plugin Check compliance: completed database query review with explicit justification documentation for every direct query, confirming all table references originate from trusted internal sources.<\/li>\n<li>Plugin Check compliance: replaced remaining integer type casts with WordPress's dedicated integer sanitization function for all page and period parameters.<\/li>\n<\/ul>\n\n<h4>1.0.10<\/h4>\n\n<ul>\n<li>Plugin Check compliance: dashboard chart library is now bundled with the plugin instead of loaded from an external network resource.<\/li>\n<li>Plugin Check compliance: hardened database queries so table name references are always escaped at the source.<\/li>\n<li>Plugin Check compliance: corrected internal variable naming to consistently use the plugin's own prefix.<\/li>\n<li>Plugin Check compliance: documented and resolved output escaping checks across the dashboard and print report.<\/li>\n<\/ul>\n\n<h4>1.0.9<\/h4>\n\n<ul>\n<li>Adjusted internal file structure for licence management to meet hosting platform compliance requirements.<\/li>\n<\/ul>\n\n<h4>1.0.8<\/h4>\n\n<ul>\n<li>Plugin Check (PCP) compliance pass: replaced parse_url() with wp_parse_url() throughout.<\/li>\n<li>Plugin Check: added wp_unslash() to all $_GET, $_POST, and $_SERVER reads before sanitisation, across the classifier, admin, report, and white-label classes.<\/li>\n<li>Plugin Check: removed load_plugin_textdomain() call \u2014 WordPress.org auto-loads translations for hosted plugins since WordPress 4.6.<\/li>\n<li>Plugin Check: documented justification for in-memory CSV stream handling (php:\/\/memory is not a filesystem path; WP_Filesystem does not apply).<\/li>\n<li>Plugin Check: documented justification for table-name SQL interpolation in the database class \u2014 table names originate exclusively from $wpdb-&gt;prefix, never from user input; all user-supplied values use $wpdb-&gt;prepare() placeholders.<\/li>\n<\/ul>\n\n<h4>1.0.7<\/h4>\n\n<ul>\n<li>Updated licence management SDK to latest release.<\/li>\n<li>Confirmed compatibility with WordPress 7.0.<\/li>\n<\/ul>\n\n<h4>1.0.6<\/h4>\n\n<ul>\n<li>Uninstall: moved cleanup logic from uninstall.php to the licence management after_uninstall hook. Delete on uninstall behaviour is unchanged.<\/li>\n<\/ul>\n\n<h4>1.0.5<\/h4>\n\n<ul>\n<li>Accessibility: resolved nine WCAG 2.1 AA contrast failures across admin UI and print report. Active tab, primary button, and period selector now use dark text on teal background (8.19:1). Teal text on white replaced with accessible variant #0A8078 (4.80:1). Muted informational text lifted from #9CA3AF to #6B7280.<\/li>\n<li>Accessibility: added :focus-visible styles to all interactive elements \u2014 inputs, buttons, period pills, channel tabs, drill-down controls.<\/li>\n<li>Accessibility: added aria-label to hidden file import input.<\/li>\n<\/ul>\n\n<h4>1.0.4<\/h4>\n\n<ul>\n<li>Storage: free tier row cap (30 rows) now enforced at insert time, preventing log table bloat on busy sites.<\/li>\n<li>Storage: landing_url column changed from TEXT to VARCHAR(500) for more efficient storage. Database schema version updated.<\/li>\n<li>Settings: added Data and Storage panel with Delete data on uninstall option (all tiers). When enabled, plugin deletion removes all tables and options cleanly.<\/li>\n<li>Added uninstall.php \u2014 drops attribution and conversion tables and removes all plugin options when Delete data on uninstall is enabled.<\/li>\n<\/ul>\n\n<h4>1.0.3<\/h4>\n\n<ul>\n<li>Attribution panel moved to top-level WordPress admin menu (Settings &gt; Referrer Attribution is now Attribution in the sidebar).<\/li>\n<li>Classifier: extended built-in system path guard to cover \/robots.txt, \/sitemap.xml, \/favicon.ico, \/.well-known\/, and additional WordPress entry points.<\/li>\n<li>Settings: added Path Exclusions field \u2014 one path prefix per line, applied before classification runs.<\/li>\n<li>Settings: surfaced Self-Referral Exclusions field \u2014 shows the auto-excluded site domain and accepts additional domains (staging, subdomains) one per line.<\/li>\n<\/ul>\n\n<h4>1.0.2<\/h4>\n\n<ul>\n<li>Classifier: added early-exit guard for xmlrpc.php, wp-cron.php, wp-signup.php, and wp-activate.php requests. Bot probes targeting these endpoints no longer appear in the session log.<\/li>\n<\/ul>\n\n<h4>1.0.1<\/h4>\n\n<ul>\n<li>Licence management configuration updated to reflect dedicated product website.<\/li>\n<li>Admin page footer added: CQIP ecosystem attribution line.<\/li>\n<li>Pro upgrade prompt copy updated \u2014 removed third-party library name.<\/li>\n<li>Noop upgrade URL updated to referrerattribution.com\/pro\/.<\/li>\n<li>British English corrected in code comments.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial standalone release.<\/li>\n<li>Nine-channel classification engine.<\/li>\n<li>AI Referrer Taxonomy with 17 default entries.<\/li>\n<li>Dashboard with summary cards and four charts (Pro).<\/li>\n<li>Period selector \u2014 7, 30, 90 days (Pro).<\/li>\n<li>Channel drill-down to source level (Pro).<\/li>\n<li>Sessions log with filters and CSV export (Pro for full access).<\/li>\n<li>Conversions log with filters and CSV export (Pro).<\/li>\n<li>Print \/ PDF report \u2014 opens a formatted browser print view, no server-side library required (Pro).<\/li>\n<li>White-label branding configuration (Pro).<\/li>\n<li>Consent gate for CQI Consent integration.<\/li>\n<li>GDPR personal data export and erasure hooks.<\/li>\n<li>WP-Cron daily log pruning.<\/li>\n<li>License management and Pro upgrade flow integrated.<\/li>\n<\/ul>","raw_excerpt":"Know where every visitor came from, including ChatGPT, Gemini, and Perplexity. No JavaScript, no cookie banner trigger, no page speed cost.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/328423","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=328423"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/hdfraser"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=328423"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=328423"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=328423"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=328423"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=328423"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=328423"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}