xStore.products

Đọc danh mục sản phẩm: danh sách có phân trang, chi tiết, biến thể, sản phẩm liên quan.

Phương thức

Phương thức Cú pháp Mô tả Từ phiên bản
list xStore.products.list({ limit, cursor, sort, category, collection, q, ids }): Promise<CursorPaginatedResponse<ProductCard>> Danh sách thẻ sản phẩm, phân trang bằng con trỏ. sort nhận newest | price_asc | price_desc; KHÔNG có featured. 2.1
get xStore.products.get(productId): Promise<ProductDetail> Chi tiết sản phẩm, kèm biến thể, ảnh, thương hiệu và category_ids. 2.1
getBySlug xStore.products.getBySlug(slug): Promise<ProductDetail> Chi tiết sản phẩm theo slug. Slug dùng để TRA CỨU, không dùng để ghép đường dẫn — đường dẫn nằm ở trường url. 2.1
related xStore.products.related(productId, { limit }): Promise<CursorPaginatedResponse<ProductCard>> Sản phẩm liên quan, cùng hình dạng thẻ với list(). 2.1
variants xStore.products.variants(productId): Promise<CursorPaginatedResponse<ProductVariant>> Biến thể của sản phẩm. Tồn kho ở đây là stock_quantity, khác với available_quantity trên thẻ sản phẩm. 2.1

Ví dụ đầy đủ

<script>
  // Lưới sản phẩm của một danh mục, sắp theo giá tăng dần.
  async function renderGrid(categoryId) {
    const trang = await xStore.products.list({
      category: categoryId,     // id danh mục, KHÔNG phải slug
      sort: 'price_asc',        // newest | price_asc | price_desc
      limit: 24,
    });

    document.getElementById('grid').innerHTML = trang.items.map((sp) => {
      // url có thể null — LUÔN kiểm tra trước khi tạo liên kết.
      const href = sp.url ?? '#';
      const gia  = xStore.utils.formatCurrency(sp.effective_price ?? sp.price ?? 0);
      return `<a class="product-card" href="${href}">
                <img src="${sp.cover_image_url ?? ''}" alt="${sp.title}" loading="lazy">
                <span>${sp.title}</span>
                <span>${gia}</span>
              </a>`;
    }).join('');

    // Trang tiếp theo: truyền lại next_cursor, đừng tự đoán offset.
    if (trang.has_more) {
      document.getElementById('more').dataset.cursor = trang.next_cursor;
    }
  }

  // Trang chi tiết: lấy theo slug rồi đọc biến thể từ chính kết quả đó.
  async function renderDetail(slug) {
    const sp = await xStore.products.getBySlug(slug);
    console.log(sp.title, sp.variants?.length ?? 0, 'biến thể');
  }
</script>

Thư viện gọi tới /api/... trên chính tên miền cửa hàng, nên không cần khai báo địa chỉ máy chủ ở bất kỳ đâu.

Xem thêm Sự kiện để giao diện tự cập nhật sau mỗi thao tác.