Found a bug? Have a great feature idea? Get on GitHub and tell us about it and we'll get right on it: https://eshop-optimizer.com


= 8.1 — Events (Beta) & Competitions, a richer storefront block library, storefront polish (20/06/2026) =

* **Events (Beta).** A complete event-management module modelled on Competitions: an Events CPT with a participants table, XLSX/CSV participant import (update-vs-overwrite), tokenised one-click RSVP confirm/decline, parametric newsletter invitations through The Newsletter Plugin ({salutation}/{title} merge, BUILD + dry-run only — never auto-sent), front-end self-registration via a new `aieo/event-registration` block and `[aieo_event_register]` shortcode, a Google Maps location URL, quick-create JS, and an attendance stats panel with XLSX export. Admin-plugin only.
* **Competitions.** A competitions / giveaway module sitting alongside Events.
* **AIEO Product Slider block.** A horizontal product slider with the exact look of the product-page recommendation rails (thin uppercase title + underline, then cards) — manual title, filtered by category, tag and/or a specific set of product IDs. Replaces the legacy OM `[responsive_product_slider]` shortcodes.
* **AIEO Category Footer Hero block.** Lays a product category's SEO footer text beside the category image (image left, small rich text right) with the hero divider line cutting across the image — the horizontal counterpart to the category hero, for the bottom of the archive.
* **AIEO Trust Badges block.** A configurable trust strip of icon + title + subtitle columns (shipping / payment / returns / quality), with four bundled icons.
* **"Feature heading" opt-in for blocks.** The Brand Slider, Google Reviews and Latest Posts Overlay blocks gained a toggle to render their heading in the big thin-uppercase + full-width-underline style the product sliders use — inherited from one source so it never drifts, with the underline contained to the body width on the constrained blocks.
* **AIEO Latest Posts Overlay.** Now supports an optional section heading (with the feature-heading style) and a "glass" card style — tall portrait cards with a frosted-glass info bar — reproducing the legacy live blog layout.
* **Blog category archives.** A redesigned blog (sub)category header: a featured latest-post hero with the category-hero look, a subcategories dropdown, and a category lead, applied across every blog category and subcategory.
* **Product archive cards.** Evened the QUICK VIEW ↔ ΑΓΟΡΑ spacing between variable and simple products (the WC variation-form chrome no longer adds height above the buy button on image/colour-swatch products), tightened the variation swatches, and centred the buy-button label.
* **Side-cart.** The "You might like" recommendations sidebar now hides itself entirely when there are no recommendations (or no seed product) instead of showing an empty pane — the cart takes the full panel width.
* **Greek translations.** Customer-facing recommendation rail titles reworded from back-office jargon ("cross-sells / up-sells") into natural shopper language, plus footer trust-badge copy.

= 8.0.1 — Promo Surface full-width + single consent control (16/06/2026) =

* **Promo Surface "Full width" now bleeds edge-to-edge when nested.** The `aieo/promo-surface` block already forced a full-bleed when it was a direct child of the theme's constrained root, but on a *programmable* front page (where the page is rendered through `wp:post-content`) the surface sat one level deeper and kept its parent's root-padding-inset width, leaving a side gap. The full-bleed rule now sets an explicit `width:100vw` (not just `max-width`), so the surface fills the viewport regardless of nesting depth.
* **One cookie button, not two (consent control de-duplicated).** The first-party CMP rendered its own floating "reopen" button AND the side-cart bottom bar rendered a separate bespoke cookie item — two controls opening the same modal (a duplicate on mobile, and the bar one leaked onto desktop). They are now a single control: the side-cart bar's consent item reuses the CMP's `.aieo-cmp-reopen` styling (the themed floating circle on desktop, via `AIEO_Consent::reopen_button_vars()`) and flattens into the bar on mobile, while `AIEO_Consent::render_reopen()` suppresses its standalone button whenever the bar carries it (`AIEO_Side_Cart_Display::consent_button_active()`). No duplicated markup; styled per breakpoint. (Shared `class-aieo-side-cart-display.php` updated in both the admin plugin and `ai-eshop-optimizer-runtime`.)

