41 "summary": "Gift-card products are ordinary WooCommerce products discriminated ONLY by type == \"pw-gift-card\" — no PW-specific meta key or property exists on the record [VERIFIED LIVE 2026-08-16: meta_data carried only _created_via and third-party keys]. The core products import must NOT map these as plain store products; enumerate them authoritatively with GET /wc/v3/products?type=pw-gift-card (the type enum on wc/v3/products includes pw-gift-card [VERIFIED LIVE 2026-08-16]) and route them to gift-cards/gift-card-product instead."
42 },
43 {
44 "code": "denominations-are-variations",
45 "severity": "warning",
46 "summary": "Denominations live as product variations under a \"Gift Card Amount\" attribute — one variation per amount, each with its own price [VERIFIED LIVE 2026-08-16: variations 10/25/50/100 on the reference store]. Map the variation prices to the Wix gift-card product's denomination options; a variant-filtering transform that drops unknown attribute terms would silently lose denominations."
47 }
48 ]
49 },
50 {
51 "entity": "gift-card",
52 "channel": "core-meta",
53 "embeddedIn": ["/wc/v3/orders"],
54 "propertyPath": "pw_gift_card_number",
55 "candidateTargetRefs": [
56 "gift-cards/gift-card"
57 ],
58 "pitfalls": [
59 {
60 "code": "issuance-is-core-meta-not-db-only",
61 "severity": "warning",
62 "summary": "CORRECTED 2026-08-17 (VERIFIED LIVE on poratus, resolving the 2026-08-16 quirk below): issued-card identity (code, amount, recipient email, sender name, message) is NOT db-only — it rides as line_item.meta_data (pw_gift_card_number/pw_gift_card_amount/pw_gift_card_to/pw_gift_card_from/pw_gift_card_message) on GET /wc/v3/orders once the order reaches processing or completed. The plugin's own PHP source (pw-gift-cards-purchasing.php, github.com/common-repository/pw-woocommerce-gift-cards mirror) calls PW_Gift_Card::create_card() from the woocommerce_order_status_processing/woocommerce_payment_complete (both gated on is_paid()) and woocommerce_order_status_completed hooks — a pending/on-hold order simply has no card yet, which is not the same as 'unreachable'. Only the ongoing BALANCE (post-issuance activity/redemption) remains genuinely db-only — see gift-card-activity's no-wix-write-surface-for-history pitfall, now also live-confirmed."
63 },
64 {
65 "code": "outstanding-balance-is-a-liability",
66 "severity": "blocker",
67 "summary": "Unspent balances are money owed to customers. Reconcile the total outstanding value before and after import and show it in the execution plan; a silently dropped card is a lost customer entitlement."
72 "summary": "CORRECTED 2026-08-17 (VERIFIED LIVE against the real Wix Create Gift Card endpoint, msid fd0ad9fb-d439-406f-8a00-b6c6ad0d95ab): the 2026-08-16 note below that PW's dash-separated format 'fits' Wix's 8-20 character bound is INCOMPLETE and misleading. Wix's giftCard.code rejects ANY non-alphanumeric character outright (live 428 INVALID_CODE: 'Gift Card Code can only contain letters(A-z) and numbers(0-9)') — independent of length. PW's own default code format (four groups of four separated by hyphens, e.g. ARQQ-69TH-5Q4Z-TBYQ) is REJECTED AS-IS by Wix, every single time, not just as an edge case. Stripping the hyphens produces a 16-character alphanumeric string Wix accepts (confirmed live: create + read-back succeeded), but that changes the code the customer already holds printed/emailed — the same 'do not silently rewrite' principle as the length pitfall, except this one is the DEFAULT case for this plugin, not an outlier."
73 },
74 {
75 "code": "balance-derived-from-activity",
76 "severity": "warning",
77 "summary": "PW derives a card's balance from its activity ledger (sum of credit/debit rows), and Wix likewise only accepts an initial value with balance derived from transactions. A partly-redeemed card needs an explicit policy: import at remaining balance, or at face value with the spend replayed. Decide it in the mapping plan; do not default silently. [DOCUMENTED]"
78 }
79 ]
80 },
81 {
82 "entity": "gift-card-activity",
83 "channel": "db-only",
84 "candidateTargetRefs": [],
85 "blocked": [
86 {
87 "kind": "bridge-plugin",
88 "resolution": "No fulfillment path exists yet. Once wix-migration-helper's Case 2 is cleared for production and the site owner installs it, its route exposes this ledger read-only.",
104 "summary": "Per-card activity history (issuance, redemptions, adjustments) is durable data in the same plugin-owned tables as the cards [DOCUMENTED], but Wix has no public method to write historical gift-card transactions (see gift-cards/gift-card pitfall no-transaction-history-import); the domain entity's documented fallback is a CMS archive. Unlike issued-card identity (see gift-card's issuance-is-core-meta-not-db-only pitfall — that data turned out to be reachable via order line-item meta), this activity ledger itself has no REST path at all; see this same entity's redemption-invisible-even-in-order-rest-data pitfall, and spec 0040's bridge-plugin proposal for the actual unblock."
109 "summary": "VERIFIED LIVE 2026-08-17 (poratus): this is a stronger claim than 'db-only plugin tables' — applying a gift card at checkout adds a custom WooCommerce order-item type ('pw_gift_card', class WC_Order_Item_PW_Gift_Card via $order->add_item()) that the stock /wc/v3/orders REST controller never serializes at all (it only knows line_items/fee_lines/shipping_lines/coupon_lines/tax_lines). A live redemption was generated end-to-end (headless storefront checkout via the WooCommerce Store API) and the resulting order's full REST payload has ZERO trace of it: order.total drops by the redeemed amount, but discount_total/fee_lines/coupon_lines are all unchanged, so nothing in the standard response explains why. There is no order-meta fallback here the way there is for gift-card-issuance — this genuinely has no REST path at all, only a DB export."
110 }
111 ]
112 }
113 ],
114 "quirks": [
115 "Storage model [VERIFIED LIVE 2026-08-16, the reference store, v2.47]: gift-card PRODUCTS (catalog) are REST-visible as wc/v3 products of type pw-gift-card with denomination variations. UPDATED 2026-08-17 (poratus, VERIFIED LIVE): issued-card IDENTITY (code/amount/recipient) is reachable too, once positively observed on a completed order — see gift-card's issuance-is-core-meta-not-db-only pitfall. Only the ongoing balance/redemption ledger is genuinely db-only with no REST route at all.",
116 "The route /wc-pimwick/v1/pw-gift-cards previously recorded on the Wix-side sourceAliases (gift-cards/gift-card) does NOT exist: 404 rest_no_route, and no wc-pimwick namespace in the REST index [VERIFIED LIVE 2026-08-16 against free v2.47, re-confirmed 2026-08-17 on poratus]. Whether the separate PW Gift Cards Pro plugin registers such a surface is [NEEDS-VERIFICATION].",
117 "Plugin id basename differs from the directory: pw-woocommerce-gift-cards/pw-gift-cards, no .php suffix on this host's plugin list [VERIFIED LIVE 2026-08-16]. Never construct dir/dir.php.",
118 "Unauthenticated fingerprint: the storefront homepage loads /wp-content/plugins/pw-woocommerce-gift-cards/assets/dist/blocks.js?ver=2.47, so the asset-path signal works with no credentials [VERIFIED LIVE 2026-08-16].",
119 "Enumerating gift-card products via the {parentId}/variations child route depends on the sampled parent page containing the pw-gift-card product; the authoritative enumeration is GET /wc/v3/products?type=pw-gift-card (returned the product with X-WP-Total [VERIFIED LIVE 2026-08-16]).",
120 "RESOLVED 2026-08-17 (was NEEDS-VERIFICATION as of 2026-08-16, below): a gift-card PURCHASE order DOES carry PW recipient/message line-item meta once it actually completes. VERIFIED LIVE on poratus by generating 3 real orders via the WooCommerce REST API directly (POST /wc/v3/orders with the same pw_gift_card_amount/to/from/message meta the plugin's own checkout hook sets, then PUT status:completed — a status transition fires the same woocommerce_order_status_completed hook regardless of whether the order originated from checkout or the REST API) and confirming pw_gift_card_number appeared on completion. Prior note, for context: 'all 150 orders on the reference store were scanned ... and none contained PW keys — but the store has never sold a gift card, so there was no positive case to observe.'",
121 "Discovered 2026-08-17 (poratus): the plugin's checkout redeem widget ('Have a gift card?') is wired only to classic Cart/Checkout template hooks (woocommerce_before_checkout_form, woocommerce_review_order_before_order_total, woocommerce_cart_totals_before_order_total). A site using WooCommerce's Cart/Checkout BLOCKS (poratus does) never renders it at all — confirmed by finding no classic form markup and no localized pwgc nonce anywhere on the block-rendered /cart/ or /checkout/ pages. The plugin's own AJAX action (admin-ajax.php?action=pw-gift-cards-redeem) and Store API cart 'extensions.pw-gift-cards' data still work if invoked directly (verified by doing exactly that, via a temporary [woocommerce_cart]-shortcode page created solely to obtain a real nonce, then deleted) — but a real end customer on an unmodified block-checkout site currently has no way to redeem a card through the storefront UI at all."