Turn on Hide Price Until Login for individual products. Each product gets a "Login to purchase" entry in its FluentCart menu, and the module's "Apply to" setting chooses between those products and all products. Stores that already used the…
Read full notes
Turn on Hide Price Until Login for individual products. Each product gets a "Login to purchase" entry in its FluentCart menu, and the module's "Apply to" setting chooses between those products and all products. Stores that already used the module keep applying it to all products, so updating exposes no price; new setups are opt-in. Buy Now, Add to Cart, and quantity controls are now left out of the page per product, so a shop grid can mix hidden and visible products.
Fixes: guest modal checkout for a login-only product now shows the login prompt instead of the HTTP 500 it returned since 2.6.4, and orders containing a login-only product are refused when the buyer must log in, closing carts created before the product required login. Invoice and existing-order payment links are unaffected.
Validation: 21 per-product checks and the scope migration on MariaDB, 13 store-wide checks on FluentCart 1.6.6, real HTTP tests of Buy Now, modal checkout, and order placement for guests and logged-in customers in both modes, a failing pre-fix run, existing checkout cache-buster, currency, and invoice contract checks, PHP/JavaScript syntax, generated assets, and package integrity.
Keep Hide Price Until Login prices off the page for guests. Product pages, shop grids, product cards, variant data, pricing tables, search results, and the public product API now leave the server with the login prompt instead of the amount…
Read full notes
Keep Hide Price Until Login prices off the page for guests. Product pages, shop grids, product cards, variant data, pricing tables, search results, and the public product API now leave the server with the login prompt instead of the amount. Buy Now and Add to Cart controls are hidden on FluentCart 1.6 markup, and guest instant-checkout links are refused. Unchecked login-link and redirect settings are now respected, and the prompt holds on Multi-Currency stores.
Validation: 13 hide-price checks on FluentCart 1.6.6 (guest and admin rendering, REST, pricing table, instant checkout, signed-in REST without a nonce) with a failing pre-fix run, a guest scan of 9 storefront and API surfaces, existing checkout cache-buster, currency, and invoice contract checks, PHP/JavaScript syntax, generated assets, and package integrity.
Core Tables 1.0.0-beta.1 includes the full 0.2.0 dataset/Sheets workflow and adds readable chart axes and exact values on hover.
Read full notes4 changes
This is a beta release. Requires WordPress 6.9+ and PHP 8.3+. Back up the database before upgrading; preserve AUTH_KEY for encrypted connections. Version 0.2.0 is retained for rollback.
Validation: PHP/static/JS checks, 19 unit tests, 246 integration checks, ten concurrent-write races, and actual chart/editor/public browser workflows. No additional accessibility certification or customer pilot is claimed.
Delivery verified: GitHub and FluentCart serve the same 213,314-byte ZIP (0609084ee3086de812637960d2351f6f4b1a9124cfeb953c297e8b93d2cf1611). The licensed updater returns 1.0.0-beta.1 with a direct signed R2 package; invalid activation receives no package. A real WordPress bulk upgrade from 0.2.0 passed with maintenance mode active. The temporary verification license was removed, and the 0.2.0 artifact is retained for rollback. All six release CI jobs passed.
Automatic X/Y labels from selected public columns, numeric/category ticks, and currency units.
Point and bar values on hover, focus, or touch, including signed and zero values.
Matching editor previews, nearest-point selection for dense lines, and native titles when JavaScript is unavailable.
Core Tables 0.2.0 adds read-only Google Sheets refresh, indexed datasets up to 10,000 rows, line charts, and simpler table/chart block workflows.
Read full notes5 changes
Requires WordPress 6.9+ and PHP 8.3+. Back up the database before upgrading; version 0.2.0 adds revision indexes and source/job tables while retaining existing datasets and publications. Preserve WordPress AUTH_KEY to retain access to encrypted connections.
The product remains early access. Google Sheets uses a customer-managed service account. Full assistive-technology certification, automated personal-data detection, and unsupported external-cache invalidation are not claimed.
Validation: PHP/static/JavaScript checks, 19 unit tests, 237 integration checks, 10 concurrent save/publication races, and actual Block Editor/public table workflows. The prior 0.1.1 package remains available for rollback.
Delivery verified: GitHub and FluentCart serve the same 203,617-byte ZIP (e7c5c8fcc947e291119f27c36083871351469f2fa00774e6bfd9e3a4b71261cf). The licensed updater returned 0.2.0 with a direct signed R2 package; invalid activation received no package. A real WordPress bulk upgrade from 0.1.1 succeeded with maintenance mode active. The temporary verification license was removed, and the prior 0.1.1 artifact is retained for rollback. All six release CI jobs passed.
Connect a Google Sheet with explicit column mapping, encrypted credentials, draft review, refresh scheduling, pause/resume, cancellation, and retry status.
Search and browse all accessible datasets, restore older revisions, and manage retained history or permanently delete reviewed datasets from Trash.
Use typed filters, rich cells, line/bar charts, and optional public CSV exports.
Choose datasets in a focused dialog, adjust presentation in the native Styles tab, and keep dataset editor actions visible while scrolling.
Pagination and CSV buttons default off. Without pagination, all published rows are displayed. Enabling pagination restores page controls; downloads also require dataset-level permission.
Star Rating votes never saved. Since 2.9.0 the public acf-blocks/v1/ratings route used floatval as the sanitize_callback for rating and initialRating. WordPress calls sanitize callbacks with three arguments ($value, $request, $param), and…
Read full notes21 changes
What's Changed
Fixed
Star Rating votes never saved. Since 2.9.0 the public acf-blocks/v1/ratings route used floatval as the sanitize_callback for rating and initialRating. WordPress calls sanitize callbacks with three arguments ($value, $request, $param), and an internal PHP function given more arguments than it accepts throws ArgumentCountError on PHP 8 (PHP 7 warned and returned null, which the range check then rejected). Every submission failed before reaching storage: a 500 on PHP 8, a 400 on PHP 7. Both arguments now use acf_star_rating_sanitize_float(), which also turns non-numeric input, arrays included, into 0, so the existing 1 to 5 range check answers it with a 400 instead of counting it.
The Star Rating widget had no REST URL on block themes. The script was registered on wp_enqueue_scripts, but a block theme renders its template, and every block in it, before wp_head fires that hook. The render template's wp_localize_script() call hit an unregistered handle and returned false, and a static flag stopped later renders from retrying, so window.acfStarRating was never defined and the submit handler returned without sending anything. Registration and localization now happen once on init, and the template calls the same helper before enqueueing so renders outside the normal hook order are covered too. Classic themes, where wp_enqueue_scripts runs before the content, were only affected by the first bug.
Added
Regression tests: every sanitize callback on the ratings route must be a PHP function that tolerates WordPress's three arguments, and the Star Rating script must be registered and localized on init, with no localization left in the render template.
Commits
2.11.4: fix Star Rating votes on PHP 8 and block themes (8676090)
docs add Buy Me a Coffee support links to README (2ebb43d)
A fix for "Don't cache this page" in optimize-only mode, and admin and CLI text that now matches the screens it describes.
Read full notes4 changes
Fixes
In optimize-only mode, a page marked "Don't cache this page", or one that defines DONOTCACHEPAGE, is now sent no-store as 1.2.0 described. It was left unoptimized but sent no cache headers, so a host cache (LiteSpeed, Hostinger, Kinsta) could store it for its own default lifetime.
The CSS status panel no longer reports "Needs cache setup" in optimize-only mode. Unused-CSS builds run in that mode without the drop-in or WP_CACHE.
cache explain and cache verify accept every hostname --page-url accepts, including aliases added with the gt_performance_canonical_hosts filter. The page-url check let an alias through and the inspector then refused it as another site. The Diagnostics explainer and the explain ability accept the same hostnames.
The language and currency plugin advice names the "Cookie prefixes that bypass cache" field by its label, and the database --all-revisions help names the "Run selected optimization" button.
Works out of the box: a guided setup, optimization for sites whose host already caches pages, and a plugin that cleans up after itself.
Read full notes18 changes
Setup and cache modes
Caching
Cloudflare
Compatibility and diagnostics
A Setup tab walks a fresh install to a verified cached page: AUTH_KEY, OpenSSL, the cache directory, and who owns advanced-cache.php; active page-cache plugins and host caches (from the environment, or from the home page's headers fetched once as a visitor: LiteSpeed, Kinsta, Hostinger, SiteGround, WP Engine, Varnish, Nginx, and others); the cache mode; Cloudflare; store and language plugins; and a verification that requests the home page as a visitor, up to four times two seconds apart, until GT Performance answers HIT. Cloudflare's answer is shown beside the result rather than deciding it, because right after a full purge the edge can keep answering MISS for a minute while the origin already serves HITs. Nothing runs until a button is pressed, and activation does not redirect. The Dashboard points to Setup until verification passes.
Optimize-only mode runs the optimization pipeline on responses the eligibility rules would cache and hands them to the host's cache without storing them. The drop-in is not required, and the compiled configuration tells an installed one never to serve. Bypassed requests start no output buffer. Responses must pass the same checks a stored page must, and warming and stale refresh are skipped. Cache headers for eligible pages are left to the host. A response the eligibility rules would not cache is sent no-store, as in store mode: a shared cache that receives no Cache-Control applies its own default lifetime (two hours at Cloudflare), so staying silent would have shared pages this plugin refused to cache. The mode is chosen in Setup or on the Cache tab and shown on the Dashboard, in the health report, cache status, and the site-status ability.
"Cache each value separately" lists query parameters whose values each get their own stored copy, instead of bypassing the cache as unknown parameters. Values over 100 characters are not cached, and a page holds at most 100 variants; beyond that, new values are served uncached. Each variant is recorded in a per-page index, so purging the page removes every variant at the origin and passes their URLs to the edge purge.
The editor's GT Performance box adds "Don't cache this page" (never stored or optimized, sent no-store, reported by Explain as page-option) and "Use original CSS" (full stylesheets, no unused-CSS build queued).
Query parameters sent as arrays (name[]=) bypass the cache as query_array:<name> and are sent no-store, like never-cache parameters. parse_str() made them arrays and the request context kept only scalars, so ?preview[]=1 or ?s[]=x was judged and keyed as the page with no query, in WordPress and in the drop-in.
A preload that gets a redirect or a 4xx is recorded as skipped (redirect_301, http_404) instead of failing and retrying three times. On a large site, sitemap URLs of moved posts had made up most of the queue's failed jobs. Server errors and transport failures still fail and retry.
A settings save advances the cache generation, which purges the origin and sends purge-everything to Cloudflare, only when a setting that reaches cached pages changed. Credentials, connection status, background work, and admin-only settings are listed as output-neutral; anything else, including any new setting, still purges.
Unused CSS kept a block theme's fluid font sizes. The bundled parser (Sabberworm 9.4 and 9.5) silently drops any declaration with a bare parenthesised group inside a math function, such as clamp(1rem, 1rem + ((1vw - 0.2rem) * 0.196), 1.125rem), which is how WordPress writes every fluid font size; on Twenty Twenty-Five the page title fell from 43.8px to 16px. Such values are now hidden from the parser and restored byte for byte, and a stylesheet whose round trip loses any declaration is left untouched rather than pruned. Builds made before 1.2.0 are not reused after updating.
A price or stock change saved through the store's own tools purges the product, its shop page, and its categories immediately, at the origin and at the edge. Only that purge fires after the new price is written; it used to be queued, so a WooCommerce price change reached visitors only after the next queue run, and Cloudflare could re-store the old price in between. Listings found through recorded dependencies stay queued, since bulk stock syncs touch thousands of products.
Deactivation deletes this site's managed Cache Rule, leaving every other rule, and purges this site's hostnames, best effort and without blocking deactivation. After reactivation the Cloudflare tab says the rule is gone until the next sync. wp gt-performance cloudflare disconnect [--forget] and a Disconnect button do the same and turn the integration off; --forget also deletes the credentials and Zone ID.
Sites that share a Cloudflare zone (example.com and shop.example.com on separate installs) no longer take over each other's cache rule. Every site used one fixed rule ref, and refs are unique per zone, so a second site's sync overwrote the first site's rule and its deactivation deleted it. New rules get a ref per hostname; a rule under the old shared ref still belongs to the site whose host its expression names and keeps that ref when updated, since Cloudflare refuses to change a ref. Conflict detection no longer mistakes a subdomain's rule for this host's.
A full edge purge (a cache-relevant settings save, disconnect, deactivation, cloudflare purge without --page-url) purges this site's hostnames instead of sending purge_everything, which also emptied Cloudflare's cache for every other site and subdomain in the zone. Purge by hostname is available on every plan.
Deactivation also empties the local page store. Nothing purges while the plugin is off, so a page edited in the meantime came back from the store as a HIT on reactivation.
Every sync, including the one Setup runs, purges this site's hostnames after writing the rule. A request that reached Cloudflare in the seconds before a just-deleted rule stopped applying could store the page WordPress sent without the plugin, and recreating the rule served that copy. Callers report a failed purge.
The ruleset backup written on every sync was never read, and restoring it would undo the site owner's later rule changes, so it is no longer written. Uninstall still removes the old option.
The connection check adds two stages that warn rather than fail: whether the site host's DNS records are proxied (falling back to the site's own CF-Ray header when the token cannot read DNS), and whether APO is on. The summary says when a stage needs attention.
WPML, Polylang, TranslatePress, Weglot, WooCommerce Multilingual & Multicurrency, CURCY, FOX (WOOCS), Aelia Currency Switcher, and Price Based on Country are detected. Integrations flags each active one with what to set, and the health report warns while any is active. Nothing is changed automatically.
The health report and cron checks are translatable, CronHealth leaves the server path out of exported reports through a flag instead of string replacement, and languages/gt-performance.pot ships with the plugin.
Upgraded the site-local Support Agent role to cover the full Core Support interface, including Diagnostics and the email triage lab, using dedicated plugin capabilities. It does not grant WordPress administrator permissions.
Read full notes4 changes
Upgraded the site-local Support Agent role to cover the full Core Support interface, including Diagnostics and the email triage lab, using dedicated plugin capabilities. It does not grant WordPress administrator permissions.
Added an idempotent role upgrade, agent login routing, and 22 assertions using a real non-admin WordPress user.
Replaced text-symbol icons with a bundled subset of the owner-provided Tabler SVG collection and applied the previously created plugin mark.
Added guarded operator provisioning for a demo Support Agent account. Passwords are supplied outside the repository and never bundled.