vheissu / ci-twig
Twig templating integration for CodeIgniter 4
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 12
Watchers: 2
Forks: 6
Open Issues: 3
pkg:composer/vheissu/ci-twig
Requires
- php: ^8.1
- twig/twig: ^3.22
Requires (Dev)
- codeigniter4/framework: ^4.6
- pestphp/pest: ^3.0
- phpstan/phpstan: ^2.0
This package is auto-updated.
Last update: 2026-01-13 02:12:36 UTC
README
Twig templating integration for CodeIgniter 4.
Requirements
- PHP 8.1+
- CodeIgniter 4.6+
Installation
Step 1: Install via Composer
composer require vheissu/ci-twig
Step 2: Register the Service
Add the Twig service to your app/Config/Services.php:
<?php namespace Config; use CodeIgniter\Config\BaseService; class Services extends BaseService { public static function twig(bool $getShared = true): \Vheissu\CiTwig\Twig { if ($getShared) { return static::getSharedInstance('twig'); } return new \Vheissu\CiTwig\Twig(config('Twig')); } }
Step 3: Create Configuration (Optional)
Create app/Config/Twig.php to customize settings:
<?php namespace Config; use Vheissu\CiTwig\Config\Twig as BaseTwig; class Twig extends BaseTwig { public bool $debug = true; public array $functions = [ 'base_url', 'site_url', ]; }
That's it! You're ready to use Twig templates.
Quick Start
In Your Controller
<?php namespace App\Controllers; class Home extends BaseController { public function index() { // Load URL helper if using base_url(), site_url(), etc. helper('url'); $twig = service('twig'); return $twig->render('home', [ 'title' => 'Welcome', 'user' => $this->getUser(), ]); } }
Create a Template
Create app/Views/home.twig:
<!DOCTYPE html> <html> <head> <title>{{ title }}</title> </head> <body> <h1>{{ title }}</h1> <p>Hello, {{ user.name }}!</p> </body> </html>
Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
extension |
string | .twig |
Template file extension |
templatePaths |
array | [APPPATH . 'Views/'] |
Directories to search for templates |
cacheEnabled |
bool | false |
Enable compiled template caching |
cachePath |
string | WRITEPATH . 'cache/twig/' |
Cache directory |
debug |
bool | false |
Enable debug mode (enables dump()) |
autoReload |
bool | true |
Recompile templates when source changes |
autoescape |
string|bool | 'html' |
Auto-escape strategy ('html', 'js', false) |
functions |
array | [] |
PHP functions to expose in templates |
filters |
array | [] |
PHP functions to use as filters |
strictVariables |
bool | false |
Throw exception on undefined variables |
enableCiExtension |
bool | true |
Enable built-in CI4 helper functions |
modulePaths |
bool|array | true |
Auto-discover HMVC module view paths |
Production Configuration Example
<?php namespace Config; use Vheissu\CiTwig\Config\Twig as BaseTwig; class Twig extends BaseTwig { public bool $debug = false; public bool $cacheEnabled = true; public bool $autoReload = false; public array $functions = [ 'base_url', 'site_url', 'lang', ]; public array $filters = [ 'esc', ]; }
Usage
Rendering Templates
$twig = service('twig'); // Render and return as string $html = $twig->render('pages/about', ['title' => 'About Us']); // Render and output directly $twig->display('pages/about', ['title' => 'About Us']); // Extension is optional $twig->render('pages/about'); // Looks for pages/about.twig $twig->render('pages/about.twig'); // Same result // Render a string as a template $html = $twig->renderString('Hello, {{ name }}!', ['name' => 'World']);
Setting Variables
$twig = service('twig'); // Set a single variable $twig->set('title', 'My Page'); // Set multiple variables $twig->set([ 'title' => 'My Page', 'items' => ['one', 'two', 'three'], ]); // Set a global variable (persists across all renders) $twig->set('site_name', 'My Website', global: true); // Variables can also be passed directly to render() $twig->render('page', ['title' => 'Passed directly']);
Registering Custom Functions
$twig = service('twig'); // Register an existing PHP function $twig->registerFunction('strtoupper'); // Register with a custom callback $twig->registerFunction('asset', fn($path) => base_url("assets/{$path}")); // Use in template: {{ asset('css/style.css') }}
Registering Custom Filters
$twig = service('twig'); // Register an existing PHP function as a filter $twig->registerFilter('ucfirst'); // Register with a custom callback $twig->registerFilter('money', fn($n) => '$' . number_format($n, 2)); // Use in template: {{ price|money }}
Method Chaining
All methods return $this for fluent chaining:
return service('twig') ->set('title', 'Dashboard') ->set('user', $user) ->registerFunction('format_date', fn($d) => $d->format('M j, Y')) ->render('dashboard');
Template Syntax
CI-Twig uses standard Twig syntax.
Variables
{{ title }}
{{ user.name }}
{{ user.getEmail() }}
{{ items[0] }}
Control Structures
{% if user.isAdmin %}
<span class="badge">Admin</span>
{% endif %}
{% for item in items %}
<li>{{ item.name }}</li>
{% else %}
<li>No items found</li>
{% endfor %}
Template Inheritance
base.twig:
<!DOCTYPE html> <html> <head> <title>{% block title %}Default{% endblock %}</title> </head> <body> {% block content %}{% endblock %} </body> </html>
page.twig:
{% extends 'base.twig' %}
{% block title %}{{ page_title }}{% endblock %}
{% block content %}
<h1>{{ page_title }}</h1>
<p>{{ content }}</p>
{% endblock %}
Including Partials
{% include 'partials/header.twig' %}
{% include 'partials/nav.twig' with {'active': 'home'} %}
Built-in CI4 Functions
When enableCiExtension is true (default), these functions are available:
{# URLs - requires url helper loaded #} {{ base_url('assets/style.css') }} {{ site_url('users/profile') }} {{ current_url() }} {# Security #} {{ csrf_field() }} {{ csrf_token() }} {{ csrf_hash() }} {# Forms - requires form helper loaded #} {{ form_open('users/save') }} {{ form_input('email', old('email')) }} {{ form_close() }} {# Form validation #} {{ old('field_name', 'default') }} {{ validation_errors() }} {# Language #} {{ lang('App.welcome') }} {# Session #} {{ session('user_id') }} {# Environment #} {{ env('app.baseURL') }} {# Escaping #} {{ esc(user_input, 'html') }} {# Routing #} {{ route_to('users.show', user.id) }}
Debug Mode
When debug is true:
{{ dump(variable) }}
{{ dump() }} {# Dumps all available variables #}
HMVC / Module Support
CI-Twig automatically discovers module view paths. Templates in your modules are available without configuration:
app/
├── Modules/
│ └── Blog/
│ └── Views/
│ └── posts/
│ └── index.twig
// This works automatically $twig->render('posts/index');
Or manually specify module paths:
public array|bool $modulePaths = [ APPPATH . 'Modules/Blog/Views/', APPPATH . 'Modules/Shop/Views/', ];
Managing Template Paths
$twig = service('twig'); // Add a path to the search list $twig->addPath(APPPATH . 'Themes/default/'); // Prepend a path (searched first - useful for theme overrides) $twig->prependPath(APPPATH . 'Themes/custom/'); // Add a namespaced path $twig->addPath(APPPATH . 'Modules/Blog/Views/', 'blog');
Use namespaced templates:
{% include '@blog/sidebar.twig' %}
{% extends '@blog/layout.twig' %}
Advanced: Accessing Twig Directly
$twig = service('twig'); // Get the Twig\Environment instance $env = $twig->getEnvironment(); $env->addExtension(new MyCustomExtension()); // Get the Twig\Loader\FilesystemLoader $loader = $twig->getLoader();
Migrating from CI3
| CodeIgniter 3 | CodeIgniter 4 |
|---|---|
$this->load->library('twig') |
service('twig') |
$this->twig->parse('view', $data) |
service('twig')->render('view', $data) |
$this->twig->parse('view', $data, TRUE) |
service('twig')->render('view', $data) |
$this->twig->parse('view', $data, FALSE) |
service('twig')->display('view', $data) |
config/twig.php (array) |
app/Config/Twig.php (class) |
Development
The repository includes a test application for development:
# Install dependencies composer install # Run tests composer test # Run the test application cd testapp composer install php spark serve # Visit http://localhost:8080/twigdemo
License
MIT License. See LICENSE for details.
Credits
- Dwayne Charrington
- Twig by Symfony