75 template plugins for XOOPS — covering user access, UI components, text processing, formatting, security, SEO, and more. All self-contained, zero external dependencies, compatible with Smarty 4 and Smarty 5.
- PHP 8.2+
- Smarty 4.x or 5.x
- XOOPS CMS 2.5.x (for
xo_*plugins; other plugins work standalone)
Place the smarty4_plugins/ directory at htdocs/class/smarty4_plugins/ and add one line to
htdocs/class/template.php after the existing smarty3_plugins registration:
$this->addPluginsDir(XOOPS_ROOT_PATH . '/class/smarty3_plugins');
$this->addPluginsDir(XOOPS_ROOT_PATH . '/class/smarty4_plugins'); // add thisDrop this file at htdocs/preloads/smarty4plugins.php:
<?php
declare(strict_types=1);
class Smarty4pluginsPreload extends XoopsPreloadItem
{
public static function eventCoreClassTemplateNew(array $args): void
{
$tpl = $args[0];
$dir = XOOPS_ROOT_PATH . '/class/smarty4_plugins';
if (\is_dir($dir)) {
$tpl->addPluginsDir($dir);
}
}
}Both approaches register the directory after the core smarty3_plugins, so core plugins always take precedence if names overlap.
After either method, clear compiled templates (XOOPS_VAR_PATH/caches/smarty_compile/).
Functions for accessing XOOPS users, config, modules, permissions, and notifications directly from templates.
| Plugin | Type | Usage |
|---|---|---|
xo_get_current_user |
function | <{xo_get_current_user assign="user"}> |
xo_get_config |
function | <{xo_get_config name="sitename" assign="val"}> |
xo_get_module_info |
function | <{xo_get_module_info dirname="news" assign="mod"}> |
xo_get_notifications |
function | <{xo_get_notifications assign="notifs"}> |
xo_render_block |
function | <{xo_render_block options=$blockOptions}> |
xo_render_menu |
function | <{xo_render_menu module="news"}> |
xo_avatar |
function | <{xo_avatar uid=$userId size=64}> |
xo_module_url |
function | <{xo_module_url module="news" path="article.php"}> |
xo_debug |
function | <{xo_debug var=$data label="Debug"}> |
is_user_logged_in |
function | <{if <{is_user_logged_in}>}> |
has_user_permission |
function | <{if <{has_user_permission permission="module_admin"}>}> |
user_has_role |
function | <{if <{user_has_role role="1"}>}> |
xo_permission |
block | <{xo_permission require="module_admin"}>...<{/xo_permission}> |
Bootstrap 5-compatible HTML output for common interface elements.
| Plugin | Type | Usage |
|---|---|---|
render_breadcrumbs |
function | <{render_breadcrumbs items=$breadcrumbs}> |
render_pagination |
function | <{render_pagination totalPages=10 currentPage=3 urlPattern="?p={page}"}> |
render_alert |
function | <{render_alert message="Saved!" type="success" dismissible=true}> |
render_form_errors |
function | <{render_form_errors errors=$errors}> |
create_button |
function | <{create_button label="Save" type="submit" class="btn btn-primary" icon="bi-check"}> |
embed_pdf |
function | <{embed_pdf url="document.pdf" height="600"}> |
render_qr_code |
function | <{render_qr_code text="https://xoops.org" size=200}> |
Form helpers with automatic XOOPS CSRF token injection.
| Plugin | Type | Usage |
|---|---|---|
form_open |
function | <{form_open action="save.php" method="post" class="needs-validation"}> |
form_close |
function | <{form_close}> |
form_input |
function | <{form_input type="text" name="title" value=$title class="form-control"}> |
generate_csrf_token |
function | <{generate_csrf_token}> |
form_open automatically injects the XOOPS CSRF token for POST forms. form_input passes through any HTML attribute.
| Plugin | Type | Usage |
|---|---|---|
validate_email |
function | <{if <{validate_email email=$email}>}> |
validate_form |
function | <{validate_form data=$formData rules=$rules assign="errors"}> |
validate_csrf_token |
function | <{if <{validate_csrf_token}>}> |
validate_form rules: ['field' => ['required' => true, 'min_length' => 3, 'max_length' => 255, 'email' => true, 'numeric' => true]]
| Plugin | Type | Usage |
|---|---|---|
slugify |
modifier | <{$title|slugify}> |
excerpt |
modifier | <{$text|excerpt:150}> — character-based, word-boundary aware |
truncate_words |
modifier | <{$text|truncate_words:20}> — word-count based |
highlight_text |
modifier | <{$content|highlight_text:$query}> |
linkify |
modifier | <{$text|linkify}> — adds rel="noopener noreferrer nofollow" |
obfuscate_text |
modifier | <{$email|obfuscate_text}> — HTML entity encoding |
pluralize |
modifier | <{$count|pluralize:"comment":"comments"}> |
extract_hashtags |
modifier | <{$text|extract_hashtags assign="tags"}> |
nl2p |
modifier | <{$content|nl2p}> — double newlines to <p>, single to <br> |
reading_time |
modifier | <{$text|reading_time}> — "3 min read" |
| Plugin | Type | Usage |
|---|---|---|
relative_time |
modifier | <{$date|relative_time}> — "3 hours ago" |
format_date |
modifier | <{$date|format_date:"M d, Y"}> — accepts strings or timestamps |
datetime_diff |
function | <{datetime_diff start=$a end=$b format="%d days" assign="diff"}> |
| Plugin | Type | Usage |
|---|---|---|
format_currency |
modifier | <{$price|format_currency:"USD":"en_US"}> — ICU with fallback |
number_format |
modifier | <{$n|number_format:2:".":","> |
format_phone_number |
modifier | <{$phone|format_phone_number}> — "(555) 123-4567" |
bytes_format |
modifier | <{$size|bytes_format}> — "1.23 MB" |
| Plugin | Type | Usage |
|---|---|---|
sanitize_string |
modifier | <{$input|sanitize_string}> — htmlspecialchars |
sanitize_filename |
modifier | <{$name|sanitize_filename}> |
sanitize_url |
modifier | <{$url|sanitize_url}> — blocks unsafe schemes |
sanitize_string_for_xml |
modifier | <{$text|sanitize_string_for_xml}> |
hash_string |
modifier | <{$data|hash_string:"sha256"}> — validates algorithm |
strip_html_comments |
modifier | <{$html|strip_html_comments}> |
Do not combine |sanitize_string with Smarty's |escape — both do htmlspecialchars and using both causes double-escaping.
| Plugin | Type | Usage |
|---|---|---|
generate_url |
function | <{generate_url route="news/index.php" params=$query}> |
generate_canonical_url |
function | <{generate_canonical_url path="modules/news/"}> — uses XOOPS_URL |
url_segment |
function | <{url_segment index=2 assign="seg"}> |
get_referrer |
function | <{get_referrer assign="ref"}> |
strip_protocol |
modifier | <{$url|strip_protocol}> |
parse_url |
modifier | <{$url|parse_url assign="parts"}> |
gravatar |
modifier | <{$email|gravatar:64:"retro"}> |
| Plugin | Type | Usage |
|---|---|---|
generate_meta_tags |
function | <{generate_meta_tags config=$metaConfig}> |
social_share |
function | <{social_share url=$url title=$title}> — full bar or single platform |
generate_xml_sitemap |
function | <{generate_xml_sitemap pages=$pages assign="xml"}> |
| Plugin | Type | Usage |
|---|---|---|
array_sort |
modifier | <{$items|array_sort:"name":"desc" assign="sorted"}> |
array_filter |
modifier | <{$items|array_filter:"status":"active" assign="filtered"}> |
| Plugin | Type | Usage |
|---|---|---|
file_exists |
modifier | <{if $path|file_exists}> |
is_image |
modifier | <{if $path|is_image}> — jpg, png, gif, webp, svg, avif, bmp, ico |
get_file_size |
modifier | <{$path|get_file_size}> — "1.23 MB" |
get_mime_type |
modifier | <{$path|get_mime_type}> — "image/png" |
| Plugin | Type | Usage |
|---|---|---|
get_current_year |
function | © <{get_current_year}> |
get_session_data |
function | <{get_session_data key="flash" assign="msg"}> — read-only |
display_error |
function | <{display_error message="Something failed"}> |
array_to_csv |
function | <{array_to_csv array=$data assign="csv"}> |
base64_encode_file |
function | <{base64_encode_file path="images/logo.png"}> |
mask_email |
modifier | <{$email|mask_email}> — "u***@domain.com" |
youtube_id |
modifier | <{$url|youtube_id}> — extracts video ID |
pretty_print_json |
modifier | <{$data|pretty_print_json}> |
translate |
modifier | <{"_MI_NEWS_TITLE"|translate}> — XOOPS constant lookup |
All function plugins use object as the template parameter type hint, which works with both:
- Smarty 4:
Smarty_Internal_Template - Smarty 5:
\Smarty\Template
function smarty_function_example(array $params, object $template): stringModifier plugins don't receive the template object in any Smarty version, so they work unchanged across all versions.
This library coexists with the existing smarty3_plugins/ directory:
smarty3_plugins/ (core) |
smarty4_plugins/ (this library) |
|
|---|---|---|
| Contents | 7 compiler plugins, 11 functions, 3 modifiers, 1 resource | 39 functions, 35 modifiers, 1 block |
| Focus | XOOPS internals (icon paths, block rendering, debug) | General-purpose utilities |
| Filename collisions | Zero | — |
| Search order | First (takes precedence) | Second (fallback) |
The two sets use different naming conventions (core: xoBlock, xoPageNav; library: xo_get_config, render_pagination) and serve complementary purposes.
The xoops-helpers library provides PHP-level utility classes (Str, Number, Date, Url, HtmlBuilder, etc.) plus 3 class-based Smarty plugins (asset_url, css_classes, format_number).
This plugin library and xoops-helpers serve different layers:
- smarty4_plugins — template-layer utilities, auto-discovered from files, zero dependencies
- xoops-helpers — PHP-layer utilities for controllers/handlers, plus class-based Smarty plugins registered via
PluginRegistrar::register()
17 of the 75 plugins implement logic that also exists in xoops-helpers (slugify, excerpt, format_currency, etc.). This is intentional: the plugins are self-contained and work without xoops-helpers installed. When xoops-helpers is available, the plugins could optionally delegate to it in a future version.
The xoops-helpers format_number function plugin and this library's number_format modifier plugin have similar names but are different Smarty plugin types — the function provides richer formatting modes (filesize, human, percentage, ordinal, currency), while the modifier wraps PHP's number_format(). Both can be used in the same template without conflict.
Self-contained. Every plugin carries its own logic inline. No shared helper class, no external dependencies. Each file can be understood, tested, or removed independently.
Presentation only. No database queries, no session writes, no file uploads, no email sending. Plugins provide read-only data access and output formatting. State-changing operations belong in PHP code, not templates.
Secure by default. Most plugins escape HTML output and sanitize URLs to block unsafe schemes. HTML-composing modifiers (linkify, highlight_text, nl2p) escape their input before inserting markup. CSRF tokens use the XOOPS security system. The xo_debug plugin only outputs when debug mode is active.
assign everywhere. All function plugins support assign="varname" to store results in template variables instead of printing them directly.
<{xo_get_config name="sitename" assign="sitename"}>
<{generate_meta_tags config=$metaTags}>
<{render_breadcrumbs items=$breadcrumbs}>
<{foreach from=$articles item=article}>
<article class="card mb-3">
<div class="card-body">
<h2><a href="<{xo_module_url module="news" path="article.php" params=['id' => $article.id]}>">
<{$article.title}>
</a></h2>
<p class="text-muted">
<{$article.created|relative_time}> · <{$article.body|reading_time}>
</p>
<p><{$article.body|excerpt:200}></p>
<{social_share url=$article.url title=$article.title}>
</div>
</article>
<{/foreach}>
<{render_pagination totalPages=$totalPages currentPage=$currentPage urlPattern="?page={page}"}><{xo_permission logged_in=true}>
<{xo_get_current_user assign="user"}>
<{xo_avatar uid=$user.uid size=48 class="rounded-circle"}>
Welcome, <{$user.uname}>!
<{xo_permission require="module_admin"}>
<a href="admin/" class="btn btn-warning">Admin Panel</a>
<{/xo_permission}>
<{/xo_permission}><{validate_form data=$formData rules=$rules assign="errors"}>
<{if $errors}>
<{render_form_errors errors=$errors}>
<{/if}>
<{form_open action="save.php" method="post"}>
<{form_input type="text" name="title" value=$title class="form-control" required="required"}>
<{form_input type="email" name="email" value=$email class="form-control"}>
<{create_button label="Save" type="submit" class="btn btn-primary"}>
<{form_close}>Before reaching for a plugin, check if Smarty already provides it:
| Need | Smarty built-in |
|---|---|
| Capitalize | |capitalize |
| Strip HTML tags | |strip_tags |
| Word wrap | |wordwrap:80 |
| Upper/lowercase | |upper / |lower |
| Escape HTML/URL/JS | |escape:"html" |
| Truncate by characters | |truncate:80 |
| String replacement | |replace:"old":"new" |
| Default value | |default:"N/A" |
| Date formatting (strftime) | |date_format:"%Y-%m-%d" |
Newline to <br> |
|nl2br |
See TUTORIAL.md for detailed usage of every plugin with examples.
GPL-2.0-or-later — same as XOOPS CMS.