Developer docs  /  Themes

Wrapper & include contracts

{% include 'name' %} is resolved by ThemeFileProvider inThemeV2RenderService.cs against the in-memory file dictionary. A bare name(no folder) is looked up in this order:

  1. snippets/{name}.fluid
  2. partials/{name}.fluid
  3. sections/{name}.fluid

A name containing / (e.g. sections/cta) resolves as-is. .fluid /.liquid suffixes on the include name are stripped. A snippet thereforeshadows a partial or section of the same name — don't reuse names acrossfolders.

Snippets/partials do not get an isolated scope: an {% include %} sees thecaller's variables. That's why space-card reads a loop variable called itemand attribute-tile reads Attribute — the caller must assign those namesbefore including.

The section wrapper contract

Templates never call sections directly with hard-coded markup. Everysection-driven template (home, page, contact, attributes, and the tailof spaces / space-detail / location / locations) renders sections withthis exact loop:

{% for Section in Sections %}
{% if Section.IsVisible %}
<div data-alyta-section="{{ Section.Id }}" data-alyta-type="{{ Section.Type }}"{% if Section.HideOnMobile %} class="alyta-hide-mobile"{% endif %}{% include 'section-style' %}>
{% include Section.Type %}
</div>
{% endif %}
{% endfor %}

A custom theme must preserve this wrapper in its templates:

  • data-alyta-section="{{ Section.Id }}" — the builder's live preview targets sections by this attribute (section selection/highlighting).
  • data-alyta-type="{{ Section.Type }}" — identifies which section file rendered the block.
  • class="alyta-hide-mobile" — honours the per-section "hide on mobile" toggle (CSS in theme.css).
  • {% include 'section-style' %} — applies the shared style overrides (see the section-style snippet entry below). Without it the six override* settings the builder shows on every section do nothing.
  • Section.Type is the section file's base name (hero, cta, …), so {% include Section.Type %} resolves to sections/{type}.fluid.

Inside a section file the current section instance is available as Section(Section.Settings.*, Section.Blocks where each block has .Type and.Settings). Settings and default blocks are hydrated from the section's{% schema %} block by ThemeV2SectionHydrator before rendering, so asetting with a schema default is never missing at render time.

{% schema %} blocks

Each section ends with an inline {% schema %} … {% endschema %} JSON block.It is stripped before Fluid parsing (ThemeV2SchemaBlock.Strip) — it isbuilder metadata, not template code. The schema defines:

  • name — must match the file's base name (this is the section type),
  • label — the friendly name in the builder,
  • settings — the inspector fields (text, textarea, url, image, color, checkbox, select, range, number, plus the entity pickers space, categories, locations, attributes, attribute),
  • blocks / maxBlocks / defaultBlocks — repeatable content items.

AdminThemeV2Service.GetSectionSchemasAsync appends six shared style-overridesettings to every section schema at read time(ThemeV2SectionStyleOverrides.AppendTo): overrideTextScale,overrideTextColor, overrideHeadingColor, overrideBackgroundColor,overrideButtonColor, overrideButtonTextColor. Never declare these in yourown {% schema %} blocks — they arrive automatically, and thesection-style snippet is what applies them.

Render context cheat-sheet

Properties available to sections/snippets/partials (built inThemeV2RenderService.BuildRenderContextAsync):

  • OrganisationContents: Id, Name, Host, Logo, MainImage, SpaceName (tenant terminology, e.g. "Unit" — always pluralise with the plural filter)
  • PageContents: Slug, Title, Template
  • SettingsContents: Global settings (LogoUrl, FaviconUrl, PrimaryColor, MetaTitle…, AnnouncementEnabled/Text/Link/Background, social URLs, RecaptchaSiteKey, HidePricing, ShowBookOnline (default true), ShowGetQuote (default true), CustomCssCode, CustomHeadHtml) plus Settings.Design.* — a string dictionary populated from schema/settings.json ids (primaryColor, bodyFont, logoUrl, colorMode, …)
  • SectionsContents: Ordered, visible-filtered list of ThemeV2SectionInstance for the page key
  • LocationsContents: Active, non-hidden locations: Id, Name, Address (pre-joined string), PhoneNumber, EmailAddress, Image, Latitude, Longitude, Categories
  • CategoriesContents: Categories across locations (narrowed to the filtered location when one is active): Id, Name, Icon, Price, DurationType, Width, Length, Height
  • SpacesContents: Vacant active spaces (capped at 200), each: Id, UId, Name, Icon, CategoryId/Name, Price, DurationType, Status, Width/Length/Height/DoorHeight, AllowOnlineBookings, LocationId/Name, Medias[], Attributes[] (names), AttributeIds[], promotion fields (PromotionLabel, PromotionPrice, PromotionRuleType, PromotionRequiredAmount, PromotionDurationType)
  • Space / LocationContents: The single entity on detail routes; null elsewhere
  • AttributesContents: Org-wide attribute catalogue: Id, Name, SpaceCount
  • RequestContents: Path, BaseUrl, FilterLocationId/Name, FilterCategoryId/Name, FilterAttributeNames, IsEmbed
  • CmsPage / CmsPagesContents: Current/all CMS pages (Slug, Title, Content, meta fields)
  • MenusContents: Menus by Name — the theme looks for "MainMenu", "Footer", "TopBar"; items have Label, Url, IsActive, Children
  • Header / FooterContents: Builder-edited chrome content (Header.HideLoginButton, Header.LoginLabel, Header.TopBarEnabled; Footer.BusinessName/Address/Phone/Email/LogoUrl/LinkColumns + social URL overrides)

Custom Fluid filters registered by the renderer (all usable in any file):dollar, storefront_url, external_url, dateformat, asset_url, json,plural, cycle_abbrev, attr_icon, attr_icon_key, safe_video_url,multiply.

Two routing conventions matter to markup: internal storefront links arewritten as /t/... (or passed through | storefront_url, which prefixes/t onto site-relative URLs), and space detail links target the spaceUId, not the name (/t/spaces/{{item.UId}}) — names aren't unique.