Templates and Layouts

The Fuwafuwa Framework uses a template system where content views are wrapped in layout templates. This promotes code reuse and maintains consistent page structure across your application.

Templates are the foundation of your application's user interface. They define the overall layout and structure of your pages, including headers, footers, navigation, and other common elements. Content views are then injected into these templates, providing the specific content for each page.

This approach allows you to create a consistent look and feel for your entire application without having to duplicate code. It also makes it easy to make changes to the overall layout - you only need to modify the template file, and all pages that use that template will update automatically.

Template Hierarchy
Layout Template (wrapper)
    └── Content View (your page)

Template Resolution Order

Fuwafuwa Framework uses a smart template resolution system that allows you to override the default template behavior in various ways. This system gives you full control over which template is used for each page, while still providing sensible defaults.

The template resolution order determines which template is selected when rendering a page. Templates are selected in this priority order (highest to lowest):

  1. $f3['layout'] - Controller override (highest priority)
  2. theme.ini URL patterns - Centralized configuration
  3. ?_bare=1 - Bare template for debugging
  4. Default template - Fallback to templates/template

Controller Override

The most powerful way to override the default template behavior is by setting $f3['layout'] in your controller. This allows you to dynamically select the template based on any condition or logic in your controller.

Controller overrides have the highest priority in the template resolution order, which means they will always take precedence over any other template configuration.

Set $f3['layout'] in your controller to override the template:

class MyController extends \Fuwafuwa\Controller {
    function execute(\Base $f3, string $action = ""): void {
        // Use bare template (no header/footer)
        $f3['layout'] = 'templates/bare';

        // Use custom template
        $f3['layout'] = 'templates/custom';

        // Content file is its own template (no wrapper)
        $f3['layout'] = '*';

        // ... rest of controller logic
    }
}

Special Values

ValueDescription
'*'Content file is its own template (no wrapper)
'templates/bare'Minimal template without navigation
'templates/template'Default main template
Custom pathAny template path relative to theme directory

Theme Configuration

For static, route-based template overrides, you can define URL-to-template mappings in themes/tailwind/theme.ini. This allows you to specify a specific template for a particular URL pattern without having to modify your controllers.

Theme configuration overrides have the second highest priority in the template resolution order, after controller overrides but before the default template.

Define URL-to-template mappings in themes/tailwind/theme.ini:

[theme.templates]
main = templates/template
bare = templates/bare

; RSS feeds use themselves as templates
templates/rss = *
templates/sitemap = *

; Specific routes
admin/config = templates/admin
user/profile = templates/simple

; Wildcard patterns
print/* = templates/print
api/* = templates/api

Query Parameter (Debugging)

For debugging purposes, you can use the ?_bare=1 query parameter to temporarily switch to the bare template. This can be helpful when troubleshooting layout issues or when you want to see just the content without any wrapper elements.

The query parameter override has the third highest priority in the template resolution order, after controller and theme configuration overrides but before the default template.

Add ?_bare=1 to any URL to use the bare template:

https://example.com/page?_bare=1

Template File Locations

themes/tailwind/
├── templates/
│   ├── template.html      (default main template)
│   ├── bare.html          (minimal template)
│   ├── admin.html         (admin panel template)
│   └── custom.html        (your custom template)
└── ...

Content Injection

Content injection is the mechanism by which content views are inserted into layout templates. This allows you to define the overall structure of your pages in the template and then inject specific content for each page.

Fuwafuwa uses the <f3:inject> tag to handle content injection. This tag allows you to inject content into specific fragments of your template, giving you full control over where each piece of content appears.

Content views inject into templates using <f3:inject>:

Template (template.html)

<!doctype html>
<html>
<head>
    <f3:fragment id="meta" tag="FALSE" />
    <f3:fragment id="style" tag="FALSE" />
</head>
<body>
    <nav><!-- navigation --></nav>

    <!-- Content is injected here -->
    <f3:fragment id="content" tag="FALSE" />
    <check if="{{ isset(@content_html) }}">{{@content_html | raw }}</check>

    <footer><!-- footer --></footer>

    <f3:fragment id="script" tag="FALSE" />
    <include href="{{@content}}" if="{{@content}}" />
</body>
</html>

Content View (my-page.html)

<f3:inject id="content">
    <h1>My Page Title</h1>
    <p>This is my page content.</p>
</f3:inject>

<f3:inject id="style" mode="append">
    <style>
        .custom { color: blue; }
    </style>
</f3:inject>

Injection Modes

ModeDescription
overwriteReplace existing content (default)
appendAdd after existing content
prependAdd before existing content

Common Use Cases

There are many practical uses for Fuwafuwa's template system. Here are some common scenarios where you might want to override the default template behavior:

Print-Friendly Pages

// Controller
$f3['layout'] = 'templates/print';
# Or in theme.ini
print/* = templates/print

API Responses (HTML)

// Controller for HTML API responses
$f3['layout'] = 'templates/api';

Modal/Popup Content

// Controller for modal content
$f3['layout'] = 'templates/bare';

Custom Admin Layout

class AdminController extends \Fuwafuwa\Controller {
    function beforeRoute(\Base $f3): void {
        parent::beforeRoute($f3);
        $f3['layout'] = 'templates/admin';
    }
}

View-Level Template Selection

⚠️ Not Possible

You cannot specify templates from within view files because:

  1. Template selection happens before view rendering
  2. Views are rendered inside templates, not the other way around
  3. The Theme::render() method decides the template first, then renders the content

This is an important architectural decision that ensures consistency and predictability in how templates are selected and used. It means that you must always define your template selection logic in your controllers or in the theme configuration file.

If you need different layouts based on content conditions, use the controller:

class MyController extends \Fuwafuwa\Controller {
    function execute(\Base $f3, string $action = ""): void {
        // Conditionally select template
        if ($someCondition) {
            $f3['layout'] = 'templates/custom';
        } else {
            $f3['layout'] = 'templates/bare';
        }
    }
}

Template Inheritance

Fuwafuwa supports template inheritance, which allows you to create base templates that are extended by other templates. This is a powerful way to reuse code and maintain consistency across your application.

With template inheritance, you define a base template that contains the common elements of your pages. Then, other templates can extend this base template and override specific sections as needed.

Templates can include other templates for composition:

<!-- templates/base.html -->
<f3:fragment id="content" tag="FALSE" />

<!-- templates/admin.html extends base -->
<include href="templates/base.html" />
<nav>Admin Navigation</nav>

Best Practices

  1. Use Controller Override for dynamic/conditional layouts
  2. Use theme.ini for static, route-based layouts
  3. Keep templates minimal - only include wrapper elements
  4. Use fragments for extensible sections (meta, style, script)
  5. Document custom templates in your team's coding standards