SMMFor

Code theme (Liquid)

Write your site in your own HTML, CSS and JavaScript; file structure, variables, filters, security rules and a complete example theme.

When to use it

Ready-made designs and the page builder cover most panels. If you want to design your storefront pixel by pixel, Admin → Code theme lets you write the home page and your own pages as Liquid templates.

A code theme only replaces storefront pages. Ordering, payments, sign-in/sign-up, the customer panel and the services page keep working as they are. Theme CSS variables, your custom CSS and custom code are still loaded on themed pages.

Files

FileAddressRole
layout.liquid—Wraps every themed page. The page goes in with {{ content_for_layout | raw }}. Required.
home.liquid/enHome page. Required.
about.liquid/en/aboutEvery {name}.liquid file is published at its own address
_card.liquid—Files starting with an underscore are partials; no address, used with {% render '_card' %}

Rules:

  • File names: lowercase letters, digits and dashes; a leading _ for partials; at most 42 characters + .liquid.
  • At most 40 files, at most 100 KB per file.
  • Reserved addresses (admin, dashboard, login, register, services, blog, api, api-docs, order, media…) can't be page files.
  • No separate CSS/JS/image files: write CSS in <style> and JavaScript in <script>; upload images to the Media library and use their /media/... URL.
  • Every file is parsed on save; syntax errors show the file name and the first line of the error.

Variables

VariableContent
site.name, site.url, site.logo, site.logo_darkPanel name, address, logos
site.locale, site.localesCurrent language and the panel's languages
site.support_email, site.telegramSupport email and Telegram link
user.logged_inWhether the visitor is signed in
user.email, user.name, user.balanceWhen signed in; balance as a USD number
nav.headerMenu items: list of { label, href }
catalog.groupsService groups: { name, slug, platform, services (count), categories: [{ name }] }
catalog.service_countTotal services on sale
blog.postsLatest posts: { title, excerpt, cover, url, date }
page.template, page.localeName of the rendered file and language
content_for_layoutOnly in layout.liquid: the rendered page

An undefined variable renders empty instead of failing.

Filters

All built-in Liquid filters (date, upcase, truncate, where, sort…) and tags (if, for, assign, capture, render…) are available. SMMFor adds three filters:

FilterExampleResult
t{{ 'nav.services' | t }}The panel's translated text in the visitor's language. Missing keys print the key itself.
url{{ '/services' | url }}Language-prefixed address: /en/services. https:// URLs are left as they are.
money{{ user.balance | money }}Formats a USD amount: $12.50

An unknown filter is an error (to catch typos).

Security rules

  • {{ }} output is HTML-escaped. Use | raw to print trusted HTML as-is.
  • Templates have no disk or network access; they can only render the theme's own files.
  • Each page has a time (250 ms) and memory limit.
  • Your <script> tags automatically get the site's security nonce; external scripts can be loaded through them. Inline event attributes like onclick="..." and javascript: links don't run; attach events with addEventListener.
  • Publishing and activating ask for your 2FA code (or admin password), because a theme can run scripts on your site.
  • If a page fails, the site doesn't crash; an error message is shown in place of that page.

Publishing

  1. Save draft: doesn't touch the site.
  2. Preview: opens the draft in a new tab with ?theme_preview=1. Only you (admin) see the draft.
  3. Publish: makes the draft the live version and adds it to the history (the last 20 versions are kept).
  4. Tick "Use the code theme on my site". The theme is shown only when it is published and active. Turn it off and the site immediately falls back to your block pages/design.
  5. Restore an earlier version: loads a past version into the draft; nothing changes on the site until you publish.

A published theme can stay cached for up to 60 seconds.

A complete example theme

These four files make a working theme with a menu, sign-in aware buttons, platform cards, blog posts, an FAQ and an About page. Colours come from the theme variables, so your Appearance colours apply here too.

layout.liquid

<div class="ct">
  <header class="ct-header">
    <a class="ct-brand" href="{{ '/' | url }}">
      {% if site.logo != blank %}<img src="{{ site.logo }}" alt="{{ site.name }}" height="32">{% else %}{{ site.name }}{% endif %}
    </a>
    <nav class="ct-nav">
      {% for item in nav.header %}<a href="{{ item.href }}">{{ item.label }}</a>{% endfor %}
      <a href="{{ '/services' | url }}">{{ 'nav.services' | t }}</a>
      <a href="{{ '/about' | url }}">About</a>
    </nav>
    <div class="ct-actions">
      {% if user.logged_in %}
        <span class="ct-balance">{{ user.balance | money }}</span>
        <a class="ct-btn" href="{{ '/dashboard/new-order' | url }}">{{ 'nav.dashboard' | t }}</a>
      {% else %}
        <a href="{{ '/login' | url }}">{{ 'nav.login' | t }}</a>
        <a class="ct-btn" href="{{ '/register' | url }}">{{ 'nav.register' | t }}</a>
      {% endif %}
    </div>
    <button class="ct-burger" type="button" aria-label="Menu">☰</button>
  </header>

  <main>{{ content_for_layout | raw }}</main>

  <footer class="ct-footer">
    <span>© {{ 'now' | date: '%Y' }} {{ site.name }}</span>
    {% if site.support_email != blank %}<a href="mailto:{{ site.support_email }}">{{ site.support_email }}</a>{% endif %}
    {% if site.telegram != blank %}<a href="{{ site.telegram }}">Telegram</a>{% endif %}
  </footer>
</div>

