Releases: ackm04/tack-ecommerce-extensions
Release list
v1.6.0 — Recovered fixes that never reached the published extensions
This release exists because the extensions were maintained in two repositories and drifted. Some fixes were made in the TackQuote monorepo and never republished, so they were missing from the plugins merchants actually installed. Those are now recovered, and the duplication is being removed so it cannot happen again.
| platform | version | download |
|---|---|---|
| WooCommerce | 1.5.0 | tackquote.zip |
| Magento 2 | 1.4.0 | tack-magento2.zip |
| Shopware 6 | 0.3.0 | tack-shopware.zip |
| PrestaShop | 1.3.1 | tack-prestashop.zip |
| OpenCart | 1.3.1 | tack.ocmod.zip |
What was actually missing from your installed plugin
WooCommerce — order sync was sending a fraction of the order. The published plugin shipped a 270-line order sync against a 626-line one. Purchase-order numbers were not sent at all: if your store collects a PO number at checkout, it never reached TackQuote. Both recovered.
Magento — two fixes you have been running without. Buyer personal data was written into var/log on every API error. And a TackQuote call with a 20-second budget ran on every storefront page render rather than being cached — the fix adds a 15-minute cache and separates read and write timeouts.
Shopware — the API key field did nothing. The settings screen asked you to paste a TackQuote API key, and the plugin never read it. The method that consumes it existed in the monorepo and had never been published. If you configured a key and wondered why nothing used it, that is why.
OpenCart — the README told you to install the wrong file. It pointed at a source archive and asked you to build the installer yourself. OpenCart derives an extension's internal code from the zip filename, so following those instructions produced an extension that installs cleanly and then 404s every route. Both READMEs now point at /releases/latest/, so they cannot go stale again.
Fixes to the quote-only mode released in v1.5.0
Quote-only mode itself works, but its tests could not tell a wired guard from an unwired one. On WooCommerce and Shopware the whole suite stayed green with the enforcement disconnected — a store in that state hides the buy button while the API keeps accepting orders. That gap is closed on both.
On Magento, one merge in this release would have silently disabled all three quote-only guards on a Marketplace install: the module's class-loading map did not cover the directory the guards live in, and nothing local catches it because Magento resolves those classes anyway on a manual install. Caught and pinned.
Magento's quote-only settings section also had no translations at all, so it fell back to English in every non-English store. Fixed.
Verification
418 automated checks across the five platforms, all passing against the merged result: WooCommerce 47, Magento 173, Shopware 69, PrestaShop 58, OpenCart 71.
Every fix was proved by breaking it and confirming a test fails — 13 mutations on WooCommerce, 21 on Magento, 13 on OpenCart/PrestaShop, 5 on Shopware. Three of those mutations initially survived, each revealing something genuinely untested rather than confirming what we already believed.
Not verified: none of this was exercised against a running storefront, and wp plugin check was not run on the merged WooCommerce result. Test on a staging store before updating a live shop.
After this release
The extension copies in the TackQuote monorepo are being removed. This repository is the single source of truth: WordPress.org publishes from it, and every artifact here is built from it.
What's Changed
- fix(wordpress): reconcile the WooCommerce plugin with the monorepo copy (#340) by @ackm04 in #15
- fix(magento2): reconcile the two copies of the module, losing neither side's work (#340) by @ackm04 in #16
- fix(opencart,prestashop): reconcile against the monorepo copies before they are retired (#340) by @ackm04 in #17
- fix(shopware,squarespace): recover ping(), and prove the quote-only guard is wired (#340) by @ackm04 in #18
- docs: state that this repository is the single source of truth (#340) by @ackm04 in #19
Full Changelog: v1.5.0...v1.6.0
v1.5.0 — Quote-only B2B store mode on all five platforms
Turn any storefront into a B2B catalogue: Add to cart is withdrawn and customers request a quote instead. Now available on all five self-hosted platforms.
| platform | download | version |
|---|---|---|
| WooCommerce | tackquote.zip |
1.4.0 |
| Shopware 6 | tack-shopware.zip |
0.3.0 |
| PrestaShop | tack-prestashop.zip |
1.3.0 |
| OpenCart | tack.ocmod.zip |
1.3.0 |
| Magento 2 | tack-magento2.zip |
1.3.0 |
On every platform you choose who it applies to — every customer, signed-out visitors only (so approved trade customers keep a normal cart), or specific customer groups — and administrators keep a working cart so you can test your own store while it is closed to customers.
It is enforced on the server, not by hiding a button
Hiding "Add to cart" with CSS is not a policy. On each platform the refusal happens in the platform's own cart code, so a hand-typed add-to-cart link, an API call, or a page served from cache is refused exactly like the button is:
- WooCommerce — products become non-purchasable, which
WC_Cart::add_to_cart()checks - Shopware — a decorated
CartItemAddRoutethrows before delegating; one decoration covers the Store API and both storefront controllers - PrestaShop — refused in the first statement of
FrontController::init(), before any controller runs - OpenCart — the route is rewritten before dispatch, so core's cart controller is never constructed
- Magento 2 — a
beforeplugin onQuote::addProduct(), the@apimethod every add path funnels through
Carts that were already full
A cart filled before you switch the mode on is handled everywhere rather than left as a hole — WooCommerce and Shopware block it at checkout, PrestaShop and OpenCart refuse to grow or convert it. In every case the shopper can still empty their cart, so nobody is stranded with a basket they can neither order nor clear.
Read this before switching on
Magento: the REST, SOAP and GraphQL APIs are not covered. POST /rest/V1/guest-carts/{cartId}/items is anonymous, and Luma's own checkout places orders over webapi_rest. Quote-only is enforced for storefront traffic; a store whose API is exposed to untrusted callers is not fully closed by this release alone. Guarding those areas correctly needs work we would not guess at, so it is documented rather than faked.
Shopware Cloud is not covered. Enforcement lives in the plugin; the Shopware App ships no PHP, so a Cloud store running the app is not quote-only even if the plugin config suggests otherwise.
PrestaShop deliberately does not touch the native PS_CATALOG_MODE setting — it applies catalog mode for the current request only. That keeps per-group scoping possible, leaves the merchant's own setting alone, and means uninstalling never strands the shop in catalog mode. Order history and invoices stay reachable for customers who bought while the shop was still selling.
WooCommerce also fixes the broken Settings link
Clicking Settings on the Plugins screen previously failed with "Sorry, you are not allowed to access this page" — for administrators too. It was never a permissions problem: the link pointed at a page slug that two renames had moved. Fixed in 1.3.4 and included here.
If you are upgrading a manually installed WooCommerce 1.3.3, deactivate and delete it first — the folder changed, so WordPress treats this as a separate plugin. Your API key and settings survive.
Verification
342 automated checks across the five platforms, all passing against merged main: WooCommerce 25, PrestaShop 49, OpenCart 67, Shopware 65, Magento 136.
Each platform's guard was independently broken by hand to confirm the tests actually fail when enforcement is removed — a suite that stays green with the control deleted proves nothing.
Not verified: none of this has been exercised against a running storefront. Every platform is covered by unit tests plus reading the vendors' real source (WooCommerce 11.0.1, Shopware 6.6.10.22, PrestaShop 8.2, OpenCart 4.1.0.4, Magento 2.4.8-p5). Smoke-test on a staging store before switching a live shop to quote-only.
What's Changed
- feat(shopware): quote-only (B2B catalog) mode, enforced on the server by @ackm04 in #10
- feat(prestashop): quote-only (B2B catalog) mode, enforced on the server by @ackm04 in #11
- feat(opencart): quote-only (B2B catalog) mode, enforced on the server by @ackm04 in #12
- fix(shopware): bump plugin to 0.3.0 and add a changelog by @ackm04 in #13
- feat(magento2): quote-only (B2B catalog) mode, enforced on the server by @ackm04 in #14
Full Changelog: v1.4.0...v1.5.0
v1.4.0 — WooCommerce 1.4.0: quote-only B2B store mode, and the Settings link fixed
Install
Download tackquote.zip below → WordPress admin → Plugins → Add New → Upload Plugin.
If you have 1.3.3 installed, deactivate and delete it first — 1.3.3 shipped in a tackquote-for-woocommerce/ folder, so WordPress treats this as a separate plugin. Your API key and settings are stored as WordPress options and survive.
Fixed: "Sorry, you are not allowed to access this page"
Clicking Settings on the Plugins screen failed for everyone, including full administrators.
It was never a permissions problem. The Settings link carried a hardcoded admin.php?page=tack-quotes, which was the admin page slug up to 1.3.1. The 1.3.2 and 1.3.3 renames moved the slug — first to tackquote-for-woocommerce, then to the WordPress.org slug tackquote — and left the link pointing at a page that no longer exists.
wp-admin/admin.php renders a page only if its slug is registered, and otherwise calls wp_die() with the same sentence it uses for a genuine capability failure. That collision is what made this look like a permissions bug. The page itself was always correctly registered at manage_options, and it still is — it holds the API key that authenticates your whole store.
The link is now derived from the same constant the menu is registered with, so the two cannot drift apart again.
New: quote-only (B2B catalog) store mode
A single Store mode setting turns your whole storefront into a B2B catalogue. "Add to cart" is withdrawn and customers request a quote instead — your products, categories and search keep working, only checkout goes away.
- Applies to — every customer, or signed-out visitors only (so approved trade customers keep a normal cart), or specific roles
- Prices — optionally replaced with "Price on request"
- You are not locked out — anyone who can manage WooCommerce still sees a working cart, so you can test your store while it is closed to customers. Switching back restores checkout immediately.
It is enforced on the server, not by hiding a button: products become non-purchasable, so a hand-typed ?add-to-cart= link, the Store API and cached pages are all refused the same way the button is.
Two details worth knowing:
- Carts filled before you switch are emptied on the cart and checkout pages with an explanation. WooCommerce's own cart validation checks only that a product still exists, not that it can be bought, so without this an older cart could still be checked out and the store would not really be quote-only.
- Quote buttons now mount outside the add-to-cart form. They previously rendered inside it, so withdrawing the cart button would have removed the quote button too and left a normal-looking product page with no way to transact at all.
Other platforms
The Magento 2, OpenCart, PrestaShop, Shopware, Zen Cart, Wix and Squarespace artifacts are unchanged from v1.3.0 and are re-attached here so the latest release remains complete. Quote-only mode is being brought to the other platforms next.
What's Changed
- fix(wordpress): Settings link led to "not allowed to access this page" by @ackm04 in #7
- feat(wordpress): quote-only (B2B catalog) store mode by @ackm04 in #9
Full Changelog: v1.3.0...v1.4.0
v1.3.0 — WooCommerce 1.3.3 renamed to `tackquote` for WordPress.org
Ten artifacts, all built by scripts/package-all.sh from this commit.
WooCommerce is the headline: tackquote.zip is the WordPress.org submission
artifact, and the plugin has been renamed to its assigned directory slug.
WooCommerce — plugin 1.3.3, renamed to tackquote
WordPress.org pended our submission. The assigned slug is tackquote, and the
rule is that the text domain must equal the slug. The plugin now uses tackquote
throughout — 127 i18n literals, the Text Domain: header, the directory, the main
file, PLUGIN_SLUG and the packaged zip name.
If you installed 1.3.2 manually, delete it by hand before installing this. The
folder changed from tackquote-for-woocommerce/ to tackquote/, so WordPress sees
this as a separate plugin and you would end up with both active.
readme.txt now carries a full == External services == section — what TackQuote
is, that the plugin cannot work without it, that nothing is sent until an API key
is entered, then every endpoint with its payload and trigger, then the Terms and
Privacy links. The order-sync entry is written from this build's actual
build_payload(): eleven fields, no billing or shipping street addresses, and no
card or gateway data.
The stale github.com/tackquote/… link that returned 404 is gone.
Downloads
| Platform | File | Notes |
|---|---|---|
| WooCommerce | tackquote.zip |
Plugins → Add New → Upload. Root is tackquote/ |
| Shopware Cloud / 6.6+ (App) | tack-shopware-app.zip |
Needs <setup><secret> injected — see the app README |
| Shopware self-hosted (plugin) | tack-shopware.zip |
Extract to custom/plugins/TackQuote |
| OpenCart 4.x | tack.ocmod.zip |
Do not rename this file — see below |
| OpenCart (source only) | tack-opencart-source.zip |
Not installable; reading copy |
| PrestaShop | tack-prestashop.zip |
Module Manager → Upload a module |
| Magento 2.4 | tack-magento2.zip |
unzip tack-magento2.zip -d <root>/app/code |
| Zen Cart | tack-zencart.zip |
Copy the contents of store-root/ only |
| Squarespace / Wix | tack-squarespace.zip, tack-wix.zip |
Code snippets |
OpenCart: the filename is load-bearing
OpenCart derives the extension code from the zip filename, and every namespace
and event action in the package hard-codes tack. A zip under any other name
installs successfully and then returns 404 on every route, with nothing in the
error log.
Zen Cart: copy the contents, not the folder
Copy the contents of store-root/ into your store root. Leave zc_install/
(the SQL) and the README on your own machine.
Every archive's root is now verified
scripts/addon-archive-layout.spec.mjs asserts each archive's top-level entry
against the vendor's own rule, and fails with that rule rather than just a
mismatch. It also asserts no add-on ships apps/api, apps/web,
packages/database or .env.
That gate exists because three archives were previously built with an extra
wrapper directory and could not install at all — most seriously Magento, whose
published v1.1.0 asset had a magento2/ root instead of Vendor/Module/, so
setup:upgrade could never discover it.
Verification
php -l clean on every shipped PHP file (8.2, plus 7.4 where a plugin declares
that floor). Shopware manifest validated against manifest-3.0.xsd with
name == directory. tackquote.zip confirmed to contain no bin/, tests/,
.github or *.md, with Text Domain: tackquote and Stable tag: 1.3.3 read
back out of the built archive rather than the source tree.
GitHub Actions is billing-blocked on this account, so these were built locally with
the same script the release workflow invokes.
What's Changed
- Redesign GitHub Pages extension showcase by @ackm04 in #3
- Refine hero banner by @ackm04 in #4
- Mark all platform integrations as verified by @ackm04 in #5
- fix(wporg): adopt the assigned slug
tackquote, disclose the external service by @ackm04 in #6
Full Changelog: v1.2.0...v1.3.0
v1.2.0 — Storefront Extensions: reproducible builds, Shopware Cloud app, install-blocking fixes
Ten installable artifacts, all rebuilt from the current source by
scripts/package-all.sh.
If you tried to install from v1.1.0, that is why it did not work. No release
asset on this repo was ever built by CI — the release workflow sat in a
subdirectory where GitHub never reads it, so every zip was uploaded by hand and
they had drifted from the source.
Read this first
| Platform | Download | Notes |
|---|---|---|
| Shopware Cloud / 6.6+ (App) | tack-shopware-app.zip |
New — never shipped in a release before. Upload under Extensions → My Extensions → Upload. |
| Shopware self-hosted (plugin) | tack-shopware.zip |
Extract to custom/plugins/TackQuote |
| WooCommerce | tackquote-for-woocommerce.zip |
Plugins → Add New → Upload |
| OpenCart 4.x | tack.ocmod.zip |
Do not rename this file. See below. |
| OpenCart (source only) | tack-opencart-source.zip |
Not installable — reading copy |
| PrestaShop | tack-prestashop.zip |
Module Manager → Upload a module |
| Magento 2.4 | tack-magento2.zip |
unzip tack-magento2.zip -d <root>/app/code |
| Zen Cart | tack-zencart.zip |
Copy the contents of store-root/ only |
| Squarespace / Wix | tack-squarespace.zip, tack-wix.zip |
Code snippets |
OpenCart: the filename is load-bearing
OpenCart derives the extension code from the zip filename, and every
namespace and event action in this package hard-codes tack. A zip under any
other name installs successfully and then returns 404 on every route, with
nothing in the error log. Keep it tack.ocmod.zip.
Zen Cart: copy the contents, not the folder
The archive separates what goes on the server from what must not. Copy the
contents of store-root/ into your store root. Leave zc_install/ (the SQL)
and the README on your own machine — the previous README told you to copy them
in, which published install.sql under your web root.
Fixed in this release
- Magento's v1.1.0 asset was never installable. Its top-level directory was
magento2/instead ofVendor/Module/, so Magento could never discover the
module. It also contained eight files that exist nowhere in this repository. - PrestaShop merchants were never offered the v1.1.0 upgrade. The module
declared version1.0.0at every tag, and PrestaShop keys upgrades off that
value. - PrestaShop's "no API key set" warning could never appear.
config.xmlsaid
need_instance=0while the class said1, so the module installed, reported
itself active, rendered no button, and explained nothing. - PrestaShop advertised order sync that does not exist. Claim corrected.
- Zen Cart README no longer instructs you to publish the SQL under your web root.
- WooCommerce packaging no longer risks shipping tests and dev config.
- Versions bumped where they had never been bumped at all.
Known gaps (documented, not fixed)
- Zen Cart
install.sqlis not idempotent. A second run creates a duplicate
empty config group, then fails on a duplicate key. The README has the cleanup. - Zen Cart quote button on a custom template. The template file hardcodes
template_defaultasset paths, so on a custom template the CSS/JS 404 and the
button does nothing. The README documents the two manual edits. - Magento credential cache. After an admin edits API credentials they stay
cached for up to 15 minutes; the observer that flushed them was one of the
eight files that only ever existed in the old published asset. - Magento license metadata declares GPL-2.0-or-later while the repo LICENSE
is MIT. Unresolved deliberately.
How these were verified
php -l on every shipped PHP file (8.3, plus 7.4 where a plugin declares that
floor); the Shopware manifest validated against manifest-3.0.xsd with
name==directory (that name is concatenated into the registration proof HMAC, so
a mismatch breaks registration silently); Zen Cart SQL executed against MySQL 8
on the authentic v1.5.8a schema; OpenCart's 29 in-repo tests passing; secret
scans clean on all ten artifacts. Every layout rule came from the vendor's own
documentation, not from a sibling directory.
GitHub Actions is billing-blocked on this account, so these were built locally
with the same script the workflow invokes.
What's Changed
Full Changelog: v1.1.0...v1.2.0
v1.1.0 — Storefront Extensions: security fixes, WooCommerce 1.3.1, OpenCart 1.2.0
First refresh of the release assets since 2026-08-01. Every archive here is rebuilt from
current main; the v1.0.0 assets were three weeks stale and predate all of the security work
below.
New in this release: tack.ocmod.zip — the OpenCart merchant installer, which was never
published before. Previously you had to build it yourself from the source archive. It must
keep that exact filename: OpenCart derives the extension code from the zip filename, nothing
inside the package pins it, and a renamed archive installs cleanly and then 404s on every route
with no error.
Package versions
| Package | Version | Notes |
|---|---|---|
tack-woocommerce.zip |
1.3.1 | Verified on WordPress 7.1 + WooCommerce 11.0.1 |
tack.ocmod.zip / tack-opencart.zip |
1.2.0 | Verified on OpenCart 4.1.0.4 |
tack-prestashop.zip |
1.0.0 | unchanged |
tack-magento2.zip, tack-shopware.zip, tack-zencart.zip, tack-wix.zip, tack-squarespace.zip |
— | rebuilt, no source changes |
WooCommerce — security and WordPress.org compliance
- Storefront/admin XSS closed. The quote modal escaped only labels and placeholders while
interpolatingidandnameraw from server-suppliedrequiredCompanyFields. Because the API
base URL is a setting a shop manager can edit, this was a path to script execution in an
administrator's browser. Proven fixed by running the shipped function against
x" autofocus onfocus=…before and after. - The API key is no longer written into the settings page HTML. A masked value was computed
and then discarded; the field emitted the real key, andtype="password"hid it from the eye
only, not from page source. - The settings page can now actually be saved. It was registered under
manage_woocommerce
while posting tooptions.php, which requiresmanage_options— so the one role the page was
built for could never save it. - Order sync no longer sits inside checkout. It was a synchronous 20-second HTTP POST inside
three checkout hooks, whilereadme.txtpromised it "never blocks checkout". It is now handed
to Action Scheduler, and that promise is true: a status transition completes in ~350 ms and
enqueues exactly one background job — one, not two, even though both the creation and the
transition hook fire. - Privacy disclosure added naming the exact fields and destination endpoint, and order sync
now ships off by default. phpcs --standard=WordPressandwp plugin checkboth run clean.
OpenCart
- Admin XSS closed. The test-connection result was written with
innerHTMLfrom a remote
response whose host is a merchant-editable setting. test()now checks permissions. Against the previous code, an administrator with no rights
on this extension could complete a live outbound call using the store's API key.- Silent save failures fixed. The controller wrote one error key and the template read a
different one, so a permission denial changed nothing and said nothing. Save now answers the
AJAX contract the form actually declares. - Adds the multi-product quote cart: storefront view event, drawer and controls templates, and
the accompanying JS/CSS.
Verification
Both refreshed packages were installed and exercised on real stores rather than reasoned about.
Every archive was also checked to contain no .DS_Store, no .phpunit.cache, no node_modules,
no store-listing assets, and no secret-shaped strings — a previous release shipped test-result
caches and listing screenshots that exposed part of a development API key.
Known limitation
Buyer first/last name supplied on OpenCart and PrestaShop quote forms is not yet stored as
structured buyer identity — the buyer record's name is currently derived from the email address.
A fix is in progress and will land in a follow-up point release. WooCommerce and Magento are
unaffected and store the name as typed.
v1.0.0 - Storefront Extensions Release
⚠️ Superseded — do not download from this releaseUse v1.1.0 instead.
The archives attached below were built on 2026-08-01 and predate every security
fix since, including:
- a storefront XSS in the WooCommerce plugin's quote modal
- the WooCommerce API key being printed into the settings page HTML
- an admin XSS in the OpenCart extension's test-connection result
- OpenCart's
test()action having no permission check, so any administrator
could spend the store's API key- WooCommerce order sync running a synchronous 20-second HTTP POST inside
checkout, while the readme promised it never blocked checkoutThey are left attached only so existing links do not 404. Nothing here should be
installed on a live store.
Initial public release of Tack B2B eCommerce extensions for WooCommerce, Magento 2, OpenCart, PrestaShop, Shopware, ZenCart, Squarespace, and Wix.