vheissu / ci-smarty
Smarty 5 template engine integration for CodeIgniter 4
Requires
- php: ^8.1
- smarty/smarty: ^5.8.4
Requires (Dev)
- codeigniter/phpstan-codeigniter: ^1.5
- codeigniter4/framework: ^4.5
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^10.5 || ^11.2
Suggests
None
Provides
None
Conflicts
- codeigniter4/framework: <4.5
Replaces
None
This package is not auto-updated.
Last update: 2026-09-26 22:23:08 UTC
README
Use Smarty 5 templates in CodeIgniter 4 applications.
Requirements
- PHP 8.1 or newer
- CodeIgniter 4.5 or newer
- Smarty 5.8.4 or newer (installed for you by Composer)
Looking for the CodeIgniter 3 version? It is tagged v3.0.0 and is no longer updated.
Installation
composer require vheissu/ci-smarty
CodeIgniter finds the package's config, service and helper on its own, as long as Composer package discovery is on (it is by default in app/Config/Modules.php).
Smarty writes compiled templates to writable/smarty/, so that folder needs to be writable by your web server. It's created on first use.
Rendering templates
Put templates in app/Views with a .tpl extension and render them with the smarty() helper, which works like CodeIgniter's view():
namespace App\Controllers; class Blog extends BaseController { public function show(int $id): string { helper('smarty'); return smarty('blog/show', [ 'post' => model('PostModel')->find($id), ]); } }
{* app/Views/blog/show.tpl *} {extends file="layout.tpl"} {block name=title}{$post.title}{/block} {block name=body} <h1>{$post.title}</h1> {$post.body_html nofilter} {/block}
Add 'smarty' to $helpers in BaseController if you'd rather not call helper('smarty') every time.
The renderer is also available as a service. It implements CodeIgniter's RendererInterface, so setData(), setVar(), render() and renderString() behave the way they do on the built-in view renderer:
$smarty = service('smarty'); $smarty->setVar('user', $user) ->setData(['title' => 'Account']); return $smarty->render('account/index');
getSmarty() returns the underlying Smarty\Smarty object when you need something this package doesn't wrap, such as registering your own plugins or clearing caches.
Escaping
Every {$variable} is HTML-escaped. To print markup you trust, use nofilter:
{$comment} {* escaped *} {$trusted_html nofilter} {* printed as-is *}
You can switch this off with $escapeHtml = false, but then every template has to escape its own output, and one missed |escape is an XSS hole.
Namespaced views
Views inside modules or packages are loaded by namespace, the same way CodeIgniter loads them:
return smarty('Acme\Blog\Views\post', $data);
A namespaced template can {extends} and {include} other templates from its own Views folder.
Configuration
Create app/Config/Smarty.php and override whatever you need:
<?php namespace Config; use Vheissu\CiSmarty\Config\Smarty as BaseSmarty; class Smarty extends BaseSmarty { public ?string $theme = 'default'; public bool $compileCheck = ENVIRONMENT !== 'production'; }
| Option | Default | What it does |
|---|---|---|
extension |
'tpl' |
Added to template names that don't have an extension. |
templateDirectories |
[APPPATH . 'Views'] |
Where templates are looked up, in order. |
compileDirectory |
WRITEPATH . 'smarty/compiled' |
Compiled templates. Must be writable. |
cacheDirectory |
WRITEPATH . 'smarty/cache' |
Cached output. Must be writable. |
configDirectories |
[] |
Folders {config_load} reads from. |
extensions |
[] |
Class names of Smarty extensions to register. |
registerHelpers |
true |
Register the template functions listed below. |
escapeHtml |
true |
Escape every {$variable}. |
securityPolicy |
Smarty\Security::class |
Security policy class, or null for none. |
caching |
false |
Cache the output of every template. See Caching. |
cacheLifetime |
3600 |
Default cache lifetime in seconds. |
compileCheck |
true |
Recompile a template when its source changes. |
forceCompile |
false |
Recompile on every request. For debugging only. |
debugging |
false |
Show the Smarty debug console. Never enable this in production. |
errorReporting |
null |
Error level while templates run. null keeps PHP's. |
muteUndefinedOrNullWarnings |
false |
Treat undefined variables as null instead of warning. |
saveData |
true |
Keep variables between renders, like Config\View::$saveData. |
theme |
null |
Active theme. See Themes. |
themeDirectory |
ROOTPATH . 'themes' |
Where theme templates live. |
themeAssetsPath |
'themes' |
Public path, under base_url(), for theme assets. |
Themes
A theme is a folder of templates that override the ones in app/Views. If a theme doesn't have a template, the one in app/Views is used, so a theme only needs the files it changes.
Theme templates and theme assets are kept apart so templates are never served straight from the web root:
themes/
dark/
layout.tpl overrides app/Views/layout.tpl
public/
themes/
dark/
css/app.css
js/app.js
img/logo.png
Set the theme in app/Config/Smarty.php, or switch it per request:
service('smarty')->setTheme('dark'); service('smarty')->setTheme(null); // back to app/Views only
Theme names may only contain letters, numbers, dashes and underscores. Anything else throws an InvalidArgumentException, so it is safe to set a theme from a user preference.
Template functions
These tags print HTML. File names are relative to the active theme's css, js or img folder. Full https:// or // URLs are used unchanged. Any other attribute you pass is added to the tag and escaped. true prints a bare attribute, and false leaves the attribute out.
{css file="app.css"} {css file="print.css" media="print"} {js file="app.js" defer=true} {img file="logo.png" alt="Acme" class="brand"} {csrf_field}
These functions return values, so you can use them anywhere a variable can go. Their output is escaped like any other value:
<a href="{site_url('blog')}">Blog</a> <a href="{route_to('Blog::show', $post.id)}">{$post.title}</a> <img src="{base_url('uploads/')}{$photo.file}" alt=""> <link rel="preload" href="{theme_url('fonts/body.woff2')}" as="font"> <p>{lang('App.welcome')}</p> <meta name="{csrf_token()}" content="{csrf_hash()}">
Set $registerHelpers = false if you don't want any of them.
Caching
Output caching is off unless you ask for it. When a template is cached, Smarty returns the cached output without running the template, so every visitor gets the same page. Always give each variation of a page its own cache_name:
return smarty('blog/show', ['post' => $post], [ 'cache' => 300, // seconds 'cache_name' => 'post|' . $post['id'], ]);
{csrf_field} is never cached. Wrap other per-visitor output in {nocache}...{/nocache}.
To clear caches, use the Smarty object: service('smarty')->getSmarty()->clearAllCache().
Security
- Smarty's security policy is on by default. Templates can only load files from the template, theme and config directories. For a stricter policy (limiting tags, modifiers or static class access), extend
Smarty\Securityand set$securityPolicyto your class. - Never pass user input to
renderString()as the template. A template can run code on your server. Pass user input as data, where it is escaped. renderString()stores a compiled copy of each distinct string in the compile directory. Don't render an endless stream of unique strings.- View names containing
..are rejected. - If you turn off
compileCheckin production, emptywritable/smarty/compiledon every deploy, or old templates will keep being served.
Upgrading from the CodeIgniter 3 version
The 4.x release is a rewrite for CodeIgniter 4 and Smarty 5. It's installed with Composer, and Smarty is no longer bundled in the repository.
$this->parser->parse('view', $data)becomessmarty('view', $data)orservice('smarty')->render('view'). The third argument ($return) is gone, because CodeIgniter 4 controllers return their output.parse_string()andstring_parse()becomerenderString().- Variables are now escaped by default. Add
nofilterwhere a template printed HTML on purpose. - Caching used to be on by default, with a one-hour lifetime. That served one visitor's page to everyone else for an hour. It's now off. See Caching if you want it back.
{$this}is no longer assigned. Pass templates the data they need.- The CodeIgniter 3 helpers
userdata(),flashdata()anduriseg()are gone. Pass those values in as data. {css('app.css')}becomes{css file="app.css"}, and the same goes forjsandimg.- Themes no longer load a
functions.php. Register plugins through$extensionsorgetSmarty()instead. - Theme templates move out of
public/intothemes/<name>/at the project root, and there is noviews/subfolder. Assets stay inpublic/themes/<name>/. - The
MY_Parser,MY_OutputandCI_Smartyclasses are gone. - Smarty 5 itself changed a lot compared with Smarty 3. Read its upgrade notes, particularly the part about calling PHP functions from templates, which now requires registering them.
Development
composer install composer test # PHPUnit composer analyze # PHPStan
License
MIT. See LICENSE.