<style>
  .ct { max-width: 1160px; margin: 0 auto; padding: 20px 16px; color: var(--on-surface); }
  .ct-header { display: flex; align-items: center; gap: 20px; padding: 10px 0 28px; }
  .ct-brand { font: 800 20px/1 var(--font-family-display); display: flex; align-items: center; }
  .ct-nav { display: flex; gap: 18px; margin-left: 12px; }
  .ct-nav a, .ct-actions a { color: var(--on-surface-variant); font-weight: 600; }
  .ct-nav a:hover { color: var(--primary); }
  .ct-actions { margin-left: auto; display: flex; align-items: center; gap: 14px; }
  .ct-balance { font-weight: 700; color: var(--primary); }
  .ct-btn { background: var(--brand-solid); color: var(--on-brand) !important; padding: 10px 18px; border-radius: var(--radius-3xl); font-weight: 700; }
  .ct-burger { display: none; margin-left: auto; font-size: 22px; background: none; border: 0; color: inherit; }
  .ct-card { background: var(--surface-container-lowest); border: 1px solid var(--outline-variant); border-radius: var(--radius-2xl); padding: 20px; }
  .ct-footer { display: flex; flex-wrap: wrap; gap: 18px; margin-top: 72px; padding-top: 24px; border-top: 1px solid var(--outline-variant); color: var(--on-surface-variant); font-size: 14px; }
  @media (max-width: 760px) {
    .ct-nav, .ct-actions { display: none; }
    .ct-burger { display: block; }
    .ct.open .ct-nav, .ct.open .ct-actions { display: flex; flex-direction: column; align-items: flex-start; width: 100%; margin: 0; }
    .ct-header { flex-wrap: wrap; }
  }
</style>

<script>
  // Inline onclick doesn't run; use addEventListener.
  document.querySelector(".ct-burger")?.addEventListener("click", () => {
    document.querySelector(".ct")?.classList.toggle("open");
  });
</script>

home.liquid

<section class="hero">
  <p class="eyebrow">{{ catalog.service_count }} services · 24/7 support</p>
  <h1>Grow your accounts with {{ site.name }}</h1>
  <p class="lead">{{ 'landing.lead' | t }}</p>
  <div class="cta">
    <a class="ct-btn" href="{{ '/dashboard/new-order' | url }}">{{ 'landing.ctaPrimary' | t }}</a>
    <a href="{{ '/services' | url }}">Price list →</a>
  </div>
</section>

{% render '_platforms', catalog: catalog %}

{% if blog.posts.size > 0 %}
  <h2 class="title">From the blog</h2>
  <div class="grid">
    {% for p in blog.posts limit: 3 %}
      <a class="ct-card" href="{{ p.url }}">
        {% if p.cover != blank %}<img src="{{ p.cover }}" alt="" loading="lazy">{% endif %}
        <strong>{{ p.title }}</strong>
        <p>{{ p.excerpt | truncate: 120 }}</p>
      </a>
    {% endfor %}
  </div>
{% endif %}

<h2 class="title">FAQ</h2>
<details class="ct-card"><summary>When does my order start?</summary><p>Most services start within minutes.</p></details>
<details class="ct-card"><summary>How can I pay?</summary><p>Add funds by card, crypto or bank transfer.</p></details>

<style>
  .hero { text-align: center; padding: 56px 0 40px; }
  .hero h1 { font: 900 clamp(32px, 6vw, 56px)/1.08 var(--font-family-display); letter-spacing: -0.02em; }
  .eyebrow { color: var(--primary); font-weight: 700; text-transform: uppercase; letter-spacing: .12em; font-size: 12px; }
  .lead { max-width: 560px; margin: 16px auto 28px; color: var(--on-surface-variant); font-size: 18px; }
  .cta { display: flex; gap: 18px; justify-content: center; align-items: center; }
  .title { font: 800 26px/1.2 var(--font-family-display); margin: 56px 0 18px; }
  .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 16px; }
  .grid img { width: 100%; border-radius: var(--radius-xl); margin-bottom: 10px; }
  details.ct-card { margin-bottom: 10px; }
  details summary { cursor: pointer; font-weight: 700; }
</style>

_platforms.liquid

<section class="platforms">
  {% for group in catalog.groups limit: 8 %}
    <a class="ct-card platform" href="{{ '/services' | url }}#{{ group.slug }}">
      <strong>{{ group.name }}</strong>
      <span>{{ group.services }} services</span>
      <small>{% for c in group.categories limit: 3 %}{{ c.name }}{% unless forloop.last %} · {% endunless %}{% endfor %}</small>
    </a>
  {% endfor %}
</section>

<style>
  .platforms { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 14px; }
  .platform { display: flex; flex-direction: column; gap: 4px; transition: transform .15s; }
  .platform:hover { transform: translateY(-2px); border-color: var(--primary); }
  .platform span { color: var(--primary); font-weight: 700; }
  .platform small { color: var(--on-surface-variant); }
</style>

about.liquid

<section class="ct-card" style="max-width:760px;margin:24px auto">
  <h1 style="font:800 34px/1.15 var(--font-family-display)">About us</h1>
  <p>{{ site.name }} sells social media services at wholesale prices.</p>
  {% if user.logged_in %}
    <p>Welcome back {{ user.name | default: user.email }}! Your balance: <strong>{{ user.balance | money }}</strong></p>
  {% endif %}
</section>

This page is published at /en/about.

Common mistakes

SymptomCause / fix
HTML tags show up as textOutput is escaped. Use | raw for trusted HTML.
undefined filter: ...Typo in a filter name; only Liquid's filters plus t, url, money exist.
Template not found: _xThe partial doesn't exist or is named differently; don't write .liquid inside render.
A button does nothingInline onclick is blocked; use addEventListener.
Changes don't show on the siteDid you publish, and is "use the code theme" on? Wait a minute for the cache.
X: this address is used by the panelThe file name clashes with a reserved address; pick another name.