=== Spectare Personalisation ===
Contributors: nigemchugh
Tags: personalisation, personalization, ai, dynamic content, marketing
Requires at least: 5.8
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 1.11.3
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

AI-driven personalisation for WordPress. Spectare assembles a different page experience for every visitor based on referrer and UTM signals.

== Description ==

Spectare reads where each visitor came from (referrer, UTM parameters, page context) and silently assembles a personalised version of your page from a library of content blocks called atoms. No surveys, no cookies, no asking visitors who they are.

You write your content once as atoms: a pricing block, a feature explanation, a case study, a FAQ. Spectare picks the right 3 to 5 atoms for each visitor and slots them into your page in milliseconds.

**How it works**

1. A visitor arrives on your site. Spectare reads their referrer URL, UTM parameters, and page content.
2. An AI classifies their likely audience (developer, executive, manager) and buyer stage (awareness, consideration, decision).
3. Spectare selects the most relevant atoms from your library and assembles them into named slots on the page.
4. The assembled content is cached so repeat visitors are served instantly.

**Two ways to personalise**

The plugin supports two integration paths. You can use either, or both on different pages.

* **Option A: client-side slots.** The Spectare widget script fills named placeholders in the browser after the page loads. Simplest to set up, and safe with any page cache because the personalisation happens client-side.
* **Option B: server-side zones.** PHP calls Spectare with your API key and renders personalised components into the HTML before the page is sent, so there is no flash of default content. Pages using a zone automatically send a `Cache-Control: no-store` header so caching plugins cannot serve stale personalised HTML.

**What this plugin does**

* Injects the Spectare widget script onto every page for client-side slots (optional, can be disabled)
* Provides a Gutenberg block (Spectare Slot) and a `[spectare_slot]` shortcode for client-side slots
* Provides a Gutenberg block (Spectare Zone) and a `[spectare_zone]` shortcode for server-side zones
* Optionally serves an agent entry point at your-domain.com/llms.txt (off by default), generated from your Spectare content: a curated map of what you offer, so an AI agent reading your site extracts your facts accurately from a few fetches instead of scraping every page
* Adds a settings page under Settings → Spectare for your organisation slug, base URL, and API key

**Client-side slots (Option A)**

Slots are named placeholders the widget script fills in the browser. Slot names map to positions in your assembled layout:

* `primary`: the main content area, highest priority atom
* `supporting`: secondary content, one or more blocks
* `secondary`: lowest priority, often a FAQ or comparison

Use the Spectare Slot block in Gutenberg or the shortcode in the classic editor:

`[spectare_slot name="primary"]`
`[spectare_slot name="supporting"]`
`[spectare_slot name="secondary"]`

You can reserve vertical space to prevent layout shift while content loads:

`[spectare_slot name="primary" height="200"]`

**Server-side zones (Option B)**

Zones are rendered by PHP before the page is sent, using your API key. Each zone renders a different kind of personalised component: hero banners at the top, body content in the middle, social proof and calls to action further down. There are four zones:

`[spectare_zone zone="hero"]`
`[spectare_zone zone="body"]`
`[spectare_zone zone="proof"]`
`[spectare_zone zone="cta"]`

Server-side zones need your API key in Settings → Spectare (find it in your Spectare admin under Settings). Any page using a zone sends `Cache-Control: no-store` automatically.

**Requirements**

A Spectare account is required. Sign up at [spectare.ai](https://spectare.ai). Spectare is free to start with a 14-day trial; paid plans start at $19/month. See [spectare.ai/pricing](https://spectare.ai/pricing) for current plans and limits.

== External services ==

This plugin connects to the Spectare service (spectare.ai, or your own base URL if you self-host) to personalise your pages. It sends and receives data in the following ways:

**Widget script.** When auto-inject is on and your organisation slug is set, the plugin loads `spectare.js` from the Spectare service on your public pages. The script sends the visitor's referrer, UTM parameters, current page URL, and (in the visitor's own browser storage) their recent page history on your site to the Spectare API to classify intent and fetch personalised content. No account data, names, or email addresses are collected, and Spectare sets no cookies by default.

**Server-side zones.** Pages using `[spectare_zone]` call the Spectare assembly API from your server, sending the visitor's referrer, UTM parameters, and page URL, authenticated with your API key. If you enable the returning-visitors option, the visitor's last three page paths on your own site are included from a first-party cookie.