= 8.0 "Fable / Mythos 5" - marketplace-feed URLs + an attribute-driven product-colour pipeline for SEO and feeds (14/06/2026) =

* **Absolute marketplace-feed links.** Products with an SEO canonical were being exported with a relative `<g:link>` (no domain), so Google / Skroutz silently dropped them. The catalogue build now absolutises the canonical into the core-vitals product URL, with a defensive absolutise at feed output; the sitemap and the on-page canonical tag were already correct.
* **Product colour from your attributes.** A new "AIEO colour context" flag (Products -> Attributes, with a one-click bulk action) marks which swatch attributes represent a colour; the catalogue build reads the term NAME (e.g. "French Caramel") into the product colour used by the JSON-LD schema and the marketplace feeds, as real per-variant values rather than slugs. Completes the 7.4 colour follow-up (parents stay clean: Google carries colour on each variant plus variesBy:color).
* **Platform.** Asset-minification system (minified CSS/JS served automatically), an SEO opportunities scorer + module, session analytics, the Courier Center fulfilment driver, and SQL runtime helpers. Requires-PHP floor set to 7.4.

= 7.4 Merchant-listing & Local SEO schema completeness — clear Google Search Console's "missing field" warnings across Product and LocalBusiness, plus a clean Channel view for attribution. Now requires WordPress 7.0+ (11–12/06/2026) =

* **Product `color` on every product.** The Product / ProductGroup schema now ALWAYS emits a `color` property, read straight from the core vitals colour (the single source of truth). Variable products carry real per-variant colours (and `variesBy`); simple products emit the field present-but-empty until you designate a colour-denoting attribute to populate vitals — a guided follow-up documented in `documentation/SEO_SCHEMA_NEXT_OPTIMIZATIONS.md`. No data keys were faked: the empty value is honest, and fills in automatically once vitals colour is populated, with no further code change.
* **Shipping & returns on every product Offer.** A new "Returns & shipping" card in the SEO → Schema tab emits `OfferShippingDetails` + `MerchantReturnPolicy` on each Offer — return window (days) + free-returns flag + country, and shipping rate + handling/transit-time range + country. Both are OFF until you enter values, because wrong terms trigger Merchant Center issues; once on, they apply site-wide to every product and variation.
* **`productGroupID` "invalid string length" fixed.** A long slug-style parent SKU exceeded Google's ~50-char item-group-id limit and was rejected; the group id now falls back to the stable numeric product ID when the SKU is too long.
* **LocalBusiness `priceRange` + `image` per store.** The Locations & Reviews location editor (Schema extras) now offers a Google-recognised price-tier selector (€ / €€ / €€€ / €€€€) and a WordPress media-gallery image picker with preview. Both persist per location and feed each store's `HealthAndBeautyBusiness` node, clearing the "missing image / priceRange" Local-SEO warnings across every page that carries the store graph.
* **UTM Explorer — new "Channel" dimension.** A top-level breakdown by the RESOLVED marketing channel, with consolidated friendly labels — paid Google cleanly separated from Organic Search (organic + organic_search merged), plus Facebook – Paid, Direct, Skroutz, Instagram, Phone, etc. The Source view additionally relabels paid traffic so Google Ads no longer hides inside the organic `google` bucket; raw `utm_source` is preserved underneath. Labels are display-only — the stored channel keys other modules match on (ROI Wizard, ad connectors, Enhanced Conversions) are untouched.
* **Attribution accuracy.** Order analytics (`wp_aieo_order_stats`) now bucket by the site's configured WordPress timezone instead of UTC, so AIEO's daily order counts/revenue match WooCommerce Analytics day-for-day; and the self-referral "internal" channel folds into the standard "(direct)" bucket.

= 7.3 In-house SEO engine — replace AIOSEO/Yoast with a faster, Greek-aware engine: rich commerce + local-business + image schema, redirects, a static sitemap, demand-aware scoring + Greek AI Assist, and an AIOSEO migration with a pre-cutover verify — all served from materialized data at ~0 ms (09–10/06/2026) =

