Übersicht
Greifen Sie über zwei Methoden auf Produktdaten zu:getStore()- Gibt alle Produkte im Shop zurück (in der Shop-Antwort enthalten)getProduct()- Ruft ein einzelnes Produkt per ID oder Slug abgetProductReviews()- Ruft paginierte Bewertungen für ein Produkt ab
Alle Produkte abrufen
Produkte sind in der Shop-Antwort enthalten:const response = await komerza.getStore();
if (response.success) {
const products = response.data.products;
products.forEach((product) => {
console.log(product.name, product.variants.length, "Varianten");
});
}
Einzelnes Produkt abrufen
Ein Produkt per ID oder Slug abrufen:const response = await komerza.getProduct("product-id-or-slug");
Parameter
Die eindeutige ID des Produkts (UUID) oder der URL-Slug
Beispiel
// Per ID
const byId = await komerza.getProduct("550e8400-e29b-41d4-a716-446655440000");
// Per Slug
const bySlug = await komerza.getProduct("premium-license");
if (bySlug.success) {
const product = bySlug.data;
console.log(product.name);
console.log(product.description);
console.log(product.variants);
}
Produkt-Objekt
interface Product {
id: string; // Eindeutige Kennung
name: string; // Produktname
description: string; // Beschreibung (unterstützt Markdown)
slug?: string; // URL-freundlicher Slug
imageNames: string[]; // Produkt-Bilddateinamen (siehe Bilder-Seite)
rating: number; // Durchschnittliche Bewertung
order: number; // Anzeigereihenfolge
visibility: number; // 0=Öffentlich, 1=Nicht gelistet, 2=Privat
storeId: string; // ID des übergeordneten Shops
variants: Variant[]; // Produktvarianten
dateCreated: string; // ISO 8601-Zeitstempel
}
Varianten
Jedes Produkt hat eine oder mehrere Varianten. Jede Variante hat ihren eigenen Preis, Bestand und Einstellungen:interface Variant {
id: string; // Varianten-ID
name: string; // Variantenname
productId: string; // ID des übergeordneten Produkts
storeId: string; // Shop-ID
cost: number; // Preis in der Shop-Währung
stock: number; // Verfügbarer Bestand
stockMode: number; // Bestandsberechnungsmodus (siehe unten)
minimumQuantity: number; // Mindest-Kaufmenge (Standard: 1)
maximumQuantity: number; // Maximale Kaufmenge (-1 = unbegrenzt)
order: number; // Anzeigereihenfolge
imageNames: string[]; // Variantenspezifische Bilddateinamen
type: number; // 0=Einmalig, 1=Abonnement
subscriptionPeriod?: string; // Abonnementdauer falls zutreffend
requireDiscordAuthorization: boolean;
dateCreated: string;
}
Bestandsberechnungsmodus
Das FeldstockMode bestimmt, wie die Bestandsverfügbarkeit berechnet wird:
| Wert | Modus | Beschreibung |
|---|---|---|
| 0 | Berechnet | Bestand wird automatisch aus verfügbaren Artikel berechnet |
| 1 | Ignoriert | Bestand wird nicht verfolgt – immer verfügbar |
| 2 | Fest | Bestand wird manuell gesetzt und bei Kauf dekrementiert |
Bilder anzeigen
Produkt- und Varianten-imageNames enthalten Dateinamen, keine vollständigen URLs. Lesen Sie die Seite Bilder, um zu erfahren, wie vollständige Bild-URLs erstellt werden.
Varianten anzeigen
async function produktAnzeigen(productId) {
const [productResponse, formatter] = await Promise.all([
komerza.getProduct(productId),
komerza.createFormatter(),
]);
if (!productResponse.success) return;
const product = productResponse.data;
// Varianten nach Reihenfolge sortieren
const variants = product.variants.sort((a, b) => a.order - b.order);
variants.forEach((variant) => {
const price = formatter.format(variant.cost);
const inStock = variant.stockMode === 1 || variant.stock > 0;
console.log(`${variant.name}: ${price}`);
console.log(` Bestand: ${inStock ? "Verfügbar" : "Nicht verfügbar"}`);
console.log(` Min Menge: ${variant.minimumQuantity}`);
console.log(
` Max Menge: ${
variant.maximumQuantity === -1 ? "Unbegrenzt" : variant.maximumQuantity
}`,
);
});
}
Variantenauswahl
<select id="variant-select" onchange="updatePrice()">
<!-- Dynamisch befüllt -->
</select>
<span id="price"></span>
<button onclick="addToCart()">In den Warenkorb</button>
<script>
let currentProduct;
let formatter;
async function loadProduct(productId) {
[{ data: currentProduct }, formatter] = await Promise.all([
komerza.getProduct(productId),
komerza.createFormatter(),
]);
const select = document.getElementById("variant-select");
select.innerHTML = currentProduct.variants
.map(
(v) =>
`<option value="${v.id}">${v.name} - ${formatter.format(
v.cost,
)}</option>`,
)
.join("");
updatePrice();
}
function updatePrice() {
const variantId = document.getElementById("variant-select").value;
const variant = currentProduct.variants.find((v) => v.id === variantId);
document.getElementById("price").textContent = formatter.format(
variant.cost,
);
}
function addToCart() {
const variantId = document.getElementById("variant-select").value;
komerza.addToBasket(currentProduct.id, variantId);
}
</script>
Produktbewertungen
Paginierte Bewertungen für ein Produkt abrufen:const response = await komerza.getProductReviews(productId, page);
Parameter
Die eindeutige ID des Produkts
Seitenzahl (1-basiert)
Rückgabe
GibtPaginatedApiResponse<Review> zurück:
interface PaginatedApiResponse<Review> {
success: boolean;
pages: number; // Gesamtzahl der Seiten
data?: Review[]; // Array von Bewertungen
message?: string;
}
interface Review {
id: string;
rating: number; // 1-5 Sterne
reason: string; // Bewertungstext
productId: string;
reply?: string; // Händlerantwort falls vorhanden
dateCreated: string;
}
Bewertungen anzeigen
async function bewertungenAnzeigen(productId, page = 1) {
const response = await komerza.getProductReviews(productId, page);
if (!response.success) return;
const container = document.getElementById("reviews");
container.innerHTML = response.data
.map(
(review) => `
<div class="review">
<div class="rating">${"★".repeat(review.rating)}${"☆".repeat(
5 - review.rating,
)}</div>
<p>${review.reason}</p>
${
review.reply
? `<p class="reply"><strong>Antwort:</strong> ${review.reply}</p>`
: ""
}
<time>${new Date(review.dateCreated).toLocaleDateString()}</time>
</div>
`,
)
.join("");
// Paginierung
if (response.pages > 1) {
container.innerHTML += `
<div class="pagination">
${
page > 1
? `<button onclick="bewertungenAnzeigen('${productId}', ${
page - 1
})">Zurück</button>`
: ""
}
<span>Seite ${page} von ${response.pages}</span>
${
page < response.pages
? `<button onclick="bewertungenAnzeigen('${productId}', ${
page + 1
})">Weiter</button>`
: ""
}
</div>
`;
}
}
Produktbilder
Produktbilder werden per Dateiname referenziert. Vollständige URL erstellen:function getProductImageUrl(storeId, productId, imageName) {
return `https://cdn.komerza.com/stores/${storeId}/products/${productId}/${imageName}`;
}
// Verwendung
const product = response.data;
const imageUrl = getProductImageUrl(
product.storeId,
product.id,
product.imageNames[0],
);
Bildergalerie
function produktbilderAnzeigen(product) {
const gallery = document.getElementById("gallery");
// Variantenbilder verwenden falls verfügbar, sonst Produktbilder
const images =
product.variants[0].imageNames.length > 0
? product.variants[0].imageNames
: product.imageNames;
gallery.innerHTML = images
.map(
(img) => `
<img
src="https://cdn.komerza.com/stores/${product.storeId}/products/${product.id}/${img}"
alt="${product.name}"
loading="lazy"
/>
`,
)
.join("");
}
Bestandsverwaltung
Bestandsverfügbarkeit prüfen, bevor zum Warenkorb hinzugefügt wird:function kannInWarenkorbLegen(variant, quantity) {
// stockMode 1 = Ignoriert (unbegrenzt)
if (variant.stockMode === 1) return true;
// Verfügbaren Bestand prüfen
if (variant.stock < quantity) return false;
// Mengenbeschränkungen prüfen
if (quantity < variant.minimumQuantity) return false;
if (variant.maximumQuantity !== -1 && quantity > variant.maximumQuantity)
return false;
return true;
}
function getBestandsStatus(variant) {
if (variant.stockMode === 1) return "Auf Lager";
if (variant.stock === 0) return "Nicht verfügbar";
if (variant.stock < 10) return `Nur noch ${variant.stock} verfügbar`;
return "Auf Lager";
}
Vollständiges Beispiel
<!DOCTYPE html>
<html>
<head>
<title>Produktseite</title>
<script src="https://cdn.komerza.com/komerza.min.js"></script>
<style>
.product {
max-width: 600px;
margin: 0 auto;
}
.gallery img {
max-width: 100%;
}
.variants {
margin: 20px 0;
}
.reviews {
margin-top: 40px;
}
.review {
border-bottom: 1px solid #eee;
padding: 15px 0;
}
.rating {
color: gold;
}
</style>
</head>
<body>
<div class="product">
<div id="gallery"></div>
<h1 id="name"></h1>
<p id="description"></p>
<p id="rating"></p>
<div class="variants">
<select id="variant-select"></select>
<span id="price"></span>
<span id="stock"></span>
</div>
<div>
<label
>Menge: <input type="number" id="quantity" value="1" min="1"
/></label>
<button id="add-btn" onclick="addToCart()">In den Warenkorb</button>
</div>
<div class="reviews">
<h2>Bewertungen</h2>
<div id="reviews"></div>
</div>
</div>
<script>
komerza.init("your-store-id");
let product;
let formatter;
async function loadProduct(idOrSlug) {
const [productResponse, fmt] = await Promise.all([
komerza.getProduct(idOrSlug),
komerza.createFormatter(),
]);
if (!productResponse.success) {
alert("Produkt nicht gefunden");
return;
}
product = productResponse.data;
formatter = fmt;
// Produktinformationen anzeigen
document.getElementById("name").textContent = product.name;
document.getElementById("description").textContent =
product.description;
document.getElementById("rating").textContent =
`${product.rating}★ Bewertung`;
// Bilder anzeigen
const images = product.imageNames;
document.getElementById("gallery").innerHTML = images
.map(
(img) =>
`<img src="https://cdn.komerza.com/stores/${product.storeId}/products/${product.id}/${img}" />`,
)
.join("");
// Varianten befüllen
const select = document.getElementById("variant-select");
select.innerHTML = product.variants
.map((v) => `<option value="${v.id}">${v.name}</option>`)
.join("");
select.onchange = updateVariantDisplay;
updateVariantDisplay();
loadReviews(1);
}
function updateVariantDisplay() {
const variantId = document.getElementById("variant-select").value;
const variant = product.variants.find((v) => v.id === variantId);
document.getElementById("price").textContent = formatter.format(
variant.cost,
);
// Bestandsstatus
let stockText = "Auf Lager";
if (variant.stockMode !== 1) {
if (variant.stock === 0) stockText = "Nicht verfügbar";
else if (variant.stock < 10)
stockText = `Nur noch ${variant.stock} verfügbar`;
}
document.getElementById("stock").textContent = stockText;
// Mengenbeschränkungen aktualisieren
const qtyInput = document.getElementById("quantity");
qtyInput.min = variant.minimumQuantity;
qtyInput.max =
variant.maximumQuantity === -1 ? 999 : variant.maximumQuantity;
qtyInput.value = variant.minimumQuantity;
// Schaltfläche deaktivieren wenn nicht verfügbar
document.getElementById("add-btn").disabled =
variant.stockMode !== 1 && variant.stock === 0;
}
function addToCart() {
const variantId = document.getElementById("variant-select").value;
const quantity = parseInt(document.getElementById("quantity").value);
komerza.addToBasket(product.id, variantId, quantity);
alert("In den Warenkorb gelegt!");
}
async function loadReviews(page) {
const response = await komerza.getProductReviews(product.id, page);
if (!response.success || response.data.length === 0) {
document.getElementById("reviews").innerHTML =
"<p>Noch keine Bewertungen</p>";
return;
}
document.getElementById("reviews").innerHTML = response.data
.map(
(review) => `
<div class="review">
<div class="rating">${"★".repeat(review.rating)}${"☆".repeat(
5 - review.rating,
)}</div>
<p>${review.reason}</p>
${review.reply ? `<p><em>Antwort: ${review.reply}</em></p>` : ""}
</div>
`,
)
.join("");
}
// Produkt aus URL laden oder Standard verwenden
const urlParams = new URLSearchParams(window.location.search);
const productId = urlParams.get("product") || "your-default-product-slug";
loadProduct(productId);
</script>
</body>
</html>
Nächste Schritte
Währungsformatierung
Preise in der Shop-Währung formatieren
Warenkorb-Verwaltung
Produkte zum Warenkorb hinzufügen