From afd71e192a5b3e2b29588f384b7273cef3a88c6f Mon Sep 17 00:00:00 2001 From: Jasper Frumau Date: Mon, 5 Oct 2026 10:08:26 +0700 Subject: [PATCH 1/4] Add Free Store Checkup Button To WooCommerce CTA Sends visitors and internal link value from WooCommerce posts to /woocommerce-checkup/, which stored only 9 scans in 90 days. Appended last because contentOnly re-syncs placed instances to the template by position; mid-list it would duplicate the services link in existing posts. --- resources/js/blocks/cta/block.json | 2 +- resources/js/blocks/cta/templates.js | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/resources/js/blocks/cta/block.json b/resources/js/blocks/cta/block.json index 617fe7f..61afd4f 100644 --- a/resources/js/blocks/cta/block.json +++ b/resources/js/blocks/cta/block.json @@ -2,7 +2,7 @@ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 3, "name": "imagewize/cta", - "version": "1.0.0", + "version": "1.1.0", "title": "CTA", "category": "nynaeve/cta", "icon": "megaphone", diff --git a/resources/js/blocks/cta/templates.js b/resources/js/blocks/cta/templates.js index 7f1a9f2..a224d21 100644 --- a/resources/js/blocks/cta/templates.js +++ b/resources/js/blocks/cta/templates.js @@ -14,7 +14,7 @@ /** * Build an InnerBlocks template from a variant's copy. * - * The first button is the filled call, the second the outline one. Variants + * The first button is the filled call, every later one outline. Variants * that lead with a different call (performance-partnership) express that by * ordering `buttons`, not by changing the structure. */ @@ -155,6 +155,10 @@ export const VARIANTS = { buttons: [ ['Get a Quote', '/contact/?service=woocommerce'], ['View WooCommerce Services', '/services/woocommerce/'], + // Must stay last: contentOnly re-syncs placed instances to this + // template by position, so a button inserted mid-list would shift + // existing ones and duplicate the services link on open. + ['Run the Free Store Checkup', '/woocommerce-checkup/'], ], }), }, From a701758ade173e8e2a06b5105c5dfba6568539a9 Mon Sep 17 00:00:00 2001 From: Jasper Frumau Date: Mon, 5 Oct 2026 10:08:26 +0700 Subject: [PATCH 2/4] Add Sentinel Block Fixture Testing Adds @imwz/wp-pattern-sentinel as a dev dependency with npm run test:patterns, and a fixture of the WooCommerce CTA as stored in post_content. The .html fixture needs Sentinel 1.2.0 (imagewize/wp-pattern-sentinel#24). --- package-lock.json | 115 ++++++++++++++++++++++++++++ package.json | 4 +- tests/sentinel/cta-woocommerce.html | 48 ++++++++++++ 3 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 tests/sentinel/cta-woocommerce.html diff --git a/package-lock.json b/package-lock.json index 306d1e8..4009376 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "classnames": "^2.5.1" }, "devDependencies": { + "@imwz/wp-pattern-sentinel": "^1.1.5", "@roots/vite-plugin": "^2.0.2", "@tailwindcss/vite": "^4.0.9", "@wordpress/icons": "^10.9.0", @@ -30,6 +31,24 @@ "node": ">=6.9.0" } }, + "node_modules/@imwz/wp-pattern-sentinel": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@imwz/wp-pattern-sentinel/-/wp-pattern-sentinel-1.1.5.tgz", + "integrity": "sha512-0YCveCoqH6+rpb5UqyqmHGhDZWRTU+f6NsaNRJk4CBOWoY/ENvesGEFETgLp1xAGnoezH2/zMvIwF17Kv6dxOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-yaml": "^4.3.1", + "p-queue": "^8.0.1", + "playwright": "^1.44.0" + }, + "bin": { + "sentinel": "bin/sentinel.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -1142,6 +1161,13 @@ "ajv": "^8.8.2" } }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, "node_modules/baseline-browser-mapping": { "version": "2.11.20", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.20.tgz", @@ -1381,6 +1407,13 @@ "node": ">=6" } }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true, + "license": "MIT" + }, "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", @@ -1523,6 +1556,29 @@ "dev": true, "license": "MIT" }, + "node_modules/js-yaml": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -2001,6 +2057,36 @@ "node": ">=18" } }, + "node_modules/p-queue": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-8.1.1.tgz", + "integrity": "sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventemitter3": "^5.0.1", + "p-timeout": "^6.1.2" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.4.tgz", + "integrity": "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/param-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", @@ -2054,6 +2140,35 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/playwright": { + "version": "1.63.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.63.0.tgz", + "integrity": "sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.63.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/playwright-core": { + "version": "1.63.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.63.0.tgz", + "integrity": "sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/postcss": { "version": "8.5.26", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", diff --git a/package.json b/package.json index c98811c..006068e 100644 --- a/package.json +++ b/package.json @@ -13,9 +13,11 @@ "translate:update": "for file in ./resources/lang/*.po; do wp i18n update-po ./resources/lang/nynaeve.pot $file; done", "translate:compile": "npm run translate:mo && npm run translate:js", "translate:js": "wp i18n make-json ./resources/lang --pretty-print", - "translate:mo": "wp i18n make-mo ./resources/lang ./resources/lang" + "translate:mo": "wp i18n make-mo ./resources/lang ./resources/lang", + "test:patterns": "sentinel --trellis --trellis-dir=../imagewize.com/trellis --site=imagewize.com tests/sentinel/" }, "devDependencies": { + "@imwz/wp-pattern-sentinel": "^1.1.5", "@roots/vite-plugin": "^2.0.2", "@tailwindcss/vite": "^4.0.9", "@wordpress/icons": "^10.9.0", diff --git a/tests/sentinel/cta-woocommerce.html b/tests/sentinel/cta-woocommerce.html new file mode 100644 index 0000000..f207ee2 --- /dev/null +++ b/tests/sentinel/cta-woocommerce.html @@ -0,0 +1,48 @@ + + +
+ + + + +
+

Need a WooCommerce Developer for Your Store?

+ + + +

We build and optimize WooCommerce stores for SMEs — from custom checkout flows and payment integrations to performance tuning and ongoing maintenance. Fixed-price quotes available.

+ + + +
    +
  • Custom checkout and cart optimization
  • + + + +
  • Payment gateway integration (Stripe, Mollie, PayPal)
  • + + + +
  • WooCommerce performance and speed optimization
  • + + + +
  • Ongoing store maintenance and support
  • +
+ + + + +
+
+ From 5507ef1506bab3810654f920625b051b70f41e94 Mon Sep 17 00:00:00 2001 From: Jasper Frumau Date: Mon, 5 Oct 2026 10:08:26 +0700 Subject: [PATCH 3/4] Bump Version To 4.1.0 --- CHANGELOG.md | 15 +++++++++++++++ readme.txt | 5 ++++- style.css | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee7ba9a..b29fb33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ All notable changes to the Nynaeve theme will be documented in this file. +## [4.1.0] - 2026-10-05 + +### Added + +- `imagewize/cta` `woocommerce` variant: a third button, **Run the Free Store Checkup**, linking to `/woocommerce-checkup/`. It sends visitors and internal link value from every WooCommerce post to the free checkup tool. The checkup tool had stored only 9 scans in 90 days, 5 of them internal test runs. The button is appended **last** on purpose. The block uses `templateLock: "contentOnly"`, and Gutenberg re-syncs placed instances to the template by position (`use-inner-block-template-sync.js`). Inserted mid-list, the new button would make an existing post show the services link twice when opened in the editor. Placed last, an old post gains the checkup button the next time it is opened and saved. +- The `woocommerce-de` variant is unchanged, because the checkup's on-page report is English only. + +### Technical + +- Added `@imwz/wp-pattern-sentinel` as a dev dependency, plus `npm run test:patterns`. It round-trips the fixtures in `tests/sentinel/` through the local editor (`imagewize.test`, Trellis credentials) and reports block-validation errors or content drift. The first fixture, `cta-woocommerce.html`, is the WooCommerce CTA as serialized in posts. `.html` fixtures need Sentinel 1.2.0 or later. + +### Notes + +- **Existing posts don't change on the frontend** until their stored markup is migrated: a static block's saved HTML is what renders. Append the button to placed `is-variant-woocommerce` instances on production with a scripted update (a database export first). Opening and saving a post in the editor also works, one post at a time. + ## [4.0.1] - 2026-09-03 ### Technical diff --git a/readme.txt b/readme.txt index 55b75a2..9ff5f55 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ Contributors: jasperfrumau Requires at least: 6.6 Tested up to: 6.9 Requires PHP: 8.3 -Stable tag: 4.0.1 +Stable tag: 4.1.0 License: MIT License License URI: https://opensource.org/licenses/MIT @@ -24,6 +24,9 @@ Export the database first and verify each dry-run count before dropping --dry-ru == Changelog == += 4.1.0 - 10/05/26 = +* FEATURE: The WooCommerce CTA variant gains a third button, Run the Free Store Checkup, linking to /woocommerce-checkup/. It is appended last so existing posts re-sync cleanly when opened in the editor. Already-published posts need their stored markup updated to show it on the frontend. + = 4.0.1 - 09/03/26 = * TECHNICAL: npm dependencies updated - tailwindcss and @tailwindcss/vite 4.3.1 to 4.3.3, laravel-vite-plugin 3.1.0 to 3.2.0, vite 8.0.16 to 8.2.2, plus transitive dependency bumps. No code changes. diff --git a/style.css b/style.css index e02cb9d..7c58b3a 100644 --- a/style.css +++ b/style.css @@ -2,7 +2,7 @@ Theme Name: Nynaeve Theme URI: https://imagewize.com Description: Modern WordPress theme built on Sage 11 with reusable custom blocks using WordPress native tools and the Roots.io stack. -Version: 4.0.1 +Version: 4.1.0 Author: Jasper Frumau Author URI: https://magewize.com Text Domain: nynaeve From 76c0315efe3ec73498fc4604f688e2b2d47f9d25 Mon Sep 17 00:00:00 2001 From: Jasper Frumau Date: Mon, 5 Oct 2026 10:21:05 +0700 Subject: [PATCH 4/4] Require Sentinel 1.2.0 For HTML Fixtures Sentinel 1.2.0 is now published. Its folder scan collects .html files, so the cta-woocommerce.html fixture is actually picked up. With ^1.1.5 an existing lock stayed on 1.1.5, which found no files and failed. --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4009376..3b8ca62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "classnames": "^2.5.1" }, "devDependencies": { - "@imwz/wp-pattern-sentinel": "^1.1.5", + "@imwz/wp-pattern-sentinel": "^1.2.0", "@roots/vite-plugin": "^2.0.2", "@tailwindcss/vite": "^4.0.9", "@wordpress/icons": "^10.9.0", @@ -32,9 +32,9 @@ } }, "node_modules/@imwz/wp-pattern-sentinel": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@imwz/wp-pattern-sentinel/-/wp-pattern-sentinel-1.1.5.tgz", - "integrity": "sha512-0YCveCoqH6+rpb5UqyqmHGhDZWRTU+f6NsaNRJk4CBOWoY/ENvesGEFETgLp1xAGnoezH2/zMvIwF17Kv6dxOw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@imwz/wp-pattern-sentinel/-/wp-pattern-sentinel-1.2.0.tgz", + "integrity": "sha512-AlUY68LfhHs/a1RbsC7CsExoG0lAdFi+YrZb+XBfltnWb/pv5nUSXCxcYH7Qd1GgzeJ/WbJVwWaWrdWb+lWf5g==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 006068e..1661b43 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "test:patterns": "sentinel --trellis --trellis-dir=../imagewize.com/trellis --site=imagewize.com tests/sentinel/" }, "devDependencies": { - "@imwz/wp-pattern-sentinel": "^1.1.5", + "@imwz/wp-pattern-sentinel": "^1.2.0", "@roots/vite-plugin": "^2.0.2", "@tailwindcss/vite": "^4.0.9", "@wordpress/icons": "^10.9.0",