Většina hlášení typu „doplněk Shoptet nefunguje" má jednu z několika opakujících se příčin. Sesbírali jsme je z reálných nasazení a seřadili podle toho, jak často je vidíme.
Než začnete hledat v tomhle seznamu, projděte tři kroky. Odfiltrují většinu případů za minutu:
- DevTools → Network, filtr
multipack. Načetly semultipack.jsamultipack.cssse statusem 200? Proběhlo načtení konfigurace a jaký vrátilo status? - DevTools → Console. Je tam
Uncaught? Chyba v renderu vypadá zvenku úplně stejně jako „skript se nenačetl". - Podívejte se na skutečnou URL requestu. Neobsahuje
/nullnebo/undefined? Je v ní shortcode bez hranatých závorek?
Příklady vycházejí ze smyšleného e-shopu www.example.cz (projectId 123456) a konfigurace
„Kávový balíček" se shortcodem w-multipack-ABC12 — 3 sloty, sleva 15 %.
Widget se nevykreslí
1. Na stránce není vůbec nic
Skript se buď nenačetl, nebo se načetl a spadl při renderu. V Network musí multipack.js vrátit
200 — status 404 znamená překlep v cestě /user/documents/… nebo soubor nahraný o adresář jinam.
Žádný request znamená, že HTML vložka není uložená, nebo je uložená jen pro jinou jazykovou mutaci
či doménu e-shopu.
Když request projde a přesto se nic nevykreslí, otevřete konzoli. Typické pády jsou na null
v poli url nebo default_category a na skladovosti zpracované jako číslo — stock chodí jako
string "12.000", takže potřebuje parseFloat.
2. Na stránce je vidět holý text shortcodu
Skript nenašel shortcode v podobě, kterou hledá — buď se vůbec nenačetl (viz bod výš), nebo se
text shortcodu ve stránce liší od očekávaného tvaru. Rychlá kontrola: Ctrl+U a vyhledat
w-multipack ve zdrojovém kódu stránky.
3. WYSIWYG editor shortcode rozbil
Nejčastější příčina předchozího bodu. Editor obsahu si text rád „opraví" — a rozdělený shortcode už neodpovídá vzoru, který skript hledá.
| Co v HTML uvidíte | Co se stalo |
|---|---|
[w-multipack-ABC12] |
editor převedl hranaté závorky na entity |
[w-multipack-<span>ABC12</span>] |
text se rozpadl na víc uzlů, typicky po vložení z Wordu |
[w-multipack-ABC12] s uvnitř |
nezlomitelná mezera z formátování |
[w-multipack-abc12] |
malá písmena — shortcode je case-sensitive, tvar je [A-Z0-9]{5} |
Spolehlivé řešení je vždycky stejné: v editoru přepnout do režimu zdrojového kódu, shortcode
smazat a napsat ručně jako prostý text na samostatný řádek. Pak uložit a zkontrolovat
přes Ctrl+U.
4. Změna JS nebo CSS se na e-shopu neprojevila
Soubory z /user/documents/ jdou přes CDN a browser cache s dlouhým TTL, takže samotné nahrání
nové verze nestačí. Deploy je dvoukrokový: nahrát soubor a zvýšit parametr ?v= v HTML
vložce.
<link rel="stylesheet" href="/user/documents/multipack/multipack.css?v=1.0.3">
<script src="/user/documents/multipack/multipack.js?v=1.0.3" defer></script>
Verze zvyšujte u obou souborů společně. Rozjeté verze (CSS 1.02, JS 1.07) jsou klasický zdroj
hlášky „u mě to vypadá jinak než u tebe".
Chyby z API
5. Načtení konfigurace vrací 404
Pro dvojici projectId + shortcode neexistuje konfigurace. Zkontrolujte tři věci: že je
v URL shortcode bez hranatých závorek, že testujete na e-shopu, kde je konfigurace opravdu
založená, a že ji obchodník mezitím nesmazal — smazáním konfigurace shortcode přestává platit.
Drobnost, na kterou se hodí myslet dopředu: tělo téhle odpovědi je prostý JSON řetězec, ne objekt.
Ve svém error handleru s tím počítejte, ať vám hláška pro zákazníka nevyjde jako undefined.
6. Vytvoření sady vrací 422
Odeslaný výběr neprošel validací. Prakticky vždy jde o jednu ze tří věcí: počet GUIDů neodpovídá
product_count (musí jich být přesně tolik), shortcode nemá 17 znaků, nebo některý GUID nemá
36 znaků.
Řešení je preventivní — odesílejte až po kompletním výběru a do té doby držte tlačítko disabled.
Tělo 422 je objekt s klíči guids a shortcode; hlášky jsou anglicky a nejsou určené koncovému
zákazníkovi, takže podle klíče zobrazte vlastní českou hlášku.
7. V URL requestu se objevuje /null
Cenová hladina je volitelný segment cesty. Naivní skládání URL ho vyrobí i tehdy, když žádná hladina není:
// špatně – v URL vznikne "/null"
const url = `${base}/configuration-products/${shortcode}/${ctx.customer?.priceListId ?? null}`;
// správně – segment se prostě vynechá
const id = Number.isInteger(ctx.customer?.priceListId) ? ctx.customer.priceListId : null;
const url = `${base}/configuration-products/${shortcode}` + (id !== null ? `/${id}` : '');
Pozor při vývoji: na některých e-shopech vrací dataLayer priceListId i nepřihlášeným
návštěvníkům, takže se chyba na testovacím účtu vůbec nemusí projevit.
Ceny a měny
8. Cena v košíku se liší od ceny ve widgetu
Widget zobrazuje vlastní orientační výpočet z listingových cen, ale závazná je cena spočítaná backendem. Rozejít se můžou hlavně u produktů s variantami a u akčních cen — listing pracuje s nejnižší cenou napříč variantami, sada se počítá z ceny první varianty v základní měně e-shopu.
Řešení: po úspěšném vytvoření sady přepište zobrazenou cenu hodnotou price z odpovědi a během
výběru cenu označte jako orientační. Produkty, které bývají v akci, do balíčku raději nezařazujte —
nebo si to předem vyjasněte s obchodníkem.
9. Přihlášený B2B zákazník vidí jiné ceny
Cenová hladina ovlivňuje ceny ve výpisu produktů, ze kterého zákazník vybírá. Sada se pak zakládá z běžných cen se slevou nastavenou v konfiguraci.
Na e-shopech s aktivními cenovými hladinami to řešte domluvou s obchodníkem — balíček se pro B2B segment buď nenabízí, nebo se sleva nastaví tak, aby dávala smysl i pro něj. Ve widgetu pak vždy zobrazte závaznou cenu z odpovědi.
10. E-shop s víc měnami ukazuje částku v korunách
Závazná cena sady je vždy v základní měně e-shopu, zatímco listing je přepočtený kurzem podle měny, kterou má zákazník přepnutou. Zákazníkovi v eurech tedy nesmíte tuhle hodnotu zobrazit jako částku v jeho měně.
Máte dvě varianty: buď ji přepočítat kurzem z dataLayeru a označit jako orientační, nebo cenu ve
widgetu nepřepisovat a spolehnout se na přepočet v košíku Shoptetu. Starter na to má přepínač
useApiPriceInSummary. A nehardcodujte cenový klíč:
const priceKey = 'price_' + (ctx.currency || 'CZK'); // ne: product.price_CZK
const price = product[priceKey];
11. Produkt se zobrazuje za 0 Kč
Produkt není zařazený v cenové hladině přihlášeného zákazníka, takže k němu nepřichází cena. Nulu nikdy nezobrazujte jako platnou cenu a nepouštějte ji do součtu — produkt v nabídce buď skryjte, nebo místo ceny napište „cena na dotaz".
Košík a odesílání
12. Dvojklik založí dvě sady
Chybí ochrana proti dvojímu odeslání. Každé odeslání zakládá v katalogu reálný produkt, takže dvojklik znamená dva produkty — a když se navíc mezi kliknutími změní pořadí GUIDů, vyhodnotí se to jako jiná kombinace.
Potřebujete tři věci najednou: single-flight guard (druhý klik dostane tentýž Promise),
disabled na tlačítku a viditelný spinner. Samotné disabled nestačí, protože mezi kliknutím
a nastavením atributu je několik milisekund. A GUIDy vždycky řaďte:
const guids = selection.map((p) => p.guid).slice().sort();
.slice() tam nechte — sort() mutuje pole in-place a rozhodil by vám pořadí slotů v UI.
13. shoptet is not defined
Váš skript běží dřív než šablonové skripty Shoptetu. Typicky proto, že je vložený do hlavičky
nebo bez atributu defer.
Skript patří do patičkové HTML vložky s defer, init navažte na DOMContentLoaded a dostupnost
si před voláním ověřte:
if (typeof shoptet !== 'undefined' && shoptet.cartShared?.addToCart) {
shoptet.cartShared.addToCart({ productCode: data.code, amount: quantity });
}
Když funkce chybí, zobrazte srozumitelnou chybu místo tichého selhání. Vlastním fetchem na
košíkové akce to neobcházejte — blokuje ho CSRF ochrana Shoptetu.
14. Sada zmizela z katalogu a kód přestal platit
Tohle není chyba, ale záměrné chování. Vygenerované sady jsou produkty vytvořené na míru jednomu nákupu. Každou noc proto běží úklid, který smaže každou sadu, ke které neexistuje objednávka — jinak by e-shopu za pár měsíců zaplevelily katalog stovky jednorázových produktů.
Prakticky to znamená, že kód sady platí nejdéle do nejbližší půlnoci. Neukládejte ho do
localStorage, do sdílených odkazů ani do e-mailů. Ukládejte si GUIDy vybraných produktů
a při návratu zákazníka si o sadu požádejte znovu — stejná kombinace vrátí existující sadu, jinak
se založí nová. Objednané sady zůstávají.
Vzhled a UX
15. Obrázky produktů se nenačítají
Pole image není URL, ale název souboru včetně podepsaného query stringu. Nejčastější chyba je,
že se query string odstraní nebo znovu zaenkóduje, případně se použije hostname stránky místo
hostname z product.url.
const host = product.url ? new URL(product.url).hostname : window.location.hostname;
const src = `https://cdn.myshoptet.com/usr/${host}/user/shop/orig/${product.image}`;
Query string nechte beze změny a počítejte s tím, že image může chybět — mějte připravený
placeholder.
16. Widget rozbil layout šablony
Globální CSS. Pravidla na holých selektorech (h2, select, .rating-star, :root) se propíšou
do celého e-shopu, protože widget běží uvnitř cizí šablony.
Všechna pravidla zanořte pod kořenovou třídu widgetu (.wt-multipack …), včetně věcí jako
scroll-behavior nebo max-width na kontejnerech. Obrázkům nastavte width/height nebo
aspect-ratio, ať vám při načítání neskáče layout.
17. Vyprodaný produkt se dostane do sady
Hlídat, co je v nabídce, je úkol frontendu — a je to jedna z věcí, které stojí za pět minut práce
navíc. Vyprodané produkty ve výběru zablokujte nebo skryjte a nezapomeňte, že stock je string:
const available = parseFloat(product.stock) > 0;
Finální kontrola dostupnosti pak proběhne v košíku Shoptetu podle nastavení e-shopu, ale zákazník by se do ní neměl dostat překvapením.
18. Počet slotů nesedí nebo se sloty přehazují
Počet slotů je odvozený z column_number místo z product_count, nebo se kód spoléhá na pořadí,
ve kterém kategorie dorazí.
Autoritativní je vždy product_count (2–5). Kategorie si seřaďte sami — podle column_number,
pak podle name s localeCompare(…, 'cs'). Totéž platí pro pořadí produktů uvnitř kategorie.
Kdy nám napsat
Když nic z výše uvedeného nepomůže, napište na jsme@webotvurci.cz. Ať to nemusíme řešit na dvakrát, přiložte:
- URL stránky s widgetem a
projectIdi shortcode konfigurace, - screenshot konzole a záložky Network — ideálně s viditelnou URL requestu, status kódem a tělem odpovědi,
- čas i s časovou zónou, kdy se to stalo,
- co jste už zkoušeli a jestli se to děje pořád, nebo jen občas.
Bez projectId a shortcodu se problém na naší straně nedohledá.
Kam dál
- FAQ a řešení problémů na GitHubu — stejný index s odkazy do detailní dokumentace.
- Startovací implementace
examples/starter— funkční widget, který má většinu těchhle pastí ošetřenou. - Sestav si vlastní balíček — co doplněk umí, ceník a živá ukázka.
Potřebujete s nasazením pomoct nebo si nechat zkontrolovat hotovou implementaci? Ozvěte se na jsme@webotvurci.cz.