Skip to main content

Changelog

All notable user-facing changes to SyteHero are documented here. Uses Keep a Changelog format with Added / Changed / Fixed / Removed buckets.


v1.0.191 — 2026-10-26​

Added​

  • The license consent record now includes the address of the person who agreed, alongside the server's. It is saved as reported by your site and is not verified.

v1.0.190 — 2026-10-26​

Fixed​

  • The debug log can no longer contain text a web server could run. Text from a request or an error message could reach the log as written, and two requests writing at the same moment could leave the log without the line at its top that stops a web server from running it. Now every character that could start code is stored in a harmless escaped form, and each request checks that line and writes under a lock, writing nothing when it cannot.

v1.0.189 — 2026-10-26​

Fixed​

  • A banner shortcode no longer crashes the page on older WordPress. On WordPress before 6.5, a banner shortcode with no settings in it ([your_banner]) stopped the page with a fatal error.
  • The debug log can no longer be downloaded from your site. On servers that ignore .htaccess (OpenLiteSpeed, Nginx), the log at its fixed address could be fetched by anyone while debug logging was on. It now lives in a folder whose name includes a code made from your site's security keys, in a file that starts with a line that stops a web server from showing it. It is also capped at 1 MB, with one older file kept. Updating removes the old sytehero-logs folder, and deleting the plugin removes the new one.
  • Saving the Heroes tab at the same moment the plugin gives older custom slides their ids no longer loses the save.
  • The fallback slide is now named the same in analytics on every page. Before, it took the title of whichever page it was shown on.
  • Deactivating SyteHero now stops all of its background tasks, including the analytics clean-up, the licence re-check, the Google Calendar sync, the banner check and the cache purge. Before, they kept running with nothing to answer them. Sale and slide start and end events stay booked, as before, so a sale still ends on time after you turn the plugin back on.
  • During an update across several servers that share a database, the page-file version cache no longer gets rewritten back and forth, and a file whose modified time moves backwards is no longer re-checked on every page load.

v1.0.188 — 2026-10-26​

Added​

  • A publicSubset() helper in the headless kit gives a frontend only what may reach the visitor's browser: live items and pre-armed ones, without the names, products or dates of campaigns that have not started.

Changed​

  • Visit tracking is harder to flood. Visitors on one IPv6 network now share one limit, and your site records at most 600 new visits a minute, with a fair share for each source so a few cannot crowd everyone else out, and a separate allowance for visitors returning from the same place. At most 2 million stored visits are kept: when there are more, each source of visits is held to its share, a flooding one first, so a flood no longer removes your older visits from elsewhere, and visits that led to an order are always kept. A developer can change either number with a filter.
  • On a headless site, slide views and clicks reported from anywhere but your own site are counted only when they state the visitor's consent, as the frontend's own already had to. Your WordPress pages now state it with every view and click they report, after your consent banner allowed it.
  • The headless kit's clock check now ignores a difference of more than an hour from the server's clock (it was 24 hours), and its request now goes past caches, a CDN's included.

Fixed​

  • Slide views and clicks from a headless frontend are no longer lost when its pages send no referrer. On a frontend whose pages set Referrer-Policy: no-referrer, every view and click was refused without an error.
  • A headless frontend whose consent banner only answers when asked now records the visit's source. When the visitor accepted after the page had loaded, the landing visit (and the campaign link it came from) was lost, and the slide in view was not counted.
  • On FluentCart, an order whose visitor sent Global Privacy Control or declined statistics is no longer linked to their earlier visits. The checkout already kept no hero credit for such an order; the link to the visitor's earlier visits was still made when the payment was processed.
  • A pre-armed campaign on a headless frontend now comes down on time when the visitor's device wakes from sleep or they return to the page with the Back button. Before, it could stay up past its end.
  • The Analytics tab no longer plays a YouTube or Vimeo video reported by a visitor's browser for a slide that no longer exists. Playing it let whoever uploaded the video see when you opened the tab. Slides you still have preview as before.

v1.0.187 — 2026-10-26​

Fixed​

  • Deleting SyteHero now runs its clean-up at all. The clean-up was left out of the plugin download before, so deleting the plugin from the Plugins page removed nothing.
  • Deleting SyteHero now ends every running sale first. WooCommerce products get their own sale price and dates back, if they had a sale of their own, or else their regular price; FluentCart products get the price the sale replaced. A price you changed yourself while the sale ran is kept. Before, a sale price that was on when the plugin was deleted stayed on, and with nothing left to end it, a FluentCart sale (or a WooCommerce sale with no end date) never ended.
  • Deleting SyteHero now removes everything it stored. Before, its source-tracking tables (visitor ids and hashed emails among them), several settings, temporary data, scheduled tasks and its debug log folder were left behind. Your products, orders and their own data stay, and so do images you generated with AI and saved to the Media Library.
  • On a multisite network, deleting SyteHero now cleans every site, not only the main one.

v1.0.185 — 2026-10-26​

Fixed​

  • Daily sales reports no longer miss orders on sites with a persistent object cache (such as Redis or Memcached). Each report started at midnight instead of at the previous report, so the orders placed between the send time and midnight never appeared in any report, and a report could be sent twice.
  • Every order now appears in exactly one sales report. Before, "Only include completed orders" on WooCommerce counted an order in every report sent on the day it was completed, and a few orders placed while a report was being sent were left out of both.
  • On FluentCart, "Only include completed orders" reports are no longer always empty. They now include paid orders whose status is Completed, counted on the day they were completed.
  • A sales report now includes every order in its period. Before, a report stopped at 200 orders and left the rest out without saying so.
  • A hero slide is now credited with an order's revenue only once the order is paid. Before, an order that was declined, cancelled or never paid still counted on the Analytics tab.
  • On FluentCart, an order placed after clicking a hero slide is now credited to that slide. Before, many such orders were not credited, and the click could later be credited to a different order instead.
  • On FluentCart, amounts in reports now use your currency's decimals, for example none for the Japanese yen.
  • Orders you add in wp-admin, or place while logged in as a store manager, are no longer credited to a hero slide. The hero click in your browser is yours, not a customer's.

Changed​

  • Checkout now respects Global Privacy Control and a declined consent. When the visitor's browser sends Global Privacy Control, or they declined statistics cookies in your consent banner, SyteHero records nothing about the order: no "via Hero" flag, no revenue for the hero slide, and no link to the visitor's earlier visits. An affiliate coupon still earns its commission.

v1.0.184 — 2026-10-26​

Fixed​

  • Saving the Banners tab no longer moves a linked sale's start or end that you did not change. On the night the clocks go back, after a change of your site's time zone, or for a sale whose times have seconds (set through the API or a calendar), a save that changed nothing could move the sale, and its prices, by up to an hour.
  • Updating a product no longer moves its slide schedule, or the sale linked to the slide. On the night the clocks go back, an Update that changed nothing could move both an hour earlier. The same goes for the Heroes tab's schedule save and the API.
  • Saving the Heroes tab no longer moves a custom slide's schedule, or the sale linked to it, when you did not change it. On the night the clocks go back, or for a schedule whose times have seconds, a save that changed nothing could move it by up to an hour.
  • Two sales that follow each other on one banner now each get the banner. Before, the banner showed the later sale's dates while the first one ran, and when the first sale ended it lost the next sale's dates.
  • Your own banner text is no longer replaced by the default text when a sale on the banner ends. Before, it could be lost.
  • A date that does not exist, such as 30 February, is no longer saved as a date in March. It is not accepted.
  • The Go live immediately option on the Schedules tab, and the status shown beside a slide on the Heroes tab, now follow your site's time, whatever time zone your computer is set to.
  • The API refuses a banner or slide time it cannot read. Before, a slide time written with a time zone (such as Z) deleted the slide's schedule and unlinked it from its sale while reporting success, and any banner time was saved as sent. Banner and slide times are in your site's time zone; sale times in the API are still UTC.
  • A banner schedule changed through the API now switches the banner on and off on time, and updates the sale linked to it, as saving the Banners tab does.

Changed​

  • When a sale on a banner has ended, saving your schedules no longer puts that sale back on the banner. The banner shows your own text again, as it does when the sale ends.

v1.0.183 — 2026-10-26​

Fixed​

  • A product's price is no longer left wrong when one sale ends and another starts at the same moment. Before, the two changes could cross: the product could end up at its regular price during the new sale, or, on FluentCart, stay at the old sale's price after both sales had ended.
  • Saving the Schedules tab and the automatic save of a schedule card no longer overwrite each other. A sale you deleted could come back. Save now waits for any automatic save still on its way.
  • Typing a sale's date no longer changes prices before you finish. A date is saved automatically when you leave its field, not while you type it.
  • On FluentCart, a sale price of 0, or text that is not a price, no longer stops another running sale's price from going on. It is not saved as a price, and it is never shown as a sale price.
  • On a store that writes prices with a decimal comma, a sale price such as 19,99 is no longer read as 1999. Prices are read and shown the way your store writes them. A sale price that is not lower than the product's regular price is not applied, and saving the schedule warns you about it.
  • While your license has lapsed, saving no longer puts sale prices on products. Prices still come off when a sale ends.
  • On WooCommerce, sale prices written early by older versions are now also removed from products you have since saved in the product editor. Before, those products could start their sale up to a day early.
  • The LiteSpeed cache is now cleared when a sale starts or ends from a page visit or from the five-minute check. Before, visitors could keep seeing the old prices.
  • On WooCommerce, a product's own sale price comes back when a SyteHero sale on it ends. Before, the product went back to its regular price.
  • On FluentCart, a price you change while a sale is running is kept when the sale ends. Before, the price from before the sale was put back over yours.
  • Removing the plugin now also removes the WooCommerce sale prices and dates that older versions wrote early, for sales that are not running.

Changed​

  • The help now says what turning the Schedules tab off does. It hides the schedule editor only: sales you have saved still start and end. To cancel a sale, delete it.

v1.0.182 — 2026-10-26​

Fixed​

  • A license key the license server doesn't know is now reported as not found, and features lock. Before, the key was treated as if the license server couldn't be reached: features stayed unlocked for 14 days and the Settings page said "Endpoint is not allowlisted". Removing the license from a site the license server holds no activation for is also answered at once.
  • Save Configuration no longer activates the license. Only Save License activates a site that shows Activation Required, so saving a setting on a staging copy of a site no longer uses up one of the license's activations. A new key or email you type in is still activated whichever button you click.
  • Removing the license while a background license check runs no longer leaves features unlocked. Saving, refreshing or removing the license no longer runs at the same time as a background check: while one runs, the page says "A license check is running. Please try again in a moment." Nothing about the license changes until you try again; your other settings are still saved.
  • The Settings page no longer says "License Active" when features are locked. After 15 days without a successful license check it shows License Re-check Needed, with a pointer to Refresh License Status. While the license server can't be reached and features keep working, it shows License Active.
  • Uninstalling SyteHero now also removes its license-check lock and the install-check rate limits.

v1.0.181 — 2026-10-26​

Fixed​

  • Three background maintenance tasks can no longer fail if they're triggered without their usual settings.

v1.0.180 — 2026-10-25​

Fixed​

  • On WooCommerce, a scheduled sale's price no longer shows before the sale starts. Saving a sale used to write its sale price to the products straight away, where WooCommerce's Store API (read by block themes and apps) listed it, also for a variation looked up on its own. Nothing is written to a product now until its sale starts. Sale prices that earlier versions wrote early are removed once after you update, in the background, wherever they still match the sale exactly; a price you have edited since is left alone. Where two running sales include one product, or an earlier version replaced a running sale's price with a later sale's, the right sale's price goes back on.
  • Saving a future sale no longer takes a running sale's price off a product both include.
  • Taking a product out of one sale no longer resets its price while another running sale still includes it. Nor does the end or removal of the sale with the higher price, also while the license has lapsed.
  • Saving a sale no longer makes WooCommerce rebuild its product lookup data for the whole store. Only the products the sale changed are refreshed.

