{% 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:
snippets/{name}.fluidpartials/{name}.fluidsections/{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 intheme.css).{% include 'section-style' %}— applies the shared style overrides (see thesection-stylesnippet entry below). Without it the sixoverride*settings the builder shows on every section do nothing.Section.Typeis the section file's base name (hero,cta, …), so{% include Section.Type %}resolves tosections/{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 pickersspace,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):
Organisation— Contents:Id,Name,Host,Logo,MainImage,SpaceName(tenant terminology, e.g. "Unit" — always pluralise with thepluralfilter)Page— Contents:Slug,Title,TemplateSettings— Contents: Global settings (LogoUrl,FaviconUrl,PrimaryColor,MetaTitle…,AnnouncementEnabled/Text/Link/Background, social URLs,RecaptchaSiteKey,HidePricing,ShowBookOnline(default true),ShowGetQuote(default true),CustomCssCode,CustomHeadHtml) plusSettings.Design.*— a string dictionary populated fromschema/settings.jsonids (primaryColor,bodyFont,logoUrl,colorMode, …)Sections— Contents: Ordered, visible-filtered list ofThemeV2SectionInstancefor the page keyLocations— Contents: Active, non-hidden locations:Id,Name,Address(pre-joined string),PhoneNumber,EmailAddress,Image,Latitude,Longitude,CategoriesCategories— Contents: Categories across locations (narrowed to the filtered location when one is active):Id,Name,Icon,Price,DurationType,Width,Length,HeightSpaces— Contents: 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/Location— Contents: The single entity on detail routes; null elsewhereAttributes— Contents: Org-wide attribute catalogue:Id,Name,SpaceCountRequest— Contents:Path,BaseUrl,FilterLocationId/Name,FilterCategoryId/Name,FilterAttributeNames,IsEmbedCmsPage/CmsPages— Contents: Current/all CMS pages (Slug,Title,Content, meta fields)Menus— Contents: Menus byName— the theme looks for"MainMenu","Footer","TopBar"; items haveLabel,Url,IsActive,ChildrenHeader/Footer— Contents: 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.