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.
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):
$f3['layout']- Controller override (highest priority)theme.iniURL patterns - Centralized configuration?_bare=1- Bare template for debugging- 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
| Value | Description |
|---|---|
'*' | Content file is its own template (no wrapper) |
'templates/bare' | Minimal template without navigation |
'templates/template' | Default main template |
| Custom path | Any 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
| Mode | Description |
|---|---|
overwrite | Replace existing content (default) |
append | Add after existing content |
prepend | Add 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
You cannot specify templates from within view files because:
- Template selection happens before view rendering
- Views are rendered inside templates, not the other way around
- 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
- Use Controller Override for dynamic/conditional layouts
- Use theme.ini for static, route-based layouts
- Keep templates minimal - only include wrapper elements
- Use fragments for extensible sections (meta, style, script)
- Document custom templates in your team's coding standards