Changed​

  • When two running sales include the same product, the lower sale price is the one shown. When that sale ends, the other sale's price goes back on.
  • A sale starts, and ends, within about a minute on a site with visitors. After a page is sent, SyteHero starts any sale that is due and takes off the price of any sale that has ended (putting another running sale's price back), at most once a minute, so neither waits for the next scheduled-task run. The store's API requests, such as a block theme's cart and checkout, never wait for it.
  • A sale that has not started no longer appears in the banner editor's list of store sales, pre-fills the product's sale dates in the product editor, or offers Match Sale Dates on the Featured Products page. On WooCommerce and FluentCart alike. All three show it once it starts.

v1.0.179 — 2026-10-25​

Fixed​

  • On WooCommerce, a sale now switches the product to its sale price as soon as the sale starts, everywhere the store shows prices.

v1.0.178 — 2026-10-25​

Added​

  • Pre-arm on headless sites. On a site with a frontend address, each sale card has a "Pre-arm on headless sites" switch (off by default). When it is on, the sale's slide, banner and countdown are sent to the frontend with the page before the sale starts and appear a minute after the start time, then come down a minute before the end. Anyone who reads the page source can see them early, including anything you type into the banner, slide text or sale name, such as a price. The feed's own price fields never reach a page before the sale has been applied. The headless feed now says which sales are pre-armed and lists every sale that names a slide, and the browser kit gains helpers that time the show and hide on the server's clock.

Changed​

  • Sale prices are no longer listed in the headless feed until the sale has been applied. Before the start, and after the end, the price fields of a sale's items are empty, so a price from the feed cannot reach a page early.

v1.0.177 — 2026-10-25​

Fixed​

  • A site no longer locks its licence when the licence server answers with a web page instead of licence data. If something in front of the licence server (a website, a cache or a proxy) answers in its place, SyteHero now treats the server as unreachable instead of reading the page as "licence not found". A licence that was valid stays active through the usual grace period, and the check is retried.
  • WordPress error replies and server failures behind the licence server no longer lock a valid licence. A "route not found" or "forbidden" reply from WordPress itself, or a failure of the store system behind the licence server, now counts as the server being unreachable, with the same grace period.
  • Removing a licence now warns you when its activation could not be freed. If the licence server can't be reached when you remove a licence, the licence is still removed from the site, and a notice tells you to free the activation from your SyteWide account.

Added​

  • wp-config settings to point a site at a different licence or update server. SYTEHERO_LICENSE_GATEWAY_URL and SYTEHERO_PUC_METADATA_URL can be set in wp-config.php. Only secure (https://) addresses without a username or password are accepted; anything else is ignored and the usual server is used. The licence address receives the site's licence key and email, and the update address decides which plugin code is installed, so point them only at a server you control. wp sytehero status shows whether each setting is in use or was ignored.

v1.0.176 — 2026-10-23​

Changed​

  • Pages no longer show the SyteHero version in script and style links; files still refresh in browsers when they change.

v1.0.175 — 2026-10-23​

Added​

  • A private version check for SyteWide's maintenance tools. SyteWide's tools can now see which SyteHero version a site runs without logging in to the server. The check answers only a request that carries the fleet's secret token; to anyone else it looks like a page that does not exist, and no cache ever keeps a copy. It works whatever the state of the licence. Nothing changes for visitors.

v1.0.174 — 2026-10-22​

Fixed​

  • Orders placed through WooCommerce's block checkout are now credited to the hero that was clicked. Before, only the classic checkout credited the order to the hero, so block-checkout sales never showed as "via Hero" or counted toward the slide's revenue. Block-checkout orders also now get their traffic source recorded in Attribution. An order is credited and recorded once, however it is placed.

v1.0.173 — 2026-10-22​

Added​

  • Headless frontends get a small script to measure hero impressions and clicks. A frontend on its own hostname can now count which heroes visitors see and click, and credit orders to the hero that was clicked, the way a WordPress page does. The script tracks only after the frontend's own consent banner says the visitor agreed, and stops if they withdraw. It does nothing for visitors who send Global Privacy Control or open a page with ?sytehero_notrack=1.
  • A documented contract for it. The hero feed now says where the script is and carries its checksum, so a frontend build can fetch it and verify it, and a developer guide lists every request the script makes, the limits the site applies, and what is silently not counted.

v1.0.172 — 2026-10-22​

Changed​

  • Preparation for crediting hero clicks on a headless frontend. This takes effect once the browser kit for headless frontends ships; until then nothing writes the cookie it prepares for. When your headless frontend and WordPress share a parent domain (for example www.example.com and wp.example.com), the hero feed now names that domain and a short id of your WordPress site, and checkout clears the hero-click cookie on that domain too, so an order is credited to a hero once and later orders are not credited to the same slide.
  • The clear keeps working after you change or turn off the headless frontend. For 31 days after the shared domain was last in use, checkout still clears the cookie there, because a frontend built earlier may still write it.
  • Two stores under one domain do not credit each other's hero clicks. A click recorded for another SyteHero store under the same parent domain is left for that store.
  • No shared hosting domain is ever used. The feed names no domain when the frontend and WordPress do not share one of their own, including a hosting provider's shared staging domain such as sytestage.com; the click is then still counted, but no order is credited "via Hero" from a frontend click.

Nothing changes for a site that is not headless.


v1.0.171 — 2026-10-22​

Added​

  • Headless frontends can now fetch the site's slider, sales and banners data with the site's PhantomStudio key. A headless frontend build reads one document with every slide and its schedule, the fallback slide, the custom heroes, the slider settings, the sales and the banners, so a static site can show what the WordPress site shows. The feed needs SyteOps, answers only a request carrying the site's PhantomStudio key, and is never cached. On a site whose licence is locked it carries no slides, sales or banners.
  • wp sytehero feed prints the same data on the site, so you can check what a headless build will receive.
  • The Integrations page's Headless Frontend card says whether the feed is available, that it needs SyteOps when it is not, and to turn on SyteOps' PhantomStudio integration when SyteOps is active but that integration is off.
  • wp sytehero status reports the feed (whether it is available and its format version) and how many scheduled sale, slide and banner changes are more than five minutes late.

Nothing changes for a site that is not headless.


v1.0.170 — 2026-10-22​

Fixed​

  • FluentCart stores now show their own currency. The currency symbol and code SyteHero uses on a FluentCart store (prices in the AI product picker, sales reports and order emails) now follow the store's currency setting. Before, they were always $ and USD.

Changed​

  • Internal groundwork for headless frontends. SyteHero can now describe a site's slider settings, sales, banners and browser settings as plain data, and its store connection reports the store's currency code. Nothing uses this yet, and nothing changes in how SyteHero behaves.

v1.0.169 — 2026-10-22​

Changed​

  • Groundwork for a headless data feed. SyteHero can now read every configured slide, the fallback slide and the custom heroes as data, along with whether each slide is live, scheduled or paused. Nothing uses it yet, so nothing changes on your site: the hero slider prints exactly what it printed before.

v1.0.168 — 2026-10-22​

Changed​

  • SyteHero now stays unlocked only on a site the licence is activated for. A site that is not activated on its licence shows an "Activation Required" notice on the Settings page, and its features stay locked until it is. Click Save License to activate it with the key and email already saved. If this site was activated before under this same address and the licence has a free activation, SyteHero first tries to activate it again: in its background check, or when you click Refresh License Status or Save License, and again at the next check if the licence server couldn't be reached. A site whose address was never recorded never activates itself in the background: it locks at its first check after this update, with no 14 days, until you click Save License.
  • SyteHero confirms the licence at least every 15 days. After 14 days without a successful check, an administrator's next dashboard visit runs one (at most once an hour); after 15 days, features lock until a check succeeds. The count starts at this update, so nothing locks when you update.
  • After a site moves to a new address, it keeps working for 14 days while you move the licence. Administrators see a notice naming the old and new addresses, the date the 14 days end, and how to move the licence with wp sytehero license move --from=<old address> (or remove the old address from the licence in your account and activate it on this site). When the 14 days end, the site locks until the licence is moved or activated there.
  • If the licence server can't be reached, features keep working for up to 14 days after the last successful check. Before, every failed check started the 14 days again. On a site that moved, those days end no later than the 14 days to move the licence.

v1.0.167 — 2026-10-22​

Changed​

  • Internal tidy-up. The install-check route's rate-limit clock was tidied internally. Nothing changes in how SyteHero behaves.

v1.0.166 — 2026-10-22​

Fixed​

  • An expired licence keeps showing as expired. An expired licence now keeps showing as expired, with its "Renew or contact support" prompt on the Settings page, instead of reading "Validation Pending" after a background licence check, including when the licence server is briefly busy or unreachable during that check. Renewing the licence unlocks the plugin again as before.
  • A disabled licence shows as suspended. A licence that has been disabled now shows as suspended, with a "License Issue" notice on the Settings page, instead of asking you to activate it. wp sytehero license move refuses a disabled licence before it changes anything, so the old site keeps its activation.
  • A licence at its activation limit shows a clear notice. The Settings page now says the licence has reached its activation limit and how to free one, instead of "Validation Pending".

v1.0.165 — 2026-10-21​

Fixed​

  • Debug logging no longer records the text of licence-server replies. With Write debug logs to file on, a licence check now logs only the reply's status codes, a short reason code, and, for a reply that is not JSON, its content type and length. The server's message, the body of a reply that is not JSON, and the text of a connection error are no longer written to the log, so a server error can't put licence details into it. What the Settings page and wp sytehero commands show is unchanged.

v1.0.164 — 2026-10-21​

Fixed​

  • The licence move checks the old address more strictly and reports the licence server's answers more clearly. wp sytehero license move now goes ahead only when the old address serves your headless frontend's marker as JSON, with every copy of its backend header naming this site; a marker served as a web page, or with a header that is empty or names another site, is treated as "the old host could not be checked" and can be retried. When the licence server refuses the move because the licence key, email or product does not match, or because it does not recognise the request's credentials, the move now reports error_license_status instead of error_server_unreachable, so it is not retried; a key or activation the server cannot find is reported as refused_not_activated. Only a server that cannot be reached or answers with a server error is reported as retryable.

v1.0.163 — 2026-10-21​

Added​

  • Move your licence to the site's new address: wp sytehero license move. After a site moves to a new address, for example when WordPress moves to a subdomain for a headless setup, run wp sytehero license move --from=<old address> --format=json on the site at its new address. It frees the activation of the old address and activates the new one with the same licence key, and it is safe to run again: a finished move answers already_moved, and an interrupted one picks up where it stopped. Add --dry-run to run every check without changing anything. A copy of your site never takes your licence: the move goes ahead only when the old address serves the marker your new headless frontend publishes there, naming this site, and a copy is refused. If WordPress still answers at the old address, finish the switch to the new address first. An old address that is gone for good needs the licence deactivated and activated again from Settings instead. The command prints a single line a script can read and never your licence key, email or any licence id. wp sytehero license status now reports that the move is available.

v1.0.162 — 2026-10-21​

Added​

  • See which address your licence is activated under: wp sytehero license status. It shows whether the licence is active, the site address (host) it is activated under, this site's address and whether the two match. Add --format=json for a single line a script can read, and --refresh to run the background licence check once first (this also records the address for a site that was activated before this version). wp sytehero status now reports the same details in its licence section. Neither prints your licence key, email or any licence id.

Changed​

  • Background licence checks no longer re-activate your licence under a different address. SyteHero now remembers the address your licence was activated under. A copy of your site (staging, a restored backup, a site-copy tool) no longer activates itself in the background and uses up one of your activations. Switching between www. and the bare address is not a change of address. SyteHero never locks a site because its address changed, but if that site's licence later needs re-activating (for example, the licence server reports it as expired), the background check does not re-activate it under the new address: it waits for the automatic move, coming in the next version, or you can re-activate it from Settings. To move an activation today, deactivate the licence before the move and activate it again afterwards.

v1.0.161 — 2026-10-20​

Changed​

  • When SyteOps Leads is on, SyteHero's consent mode follows SyteOps' consent setting. Opt-out, opt-in and geo-based now apply to SyteHero's tracking as they do to SyteOps', and a visitor's opt-in or opt-out answer comes from SyteOps. Without SyteOps, or with SyteOps' Leads module off, nothing changes: SyteHero keeps its own geo rule. Upgrade note: SyteOps' consent setting defaults to opt-out, so on a site with SyteOps Leads on where that setting was never changed, SyteHero no longer applies its EU/UK opt-in gate after this update. Set SyteOps' consent setting to geo-based (or opt-in) to keep it. A site's sytehero_consent_config filter can still set the mode. The sytehero_visitor_jurisdiction filter is not consulted while SyteOps is set to geo-based; use SyteOps' syteops_leads_visitor_jurisdiction instead. Until SyteOps v1.6.693, clear your page cache after changing the consent setting in SyteOps. wp sytehero status now reports the consent mode and who set it.

Fixed​

  • The visitor jurisdiction lookup is never stored by LiteSpeed page caches. The lookup could be saved and replayed to the next visitor on sites using LiteSpeed Cache; it now tells LiteSpeed and other page caches to skip it, and sends no-cache headers on WordPress 6.3.2 and later.

v1.0.160 — 2026-10-13​

Added​

  • Headless sites: the frontend is asked to rebuild when your campaigns change. On a site with a separate frontend, SyteHero now asks for the frontend to be rebuilt when a sale starts or ends, when a banner's scheduled window opens or closes, and when slides, sale schedules or banners are saved, so the frontend does not keep showing an old price or an ended campaign. Several changes made together lead to one rebuild. This needs SyteOps with its rebuild address set. On a site without a separate frontend no rebuild is requested and no scheduled task is added for it.
  • SyteOps' headless status lists what SyteHero offers. On any site that runs both plugins, headless or not, SyteOps' pairing status now includes SyteHero's capability names. They say what this version can do, not that anything is switched on.

v1.0.159 — 2026-10-13​

Added​

  • A wp sytehero status command. It reports the plugin's version, whether the licence is unlocked, the frontend address of a headless site, the public endpoints and when each scheduled task runs next, for site checks and frontend builds. Add --format=json for a single line a script can read. It prints no licence key, no credential and no IP address.


v1.0.158 — 2026-10-13​

Fixed​

  • A custom slide in the main slider keeps its own numbers. A custom slide you add to the main slider is now counted under its own identity, so its views, clicks and revenue stay with it when slides are paused, when a slide's schedule starts or ends, or when slides are reordered. Before, a custom slide was counted by its position among the custom slides showing at that moment, and any of those changes could move one slide's numbers onto another. Featured products, page and category slides, custom heroes and the fallback slide were not affected and are unchanged.

Changed​

  • A custom slide's history starts fresh from this version. The numbers recorded earlier are not moved and not deleted: they stay listed under the old entries in the Analytics tab and the Sources dashboard until they age out after 90 days. They cannot be given to one slide, because an old entry followed a position in the slider, and different slides held it at different times. Totals are unaffected.
  • A custom slide is named in the Sources dashboard from the start. Its row shows the slide's title as soon as an order is credited to it, without waiting for the slide to be viewed.

v1.0.157 — 2026-10-13​

Changed​

  • A slide shown only by a slider with its own tag is recognised from an ordinary page view. SyteHero learns such a slide by seeing its own slider show it to a visitor or customer. It no longer learns one from an admin-ajax or REST request, where the caller can choose what is shown.

v1.0.156 — 2026-10-13​

These changes harden the anonymous reports your pages send (visits, slide views and CTA clicks). Pages rendered by WordPress keep reporting exactly as before.

Fixed​

  • Visit reports must be sent in the body of the request. The visit-tracking endpoint also accepted its details from the address of the request, so a link or an image placed on your site could record a made-up visit whenever someone loaded it. Only the body of the request counts now, and a request with no body records nothing. SyteHero's own pages have always reported in the body.
  • Slide views and clicks are no longer dropped on sites with a persistent object cache (Redis, Memcached). On those sites, after one view or click was recorded, every other one arriving in the next five seconds was lost.
  • A view or click that could not be recorded no longer blocks the visitor's next one. Before, it still used up that visitor's allowance, so the same slide was not counted for them for up to five minutes.

Changed​

  • A limit on made-up slides. A view, a click or a sale can name any slide, so a script could fill your analytics with slides that do not exist. Slides that are not part of your site are now limited three ways. At most 2,000 of them are taken; nothing you already have is deleted to get there, and a site that already holds more simply takes no new ones until the old ones age out. On any one day (UTC) at most 200 of them are counted, whether they are new that day or not; once one has been counted that day, its further views, clicks and sales that day are counted too. And no name and no preview is kept for such a slide, so it appears in the Analytics tab by its identifier only. The slides you have set up are not limited and do not use up either number: featured products, the page, category and custom slides of the main slider, custom heroes and the fallback slide. Developers can change the two numbers with the sytehero_analytics_max_unknown_slide_keys and sytehero_analytics_max_new_slide_keys_per_day filters.
  • Sales revenue follows the same limit. Revenue is credited to the slide named by a cookie in the buyer's browser, and a buyer can change that cookie. Revenue for one of your own slides is not held back by the limit. Revenue that names any other slide is limited like a view of it, and a slide name of more than 60 characters is ignored. The order itself is never affected.
  • Revenue waits a moment when the analytics are busy. SyteHero saves one view, click or sale at a time. A sale that arrived while another was being saved used to be left out at once; it now retries for up to about a sixth of a second. A view or click still does not wait. If a sale's revenue cannot be saved it is left out of that slide's total and, when debug logging is on, noted in the debug log.
  • The same size limits apply to both ways of reporting a slide view. A slide identifier of more than 60 characters, or a media address of more than 2,048, is refused however the view is reported. Before, one of the two ways had no limit.
  • Headless frontends: a view or click that is not recorded because of a limit gets the same answer as one that was ({"ok":true}), so the answer does not show whether a limit has been reached. It can be sent again later.

v1.0.155 — 2026-10-13​

Added​

  • Gumlet videos now show a preview in the Analytics tab. A slide whose media is a Gumlet embed (https://play.gumlet.io/embed/…) used to show no preview there. It now plays in the tile, as YouTube and Vimeo slides do, for slides you still have. The preview appears in Chrome and Edge; other browsers show the slide's numbers without a preview. Your slides themselves are unaffected.

v1.0.154 — 2026-10-13​

These changes only affect a site that runs behind a reverse proxy, load balancer or CDN and has listed it in the SYTEHERO_TRUSTED_PROXY_IPS setting in wp-config.php. A site that never added that setting works exactly as before.

Fixed​

  • A visitor behind your proxy can no longer dodge the limits on slide views and clicks by forging an address. Each proxy adds the address it saw to the end of a forwarded list. SyteHero used to read the start of that list, which the visitor's own browser can write. It now reads from the end, the part your proxy writes.
  • Visit tracking now counts each visitor behind your proxy separately. The visit-tracking endpoint ignored the trusted proxy setting, so every visitor behind the proxy shared a single limit and visits could go unrecorded on a busy site. It now uses the same setting as slide views and clicks.

Changed​

  • X-Real-IP is no longer read unless you ask for it. It used to be a fallback when the forwarded list gave no answer, and a caller can write that header itself when the proxy does not set it. If your proxy sets X-Real-IP rather than X-Forwarded-For, add SYTEHERO_CLIENT_IP_HEADER set to x-real-ip in wp-config.php.
  • The trusted proxy list accepts address ranges. An entry may be a single address or a range such as 203.0.113.0/24 or 2001:db8::/32, which is how CDNs publish their addresses.
  • If you already use the trusted proxy setting, limits may be counted differently after this update. List every proxy between your visitors and WordPress, and nothing else: a proxy missing from the list is counted as if it were the visitor.

v1.0.153 — 2026-10-13​

Fixed​

  • A product removed from a running sale is no longer left on its sale price when taking the price off fails. If the product could not be saved at that moment, the sale's record forgot it and nothing tried again. It now stays on record and is tried again at the next five-minute check, also while your license has lapsed.
  • A FluentCart price that the database refuses to save is no longer treated as saved. The sale's record and the product's pre-sale price are kept, and the change is tried again.

v1.0.152 — 2026-10-13​

Added​

  • Sale prices are now checked every five minutes. A sale's price goes on and comes off at a scheduled moment. If that moment was missed, because a scheduled task was lost or the site could not be reached at that minute, nothing used to try again: a price could stay on after the sale ended, or never go on. The check now puts it right within about five minutes, in both directions. A price left on by a start or end that was missed before this update is not corrected automatically; end or remove that sale from the Schedules tab. The check runs with your site's scheduled tasks, so a site where those are switched off entirely is not covered.

Changed​

  • Saving while a sale is running no longer re-saves every product in it. Each save used to apply the sale price to every product in every running sale again. A sale is now applied once, and again only when its products or prices change.
  • A FluentCart sale price is only ever read from the sale itself. A price value stored anywhere else in the site's data is never applied to a product.

Fixed​

  • A sale's prices still come off when your license has lapsed. Before, a lapsed license stopped sale prices being taken off at the end of a sale. They are now always taken off. No new sale price is applied until the license is active again.
  • Changing a sale's dates no longer leaves an old start or end waiting to fire. The old end could take the price off at the old time, and the old start could put it on early.
  • A sale whose price was taken off can be applied again while it is still running. Before, it stayed off until the sale was saved again. This includes a sale switched off and on again, or emptied and refilled.
  • A product in two sales that overlap keeps a sale price when one of them ends. Before, it went back to its regular price until the schedules were next saved.
  • One product that cannot be saved no longer holds up the rest of its sale. The others get their price, and the one that failed is tried again at the next check.
  • A date changed in the Schedules tab takes effect when it is autosaved. Before, the new dates were stored but prices, slides and banners kept following the old ones until the next full save.
  • A sale created, changed or removed through the REST endpoint now schedules and clears its price changes. Before, its prices did not follow until the schedules were next saved from the admin.
  • Removing the plugin puts FluentCart prices back to what they were before a sale, and clears its sale records. Before, a product on sale when the plugin was removed kept its sale price.

v1.0.151 — 2026-10-13​

Fixed​

  • Sale prices now change at the time shown in the Schedules tab. On a site whose time zone is not UTC, a sale's prices and countdown could start and end several hours away from the time you entered, while its banner switched at the time you entered. They now all follow the time shown in the Schedules tab. A site set to UTC was never affected and sees no change.
  • A sale time entered for a date on the other side of a daylight-saving change is no longer an hour off.
  • Schedule times are always your site's time zone, whatever your browser's. Editing a sale or a slide schedule from a computer set to a different time zone no longer shifts it.
  • Saving the Banners tab no longer moves a linked sale. On a site not set to UTC, every save of the Banners tab pushed the sale linked to a banner further away by the site's offset from UTC.
  • Changing a custom slide's schedule on the Heroes tab no longer shifts the sale it is linked to.
  • The status shown beside a slide or schedule (Active, Scheduled, Expired) now matches its real window on a site not set to UTC.
  • The REST endpoint for sales refuses a date it cannot read. It used to answer as if the sale had been saved while saving nothing, and an update with an unreadable date could remove the sale. It now answers with an error and leaves everything as it was.

Changed​

  • Your existing sales are adjusted once. After you update, each sale you had already saved is corrected so that it runs at the time the Schedules tab has always shown. A notice in the WordPress admin lists the adjusted sales that have not ended yet (the first 25, then a count), each with its old and new times, and stays until you dismiss it. A sale whose lower price had started early stays on that price until the sale ends. A sale whose corrected end has already passed is ended right away.
  • A sale linked to a Google Calendar event keeps its price times, so it still matches your calendar. The Schedules tab, and the sale's banner and slide, now follow that same time; before, they could show a different one. These sales are listed in the same notice. Check that each one runs when you want it to.
  • The REST endpoint for sales takes its times in UTC. A time may be written as YYYY-MM-DD HH:MM:SS or in ISO 8601; an ISO 8601 time with an offset is converted to UTC, and one without is read as UTC.
  • Restoring a backup made with an earlier version adjusts its sale times the same way.

v1.0.150 — 2026-10-13​

Fixed​

  • FluentCart sales now change the price of a product with one price option. Before, the sale price was never applied to such a product.
  • A FluentCart sale now returns the product to the price it had before the sale. This includes products with no compare-at price, which used to keep the sale price after the sale ended.
  • Removing a FluentCart sale that never started no longer changes a price. Before, it could raise the price to the compare-at price.
  • An empty sale price is never applied. Before, it could set the price to zero. Clearing the sale price of a running sale now puts the regular price back at once.
  • A price an earlier version changed on the wrong FluentCart product is put back. Where an earlier version discounted a different product by mistake, that product returns to its compare-at price the next time the sale is saved or ends.

v1.0.149 — 2026-10-12​

Fixed​

  • Headless frontend consent can no longer be sidestepped. Reports from a separate frontend must confirm the visitor's consent (consent set to granted). That confirmation now has to be in the body of the request, not in a link's address; it is also required when a frontend reports through admin-ajax; and it is still required when the frontend shares the WordPress site's own address.
  • Slide previews in the Analytics tab are safer. For a slide that no longer exists, the preview address was reported by a visitor's browser, not chosen by you. Such an address is now shown only when it is a media file on your own site or a YouTube or Vimeo video; anything else shows no preview. For slides you still have, a preview whose media is on another site is now loaded without your login cookies, so it appears only if that site allows cross-site loading, and embeds other than YouTube and Vimeo no longer preview. Your slides themselves are unaffected.

Changed​

  • The site's own address can no longer be saved as the Frontend address. It is not a separate frontend, and saving it would have stopped visits from your WordPress pages being recorded. Enter the address of your separate frontend, or leave the field empty.

v1.0.148 — 2026-10-12​

Added​

  • Headless site support for visitor tracking. If your public site is a separate frontend and WordPress runs on its own address, enter the frontend's address under Integrations → Headless Frontend. Attribution touches, slide impressions and CTA clicks sent from that address are then recorded, under the same server-side Global Privacy Control, consent, bot and rate-limit checks as before. Because WordPress cannot see a consent choice made on your frontend, each report from the frontend must include consent set to granted, sent only after your frontend has checked the visitor's choice; anything without it is ignored. Requests from any other address are still refused. If you leave the field empty, your site keeps behaving as it did. When SyteOps manages the frontend address, SyteHero uses that one and shows it read-only.
  • Impressions and clicks can be recorded through the REST API. A separate frontend can now report slide impressions and CTA clicks without going through admin-ajax, which some CDNs challenge for anonymous visitors. Pages rendered by WordPress keep working exactly as before.

v1.0.147 — 2026-10-08​

Fixed​

  • Updating a featured product no longer resets its hero text settings. Editing stock, price, or other product details in the product editor could quietly turn a slide's Hide / Custom Text choices back into Use Default, so the first (or any) featured product showed the site-wide default copy again. Those settings now stay as you left them.
  • Swiper loop mode no longer paints the wrong slide's hero text after wrapping. On sites using the Swiper engine with looping enabled, the overlay could briefly (or stickily) show another slide's text when the rotation wrapped past the end.

v1.0.146 — 2026-09-25​

Changed​

  • Replaced fal spend estimates with fal's actual billed cost, wherever fal makes that available. Once fal's own billing system confirms what a generation actually cost (usually within minutes), the AI Media grid and the Generate modal's monthly total switch from the list-price estimate to that real figure, labeled "fal billed" instead of "fal list price"/"includes estimates" — a month can also show "mixed" when some generations are confirmed and others are still estimates. This needs a fal team key with the Admin role — the same key that already reads your account balance directly (v1.0.145); without one, everything keeps working exactly as before, still labeled by list price/estimate, and nothing about generation itself changes either way. The Generate modal now also shows the fal team's own total spend for the month when that figure is available.

v1.0.145 — 2026-09-25​

Changed​

  • The Generate modal's balance now reads your fal key's own team balance first. A fal Admin key can read its own team's account balance directly, so the separate optional billing key added in v1.0.143 is no longer needed — use an Admin key from the client's fal team instead. Sites that already saved a billing key keep working exactly as before (it's now used only as a fallback if the main key can't read the balance, and only when that key is valid but simply lacks billing permission — a rejected/revoked key is reported as such instead of silently trying another account); the field on the AI Image Providers card is hidden unless one is already stored, and shows a note explaining it's only a fallback, not needed once your fal key is an Admin key. When the fallback IS the one answering, the Generate modal now says whose balance it's actually showing, since it can belong to a different fal team than the one this site's own key is for.

v1.0.144 — 2026-09-25​

Added​

  • fal spend tracking, at fal's published list price — with honest estimates for editing models. Every AI Media grid card now shows the actual per-generation cost (e.g. "$0.025 · fal list price") instead of only a rough estimate tier, and the Generate modal shows this month's total spend and generation count (e.g. "$0.20 (6 generations, 1 not priced) · includes estimates"). Pure-generation models (priced per output megapixel, per image, or per known-duration second) are tracked at exact fal list price; editing/processing models fal prices by units it cannot derive from the output alone (e.g. "processed megapixels" or a token-priced endpoint) are tracked via fal's own historical-average estimate instead, never a number presented as exact when it is not. A generation whose cost genuinely cannot be determined shows "cost unknown" rather than a misleading $0.00 — it is never guessed, and the monthly summary calls out how many generations were not priced; when EVERY generation in a month is unpriced, the summary says so plainly ("price unknown (N generations)") instead of showing $0.00. The figure excludes any account-level discount and only counts generations run through this site.

v1.0.143 — 2026-09-25​

Added​

  • Optional fal billing key. The AI Image Providers card's fal tile now accepts a second, optional key used only to read your fal account balance. A fal team key — what most sites use for generation — cannot read fal's billing information, so this lets you add a separate Admin key from the account that pays the bill without touching the key used for generation. It's never used for image generation, uploads, or the Assets library — only the balance display.

Fixed​

  • The Generate modal's balance display no longer shows a misleading $0.00 when fal rejects the current key for reading billing information. It now shows that a billing key is needed, matching what actually fixes it.
  • Clicking the balance Refresh button now always fetches a fresh balance, instead of sometimes silently doing nothing if clicked within the automatic 5-second refresh window.

v1.0.142 — 2026-09-24​

Fixed​

  • Using an image from the fal library now reuses the copy already in your Media Library when it's the same image, instead of importing a duplicate. Previously, clicking Use on an image the site had generated itself (background removal, upscaling, Extend to Fit, or a standard AI generation) always created a second, duplicate attachment, because dedupe only recognized images imported through Use before. A site-generated image is now recognized too — by its saved output link first, then by its file contents if needed — so Use on it reuses the existing attachment instead of downloading a copy. A copy you've since cropped or rotated in WordPress's Image Editor is never matched this way, since its file has changed. A batched background sweep also backfills recognition for images generated before this update, a small number at a time, so large media libraries are never affected all at once.

v1.0.141 — 2026-09-24​

Fixed​

  • Google Calendar pull sync no longer runs twice at once. Two overlapping requests could previously both start a sync cycle, risking duplicate calendar API calls and conflicting schedule updates; only one now runs at a time, and the crash-recovery timeout is long enough (180 seconds) that a legitimately slow sync — a token refresh, a large paginated fetch, or a full resync — can never have its own lock stolen out from under it by a second overlapping request.
  • The "No Active Slides" alert email no longer sends twice for the same outage. Two page loads landing at the same moment could previously both send the alert; only one email now goes out.
  • Background license validation no longer re-checks the licensing server twice at once. Two overlapping background runs could previously both call the licensing server concurrently; only one now runs at a time.
  • A periodic Sales Summary report email can no longer send twice. Two overlapping scheduled runs could previously both build and send the same report; only one send now goes out.
  • A real-time Sales Summary digest email can no longer send twice for the same batch of orders. Two overlapping scheduled runs could previously both drain and send the same queue; only one send now goes out.

v1.0.140 — 2026-09-24​

Added​

  • AI Studio has a new Assets tab. Once a fal team API key is connected, browse, search, and filter your fal Assets library — by type or by collection — preview an asset with its lineage, and click Use to copy it straight into this site's Media Library instead of generating it again. Using the same asset a second time never creates a duplicate, even if you click "Use" on it twice at once. A SyteOps Admin can create a new collection right from this tab (the only place one can be created) and set a default collection so new generations — including background removal, upscaling, and Extend to Fit — file themselves into your library automatically; leave it unset and nothing is filed. Everyone else can still browse and reuse assets.
  • New generations no longer expire on fal's side. So an image stays reusable from the Assets tab whenever you need it later.
  • Video cards in the Assets tab now say why "Use" is disabled. A "Video · images only" label explains it, and screen readers get the same reason.

Fixed​

  • Reusing an asset that fal's search returned as the closest match, but was not actually the same picture, no longer skips filing the real generation.
  • Changing the default collection now takes effect immediately instead of sometimes reverting on the next visit.
  • Browsing the Assets tab no longer re-fetches your whole collection list on every keystroke, search, or Load more — it's cached for 5 minutes and refreshes itself the moment a collection is created or the default changes.

v1.0.139 — 2026-09-20​

Added​

  • SyteOps can supply an image AI provider's settings. On a site running SyteOps, an image AI provider SyteOps is set to manage uses the API key, on/off switch and model choices it supplies. That provider's controls on the Integrations page become read-only and carry a "Managed by SyteOps" link straight to the screen that owns them, so there is one place to change the key rather than two. Nothing SyteOps supplies is saved into SyteHero, and any key you entered here is kept untouched and comes back if management ends.
  • Without SyteOps, nothing changes. If SyteOps is not installed, or is not managing the provider, every provider keeps using the settings stored in SyteHero exactly as before.

v1.0.138 — 2026-09-10​

Changed​

  • Transform's picture uploads are held to 30 seconds. Before a Transform job is sent, SyteHero now has 30 seconds to download and upload the picture being edited and any extra reference photos a companion plugin sends with it. The photos upload one after another within that time. If they don't all finish, the job stops before it runs and asks you to try fewer photos, so a slow upload can't leave behind a generation you never see. At most 8 extra photos go with one job.
  • The 30 seconds also applies to a plain edit. With no extra photos, the picture being edited still has to be downloaded and uploaded within those 30 seconds. If its upload runs out of time, it is sent inline with the job instead, as it already was when an upload failed, so the edit still runs.
  • Each AI model's picture limit is respected. Where fal publishes how many pictures a model accepts, SyteHero never sends more. Extra photos past the limit are left out, and the picture being edited is always kept. The image models list now also tells companion plugins each model's limit.

Fixed​

  • A missing offloaded image now gives a clear error. If a picture stored on an external media host such as S3 can't be downloaded, or the host returns a web page instead of an image, the job stops with a message naming the attachment. Before, it failed inside the AI service with an unclear error.
  • A reference photo that fails to upload now stops the job. Before, it could be inlined into the request, which risks running out of memory with large photos. Now the job stops before it runs and names the photo that failed.

v1.0.137 — 2026-09-10​

Added​

  • Transform can use extra reference photos of a person. When a companion plugin such as SyteOps sends reference photos with an image edit, AI models that accept several images now receive them after the picture being edited, so the result can match that person's likeness. Models that take a single picture, text-to-image models, and masked edits behave exactly as before. The image models list now also tells companion plugins which models accept extra photos.

v1.0.136 — 2026-09-09​

Removed​

  • The Straico AI provider is no longer offered. Its API key field and model picker are gone from the AI Providers card, and any Straico key still stored is deleted when the plugin updates. The remaining providers — OpenAI, Anthropic, OpenRouter, Gemini and fal — are unchanged.

Changed​

  • A saved AI provider that no longer exists now falls back instead of failing. If a function such as Image SEO Meta was pointed at a provider that has since been retired, it quietly switches to the default provider and its recommended model rather than returning an error, so generation keeps working without visiting the settings screen. Pick a different provider at any time on the Integrations tab.

v1.0.135 — 2026-09-09​

Fixed​

  • AI text generation now works when a reasoning model is selected. Choosing one of OpenAI's reasoning models — the o-series, or anything in the GPT-5 or GPT-6 families — made every AI text request fail with an error returned by the provider, because those models reject the temperature and maximum-token settings the older chat models expect. A request to a reasoning model now leaves temperature out, so the model uses the single value it allows, and sends the response-length limit under the name those models accept instead of alongside it. Models that do accept both settings, such as GPT-4o, are unchanged, and the fix applies whether the model is reached directly or through OpenRouter.

v1.0.134 — 2026-09-08​

Changed​

  • Internal improvements and maintenance.

v1.0.133 — 2026-09-08​

Added​

  • GPT-Image 2 can now be chosen for watermark repair. It was already available for changing a picture with AI; it can now also be selected as the model that removes a watermark from an archive image. It is an option, not the default — the existing default is unchanged, deliberately, because switching it would re-run a paid repair across every image already processed.

Fixed​

  • Progress while a picture is being made now reflects what is actually happening. The image service reports a job's state, but only two of them were understood — "finished" and "working". A picture waiting its turn, a failure, and anything unrecognized all looked identical to "nothing has happened yet", so the wait showed no useful information. Waiting in the queue is now reported as waiting, along with your place in line when the service supplies it, and a job that genuinely cannot be measured says so instead of reporting zero.
  • The plugin's own image window no longer shows "0%" for the whole run. On the kinds of work the image service cannot measure, it displayed a percentage that never moved. It now shows elapsed time alone rather than a number that means nothing.
  • A picture made by changing another one is now named after the original. The new file kept a generated name, so a recognizable photo became an unrecognizable filename in your media library, in its web address, and in any log that records it. It now carries the original's name plus a marker showing it was derived, and two versions of the same picture can never overwrite each other.
  • Text you type keeps its exact characters. A backslash in an image's title, caption, description or alt text was silently removed when saved. This affected pictures created by changing another one, and the metadata editor.

v1.0.132 — 2026-09-04​

Fixed​

  • Viewing a page can no longer remove your slides. When a slide's schedule ended, the clean-up that un-features the product or removes the slide row was carried out by whichever visitor happened to load the page at the wrong moment. On a public page that meant an anonymous visitor could quietly delete slide data you still had in front of you in the admin. Expired slides were, and still are, hidden from the slider either way — only the clean-up moved. It now runs on the scheduled task that owns it, or while you are working in the admin, never from a public page view.
  • Saving hero text and styling now refreshes cached pages. Set Defaults, hero layout, per-view overrides, random lines, Custom CSS, Custom Heroes and the slider engine or theme selection all saved correctly but left cached pages untouched, so on a site with a page cache the old hero could keep being served long after the change. Saving any of them now clears the cached pages along with SyteHero's own cache.

v1.0.131 — 2026-09-04​

Changed​

  • A call-to-action button marked visible but left without a label now renders empty instead of falling back to the button text already present in your theme. An unset label is now visible so it can be corrected, rather than quietly showing unrelated copy.

Fixed​

  • The first slide no longer falls back to your theme's own hero text. On some page loads the first slide displayed whatever headline, subheadline or button label was already written into the theme's own text elements, instead of the hero text configured in SyteHero. Nothing was ever lost — the saved settings stayed correct and only the front end was affected — and re-saving the slide appeared to put it right, which made it look random. Slides after the first were unaffected: SyteHero repaints those every time the slider advances, while the first slide is painted only once, before the slider starts, and was never repainted again when rotation was switched off. A slide's configured text is now authoritative, the overlay stays hidden rather than exposing theme copy when the text elements cannot be found, and the first slide is repainted if the theme is still settling when the page loads.
  • A malformed CTA button selector no longer stops every hero on the page from painting. An invalid selector raised an error that halted all sliders on that page, leaving each of them showing theme text.

v1.0.130 — 2026-09-03​

  • A caller can now ask for a source image at a chosen resolution. Image-to-image jobs previously always sent WordPress's large intermediate — a recompressed downscale, typically 1024px — whatever the original was. A caller may now give a long-edge budget, and the largest representation that fits is sent instead. This is what preserves small text and logos through a re-roll. Existing callers are unchanged: with no budget, the large intermediate is still used.
  • The provider request contract now documents preserve and max_source_px. preserve has been read since launch and was never listed, so no caller on the other side of that seam could learn it existed.
  • Portrait 3:4 is now an offered aspect ratio. fal has always accepted it — the enum was already mapped — but it was missing from the advertised list, so a 3:4 or 2:3 source had to be squared or stretched to 9:16. It is now selectable and maps correctly on every model family.
  • A pixel budget is honored on sites that offload media to a CDN. Recorded image dimensions live in the database even when the files do not, so an offloaded library now picks the right size rather than silently falling back to the 1024px copy.
  • A source image is read only from inside the uploads directory, and an over-budget request can no longer end up sending the single largest file on disk.

v1.0.129 — 2026-09-01​

Fixed​

  • Analytics no longer go silently dark on sites that restrict the WordPress REST API. SyteHero asks a small endpoint which privacy rules apply to each visitor before it records anything. When a site's REST API was locked to logged-in users, that request was refused, and because SyteHero errs on the side of not tracking, it stopped recording everything — attribution, slide impressions and hero clicks — with no visible sign beyond a browser console error on every page. SyteHero now tells the restriction which two endpoints it needs left open, so the site keeps its REST API locked down and analytics keep working. Sites affected by this will start recording again as soon as they update; data missed while it was blocked cannot be recovered.

v1.0.128 — 2026-08-24​

Changed​

  • The fal image provider is now named the way its vendor names it. It appeared throughout the plugin as "Fal AI"; the vendor's own wordmark is lowercase "fal". The provider list, the connection test messages and the AI Studio setup hint all say "fal" now. Nothing about how it connects or what it costs has changed.

v1.0.127 — 2026-08-23​

Added​

  • Image tools can now erase part of a picture without redrawing the rest. Two new models take a mask — a shape marking the area to repair — and rebuild only what it covers, leaving every other pixel exactly as it was. Previously every image model was given the whole picture and asked, in words, to change one part of it, which is not something a picture model can promise: a corner logo would be replaced by a flat gray block, or a clean photo would come back softer than it went in. This is used by companion plugins that remove a watermark from a single corner.

v1.0.126 — 2026-08-19​

Fixed​

  • Email preview lines in your inbox are readable again. Sale alerts and report emails showed a run-together preview under the subject — New SaleOrder #72176 processing$45.66DateAug 18, 2026 3:17pmCustomerBrian Favre… — because mail apps had run out of preview text and started reading the body of the message instead. Every SyteHero email now supplies a full preview line, so nothing from the body leaks into it. That same alert now reads $45.66 · Order #72176 · Brian Favre · processing · Aug 18, 3:17pm.
  • Customer details no longer surface on your lock screen. Because mail apps had been reading the message body, a customer's email address and full shipping address could appear in inbox previews and notifications. The shipping address no longer appears there at all, and the email address appears only when an order has no customer name to show instead.
  • Orders with a missing purchase date no longer display as 1969 or 1970. The date is now omitted from both the preview line and the order card when a store's order record has no usable timestamp.
  • Real-time digest emails stated their order count once instead of repeating it in both the subject and the preview line.

Changed​

  • The preview line now carries details the subject cannot. It previously repeated the subject line. It now shows $45.66 · Order #72176 · Brian Favre · processing · Aug 18, 3:17pm for a sale alert, 3 orders · $312.40 · Daily Summary: Mar 19, 2026 for a periodic summary, and the equivalent figures for Sources, Attribution, and Schedule reports. The amount comes first, because that is the part still visible when a phone truncates the line.
  • Minimum PHP version is now 8.1 (previously listed as 7.4). SyteHero has required 8.1 for some time — the listed figure was out of date, which meant a site on an older PHP could install the plugin and hit a fatal error. Sites below PHP 8.1 will no longer be offered updates, which prevents that. If your host is below 8.1, ask them to upgrade; PHP 7.4 has been unsupported since 2022.

v1.0.125 — 2026-08-04​

Fixed​

  • License activation on SyteWide-managed sites: licensing requests now present the management credential the licensing service expects from sites SyteWide operates. Affected sites showed a License Status: Inactive with the reason edge_credential_invalid, and scheduled re-validation could turn a previously working license inactive on its own. A license that was already activated recovers by itself at the next scheduled check (within 4 hours) or immediately via Refresh License Status — no re-entry of your license key is needed. A site whose first activation was attempted while this was happening needs Activate clicked once. Installs not managed by SyteWide were never affected and behave exactly as before.
  • Licensing outages no longer revoke your grace period: when the licensing service refuses a request for infrastructure reasons — unreachable, a gateway authentication failure, the management-credential check, a server-side rate limit, or an endpoint allowlist — SyteHero now records it as unreachable rather than as a verdict on your license, so the existing grace window keeps features unlocked. Previously any such refusal cleared the grace period immediately. Genuine license answers (expired, suspended, invalid, activation limit reached) are unchanged and still lock the plugin.
  • A revoked license can no longer be revived by an outage: the "last known good" marker is now cleared when the licensing service gives a genuine answer such as expired or suspended. Previously that marker survived indefinitely, so a license that had already been revoked could be handed a fresh grace period by the next unrelated connectivity problem — and again by every one after it.
  • Licensing requests no longer follow redirects, so the credentials they carry can never be forwarded to another host. An unexpected redirect from the licensing service is now treated as a temporary outage instead of locking the plugin.

v1.0.124 — 2026-07-17​

Added​

  • Native WP Full Picture consent support: when WP Full Picture is your active consent tool, SyteHero now reads its consent choices directly — no extra configuration or per-site glue. Analytics tracking (the attribution beacon, impression beacon, and hero-click tracker) waits until a visitor grants statistics consent in Full Picture, and follows a later change or withdrawal. Global Privacy Control and the EU/EEA/UK opt-in behavior continue to apply. Sites using another consent tool are unaffected (the existing consent event/cookie seam still works).

v1.0.123 — 2026-07-16​

Added​

  • Consent-gated analytics: the attribution beacon, the slide-impression beacon, and the hero-click tracker now wait for analytics consent before storing or sending anything. EU/EEA/UK visitors are treated as opt-in (nothing stored or sent until consent); US and the rest of the world remain opt-out unless Global Privacy Control is set.
  • Global Privacy Control (GPC): honored both in the browser and server-side — a visitor sending GPC has no cookie set and no analytics recorded.
  • CMP-agnostic consent seam: SyteHero listens for a configurable consent signal (sytehero_consent_update event + window.syteHeroConsent()), wireable to any CMP with the sytehero_consent_config filter, plus a built-in WP Consent API bridge.
  • Declared cookies: SyteHero now declares every cookie it sets (sytehero_vid, sytehero_hero_click) — with lifetime, purpose, and category — and registers them with the WP Consent API so CMP scanners keep them instead of silently deleting them. See the new Privacy & Consent documentation.

Fixed​

  • The attribution beacon previously fired on every page load regardless of consent or jurisdiction, creating a server-side record for EU visitors who were never shown a choice. It is now gated.

v1.0.122 — 2026-07-15​

Added​

  • Standardization cost estimate: the profile editor, the AI Studio launcher, and each saved profile now show an estimated per-run cost (~$…) for the selected reframe, extend, and upscale steps, using the same price table as the Generate cards.
  • Standardization progress bar: a progress bar now tracks each run — in the AI Studio launcher and next to every hero slide — so you can see how far along a standardization is.
  • Open standardized image: when a run finishes, an Open full image ↗ link lets you open the new image in a new browser tab to preview it at full size.

Changed​

  • Standardized image naming: newly standardized images are now saved to the media library as “SyteHero Standardized” instead of “SyteHero AI Upscaled,” so they’re easy to recognize.

v1.0.121 — 2026-07-15​

Added​

  • Standardization tool: a new one-click Standardize action turns any client-uploaded image into a clean, un-clipped 16:9 (≥1920×1080) hero. It reframes the subject and text inward (rule-of-thirds), extends the sides to a true 16:9 with AI (skipped automatically when the image is already 16:9), then upscales 2×. Run it from the Standardize button next to every hero slide, or from AI Studio → Standardization.
  • Standardization profiles: save named presets — prompt, composition placement (Centered, Rule of Thirds, Balanced, Inset/Safe, Golden Ratio, or a custom value), reframe model (defaults to GPT-Image 2), target ratio, upscale model/factor, and an optional “move the original to Trash after success.” One profile is active and drives the slide button; switch or manage profiles in AI Studio.

v1.0.120 — 2026-07-14​

Added​

  • AI Studio: GPT-Image 2 is now available in the image model picker. It's earmarked as a high-fidelity 🛡️ model that preserves text, logos, and product details — recommended when you turn on Preserve product details — and can also be used for from-scratch generation in the Generate tab.

v1.0.119 — 2026-07-14​

Added​

  • Featured products: newly-added product slides now show the Open Button/CTA Link in New Tab, Make entire slide clickable, and Open slide link in a new tab toggles right on the row, so you can set them before saving.
  • Heroes tab: a new Hide all text & CTAs toggle on each product and supplemental slide row hides all hero text and the CTA for that slide in one click; turn it off to restore the default text.

Changed​

  • Custom slides: a CTA URL is no longer required — a title is required instead. Leave the URL blank for a non-clickable slide and set its background media after adding.

Fixed​

  • Custom slides: a custom slide with background media but no CTA URL now displays on the live site as a non-clickable slide (previously it saved and showed in the admin list but never appeared on the front end).
  • Heroes tab: the Hide all text & CTAs toggle now reflects its correct on/off state the moment the page loads (previously it always started off and corrected a moment later).
  • Heroes tab: the Retain Slide after Schedule toggle on page, category, and custom slides is now correctly linked to its label, so clicking the label text toggles it (and each slide's toggle is uniquely identified).

v1.0.118 — 2026-07-13​

Added​

  • Featured products: a Make entire slide clickable toggle now appears directly on each product row in the Heroes tab (beside Open Button/CTA Link in New Tab). Turn it on to link the whole slide to the product page — it saves automatically. The full product-vs-custom Slide Link options remain available under Modify Hero Text and in the product metabox.

Changed​

  • Heroes tab: the CTA new-tab toggle is now labeled Open Button/CTA Link in New Tab (previously "Open Link in New Tab"), so it's clearly distinct from the slide link's Open slide link in a new tab.
  • Heroes tab: the slide status toggle now reads green when Live and red when Paused across every slide type, making the two states easy to tell apart at a glance.

v1.0.117 — 2026-07-13​

Fixed​

  • Heroes tab: the schedule status pill (e.g. "Always On") now vertically centers its label within the pill.

v1.0.116 — 2026-07-12​

Added​

  • Clickable slides: make an entire slide link to its destination — a product page, a linked page/category, or a custom URL — with an optional "open in new tab." Available for featured product slides (product editor and the Heroes tab), the Heroes tab's page/category/custom supplemental slides, and standalone Custom Heroes. Buttons and text layered on the slide keep their own links.

v1.0.115 — 2026-06-30​

Fixed​

  • Email reports: Sources and Attribution reports never trigger per-order ("real-time") emails — real-time alerts stay Sales Summary only — even if a real-time toggle was left enabled before switching the report type.
  • Attribution report email: the "Top channels" section heading always names the selected attribution model.

Changed​

  • Internal hardening and cleanup of the email-report system; no change to existing report output.

v1.0.114 — 2026-06-28​

Added​

  • Attribution email reports: create a scheduled (daily/weekly/monthly) email of your multi-model attribution data — credited revenue per model, a top-channels breakdown for a chosen primary model, and a native-vs-platform comparison. Add one under Email Reports and pick the "Attribution" report type.
  • Create email report buttons: the Attribution and Sources dashboards now link straight to the report editor.

Changed​

  • The report editor section is now titled "Email Reports" (it creates sales, sources, and attribution reports — not just sales summaries).

v1.0.113 — 2026-06-28​

Fixed​

  • Critical: sites running SyteHero without WooCommerce or FluentCart active no longer crash with a fatal error on every page load. The Native Attribution journey recorder required a store connection that those sites don't have; it now stays dormant until a supported store is present.

v1.0.112 — 2026-06-27​

Fixed​

  • Native Attribution: visits with no UTM tags now resolve to their real source (e.g. Google, Facebook, or the referring site) instead of being grouped under a single "Referral" bucket.
  • Native Attribution: internal page-to-page navigation no longer creates phantom "self-referral" touches that diluted multi-touch credit.

Added​

  • Native Attribution: a "Recent attributed orders" table showing each order's entry source, referrer and landing page, the credited amount under the selected model, and whether an affiliate coupon arrived via a referral link or was entered manually.

Changed​

  • Existing orders are re-scored once after updating so the attribution totals reflect the corrected sources.

v1.0.111 — 2026-06-26​

Fixed​

  • Native Attribution on updated sites: the daily data-retention cleanup and the attribution settings now self-heal automatically on sites that updated into Native Attribution (rather than installing it fresh). Previously these were only set up during a fresh activation, so a site that received the feature via a plugin update would never schedule the retention cleanup or store its settings. Tracking still worked, but old visit data was never trimmed. No action needed — affected sites repair themselves on the next page load after updating.

v1.0.110 — 2026-06-26​

Fixed​

  • Affiliate vendors editor: the table now uses the full width, and the Commission type/amount fields sit side by side with proper spacing (they were getting squeezed onto separate lines).
  • Native Attribution settings: the section now uses the same clean collapsible styling as the other settings groups (removed a stray expander arrow and misaligned heading).

v1.0.109 — 2026-06-26​

Fixed​

  • Critical: Fixed a fatal error on plugin load introduced in 1.0.108 — one new class file was named slightly differently from what the autoloader expected, so the plugin could not boot. Renamed the file to match, and added an automated check that verifies every class file is named correctly so this cannot recur.

v1.0.108 — 2026-06-26​

Added​

  • Attribution dashboard: A new Attribution tab shows credited revenue by channel and source, with a model selector to switch instantly between first-touch, last-touch, linear, position-based, and time-decay — all from data already captured at checkout, over a 7/30/90-day window.
  • Affiliate vendor crediting: Map a coupon code to an affiliate vendor on the Attribution tab. When that coupon is redeemed, the order's closing touch is credited to the vendor under the Last-touch and Position-based models, so partner-driven sales show up against the partner. Works with both WooCommerce and FluentCart; on WooCommerce you can also set the vendor on the coupon edit screen.
  • Attribution settings: Enable or disable attribution tracking and set how long anonymous source touches are kept, under Settings → Native Attribution.
  • SyteHero vs platform comparison: The Attribution tab compares SyteHero's attribution with WooCommerce/FluentCart's own, by channel group, plus a per-vendor revenue breakdown (revenue, orders, average order value).
  • Affiliate link auto-apply: Optionally have a ?ref=COUPON link apply that coupon to the WooCommerce cart automatically (per coupon, or a global default — off by default).
  • Attribution in the report email: The Sources Analytics report email can include an optional Attribution Models section showing per-model credited revenue.
  • Affiliate commissions: Set a percentage or flat commission per affiliate coupon. SyteHero accrues what each vendor is owed as their coupons are redeemed, and the Attribution tab shows a per-vendor payout view (accrued / paid / owed) with a Mark paid button. Works with both WooCommerce and FluentCart.

Fixed​

  • Builder auto-mode rendering: Fixed a crash that could occur when a page builder (Elementor, Avada, Divi, or Gutenberg) rendered a SyteHero hero in responsive "auto" mode without a theme override.

v1.0.107 — 2026-06-26​

Added​

  • Multi-model attribution scoring: SyteHero now credits every order under five attribution models — first-touch, last-touch, linear, position-based (40 % first / 40 % last / 20 % middle), and time-decay (recent touches weighted heavier with a 7-day half-life). All five are calculated at checkout so you can compare models instantly without reprocessing orders.

v1.0.106 — 2026-06-25​

Added​

  • Multi-touch order attribution (native): SyteHero now records each visitor's full journey across sessions and devices and saves a durable attribution snapshot on every WooCommerce and FluentCart order, so your sales reports can credit the whole path to purchase — not just the last click. Journeys that belong to an order are kept regardless of the data-retention window.

Fixed​

  • FluentCart order data: FluentCart orders now read the correct fields from FluentCart's tables — the buyer's account, email, and name; the order total; the purchased line items; and the shipping address. Previously these came back empty or zero because they were read from the wrong place, which left FluentCart attribution stitching, order notifications, and sales totals incomplete. WooCommerce was unaffected.
  • FluentCart variable products & sales: Fixed FluentCart variable-product detection, variation lookups, variation search, and the price-range refresh after a scheduled sale starts or ends — these relied on FluentCart product columns that have since been renamed, so they silently did nothing. WooCommerce was unaffected.
  • FluentCart order events: Hero-slide revenue tracking, real-time order emails, and native attribution now trigger correctly when a FluentCart order is paid. FluentCart hands these events different data than WooCommerce, which SyteHero wasn't unpacking, so they previously didn't fire for FluentCart orders. WooCommerce was unaffected.
  • FluentCart media & price reads: FluentCart product images are now correctly recognized as in-use (preventing accidental cleanup), and FluentCart product prices resolve in AI Studio — both previously read a renamed FluentCart column.
  • FluentCart banner injection: Hero banners now display on FluentCart product-listing pages. They previously hooked a FluentCart action that doesn't exist, so they never appeared on FluentCart stores.

v1.0.105 — 2026-06-25​

Added​

  • Native visitor analytics (first-party, privacy-conscious) — foundation. SyteHero now records anonymous, first-party visit signals (referrer and campaign tags) with its own same-origin tracker, which is resilient to the ad blockers and page caching that often block the platforms' built-in attribution. No IP addresses are stored, a random visitor token (not personal data) is used, capture honors the WP Consent API, and it can be disabled with a filter. This is the groundwork for upcoming multi-touch attribution and channel comparison — nothing new appears in reports yet.

v1.0.104 — 2026-06-25​

Fixed​

  • More accurate referrer attribution for unusual hostnames. Web referrers whose domain begins with a TLD-like label (for example a site at io.example.com) are no longer mistaken for a mobile-app referrer and labeled "Mobile App" — they now resolve to the real site. In-app referrals (e.g. the Facebook or Instagram app) continue to resolve to the app name.

v1.0.103 — 2026-06-25​

Changed​

  • Clearer acquisition channels in the Sources dashboard and report. Channels now follow Google Analytics' standard grouping shown as "Channel · Source" — e.g. Organic Search · Google, Paid Search · Google, Organic Social · Facebook, Email · Klaviyo, Referral · somesite.com — replacing the ambiguous "Google" vs "Google (Organic)" and the cryptic "(Referral)" labels. Paid vs. organic is now split correctly by reading the campaign medium.

v1.0.102 — 2026-06-25​

Added​

  • Sources Analytics report email — get your Sources dashboard delivered on a schedule. Each Sales Summary report can now be set to a new "Sources Analytics" type that emails your acquisition-channel and SyteHero-influence breakdown (with previous-period deltas) on a daily, weekly, or monthly cadence. Choose a 7-, 30-, or 90-day period and turn individual sections on or off: KPIs, Acquisition channels, SyteHero influence split, and the Channel × Hero cross-tab. Reuses your existing recipients and schedule. Works with WooCommerce and FluentCart.

Fixed​

  • In-app referrals now show the app name instead of a raw package id. Orders that arrive from an Android or iOS in-app browser (e.g. the Facebook or Instagram app) previously showed a reverse-DNS package id like com.facebook.katana as the source. They now resolve to the real app name where known, or a clean "Mobile App" label otherwise — so Sources reports and the order attribution badge read correctly.
  • The "Open Sources Dashboard" button in the Sources Analytics email now opens the Sources tab instead of the default plugin tab.
  • A near-flat period (a change that rounds to 0.0%) now shows a neutral indicator in the Sources email instead of a colored up/down arrow next to "0.0%".

v1.0.101 — 2026-06-24​

Added​

  • Sources dashboard — see which acquisition channels and SyteHero heroes drive your sales. A new Sources tab (next to Analytics) breaks down paid orders by acquisition channel (Facebook, Google, Direct, Klaviyo, Referral, and more) and by SyteHero hero influence (Featured Hero Slider, Custom Heroes per slide). A Channel × Hero cross-tab shows what percentage of each channel's orders had a hero assist. Choose Last 7, 30, or 90 days with previous-period deltas. Works with WooCommerce and FluentCart.

v1.0.100 — 2026-06-24​

Fixed​

  • Daily sales-summary digests now cover the current day, not the day before. A daily digest reports the current day's orders up to the send time — which acts as the day's cutoff — and is labeled with that day's date. Previously a digest sent in the evening showed the full previous calendar day. Orders placed after the cutoff are included in the next day's digest. The schedule settings now note this cutoff behavior under the daily Send Time.
  • "Send Test Email" now previews the real daily digest. A daily test email now uses the same midnight-to-now window as a live digest (instead of a rolling 24 hours), so its contents match its date label and what you'll actually receive.
  • Changing "Only completed orders" no longer skips a day of orders. Toggling that filter now advances the report's cutoff to the moment of the change, so the next digest resumes cleanly without dropping orders placed since the previous send.

v1.0.099 — 2026-06-17​

Added​

  • Deploy tool: --avada / --no-avada toggle to reset Avada/Fusion caches after deploy (default on; no-op on non-Avada sites). — 2026-06-23

Changed​

  • Sales and report email footers now use title-case labels with extra spacing above the footer text and SyteHero logo. Footer references read in title case — e.g. "Sent By: Daily Sales Report · Instant Alert", with mode labels like "Daily Summary" and "Instant Alert" — the "Sent by:"/"Sent from" lines become "Sent By:"/"Sent From", and there's a little more breathing room above the footer text and the SyteHero logo plate.

v1.0.098 — 2026-06-17​

Changed​

  • Sales emails now name their cadence and the report that sent them. Subject lines carry a tag — [Daily], [Weekly], [Monthly] for scheduled summaries, [Instant] for the immediate new-sale alert, and [Digest] for the batched real-time digest — followed by the report's name (e.g. [Daily] Morning Sales — Sales Summary: Your Store (SyteHero)). Every sales email also gains a "Sent by:" line in the footer identifying the schedule, so you can tell which report produced a message even after the subject scrolls away.

v1.0.097 — 2026-06-16​

Changed​

  • "Reset Email Crons" is now "Reset Email Notifications." Alongside rescheduling the email crons, the button now also clears any pending sale-alert backlog — and sets a cut-off so already-processed orders are never re-announced — so a one-time notification flood can be stopped in a single click. It reports how many pending queues were cleared.

Fixed​

  • "New Sale" emails now send once per order. Previously a sale could be emailed twice — once at purchase and again when the order was later marked completed — which also produced batches of stale alerts when a backlog of old orders was completed together. Each order is now announced exactly once, at the moment of sale, via a persistent per-order marker.
  • SyteHero now loads on sites without WooCommerce or FluentCart. When no ecommerce gateway is active the plugin no longer fatals during boot — non-commerce features keep working and the sales tools stay dormant until a supported store is present.
  • Cleared a WordPress 6.7+ "translation loading triggered too early" notice. Admin menu titles are now translated when WordPress is ready instead of during plugin load, so the notice no longer appears in debug logs.

v1.0.096 — 2026-06-01​

Fixed​

  • Email prices now display with your store's currency precision. Sale prices and order/line-item totals that ended in a zero — for example a $37.50 price — were sometimes shown without the trailing zero ($37.5). Email prices now consistently follow your store's configured decimal places (two for USD/EUR, none for zero-decimal currencies like JPY) across the sale schedule report email and the sales-summary / new-order emails.

v1.0.095 — 2026-06-01​

Added​

  • Custom banner shortcode endings. Non-primary banners can now use a custom shortcode ending (e.g. [sytehero_banner_free_shipping]) instead of the auto-generated one. Set it in the banner's Shortcode box; leave it blank to keep the default. Endings must be unique — saving a duplicate is blocked — and changing an ending breaks any pages already using the old shortcode.

Fixed​

  • Copying a banner's shortcode now includes the surrounding [ ] brackets. On the Banners screen the shortcode is now shown — and copied — as [sytehero_product_page_banners] instead of the bare tag, so you can paste it straight into a page or builder and have it work. The hidden (deleted-banner) shortcodes are displayed with brackets too.

v1.0.094 — 2026-05-31​

Changed​

  • Brand logo updates now apply automatically. The plugin records a fingerprint of each bundled logo image and re-imports it into the media library when that image changes in an update — so the dark-mode logo fix (and any future logo refresh) shows up on the next admin load without manually clicking Refresh Brand Media Library. The button remains for forcing a full rebuild.

v1.0.093 — 2026-05-31​

Fixed​

  • SyteHero icon in email logos no longer washes out on the dark plate. The mark's two faded side cards used transparency tuned for light backgrounds, so on the dark email plate they collapsed to a near-black smudge while the center card and wordmark stayed crisp. The on-dark logo now uses solid side cards, so the full mark reads clearly. After updating, open SyteHero → Settings and click Refresh Brand Media Library once so the new logo replaces the cached copy.

v1.0.092 — 2026-05-30​

Fixed​

  • Email SyteHero logo no longer washes out in dark mode — including Gmail. The footer logo on transactional and report emails now sits on a dark backing plate (the same treatment as the logo in the email header), using the white version of the lockup. Because it doesn't depend on dark-mode CSS — which Gmail ignores — the logo stays crisp in every major email client and theme instead of fading into a near-black silhouette.

v1.0.091 — 2026-05-28​

Changed​

  • Full brand overhaul. Adopted the new SyteWide brand system end-to-end: the SyteHero slider mark (terra-cotta #D85A50) and SyteWide span mark (navy #1E3A8A) replace the legacy indigo logos across every admin page, email footer, WP admin sidebar menu icon, and the public docs site (logo, favicon, social card, primary color scale). Plugin admin color tokens migrate from indigo to terra-cotta; all stale hex fallbacks were swept so every var(--sytehero-color-primary, …) declaration resolves to a brand color even when CSS variables fail to load.
  • Brand assets now flow through the WordPress media library. Bundled brand logos are side-loaded once on activation (with admin_init and manual "Refresh Brand Media Library" fallback paths) so admin pages, transactional emails, and shortcodes render them via attachment IDs — picking up srcset, lazy-load, and CDN integrations automatically. Default brand attachments are hidden from your media browser so they never clutter the Library. A new Settings button forces a re-import if logos ever go missing.

Added​

  • SyteWide attribution in the admin footer. SyteHero plugin pages now show "SyteHero is built and maintained by SyteWide" with the current plugin version in the WP admin footer.

v1.0.089 — 2026-05-21​

Fixed​

  • Term deletion no longer crashes with SyteHero active. Syte_Hero::prevent_featured_tag_deletion() was registered against the pre_delete_term action with the wrong arity, causing a PHP 8 ArgumentCountError whenever WordPress fired the hook (admin term-delete, REST, and wp term delete from WP-CLI). Operators had to work around it with --skip-plugins=sytehero. The callback now uses the action's canonical ($term, $taxonomy) signature.
  • The SyteHero featured tag is now actually undeletable. Returning a WP_Error from an action did nothing — WordPress discards action return values — so the previous guard was a placebo. Deletion of the featured tag now halts via wp_die() from every entry point (admin, REST, WP-CLI, direct wp_delete_term()), with a clear protected-tag message.

Changed​

  • Admin tag list hides "Delete" on the SyteHero featured tag. New tag_row_actions filter removes the row action so the protected tag never offers a delete link in wp-admin/edit-tags.php?taxonomy=product_tag. The wp_die() guard remains as the deep safety net for non-UI paths.

v1.0.088 — 2026-04-22​

Fixed​

  • Elementor “Copy styles from…” now updates the canvas immediately and persists across Elementor’s server re-render. The style picker writes --sh-* custom properties on the active widget’s .sytehero-scaffold-wrap inside the preview iframe after each copy, using the same sh_* → --sh-* map as PHP StyleTokens. It also installs a short-lived MutationObserver on the widget element plus requestAnimationFrame / 150ms / 600ms / 1500ms timer re-applies, so when Elementor’s $e.run('document/elements/settings') command fires its async admin-ajax.php?action=elementor_ajax render_widget request and swaps the widget’s inner DOM, the copied vars are re-applied onto the new wrap. Previously the new wrap could land with default vars (stale model, cached response, or ahead-of-model ajax round-trip) and visually revert the author’s copy after ~200ms. The observer self-destructs once the last timer fires so consecutive copies never leak observers.
  • Scaffold CSS + editor live-preview script load on every Elementor preview boot. elementor/preview/enqueue_styles and elementor/preview/enqueue_scripts now call Assets::register() when needed and enqueue sytehero-widget-scaffold plus sytehero-editor-live-preview, fixing missing --sh-* consumers and slide media fill rules in the iframe.
  • Multi-slide editor previews stay filled when stylesheets are absent. EditorPreviewRenderer::compose_live() emits a scoped inline <style id="sytehero-editor-live-inline"> and merges object-fit:cover fill rules into each slide’s root <img> / <video> / <iframe> so the preview cannot letterbox even if asset loading regresses.
  • TA1 / TA2 / CTA no longer stay invisible in the Elementor editor preview. sytehero-frontend.css hides the overlay elements with opacity:0; visibility:hidden as FOUC protection, and relies on sytehero-frontend-overlay.js (gated by .sytehero-fhsbg) to reveal them inline with !important. The editor preview never emits .sytehero-fhsbg, so that reveal path never fired — even when the live-preview JS had already populated the overlay text from the active slide. A scoped reveal rule (.sytehero-elementor-editor-preview .sytehero-hero-text-area-1/2, .sytehero-hero-cta { opacity: 1; visibility: visible; }) is now shipped in both sytehero-widget-scaffold.css and the inline <style id="sytehero-editor-live-inline"> block, and is included in both compose() (placeholder fallback) and compose_live() (multi-slide live preview), so the overlay is visible whether or not the external stylesheet loaded.

Added​

  • StyleTokens::get_var_map() — flat map published to window.syteheroStylePicker.styleVarMap for picker DOM sync.
  • Editor-only pulse animation — .sytehero-editor-live-flash on TA / CTA after a successful copy (scoped to .sytehero-elementor-editor-preview).

Developer notes​

  • PHPUnit: StyleTokensVarMapTest, EditorPreviewAssetsHookTest, EditorPreviewMediaSizingTest (now includes FOUC-override assertions for both compose() and compose_live() paths); bootstrap: wp_register_script, wp_enqueue_script, wp_localize_script stubs for asset registration tests.

v1.0.087 — 2026-04-22​

Added​

  • Elementor editor preview gains manual slide controls. Multi-slide heroes rendered inside the Elementor editor canvas now include prev / next arrow buttons (vertically centred on the preview edges) and a dot-indicator strip (bottom centred) so authors can step through slides on demand without waiting for the auto-advance timer. The controls are scoped strictly to the editor preview (.sytehero-elementor-editor-preview) — nothing bleeds onto the published frontend. The outer preview wrap keeps pointer-events: none so the Elementor canvas stays fully interactive everywhere except the control buttons themselves, which opt back in via a pointer-events: auto island. Every button carries accessible aria-label text (Previous slide, Next slide, Go to slide N) and keyboard focus rings; clicking a control resets the auto-advance timer so the next automatic tick starts fresh from the newly-active slide's configured interval.
  • sytehero_elementor_editor_preview_manual_controls filter. Integrators who prefer the pre-v1.0.087 auto-advance-only experience can return false from this filter to hide the arrows and dot indicators. The filter receives the current slide count as its second argument so decisions can vary per-preview. Default is true (controls enabled).
  • EditorPreviewRenderer::build_manual_controls_markup( int $slide_count ). New public helper for composing the controls island in isolation — returns '' for single-slide previews and whenever the filter opts out, which keeps every branch of the emission logic unit-testable without having to stand up a full compose_live() payload.

Changed​

  • Blocksy palette bridge is now gated behind Blocksy-theme detection. StyleMapper::theme_palette_additions() previously fired whenever a colorPalette theme mod was present, regardless of which theme was active. Because colorPalette is a generic enough mod key that another theme could coincidentally use it, this risked synthesising blocksy_palette_N map entries that pointed at an unrelated theme's palette. The bridge now only runs when wp_get_theme()->get_template() resolves to blocksy (which covers Blocksy parent theme + every Blocksy child theme — child themes inherit their parent's template slug) or when BLOCKSY_PATH is defined. Vanilla-Elementor installs and installs running non-Blocksy themes with a stray colorPalette mod now see a clean kit-only fallback map, exactly as they should. The sytehero_elementor_global_color_map filter still runs last and remains the authoritative override for custom theme integrations.
  • Editor live-preview cycler refactored around a Map-keyed stage state. The slide-cycler in sytehero-editor-live-preview.js moved its current index / pending timer / slides list out of closure locals and into a Map<stage, StageState> so manual prev/next/dot click handlers can drive the same advance machinery the auto-timer uses. Behaviour for auto-advance is preserved exactly; manual advances wrap in both directions (prev on slide 0 → last slide, next on last → 0) and clear the pending auto-timer before scheduling the next tick, so authors never see a lurch from a stale pending advance firing right after they click.

Fixed​

  • Vanilla-Elementor installs no longer emit stray Blocksy palette IDs in the editor preview. See above — the Blocksy detection gate fixes a theoretical issue where a non-Blocksy theme persisting anything under the generic colorPalette mod key would have caused the hero widget's blocksy_palette_N references to resolve to that unrelated theme's colour, painting the wrong hex in the editor iframe. On real-world installs the practical impact was minimal (most non-Blocksy themes don't use colorPalette as a mod key), but the regression tests now lock this contract so the bridge stays opt-in to Blocksy forever.

Developer notes​

  • New regression tests (StyleMapperGlobalColorFallbackTest). Three new cases cover (a) vanilla-Elementor on a non-Blocksy theme with no colorPalette mod → kit-only map and no blocksy_palette_* leakage, (b) non-Blocksy theme with a stray colorPalette mod → bridge skipped and naked var() emitted for blocksy_palette_N IDs, and (c) Blocksy child theme (get_template() = blocksy, get_stylesheet() = blocksy-child) → bridge fires normally. The existing Blocksy-bridge tests were updated to explicitly activate the Blocksy theme stub so they continue to pass.
  • New test suite (EditorPreviewManualControlsTest, 14 tests / 33 assertions). Covers every branch of build_manual_controls_markup() (single-slide returns empty, multi-slide emits the island, filter can disable, filter receives slide count, dot count matches slide count, first dot marked active, per-slide aria-label and data-sh-slide-index, all buttons use type="button" to avoid Elementor form-submit conflicts) plus three end-to-end assertions through compose_live() (integration emits controls for multi-slide, omits for single-slide, honours filter opt-out). Full plugin suite green: 1,479 tests / 4,394 assertions.

v1.0.086 — 2026-04-22​

Fixed​

  • Elementor editor preview now shows CTA / Text Area 1 / Text Area 2 in their correct colours. When the hero is edited inside the Elementor panel, the editor iframe does not always load the active theme's palette stylesheet (for example Blocksy's global.css, which is what defines --e-global-color-blocksy_palette_*). Any colour the author picked via the Elementor global-colour selector therefore resolved to an undefined variable in the editor, dropping the CTA to its neutral scaffold fallback and producing an unstyled button with excess whitespace around it. Global-colour references now emit var(--e-global-color-X, #hex) — the hex is resolved from two sources in priority order: Elementor's active Kit (for vanilla Elementor globals like primary / accent / text), then a Blocksy palette bridge that reads the theme mod colorPalette directly (because Blocksy stores its palette in Customizer theme mods, not in the Elementor Kit). The editor now paints the same colours the front end does, even when Blocksy's companion CSS is absent from the iframe.

Changed​

  • Global colour lookup is cached per request and mockable via filter. A new sytehero_elementor_global_color_map filter lets integrations (and unit tests) extend or override the resolved ID → hex map without loading Elementor, and the map itself is resolved once per request. Filter precedence is: Elementor Kit → theme-palette bridge → filter (runs last and has the final say).

v1.0.085 — 2026-04-22​

  • Elementor: “Copy styles from…” uses $e.run('document/elements/settings'); editor preview matches live per-view height, glow data/CSS vars, and data-sytehero-ready; live-preview JS applies per-slide glow like the front end.
  • CTA: Scaffold defaults are a readable pill (#fff / rgba(0,0,0,0.65) padding/radius) until Style-tab tokens override.

v1.0.084 — 2026-04-22​

Fixed​

  • Border styles now copy correctly from Elementor Button widgets. The style picker's border source-key lookup covered only one of the two key patterns Elementor uses across versions (border_border vs button_border_border). Both patterns are now tried in order, so border style, border width, and border colour copy regardless of Elementor version.
  • CTA visibility animation preserves Elementor button layout. When the runtime overlay cycler shows or hides the CTA button, it now sets display: inline-flex (matching Elementor's button flex model) instead of inline-block, so the elementor-button-content-wrapper flex centering works correctly on Elementor Pro and custom Elementor-based themes.

Changed​

  • CTA padding and border-radius now explicitly default to 0. The CSS fallback values were removed in v1.0.083 with the intent of letting elementor-size-sm class defaults cascade through, but that cascade does not occur due to specificity and source-order rules. The explicit 0 fallback is restored with a CSS comment explaining the behaviour, so authors know to set these via the Style tab or "Copy styles from…" rather than expecting class-based defaults.

v1.0.083 — 2026-04-22​

Changed​

  • CTA button now renders with full Elementor button markup. The hero CTA element carries the same class set and inner HTML structure as a native Elementor Button widget (elementor-button-link, elementor-size-sm, elementor-button-content-wrapper) in all render paths (editor preview, live preview, and published scaffold). This enables Elementor theme and kit button styles to apply by default, allows "Copy styles from…" to correctly transfer all button properties (including padding and border-radius) from any Elementor Button widget on the page, and ensures the CTA's appearance matches the rest of the author's site button style.

v1.0.082 — 2026-04-22​

Fixed​

  • Hero is now truly full-bleed in the Elementor editor canvas. The section-level padding removal rule used :only-child, which always fails in the editor because Elementor injects overlay and shape elements as sibling children of the container. The selector is replaced with a :not(:has(…)) guard that ignores Elementor's own UI elements, so the container padding is correctly zeroed out in both the editor and on the published page.

v1.0.081 — 2026-04-22​

Fixed​

  • No more whitespace below the hero in the Elementor editor canvas. Elementor's .elementor-widget-container carries a default padding that appeared as a blank gap beneath the live preview. The widget container's padding is now zeroed out so the hero preview renders flush to its edges.
  • "Copy styles from…" now activates the Publish button. After a style copy the Elementor Publish / Update button stays grayed out because the saver's change-flag was never signalled. It now activates immediately after any copy.
  • CTA background colour now copies correctly from an Elementor Button widget. Elementor's native Button widget stores its background colour via Group_Control_Background under the key button_background_color. The picker map was reading background_color (wrong key), so the background was silently skipped. The key is corrected; all other button properties (border radius, text colour, hover states, etc.) were already copying correctly.

v1.0.080 — 2026-04-21​

Added​

  • Live all-slide preview in the Elementor editor. The editor canvas now cycles through every slide in the hero using the per-slide interval set in the Heroes tab. Text Area 1, Text Area 2, and CTA text fade in and out per slide. Videos (YouTube, Vimeo, Gumlet, direct mp4/webm) play inline. All three device-mode previews (desktop, tablet, mobile) each get their own independent cycling preview when Auto view mode is selected. The canvas stays fully scrollable — no FlexSlider, Swiper, or Splide in the editor.

Fixed​

  • "Copy styles from…" picker now applies styles immediately. Styles copied from another Text Area, CTA section, or a third-party widget now update the canvas preview at once and persist to the published page on save. The previous implementation used a code path that did not fire the change events Elementor needs to update the preview, so nothing appeared to change. Native panel controls were not affected.

v1.0.079 — 2026-04-21​

Added​

  • CTA Button style section now renders a real button. Before v1.0.079 the SyteHero Hero Slider's CTA section inherited the same text-oriented controls as Text Area 1 / Text Area 2 — great for styling a heading, wrong for styling a button. v1.0.079 gives CTA its own button-parity control set: text colour + hover, background colour + hover, border (style / width / colour / radius), box-shadow, plus the typography and padding controls you already had. The hover controls drive a matching CSS :hover / :focus-visible state on the rendered .sytehero-hero-cta anchor. Available in every builder integration: Elementor (dedicated controls), Gutenberg (Inspector Panel was resynced to the new attribute surface), and Avada Fusion / Divi (the divergent schema flows through their existing control_args pipelines — shadows land as textareas, borders as dimension controls).
  • "Copy styles from…" picker now filters by section (Elementor). Text Area 1 and Text Area 2 dropdowns list only text widgets (Heading, Text Editor, Icon Box, Call-to-Action). The CTA Button dropdown lists only button widgets. Copying from an Elementor Button widget into CTA populates colour, hover colour, background, hover background, border (style / width / colour / radius), padding, typography, text-shadow, and box-shadow in one click.

Changed​

  • Third-party widgets need a registered category to appear in the picker. v1.0.078's "list every widget on the page" behaviour is replaced by a curated allowlist. Third-party widgets can join either dropdown by registering a map entry via the existing sytehero_elementor_style_picker_map filter — each entry now declares 'category' => 'text' | 'button' | 'both'. See docs/developer/integrations/elementor-widgets.md.

Removed​

  • Text-only controls on the CTA Button style section. text-decoration, text-decoration colour / style / thickness, text-underline-offset, text-stroke, text-indent, white-space, and font-variant are gone from the CTA panel. Saved values for those controls on existing widgets stop applying — the feature shipped in v1.0.077 and the blast radius is small. Text Area 1 / Text Area 2 are unchanged.

v1.0.078 — 2026-04-21​

Fixed​

  • Elementor "Copy styles from…" picker now lists every widget on the page. v1.0.077 only surfaced Heading / Text Editor / Button / Icon Box / Call-to-Action source widgets, and on some Elementor versions the "Other widgets on this page" group came up empty even when those widget types were present. v1.0.078 switches the picker to enumerate widgets via the Elementor preview iframe's DOM (the data-id + data-widget_type attributes Elementor exposes on every rendered widget) — stable across Elementor versions — and drops the mapped-types filter. Every widget on the page now appears in the dropdown; copying from an unmapped widget (third-party Advanced Headings, theme widgets, etc.) uses a generic fallback that picks up standard colour / typography / text-shadow / padding fields. Properties the source widget doesn't expose remain unchanged on the target, same as before.

v1.0.077 — 2026-04-21​

Added​

  • Copy styles from another widget (Elementor). Each of the three Style sections on the SyteHero Hero Slider widget (Text Area 1, Text Area 2, CTA Button) now has a Copy from… dropdown at the top. Pick any Heading, Text Editor, Button, Icon Box, or Call-to-Action widget on the current page and that widget's colour, typography, alignment, padding, and text-shadow flow into the SyteHero section in one click. You can also copy between SyteHero's own sections (e.g. TA1 → TA2 → CTA) in the same dropdown. Every copy is one undoable action (Ctrl/Cmd+Z). Properties the source widget doesn't expose are left unchanged on the target. Works entirely in the Elementor editor — no frontend bundle impact.

v1.0.076 — 2026-04-21​

Changed​

  • Auto is now the default View variant — "Default" is gone. The v1.0.075 release added an "Auto" option to the hero widget's View variant control alongside the legacy "Default". Feedback was unanimous: the two options were confusing, and Auto is what almost everyone wants — a widget that adapts to the viewport automatically. v1.0.076 removes "Default" from the control and makes Auto the default selection for new widgets. Existing widgets that had "Default" saved are silently upgraded to Auto on the next page load, so no re-save or migration is required. If you prefer a single forced view, Desktop / Tablet / Mobile are still available exactly as before.

Removed​

  • "Default (as configured)" option in all four builder integrations. Replaced by Auto. See Changed above.

v1.0.075 — 2026-04-20​

Added​

  • Auto View mode for hero widgets. New "Auto" option in the View variant control on every builder (Elementor, Gutenberg, Divi, Avada). When selected, the hero renders the Desktop, Tablet, and Mobile views and shows the correct one at each viewport size — automatically. In Elementor, the editor's device-mode toggle (Desktop / Tablet / Mobile preview buttons) also drives the switch, so you see exactly what visitors will see while you design. Uses Elementor's configured breakpoints when active; on other builders, falls back to 1199 / 767 px (matches the plugin's own frontend CSS breakpoints). Existing widgets set to Default / Desktop / Tablet / Mobile are unchanged.

Internal​

  • New BreakpointProviderInterface subsystem. Third-party builders (Bricks, Beaver Builder, etc.) can now register their own breakpoint providers via the sytehero_breakpoint_providers filter without touching plugin core. See docs/developer/architecture/auto-breakpoint-mode.md.

v1.0.074 — 2026-04-20​

Fixed​

  • Hero image now fills the wrapper at all viewport widths. On Elementor, Divi, Gutenberg, and Avada, the hero background image previously rendered at its natural aspect ratio rather than filling the container — leaving a white band below the hero on tablet and mobile viewports (and when the browser window was narrower than the source image width). The text overlays and CTA button, being centered in the full-height wrapper, would visually float in the middle of the empty white area. Root cause: FlexSlider's vendor stylesheet was loaded after sytehero-frontend.css and its equal-specificity height: auto rule won the cascade. Fixed by bumping the SyteHero image rule specificity so it reliably wins regardless of stylesheet load order.

v1.0.073 — 2026-04-20​

Internal​

  • FeaturedProductsPage data assembly extracted. A new FeaturedProductsPageDataAssembler class (+ readonly FeaturedProductsPageData DTO) now owns all data preparation work previously inline in FeaturedProductsPage::render(). The render method is reduced from ~1 980 to ~1 640 lines; output is byte-for-byte identical, verified by the render-equivalence harness. No user-facing behavior changed.

v1.0.072 — 2026-04-20​

Internal​

  • WP integration test harness added. A second PHPUnit suite (phpunit.integration.xml.dist) now boots a real WordPress environment against a local MySQL database. Provides render-equivalence pinning for FeaturedProductsPage, guarding future admin-page decomposition work against silent HTML regressions. No user-facing behavior changed.

v1.0.071 — 2026-04-20​

Internal​

  • AI AJAX handler refactored into concern-scoped classes. The single 1 400-line AiImageAjaxHandler class has been split into six focused handlers (AiSettingsAjaxHandler, AiGenerationAjaxHandler, AiPromptAjaxHandler, AiEditingAjaxHandler, AiVideoAjaxHandler, AiPipelineAjaxHandler) plus a shared AiImageAjaxSupport utility class and a thin AiImageAjaxController orchestrator. All 21 wp_ajax_* action names and priorities are identical to before. No user-facing behavior changed.

v1.0.070 — 2026-04-20​

Internal​

  • Modularization cleanup across the builder integration layer. Four near-identical whitespace-class sanitizers are now a single shared helper (ClassTokenSanitizer); the repeated hero-render ceremony across the Elementor / Avada / Divi / Gutenberg widget render paths lives in a single BuilderHeroRenderer trait that each builder opts into; the duplicated resolve_view_glow_enabled logic between the featured and custom hero shortcodes is now a single SlideOverlayResolver call; and the admin Featured Products page routes its slide-id collection through the already-canonical SlideOrderingService statics. Unit coverage expanded by ~25 tests across ClassTokenSanitizer, SlideOverlayResolver, SlideOrderingService, and the new trait. No public API, hook name, option key, AJAX action, or asset handle changed.

v1.0.069 — 2026-04-20​

Removed​

  • Reactive breakpoint auto-swap has been removed. Earlier v1.0.061 introduced a JavaScript listener that tried to swap the hero's desktop/tablet/mobile layout class as the viewport changed. It didn't reliably match Elementor's live breakpoints and could freeze at the wrong view, so it's gone.

Fixed​

  • Hero view is now driven entirely by the element-level "View" dropdown (Default / Desktop / Tablet / Mobile) on each builder — Elementor, Avada/Fusion, Divi, and Gutenberg. The view you pick in the editor is the view the visitor sees, full stop. No runtime class swapping, no guesswork about whose breakpoint config is authoritative.

Release note: v1.0.069 ships bundled with the v1.0.068 typography expansion (entry immediately below) — the two releases were cut together rather than as separate tags.


v1.0.068 — 2026-04-20​

Fixed​

  • Tablet & mobile Elementor hero no longer leaves a white gap below the image. The slide image was rendering at its natural aspect ratio because vendor FlexSlider's .flexslider .slides img { height: auto } rule (specificity 0,2,1) was beating the SyteHero cover-fit rule (specificity 0,1,1). The image rule now uses .sytehero-fhsbg .slides img to match vendor specificity, and our cascade-later position lets height: 100%; object-fit: cover win — the image fills the wrapper edge to edge on every breakpoint.

Added​

  • 16 new typography & box controls per Text Area 1 / 2 / CTA Button on every builder (Elementor, Divi, Avada/Fusion, Gutenberg). Authors can now configure font-family, font-style, font-variant, letter-spacing, text-indent, white-space, text-transform, text-decoration + decoration-colour / style / thickness / underline-offset, text-shadow, text-stroke, background-colour, and padding. All routed through the shared StyleTokens pipeline → --sh-{el}-* CSS custom properties consumed by scaffold CSS, so behaviour is identical regardless of which builder you use. The existing five controls (colour, font-size, font-weight, line-height, alignment) are unchanged and back-compat. New tokens fall back to inherit so v1.0.067 sites with no per-element overrides keep their theme cascade exactly as before.
  • Keyword UI for Elementor letter-spacing / text-decoration-thickness / text-underline-offset. Each control is now a paired SELECT (Inherit / normal or auto / Custom value) plus a SLIDER conditionally shown when "Custom value" is picked, so authors can pick the keyword fallback without typing.
  • Always-visible TA1 / TA2 / CTA placeholder in the Elementor editor canvas. When no source is selected (or the picked source doesn't yet resolve to slides), the editor now shows three styled placeholder elements ("Text Area 1", "Text Area 2", "Call to Action") so authors can immediately tweak typography without having to populate content first. Toggleable via the new sytehero_elementor_editor_placeholder_enabled filter (returns true by default).

Internal​

  • Cross-builder StyleMappers refactored to be schema-driven. Adding a new typography prop is now a one-line change in StyleSchema::element_controls(); each builder's StyleMapper iterates the schema and emits its native controls. No more per-prop hand-coded blocks across four mappers.
  • Hardened token sanitization for inline-style emission. font-family rejects values with unbalanced quotes (preventing style="..." attribute escape), text-shadow / -webkit-text-stroke reject unbalanced parens (preventing invalid CSS), and the two composite sanitizers were factored into a single sanitize_css_composite helper so the rules stay in lockstep.
  • CSS regression tests added for every new typography prop on every element (48 new assertions) plus a vendor-specificity guard for the cover-fit rule and unit tests for EditorPreviewRenderer::placeholder_payload(), so future stylesheet refactors can't silently regress any of these fixes.

v1.0.067 — 2026-04-19​

Fixed​

  • Elementor hero CTA now centers horizontally inside the overlay. A legacy align-self: flex-start rule on .sytehero-hero-cta (written for the older theme-shortcode path where the CTA's parent was a flex row) was overriding the scaffold overlay's align-items: center and pushing the CTA to the left edge in Elementor placements. The scaffold overlay now neutralizes that legacy rule so the CTA inherits the overlay's centered alignment alongside Text Area 1 and Text Area 2.
  • Hero overlay text defaults to white in the Elementor / Gutenberg scaffold. Text Area 1 / 2 previously fell back to inherit, which on most themes resolved to the page's dark body color and made them invisible against dark hero images until an author manually configured a color. The default is now #fff, so the hero is readable out-of-the-box; authors who set a color via builder controls keep their value.
  • 5px minimum spacing between Text Area 1, Text Area 2, and CTA is now enforced on all themes. Previously, configuring a margin of 0% (or leaving the per-element margin off) could collapse the elements together. The scaffold overlay's gap is floored at 5px, the per-element margin rules clamp to max(5px, configured value), and a baseline 5px top margin applies to TA2 and CTA inside the hero wrapper on Avada, Divi, Elementor, and Gutenberg.

v1.0.066 — 2026-04-19​

Fixed​

  • Hero slider no longer inherits a 4 px white border on all four sides. FlexSlider's bundled stylesheet (the library SyteHero uses under the hood for the default slider engine) applies a 4 px white border + 4 px rounded corners to .flexslider — a classic "Polaroid frame" default intended for card-style image galleries, not full-bleed heroes. The border has been silently present on every SyteHero hero since forever but was invisible while earlier bugs kept the slider collapsed to 0 px in Elementor; once the v1.0.063 width fix let the slider render at real dimensions, the border became user-visible. The new reset zeroes the border, radius, box-shadow, and the white background on the hero-scoped .flexslider element only — leaving any FlexSlider use outside the hero (if any) untouched. Affects Avada / Divi / Elementor / plain-shortcode placements equally.
  • Simplified the v1.0.064–065 Elementor full-bleed rule. The gap, widget margin, and .elementor-widget-container padding overrides that were piled on in v1.0.065 were defensive speculation against the wrong root cause (the border was FlexSlider, not Elementor container chrome). They are removed; the rule now only zeroes the .e-con padding shorthand + its four logical longhands, which is all that is actually needed for the Elementor full-bleed case.

Internal​

  • FlexSlider reset regression test added so a future vendor-CSS refresh cannot silently restore the Polaroid frame.

v1.0.065 — 2026-04-19​

Fixed​

  • Elementor full-bleed rule now actually zeroes every padding variant. The v1.0.064 rule only zeroed the padding shorthand, but Elementor emits padding via padding-block-start / padding-block-end / padding-inline-start / padding-inline-end logical longhands on some kit and version combinations — those longhands aren't reset by a physical shorthand in the same cascade, so a residual border persisted on affected sites. The full-bleed rule now zeroes the shorthand, all four logical longhands, the container gap, the widget's margin, and .elementor-widget-container's own padding, so no single layer can keep a residual gutter when the SyteHero Hero Slider is the sole widget in its section.

Internal​

  • CSS regression test expanded — two new assertions lock in the logical-longhand zeros + the widget-container reset so a future "simplification" of the rule can't silently re-introduce the border.

v1.0.064 — 2026-04-19​

Fixed​

  • Elementor hero no longer shows a white border around it. When the SyteHero Hero Slider is the only widget in its Elementor section, the section's default 10 px padding is now zeroed so the hero runs edge-to-edge — which is what almost every hero placement wants. Sections that contain additional widgets alongside the hero keep their normal padding, and sections where the padding is set explicitly via Elementor's section controls still win on specificity.
  • Editor preview now respects the SyteHero license state. On sites without an active license, the Elementor editor canvas falls back to the dashed placeholder instead of showing real overlay text and product images — matching the published-page behavior that renders empty when the license is locked.

Added​

  • sytehero_elementor_editor_preview_enabled filter — a kill-switch for the Elementor editor static-preview feature introduced in v1.0.063. Return false to restore the pre-v1.0.063 dashed placeholder. Useful on very large product catalogues where the extra per-editor-open product query noticeably slows editor load, or for authors who simply preferred the older placeholder card.

Internal​

  • CSS regression test added so the v1.0.063 Elementor width-collapse fix cannot silently disappear in a future scaffold-CSS refactor. Exercises the three --elementor-scoped rules plus the new sole-widget full-bleed selector.
  • Featured-slides repository accepts a read-only cache mode. FeaturedSlidesRepository::get_slides_by_tag_slug() gained an optional third argument $skip_cache_write (default false). When true (and $skip_cache is false), the repository reads the frontend transient cache for speed but never writes to it — letting admin-context callers (the Elementor editor preview, chiefly) avoid seeding the public cache with a query that may legally include draft / pending products. Existing two-arg callers are unaffected.

v1.0.063 — 2026-04-19​

Fixed​

  • Elementor hero no longer renders as a 0-width gray box on the published page. Elementor's outer widget element is display: flex (default flex-direction: row), and inside our scaffold both the slider (.sytehero-fhsbg) and overlay are absolutely positioned, contributing zero intrinsic horizontal extent. Without an explicit width, .elementor-widget-container was collapsing to 0 px wide — the slide image (width: 100%) then rendered at 0×0, while the heights cascaded correctly from :has() rules and the inline sizer. Added three width rules scoped to the --elementor builder modifier so the chain inherits the column's available width. Other builder integrations (Avada, Divi, Gutenberg) are unaffected.

Added​

  • Static first-slide preview inside the Elementor editor canvas. Dropping or selecting the SyteHero Hero Slider widget in the Elementor editor now shows a non-interactive snapshot of what the published hero will display — first slide's image, overlay text, and CTA — instead of the previous "live preview disabled" placeholder card. The preview is wrapped in pointer-events: none and never instantiates the slider engine, so the editor canvas's scroll and Elementor's drag handles work normally. Style-tab controls (gap, alignment, color tokens) update the preview live. When no source is selected or no slides are configured, the existing dashed placeholder still appears.

v1.0.062 — 2026-04-19​

Fixed​

  • Theme/framework auto-detection now recognizes Elementor when it's installed as a plugin, even on Avada- or Divi-themed sites. Previously, an Avada site with Elementor active would auto-detect as Avada — so SyteHero's inline sizer would hunt for .fusion-column-wrapper ancestors that never exist inside an Elementor page, and the hero wrapper wouldn't receive its sizing tokens. Fresh installs now default to Elementor on those mixed setups. Existing sites can re-run detection from SyteHero → Settings → Detect (or override manually via the Theme dropdown).

Added​

  • sytehero/is_elementor_plugin_active filter — override SyteHero's Elementor plugin detection. Useful if you want to force a theme-based profile even when Elementor is active (e.g., an Avada site where Elementor is installed but only used on a handful of pages managed by the SyteHero Avada widget). Receives the bootstrap-derived boolean and must return a boolean.

v1.0.061 — 2026-04-19​

Fixed​

  • Elementor builder canvas: hero no longer collapses to 0 px. The scaffold wrap/stage layers that wrap every builder widget's slider did not carry a min-height, so the absolutely-positioned .sytehero-fhsbg slider had no sized containing block and disappeared inside the Elementor canvas. The scaffold now propagates the same min-height formula the outer-wrapper sizer uses, scoped with :has(.sytehero-fhsbg) so non-hero widgets still flow at their natural height. Same fix applies silently to Avada, Divi, and Gutenberg scaffolds.

Added​

  • Builder widgets detect the viewport's breakpoint automatically. Elementor, Avada Fusion, Divi, and Gutenberg SyteHero widgets now opt into reactive breakpoint detection — the wrapper's sytehero-hero-featured--{desktop|tablet|mobile} class tracks the viewport via matchMedia, so authors no longer need to hand-pick a view per breakpoint or render per-view variants. Elementor's own breakpoint config is honored when present (so changing tablet to 900 px in Site Settings → Layout flows through automatically). Plain [sytehero_featured] / [sytehero_custom] shortcodes placed outside a builder widget keep the existing fixed-view behavior.
  • sytehero/breakpoints filter — pin custom viewport thresholds site-wide without editing core. Receives ( array $breakpoints, string $theme_key ) and must return [ 'mobile_max' => int, 'tablet_max' => int ]. Defaults follow each theme's own conventions (Elementor 767/1024, Avada 640/1024, Divi 767/980, generic 767/1024).

Changed​

  • Heads-up for custom CSS authors. On pages rendered through a SyteHero builder widget (Elementor / Avada Fusion / Divi / Gutenberg), the hero wrapper's view class (.sytehero-hero-featured--desktop|--tablet|--mobile) now tracks the visitor's viewport instead of staying pinned to whatever view the widget was configured for. If you have site CSS that assumes a stable --desktop class on a placement, that rule will unselect on mobile/tablet viewports. To restore the old "always desktop" behavior on a specific placement, target by the widget-specific wrapper class instead (e.g., .sytehero-scaffold-wrap--elementor, or a custom class you add via the widget's "Extra wrapper CSS class" field). Plain shortcode calls outside a builder widget are unaffected.

Internal​

  • Inline sizer script de-duplicated into Syte\Hero\Frontend\SliderSizerScript — both [sytehero_featured] and [sytehero_custom] now emit byte-identical sizing JS, and the helper has dedicated unit-test coverage (11 tests).
  • Elementor live-config read hardened: the resolver now checks window.elementorFrontend.config.responsive.activeBreakpoints (Elementor 3.4+), window.elementorFrontend.config.responsive.breakpoints (3.2–3.3), and the raw window.elementorFrontendConfig.responsive.{activeBreakpoints,breakpoints} fallback, so user-overridden Elementor breakpoints propagate regardless of load order.

v1.0.060 — 2026-04-19​

Changed​

  • Builder profile-override system hardened. The 4 builder integrations (Avada Fusion, Divi, Elementor, Gutenberg) that override the active theme injection profile during their render now share a single RenderProfileScope helper that wraps add_filter / do_shortcode / remove_filter in a try/finally. If the shortcode chain throws (license check, repository query, theme adapter), the override is no longer leaked past the render — preventing silent corruption of subsequent slider renders on the same page request.
  • Gutenberg block override now covers all three injection selectors (overlay_wrapper_selector, text_host_selector, cta_text_selector) instead of only the wrapper. On sites where SyteHero is set to a host theme like Avada, the Gutenberg block's overlay text and CTA injection no longer try to find Avada-specific selectors (.fusion-text, .fusion-button-text) inside the host-theme-agnostic block scaffold.
  • Theme keys exposed as constants on ThemeConfig (THEME_KEY_AVADA, THEME_KEY_DIVI, THEME_KEY_ELEMENTOR) so builder integrations don't repeat magic-string keys that a future refactor could silently drift from.

Fixed​

  • ServiceContainer::get_active_theme_injection_profile() now type-guards the resolved theme adapter's return value. A misbehaving custom adapter that returns a non-array (object, null, scalar) now falls back to the global ThemeConfig instead of corrupting the downstream shortcode chain.
  • Frontend slider JS fallback chain reordered for clarity. Builder-specific selectors (.elementor-widget-container, .e-con, .et_pb_column, .sytehero-scaffold-wrap) are tried first; the [data-sytehero-hero-wrapper] data attribute is now last because it's only set by the inline sizer that has already failed by the time we reach the fallback.

Added​

  • Public Syte\\Hero\\Integrations\\Scaffold\\RenderProfileScope helper class. Two static methods: with_override( callable $override, callable $body ) for exception-safe profile substitution during a render, and force_theme( string $theme_key ) to build a fixed-profile override callable from a ThemeConfig::THEME_KEY_* constant. Available for any custom integration that needs the same scoped-override behavior.
  • 10 new unit tests covering the filter contract: RenderProfileScopeTest (7 tests, including try/finally cleanup on body exception) and ServiceContainerProfileFilterTest (3 tests covering the filter wiring + non-array result guard). PHPUnit suite is now 1230 tests / 3720 assertions.

v1.0.059 — 2026-04-19​

Fixed​

  • All builder integrations now use their own theme profile during render, not just Elementor (v1.0.058). The same root cause that collapsed Elementor heroes to a sliver — the inline sizer using whichever profile the global SyteHero setting selected — would have surfaced any time a builder integration was used on a site whose SyteHero theme didn't match. Each builder now owns its rendering context:
    • Avada Fusion element forces the Avada profile (.fusion-column-wrapper).
    • Divi module forces the Divi profile (.et_pb_column).
    • Elementor widget continues to force the Elementor profile (.elementor-widget-container chain).
    • Gutenberg block sizes against the scaffold's own wrapper (.sytehero-scaffold-wrap) so the block works in any host theme without depending on theme-specific column structure.

v1.0.058 — 2026-04-19​

Fixed​

  • Elementor pages: SyteHero hero now renders at full size instead of collapsing to a small square in the corner. The shortcode's inline sizing CSS/JS was hardcoded to the globally-selected SyteHero theme (typically Avada's .fusion-column-wrapper), which doesn't exist inside an Elementor widget — leaving the absolutely-positioned slider with no parent height. The Elementor widget now overrides the active injection profile during its render, and the frontend slider JS falls back to the closest .elementor-widget-container / .e-con / [data-sytehero-hero-wrapper] when the configured selector doesn't match. Sites that use SyteHero in mixed-builder contexts (e.g. Avada theme with Elementor pages) will see the hero render correctly in both.
  • Save Image Details: preview at the top now reliably appears with the actual generated image. In the non-deferred save flow, the modal opened the dialog before the image URL had been fetched, so the preview block stayed empty. The flow now fetches the preview URL before opening the dialog, falls back to reading the rendered result <img> element when state is empty, and always renders the preview wrapper as a stable visual anchor.
  • Discard button is now always visible in the Save Image Details dialog — including in studio mode where no attachment exists yet. In the no-attachment case, Discard simply resets the in-flight generation and closes the dialog so users can re-prompt; in preset-tool mode it still deletes the auto-saved attachment from the media library.
  • Modal no longer auto-closes after saving SEO metadata. Previously, completing a non-deferred save closed the entire modal, removing the user's chance to review the saved image, regenerate, or apply it. The modal now stays open after save so the user can decide what to do next.

Added​

  • sytehero_active_theme_injection_profile filter lets renderers temporarily substitute the active theme injection profile for the duration of a single shortcode render. Used by the Elementor widget to force its own profile on Avada-themed sites; available for any custom integration that needs the same.

v1.0.057 — 2026-04-19​

Added​

  • Save Image Details now shows a preview of the generated image at the top of the dialog, so you can see exactly what you're about to save before filling in title/alt/caption/description.
  • "Discard" button in Save Image Details for AI Studio's preset tools (Extend to Fit, Remove Background) where the generated image is auto-saved to the Media Library before the dialog opens. Clicking Discard prompts for confirmation, then deletes the attachment so you don't have to clean up unwanted images by hand. The original source image is preserved so you can immediately retry. If the image is already in use elsewhere on the site, Discard surfaces a friendly inline message instead of force-deleting. (Studio mode hides the button entirely — Cancel still works there because nothing was saved yet.)
  • sytehero_fal_outpaint_guardrail_prompt filter for agencies and developers who want to tune the outpaint guardrail phrasing per-site without forking. Receives ( string $prompt, string $image_url, string $user_prompt ).

Changed​

  • Extend-to-Fit Aspect Ratio panel spacing has been refined. The description, the "Extend to <ratio>" button, and the optional fill-prompt input now have proper visual hierarchy — the button reads as the primary action and the prompt is visually separated as an optional refinement.
  • Outpaint (Extend to Fit) now reliably matches the original background. A guardrail instruction is automatically prepended to every outpaint request asking the model to seamlessly extend the existing scene and avoid introducing unrelated objects, text, or scenery. Your custom fill-prompt (if any) is appended as additional direction. The fill-prompt placeholder and an inline tip have been updated to reflect this.
  • Elementor editor placeholder for the SyteHero Hero Slider widget now shows the human-readable source name (e.g. "Featured Products slider", "Custom Hero: Spring Sale") instead of the raw slug.

Fixed​

  • Elementor editor canvas no longer loses scroll when the SyteHero Hero Slider widget is added. The featured-products slider's positioning and touch handlers were trapping wheel/touch events inside Elementor's preview iframe. The widget now renders a static placeholder when in edit mode (the live slider still renders normally on the published page), the slider's frontend JS bails early if it detects Elementor edit mode, and a defensive CSS reset neutralises the slider's overflow:hidden/position:absolute whenever Elementor's editor body class is present — so even hero markup that lands in the editor through other paths (HTML/shortcode widgets, cached templates) can no longer trap scroll.

v1.0.056 — 2026-04-19​

Fixed​

  • Dragging an image into the AI Studio source area now reliably selects it. A follow-up to v1.0.055 addressing two stacked issues: the uploader falls back through sizes.medium.url → url → guid (and logs a warning if none are usable), and the thumbnail <img> retries with the full-size URL when its subsize variant (e.g. -229x300.jpg) fails to load. If both variants fail (the rare case where the upload response URL points to a different origin that hasn't yet received the file), the drop zone restores its placeholder and surfaces an "Upload failed" hint instead of silently collapsing. Fix spans every AI Studio modal — AI Studio, Remove Background, Extend to Fit, Upscale, Image-to-Video, Hero generator.

Added​

  • "Processing…" spinner in the source image drop zone during upload. Dropping an image (or using the AI Studio "Upload File" button) now shows a centred spinner and a pulsing accent border while the file is uploading, so the zone never looks unresponsive between drop and selection. The AI Copy Reference image tile gets an equivalent spinner overlay. Copy is localizable via SyteHero.i18n.aiSourceProcessing / aiSourceUploading / aiSourceUploadFailed.
  • Drag-and-drop on the AI Copy modal's Reference image tile. The tile already accepted click-to-pick via the Media Library; it now also accepts a dropped image file, mirroring the behaviour of every other image input in AI Studio.

Changed​

  • "Extend to Fit Aspect Ratio" now sits directly under the Quality selector inside the generation options, instead of appearing as a standalone row above the prompt. Keeps the option visually grouped with the other generation controls where users expect it.

v1.0.055 — 2026-04-19​

Changed​

  • Unified drop-zone placeholder wording across AI tool modals. The per-tool modals (Remove Background, Extend to Fit, Upscale, Image-to-Video) now read "Drop or click" to match the hero and AI Studio modals, replacing the longer "Drop or click to select image" for a consistent drop-target affordance.

v1.0.054 — 2026-04-19​

Fixed​

  • "Unexpected status: in_progress" error on slow AI generations. The AI image modals were only recognising fal.ai status codes in their legacy uppercase form, so when a model stayed in progress long enough to be re-polled (common with Nano Banana Pro), the UI bailed out with an error. Poll handlers now normalise the response so either uppercase or lowercase statuses round-trip cleanly.
  • Drag-and-drop uploads into the AI Studio modal no longer vanish. Previously the dropped file uploaded to the Media Library but never appeared in the source area unless the Media Library picker had been opened first. The drop handler is now wired to the same state-update path as click-to-select, so the thumbnail updates immediately.
  • AI Studio "Upload File" button now shows the image straight away. Same class of bug as the drag-drop case: if a user clicked Upload File before ever opening the Media Library picker, the file uploaded but the thumb stayed empty. It now routes through the base modal's shared selection handler.

Added​

  • Drag-and-drop is now available in every AI modal. The hero image generator, AI Studio, and the per-tool modals (Remove Background, Extend to Fit, Upscale, Image-to-Video) all accept an image file dropped onto their source area in addition to click-to-pick. The placeholder now reads "Drop or click to select" as a visible hint.

Changed​

  • "Extend to Fit" is now a collapsed dropdown instead of an always-visible row. It used to appear automatically whenever the source image's aspect ratio didn't match the target, which confused users unfamiliar with outpainting. It now only appears when your source actually doesn't match the selected ratio, shows up collapsed by default, and carries a discreet "Recommended — your source doesn't match…" hint next to the summary. Opening it reveals the optional fill prompt and "Extend to <ratio>" button. The Extend to Fit tool modal keeps the dropdown auto-expanded since it's the tool's primary action.

v1.0.053 — 2026-04-19​

Changed​

  • Scaffold wrapper discovery simplified. sytehero-frontend-overlay.js now recognises .sytehero-scaffold-wrap as the overlay wrapper directly, short-circuiting the theme-profile walk-up when a builder widget is present. The scaffold no longer needs to carry .e-con (or any theme-specific class) to be discoverable, and the Elementor builder path stops emitting .e-con entirely.
  • Non-Elementor builders emit a bare CTA text <span></span> — the unreferenced sytehero-hero-cta-text class introduced in v1.0.052 has been dropped. The Elementor path continues to emit .elementor-button-text where the Elementor theme profile's host selector expects it.

Added​

  • Editor-script handle contract tests — HeroSliderBlockModuleTest now directly asserts editor_script_handle() returns 'sytehero-hero-slider-editor-script' and stays in lockstep with BLOCK_NAME. A generate_block_asset_handle() test stub in tests/bootstrap.php mirrors WP's real algorithm so both the live and fallback paths are covered.
  • Strengthened coexistence-test sentinel — verifies via reflection that the three DiviModuleRegistrarCoexistenceTest future-contract methods still exist so a rename or accidental deletion trips a failing test immediately.

v1.0.052 — 2026-04-19​

Changed​

  • Scaffold decoupled from Elementor-specific class names. The builder-scaffold renderer now emits .e-con, .elementor-widget-container, .elementor-button, and .elementor-button-text only for the Elementor widget path. Gutenberg / Avada / Divi / Divi 5 scaffolds produce clean, theme-neutral DOM — .sytehero-hero-text-area-1, .sytehero-hero-text-area-2, .sytehero-hero-cta, .sytehero-hero-cta-text. No frontend behaviour change (the overlay-injection JS's el.closest(selector) || el fallback continues to land text in our elements regardless).
  • Gutenberg block editor-script handle is now computed dynamically via generate_block_asset_handle() instead of a hardcoded string — future-proof against WP's handle-generation algorithm changes.
  • Fusion Builder preview template uses the underscore HTML-escape delimiter ({{- }} instead of {{= }}) for data.sh_source interpolation. Defensive escaping at the template boundary even though the field currently only carries sanitized dropdown values.

Added​

  • CI Node build step. .github/workflows/release.yml now runs npm ci + npm run build:all between PHPUnit and the ZIP-staging step, so the release zip always contains freshly-built assets/blocks/ and assets/divi5/ rather than whatever was last committed.
  • Coming Soon placeholder contract tests — asserts the Divi 5 placeholder row in Settings remains inert (no TabGateOptions key backing it) until the module actually ships.
  • Divi 4 ↔ Divi 5 coexistence contract tests (deliberately skipped until the D5 module lands). Encodes the required short-circuit behaviour as a ready-made regression net for the future implementer.
  • Divi 5 stub bundle emits a small runtime marker (window.SyteHeroDivi5 = 'coming-soon', ~88 bytes) so WP caching/minify plugins don't treat the compiled file as corrupt.

Notes​

  • An attempt to migrate from deprecated divi-types-* npm aliases to the direct @divi/* packages was reverted — the direct packages have a transitive dependency (@types/[email protected]) that's missing from the npm registry, breaking fresh installs. Deferred to the Divi 5 native module continuation work; conditions for a successful re-attempt are documented.
  • No runtime behaviour change on any of the four supported builders.

v1.0.051 — 2026-04-19​

Added​

  • Divi 5 native module infrastructure (Coming Soon feature). Build-time groundwork for a future first-class Divi 5 module — npm dependencies (@divi/types + targeted @types/divi__* packages), TypeScript + Webpack configs, a build:divi5 script, and a stub src/divi5/ source tree that compiles cleanly. The module implementation itself is deferred pending a green-light signal (customer demand, Divi 5 adoption threshold, or upstream @divi/* API stabilisation); see docs/superpowers/plans/2026-04-19-divi5-module-continuation.md.
  • "Divi 5 native module (Coming Soon)" placeholder under Settings → Advanced → Tab access. Greyed out and non-interactive — marks where the real toggle will appear when the module ships.

Changed​

  • Divi Classic module and Gutenberg block documentation now reference the Coming Soon Divi 5 roadmap.

Notes​

  • No runtime behaviour changes on Divi 4 or Divi 5 sites. The Classic module from v1.0.049 continues to serve both (Divi 5 via its Classic-compatibility layer).
  • Rolling back this release is safe: all additions are dev-only tooling + a disabled UI row; no new runtime code paths were introduced.

v1.0.050 — 2026-04-19​

Added​

  • Fusion Builder element preview — the SyteHero Hero Slider element now renders a labelled preview card inside Fusion Builder showing the element's name and selected source. Previously the builder showed only a generic element rectangle.

v1.0.049 — 2026-04-18​

Added​

  • Avada / Fusion Builder element: SyteHero Hero Slider — register a native Fusion Builder element via fusion_builder_map() on fusion_builder_before_init. The element wraps a shortcode ([sytehero_fusion_hero_slider]) that reuses the shared scaffold subsystem introduced in v1.0.047, producing byte-identical frontend markup to the Elementor widget and Gutenberg block for equivalent attributes. Style tab exposes colour, font size, font weight, line height, and alignment per Text Area 1 / Text Area 2 / CTA, plus a layout gap.
  • Divi Classic module: SyteHero Hero Slider — register a custom ET_Builder_Module subclass via et_builder_ready. Targets the classic back-end Divi Builder; the Visual Builder uses Divi's AJAX fallback rendering (a future release may add native VB rendering via a Divi Extension). Same Style-tab controls as the Fusion element.
  • Settings → Tab access toggles — two new toggles (Enable Fusion Builder element, Enable Divi module) let admins hide each integration without affecting existing shortcode placements.

Changed​

  • Bumped the shared scaffold subsystem's builder set to four: Elementor (v1.0.047), Gutenberg (v1.0.048), Avada / Fusion Builder, Divi Classic. Every builder consumes the same Syte\Hero\Integrations\Scaffold\StyleSchema + ScaffoldRenderer so authors see consistent behaviour across platforms.

v1.0.048 — 2026-04-18​

Added​

  • Gutenberg block: SyteHero Hero Slider — insert the block on any post, page, or site-editor template and pick a saved hero from the Inspector. The overlay (Text Area 1, Text Area 2, CTA) is pre-packaged in the block's output; no container assembly required. Reuses the shared scaffold subsystem introduced in v1.0.047 so block placements produce the same frontend markup as the Elementor widget.
  • Inspector Style panels — colour, font size, font weight, line height, and alignment per Text Area 1 / Text Area 2 / CTA, plus a layout gap control. Values cascade on top of the global SyteHero Settings defaults.
  • Settings → Tab access → Enable Gutenberg block toggle — hides the block from the inserter without affecting existing shortcode placements.

Changed​

  • Minimum WordPress version bumped to 5.8 (required for block.json-based block registration). Effectively no real-site impact; WP 5.0–5.7 is <1% of active sites per wordpress.org usage stats.
  • Build pipeline: root package.json + @wordpress/scripts added for the Gutenberg block bundle. Dev-only — src/, package.json, node_modules/ are excluded from the release zip by the existing allowlist. Built output ships from assets/blocks/.

v1.0.047 — 2026-04-18​

Added​

  • Pre-packaged overlay scaffold for the Elementor widget — dropping the SyteHero Hero Slider widget onto a page now produces the Text Area 1, Text Area 2, and CTA overlay automatically. No separate Heading/Button widgets required and no CSS-class scaffolding to remember. Content still comes from SyteHero → Custom Heroes (or the Featured Products slider); empty source fields hide the matching overlay element.
  • Style tab on the Elementor widget — per-placement controls for text colour, font size, font weight, line height, and alignment on each of Text Area 1, Text Area 2, and CTA, plus a layout "gap between elements" control. Values cascade on top of the global SyteHero Settings defaults.

Changed​

  • Shared scaffold subsystem introduced under Syte\Hero\Integrations\Scaffold (StyleSchema, StyleTokens, ScaffoldRenderer). The Elementor widget is the first consumer; the Gutenberg block (v1.0.048) and Avada/Divi elements (v1.0.049) will reuse the same building blocks.

v1.0.046 — 2026-04-18​

Added​

  • Elementor widget: SyteHero Hero Slider — drop a "SyteHero Hero Slider" widget onto any Elementor page and pick either the Featured Products slider or a saved Custom Hero from a dropdown. Rotation, Text Area 1 / Text Area 2 / CTA overlays, license gating, and theme styling are inherited from the existing shortcode path, so there is no duplicate content to manage. Per-instance view variant (desktop/tablet/mobile) and an optional wrapper CSS class are exposed.
  • Settings → Tab access → Enable Elementor widgets toggle — lets admins turn the widget off globally without affecting existing shortcode placements.

v1.0.045 — 2026-04-16​

Fixed​

  • Fatal error on admin pages — added missing use import for AiProviderAjaxHandler in AdminJsConfig after the AJAX namespace refactor. The class moved to Admin\Ajax but the reference was not updated, causing a fatal "Class not found" error on every admin page load.

v1.0.044 — 2026-04-16​

Fixed​

  • Uniform hero height — product, custom/page, and fallback slides now all render at the same configured height. Previously, custom slides with large images could push the hero beyond the set viewport height.
  • FlexSlider smoothHeight — no longer fights the hero height constraint inside the slider background.
  • Supplemental slide auto-save — editing text, margins, modes, or glow on custom/page slides now auto-saves via AJAX. Previously these changes were lost because the save was never triggered.
  • Push View persistence — the Push View button now persists changes for supplemental and fallback hero text editors.

v1.0.043 — 2026-04-15​

Fixed​

  • Straico AI provider — migrated from v1 API (which returned HTTP 522) to the OpenAI-compatible v2 API. Straico now uses the same request format as OpenAI and OpenRouter.
  • Straico model picker — filters to chat models only, excluding image, video, and audio models from the text-provider dropdown.

Changed​

  • AI chat completion timeout — increased from 30 seconds to 60 seconds to accommodate slower LLM providers and aggregator services.
  • OpenAI-format token limit — requests now send both max_completion_tokens and max_tokens for broad compatibility with OpenAI-compatible providers.

v1.0.042 — 2026-04-15​

Fixed​

  • Admin-bar launcher reliability — removed a hard script dependency (media-editor) that could silently prevent the launcher from loading, causing admin-bar AI Studio items to stop responding to clicks.
  • Modal media picker diagnostics — media picker guards now log a visible console warning when wp.media is unavailable, replacing the previous silent no-op.

Changed​

  • Launcher script hardening — script loader now tracks already-loaded assets to prevent duplicates, scopes click handling to the admin bar, and logs errors on script load failure.

v1.0.041 — 2026-04-15​

Fixed​

  • AI Studio admin-bar modals on every page — Generate, Transform, Remove Background, Upscale, Extend to Fit, Image to Video, and AI Copy now work when launched from the admin bar on any admin page (Dashboard, Posts, Users, Plugins) or on the frontend for logged-in admins. Previously the modals opened but buttons inside were inert because their scripts didn't receive the full SyteHero config or the WordPress media picker.

Changed​

  • Admin-bar launcher moved to enqueued assets — the launcher script and styles previously printed inline in each admin page now load from cacheable sytehero-admin-bar-launcher.js and .css files. No user-facing difference beyond slightly smaller page HTML.

v1.0.040 — 2026-04-15​

Fixed​

  • AI provider tokens-refresh button — the refresh button next to Max Tokens on the AI Image provider card now syncs only the tokens value from the selected model. It no longer refetches the models list. If the models haven't been loaded yet, click Refresh models first.
  • Admin-bar AI modals — modals launched from the top SyteHero → AI Studio → [modal] menu (AI Copy, BG Removal, Upscale, Outpaint, Image-to-Video) now render with the same styling as the AI Studio Generate modal. Previously, opening them outside the AI Studio page loaded only the base modal stylesheet, leaving drop zones and AI Copy-specific layout unstyled.

v1.0.039 — 2026-04-15​

Changed​

  • AI Copy modal styling — reference tiles, inputs, suggestion chips, and status states now use the same dark modal surface styling as the other AI Studio modals.
  • Transform modal footer layout — action groups now keep a cleaner responsive structure as space tightens, with more consistent button alignment across desktop and mobile.

v1.0.038 — 2026-04-15​

Changed​

  • Prompt Enhancement — now routes through the shared AI text-provider system. Fal is registered as a text provider so existing Fal-only setups keep working without any extra configuration. Saved Fal API keys carry over automatically.

Removed​

  • Legacy AI image shims — sytehero_fal_* AJAX action aliases, the sytehero_fal_settings option, and the FalAiSettings / get_fal_service transitional helpers from the v1.0.036 AI provider refactor have been removed. Any integrations still calling the old names must update to sytehero_ai_image_*.

v1.0.037 — 2026-04-15​

Changed​

  • AI Studio — Integrations tab — AI image providers now render as separate card-style blocks with a shared save flow, making multi-provider configuration faster and less error-prone. Per-provider connection testing is preserved.
  • Documentation — Integrations docs updated to describe the refreshed card layout and shared save workflow.

v1.0.036 — 2026-04-15​

Changed​

  • AI Studio — Fal AI is now implemented as the first adapter in a pluggable AI image/media provider system. Each capability (Generate, Transform, Remove BG, Upscale, Extend to Fit, Image-to-Video) can be independently routed to different providers. Existing Fal API key and settings migrate automatically on upgrade.
  • Prompt Enhancement — now available as a function area on the Integrations tab; when configured with a text provider (Claude, OpenAI, etc.) prompts are enhanced via that provider instead of Fal's built-in model.

v1.0.035 — 2026-04-09​

Changed​

  • FluentCart detection — recognizes FluentCart and FluentCart Pro using broader class and constant signals when WooCommerce is not installed

Fixed​

  • Plugin activation — no longer fatals when the ecommerce gateway is unavailable; featured-tag setup runs when the store is ready

v1.0.034 — 2026-04-09​

Added​

  • Integrations refresh — refresh actions for the AI model list and max-tokens fields on the Integrations card

Changed​

  • AI Providers card — three-column layout, Browse Models links, clearer dropdowns, and visual polish
  • Maintenance — uninstall cleanup, FluentCart-related fixes, and modularization from the comprehensive review

Fixed​

  • Fal balance capture — fast models record post-generation balance and cost data more reliably
  • AI integrations — Straico and Gemini model loading, integrations refresh behavior, badge contrast, and max-tokens synchronization

v1.0.033 — 2026-04-08​

Added​

  • AI Studio modal — new dark-themed modal for text-to-image and image-to-image generation, accessible from any admin page
  • Admin bar launcher — a ✨ icon in the WordPress admin bar opens the AI Studio modal from any admin screen without navigating to the AI Studio page
  • AI media manager — dedicated AI Media tab to browse and delete AI-generated images, with usage detection to protect in-use assets

Removed​

  • Unused Media Scanner — AI Studio's Tools tab and all underlying scan/delete/export functionality has been removed.

Changed​

  • Admin background — Plugin admin pages now use a neutral slate-gray page canvas (#f8fafc) so white cards visually lift off the background.

Fixed​

  • Countdown modal save — Clicking "Save Settings" in the countdown modal now immediately persists settings via AJAX. A second manual save of the schedule form is no longer required.
  • Analytics click tracking — CTA clicks are now tracked at click time via a rate-limited AJAX beacon. Previously, "clicks" only recorded at completed checkout.

Changed​

  • AI Studio checkboxes — Custom checkbox styling with proper checked state and focus indicator replaces the native browser rendering.

v1.0.032 — 2026-04-01​

Added​

  • AI hero image generation powered by fal.ai — select a source image from the media library, write a prompt, pick a model (with cost indicators), and generate a new hero image directly in the WordPress admin
  • New fal.ai integration card on the Integrations tab for API key management and connection testing
  • "Generate with AI" buttons on the product metabox, Heroes tab, and Schedules tab

v1.0.031 — 2026-04-01​

Changed​

  • FluentCart release workflow: clearer logging and documentation for the x-sytehero-release WAF header (including guidance when the same Cloudflare zone also fronts SyteOps)

v1.0.030 — 2026-04-01​

Changed​

  • Release automation can optionally publish the plugin ZIP to SyteWide FluentCart product downloadables when repository credentials are configured (no change required for sites that only install updates from SyteWide)

v1.0.029 — 2026-04-01​

Fixed​

  • Video and iframe content now displays correctly in analytics hover preview when a slide uses video media

v1.0.027 — 2026-04-01​

Added​

  • Persistent slide labels in the analytics dashboard — label your slides for easy identification
  • Hover preview tooltip showing the slide image or video in analytics Card and Table views

v1.0.026 — 2026-03-31​

Added​

  • "No-track" bookmark link in analytics settings for quickly toggling tracking on and off

v1.0.025 — 2026-03-31​

Fixed​

  • Countdown timer now correctly respects tablet device visibility toggle

v1.0.024 — 2026-03-31​

Added​

  • Analytics fallback labels for slides without explicit names
  • Reset button for analytics data
  • Option to exclude admin users from analytics tracking

Fixed​

  • Hero rotation order now preserved when schedules add or remove slides

v1.0.010 — 2026-03-30​

Added​

  • Sale countdown timer overlay — display a live countdown on hero slides tied to sale end dates, with configurable position (top strip or below CTA) and per-slide visibility toggles
  • Slide performance analytics dashboard — track slide impressions with Card and Table views, date-range filtering, and a visual analytics tab in the admin

Changed​

  • SyteWide branding applied to admin page header
  • Analytics tab repositioned for better workflow

v1.0.009 — 2026-03-30​

Fixed​

  • Email footer logo now renders at correct size with shared branding helper

v1.0.007 — 2026-03-30​

Changed​

  • Updated to transparent PNG logos across admin and email branding

v1.0.004 — 2026-03-30​

Fixed​

  • Email report cron scheduling now fires reliably
  • Corrected shortcode tag names after rebrand

Added​

  • Cron diagnostics in admin for troubleshooting scheduled emails

v1.0.000 — 2026-03-28​

Added​

SyteHero launches as the successor to SyteSlyders, carrying forward all features under a new name and unified codebase:

  • Featured product hero slider with drag-and-drop ordering, per-slide scheduling, and pause controls
  • Hero text overlays with per-view (desktop/tablet/mobile) customization, glow effects, and CTA buttons
  • Custom heroes — add page, category, or custom URL slides alongside products
  • Sales scheduling — start/end dates, retain-after-expiry, and banner sync
  • Banners — rich-text announcement banners tied to sale schedules
  • Custom CSS — cross-theme CSS editor scoped to hero wrappers
  • Shortcodes — embed featured and custom sliders anywhere via shortcode
  • Slider engines — choose between FlexSlider, Swiper, or Splide
  • Multi-theme support — Avada, Divi, and Elementor integrations with theme-aware injection
  • Multi-ecommerce support — works with both WooCommerce and FluentCart
  • Google Calendar integration — two-way sync of sale schedules with Google Calendar
  • Shippo shipping integration — tracking info and shipping label costs in sales summary emails
  • Sales summary reports — periodic and real-time order notification emails with dark mode support
  • Backup & restore — full settings export/import
  • License activation — first-run setup with EULA consent and SyteWide license validation
  • Set Defaults modal — configure master hero text defaults and push to individual slides
  • Admin preview — responsive browser-style preview with desktop/tablet/mobile breakpoints
  • Documentation tab — in-plugin docs with configurable demo video