**Conversion reporting.** When WooCommerce or a supported form plugin completes an order or submission, the plugin reports the goal name, type, and (for orders) the total and currency to the Spectare API. No customer personal data is sent.

**Agent entry point.** If you enable llms.txt serving, the plugin fetches your generated llms.txt from the Spectare API and serves it on your domain.

These calls go to the Spectare service: [privacy policy](https://spectare.ai/privacy). No data is sent to Spectare until you enter your organisation slug in settings.

== Installation ==

1. Download the plugin zip from your Spectare admin under Settings, or from the WordPress plugin directory.
2. In your WordPress dashboard, go to Plugins → Add New → Upload Plugin and upload the zip file.
3. Click Install Now, then Activate Plugin.
4. Go to Settings → Spectare and enter your organisation slug (found in your Spectare admin under Settings). For server-side zones, also enter your API key.
5. Add a Spectare Slot block (client-side) or a Spectare Zone block (server-side) in the Gutenberg editor, or use the `[spectare_slot]` or `[spectare_zone]` shortcode wherever you want personalised content to appear.

That is all. Spectare handles everything else automatically.

== Frequently Asked Questions ==

= Do I need to write code? =

No. The plugin handles script injection and slot rendering. You write your content atoms in the Spectare admin and the plugin takes care of the rest.

= What is an atom? =

An atom is one focused piece of content: a feature explanation, a pricing block, a FAQ, a case study. You write atoms in the Spectare admin. Spectare assembles the right combination for each visitor.

= How many atoms should I write? =

Ten is enough to see meaningful personalisation. The recommended starting set covers your core feature, your main differentiator, pricing, a common objection, a competitor comparison, a developer how-to, a customer outcome, a pricing FAQ, your data handling stance, and your integration story.

= Does Spectare use cookies or track personal data? =

No cookies are set and no personal data is collected. Spectare reads only the HTTP referrer header, UTM parameters already present in the URL, and the text content of the current page. Nothing is stored on the visitor's device.

= Should I use slots or zones? =

Use client-side slots (Option A) if you want the simplest setup and your pages are served from a cache: personalisation happens in the browser, so it is safe with any caching plugin or CDN. Use server-side zones (Option B) if you want the personalised content baked into the HTML with no flash of default content, for example on a landing page where above-the-fold speed matters. Zones need an API key and send a no-store header, so the page is not cached. You can mix both: zones for the hero, slots lower down.

= Can I use Spectare with a page builder? =

Yes. Any builder that supports shortcodes (Elementor, Divi, WPBakery, Beaver Builder) can use `[spectare_slot]`. The Gutenberg block works natively in the block editor.

= What if I want to load the script manually? =

Disable auto-inject in Settings → Spectare → Auto-inject widget. Then add the script tag yourself:

`<script src="https://spectare.ai/spectare.js" data-org="your-slug" async></script>`

= What is the agent entry point (llms.txt) feature? =

Spectare generates an llms.txt file from your published content and the plugin can serve it at your-domain.com/llms.txt. It is a curated entry point that maps your content, so an AI agent reading your site extracts accurate facts from a few fetches instead of guessing from a scraped page, and it keeps agent crawl cost down as pay-per-crawl arrives. It also documents your qualify endpoint, so an assistant helping someone can send them on to a page built for their intent. It is off by default: turn it on with the "Serve llms.txt" setting. Once on, it updates automatically as you edit content, and "Refresh llms.txt" pulls the latest immediately. Only published atoms are included, never drafts. Requires pretty permalinks (Settings → Permalinks, any option other than Plain).

= Does this slow down my site? =

The Spectare script loads asynchronously and does not block page rendering. Personalised content fills slots after the page is visible. Cached assemblies (repeat visitors with the same intent profile) are served in under 100ms.

= What WordPress versions are supported? =

WordPress 5.8 and above. The Gutenberg block requires the block editor introduced in WordPress 5.0, but the shortcode works in any editor version.

== Screenshots ==

1. Spectare blocks in the editor: drop a slot or zone where personalised content should appear.
2. The settings page: your organisation slug, API key, and the toggles that control the plugin.
3. A page assembled by Spectare: personalised hero, content, and call to action rendered in zones.

== Changelog ==

= 1.11.3 =
* All script and style output now travels through the WordPress enqueue system: the zone
  stylesheet is an inline style enqueued in the head, the conversion-attribution snippet an
  inline script enqueued in the footer, and the import page script an admin enqueue scoped
  to its own page. No raw script or style tags remain.
* Shortcode fallback content is passed through wp_kses_post on return.

= 1.11.2 =
* The Plugin URI now points to the plugin guide at spectare.ai/guide/wordpress, distinct from
  the Author URI, as the directory requires.

= 1.11.1 =
* Plugin Check pass: settings fields now escape at the point of output, the UTM reads and the
  DONOTCACHEPAGE convention constant carry documented sniff exemptions, and the renderer
  fallback notice only logs under WP_DEBUG.

= 1.11.0 =
* WordPress.org directory release. The build distributed through the directory updates via
  WordPress.org only; the self-hosted update channel is not present in it.
* New "External services" section in this readme documenting every call the plugin makes to
  the Spectare service and what data travels with it.
* Tested against WordPress 7.1.

= 1.10.0 =
* Zone pages now tell Spectare which zones they placed, detected from the page's own
  shortcodes and blocks. The assembled content is then composed only from components those
  zones can render, so a page with just a body zone gets a fuller body instead of a hero
  and call to action it never shows. Pages the plugin cannot read (page builders, widgets)
  behave exactly as before.
* Conversions on zone pages now credit the hero image that was shown, so image selection
  can learn which images convert on WordPress sites.

= 1.9.0 =
* Zones now respect per-component zone placements set in your Spectare settings. Previously a
  zone override saved in Spectare was silently ignored on WordPress, which rendered every
  component in its default zone. If you set zone overrides, components may move to the zone
  you actually chose after this update.
* The llms.txt feature is now described as what it is: an agent entry point. A curated map of
  your content so an AI agent reading your site extracts accurate facts from a few fetches,
  rather than a visibility promise.

= 1.8.2 =
* The Spectare logo now appears on the settings page, on update rows and in the plugin
  details window, so the plugin is recognisable at a glance in a busy admin.

= 1.8.1 =
* Supporting content now renders as a compact card: the title, a one-sentence summary, and the
  full text one tap away. Pages read as pages rather than columns of full prose, and nothing
  becomes unreachable.

= 1.8.0 =
* Form conversions. Submissions through Gravity Forms, WPForms and Contact Form 7 now report a
  lead conversion to Spectare automatically, with no thank-you page or URL goal needed. Rename
  the goal with the spectare_form_goal_name filter, or disable with spectare_track_forms.
* Click goals. Clicks on phone numbers, email links and booking platforms (OpenTable, Tock,
  Design My Night, SevenRooms, Resy, Eventbrite and others) count as conversions, since those
  journeys never end on a page a URL goal could match. On by default; switch off in settings.

= 1.7.0 =
* Automatic updates. The plugin now checks spectare.ai for new versions and updates through the
  normal WordPress update screen. This is the last version you install by uploading a zip.
* WooCommerce order tracking. When WooCommerce is active and your API key is set, every paid
  order reports a conversion to Spectare with the real order total and currency, so the
  analytics and the learning loop see what actually sells. No configuration needed; disable
  with the spectare_track_woocommerce filter.
* The comparison table now carries proper header scope attributes for screen readers.

= 1.6.1 =
* The announcement zone added in 1.6.0 was missing from the block editor's zone list and from the
  setup instructions, so the only way to use it was to type the shortcode by hand. It is now
  offered like every other zone.

= 1.6.0 =
* New announcement bar. A single line above the rest of a personalised section, for one
  time-limited fact worth knowing first: a member priority window, the last days of a run,
  under-12s free this month. Place it with [spectare_zone zone="announce"].
* It only appears when your content actually states such a fact and carries the dates it is true
  between, so it disappears on its own when the offer ends rather than sitting there out of date.

= 1.5.4 =
* Longer content in a personalised section was cut off after four lines, mid-sentence, with no
  way for the reader to see the rest. The shortening was meant for a narrow column beside another
  block, and sections are laid out full width, so it was hiding content for no reason.

= 1.5.3 =
* Personalised sections can now hold your own content as a fallback. Write it between the tags,
  for example [spectare_zone zone="hero"]Your normal hero copy[/spectare_zone], and it is shown
  whenever there is nothing personalised to show: if the connection fails, if you have not
  published content for that visitor yet, or before the page finishes loading. Previously those
  situations left a gap and there was no way to say what belonged there.

= 1.5.2 =
* A personalised section containing a content block this version of the plugin does not know
  how to draw used to leave a gap, with nothing in the logs to say why. It now draws the block
  as a content card and records a note, so an out-of-date plugin degrades visibly rather than
  quietly dropping content.

= 1.5.1 =
* The primary button in a call to action block was white on a white background, so on most
  themes it was invisible. It now uses your brand colour, which you can set in Settings.
* New "Brand colour" setting. Personalised sections already inherit your theme's background and
  text colour; this is the one colour Spectare picks, used for links, labels and the primary
  button. Previously it could only be changed by overriding a CSS variable, which worked or did
  not depending on the order your stylesheets loaded in.
* Improved the contrast of the faintest text colour, which fell below the accessibility minimum
  on light themes.

= 1.5.0 =
* Atom content written with paragraphs, lists, bold or headings rendered as one unbroken block
  of text in server-rendered zones. It is now converted to HTML, matching every other way
  Spectare content is displayed.
* Added the styles that markdown content needs, including the three code styles that were
  missing, so an atom containing code no longer renders unstyled.

= 1.4.1 =
* Security fix. The page URL is sent to Spectare and shapes the personalisation, but was not
  part of the key used to cache a zone's assembly. Because that URL includes the query string,
  two visitors on the same page with different query strings shared one cached entry, so one
  visitor could be served content assembled for another. Found by a security review. Zone
  assemblies now cache per page URL as well as per referrer, campaign and visit history.

= 1.4.0 =
* Server-rendered zones can now personalise for returning visitors. Zones are rendered on your
  server, which cannot see the page history Spectare keeps in the visitor's browser, so a
  returning visitor previously looked new to them and got your default content. Enable
  "Returning visitors in zones" in Settings to store the visitor's last three page paths in a
  first-party cookie on your own domain, which your server passes to Spectare. Off by default,
  because it adds a cookie: check your cookie policy before enabling. Slots have always
  personalised for returning visitors and are unaffected either way.
* Zone assemblies are cached per visit history as well as per referrer and campaign, so two
  visitors with different histories no longer share a cached zone.

= 1.3.1 =
* Atom body text in server-rendered zones is now clamped to four lines instead of printing
  the full atom. Long atoms were rendering as a wall of prose beside structured components.
  Set full on an atom in the assembly to print the whole body.
* Zone assemblies are now cached for an hour instead of a minute. At one minute the cache
  expired between visitors on lower traffic sites, so most visitors paid a cold blocking
  render and billed a personalisation. Filter: spectare_assembly_cache_ttl.
* The zone request timeout is now 15 seconds instead of 20. This call blocks the page render,
  so it stays bounded, but it has to sit above a cold assembly rather than below it: a cold
  miss is a full model call and can take 9 to 13 seconds. With the hour-long cache above, at
  most one visitor per hour per traffic source waits that long. Filter:
  spectare_assembly_timeout.
* A failed zone request is remembered for 30 seconds, so a slow or unavailable backend costs
  one visitor the timeout rather than every visitor until it recovers. Filter:
  spectare_assembly_fail_ttl.

= 1.3.0 =
* Added content import (Settings → Spectare Import): scan your published pages, pick which to import, and Spectare rewrites them into focused content atoms saved as drafts for review. Nothing is published automatically. Reads raw Gutenberg blocks where available and falls back to a heading split for classic/page-builder content. Requires your Spectare API key.

= 1.2.0 =
* Added an agent entry point: the plugin serves an llms.txt at your domain root, generated from your published Spectare content, so an AI agent reading your site extracts accurate facts from a few fetches.
* Added "Serve llms.txt" toggle (off by default) and a "Refresh llms.txt" button in Settings → Spectare.
* llms.txt is cached locally and refreshes automatically as your content changes. Requires pretty permalinks.

= 1.1.0 =
* Added server-side Zone blocks: the [spectare_zone] shortcode and Spectare Zone Gutenberg block render personalised components in named zones (hero, body, proof, cta) via server-side assembly.
* Added an API key setting (Settings → Spectare) required for the server-side zone path.
* Pages using [spectare_zone] now send a Cache-Control: no-store header automatically to prevent caching plugins from serving stale personalised content.
* Reorganised the settings Quick start into Option A (client-side slots) and Option B (server-side zones).

= 1.0.0 =
* Initial release.
* Auto-inject of Spectare widget script via wp_enqueue_scripts.
* Gutenberg block (Spectare Slot) with slot selector, custom name, and reserved height options.
* Shortcode [spectare_slot] with name and height attributes.
* Settings page with organisation slug, base URL, and auto-inject toggle.
