Migrate from WooCommerce Product Add-Ons
POM Tweaks can copy an existing catalog from the official WooCommerce Product Add-Ons extension into POM Product Add-Ons. The migration preserves the source configuration, converts repeated option labels into shared Reusable Choices, verifies every imported record before enabling the tweak, and can restore the POM data that existed before the migration.
This guide is for store administrators with WP-CLI access. Plan the final storefront switch during a maintenance window so customers never see two add-on systems or an untested configuration.
Before you begin
- Back up the selected site's database, POM Tweaks settings, existing Product Add-Ons uploads, and configured private file storage from one consistent recovery point.
- Keep WooCommerce and POM Tweaks active.
- Keep the official extension installed until migration and storefront verification are complete. Its data can be migrated whether the extension is active or inactive.
- Finish pending edits in the official extension before starting.
- Run every command for exactly one site. On multisite, use
--url=<site-url>or one explicit--blog_id=<id>; the command never traverses the network. - Run WP-CLI in the site's PHP environment with a filesystem user that can read existing POM Tweaks settings and write the activation file. Access granted to the web server does not automatically apply to a command run on the host.
What is copied
The migration copies:
- published and draft global groups, including groups with no fields yet;
- assignments to all products or exact product categories;
- product- and variation-level fields;
- the product setting that excludes global groups;
- field order, required state, headings, descriptions, placeholders, restrictions, defaults, and file-type limits;
- flat, quantity-based, and percentage-based prices;
- WooCommerce Bookings person and block multipliers, including the legacy Accommodation Bookings night multiplier;
- option labels, images, prices, visibility, and default selections.
Options with the same label, ignoring letter case and repeated whitespace, become one Reusable Choice, even when they occur in different fields or groups. Each use retains its own price, image, visibility, order, and default state. After cutover, disabling that Reusable Choice disables or hides every linked use according to its POM availability setting.
The migration does not change or remove the official extension's groups, product fields, or historical order data. A source group assigned to a category remains limited to that exact category; child-category behavior is not added during conversion.
Historical uploaded files are not bulk-moved by the configuration command. After storefront cutover, an authorized cart or order view copies a recognized local legacy upload into private storage and registers its order relationship without rewriting the historical customer-facing metadata. Keep the source uploads during the rollback window. On Nginx or another server that does not honor directory deny files, have the host block direct web access to the legacy upload locations before serving historical orders through POM.
Run the preflight
From the WordPress installation directory, run:
wp pomtweaks product-add-ons migrate --url=https://example.test --dry-run
The result reports the number of groups, product configurations, fields, option uses, and unique Reusable Choices. A dry run does not create posts, update products, change options, or enable the tweak.
For an eligible import, the dry run also checks access to the activation settings before any records are changed. An access error identifies the configured file, its resolved existing filesystem path, and the CLI effective user ID when available. Symbolic links and shared mounts can expose the same storage under different paths; use the framework's configured settings tree rather than creating a second copy at another location. A successful preflight does not prevent permissions or storage availability from changing during the import.
The preflight stops before any write when it finds either of these conditions:
- A custom source field type has no POM Product Add-Ons equivalent. Replace or remove that field in the official extension, then run the preflight again.
- A source product already has any POM-owned local definition, group exclusion, global exclusion, or translation override. Review those product IDs before deciding which version should win.
If the official data should replace existing POM local definitions, repeat the real migration with --overwrite-existing. POM Tweaks stores the previous POM values so cleanup can restore them.
Migrate one site
After a clean preflight, run:
wp pomtweaks product-add-ons migrate --url=https://example.test
For an explicit multisite blog ID, use:
wp pomtweaks product-add-ons migrate --blog_id=13
The command imports the records, reads every published POM record back, and compares it with the current official source. It enables Product Add-Ons under Settings → POM Tweaks → E-Commerce → Products only after definitions, scopes, product exclusions, Reusable Choices, compatibility IDs, and system ownership all match. Re-running a completed migration verifies the retained import again. Use --force only when source records were added or received non-identity edits such as a price or description change and the already imported POM records should be refreshed; this replaces edits made directly to those imported POM records.
Run the read-only cutover gate after migration:
wp pomtweaks product-add-ons verify --url=https://example.test
The command exits successfully only when all eligible official records still match their published POM records and the Product Add-Ons tweak is enabled for this site. A JSON report is available with --format=json. A mismatch, missing migration state, stale imported record, or disabled tweak returns a non-zero exit status, so the command can safely stop a deployment script before the official extension is deactivated.
If source groups or fields were deleted after a completed migration, use cleanup followed by a fresh migration instead of --force. That sequence also removes imported records that no longer have a source counterpart.
Review before storefront cutover
While the official extension remains active, the POM storefront and pricing handlers stay dormant to prevent duplicate fields and charges. You can still review the imported administration records.
- Open Products → Product Add-Ons.
- Compare each imported global group with its official source group.
- Open Reusable Choices and confirm that repeated labels were intentionally linked.
- Review any labels that look similar but represent different concepts. Duplicate or replace a choice where those uses should remain independent.
- Check the Product Add-Ons panel on representative simple and variable products.
- Confirm group status, category scope, field order, defaults, prices, images, restrictions, and file types.
Switch the storefront
- Put the store into its normal maintenance or controlled-release mode.
- Run the
verifycommand and require a successful exit status. - Deactivate the official WooCommerce Product Add-Ons extension at the site scope where it is active. Do not delete it yet. If the extension is network-active, do not use a per-site cutover: first change its activation strategy in a separately planned network maintenance window.
- Run
verifyagain. Source metadata remains available while the official extension is inactive, so the same read-only comparison must still pass. - Clear page and CDN caches used by the store. POM's Product Add-Ons caches and assignment index are invalidated by the migration itself.
- Open one simple product and one variable product containing imported fields.
- Test required validation, defaults, hidden options, every price method, quantity changes, cart editing, Cart and Checkout Blocks, and a test order.
- Confirm the order contains the accepted labels, values, and add-on total.
- Compare the same representative product through the Product Add-Ons v1 or v2 API and the native WooCommerce product API before and after cutover.
- Send a test order webhook and confirm its line-item add-on metadata and any expected
addon_price,type, ortable_idproperties retain their previous shape. - Reopen normal customer traffic only after totals, API responses, webhook data, and order details match the source behavior.
When Bookings is part of the store, also compare one person-priced booking, one block- or night-priced booking, and one field combining both multipliers. Change the booking date, resource, duration, and people before adding it to the cart, then confirm POM and the source extension produce the same total.
Expected result
POM Product Add-Ons becomes the only storefront add-on handler. Global and product-local fields retain their assignments and pricing behavior, repeated source labels are centrally manageable as Reusable Choices, and the original extension data remains available for rollback.
An official minimum or maximum of 0 means that bound is absent. The importer and official-compatible write API convert explicit zero bounds to POM's empty bound. In the native editor, an empty Maximum means unlimited; a numeric 0 is a real maximum. Include a positive amount in the storefront check for any migrated customer-defined price field.
Old unsigned add-to-cart links containing addon-<product>-<position> values are not direct-purchase credentials for POM. For links in external websites or proposals, generate a signed direct-purchase link and replace the complete URL.
Roll back or clean the import
First preview the cleanup:
wp pomtweaks product-add-ons cleanup --url=https://example.test --dry-run
For a live rollback, reactivate the official extension first when customer continuity is required, then run:
wp pomtweaks product-add-ons cleanup --url=https://example.test --yes
Cleanup restores the POM local product values and tweak-enabled state that existed before migration. Imported groups and Reusable Choices move to WordPress Trash, where they remain recoverable. The official extension's configuration and historical orders are not changed.
Use cleanup during the migration rollback window. If imported groups or Reusable Choices have since been reused in new POM configurations, review those relationships and perform a selective manual rollback instead of trashing every imported record.
Verify compatibility IDs
After migration, inspect the selected site's retained numeric IDs:
wp pomtweaks product-add-ons legacy-ids --url=https://example.test --format=json
The report scans Product Add-On groups and exact product-local definition metadata in bounded pages. It reports the number of live fields and groups, retained mappings, checksum state, and any UUID or numeric-ID conflict without changing a definition. On multisite, run it once per site with that site's URL; it never reads or writes a network-wide registry.
When the report identifies only a missing or damaged derived registry and the live identities are unambiguous, rebuild it with:
wp pomtweaks product-add-ons legacy-ids --url=https://example.test --rebuild --format=json
Rebuild is idempotent. It preserves retired reservations and never changes a live field or group ID to conceal a collision. If the report contains a live collision, keep both affected definitions unchanged, review their source or import package, and remove or replace the conflicting reference before saving again.
Troubleshooting
- No source data found: confirm the command targets the correct site and that the official extension's groups or product fields exist on that site.
- Unsupported field types: a third-party integration may have added a custom type. Convert it to a standard official field type before migration.
- Existing POM data conflict: inspect the reported product IDs. Use
--overwrite-existingonly when the source version should replace those local POM definitions. - POM fields do not appear after migration: confirm the official extension is inactive, Product Add-Ons is enabled in POM Tweaks, the group is published, and its scope includes the product.
- Activation settings cannot be written: keep the official extension active and run
verify. If all source counts match their verified counts and the only issue istweak_disabled, enable Product Add-Ons in the selected site's POM Tweaks settings, then runverifyagain. Alternatively, restore CLI access to the same settings tree and repeatmigratewithout--forceor--overwrite-existing; an already verified import is checked again before activation. Do not repeat the import or run cleanup merely to resolve filesystem access. - An identically named option should not be shared: create a separate Reusable Choice and replace that particular field membership before cutover.
- A command was interrupted: run the dry run again, then repeat the migration. Saved source mappings allow the command to resume without duplicating completed records.
- Verification reports a stale source: an official group, product configuration, or option label was removed after import. Run cleanup and perform a fresh migration so obsolete imported records are removed safely.
- Verification reports a mismatch: keep the official extension active. Use
migrate --forcefor additions and non-identity source edits such as prices or descriptions. Use cleanup followed by a fresh migration for deletions and for option-label renames, because labels define the reusable-choice source identity. - Compatibility ID collision: the requested imported integer already belongs to another UUID on this site. Do not relabel or force-link it; clone with new identities or remove the conflicting imported reference, then repeat preflight.
Related: Create groups and reusable choices, Official Product Add-Ons compatibility, and Management REST API.