Changelog
Every version of the plugin that traded your WooCommerce data for a FluentCart future.
What shipped, when it shipped, and what changed between one version and the next.
August 2026
v1.5.2
Released 13 August 2026 — GitHub Release
Staging preview: test this release on a staging copy with a current backup. Do not run it on a production shop yet. The guided migration is deliberately available for real-world rehearsal before it receives production approval. Optimism remains a poor backup format.
CartShift now guides a same-site WooCommerce-to-FluentCart migration entirely in WordPress. The new store check, review and migration journey replaces the terminal-shaped obstacle course with one clear browser flow.
The review groups routine decisions into bulk actions and reserves individual choices for genuine conflicts. It shows the customer, products, order details and existing FluentCart record together, so “Order 9101” is no longer expected to explain itself. Exact matches can be reused, safe records can be created, and incompatible or unwanted records can stay in WooCommerce without leaving broken dependent orders behind.
Existing FluentCart records are protected by evidence-bound mapping and target fingerprints. CartShift will not quietly overwrite or duplicate them. Guest customers, historical commerce data, skipped records and WooCommerce features FluentCart cannot reproduce are shown in plain-English reports instead of being filed under “probably fine”.
WooCommerce variations that share parent stock are migrated unavailable with their original stock evidence retained. The report explains the manual stock setup required rather than multiplying one shared quantity across every variation, which would be an exciting way to sell inventory that does not exist.
This release also adds durable guided progress, stale-review renewal, subscription cutover recovery and receipt-owned rollback protection. Automated coverage is broad; production approval still waits for successful staging rehearsals on varied shops. That is why GitHub marks 1.5.2 as a pre-release.
v1.5.0
Released 10 August 2026 — GitHub Release
CartShift can now move a complete WooCommerce store to FluentCart — products, variations, categories, media, downloads, customers, orders, refunds, discounts, taxes, payment history and subscriptions — while preserving their relationships and exact amounts.
A read-only audit catches missing or ambiguous data before anything is written. Transfers between separate sites use a sealed package, explicit mapping decisions and a staged cutover, so subscription renewals do not switch owners on optimism alone.
Repeat runs do not create duplicates, existing FluentCart data is protected by ownership checks, and rollback removes only CartShift-owned records while restoring the source subscription settings. The full workflow was rehearsed on empty and populated destinations, including an exact rollback. Apparently, “100% complete” is not an accounting method.
v1.4.1
Released 9 August 2026 — GitHub Release
Three fixes to the mapping feature that shipped hours earlier, all found by review rather than by anyone's store breaking. Worth taking if you are on 1.4.0.
- Mappings now respect the run's scope. If you mapped your whole catalogue and then ran a partial migration, promotion still touched every mapped product — adding variants to FluentCart products the run was never going to migrate. It now skips them and says so.
- SKUs no longer need the mbstring extension. Any non-empty SKU could fatal on a host without it. The fallback is character-safe, so a Polish or accented SKU is not sliced in half.
- Variants pair by the order you see. The fallback that matches variations by position was using creation order, not FluentCart's display order. If you had ever reordered your variants, history could land on the wrong one.
v1.4.0
Released 9 August 2026 — GitHub Release
CartShift used to assume FluentCart was empty. If you had already rebuilt your catalogue by hand — properly, with the pricing model FluentCart actually supports — it cheerfully built you a second one and attached eight years of order history to the copy.
Now you can tell it which product is which.
Product mapping
A new step in the wizard, between choosing what to migrate and running it. Every WooCommerce product gets a row: link it to the FluentCart product you already made, let CartShift create it, or skip it entirely.
The matcher suggests candidates and sorts them into confidence bands — same SKU or same name and price lands in Strong, a similar name in Likely, anything it is not sure about goes to No candidate rather than offering you a bad guess. Nothing links itself. Every band has a bulk button, so a catalogue of three hundred is not three hundred clicks.
Orders, subscriptions, coupons and downloads all follow the mapping automatically. Rollback only removes what CartShift created, so a product you built by hand survives untouched.
If a WooCommerce variation has no counterpart, CartShift adds one to your product — priced from the source, and flagged so a rollback takes it back out. The row tells you before you commit. A dry run adds nothing at all.
The step is skipped entirely when FluentCart is empty, which is most first migrations.
Accented product names
The matcher compared text byte by byte, so Żółty kabel and Zolty kabel scored as different products and a Polish catalogue matched nothing at all. Names are now folded before comparison, and the confidence thresholds were re-measured against real catalogues rather than guessed.
The same bug sat in variation matching, where it mattered more: unable to pair Biały with Bialy, it fell back to matching by position and could put one variation's sales on another's row.
Fixes found while testing the above
- Every migrated order tried to write a column FluentCart does not have. Harmless to your data, but it failed silently on all of them.
- Database write failures never reached the error count, so a run could report 0 errors, Success while the log filled up. That is how the bug above went unnoticed.
- Rolling back could leave one of your own products advertising a price none of its variants had.
v1.3.1
Released 8 August 2026 — GitHub Release
Fixed the admin layout, which had been quietly overflowing sideways on narrower screens, and rebuilt the bundle that ships with it — the previous release had shipped a stale one, so the fix was in the source and not on your screen.
The rest is housekeeping you will never see: one product-type rule where there had been four copies, one column allow-list where there had been three, and a dead method removed. Four copies of the same rule is three chances for the progress bar to disagree with itself.
v1.3.0
Released 7 August 2026 — GitHub Release
Migration stopped being all-or-nothing.
Choose what moves
Three modes: everything, everything from a date, or a hand-picked set of products and customers. The picker searches by name, SKU or email rather than dumping a fifty-thousand-order catalogue on the page.
And what that costs you
Picking a subset has consequences, and CartShift now states them before you start instead of letting you discover them afterwards. A receipt panel counts what your choice actually drags in — pick a product and the orders containing it come too, unless you say otherwise — and names what gets left behind.
A run that would migrate nothing is refused outright, with the reason, rather than reporting a cheerful zero.
v1.2.2
Released 7 August 2026 — GitHub Release
Dry run started telling the truth.
It had been reporting problems the real run would not have had. Each batch runs in its own request, so by the time a dry run reached your orders it had forgotten the products it validated a moment earlier and declared every reference broken. It now remembers, inside its own sandbox, and still writes nothing to FluentCart.
Also in this release: coupons restricted to particular products now resolve those restrictions correctly instead of quietly widening to your whole shop; preflight warns when a WooCommerce entitlement bridge is active; and unsupported product types are reported with the number of orders that reference them, so "we cannot migrate these four products" comes with the number of orders it affects.
March 2026
v1.1.0
Released 15 March 2026
A complete rewrite. The old codebase was a flat script with no separation of concerns — a god-class controller, static mappers, and enough corrupted JSON to make a database cry. I burned it down and rebuilt it properly. PER-CS 3.0, PHP 8.3, modular architecture, and 182 tests that actually prove things work.
If you ran a migration with v1.0.x, bless your heart. This version fixes every data integrity issue I found — and I found a lot.
Architecture
Rebuilt from scratch following the fchub-memberships module pattern. DI container, feature flags, interface contracts, the works. The old 382-line AdminController is now four focused controllers that delegate to domain services. Mappers are instance classes with constructor injection instead of bags of static methods. Every class is final unless it's designed for inheritance.
The admin UI moved from 770 lines of vanilla JS string concatenation to Vue 3 with Vite. Reactive state, composables, scoped styles, and a build step that outputs 99KB. The kind of frontend you can actually debug without questioning your life choices.
Data integrity fixes (the scary ones)
- Double JSON encoding — nine fields across six mappers called
json_encode()before passing arrays to FluentCart models that already encode internally. Every piece of metadata in every migrated record was corrupted. Fixed everywhere. - Order status mapping —
pendingmapped to a status FluentCart doesn't recognise.cancelledmapped tofailed. Both wrong. Now maps correctly using backed PHP 8.3 enums. - Order type — was
onetime(not a thing in FC). Nowcheckout, matching FC's own migrator. - Guest customer IDs — used
crc32()which collides at ~77k emails and produces negative integers on 64-bit PHP. Now uses the email string directly as the key. - Null foreign keys — if a customer wasn't migrated, the order was created with
customer_id = 0. Now validates all FKs before creating records and skips with a logged warning. - Rollback deleted pre-existing data — if a customer already existed in FC, rollback would delete them. Now tracks
created_by_migrationand only rolls back what the migration actually created. - Zero-decimal currencies — JPY, KRW, and 14 others were multiplied by 100, turning ¥1000 into ¥100,000. Now handled correctly.
- Tax behaviour inverted — inclusive tax was stored as exclusive and vice versa. The trifecta of wrong.
- Unit price from discounted total — items with coupons had incorrect per-unit pricing. Now derives from the pre-discount subtotal.
New data migrated
Products get gallery images, variation thumbnails, download files, weight/dimensions, default variation selection, shipping classes, product visibility (private preserved, hidden mapped), brands, tags (as searchable meta), and FC attribute system integration.
Orders get applied coupons, fee line items as proper FC records, per-item refund tracking, shipping line details, order notes, key meta fields (transaction ID, customer note, phone numbers), invoice numbers (WC-{id}), exchange rates, and partial refund status sync.
Subscriptions get Stripe/PayPal vendor IDs, multi-item warnings, and quarterly/half-yearly billing intervals.
Customers get purchase stats recalculated post-migration: LTV, AOV, purchase count, first/last purchase dates — all matching FC's actual schema including the JSON-by-currency purchase_value format.
Coupons get FC's real condition schema with product/category restrictions and email restrictions.
Migration engine
- Batch processing — each batch processes 50 records then returns immediately. The UI drives batches via REST for real-time progress. No more single-request timeout bombs.
- Action Scheduler — available for WP-CLI background processing. The web UI uses direct REST batches for instant feedback.
- Dry run — actually works now (it was a complete no-op before — the flag travelled through the stack and did nothing). Validates every record without writing to the database. Log entries show exactly what would happen.
- Transaction wrapping — each record wrapped in
START TRANSACTION / COMMIT / ROLLBACK. Partial data on failure is impossible. - Cache management —
wp_cache_flush()every 5 batches to prevent memory exhaustion on large stores. - HPOS compatible — all order queries use the
wc_orderstable, notwp_posts.
Preflight
Eight checks now, up from five: WooCommerce, FluentCart, WC Subscriptions (optional), PHP memory, max execution time, product type breakdown (warns about unsupported types), existing FC data, and migration table existence.
WP-CLI
Five commands: wp cartshift migrate, rollback, status, log, finalize. The migrate command runs synchronously with progress bars per entity. log supports --format=table|json|csv and --status filtering.
Admin UI
Vue 3 + Vite. Preflight checks with status badges, entity selection with auto-dependency resolution, real-time progress bars, expandable migration log with search/filter/load-more, CSV export, dark mode sync with FluentCart's theme.
Rollback improvements
Uses wp_delete_post() for products (not raw SQL — the old way left orphaned meta, terms, and thumbnails). Includes guest customers. Respects the created_by_migration flag. Follows Constants::ROLLBACK_ORDER for dependency-safe deletion.
Post-migration finalization
New POST /cartshift/v1/finalize endpoint recalculates customer purchase stats (LTV, AOV, purchase count, dates) and clears caches. Available via the admin UI button and wp cartshift finalize.
v1.0.3
Released 6 March 2026 — GitHub Release
Fixed a fatal error when multiple FCHub plugins are active at the same time. The shared GitHubUpdater class used a class_exists guard that PHP's OPcache cheerfully ignored during early class binding — so the second plugin to load would redeclare the class and take the site down. Wrapped the class inside the conditional so OPcache actually respects it.
v1.0.2
Released 3 March 2026 — GitHub Release
Raised the floor. PHP 8.1 and WordPress 6.4 are now the documented minimums. No functional changes — if it worked before, it still works. If you were running PHP 7.4, now you have a nudge.
Requirements bump
- Minimum PHP raised from 7.4 to 8.1
- Minimum WordPress raised from 6.0 to 6.4
v1.0.1
Released 3 March 2026 — GitHub Release
Version bump only. The first release under the monorepo slash-tag convention (cartshift/v*). No code changed. v1.0.0 shipped under the old wc-fc-v1.0.0 tag format; this corrects that.
v1.0.0
Released 2 March 2026 — GitHub Release
The initial release. A complete one-time migration tool for moving WooCommerce data into FluentCart — products, customers, orders, subscriptions, and coupons. The kind of thing you only run once, but had better run correctly.
One-time tool
CartShift is designed for a single migration run. Once you have verified your data in FluentCart, deactivate and delete the plugin. It has no ongoing function after migration is complete.
Migration suite
Five entity types, migrated in dependency order regardless of what you ask for:
| Entity | What moves across |
|---|---|
| Products | Simple and variable products, categories, variations, featured images, SKUs, stock settings, fulfillment type |
| Customers | Registered customers and guest emails extracted from orders, with billing and shipping addresses |
| Coupons | Discount codes, types (percentage/fixed), amounts, expiry dates, usage limits, conditions |
| Orders | Order records, line items, addresses, payment transactions, refund transactions, status mapping |
| Subscriptions | Billing intervals, trial periods, signup fees, renewal dates, status mapping — requires WC Subscriptions |
Grouped and external products are skipped. Subscription migration is silently skipped if WC Subscriptions is not active.
Preflight checks
Run before touching any data. Five checks:
- WooCommerce active — hard requirement, blocks migration if missing
- FluentCart active — hard requirement, blocks migration if missing
- WC Subscriptions — informational, determines whether subscription migration is available
- PHP memory — warns below 256 MB, does not block
- Existing FluentCart data — warns if FluentCart already contains records, does not block
The ready flag in the preflight response is true only when both required checks pass.
Dry run mode
Pass "dry_run": true to the migrate endpoint and every record is validated and logged without writing anything to FluentCart. Use it to find errors before committing. The migration log stays intact after dry runs so you can review what would have happened.
Batch processing
All entity types process in batches of 50 records. Peak memory usage stays predictable regardless of store size. A store with 10,000 orders runs in 200 batches.
ID mapping
Every successfully migrated record is tracked in wp_cartshift_id_map — a permanent mapping between WooCommerce IDs and FluentCart IDs. Orders use this to look up the correct customer and product IDs. Rollback uses it to find and delete exactly the right records.
Migration log
Every processed record (success, skip, or error) writes to wp_cartshift_migration_log. Queryable via REST API with pagination. Survives rollback so you can audit what happened.
Rollback
Changed your mind? The rollback endpoint deletes all FluentCart records created by the migration — in reverse dependency order — using the ID map. Pre-existing FluentCart data is untouched. The migration log is preserved. After rollback, the ID map is cleared and you can start again from scratch.
Status and type mapping
Both order statuses and subscription statuses are translated to their FluentCart equivalents. Order types are inferred from their contents: regular orders become onetime, orders with subscription products become subscription, WC renewal orders become renewal.
HPOS support
Customer counting and guest email extraction work with both HPOS (High-Performance Order Storage) and legacy post-based order storage.
Deduplication
- Customers with the same email already in FluentCart are linked rather than duplicated
- Coupons with the same code are skipped with the mapping stored
- Duplicate product SKUs get a
-wc{id}suffix to stay unique - Product categories matched by slug are reused, not duplicated