* **A complete on-page SEO engine, folded into AIEO.** Title, meta description, canonical, robots, Open Graph and Twitter cards plus the JSON-LD `@graph` are now AIEO's to emit — built ONCE into a head cache and served by the thin runtime in a single cached read. No per-request assembly, no Vue admin SPA, no telemetry, no licence calls: ~0 ms added TTFB versus the 100–300 ms AIOSEO/Yoast/RankMath add per render. It runs **augment-only behind your current SEO plugin** (changes nothing on the page) until you turn it on, so 7.3 is safe to deploy ahead of any cut-over.
* **Canonical category, one resolver.** Pin one canonical category per product (the AIOSEO "primary category" mechanism) and a single resolver drives the **permalink, the `<link rel=canonical>` and the sitemap entry** in lock-step — they can never drift apart. A "SEO" editor metabox offers the canonical-category picker (plus title / meta / canonical override / robots), and a chunked bulk tool sets it across a whole catalogue.
* **Rich, correct commerce schema — entirely from the core vitals table (no live WooCommerce queries on the build path).** Variable products now emit a `ProductGroup` with `hasVariant` / `variesBy` so Google surfaces the variants instead of collapsing them into a phantom single item; on-sale products carry a `UnitPriceSpecification` strikethrough (the "was" price); plus `gtin`, `Brand`, and operator-configured `MerchantReturnPolicy` + `OfferShippingDetails` (off unless they reflect your real terms). Category, brand, attribute and tag archives are first-class landing pages too — `CollectionPage` + a product `ItemList` + `BreadcrumbList` + `inLanguage` — and their canonicals are the pretty `/product-category/…` URLs (a query-string-canonical bug from early builds is fixed).
* **Local SEO for physical stores.** A `LocalBusiness` node per shop, built from your Locations & Reviews Google locations — address, opening hours, geo, "Open in Maps" / "Rate us" links — linked under the site Organization, with one location pinned as HQ. Three new storefront blocks (**Store Locator**, **Opening Hours**, **Business Info**) render the same data anywhere, and an optional **store-page post type** lets each shop have its own page; you choose its URL base and label (nothing is hardcoded), and store pages get their own sitemap entries. Stars are never self-emitted (they stay on your Google Business Profile, per Google's policy).
* **Image SEO (no AI, no credits).** Empty product featured-image alt text is auto-filled from the product title (or your imported format) — only empties, so any alt you or AIOSEO already set is preserved — and one `<image:image>` per product is added to the sitemap for Google Images.
* **Redirects with an automatic slug-change monitor.** Rename a product or post and the old URL keeps working (an automatic 301), so the canonical/permalink changes at cut-over never 404. A clean unique-404 list (deduplicated, with hit counts) offers a one-click "Create redirect". Served at the nginx edge before PHP where available, with a PHP `template_redirect` fallback for portability.
* **A static, outage-proof sitemap.** Cron-built to static `.xml` files — chunked into shards of ≤2,000 URLs plus a sitemap index — and served as files. It keeps serving even if the plugin is deactivated or broken (no repeat of the "two weeks with no sitemap" failure mode).
* **Demand-aware SEO score, health dashboard & Greek AI Assist (day one).** A live 0–100 score with a checklist in the editor, a "SEO Health" dashboard that lists the **highest-demand** low-scoring pages first (not alphabetical), and one-click Claude **AI Assist** — generate/improve title, meta description, summary and keyphrases — fluent in Greek from the start.
* **AIOSEO → AIEO migration engine + a pre-cutover verify.** A read-only importer copies your **entire** AIOSEO configuration — per-object meta, global settings (separator, Organization, social, robots, per-type/taxonomy formats), the image-alt format, and redirects — into AIEO storage, with a mapping report that lists every field as mapped / transformed / dropped (deprecated **FAQPage/HowTo schema is stripped**, not migrated as zombie markup). Then a one-click **"Pre-cutover verify"** compares the head AIEO would emit against your LIVE head over a sample of products, categories and pages, flagging any title / canonical / robots drift and confirming every canonical equals its permalink — so you flip the switch with confidence and keep AIOSEO installed-but-inactive as a rollback.
* **EU Omnibus reference price.** A 30-day-lowest-price history feeds the legally-required "lowest price of the last 30 days" reference on reductions.
* **Multilingual.** Per-language head + `hreflang` for WPML/Polylang (including Polylang, which AIOSEO never localised), and a TranslatePress-aware sitemap that emits the per-language prefixed URLs.
* **Core vitals carry the canonical.** Each product's `product_url` in the core vitals table is now its SEO canonical where one exists (otherwise the existing reference is left untouched); the column was widened to 300 characters and the write is bounded, so a stray over-long canonical can never overflow or fail the catalogue rebuild — our most load-bearing table.
* **Editor blocks discoverable again.** All AIEO blocks now appear in the inserter regardless of a block theme's curated block-palette (e.g. roosterX), and every block title is prefixed "AIEO" so they're findable by search; product-context blocks (swatches, PDP messages…) stay correctly scoped to single-product templates.
* **Fixes & runtime.** Fixed a 404 / MIME-type console error from a retired product-labels stylesheet that was still being enqueued. The thin front-end **runtime plugin moves to its own 1.0 version track** and now also serves the SEO head, the sitemap and the redirects with the core plugin trimmed from the request.

= 7.2 TikTok conversions, consent carried on every event, runtime-owned measurement, in-request event delivery — and the searchable ROI / UTM reports (08–09/06/2026) =

* **TikTok added to Pixels & Conversions.** TikTok joins Meta and Google as a fully-owned platform — a browser **TikTok Pixel** and the server-side **Events API**, deduplicated on a shared event id, with the click id (`ttclid`) recovered from the captured attribution session. Same consent-gated architecture as the Facebook CAPI; spec-verified against TikTok's current docs.
* **Consent travels with every event (in-band signalling).** Beyond the consent gate, AIEO now tells the ad platforms the consent state *on each event*: region-aware **Google Consent Mode v2** defaults (deny in the EEA, grant elsewhere, emitted before any tag fires), GA4 Measurement-Protocol top-level **consent**, Google Ads per-conversion **consent**, and Meta CAPI **Data Processing Options** — so a declined category down-scopes the conversion at Google / Meta / TikTok too, not just in the browser. Consent is snapshotted onto the order at checkout so the asynchronous server sends carry the right state.
* **The runtime owns measurement when present.** When the premium runtime plugin is active it serves all three browser pixels (Meta / TikTok / Google tag) **and** the three server senders itself — even on requests where the core plugin is trimmed — by lazy-loading the core send logic by path. The core plugin stays fully functional on its own; each surface is gated so exactly one of the two serves it.
* **Event delivery rebuilt for scale.** Server-side conversions no longer queue through Action Scheduler. They flush the page response to the shopper first (`fastcgi_finish_request`, LiteSpeed too) and send in the *same* request — zero checkout latency, no WP-Cron dependency, and nothing to back up at thousands of events a minute. A **"Fire-and-forget"** toggle in Pixels & Conversions (on by default) frees the worker the instant each event is sent; switch it off to wait for and log every platform's reply (sent / failed) while validating a setup.
* **Order origin in staff e-mails.** New-order staff notifications now show where the order came from — the marketplace (Skroutz / ShopFlix / eMAG …) or the site with its marketing channel and campaign — read from the one canonical order-facts source. (This replaces the PixelYourSite origin line that frequently failed to render.)
* **Ad-connector setup links.** The Google / Meta / TikTok credential wizards now link straight to where each value is found, so the "what to ask your agency" guidance is actionable.
* **UTM Explorer (new report).** A cascading drill-down across the five campaign tags — Source → Medium → Campaign → Term → Content — where each level is a searchable multi-select that narrows the lists below it to what actually co-occurred under your choices. It lives on the ROI Wizard page (and is findable from the admin command palette by searching "utm"). The table breaks the current selection down by the next level, with orders, revenue and average order value.
* **Searchable multi-select across the whole cockpit.** Every selector in the ROI Wizard and UTM Explorer — the **Type**, the exact detected **value**, the five UTM levels and the ad-spend **ledger value** — became the same fast searchable picker used for product selection (search, tick several, Done). Choosing from hundreds of creatives or campaigns now takes seconds instead of scrolling a giant dropdown. **Type** accepts several types at once and stacks one results table per type; **Exact** offers the union of the selected dimensions' values.
* **Reco lift per channel.** A new ROI type that shows the recommendation engine's incremental orders and € *over and above* each traffic channel — of the orders Google / Meta / organic brought, what share the recommendations assisted and what they added.
* **Period comparison (both reports).** Compare any result against the **previous period** or the **same period last year**, with a green / red Δ% shown inline on every metric. Off by default.
* **Report polish.** The UTM Explorer is consolidated onto the ROI Wizard page (ROI → UTM → ledger order); From / To dates lead each row; rows are top-aligned so selecting a value no longer nudges the controls; the Ad-spend connectors moved into a renamed **Tools & Settings** group; the default date range is the last 30 days.

= 7.1 First-party measurement & consent, then the ROI Wizard & ad-spend connectors (Google · Meta · TikTok), one canonical order revenue/channel (06–08/06/2026) =

* **Pixels & Conversions (server-side measurement).** AIEO can now own the Facebook (Meta) Pixel and Google Analytics 4 end to end — a thin browser pixel **and** server-side Conversions API / GA4 Measurement Protocol, deduplicated on a shared event id, sent after the order is saved (zero checkout latency). Each platform is selectable, with master off-switches so you can keep PixelYourSite; Facebook credentials can be read from PixelYourSite if present.
* **Advertiser-grade match quality (PixelYourSite-Pro parity).** Facebook browser **Advanced Matching** (hashed client-side, consent-gated) on top of the full server-side set; **complete GA4 user-data** (name + address, Unicode-correct for Greek); a built-in **Google tag** loader (gtag.js or a GTM container, wired to Consent Mode v2); and **Google Ads Enhanced Conversions** both in-browser and **server-side via the Google Ads API** (keyed on the captured gclid).
* **Consent / GDPR — first-party CMP.** A lightweight first-party cookie-consent banner (no external CMP, no IAB TCF bloat): rich-text message, three actions (Accept all / Decline / Customize) with a per-category preferences panel, per-button theming with an equal-prominence guard, two layouts (bar or centre glass pop-up), a floating "Cookie settings" re-open button, and a policy-version re-prompt. Drives Google Consent Mode v2 and gates AIEO analytics plus the Facebook / GA4 senders, with a built-in cookie scanner.
* **Checkout timing.** Active vs idle time is measured for each successful checkout and aggregated per product, so offer timing (exit-intent, etc.) can be set from real deliberation data; coupon-completed orders are tagged and excludable from the baseline.
* **Custom Tabs + Product Tab Ordering (Product Display).** Up to five extra renamable product tabs (each with its own rich text per product, auto-hidden when empty; one-click migration from the legacy Pods usage/specification fields), plus a drag-and-drop card that orders the WooCommerce tabs together with the Custom Tabs on both block and classic themes.
* **ROI Wizard — one cockpit for "what actually drove the sale".** A new **Attribution → ROI Wizard**: pick a **type** (⭐ Recommendation engine, Offer, Channel, Campaign, Creative), then the exact detected value, then a period — and see orders, revenue, cost, net, **ROAS** and **ROI %**. AIEO's own contribution is front and centre: recommendation-assisted sales and offer effectiveness (free shipping, gifts, discounts) are quantified right next to marketing channels and campaigns. Revenue is the order AIEO computes; offers carry their *real* cost automatically (free-shipping uses the courier rate already computed in Fulfillment), and channels/campaigns use the ad spend you enter or sync.
* **Ad-spend ledger + bulk CSV.** A per-period, per-dimension ad-spend ledger backs channel / campaign / creative ROI. Enter spend inline, or **export a CSV, fill a whole quarter in a spreadsheet, and re-import** — manual entry, CSV and the connectors all land in one place, summed over your reporting window.
* **Ad-spend connectors — Google Ads, Meta, TikTok.** Connect each platform once through a guided credential wizard (with exactly *what to ask your ad agency for*); AIEO then pulls campaign spend nightly into the ledger, so ROI becomes automatic and you never leave AIEO to reconcile spend against revenue — one cockpit for spend AND your own recommendation / offer / channel attribution. Credentials are stored encrypted; the pull is read-only.
* **One canonical order revenue + channel.** A single source of truth for each order's revenue and marketing channel (`AIEO_Order_Facts`), reading from the order AIEO computes, with a documented map of where every order fact lives — including why the WooCommerce total and the ERP invoice total are *intentionally* different (the reconciliation behind pickup-store invoicing). The offer-effectiveness report now reads the canonical channel, so per-channel offer ROI no longer mislabels orders as "unattributed" when they were placed before attribution caught up.
* **Accurate engagement & attribution.** The engagement score is now one canonical formula everywhere (it previously differed between the AI-chat context and the analytics reports). Re-delivered tracking beacons can no longer double-count add-to-cart totals (idempotent, deduplicated server-side). The Attribution dashboard no longer writes thousands of rows on every page view — the channel back-fill moved to an hourly background job — and all of its channel cards now use one consistent 7-day attribution window.
* **Storefront & block editor.** Carousels (Brand Slider, recently-viewed and the like) gained an optional **"Recos carousel" slider style** — the pink scroll-progress bar matching the recommendations carousel — selectable per block; the **Google Reviews** block gained a true manual swipe-scroll mode. Fixed block-editor errors ("Invalid parameter(s): attributes") that appeared on AIEO blocks under WordPress 7 by registering the shared responsive / section-header attributes server-side.
* **Housekeeping.** The server-side conversion log now self-prunes (30-day retention). Fixed a stored-procedure installer that, because of a `DELIMITER` directive, had silently never updated the session-analytics procedures.

= 7.0 Product-page layout builder (block + classic themes), reusable product/variation picker, master Button Styles (padding/sizing/glass), side-cart mobile bar styling, wishlist & brand in the layout builder, sticky admin navigation (05/06/2026) =

* **Side-cart mobile bottom bar — fully theme-independent + styleable.** The mobile sticky bottom bar (Navigator / Search / AI Chat / Cart) gets its own controls on the Side Cart tab: bar background colour + height, icon colour, and the cart-count number + circle colours (each can differ from desktop). A new **glass effect** renders the bar semi-transparent with a frosted backdrop-blur (opacity + blur configurable) so the page shows through. New **per-option "selected" colours** (background / text / border for each of Navigator, Search, AI Chat, Cart) highlight an option while its panel is open. When ONLY the cart icon is enabled you can show it as a **floating bubble** (like the desktop cart) instead of a full-width bar, and a lone cart icon is now centred with its count badge correctly anchored.
* **Side-cart display owned by the runtime.** The whole side-cart surface (the floating shell, the mobile bar, the slide-out panel and its assets) moved into one shared class bundled in both plugins, so the runtime renders it even when the admin plugin is trimmed from a request; the admin module remains the standalone fallback.
* **Product Needs — new "Pills" display.** Alongside the stacked list, the product-needs taxonomy can now render as tag-style pills laid out side by side, with their own text size, corner radius, vertical / horizontal padding, gap, background, border (width + colour) and text colour.
* **Master Button Styles — padding, sizing and glass.** Every master button group (Primary / Secondary / Archive) now also controls **Top / Right / Bottom / Left text padding** and **min / max width + height** (0 = no constraint), plus an opt-in **glass effect** (transparent background via `color-mix` + backdrop blur, opacity + blur per group). The Secondary group gained full hover parity — a base border plus hover background / text / border colours — to match Primary and Archive.
* **Wishlist + Brand in the product-page layout builder.** "Add to Wishlist" is now a positionable element in the Display Order list with a **Beside image / Beside the product title / Under image** choice (the heart sits inline next to the title by default). Brand Display gained the same **"Beside the product title"** option, and the builder's placement is now authoritative over the per-module Brand position setting.
* **Admin polish.** Fixed the "AI Optimizer" toolbar icon occasionally stacking above its label (a theme `img{display:block}` rule). Reordered the AI Optimizer sidebar submenu to **Data Prep → e-shop Manager → AI Chat → Interactivity (IAPI) → Rec Cache** and removed the one-off Session Schema Migrator from the menu. The AIEO admin **top bar and the e-shop Manager / Analytics sub-tab navigation are now sticky**, staying visible as you scroll long settings pages.

* **Product-page layout builder — one list orders the whole product info column.** Storefront Display → Single Product Page → Dashboard now has a single drag-and-drop "Display Order" card that governs the vertical order of EVERYTHING in the product info column: the core elements (title, rating, short description, sale-eligibility and free-shipping messages, price, add-to-cart) AND the info modules (product meta, categories, brand, payment logos, trust badges, back-in-stock waitlist, free brand gifts, complementary products, product needs, role-pricing login). Each module also gets a per-item "Beside image / Under image" choice, so it can be moved beneath the gallery. The same saved order is honoured on BOTH the block (FSE) theme — via CSS `order` on the info-column flex children — and on classic themes (Botiga / FemmeFatale-V2), by re-prioritising the matching WooCommerce single-product-summary hooks (WC core templates + AIEO modules), so the two render identically. Core blocks that ignore `className` (rating, short description, add-to-cart) are now wrapped so their order always applies, and Brand Display's before/under-title placements follow the list instead of being pinned above the title.
* **Restored the product "ΚΑΤΗΓΟΡΙΕΣ" (Categories) line as its own positionable module.** When AIEO replaced WooCommerce's native product-meta block (SKU + categories + tags) with its SKU/barcode strip, the categories line was dropped. It is back as its own orderable module — a clickable comma-separated list, styled to match the SKU/Barcode rows (label and list flow as one inline stream, with uniform vertical spacing) — placeable before or after Product Meta. The Role-pricing "log in to see your price" message is likewise positionable within the info column. (Product Categories was also moved to the "Single Product Page" section of the Storefront Display menu, next to Product Meta.)
* **Reusable product / variation picker on every product-criteria field.** A shared modal browser — search by name, SKU or brand; pick simple products, whole variable products, or specific variations; drafts and deleted items shown greyed, variations badged — replaces the free-text ID/SKU/barcode boxes on the offer forms: **Product discounts, Free gifts and Free shipping** (both the "specific products" and the "excluded products" lists), plus the **Product Exchanger** feed builder and the **marketplace feed exporter**. Picked variations roll up to their parent so cart matching is unchanged, and existing saved selections migrate automatically. One shared implementation (`AIEO_DMM_Product_Picker`) drives them all.
* **Master "Button Styles" control (Tools).** A single card now sets the default background, text colour, border (colour + width), corner radius and hover state for every AIEO storefront button — with three masters: **Primary** (add-to-cart, checkout, "notify me", "add selected"…), **Secondary / neutral** (view cart, save / share cart, apply coupon) and **Archive** product-card buttons. Each button that already had its own colour picker — Back-in-Stock Waitlist, Complementary, Sticky Add-to-Cart, Side-Cart — now inherits the master by default and overrides it only when you set a value (a CSS custom-property fallback chain, so nothing you previously customised changes). The side-cart action buttons, the storefront "Save / share my cart" button, the coupon-Apply button and the variable-product multi-select "update cart" button were aligned to the same tokens. Also fixes a long-standing admin bug where the colour-picker swatches rendered blank on the DMM settings pages (a global rule forced the swatch background transparent) — every DMM colour picker now shows its colour.
* **Admin discoverability.** The Ctrl / ⌘-K quick navigator now indexes the product-page layout/positioning card and the Saved & Abandoned Carts report; the AI Insights assistant gained an abandoned-carts analysis playbook plus "where does this live" pointers for the layout builder, the carts report and the product picker.
* **Auto-restock — e-shop sales no longer counted as physical-store demand.** The "Stock Recovery" auto-restock signal mines physical-store sales from the ERP to find products that are out-of-stock online but still selling in shops. The e-shop's own sales — invoiced through the head-office branch with a distinct ERP invoice-type code — are excluded from that signal so they cannot inflate in-store demand and trigger false restocks. The contract is documented for multi-store setups (give the e-shop's ERP sales a distinct invoice type).
* **Stock Recovery — out-of-stock cancellations surfaced as a "failed restock" signal.** When an order line is cancelled with the reason "Out of stock", the affected products are reconciled against the restock activity and shown in the Failures KPI, so restocks that didn't actually prevent a lost sale are visible.
