s_skaidocsTài liệu
LINGO REFERENCE

stack & push

Khai báo vị trí trong layout, gom CSS, script hoặc HTML từ các thành phần rồi chèn sau khi render hoàn tất.

Có sẵn · Lingo core & Theme runtime

stack — Vị trí chèn nội dung

stack nhận một ID cố định và không có thẻ đóng endstack. Tên có thể viết trực tiếp như head, style, script hoặc đặt trong dấu nháy. Tên chỉ chứa chữ cái không dấu, chữ số, dấu gạch dưới hoặc gạch ngang; không phải biểu thức hay biến.

layouts/main.html
<!doctype html>
<html lang="{{ doc.locale }}">
<head>
  {% block head %}{% endblock %}
  <title>{{ doc.title }}</title>
  {% stack head %}
  {% stack style %}
</head>
<body>
  {% block content %}{% endblock %}
  {% stack script %}
</body>
</html>

push — Bổ sung nội dung theo ID

push mở một vùng nội dung và đóng bằng endpush. Nội dung không xuất tại chỗ khai báo, mà được chuyển đến stack có cùng ID. Một stack có thể nhận nhiều push.

pages/products/index.html
{% extends "layouts/main.html" %}
{% block head %}
  {% doc title="Sản phẩm · Skai" %}
{% endblock %}
{% block content %}
  <section class="product-list">Danh sách sản phẩm</section>

  {% push style %}
    <style>.product-list { border-radius: 16px; }</style>
  {% endpush %}
  {% push script %}
    <script src="{{ asset('products.js') }}" defer></script>
  {% endpush %}
{% endblock %}
Push sau stack vẫn hoạt độngEngine render nội dung một lần, thu thập các push trong lần render hiện tại rồi thay thế vị trí stack ở bước cuối. Không lưu dữ liệu stack vào DB, không dùng chung giữa các request.

Khai báo push ngoài block

Page có extends có thể đặt push trực tiếp ngoài các block, trước hoặc sau phần khai báo block. Không cần tạo block riêng chỉ để nạp CSS/script.

PAGE KẾ THỪA LAYOUT
{% extends "layouts/main.html" %}
{% block content %}
  <h1>Sản phẩm</h1>
{% endblock %}

{% push script %}
  <script src="{{ asset('products.js') }}" defer></script>
{% endpush %}

Push ngoài block chạy sau khi layout và các block đã render. Với kế thừa nhiều tầng, chúng chạy từ template cha đến trang con, giữ thứ tự khai báo trong từng file. Biểu thức được đọc ở thời điểm thực thi push.

Điều kiện đặt bên trong pushChỉ push nằm trực tiếp ở cấp gốc của template con được thực thi thêm. Những node khác ngoài block vẫn bị bỏ qua; nếu cần if, for, set hoặc include, đặt chúng bên trong push.

Dùng trong section và include

File include có thể tự push tài nguyên cần dùng. Cơ chế này vẫn hoạt động với include ... only; only cô lập biến đầu vào, không tách stack của lần render.

sections/gallery.html
<div class="gallery">…</div>
{% push script %}
  <script src="{{ gallery_script }}" defer></script>
{% endpush %}

Gọi từ block content của page (không đặt dòng include này trong chính file gallery):

PAGE · BLOCK CONTENT

{% include "sections/gallery.html" with gallery_script=asset('gallery.js') only %}

Thứ tự và phạm vi thực thi

Mỗi lần render của request có object stack riêng; cùng ID script ở request khác không dùng chung nội dung. Runtime tự xóa tham chiếu dữ liệu khi render kết thúc hoặc lỗi, và không tái sử dụng object đã đóng. Bộ nhớ được Go GC thu hồi, không lưu DB hoặc cache toàn cục theo request ID.

  • Nhiều push cùng ID được nối theo thứ tự thực thi, không ghi đè và không tự loại trùng. Nếu include hai lần thì nội dung push cũng được thêm hai lần.
  • Stack không có push sẽ rỗng. Push không có stack tương ứng sẽ không xuất ra trang.
  • Nhiều vị trí stack cùng ID đều nhận cùng nội dung; tránh đặt trùng stack script nếu không muốn chạy script hai lần.
  • Với page kế thừa layout, push có thể nằm trong block được thực thi hoặc trực tiếp ngoài block. Push ngoài block được thêm sau các push từ layout và block. Block không được gọi hoặc bị ghi đè không tự phát sinh push.
  • Push trong nhánh if không chạy sẽ không được thu thập. Biến được đọc tại lúc thực thi push, không được đánh giá lại ở bước chèn.
  • Biến trong push vẫn được escape như template thông thường. Không dùng safe với dữ liệu người dùng chưa kiểm tra.
  • Cho phép stack lồng nhau khác ID; tham chiếu vòng trả lỗi. Nội dung thu thập và mở rộng có giới hạn an toàn 8 MiB, đồng thời chịu giới hạn của runtime.
  • Preview riêng section chỉ chèn vào những vị trí stack trong section đó. Preview toàn trang để xem CSS/script chèn vào layout.

Ví dụ đang áp dụng trong theme Folio

Folio dùng ba stack: head để chèn metadata bổ sung và JSON-LD; style để chèn stylesheet trong head; script để chèn script sau footer, trước thẻ đóng body. Cả layout chính và layout 404 đều có các vị trí này. Folio đã bỏ block head; khai báo doc thông thường nằm trực tiếp ngoài block. Metadata cần truy vấn hoặc điều kiện được xử lý trong block content.

FOLIO · pages/index.html (RÚT GỌN)
{% extends "layouts/main.html" %}
{% doc title="Skai Platform" %}
{% block content %}
  {% include "sections/home-01-hero-left-content.html" %}
  {% push script %}
    {% include "sections/home-scripts.html" %}
  {% endpush %}
{% endblock %}

Folio hiện push script riêng từ block content; cách này vẫn hoạt động. Bạn cũng có thể chuyển push ra trực tiếp ngoài block như ví dụ ở trên. Trang bài viết dùng push head cho dữ liệu có cấu trúc; metadata doc tiếp tục đi qua cơ chế SEO của runtime.

Phân biệt doc, block và stack

CƠ CHẾDÙNG CHO
docMetadata như title, description, canonical. Mỗi key chỉ giữ giá trị mới nhất.
block / endblockKhai báo vùng mà template con có thể thay thế trong layout kế thừa.
stack / pushGom nhiều đoạn HTML/CSS/script theo ID và chèn vào vị trí đã khai báo.

Không cần đổi block head thành stack. Có thể giữ block để thiết lập doc, dùng stack để nhận tài nguyên từ page và section. Runtime chèn stack trước bước chuẩn hóa SEO.