Skip to content

Template Inheritance Guide

Template inheritance is one of Miya Engine's most powerful features, allowing you to create reusable base templates and extend them with specific content.

Working Example: See examples/features/inheritance/ for a complete, working example.


Table of Contents

  1. Basic Concepts
  2. Creating a Base Template
  3. Extending Templates
  4. Using super()
  5. Best Practices
  6. Complete Example

Basic Concepts

What is Template Inheritance?

Template inheritance allows you to build a base "skeleton" template containing common elements, with blocks that child templates can override.

Key Components: - Base Template: Defines the overall structure with blocks - Child Template: Extends the base and overrides specific blocks - Blocks: Named sections that can be overridden - super(): Function to include parent block content

Syntax

{# base.html #}
{% block blockname %}
  default content
{% endblock %}

{# child.html #}
{% extends "base.html" %}
{% block blockname %}
  override content
{% endblock %}

Creating a Base Template

A base template defines the overall structure with placeholder blocks:

base.html:

<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}Default Title{% endblock %}</title>
    {% block extra_head %}{% endblock %}
</head>
<body>
    <header>
        {% block header %}
        <h1>Welcome</h1>
        {% endblock %}
    </header>

    <main>
        {% block content %}
        <!-- Main content goes here -->
        {% endblock %}
    </main>

    <footer>
        {% block footer %}
        <p>&copy; 2024 Company</p>
        {% endblock %}
    </footer>
</body>
</html>

Block Naming Best Practices: - Use descriptive names: header, content, sidebar, footer - Common blocks: title, extra_head, extra_css, extra_js - Be consistent across your application


Extending Templates

Child templates use {% extends %} to inherit from a base template:

page.html:

{% extends "base.html" %}

{% block title %}My Page Title{% endblock %}

{% block extra_head %}
<style>
    /* Page-specific styles */
    .highlight { color: blue; }
</style>
{% endblock %}

{% block content %}
<h2>Page Content</h2>
<p>This overrides the base template's content block.</p>
{% endblock %}

Important Rules

  1. {% extends %} must be the first tag in the child template
  2. Everything outside blocks is ignored in child templates
  3. Only defined blocks are overridden; undefined blocks keep base content
  4. Blocks can be nested within other blocks

Using super()

The {{ super() }} function includes the parent block's content:

Example:

{% extends "base.html" %}

{% block header %}
    {{ super() }}  {# Includes parent's <h1>Welcome</h1> #}
    <nav>Additional navigation</nav>
{% endblock %}

Output:

<header>
    <h1>Welcome</h1>
    <nav>Additional navigation</nav>
</header>

Use Cases for super()

  1. Appending to parent content:

    {% block navigation %}
        {{ super() }}
        <a href="/new-link">New Link</a>
    {% endblock %}
    

  2. Prepending to parent content:

    {% block footer %}
        <p>Additional info</p>
        {{ super() }}
    {% endblock %}
    

  3. Wrapping parent content:

    {% block content %}
        <div class="wrapper">
            {{ super() }}
        </div>
    {% endblock %}
    


Best Practices

1. Design Block Structure Carefully

Good block hierarchy:

{% block page %}
    {% block header %}...{% endblock %}
    {% block content %}
        {% block content_header %}...{% endblock %}
        {% block content_body %}...{% endblock %}
        {% block content_footer %}...{% endblock %}
    {% endblock %}
    {% block footer %}...{% endblock %}
{% endblock %}

2. Use Empty Blocks for Optional Content

{# Optional blocks that child templates can fill #}
{% block extra_css %}{% endblock %}
{% block extra_js %}{% endblock %}
{% block sidebar %}{% endblock %}

3. Provide Sensible Defaults

{% block title %}{{ site_name }} - Default Title{% endblock %}
{% block description %}Default site description{% endblock %}

4. Document Your Blocks

{# base.html #}

{# Block: page_title - Sets the browser title (required) #}
{% block page_title %}Default Title{% endblock %}

{# Block: content - Main page content (required) #}
{% block content %}{% endblock %}

{# Block: sidebar - Optional sidebar content #}
{% block sidebar %}{% endblock %}

5. Multi-Level Inheritance

You can chain inheritance multiple levels deep:

base.html
  └── layout.html (extends base.html)
       └── page.html (extends layout.html)

Example:

{# base.html - Foundation #}
{% block container %}
    {% block header %}{% endblock %}
    {% block content %}{% endblock %}
{% endblock %}

{# layout.html - Adds structure #}
{% extends "base.html" %}
{% block header %}
    <nav>{{ super() }}</nav>
{% endblock %}

{# page.html - Specific content #}
{% extends "layout.html" %}
{% block content %}
    <h1>My Page</h1>
{% endblock %}


Complete Example

Here's a complete working example from examples/features/inheritance/:

Base Template

base.html:

<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}Default Title{% endblock %}</title>
    {% block extra_head %}{% endblock %}
</head>
<body>
    <header>
        <h1>{% block header %}Welcome to Miya Engine{% endblock %}</h1>
        <nav>
            {% block navigation %}
            <a href="/">Home</a> | <a href="/about">About</a>
            {% endblock %}
        </nav>
    </header>

    <main>
        {% block content %}
        <p>This is the default content from the base template.</p>
        {% endblock %}
    </main>

    <aside>
        {% block sidebar %}
        <h3>Sidebar</h3>
        <p>Default sidebar content</p>
        {% endblock %}
    </aside>

    <footer>
        {% block footer %}
        <p>&copy; 2024 Miya Engine. All rights reserved.</p>
        {% endblock %}
    </footer>
</body>
</html>

Child Template

child.html:

{% extends "base.html" %}

{% block title %}{{ page_title }} - Miya Engine{% endblock %}

{% block extra_head %}
<style>
    body { font-family: Arial, sans-serif; }
    .highlight { color: #007bff; }
</style>
{% endblock %}

{% block header %}
{{ super() }} - Extended Edition
{% endblock %}

{% block navigation %}
{{ super() }} | <a href="/features">Features</a> | <a href="/docs">Docs</a>
{% endblock %}

{% block content %}
<h2>{{ page_title }}</h2>
<p>{{ description }}</p>

<h3>Key Features Demonstrated:</h3>
<ul>
    {% for feature in features %}
    <li class="highlight">{{ feature }}</li>
    {% endfor %}
</ul>
{% endblock %}

{% block sidebar %}
<h3>Quick Links</h3>
<ul>
    {% for link in quick_links %}
    <li><a href="{{ link.url }}">{{ link.title }}</a></li>
    {% endfor %}
</ul>

<h3>Original Sidebar</h3>
{{ super() }}
{% endblock %}

{% block footer %}
<p>Generated at: {{ timestamp }}</p>
{{ super() }}
{% endblock %}

Go Program

main.go:

package main

import (
    "fmt"
    "log"
    "time"

    "github.com/zipreport/miya"
    "github.com/zipreport/miya/loader"
)

func main() {
    // Create environment with filesystem loader
    templateParser := loader.NewDirectTemplateParser()
    fsLoader := loader.NewFileSystemLoader([]string{"."}, templateParser)
    env := miya.NewEnvironment(
        miya.WithLoader(fsLoader),
        miya.WithAutoEscape(false),
    )

    // Prepare context data
    ctx := miya.NewContext()
    ctx.Set("page_title", "Template Inheritance Showcase")
    ctx.Set("description", "Demonstrating template inheritance with extends, blocks, and super() calls.")
    ctx.Set("features", []string{
        "Template Extension ({% extends %})",
        "Block Definition and Override",
        "Super Calls ({{ super() }})",
        "Multi-level Inheritance",
    })
    ctx.Set("quick_links", []map[string]interface{}{
        {"title": "Documentation", "url": "/docs"},
        {"title": "Examples", "url": "/examples"},
    })
    ctx.Set("timestamp", time.Now().Format("2006-01-02 15:04:05"))

    // Render child template
    tmpl, err := env.GetTemplate("child.html")
    if err != nil {
        log.Fatal(err)
    }

    output, err := tmpl.Render(ctx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(output)
}

Running the Example

cd examples/features/inheritance
go run main.go

Common Patterns

Pattern 1: Multi-Page Website

templates/
  ├── base.html          # Main layout
  ├── pages/
  │   ├── home.html      # Extends base
  │   ├── about.html     # Extends base
  │   └── contact.html   # Extends base
  └── partials/
      ├── header.html
      └── footer.html

Pattern 2: Dashboard Layout

{# dashboard_base.html #}
{% extends "base.html" %}

{% block content %}
<div class="dashboard">
    <aside class="sidebar">
        {% block dashboard_sidebar %}{% endblock %}
    </aside>
    <main class="dashboard-content">
        {% block dashboard_content %}{% endblock %}
    </main>
</div>
{% endblock %}

{# specific_dashboard.html #}
{% extends "dashboard_base.html" %}
{% block dashboard_content %}
    <!-- Specific dashboard content -->
{% endblock %}

Pattern 3: Email Templates

{# email_base.html #}
<!DOCTYPE html>
<html>
<head>
    <style>
        {% block email_styles %}
        /* Base email styles */
        {% endblock %}
    </style>
</head>
<body>
    <div class="email-header">
        {% block email_header %}Logo{% endblock %}
    </div>
    <div class="email-body">
        {% block email_body %}{% endblock %}
    </div>
    <div class="email-footer">
        {% block email_footer %}Unsubscribe{% endblock %}
    </div>
</body>
</html>

Troubleshooting

Error: "Template Not Found"

Cause: The base template path is incorrect.

Solution:

// Make sure the loader can find the base template
fsLoader := loader.NewFileSystemLoader([]string{".", "templates"}, templateParser)

Error: "Block Undefined"

Cause: Trying to override a block that doesn't exist in the parent.

Solution: Check the parent template for the correct block name.

Empty Output

Cause: Content outside blocks in child templates is ignored.

Solution:

{#  This is ignored #}
<p>This content is outside any block</p>

{% block content %}
{#  This renders #}
<p>This content is inside a block</p>
{% endblock %}


See Also


Summary

Template Inheritance is Fully Supported in Miya Engine

Key Features: - {% extends %} - Inherit from base templates - {% block %} - Define overridable sections - {{ super() }} - Include parent content - Multi-level inheritance - Chain multiple templates - Nested blocks - Blocks within blocks

100% Jinja2 Compatible - All inheritance features work identically to Jinja2.