Documentation Abizvo Sites themes Liquid, the theme check and the premium standard — written from the code that enforces them

Templates and pages

A site is pages; each page renders on a template; a template is a list of sections inside a layout. The platform decides which template a request renders, writes the head, wraps the sections in <main>, and places two things after everything the theme wrote.

Layouts

layouts/theme.liquid is required. A template may name another with "layout": "minimal" (layouts/minimal.liquid); one the theme lacks is an error. Every layout must output {{ content_for_header }} inside <head> and {{ content_for_layout }} in the body — both are errors when missing. A <title> of the layout's own is a warning (the platform writes it), and <html> without lang="{{ site.language }}" is a warning.

<!doctype html>
<html lang="{{ site.language }}">
  <head>
    {{ content_for_header }}
    {{ 'theme.css' | asset_url | stylesheet_tag }}
    {% style %} :root { --page-width: {{ settings.page_width }}px; } {% endstyle %}
    {{ 'theme.js' | asset_url | script_tag }}
  </head>
  <body class="color-scheme-1">
    <a class="skip-link" href="#MainContent">{{ 'accessibility.skip_to_content' | t }}</a>
    {% sections 'announcement' %}
    {% sections 'header' %}
    {{ content_for_layout }}
    {% sections 'footer' %}
  </body>
</html>

content_for_layout is <main id="MainContent" class="ab-main" role="main" tabindex="-1"> holding the template's sections in order; a skip link to #MainContent is what every theme ships.

What the platform writes in the head

content_for_header carries, in order:

  1. <meta charset> and the viewport.
  2. <meta name="theme-color"> — the background of the colour scheme the header group's section is drawn in, resolved through the theme's defaults, so a dark header meets a dark address bar. No header, and the theme's first scheme; no scheme group, or a colour that is not hex, and no tag at all.
  3. <title>: the page's search title if set; the site's name on the home page; otherwise {page title} · {site name}.
  4. <meta name="description"> when the page has one.
  5. On a public render, <link rel="canonical"> on the site's own address; on any other render, or a page marked no-index, <meta name="robots" content="noindex, nofollow">.
  6. Open Graph (og:type, og:site_name, og:title, og:url, og:description) and a Twitter card — summary_large_image with og:image when the page has a social picture, summary otherwise.
  7. A <link rel="preload"> for each web font in use (upright file).
  8. <style data-ab-platform>: the @font-face rules, :root font stacks, the .color-{scheme} classes, the platform utilities, the Powered-by rule and the motion runtime's start states.
  9. <link rel="stylesheet"> to the bundle of every section's and block's {% stylesheet %}, when any exists.
  10. <script type="application/json" id="abizvo-page"> with the page's facts for the platform's own scripts.
  11. abizvo-motion.js when any rendered animation asked for it or the manifest declares features.animations; the effects stylesheet and abizvo-effects.js only when a rendered effect asked for it.
  12. The bundle of every {% javascript %} — only where the theme's script may run.
  13. In the editor, the canvas bridge script and stylesheet.

Page templates

A page renders on the template its TemplateKey names. If that template is gone (an alternate deleted), the type's default (page.about → page) renders instead; if that is gone too, page.

Type Renders
home the site's home page — required
page any page — required; the default for a new page
contact recommended; conventionally business-info, a {% form 'contact' %} section and the booking-calendar
blog a blog's list (/{blog}, /{blog}/tagged/{tag}, ?page=n) from the blog global — blog.{handle} for one blog; optional, the platform lists the posts without it
article a blog's post (/{blog}/{post}) from the article global — article.{handle} for one blog; optional, the entry templates draw it without it
service, portfolio, custom pages the owner assigns them to
gallery the album page (below) — recommended
album reserved for album listings
entry a collection entry's page (below)
404 the not-found page — required
product every product's own page (/products/{handle}), from the product global — optional; without it the platform draws the page inside the theme's chrome
customers/login, customers/account, customers/order, customers/addresses the customer account pages on a site that sells (templates/customers/login.json…) — optional; each page without one stays the platform's. See Liquid
password the storefront password page (/password) — optional; usually with "layout": "password" (a layouts/password.liquid without the header and footer groups). Without it the platform draws a plain page of its own
cart the cart page (/cart) on a site that sells, from the cart global — optional; paying is always the platform's checkout step at cart.checkout_page_url
collection a product collection's own page (/collections/{handle}, /collections/all, /collections/vendors?q=, /collections/types?q=), from the collection global — optional; without it the theme has no collection pages and they answer its 404
list-collections the list of the business's product collections (/collections), from the product_collections global — optional; without it /collections is a page of the site's own at that address, if there is one, or the 404
search the search page (/search?q=…), from the search global — products and the site's own pages, with filters, orders and paginate like a collection (COM-022); optional, and a theme that ships it gets routes.search_url and a predictive fragment at /search/suggest from sections/predictive-search.liquid. Never a page the owner makes

