holoAddToCart - UNAS Webshop Integration
Overview
The holoAddToCart function allows adding products directly to the UNAS webshop cart from HoloStep 3D configurators using a URL parameter.
Usage
Products are added to the cart via URL parameter:
text
https://webshop.com/product?holoAddToCart=SKU1:2,SKU2:1Supported Formats
| Format | Example | Description |
|---|---|---|
| Single SKU | holoAddToCart=SKU1 | Add 1 item |
| SKU with quantity | holoAddToCart=SKU1:2 | Add 2 items |
| Multiple products | holoAddToCart=SKU1:2,SKU2:1,SKU3:5 | Multiple products at once |
Flow
- On page load, the
initUnas()function runs - Reads the
holoAddToCartURL parameter - Parses the parameter into SKU and quantity pairs
- Calls
UnasCartAdapter.add()for each product - UNAS AJAX API call (
/shop_ajax/ajax_cart.php) - Removes URL parameter (to prevent duplicate additions)
- Refreshes cart UI (
cart_refresh()or page reload)
Main Components
1. initUnas() - Entry Point
typescript
export function initUnas() {
const urlParams = new URLSearchParams(window.location.search);
const holoAddToCartParam = urlParams.get('holoAddToCart');
// Handle holo actions when the page loads
handleHoloActions();
}2. parseHoloAddToCart() - Parameter Parsing
typescript
const parseHoloAddToCart = (param: string): Array<{ sku: string; qty: number }> => {
if (!param) return [];
return param
.split(',')
.map((item) => {
const [sku, qtyStr] = item.trim().split(':');
const qty = qtyStr ? parseInt(qtyStr, 10) : 1;
const validQty = isNaN(qty) || qty <= 0 ? 1 : qty;
return { sku: sku.trim(), qty: validQty };
})
.filter((item) => item.sku);
};3. handleHoloActions() - Add to Cart Logic
typescript
const handleHoloActions = async () => {
if (holoAddToCartParam) {
const cartItems = parseHoloAddToCart(holoAddToCartParam);
if (cartItems.length === 0) {
console.warn('No valid SKUs found in holoAddToCart parameter:', holoAddToCartParam);
return;
}
const cartAdapter = new UnasCartAdapter();
for (const { sku, qty } of cartItems) {
try {
await cartAdapter.add(sku, qty);
} catch (error: any) {
console.error(`Failed to add ${sku} (qty: ${qty}) to cart:`, error);
}
}
// Remove URL parameter
urlParams.delete('holoAddToCart');
const newUrl = window.location.pathname + (urlParams.toString() ? '?' + urlParams.toString() : '');
window.history.replaceState({}, '', newUrl);
// Refresh cart
if (window.location.pathname.includes('/shop_cart.php')) {
window.location.reload();
} else if (typeof window.cart_refresh === 'function') {
window.cart_refresh();
}
}
};UnasCartAdapter
Constants and Helper Functions
typescript
const CART_URI = '/shop_ajax/api.php';
const ADD_2_CART_URI = '/shop_ajax/ajax_cart.php';
function requireApiAuth() {
const apiAuth = window?.UNAS?.api_auth;
if (!apiAuth) {
throw new Error('[UNAS CartAdapter] window.UNAS.api_auth is missing');
}
return apiAuth;
}
function buildForm(data) {
const fd = new FormData();
Object.entries(data).forEach(([k, v]) => fd.append(k, v));
return fd;
}add() - Add Product
typescript
async add(sku, qty = 1) {
const api_auth = requireApiAuth();
const body = buildForm({
get_ajax: 1,
result_type: 'json',
lang_master: 'hu',
action: 'add',
sku,
qty,
api_auth,
});
const res = await fetch(ADD_2_CART_URI, {
method: 'POST',
body,
credentials: 'same-origin',
});
if (!res.ok) throw new Error(`[UNAS add] HTTP ${res.status}`);
return await res.json();
}remove() - Remove Product
typescript
async remove(selector: any = {}) {
const api_auth = requireApiAuth();
const { id, sku } = selector;
// Strategy A: delete by id or sku
try {
const delKey = id != null ? { id } : sku ? { sku } : null;
if (delKey) {
const delBody = buildForm({
get_ajax: 1,
result_type: 'json',
lang_master: 'hu',
action: 'del',
...delKey,
api_auth,
});
const delRes = await fetch(ADD_2_CART_URI, {
method: 'POST',
body: delBody,
credentials: 'same-origin',
});
if (delRes.ok) {
return await delRes.json().catch(() => ({}));
}
}
} catch { /* fall through to Strategy B */ }
// Strategy B: set qty=0
if (sku) {
const zeroBody = buildForm({
get_ajax: 1,
result_type: 'json',
lang_master: 'hu',
action: 'add',
sku,
qty: 0,
api_auth,
});
const zeroRes = await fetch(ADD_2_CART_URI, {
method: 'POST',
body: zeroBody,
credentials: 'same-origin',
});
if (!zeroRes.ok) throw new Error(`[UNAS remove] HTTP ${zeroRes.status}`);
return await zeroRes.json();
}
throw new Error('[UNAS remove] Provide id or sku');
}getCart() - Get Cart
typescript
async getCart() {
const api_auth = requireApiAuth();
const params = new URLSearchParams({
get_ajax: 1,
action: 'getCart',
api_auth,
} as any);
const res = await fetch(`${CART_URI}?${params.toString()}`, {
method: 'GET',
credentials: 'same-origin',
});
if (!res.ok) throw new Error(`[UNAS getCart] HTTP ${res.status}`);
const result = await res.json();
const rawItems = Array.isArray(result?.items) ? result.items : [];
const valid = rawItems.map(mapCartItem).filter(Boolean);
const { itemCount, totalPrice } = summarizeCart(result, valid);
return { items: valid, itemCount, totalPrice, raw: result };
}UNAS Global Object
The window.UNAS object is required for the integration to work.
typescript
interface UnasShop {
base_url: string;
domain: string;
username: string;
id: number;
lang: string;
currency_type: string;
currency_code: string;
sku: string;
product_id: string;
}
interface Window {
UNAS?: {
api_auth: string; // Required for API calls!
onAddToCart: (callback: (event: any, product: UnasProduct) => void) => void;
onRemoveFromCart: (callback: (event: any, product: UnasProduct) => void) => void;
getCart: (callback: (unasCart: UnasCartItem) => void) => void;
shop: UnasShop;
};
}API Endpoint Summary
| Operation | Endpoint | Method | Action |
|---|---|---|---|
| Add | /shop_ajax/ajax_cart.php | POST | add |
| Remove | /shop_ajax/ajax_cart.php | POST | del |
| Get Cart | /shop_ajax/api.php | GET | getCart |
Required Parameters for All Calls
api_auth- value ofwindow.UNAS.api_authget_ajax: 1result_type: 'json'
Example Usage
typescript
import { UnasCartAdapter } from '@holo/util';
const adapter = new UnasCartAdapter();
// Add product
await adapter.add('LBIVENGR4', 2);
// Remove product by SKU
await adapter.remove({ sku: 'LBIVENGR4' });
// Remove product by ID
await adapter.remove({ id: 12345 });
// Get cart
const cart = await adapter.getCart();
// Return value:
// {
// items: [{ id: '123', name: 'Product', quantity: 2, price: 5000, sku: 'SKU1' }],
// itemCount: 2,
// totalPrice: 10000,
// raw: { /* original UNAS response */ }
// }