Customizer – postMessage से संचार

परिचय

Customizer होस्ट पृष्ठ से postMessage के ज़रिए संचार करता है। यह साझा nonce हैंडशेक के बाद Customizer-विशिष्ट सेशन अनुरोध करता है, जिससे टोकन और कार्ट कुंजी, दोनों मिलते हैं।

सेटअप:

  1. Alter Product ऐप में ई-कॉमर्स सेटिंग टैब खोलें।
  2. एकीकरण सेक्शन में वह डोमेन सेट करें जहाँ iframe एम्बेड होगा (जैसे https://yourwebsite.com या http://localhost:3000)।

प्रक्रिया:

  1. आपकी वेबसाइट Customizer iframe लोड करती है।
  2. iframe ALTER_CHILD_HELLO भेजता है; आपका पृष्ठ उसी nonce के साथ ALTER_PARENT_ACK का जवाब देता है।
  3. iframe ALTER_CUSTOMIZER_INIT_SESSION से सेशन माँगता है, जिसके पेलोड में alterProductId, uiDesignId और mode होते हैं।
  4. आपका बैकएंड Alter Product Public API से सेशन बनाता है और पृष्ठ ALTER_CUSTOMIZER_SESSION_READY से जवाब देता है, जिसमें token, cartKey और mode होते हैं।
  5. सफलतापूर्वक सहेजने के बाद Customizer नए कार्ट आइटम के लिए ALTER_CUSTOMIZER_ADD_TO_CART या मौजूदा कार्ट आइटम के लिए ALTER_CUSTOMIZER_UPDATE_DESIGN भेजता है।

उत्पाद कॉन्फ़िगरेशन में तय किया गया वेरिएंट मेटाडेटा पेलोड में शामिल होता है।

Customizer द्वारा भेजे गए संदेश

प्रकारविवरण
ALTER_CHILD_HELLOहैंडशेक की शुरुआत (nonce शामिल है)
ALTER_CUSTOMIZER_INIT_SESSIONहोस्ट वेबसाइट से Customizer सेशन टोकन और कार्ट कुंजी माँगता है
ALTER_CUSTOMIZER_ADD_TO_CARTउपयोगकर्ता ने “कार्ट में जोड़ें” पर क्लिक किया (पेलोड में सहेजा गया डिज़ाइन/ऑर्डर डेटा है)
ALTER_CUSTOMIZER_UPDATE_DESIGNउपयोगकर्ता ने मौजूदा कार्ट आइटम/ऑर्डर के बदलाव सहेजे
ALTER_WP_CUSTOMIZER_ORDER_REQUESTमौजूदा ग्राहक ऑर्डर लोड करने का WordPress/WooCommerce अनुरोध
ALTER_WP_CUSTOMIZER_ORDER_SAVE_REQUESTग्राहक ऑर्डर डेटा और अपलोड सहेजने का WordPress/WooCommerce अनुरोध
ALTER_WP_RUNTIME_CONTEXT_REQUESTWordPress/WooCommerce रनटाइम संदर्भ का अनुरोध
ALTER_WP_LOCAL_DESIGN_REQUESTwp_local_design=1 होने पर WordPress के स्थानीय डिज़ाइन बूटस्ट्रैप का अनुरोध

जब ग्राहक Customizer में कार्ट में जोड़ें पर क्लिक करता है, तो डिफ़ॉल्ट स्थिति shopping_cart के साथ ऑर्डर रिकॉर्ड बनता है। जब तक स्थिति shopping_cart है, ग्राहक डिज़ाइन संपादित कर सकता है (जैसे इस लिंक से: https://alterproduct.com/app/customizer/{customizerId}/{orderId})। स्थिति shopping_cart या editable के अलावा कुछ और होने पर ग्राहक का संपादन बंद हो जाता है और उसे डिज़ाइन का केवल देखने वाला संस्करण मिलता है।

Customizer को मिलने वाले संदेश

प्रकारविवरण
ALTER_PARENT_ACKहैंडशेक की पुष्टि (nonce शामिल होना चाहिए)
ALTER_CUSTOMIZER_SESSION_READYCustomizer को अधिकृत करने के लिए token, cartKey और mode देता है
ALTER_CUSTOMIZER_SESSION_ERRORCustomizer सेशन अनुरोध विफल हुआ
ALTER_WP_CUSTOMIZER_ORDER_RESPONSEमौजूदा ग्राहक ऑर्डर के साथ WordPress/WooCommerce जवाब
ALTER_WP_CUSTOMIZER_ORDER_SAVE_RESPONSEग्राहक ऑर्डर सहेजने के बाद WordPress/WooCommerce जवाब
ALTER_WP_RUNTIME_CONTEXT_RESPONSEWordPress/WooCommerce रनटाइम संदर्भ का जवाब
ALTER_WP_LOCAL_DESIGN_RESPONSEWordPress के स्थानीय डिज़ाइन बूटस्ट्रैप का जवाब

पूरा उदाहरण (HTML + JS)

1<!DOCTYPE html>
2<html lang="en">
3<head>
4  <meta charset="UTF-8" />
5  <meta name="viewport" content="width=device-width, initial-scale=1" />
6  <title>Alter Product Customizer — postMessage (Handshake + Token)</title>
7  <style>
8    body { font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif; margin: 24px; }
9    iframe { width: 100%; height: 720px; border: 0; display: block; border-radius: 12px; }
10    pre { background: #0b1020; color: #d7e1ff; padding: 12px; border-radius: 12px; overflow:auto; }
11  </style>
12</head>
13<body>
14  <h1>My E-commerce</h1>
15
16  <iframe
17    id="customizerWidget"
18    src="https://alterproduct.com/app/customizer/1"
19    title="Alter Product Customizer"
20    allowfullscreen>
21  </iframe>
22
23  <h3>Logs</h3>
24  <pre id="log"></pre>
25
26  <script>
27    const IFRAME_ORIGIN = 'https://alterproduct.com';
28    const iframe = document.getElementById('customizerWidget');
29    const logEl = document.getElementById('log');
30
31    let handshakeOk = false;
32
33    function log(...args) {
34      const line = args.map(a => (typeof a === 'string' ? a : JSON.stringify(a, null, 2))).join(' ');
35      logEl.textContent += line + '\n';
36    }
37
38    function postToIframe(payload) {
39      iframe.contentWindow.postMessage(payload, IFRAME_ORIGIN);
40    }
41
42    /**
43     * Your backend owns this endpoint and should create a Customizer embed session
44     * using server-side credentials. Expected response:
45     * { sessionToken: "...", cartKey: "...", mode: "view" | "edit" }
46     */
47    async function getCustomizerSessionFromYourBackend(payload) {
48      const res = await fetch('/api/alter/customizer-session', {
49        method: 'POST',
50        headers: { 'Content-Type': 'application/json' },
51        body: JSON.stringify(payload || {}),
52      });
53
54      if (!res.ok) throw new Error('Failed to create customizer session');
55
56      const data = await res.json();
57      if (!data || !data.sessionToken || !data.cartKey) {
58        throw new Error('Missing sessionToken or cartKey');
59      }
60
61      return data;
62    }
63
64    window.addEventListener('message', async (event) => {
65      // ✅ 1) Validate origin
66      if (event.origin !== IFRAME_ORIGIN) return;
67
68      // ✅ 2) Validate source
69      if (event.source !== iframe.contentWindow) return;
70
71      const msg = event.data || {};
72      if (!msg.type || typeof msg.type !== 'string') return;
73
74      // -----------------------
75      // A) HANDSHAKE
76      // Customizer -> Host: ALTER_CHILD_HELLO { nonce }
77      // Host       -> Customizer: ALTER_PARENT_ACK { nonce }
78      // -----------------------
79      if (msg.type === 'ALTER_CHILD_HELLO') {
80        const nonce = msg.nonce;
81        if (!nonce || typeof nonce !== 'string') return;
82
83        handshakeOk = true;
84        log('[Customizer] -> Host: ALTER_CHILD_HELLO', { nonce });
85
86        log('[Host] -> Customizer: ALTER_PARENT_ACK');
87        postToIframe({ type: 'ALTER_PARENT_ACK', nonce });
88        return;
89      }
90
91      // Ignore everything until handshake is done
92      if (!handshakeOk) return;
93
94      // -----------------------
95      // B) CUSTOMIZER SESSION INIT
96      // Customizer -> Host: ALTER_CUSTOMIZER_INIT_SESSION { payload: { alterProductId, uiDesignId, mode } }
97      // Host       -> Customizer: ALTER_CUSTOMIZER_SESSION_READY { token, cartKey, mode }
98      // -----------------------
99      if (msg.type === 'ALTER_CUSTOMIZER_INIT_SESSION') {
100        try {
101          const payload = msg.payload || {};
102          const alterProductId = Number(payload.alterProductId || 0);
103          const uiDesignId = Number(payload.uiDesignId || 0);
104          const mode = payload.mode === 'edit' ? 'edit' : 'view';
105
106          log('[Customizer] -> Host: ALTER_CUSTOMIZER_INIT_SESSION', {
107            alterProductId,
108            uiDesignId,
109            mode,
110          });
111
112          const session = await getCustomizerSessionFromYourBackend({
113            alterProductId,
114            uiDesignId,
115            mode,
116          });
117
118          log('[Host] -> Customizer: ALTER_CUSTOMIZER_SESSION_READY');
119          postToIframe({
120            type: 'ALTER_CUSTOMIZER_SESSION_READY',
121            token: session.sessionToken,
122            cartKey: session.cartKey,
123            mode: session.mode || mode,
124          });
125        } catch (e) {
126          log('[Host] -> Customizer: ALTER_CUSTOMIZER_SESSION_ERROR', String(e && e.message ? e.message : e));
127          postToIframe({
128            type: 'ALTER_CUSTOMIZER_SESSION_ERROR',
129            message: String(e && e.message ? e.message : e),
130          });
131        }
132        return;
133      }
134
135      // -----------------------
136      // C) Customizer events
137      // -----------------------
138      if (msg.type === 'ALTER_CUSTOMIZER_ADD_TO_CART') {
139        log('[Customizer] -> Host: ALTER_CUSTOMIZER_ADD_TO_CART', msg.payload);
140        // Send payload to your backend and add item to cart in your e-commerce system
141        return;
142      }
143
144      if (msg.type === 'ALTER_CUSTOMIZER_UPDATE_DESIGN') {
145        log('[Customizer] -> Host: ALTER_CUSTOMIZER_UPDATE_DESIGN', msg.payload);
146        // Update an existing cart line/order in your e-commerce system
147        return;
148      }
149    });
150  </script>
151</body>
152</html>

उदाहरण पेलोड

{
  "id": 481,
  "customizerId": 10,
  "userDesignId": 10,
  "isSeenByOwner": false,
  "orderStatus": "shopping_cart",
  "createdAt": "2026-05-28T10:15:00.000Z",
  "customizerOrderURL": "https://alterproduct.com/app/customizer/10/481",
  "customizerURL": "https://alterproduct.com/app/customizer/10",
  "customizerName": "Mug 450ml (15oz)",
  "totalPrice": {
    "value": 24.99,
    "currency": "EUR"
  },
  "productGroup": {
    "id": 1,
    "name": {
      "pl": "Kubek 450ml (15oz)",
      "en": "Mug 450ml (15oz)"
    }
  },
  "productItems": [
    {
      "id": 901,
      "model3d": {
        "id": 3
      },
      "size": {
        "id": 9,
        "name": {
          "pl": "450ml (15oz)",
          "en": "450ml (15oz)"
        },
        "measureSize": {
          "D": 8.65,
          "H": 11.95
        },
        "externalMapping": {
          "attribute": {
            "internalId": 123,
            "slug": "pa_size",
            "label": "Size"
          },
          "term": {
            "internalId": 456,
            "slug": "450ml-15oz",
            "label": "450ml (15oz)"
          }
        }
      },
      "material": {
        "id": 3,
        "name": {
          "pl": "Ceramika",
          "en": "Ceramic"
        },
        "externalMapping": {
          "attribute": {
            "internalId": 124,
            "slug": "pa_material",
            "label": "Material"
          },
          "term": {
            "internalId": 457,
            "slug": "ceramic",
            "label": "Ceramic"
          }
        }
      },
      "printType": {
        "id": 5,
        "name": {
          "pl": "Sublimacja",
          "en": "Sublimation"
        },
        "externalMapping": {
          "attribute": {
            "internalId": 125,
            "slug": "pa_printing-method",
            "label": "Printing method"
          },
          "term": {
            "internalId": 458,
            "slug": "sublimation",
            "label": "Sublimation"
          }
        }
      },
      "printingMethod": {
        "id": 5,
        "name": {
          "pl": "Sublimacja",
          "en": "Sublimation"
        },
        "externalMapping": {
          "attribute": {
            "internalId": 125,
            "slug": "pa_printing-method",
            "label": "Printing method"
          },
          "term": {
            "internalId": 458,
            "slug": "sublimation",
            "label": "Sublimation"
          }
        }
      },
      "color": {
        "id": 11,
        "name": {
          "pl": "Domyślny",
          "en": "Default"
        },
        "hex": "#FFFFFF",
        "customColor": false,
        "pickedColors": {},
        "patternId": null,
        "externalMapping": {
          "attribute": {
            "internalId": 126,
            "slug": "pa_color",
            "label": "Color"
          },
          "term": {
            "internalId": 459,
            "slug": "default",
            "label": "Default"
          }
        }
      },
      "variant": {
        "id": 11,
        "productGroupId": 1,
        "productModel3dId": 3,
        "sizeId": 9,
        "materialId": 3,
        "printingMethodId": 5,
        "colorId": 11,
        "metadata": {
          "sku": "MUG-450-WHITE"
        },
        "minOrderQuantity": 1,
        "processingTime": null,
        "stockQuantity": null,
        "volume": null,
        "weight": null
      },
      "unitPrice": {
        "value": 24.99,
        "currency": "EUR"
      },
      "totalPrice": {
        "value": 24.99,
        "currency": "EUR"
      },
      "quantity": 1,
      "mockups": [
        {
          "productModel3dId": 3,
          "img": {
            "thumb": "https://api.example.com/file/protected/user_1/10/e-commerce/orders/481/mockup-thumb.webp",
            "large": "https://api.example.com/file/protected/user_1/10/e-commerce/orders/481/mockup-large.webp"
          }
        }
      ],
      "updatedAt": "2026-05-28T10:15:10.000Z"
    }
  ],
  "cartKey": "wc_cart_item_key"
}