An alternate template is {type}.{suffix}.json — page.about, entry.news. A page the owner creates on a theme site with no template chosen gets a template of its own, page.{slug}, copied from page, so the owner's sections on that page never leak to another page. The suffix is 1–48 lowercase letters, digits, hyphens and underscores.

The manifest's pages list is what a new site starts with: each names its template, exactly one is the home, and showInNavigation puts it in the menus.

The 404

An address the site does not have renders templates/404.json inside the theme's layout with a real 404 status, noindex, and a page titled "Page not found". It is where a booking link on a host that only serves the site would land if built by hand — which is why every booking address in a theme comes from the booking global, never from a path the theme writes.

Galleries and albums

The site's galleries come from the business's albums. albums lists them on every page (name, description, category, date, cover, counts, locked); the gallery template renders one album at /gallery/{albumId} with the gallery global — its items as photos and videos, the guest-code gate (unlocked, wrong_code, unlock_url), downloads (allow_downloads, download_url per item and for the whole album) and proofing (favorites: a visitor's list by name and email, favorite_url per item, send_url). A theme draws the locked state as a form posting to unlock_url and the favourites as plain links; the platform answers both.

A page rendered from the gallery template is no-store while it can carry a favourites list. MarketplaceThemesTests.Galleries_preserve_gates_downloads_and_proofing_in_both_languages holds every paid theme's gallery page to the gate, the downloads and the proofing in English and French.

Collections and entry pages

A collection is a site-level content type the owner defines — fields typed with the setting types, entries with a title, a slug and a published flag. Liquid reads collections[handle] anywhere, and a collection setting on a section lets the owner pick one. An entry's own page lives at /{collectionHandle}/{entrySlug} and renders on entry.{handle}.json when the theme (or the site) has one, else entry.json, else the platform draws the entry itself inside the theme's layout. On that page entry and collection are set, and an entry-body section is the conventional way to write entry.body.

A site has any number of menus, built by the owner under Website → Menus and read as linklists[handle] — three levels deep, so a header can draw drop-downs and a mega menu from link.links and link.links[].links. main and footer exist on every site: they are the pages marked for navigation until the owner customizes them. A section offers a menu through a link_list setting.

The business's store policies are pages of every theme site at /policies/{handle} (refund-policy, privacy-policy, terms-of-service, shipping-policy, contact-information), drawn by the platform inside the theme's layout. A footer lists them from shop.policies and draws the payment types the checkout takes from shop.payment_types with payment_type_svg_tag.

The storefront password page

An owner can keep a published site closed behind one shared password while it is not ready (Website → the site → Storefront password). A visitor without the password's cookie is sent from every page to /password, which draws the theme's password template — conventionally in its own layouts/password.liquid, with nothing of the site's menus or pages in it — or, for a theme without one, the platform's own plain page. The template reads the owner's message as shop.password_message and posts {% form 'storefront_password' %} with an input named password; a wrong one comes back as form.errors. A newsletter sign-up beside it ({% form 'newsletter' %}) still reaches the business. The right password sets an HttpOnly cookie for 30 days, scoped to the site, and a new password ends every grant. Every page of a closed site is no-store and noindex and the sitemap lists nothing; the editor's canvas and preview, and the owner signed in on the platform's /sites/… address, are never stopped. The platform's own cart, checkout and thank-you steps are not gated — a buyer coming back from paying must reach the thank-you.

What sits outside the theme

Two things are placed by the platform after everything the theme wrote, before </body>, so no template, section, setting, stylesheet or editor operation can move or remove them:

  • Powered by Abizvo — an <aside class="ab-powered" aria-label="Website platform"> with the mark and the words, on every page of every site in every mode. Its rules in the platform style carry !important. An aside rather than a second <footer>, so the page keeps one contentinfo landmark.
  • The chat button — when the site owner turns it on (off by default), the launcher and its own styles, never on the editor canvas or the owner's preview.

Both are outside the document a theme renders, and the platform's own rules for the Powered-by line outweigh a theme's stylesheet; a theme that tries to hide either will not pass review.

Forms

{% form 'contact' %} posts to the site itself (/sites/{slug}/forms/{sectionId[.blockId]}), per-visitor rate-limited, with a honeypot; the platform creates a lead for the business and emails it, then returns the visitor to the page with form.posted_successfully or form.errors set. The booking calendar is not a form: the booking global carries each open time's url into the platform's hold → details → confirm flow, on the platform's origin.

The editor's view

In the editor (request.design_mode) every section and block carries selection attributes, editable text is wrapped for inline editing, hidden sections still render (marked), an insertion point is written after each {% content_for 'blocks' %}, and a section that fails shows an error plate in place of nothing. Motion is off until the owner previews it. An edit re-renders one section in place, so a section must render correctly on its own — never depending on a sibling having rendered first.