wabisoft / craft-bonsai-twig
Internal use template helper
Installs: 827
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 1
Forks: 0
Open Issues: 0
Type:craft-plugin
Requires
- php: >=8.2.0
- craftcms/cms: ^4.4|^5.0
Requires (Dev)
- craftcms/ecs: dev-main
- craftcms/phpstan: dev-main
- marcocesarato/php-conventional-changelog: ^1.16
- mockery/mockery: ^1.6
- phpunit/phpunit: ^10.0
README
Welcome to the Bonsai Twig Plugin README! This plugin is designed to streamline your Twig templating experience by providing hierarchical template loading for various element types in Craft CMS 5.
Features
- Hierarchical Template Loading: Automatically resolve templates for entries, categories, items, and matrix blocks with intelligent fallback mechanisms
- PHP 8.2 & Craft CMS 5 Optimized: Built with modern PHP features including enums, readonly properties, null-safe operators, and union types
- Enhanced Debug Tools: Comprehensive debugging with performance metrics, cache statistics, and template hierarchy visualization
- Type Safety: Full type safety with custom exceptions, value objects, and strict type declarations
- Performance Optimized: Advanced caching strategies, path deduplication, and performance monitoring
- Security Enhanced: Path sanitization, input validation, and protection against traversal attacks
Requirements
- PHP: 8.2.0 or higher
- Craft CMS: 5.0.0 or higher
Usage Guide
Core Template Functions
The plugin provides four main Twig functions for hierarchical template loading:
1. Entry Templates
{{ entryTemplates({ entry }) }}
Description: Loads templates for entry elements with intelligent hierarchy resolution.
Parameters:
entry
(Entry): The entry element to renderpath
(string, optional): Custom template path overridestyle
(string, optional): Style variant (forwarded to the template; does not alter Entry path resolution)context
(Element, optional): Additional context elementbaseSite
(string, optional): Base site handle for multi-site setupsvariables
(array, optional): Additional variables to pass to the template Example:
{# Basic usage #} {{ entryTemplates({ entry }) }} {# With custom path and style #} {{ entryTemplates({ entry: entry, path: 'custom/path', style: 'featured' }) }} {# With additional context #} {{ entryTemplates({ entry: entry, context: parentEntry, variables: { customVar: 'value' } }) }}
2. Category Templates
{{ categoryTemplates({ entry }) }}
Description: Loads templates for category elements (in Craft 5, categories are entries).
Parameters: Same as entryTemplates
Example:
{# Basic category rendering #} {{ categoryTemplates({ entry: category }) }} {# Category with style variant #} {{ categoryTemplates({ entry: category, style: 'card' }) }}
3. Item Templates
{{ itemTemplates({ entry }) }}
Description: Specialized template loading for nested entry relationships and complex hierarchies.
Parameters: Same as entryTemplates
Example:
{# Render related items #} {% for item in entry.relatedItems.all() %} {{ itemTemplates({ entry: item }) }} {% endfor %} {# Item with context awareness #} {{ itemTemplates({ entry: item, context: parentEntry, style: 'compact' }) }}
4. Matrix Templates
{{ matrixTemplates({ block }) }}
Description: Advanced template loading for Matrix blocks with style and context awareness.
Parameters:
block
(MatrixBlock): The matrix block to renderstyle
(string, optional): Style variant for the blockctx
orcontext
(Element, optional): Parent context elementloopIndex
(int, optional): Current loop iteration (0-indexed) for Twig loop variableloopLength
(int, optional): Total number of items in loop for Twig loop variablevariables
(array, optional): Additional variables to pass to the templatenext
(string, optional): Next block type for navigationprev
(string, optional): Previous block type for navigationisFirst
(bool, optional): Whether this is the first blockentry
(Entry, optional): Parent entry elementvariables
(array, optional): Additional template variables
Basic Example:
{# Simple matrix block rendering #} {% for block in entry.matrixField.all() %} {{ matrixTemplates({ block: block }) }} {% endfor %}
Advanced Example:
{# Advanced matrix with full context and loop variables #} {% if entry.matrixField|length %} {% set style = style ?? null %} {% for block in entry.matrixField.all() %} {{ matrixTemplates({ block: block, style: style, loopIndex: loop.index0, {# Pass current iteration (0-indexed) #} loopLength: loop.length, {# Pass total number of blocks #} ctx: entry, next: block.next.type ?? false, prev: block.prev.type ?? false, isFirst: loop.first, context: context|default('basic'), entry: entry, variables: { customData: customValue, sectionHandle: entry.section.handle, blockPosition: loop.index, totalBlocks: loop.length } }) }} {% endfor %} {% endif %}
Variables Parameter:
You can pass additional variables using either approach:
{# Approach 1: Direct parameters (backward compatible) #} {{ matrixTemplates({ block: block, customData: 'some value', sectionHandle: entry.section.handle }) }} {# Approach 2: Using variables parameter (recommended) #} {{ matrixTemplates({ block: block, loopIndex: loop.index0, loopLength: loop.length, variables: { customData: 'some value', sectionHandle: entry.section.handle, blockPosition: loop.index } }) }}
Both approaches make the variables available in your matrix template. The variables
parameter is useful for organizing custom data separately from system parameters.
Debug Features
The plugin provides comprehensive debugging tools that are only active in development mode (devMode = true
). Debug information is triggered using the beastmode
URL parameter.
Debug Modes
Universal Debug Parameter
Add ?beastmode
to any URL to enable debug mode for all template types:
https://yoursite.test/some-page?beastmode
This will show debug information for any Bonsai Twig function calls on that page.
Specific Debug Modes
You can specify different levels of debug information:
# Show template paths only
?beastmode=path
# Show template hierarchy
?beastmode=hierarchy
# Show full debug info with performance metrics
?beastmode=full
# Show all available debug information
?beastmode=all
Template-Specific Debug
Target specific template types for debugging:
# Debug only entry templates
?beastmode=entry
# Debug only matrix templates
?beastmode=matrix
# Debug only category templates
?beastmode=category
# Debug only item templates
?beastmode=item
Debug Information Display
When debug mode is active, you'll see a hover overlay with detailed information:
Template Resolution Hierarchy
- Template Paths: All attempted template paths in priority order
- Current Template: The template that was successfully loaded (highlighted in green)
- Missing Templates: Templates that were checked but not found (crossed out)
- Site-Specific Templates: Templates with site context (highlighted in blue)
Site Context Information
- Current Site: The site context for the current request
- Element Site: The site associated with the element being rendered
- Base Site: The base site for fallback resolution
- Fallback Site: Alternative site for template resolution
Performance Metrics
- Resolution Time: How long it took to resolve the template
- Memory Delta: Memory usage change during template resolution
- Paths Saved: Number of paths eliminated through optimization
- Resolution Checkpoints: Detailed timing for each resolution step
Cache Performance
- Hit Rate: Percentage of cache hits vs total requests
- Cache Statistics: Detailed breakdown by cache type
- Cache Status: Whether caching is enabled and why
Debug Examples
Entry Debug Example
{# Entry template with debug capability #} {# Entry Handler Add URL parameters to render debug info in devMode: - Show paths: ?beastmode=path - Show hierarchy: ?beastmode=hierarchy - Show all entry debug: ?beastmode=entry - Show everything: ?beastmode=all #} {{ entryTemplates({ entry }) }}
Category Debug Example
{# Category template with debug capability #} {# Category Handler Add URL parameters to render debug info in devMode: - Show paths: ?beastmode=path - Show hierarchy: ?beastmode=hierarchy - Show all category debug: ?beastmode=category - Show everything: ?beastmode=all #} {{ categoryTemplates({ entry: category }) }}
Item Debug Example
{# Item template with debug capability #} {# Item Handler Add URL parameters to render debug info in devMode: - Show paths: ?beastmode=path - Show hierarchy: ?beastmode=hierarchy - Show all item debug: ?beastmode=item - Show everything: ?beastmode=all #} {{ itemTemplates({ entry: item }) }}
Matrix Debug Example
{# Matrix template with debug capability #} {# Matrix Handler Add URL parameters to render debug info in devMode: - Show paths: ?beastmode=path - Show hierarchy: ?beastmode=hierarchy - Show all matrix debug: ?beastmode=matrix - Show everything: ?beastmode=all #} {% for block in entry.matrixField.all() %} {{ matrixTemplates({ block: block }) }} {% endfor %}
Suggested Minimum Usage
For the most common use cases, here are the recommended minimal implementations:
Basic Matrix Templates (Craft 4→5 Migration)
{# Replaces the old matrix include pattern #} {% for block in matrix.all() %} {{ matrixTemplates({ block: block, handle: handle ?? null, style: style ?? null }) }} {% endfor %}
This automatically resolves templates in this order:
matrix/handle/{handle}/{blockType}.twig
(if handle provided)matrix/style/{style}/{blockType}.twig
(if style provided)matrix/{blockType}.twig
(main template)matrix/default.twig
(fallback)
Simple Entry Templates
{# Basic entry rendering #} {{ entryTemplates({ entry: entry }) }} {# Entry with style variant #} {{ entryTemplates({ entry: entry, style: 'featured' }) }}
Basic Category Templates
{# Simple category rendering #} {{ categoryTemplates({ entry: category }) }}
Basic Item Templates
{# For related entries or nested content #} {% for item in entry.relatedItems.all() %} {{ itemTemplates({ entry: item }) }} {% endfor %}
Template Resolution
How Template Resolution Works
The plugin uses intelligent hierarchical template resolution that checks multiple paths in priority order:
- Site-Specific Templates: Templates in site-specific directories (e.g.,
_site1/entry/
) - Type-Specific Templates: Templates based on element type and handle (e.g.,
entry/blog/
) - Style Variants: Templates with style suffixes (e.g.,
entry/blog--featured.twig
) - Fallback Templates: Generic templates (e.g.,
entry/default.twig
)
Template Path Examples
For an entry with section handle blog
and type handle article
:
# Checked in this order:
templates/\_site1/entry/blog/article.twig
templates/entry/blog/article.twig
templates/\_site1/entry/blog/default.twig
templates/entry/blog/default.twig
templates/\_site1/entry/default.twig
templates/entry/default.twig
With a style parameter:
{{ entryTemplates({ entry: entry, style: 'featured' }) }}
Additional paths are checked:
templates/_site1/entry/blog/article--featured.twig
templates/entry/blog/article--featured.twig
templates/_site1/entry/blog/default--featured.twig
templates/entry/blog/default--featured.twig
Matrix Block Resolution
Matrix blocks have enhanced resolution with context awareness:
# For a matrix block of type 'textBlock' with style 'hero':
templates/_site1/matrix/textBlock--hero.twig
templates/matrix/textBlock--hero.twig
templates/_site1/matrix/textBlock.twig
templates/matrix/textBlock.twig
templates/_site1/matrix/default--hero.twig
templates/matrix/default--hero.twig
templates/_site1/matrix/default.twig
templates/matrix/default.twig
Integration with Craft 5
Unified Element Model
In Craft CMS 5, categories are now entries, which simplifies template handling. The plugin automatically handles this unification while maintaining backward compatibility.
Integration with Craft 5 render()
The plugin works alongside Craft 5's built-in render()
method. While render()
looks for templates in _partials/{elementType}/{elementName}.twig
, Bonsai Twig provides more sophisticated hierarchical resolution.
Craft 5 render():
{{ entry.render() }} {# Looks for _partials/entry/blog.twig #}
Bonsai Twig:
{{ entryTemplates({ entry }) }} {# Checks multiple hierarchical paths #}
You can use both approaches as needed - render()
for simple cases and Bonsai Twig for complex hierarchical template systems.
Performance Features
Caching
The plugin includes intelligent caching that:
- Caches template path resolution results
- Invalidates cache when templates change
- Provides cache statistics in debug mode
- Can be enabled in development mode via plugin settings
Optimization
- Path Deduplication: Eliminates duplicate template paths before checking
- Early Exit: Stops checking once a template is found
- Batch Operations: Groups file system operations for efficiency
- Memory Management: Uses generators for large template lists
Security Features
- Path Sanitization: Prevents directory traversal attacks
- Input Validation: Validates all user-provided parameters
- Safe Property Access: Uses null-safe operators throughout
- Secure Caching: Uses secure hashing for cache keys
Migration Guide
Upgrading from Previous Versions
The plugin maintains full backward compatibility, but you can take advantage of new features:
Enhanced Debug Parameters
Old way:
?showEntryPath=true&showEntryHierarchy=true
New way (recommended):
?beastmode=entry
?beastmode=full
Template Function Signatures
All existing function signatures remain unchanged:
{# These continue to work exactly as before #} {{ entryTemplates({ entry }) }} {{ categoryTemplates({ entry }) }} {{ itemTemplates({ entry }) }} {{ matrixTemplates({ block }) }}
New Optional Parameters
You can now use additional parameters for enhanced functionality:
{# New optional parameters #} {{ entryTemplates({ entry: entry, style: 'featured', # New: style variants context: parentEntry, # New: context awareness variables: { key: value } # New: additional variables }) }}
Performance Improvements
The enhanced version provides significant performance improvements:
- Up to 50% faster template resolution through path optimization
- Reduced memory usage with generator-based path handling
- Intelligent caching reduces file system operations
- Early exit strategies stop checking once templates are found
New PHP 8.2 Features
The plugin now leverages modern PHP features:
- Readonly properties for immutable configuration
- Null-safe operators for safer property access
- Union types for flexible parameter handling
- Enums for type-safe constants
- Named parameters for clearer method calls
Troubleshooting
Debug Mode Not Working
- Ensure
devMode = true
in your Craft configuration - Check that you're using the correct URL parameter:
?beastmode
- Verify the plugin is installed and enabled
Templates Not Found
- Use debug mode to see which paths are being checked:
?beastmode=hierarchy
- Verify your template directory structure matches the expected hierarchy
- Check file permissions on template directories
Performance Issues
- Enable caching in plugin settings for development mode testing
- Use debug mode to check resolution times:
?beastmode=full
- Consider simplifying complex template hierarchies
Cache Issues
- Clear Craft's template cache:
./craft clear-caches/compiled-templates
- Check cache statistics in debug mode:
?beastmode=full
- Verify cache permissions in the storage directory
Support
For issues, feature requests, or questions:
- Check the debug information using
?beastmode=full
- Review the template resolution hierarchy
- Verify your template structure matches the expected patterns
- Check Craft and PHP version compatibility
Changelog
Version 6.4.0
- Full Craft CMS 5 compatibility
- PHP 8.2 feature utilization
- Enhanced debug tools with performance metrics
- Improved caching strategies
- Security enhancements
- Type safety improvements
- Comprehensive test coverage