URL & điều hướng

Mỗi mục có đường dẫn riêng

Sản phẩm, danh mục, bộ sưu tập và trang nội dung tự sở hữu đường dẫn của mình. Đường dẫn này do cửa hàng cấu hình tại Quản trị → Website → Cấu trúc URL, và có thể đặt riêng cho từng mục.

Vì vậy trong giao diện luôn dùng url của chính mục đó:

<a href="{{ product.url }}">{{ product.title }}</a>

Đừng tự ghép đường dẫn theo tiền tố:

{% comment %} SAI — bỏ qua đường dẫn riêng của sản phẩm {% endcomment %}
<a href="/san-pham/{{ product.slug }}">{{ product.title }}</a>

Cách ghép tay ở trên chỉ đúng khi cửa hàng giữ nguyên cấu trúc URL mặc định. Ngay khi người quản trị đổi cấu trúc, hoặc đặt đường dẫn riêng cho một sản phẩm, mọi liên kết ghép tay sẽ trỏ sai.

url có thể là null

Mục chưa được gán đường dẫn sẽ có url bằng null. Khi đó đừng tạo thẻ liên kết — hiển thị dạng chữ:

{% if product.url %}
  <a href="{{ product.url }}" class="product-card__name">{{ product.title }}</a>
{% else %}
  <span class="product-card__name">{{ product.title }}</span>
{% endif %}

Quy tắc này áp dụng cho product.url, category.url, collection.url, page.url, article.url và item.product_url trong giỏ hàng.

Với thẻ bao quanh cả khối (ví dụ ảnh + tên nằm chung một liên kết), viết như sau để không phải lặp lại nội dung:

{% if product.url %}<a href="{{ product.url }}" class="card">{% else %}<span class="card">{% endif %}
  <img src="{{ product.cover_image_url }}" alt="{{ product.title }}">
  <span class="card__name">{{ product.title }}</span>
{% if product.url %}</a>{% else %}</span>{% endif %}

Đường dẫn cố định của website

Một số đường dẫn thuộc về website chứ không thuộc về một mục cụ thể. Những đường dẫn này viết thẳng trong giao diện:

Đường dẫn Trang
/ Trang chủ
/san-pham Danh sách sản phẩm
/tim-kiem?q=... Tìm kiếm
/flash-sale Trang flash sale
/bai-viet Danh sách bài viết
/gio-hang Giỏ hàng
/thanh-toan Thanh toán
/dang-nhap, /dang-ky, /dang-xuat Đăng nhập, đăng ký, đăng xuất
/tai-khoan, /tai-khoan/... Khu vực tài khoản khách

Lọc bài viết theo chuyên mục

Chuyên mục bài viết không có đường dẫn riêng; lọc bằng tham số truy vấn:

{% for cat in article_categories %}
  <a href="/bai-viet?danh-muc={{ cat.slug }}">{{ cat.title }}</a>
{% endfor %}

Đường dẫn phân cấp danh mục

Trang danh mục nhận sẵn biến breadcrumb, mỗi mắt xích có url riêng và cũng có thể null:

<nav class="breadcrumb">
  <a href="/">Trang chủ</a>
  {% for crumb in breadcrumb %}
    /
    {% if forloop.last %}
      <span>{{ crumb.title }}</span>
    {% elsif crumb.url %}
      <a href="{{ crumb.url }}">{{ crumb.title }}</a>
    {% else %}
      <span>{{ crumb.title }}</span>
    {% endif %}
  {% endfor %}
</nav>

Lọc sản phẩm trong trang danh mục

Trang danh mục nhận bảng lọc ở biến filters (CategoryFilterPanel) và trạng thái đang chọn ở active_filters. Danh mục không có đường dẫn riêng cho từng bộ lọc — mọi lựa chọn nằm ở chuỗi truy vấn của chính đường dẫn danh mục đó.

Tham số Lặp lại được Ý nghĩa
brand=<mã hãng> có Lọc theo hãng. Lấy mã từ filters.brands[].id.
attr=<mã thuộc tính>:<giá trị> có Lọc theo một giá trị thuộc tính. Lấy từ filters.attributes[].id và options[].value.
price=<mã khoảng giá> có Khoảng giá đặt sẵn. Lấy từ filters.prices[].id.
min_price, max_price không Khoảng giá tự nhập, đơn vị đồng.
sort=price_asc|price_desc|newest không Sắp xếp.
stock=in_stock|out_of_stock, warehouse_id không Lọc theo tồn kho. warehouse_id chỉ có tác dụng khi stock=in_stock.
cursor không Trang kế; luôn bỏ khi dựng liên kết bật/tắt bộ lọc.

Nhiều lựa chọn ghép với nhau thế nào

Mã lạ được bỏ qua chứ không báo lỗi: ?price=khong-co-that cho ra đúng kết quả như khi không lọc gì, và ?brand= với mã không thuộc danh mục này cũng vậy. Nhờ đó một liên kết cũ sau khi cấu hình lọc thay đổi vẫn mở được.

Dựng liên kết bật/tắt

active_filters là chính các tham số trên, đã bỏ cursor, và chỉ chứa khoá đang được đặt — nên active_filters rỗng nghĩa là "chưa lọc gì":

{% if active_filters %}
  <a href="{{ category.url }}">Xoá tất cả bộ lọc</a>
{% endif %}

{% for brand in filters.brands %}
  <a href="{{ category.url }}?brand={{ brand.id }}">{{ brand.title }}</a>
{% endfor %}

Số sản phẩm khớp bộ lọc nằm ở total_count, số còn chưa hiển thị nằm ở remaining_count:

<h1>{{ total_count }} {{ category.title }}</h1>
{% if has_more %}
  <a href="?cursor={{ next_cursor }}">Xem thêm {{ remaining_count }} sản phẩm</a>
{% endif %}