Rendering Blocks
This guide explains how Basker renders content blocks and the lifecycle of block rendering in your templates.
Block Rendering Overview
Section titled “Block Rendering Overview”When you use the {% stageblocks %} tag in a template, Basker:
- Retrieves the blocks array from the content object
- Iterates through each block
- Looks up the corresponding block template
- Renders each block with its data
- Wraps the output in a container div
{# In your template #}{% stageblocks page %}
{# Outputs #}<div class="content-blocks"> <!-- Rendered block 1 --> <!-- Rendered block 2 --> <!-- ... --></div>Block Template Resolution
Section titled “Block Template Resolution”For each block, the renderer determines which template file to use:
- Check for override - If a template override was specified in the stageblocks tag
- Use default path - Look for
blocks/[blockType].liquid
{# Default resolution #}{% stageblocks page %}{# Block type "hero" → blocks/hero.liquid #}{# Block type "feature-panel" → blocks/feature-panel.liquid #}
{# With override #}{% stageblocks page, hero:blocks/hero-large.liquid %}{# Block type "hero" → blocks/hero-large.liquid #}{# Block type "feature-panel" → blocks/feature-panel.liquid (default) #}Block Context
Section titled “Block Context”Each block template receives a block object containing:
| Property | Type | Description |
|---|---|---|
block.id | string | Unique identifier for this block instance |
block.blockType | string | The block type name |
block.[field] | any | Values for each field defined in the schema |
block.[field]_html | string | HTML output for richtext fields |
The block also has access to the parent template’s context, including global objects like settings, navigation, and content-specific objects.
{# blocks/hero.liquid #}<section id="{{ block.id }}" class="hero"> <h1>{{ block.heading }}</h1>
{# Access parent context #} {% if settings.header.show_cta %} <a href="{{ settings.header.cta_link }}">Learn More</a> {% endif %}</section>Special Block Types
Section titled “Special Block Types”Liquid Blocks
Section titled “Liquid Blocks”The liquidBlock type allows editors to write custom Liquid code directly in the CMS. The code is parsed and rendered inline:
<section id="[block-id]" class="element liquid-block"> <div class="liquid-block__inner"> <!-- Rendered liquid code --> </div></section>Reusable Content Blocks
Section titled “Reusable Content Blocks”The reusableContentBlock type references a shared content entry that contains its own blocks. These are rendered recursively:
<section id="[block-id]" class="element reusable-content-block"> <div class="reusable-content-block__inner"> <!-- Recursively rendered blocks from reusable content --> </div></section>Reusable content blocks have a maximum recursion depth of 10 to prevent infinite loops.
Rendering Flow
Section titled “Rendering Flow”┌─────────────────────────────────────────────────────────┐│ {% stageblocks page %} │└─────────────────────────────────────────────────────────┘ │ ▼┌─────────────────────────────────────────────────────────┐│ Get blocks array from page.blocks │└─────────────────────────────────────────────────────────┘ │ ▼┌─────────────────────────────────────────────────────────┐│ For each block: ││ ││ 1. Hydrate relationship data (navigation, media) ││ 2. Determine block type ││ 3. Find template (override or blocks/[type].liquid) ││ 4. Render template with block context ││ 5. Append output │└─────────────────────────────────────────────────────────┘ │ ▼┌─────────────────────────────────────────────────────────┐│ Wrap all output in <div class="content-blocks"> │└─────────────────────────────────────────────────────────┘Relationship Hydration
Section titled “Relationship Hydration”Before rendering, block data is “hydrated” - relationship fields are resolved to include their full data. This means:
- Media fields include all image properties (url, alt, dimensions, focal point)
- Page relationships include navigation data (title, relativePath, children)
- Content relationships include the linked content’s properties
{# The image field is automatically hydrated #}{% if block.image %} <img src="{{ block.image | image_url: width: 800 }}" alt="{{ block.image.alt }}" width="{{ block.image.width }}" height="{{ block.image.height }}" >{% endif %}
{# Page relationships include navigation data #}{% if block.linked_page %} <a href="{{ block.linked_page.relativePath }}"> {{ block.linked_page.title }} </a>{% endif %}Error Handling
Section titled “Error Handling”When a block fails to render, Basker outputs an HTML comment instead of breaking the page:
<!-- Error rendering block hero: Template not found -->This allows other blocks to continue rendering even if one fails.
Performance Considerations
Section titled “Performance Considerations”- Block count - Rendering many blocks increases page generation time
- Relationship depth - Deep relationship chains require more database queries
- Reusable content - Each reusable content block adds a database lookup
- Liquid blocks - Custom Liquid code is parsed on every request
Debugging Blocks
Section titled “Debugging Blocks”To debug block rendering issues:
- Check block type - Ensure the
blockTypematches your template filename - Verify template exists - The file must be at
blocks/[blockType].liquid - Inspect block data - Output
{{ block | json }}to see available data - Check for errors - Look for HTML comments in the output indicating render failures
{# Debug: output all block data #}<pre>{{ block | json }}</pre>
{# Debug: check block type #}<p>Block type: {{ block.blockType }}</p>