Skip to Content
FeaturesProducts

Products

Products in Hoikka support variants, translations, and facets (attributes).

AI-friendly codebase: Try prompts like “Add a weight field to products” and the agent can trace the full path from schema to admin to storefront.

Variants

Each product has one or more variants:

// Product: "T-Shirt" // Variants: "T-Shirt - Red / M", "T-Shirt - Blue / L" const variant = { sku: "TSHIRT-RED-M", price: 2999, // cents stock: 50, facetValues: [redColor, mediumSize] };

Multi-Language Support

Default language (English) fields are stored directly on the products table. Non-default languages (e.g. Finnish) use the product_translations table, managed via TranslationService.

const product = await productService.getById(123); // Default language fields — directly on the products table product.name; // "Blue Shirt" product.slug; // "blue-shirt" product.description; // "<p>A nice shirt</p>"

Translations are edited in the admin panel via language tabs on the main form (TranslationEditor.svelte, shared by all translated entities). See Localization for details.

Description HTML (default language and translations) is sanitized on save with src/lib/server/sanitize.ts, since it is rendered with {@html} on the storefront.

Facets (Attributes)

Facets define product attributes for filtering:

// Facet: "Color" // Values: "Red", "Blue", "Green" // Facet: "Size" // Values: "S", "M", "L", "XL"

Products and variants can have facet values assigned for:

  • Filtering in collections
  • Search refinement
  • Variant selection

Admin product lists use a simple LIKE match over name and description:

const results = await productService.list({ search: "shirt" });

The storefront uses a SQLite FTS5 index instead — see Search & Categories.

Admin Operations

// Create product — default language fields go directly on the entity await productService.create({ name: "Blue Shirt", slug: "blue-shirt", description: "..." }); // Add a Finnish translation import { translationService } from "$lib/server/services/translations"; await translationService.upsertProductTranslation(productId, "fi", { name: "Sininen paita", slug: "sininen-paita", description: "..." }); // Variant operations are handled through productService // See src/lib/server/services/products.ts for variant management
Last updated on