wabisoft / craft-bonsai-twig
Internal use template helper
Installs: 930
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 1
Forks: 0
Open Issues: 0
Type:craft-plugin
pkg:composer/wabisoft/craft-bonsai-twig
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
- 7.3.3
- 7.3.2
- 7.3.1
- 7.3.0
- 7.2.1
- 7.2.0
- 7.1.1
- 7.1.0
- 7.0.10
- 7.0.9
- 7.0.8
- 7.0.7
- 7.0.6
- 7.0.5
- 7.0.4
- 7.0.2
- 7.0.1
- 7.0.0
- v6.x-dev
- 6.4.0
- 6.3.0
- 6.2.1
- 6.2.0
- 6.1.2
- 6.1.1
- 6.1.0
- 6.0.3
- 6.0.2
- 6.0.1
- 6.0.0
- v5.x-dev
- 5.0.3
- 5.0.2
- 5.0.1
- 5.0.0
- v4.x-dev
- 4.0.1
- 4.0.0
- 1.0.2
- 1.0.1
- 1.0.0
- 0.0.1
- dev-feature/add-path-variable
- dev-feature/remove-cache
- dev-feature/overhaul-plugin
- dev-main
This package is auto-updated.
Last update: 2025-12-01 17:38:42 UTC
README
Welcome to the Bonsai Twig Plugin README! This plugin is designed as a development-only tool 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, matrix blocks, and assets with intelligent fallback mechanisms
- PHP 8.2 & Craft CMS 5 Optimized: Built with modern PHP features including null-safe operators and union types
- Simple Debug Tools: Clean, focused debugging that shows template paths and resolution without performance overhead
- Development-Focused: Designed specifically for development workflow - no production features or optimizations
- Enhanced btPath() Function: Returns complete HTML output with styling, eliminating need for manual Twig wrapping
- Zero Production Overhead: Debug features return empty strings in production mode
Pure Twig Equivalents
If you need to remove the plugin, see these guides for native Twig replacements:
- Entry Templates -
entryTemplates() - Category Templates -
categoryTemplates() - Item Templates -
itemTemplates() - Matrix Templates -
matrixTemplates() - Asset Templates -
assetTemplates() - Product Templates -
productTemplates()
Requirements
- PHP: 8.2.0 or higher
- Craft CMS: 5.0.0 or higher
Usage Guide
Core Template Functions
The plugin provides five 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 blockctxorcontext(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.
5. Asset Templates
{{ assetTemplates({ asset }) }}
Description: Loads templates for Craft asset elements with intelligent hierarchy based on volume, folder, and filename.
Parameters:
asset(Asset): The asset element to renderpath(string, optional): Custom template path override (defaults to 'asset')baseSite(string, optional): Base site handle for multi-site setups
Template Hierarchy:
The asset loader checks for templates in this order:
asset/{volume}/{folder}/{filename}- Most specific match for a particular fileasset/{volume}/{filename}- For assets in root of volume (no folder)asset/{volume}/{folder}/default- Default template for a specific folderasset/{volume}/default- Default template for the volumeasset/{volume}- Volume-level templateasset/default- Global fallback
Example Usage:
{# Basic asset rendering #} {{ assetTemplates({ asset: image }) }} {# Render images in a gallery #} {% for image in entry.gallery.all() %} {{ assetTemplates({ asset: image }) }} {% endfor %} {# Custom path #} {{ assetTemplates({ asset: document, path: 'downloads' }) }} {# Multi-site support #} {{ assetTemplates({ asset: image, baseSite: 'fr' }) }}
Example Template Structure:
For an asset with volume images, folder products/featured, filename hero.jpg:
templates/
asset/
images/
products/
featured/
hero.twig ← Matches specific file
default.twig ← Folder fallback
default.twig ← Volume fallback
default.twig ← Global fallback
Use Cases:
- Custom rendering for different asset types (images, videos, PDFs)
- Volume-specific templates (e.g., different rendering for "documents" vs "images")
- Folder-based organization (e.g., "products" vs "blog" assets)
- File-specific templates for important assets
6. Enhanced Template Path Display (btPath())
The btPath() function has been enhanced to provide complete HTML output with styling, eliminating the need for manual Twig wrapping. This is particularly useful for item and matrix templates where you need to quickly identify which template is being used.
Key Features:
- Complete HTML Output: Returns formatted HTML with styling instead of plain text
- Automatic Context Detection: Shows appropriate template type (Matrix, Entry, Category, Item)
- Zero Production Overhead: Returns empty string in production mode
- No Manual Wrapping: No need for conditional blocks or manual HTML
Enhanced Usage Examples
Simple Usage (New - Recommended)
Just call the function directly - it returns complete HTML:
{{ btPath() }}
This automatically outputs styled HTML like:
<div class="bt-debug-output" id="bt-debug-abc123"> <style> #bt-debug-abc123 { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; font-size: 12px; background: #1e1e1e; color: #d4d4d4; border: 1px solid #454545; border-radius: 6px; padding: 12px; margin: 8px 0; } /* Additional scoped styles... */ </style> <div class="bt-debug-header">Matrix Block Template</div> <ul class="bt-debug-list"> <li class="bt-debug-item bt-debug-item--missing">→ matrix/textBlock--hero.twig</li> <li class="bt-debug-item bt-debug-item--resolved">✓ matrix/textBlock.twig</li> <li class="bt-debug-item bt-debug-item--missing">→ matrix/default.twig</li> </ul> </div>
The output includes:
- A unique
idattribute to scope CSS and avoid conflicts - Inline
<style>block with scoped selectors - Dark theme styling for developer-friendly display
- Visual indicators: ✓ for resolved template, → for attempts
Legacy Usage (Manual Wrapping)
You can still manually wrap the output if needed, though it's no longer necessary:
{% if btPath() %}
<div class="custom-wrapper">
{{ btPath() }}
</div>
{% endif %}
Note: The legacy <pre class="bonsai-debug"> output format from earlier versions is no longer used. The current implementation uses the <div class="bt-debug-output"> wrapper with inline styles shown above.
HTML Comment Usage
For minimal visual impact:
<!-- {{ btPath() }} -->
Output Features
The enhanced btPath() automatically includes:
- Template Type Context: Shows "Matrix Block Template", "Entry Template", etc.
- Resolved Template Marking: The found template is marked with ✓
- Clean Styling: Simple, unobtrusive CSS styling
- Attempted Paths: All paths checked during resolution
Production Mode Behavior
In production mode (devMode = false), btPath() returns an empty string with zero overhead:
{{ btPath() }} <!-- Returns empty string in production -->
Debug Features
The plugin provides debugging tools that are only active in development mode (devMode = true).
Debug Mode
Keyboard Shortcut (Recommended)
Press Cmd+B (Mac) or Ctrl+B (Windows/Linux) to open the Beastmode options modal. This lets you select which template types to debug without manually editing the URL.
URL Parameter
Add ?beastmode to any URL to enable debug mode for all template types:
https://yoursite.test/some-page?beastmode
Or filter by specific types (comma-separated):
https://yoursite.test/some-page?beastmode=entry,matrix
Valid types: entry, category, item, matrix, asset, product, or all
Debug Information Display
When debug mode is active, you'll see clean debug output showing:
Template Resolution Information
- Template Paths: All attempted template paths in priority order
- Resolved Template: The template that was successfully loaded (marked with ✓)
- Template Type: Context information (Entry, Matrix, Category, Item)
The debug output focuses on essential information without performance metrics or complex styling.
Debug Examples
Entry Debug Example
{# Entry template with debug capability #} {# Add ?beastmode to URL to see template resolution info #} {{ entryTemplates({ entry }) }}
Category Debug Example
{# Category template with debug capability #} {# Add ?beastmode to URL to see template resolution info #} {{ categoryTemplates({ entry: category }) }}
Item Debug Example
{# Item template with debug capability #} {# Add ?beastmode to URL to see template resolution info #} {{ itemTemplates({ entry: item }) }}
Matrix Debug Example
{# Matrix template with debug capability #} {# Add ?beastmode to URL to see template resolution info #} {% for block in entry.matrixField.all() %} {{ matrixTemplates({ block: block }) }} {% endfor %}
Enhanced btPath() Debug Example
{# Enhanced btPath() - returns complete HTML output #} {{ btPath() }} {# Or use in HTML comments for minimal impact #} <!-- {{ btPath() }} -->
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:
- Type-Specific Templates: Templates based on element type and handle (e.g.,
entry/blog/article) - Style Variants: Style-based paths for items and matrix blocks (e.g.,
item/{section}/{style},matrix/style/{style}/{blockType}) - 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:
entry/blog/article/{slug}
entry/blog/article/_entry
entry/blog/{slug}
entry/blog/article
entry/blog/default
entry/blog
entry/article
entry/default
Note: The style parameter is passed to the template as a variable but does not change the entry path resolution. For style-aware path resolution, use itemTemplates() or matrixTemplates() instead.
Matrix Block Resolution
Matrix blocks have style-aware path resolution:
# For a matrix block of type 'textBlock' with style 'hero':
matrix/style/hero/textBlock
matrix/textBlock
matrix/default
Additional context-aware paths are available when using ctx, handle, or position parameters.
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.
Development-Only Focus
This plugin is designed specifically as a development tool and includes:
Simplified Architecture
- No Caching: Templates change frequently in development, so no caching overhead
- Direct File System Checks: Simple template existence checking without optimization layers
- Minimal Dependencies: Only essential services for template loading
- Straightforward Logic: Easy to understand and maintain codebase
Basic Security
- Path Sanitization: Basic path cleaning to prevent directory traversal
- Input Validation: Simple parameter type checking
- Safe Property Access: Uses null-safe operators for element properties
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
?beastmode=entry
?beastmode=entry,matrix
Or use the keyboard shortcut: Cmd+B / Ctrl+B
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 }) }}
Simplified Implementation
The simplified version focuses on reliability and maintainability:
- Straightforward Logic: Simple template resolution without complex optimization
- Reduced Complexity: Fewer moving parts means fewer potential issues
- Enhanced Debug Experience: Improved btPath() function with complete HTML output
- Zero Production Overhead: Debug features automatically disabled in production
PHP 8.2 Features
The plugin leverages essential modern PHP features:
- Null-safe operators for safer property access
- Union types for flexible parameter handling
- Enums for type-safe constants
Troubleshooting
Debug Mode Not Working
- Ensure
devMode = truein 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 - Verify your template directory structure matches the expected hierarchy
- Check file permissions on template directories
Template Resolution Issues
- Use debug mode to see which paths are being checked:
?beastmodeor?beastmode=entry,matrix - Use the enhanced
btPath()function in your templates to see resolution info - Consider simplifying complex template hierarchies
Support
For issues, feature requests, or questions:
- Check the debug information using
?beastmode - Use
{{ btPath() }}in your templates to see 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
- Simplified architecture focused on development workflow
- Enhanced btPath() function with complete HTML output
- Removed performance monitoring and caching complexity
- Streamlined debug tools for essential information only
- Development-only tool focus with zero production overhead