Zum Hauptinhalt springen

Ü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 ab
  • getProductReviews() - 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

idOrSlug
string
erforderlich
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 Feld stockMode bestimmt, wie die Bestandsverfügbarkeit berechnet wird:
WertModusBeschreibung
0BerechnetBestand wird automatisch aus verfügbaren Artikel berechnet
1IgnoriertBestand wird nicht verfolgt – immer verfügbar
2FestBestand wird manuell gesetzt und bei Kauf dekrementiert
Siehe das Stock Calculation Mode Enum für vollständige Details.

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

productId
string
erforderlich
Die eindeutige ID des Produkts
page
number
erforderlich
Seitenzahl (1-basiert)

Rückgabe

Gibt PaginatedApiResponse<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