Termékoldal: a kosárba helyezés testreszabása
Hogyan épül fel a termékoldal vásárlási doboza blokkokból, és hogyan formálhatja át vagy renderelheti újra egy téma a kosárba helyezési területet a kereskedelmi logika érintése nélkül.
Ezen az oldalon
A termékoldal kosárba helyezési területe (mennyiség, a hozzáadás gomb, gyorsfizetési tárcák,
az előrendelési sor és az „Értesítést kérek”) a vásárlási doboz (buy box). A termékoldal többi
részéhez hasonlóan ez is blokkokból épül fel. A platform a mögötte lévő kereskedelmi
működést (kosárhoz adás, analitikai események, tárcás fizetések, csomagok, hibakezelés) egyetlen
hook mögött tartja: ez a useProductBuy a @poltura/theme-sdk/product
csomagból. Egy téma a vásárlási doboz minden egyes pixelét re-renderelheti, miközben továbbra is
ezt a hookot hívja meg.
Hogyan épül fel a termékoldal
A terméksablon egyetlen product-information szekcióból áll három régióval, amelyeket a
@poltura/theme-sdk/product csomagból származó productRegions határoz meg: media (a galéria
oszlopa), details (a galéria mellett) és below (a mindkettő alatti, teljes szélességű terület).
Az alapértelmezett téma pages/product.json fájlja ezekkel a blokkokkal tölti fel őket, és egy
related-products szekciót helyez el alá:
| Blokk típusa | Régió | Mit jelenít meg |
|---|---|---|
product-gallery | media | A képgaléria |
breadcrumb | details | Breadcrumb |
product-vendor | details | Márka vagy gyártó |
product-title | details | Cím |
product-rating | details | Értékelési pontszám |
price | details | Ár, eredeti ár, kedvezmény, egységár, áfamegjegyzés |
variant-picker | details | Opció- / változatválasztó |
inventory | details | Raktáron, fogyóban, elfogyott, előrendelhető állapotok |
buy-buttons | details | A vásárlási doboz: quantity, add-to-cart, wallets, product-wishlist |
delivery-info | details | Mikor indul útnak és érkezik meg, szállítónként és árakkal |
product-highlights | details | Kiemelt propok |
product-details | details | Platform, régió, lefedettség |
product-addons | details | Kiegészítő termékek, mindegyik saját kosárba gombbal |
product-tabs | below | Leírás, specifikációk és a bolt egyéb fülei |
product-safety | below | A gyártó adatai és termékbiztonsági információk |
product-reviews | below | Vásárlói vélemények és az átlagos értékelés |
A szállítási doboz
A delivery-info jeleníti meg a kiválasztott változat szállítási ígéretét: a rendelési határidőt
(visszaszámláló, ha három óránál kevesebb van hátra, előtte pontos időpont), a csatlakoztatott
szállítókat a látogató országára érvényes nappal és árral, az ingyenes szállítási értékhatárt és
egy országválasztót. Minden a bolt szállítási időre vonatkozó beállításaiból, a szállító appokból
és a termék átfutási idejéből származik, így a témának nem kell saját szállítási ígéretet
megfogalmaznia. A beállításai: style (compact vagy card), show_dispatch, show_carriers,
carrier_limit (1-től 6-ig), show_free_shipping, show_country, egy opcionális instant_label
header és egy opcionális note sor a doboz alatt. A mellékelt témák csak a style értékét állítják
be. Helyezd a blokkot a vásárlási gombok alá:
{ "id": "delivery", "type": "delivery-info", "slot": "details", "settings": { "style": "card" } }A kereskedők a Témaszerkesztő felületén rendezhetik át, adhatják hozzá, rejthetik el és
szerkeszthetik a blokkokat. A galéria, a cím, az ár, a változatválasztó, a vásárlási gombok és a
termékbiztonsági blokk statikusak: a kereskedő átstilizálhatja őket, de nem mozgathatja vagy
törölheti. A változatválasztó, a vásárlási gombok és a termékbiztonság nem is rejthető el, ahogy
a vásárlási gombokon belüli add-to-cart gomb sem. A galéria, a cím és az ár elrejthető.
A témák a platformblokkok jelölését a @poltura/theme-sdk/elements
csomagból származó overrideBlock segítségével írják felül, amelyet a src/blocks mappa alatti
fájlból exportálnak. A platform megtartja a blokk sémáját, beállítópaneljét (inspector) és adatait, és
maga rajzolja meg a blokk keretét (kereskedői stílus, horgony, kijelölés a témaszerkesztőben). A
beállítások típusbiztosan érkeznek:
import {
overrideBlock,
type ElementRenderProps,
type PlatformBlockSettings,
} from '@poltura/theme-sdk/elements';
import { AddToCartButton, useProductBuy, type ProductBuy } from '@poltura/theme-sdk/product';
type AddToCartSettings = PlatformBlockSettings<'add-to-cart'>;
function labelFor(buy: ProductBuy, settings: AddToCartSettings): string {
const status = (buy.variant ?? buy.product).availability.status;
const custom = buy.isAdding
? settings.adding_label
: status === 'preorder'
? settings.preorder_label
: status === 'comingSoon'
? settings.coming_soon_label
: status === 'unavailable'
? settings.sold_out_label
: settings.label;
return custom?.trim() || buy.ctaLabel;
}
function AddToCart({ settings }: ElementRenderProps<AddToCartSettings>) {
const buy = useProductBuy();
return (
<div className='min-w-0 flex-1'>
<AddToCartButton
label={labelFor(buy, settings)}
busy={buy.isAdding}
disabled={!buy.canAdd || buy.isAdding}
error={buy.error}
fullWidth={settings.full_width}
onAdd={() => void buy.add()}
/>
</div>
);
}
export const addToCart = overrideBlock('add-to-cart', AddToCart);Ugyanez a minta érvényes a quantity, wallets, price, inventory és buy-buttons
blokkokra is: block type-onként egy fájl a src/blocks alatt, amely az overrideBlock eredményét
exportálja.
A vásárlási hook: useProductBuy
A vásárlási doboz minden része egyetlen közös állapotot olvas a useProductBuy() segítségével.
Működik a termékoldalon, egy product card alatt és egy ProductScope belsejében is; mindenhol
máshol hibát dob.
| Mező | Jelentés |
|---|---|
product | A megvásárolni kívánt termék |
variant | A kiválasztott változat, vagy null, amíg a választott opciók egyhez sem illeszkednek |
quantity, setQuantity(n) | A hozzáadandó mennyiség |
canAdd | Hozzáadható-e most a kiválasztott változat; kapcsold ki a gombot, ha false |
isAdding | Folyamatban lévő állapot a gombhoz |
error | Miért nem sikerült az utolsó hozzáadás, az oldal nyelvén, vagy null |
add() | A művelet. Ezt hívd meg, semmi mást |
ctaLabel | A gomb szövege az adott állapothoz: kosárba, előrendelés, hamarosan vagy elfogyott |
wallet.visible | Van-e a WalletButtons komponensnek itt megjeleníthető gyorsfizetési tárcája |
wholesale | Nagykereskedelmi sávos árak a kiválasztott változathoz (WholesaleTiers), egyébként null |
personalization, giftCard | Megszemélyesítési szövegek és ajándékkártya-adatok a termékoldalon, máshol null |
bundle | A termékhez kínált csomag és a vásárló választása benne, vagy null |
Az SDK tartalmazza azokat az elemeket, amelyekből a platform vásárlási doboza felépül, mindet a
@poltura/theme-sdk/product csomagban:
| Elem | Mit jelenít meg |
|---|---|
AddToCartButton | A hozzáadás gomb az alatta lévő legutóbbi hibával |
QuantityStepper | Mínusz, beviteli mező és plusz; a megadott min, step és max között tartja a beírt mennyiséget |
WalletButtons | Apple Pay, Google Pay és egyéb gyorsfizetési tárcák; a termékoldalon kívül nem jelenik meg |
WholesaleTiers | Nagykereskedelmi vásárló sávos ára, listaára és mennyiségi lépcsői |
PersonalizationFields, GiftCardFields | A vásárló által kitöltött szövegek, illetve az ajándékkártya összege, címzettje és dátuma |
BundleSelector | A csomagajánlat és a választási lehetőségek |
AvailabilityBadge | „Előrendelés”, „Hamarosan elérhető” vagy „Elfogyott”; sima raktárállapotoknál semmi |
NotifyMe | Értesítési űrlap olyan változathoz, amely most nem vásárolható meg |
Az add() a buy.quantity mennyiséget adja hozzá, így egy saját vásárlási doboz a
QuantityStepper komponenst a buy.quantity és a buy.setQuantity értékekhez köti. Az SDK nem
adja át a témának a változat rendelési szabályait (minimum, lépésköz, maximum), így a léptetőd
csak azokat a határokat kényszeríti ki, amelyeket átadsz neki.
Előrendelés, hamarosan elérhető és értesítés
Egy változat lehet előrendelhető: most megvásárolható, és egy várható dátumtól szállítják. Az
állapota az availability a változaton (és az összes változat legjobb állapotaként a terméken
is), amely egy status alapján megkülönböztetett unió:
status | További mezők | purchasable |
|---|---|---|
inStock | quantity (ha a bolt mutatja a készletszinteket) | mindig |
backorder | nincs | mindig |
preorder | expected, remaining, message | amíg van hely az előrendelésben |
comingSoon | opensAt, expected | soha a rendelések megnyitása előtt |
unavailable | reason: outOfStock, preorderFull, paused, restricted | soha |
Minden állapot tartalmazza a label mezőt, amely a státuszt jelzi az oldal nyelvén. Az
expected.label az oldal számára már megfogalmazott ígéret („2026. 4. negyedév”, „A dátum még
megerősítésre vár”), így a témának soha nem kell magának formáznia a várható dátumot.
| Állapot | Gomb | Sor az ár alatt | Kártyajelvény |
|---|---|---|---|
preorder | „Előrendelés”, aktív | várható dátum + üzenet | „Előrendelés” |
comingSoon | „Hamarosan elérhető”, inaktív | rendelések megnyitásának dátuma | „Hamarosan elérhető” |
unavailable (preorderFull) | „Elfogyott”, inaktív | „Előrendelés betelt” | „Elfogyott” |
backorder, inStock | változatlan | változatlan | változatlan |
import { useFormat } from '@poltura/theme-sdk/i18n';
import { useProductBuy } from '@poltura/theme-sdk/product';
export function PreorderNote() {
const { variant } = useProductBuy();
const format = useFormat();
const availability = variant?.availability;
if (availability?.status === 'preorder') {
return (
<div className='flex flex-col gap-1 text-sm text-muted-foreground'>
<p>{availability.expected.label}</p>
{availability.message ? <p>{availability.message}</p> : null}
</div>
);
}
if (availability?.status === 'comingSoon') {
return <p className='text-sm text-muted-foreground'>{format.date(availability.opensAt)}</p>;
}
return null;
}A vásárlási doboz blokkjainak feliratbeállításai (témánkénti alapértelmezések megadása a
pages/product.json fájlban):
| Blokk | Beállítás | Jelentés |
|---|---|---|
add-to-cart | preorder_label | Előrendelhető változat gombszövege |
add-to-cart | coming_soon_label | Letiltott gombszöveg az előrendelések megnyitása előtt |
add-to-cart | sold_out_label | Nem megvásárolható változat letiltott gombszövege |
inventory | backorder_label | Később szállított változat készletsorának szövege |
inventory | show_preorder_remaining | „Már csak N darab maradt” megjelenítése (alapértelmezetten ki van kapcsolva; a bolt „Fennmaradó készlet megjelenítése” beállítása szükséges hozzá) |
Értesítést kérek. Ha a bolt kínál készletértesítéseket, és a kiválasztott változat még nem
vásárolható meg, a buy-buttons blokk a gombok alatt megjeleníti a NotifyMe komponenst. Ha
máshová szeretnéd helyezni, használd a <NotifyMe variantId={variant.id} reason='outOfStock' />
formát (vagy comingSoon, preorderFull). Önállóan kezeli a kérést, a captchát, a
hozzájárulási szöveget és az állapotokat. A useNotifyMe saját űrlapot támogat, így a témának
soha nem kell közvetlenül meghívnia a készletértesítési API-t.
A termékoldalon a buy-buttons blokk jeleníti meg az árkorlátot (price gate) is a gombok helyén,
ha az árak rejtve vannak a látogató elől, valamint az előrendelési dátumot és feltételeket – így
egy olyan oldal is tájékoztatja a vásárlót arról, miért nem tud vásárolni, amelynek az ár- vagy
készletblokkja el van rejtve.
Product cardok esetén az <AvailabilityBadge availability={product.availability} /> jeleníti meg
az „Előrendelés”, „Hamarosan elérhető” és „Elfogyott” jelvényeket, a variant.availability pedig
a vásárlási dobozon kívüli változat teljes állapotát tartalmazza. Mindig az availability mezőt
olvasd, soha ne a készletszinteket: egy nyitott előrendelésben lévő változat készlet nélkül is
megrendelhető, a release után pedig zárva marad, amíg az előrendeléseket nem teljesítik.
Minimális egyedi vásárlási doboz
A buy-buttons override-ja a teljes sort és annak child blockjait lecseréli:
import {
overrideBlock,
type ElementRenderProps,
type PlatformBlockSettings,
} from '@poltura/theme-sdk/elements';
import {
AddToCartButton,
NotifyMe,
QuantityStepper,
WalletButtons,
useProductBuy,
type Availability,
type NotifyMeReason,
} from '@poltura/theme-sdk/product';
import { Price, PriceGate, usePriceAccess } from '@poltura/theme-sdk/price';
import { Card, cn } from '@poltura/theme-sdk/ui';
function notifyReason(availability: Availability | null): NotifyMeReason | null {
if (availability?.status === 'comingSoon') return 'comingSoon';
if (availability?.status !== 'unavailable') return null;
if (availability.reason === 'outOfStock' || availability.reason === 'preorderFull') {
return availability.reason;
}
return null;
}
function BuyButtons({ settings }: ElementRenderProps<PlatformBlockSettings<'buy-buttons'>>) {
const buy = useProductBuy();
const access = usePriceAccess();
const reason = notifyReason(buy.variant?.availability ?? null);
if (!access.visible) {
return (
<div className='text-base font-semibold'>
<PriceGate className='underline underline-offset-2' />
</div>
);
}
return (
<Card className='flex flex-col gap-4 rounded-xl p-6'>
<Price price={(buy.variant ?? buy.product).price} className='text-4xl font-black' />
<div className={cn('flex gap-2', settings.layout === 'stacked' ? 'flex-col' : 'flex-row')}>
<QuantityStepper value={buy.quantity} onChange={buy.setQuantity} />
<AddToCartButton
label={buy.ctaLabel}
busy={buy.isAdding}
disabled={!buy.canAdd || buy.isAdding}
error={buy.error}
fullWidth
onAdd={() => void buy.add()}
/>
</div>
{buy.wallet.visible ? <WalletButtons /> : null}
{buy.variant && reason ? <NotifyMe variantId={buy.variant.id} reason={reason} /> : null}
</Card>
);
}
export const buyButtons = overrideBlock('buy-buttons', BuyButtons);A buy-buttons override-ja nem jelenít meg megszemélyesítési, ajándékkártya- vagy csomagmezőket,
hacsak nem helyezi el maga a PersonalizationFields, GiftCardFields és BundleSelector
komponenseket. Emellett override-olja a kereskedő belső quantity, add-to-cart, wallets és
product-wishlist blokkjait is. Mentsd el a kódszerkesztőben, hogy lásd a szerkesztő Előnézet
felületén, és tedd közzé, hogy élesben is megjelenjen.
A változatválasztó
A változatválasztó ugyanezt a mintát követi a saját block type-ja esetén. A platform tárolja a kijelölést, és megosztja azt a termék összes blokkjával. Ne tarts fent saját kiválasztási állapotot, különben a választó, a vásárlási doboz és a változathoz tartozó analitikai esemény eltérnek majd egymástól:
import {
overrideBlock,
type ElementRenderProps,
type PlatformBlockSettings,
} from '@poltura/theme-sdk/elements';
import { VariantOption, VariantOptionValue, useVariantPicker } from '@poltura/theme-sdk/product';
function Picker({ settings }: ElementRenderProps<PlatformBlockSettings<'variant-picker'>>) {
const picker = useVariantPicker();
if (picker.options.length === 0) return null;
return (
<div className='flex flex-col gap-4'>
{picker.options.map((option) => (
<VariantOption
key={option.id}
option={option}
display={settings.style === 'dropdown' ? 'dropdown' : option.display}
showTitle={settings.show_option_name}
>
{option.values.map((value) => (
<VariantOptionValue
key={value.id}
value={value}
onSelect={() => picker.select(option.id, value.id)}
/>
))}
</VariantOption>
))}
</div>
);
}
export const variantPicker = overrideBlock('variant-picker', Picker);Minden érték selectable mezője jelzi, hogy a kiválasztása vezethet-e még megvásárolható
változathoz, az availability pedig az általa teljessé tett változat állapota. Használd ezeket a
letiltott és halványított opciókhoz. A <VariantPicker /> a teljes platformválasztó, arra az
esetre, ha csak a classes segítségével szeretnéd módosítani a stílusát.
Áthelyezés: régiók és a szekció
Egy blokk stílusának módosítása megváltoztatja a pixeleit. Ha a vásárlási dobozt teljesen máshová szeretnéd helyezni, próbáld ki ezeket sorrendben:
A kereskedők már most is mozgathatnak blokkokat
A kereskedők a témaszerkesztő block tree-jében húzhatják át a blokkokat a media, details és below
régiók között. A szekció beállításai már most is felcserélik az oszlopokat (gallery_position),
beállítják a média szélességét (media_width), és láthatóan tartják a részletek oszlopát
(sticky_details). Mielőtt kódot írnál, ellenőrizd, hogy a kívánt layout nem érhető-e el
egyszerű áthúzással.
Saját szekció-layout kialakítása
Eltérő layouthoz override-old a product-information szekciót, és helyezd el a régiókat te magad.
Az alapértelmezett téma ezt a src/sections/product-information.tsx fájlban teszi meg. Egy
rövidebb változat:
import {
Slot,
overrideSection,
type ElementRenderProps,
type PlatformSectionSettings,
} from '@poltura/theme-sdk/elements';
import { BundleSelector, productRegions } from '@poltura/theme-sdk/product';
import { cn } from '@poltura/theme-sdk/ui';
function ProductInformation({
settings,
}: ElementRenderProps<PlatformSectionSettings<'product-information'>>) {
return (
<div className='bg-background'>
<div className='container mx-auto flex flex-col gap-10 px-4 py-8'>
<div className='grid grid-cols-1 gap-10 lg:grid-cols-2'>
<Slot
name={productRegions.media}
className={cn('flex min-w-0 flex-col gap-4', settings.gallery_position === 'right' && 'lg:order-2')}
/>
<Slot name={productRegions.details} className='flex min-w-0 flex-col gap-5' />
</div>
<BundleSelector placement='below' />
<Slot name={productRegions.below} className='flex min-w-0 flex-col gap-8' />
</div>
</div>
);
}
export const productInformation = overrideSection('product-information', ProductInformation);A kereskedő blokkjai továbbra is megjelennek a Slot-jaidban, és az oldal szerkeszthető marad a
Témaszerkesztőben.
Finomabb módosítások
- Csak tokenek: az alapértelmezett vásárlási doboz a
--primary,--card,--border,--mutedés--radiustokenekre épül. A Témaszerkesztő színei és atokens.csskód nélkül style-olják át. - Szövegek: a kereskedők a Témaszerkesztőben szerkesztik a gombok feliratait. A témák a lefordított
alapértelmezéseket a platform szövegkulcsainak override-jával módosíthatják a
texts/<language>.jsonfájlban. - Az oldal körül: a platform a
product.aboveésproduct.belowapp-slotokat a terméksablon felett és alatt rajzolja ki, így a telepített appok anélkül helyezhetnek el ott bannereket vagy tartalmat, hogy a témának bármit el kellene helyeznie.
Amit a platform kezel
Az add() mögötti kosármódosítás, a tárcás fizetések, a csomagárazás, az elérhetőség és az
analitikai események a platformnál maradnak. A te blokkodé a jelölés, a pénzügyi folyamat pedig a
useProductBuy hooké. Ez a szétválasztás biztosítja, hogy az újratervezett vásárlási doboz a
platformfrissítések után is működőképes maradjon.
Következő lépések
- Bolti űrlapok: jelenítsd meg a bolt közzétett űrlapjait.
- product referencia: a vásárlási doboz minden eleme és hookja.