A comprehensive guide for AI code assistants and developers to understand and work with ImpressCMS themes effectively.
- Overview
- Directory Structure
- Core Theme Files
- Smarty Template Basics
- Module Template Overrides
- Block Templates
- CSS and Assets
- RTL Support
- Admin Theme
- Common Pitfalls
- Practical Workflows
- ImpressCMS Theme APIs
ImpressCMS themes control the visual presentation of your website. A theme is a collection of:
- Templates - Smarty template files that define HTML structure
- Stylesheets - CSS files for styling
- Assets - Images, icons, JavaScript files
- Module Overrides - Custom templates for specific modules
- Configuration - Theme metadata and settings
- Themes are non-destructive - They override module templates without modifying module source code
- Separation of concerns - Keep presentation logic in templates, business logic in modules
- Reusability - Themes can be switched without affecting content or functionality
- Localization-aware - Support multiple languages and RTL (right-to-left) text directions
themes/yourtheme/
├── theme.html # Main site wrapper template
├── theme_admin.html # Admin area wrapper (optional)
├── style.css # Main stylesheet
├── style_admin.css # Admin stylesheet
├── README.md # Theme documentation
├── index.html # Security placeholder
│
├── blocks/
│ ├── centerblocks.html # Block container template
│ ├── centerblocks_admin.html # Admin block container
│ └── index.html
│
├── img/
│ ├── logo.png
│ ├── header_bg.jpg
│ └── index.html
│
├── icons/
│ ├── favicon.ico
│ ├── icon.png
│ └── index.html
│
├── js/
│ ├── theme.js # Optional theme JavaScript
│ └── index.html
│
├── modules/
│ ├── forum/
│ │ ├── view.thread.html # Override for forum templates
│ │ ├── index.html
│ │ └── ...
│ ├── system/
│ │ ├── system_siteclosed.html
│ │ └── index.html
│ └── [other-modules]/
│
└── rtl/
├── style.css # RTL-specific styles
├── style_admin.css # RTL admin styles
└── index.html
| Directory | Purpose | Required |
|---|---|---|
blocks/ |
Block container templates | Yes |
img/ |
Theme images, logos, backgrounds | No |
icons/ |
Favicon, app icons | No |
js/ |
Theme-specific JavaScript | No |
modules/ |
Module template overrides | No |
rtl/ |
Right-to-left language support | No |
The primary template that wraps all front-end content. This is the outermost HTML structure.
Key Responsibilities:
- Define HTML5 doctype and structure
- Include
<head>with meta tags, stylesheets, scripts - Provide placeholders for content and blocks
- Handle navigation and header/footer
Example Structure:
<!DOCTYPE html>
<html lang="<{$icms_language}>">
<{assign var=theme_name value=$xoTheme->folderName}>
<head>
<!-- Theme name -->
<{assign var=theme_name value=$xoTheme->folderName}>
<!-- Title and general metadata tags -->
<title><{$smarty.const._IMPRESSCMS_ADMIN}> <{$icms_sitename}></title>
<meta http-equiv="content-type" content="text/html; charset=<{$icms_charset}>" />
<meta name="robots" content="<{$icms_meta_robots}>" />
<meta name="keywords" content="<{$icms_meta_keywords}>" />
<meta name="description" content="<{$icms_meta_description}>" />
<meta name="rating" content="<{$icms_meta_rating}>" />
<meta name="author" content="<{$icms_meta_author}>" />
<meta name="copyright" content="<{$icms_meta_copyright}>" />
<meta name="generator" content="ImpressCMS" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><{$icms_pagetitle}></title>
<{* ImpressCMS automatically includes stylesheets here *}>
<{$icms_css}>
<{* Theme stylesheet *}>
<link rel="stylesheet" href="<{$icms_themepath}>/style.css">
<{* Module Header tags (if any) *}>
<{$icms_module_header}>
<{* Additional head content *}>
<{$icms_meta}>
</head>
<body>
<header>
<h1><{$icms_sitename}></h1>
<{* Navigation, logo, etc. *}>
</header>
<main>
<{* Left blocks *}>
<aside class="left-blocks">
<{$icms_lblocks}>
</aside>
<{* Main content *}>
<article class="main-content">
<{$icms_contents}>
</article>
<{* Right blocks *}>
<aside class="right-blocks">
<{$icms_rblocks}>
</aside>
</main>
<footer>
<{* Footer content *}>
</footer>
<{* ImpressCMS footer scripts *}>
<{$icms_footer}>
</body>
</html>Available Smarty Variables:
| Variable | Type | Description |
|---|---|---|
<{$icms_sitename}> |
string | Site name from configuration |
<{$icms_pagetitle}> |
string | Current page title |
<{$icms_language}> |
string | Current language code (e.g., 'en') |
<{$icms_themepath}> |
string | URL path to theme directory |
<{$icms_css}> |
string | Auto-generated CSS includes |
<{$icms_meta}> |
string | Meta tags and additional head content |
<{$icms_contents}> |
string | Main page content |
<{$icms_lblocks}> |
string | Left sidebar blocks |
<{$icms_rblocks}> |
string | Right sidebar blocks |
<{$icms_footer}> |
string | Footer scripts and content |
<{$icms_module_header}> |
string | Meta tags for the module that is used on this page (optional) |
Optional template for the admin backend. If not provided, ImpressCMS uses a default admin theme.
Example:
<!DOCTYPE html>
<html lang="<{$icms_language}>">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><{$icms_pagetitle}></title>
<{$icms_css}>
<link rel="stylesheet" href="<{$icms_themepath}>/style_admin.css">
<{$icms_meta}>
</head>
<body class="admin-panel">
<header class="admin-header">
<h1><{$icms_sitename}> - Admin</h1>
</header>
<div class="admin-container">
<nav class="admin-sidebar">
<{$icms_adminmenu}>
</nav>
<main class="admin-content">
<{$icms_contents}>
</main>
</div>
<{$icms_footer}>
</body>
</html>Defines how blocks are rendered in the center/main content area.
Example:
<div class="block" id="block-<{$block.bid}>">
<div class="block-header">
<h3><{$block.title}></h3>
</div>
<div class="block-content">
<{$block.content}>
</div>
</div>Available Variables:
<{$block.bid}>- Block ID<{$block.title}>- Block title<{$block.content}>- Block HTML content<{$block.weight}>- Block display order
Similar to centerblocks.html but for the admin panel.
ImpressCMS uses Smarty v2 for templating with custom delimiters <{ and }> instead of the standard { and }. Here are essential syntax rules for theme developers.
ImpressCMS uses <{ and }> as Smarty delimiters, NOT the standard { and }
This is critical for all template development in ImpressCMS themes. Always use <{ to open and }> to close Smarty tags.
<{* Simple variable output (auto-escaped) *}>
<{$variable_name}>
<{* With filters *}>
<{$variable_name|upper}>
<{$variable_name|truncate:50}>
<{$variable_name|date_format:"%Y-%m-%d"}>
<{* Conditional output *}>
<{if $user_id > 0}>
Welcome back, <{$user_name}>!
<{else}>
Please log in
<{/if}><{* Loop through arrays *}>
<{foreach item=item from=$items}>
<div class="item">
<h4><{$item.title}></h4>
<p><{$item.description}></p>
</div>
<{/foreach}>
<{* Loop with key-value pairs *}>
<{foreach key=key item=value from=$settings}>
<label><{$key}>: <{$value}></label>
<{/foreach}><{* Use language constants - ImpressCMS will provide them in the correct language *}>
<{$smarty.const.THEME_HOME}>
<{* Format timestamps *}>
<{$timestamp|date_format:"%Y-%m-%d %H:%M"}>
<{* Create URLs *}>
<a href="<{$icms_url}>/modules/modulename/index.php">Module Link</a>
<{* Include other templates *}>
<{include file="db:modulename_header.html"}>
<{* Assign variables in template *}>
<{assign var="page_title" value="My Page"}>
<{* store the theme folder for later use in file references within the theme. Add this at the beginning of the theme.html and theme_admin.html *}>
<{assign var=theme_name value=$xoTheme->folderName}>
- Use
<{and}>delimiters - Never use standard{and}in ImpressCMS - Indent with 4 spaces (per CLAUDE.md guidelines)
- Use meaningful variable names -
$user_namenot$u - Escape output by default - Smarty auto-escapes unless using
|smarty:nodefaults - Keep logic minimal - Complex logic belongs in PHP, not templates
- Use comments - Document non-obvious template sections with
<{* comment *}>
<{* Display user profile section *}>
<{if $user_id > 0}>
<div class="user-profile">
<h3><{$user_name|escape}></h3>
<p>Member since <{$join_date|date_format:"%B %Y"}></p>
</div>
<{/if}>Module template overrides allow themes to customize how modules display content without modifying module source code.
When ImpressCMS needs to render a template, it searches in this order:
- Theme override - themes/{yourtheme}/modules/{module}/{template-file}
- ImpressCMS template set - Internal template overrides
- Module default - modules/{module}/templates/{template-file}
- Fallback - Module's built-in rendering logic
Step 1: Locate the original template Step 2: Create the override directory Step 3: Create the override file Step 4: Modify as needed
- Preserve the filename exactly - Including extension (
.html,.tpl, etc.) - Preserve subdirectory structure - If original is in
templates/admin/, createmodules/forum/admin/ - Keep variable names consistent - Don't rename variables the module passes to the template
- Test thoroughly - Ensure your override works with the module's data
Original location: modules/forum/templates/view.thread.html
Override location: themes/yourtheme/modules/forum/view.thread.html
Original template:
<div class="thread">
<h2><{$thread.title}></h2>
<p class="meta">Posted by <{$thread.author}> on <{$thread.date}></p>
<div class="content">
<{$thread.body}>
</div>
</div>Customized override:
<article class="forum-thread">
<header class="thread-header">
<h2 class="thread-title"><{$thread.title}></h2>
<div class="thread-meta">
<span class="author"><{$thread.author}></span>
<time datetime="<{$thread.date|date_format:'%Y-%m-%dT%H:%M:%S'}>">
<{$thread.date|date_format:"%B %d, %Y"}>
</time>
</div>
</header>
<div class="thread-body">
<{$thread.body}>
</div>
</article>To find what templates a module uses:
- Check module documentation - Usually in
modules/{module}/docs/ - Browse module source - Look in
modules/{module}/templates/ - Check icms_version.php - Module configuration lists templates
- Use browser inspector - Look for template names in HTML comments
Blocks are reusable content containers that appear in sidebars or designated areas.
Block templates receive data from block functions and render it for display.
Example block template: themes/yourtheme/blocks/news_recent.html
<div class="news-block">
<h3 class="block-title">Recent News</h3>
<ul class="news-list">
<{foreach item=item from=$news_items}>
<li>
<a href="<{$item.url}>">
<{$item.title}>
</a>
<span class="date"><{$item.date|date_format:"%b %d"}></span>
</li>
<{/foreach}>
</ul>
</div>Blocks pass data as arrays. Common patterns:
<{* Simple list *}>
<{foreach item=item from=$items}>
<div><{$item.title}></div>
<{/foreach}>
<{* With conditional rendering *}>
<{if count($items) > 0}>
<ul>
<{foreach item=item from=$items}>
<li><{$item.title}></li>
<{/foreach}>
</ul>
<{else}>
<p>No items available</p>
<{/if}>Block templates are overridden the same way as module templates:
- Find original:
modules/{module}/templates/{blockname}.html - Create override:
themes/{yourtheme}/modules/{module}/{blockname}.html - Customize as needed
Main stylesheet at themes/yourtheme/style.css with reset, base styles, layout, blocks, and responsive design.
File at themes/yourtheme/style_admin.css focused on usability and information density.
Use Smarty variables for asset paths:
<{* Correct - uses theme path variable *}>
<img src="<{$icms_themepath}>/img/logo.png" alt="Logo">
<link rel="stylesheet" href="<{$icms_themepath}>/style.css">
<script src="<{$icms_themepath}>/js/theme.js"></script>
<{* Avoid hardcoding paths *}>
<img src="/themes/mytheme/img/logo.png"> <{* Wrong - breaks if theme moves *}><{* Bootstrap CSS *}>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
<{* jQuery *}>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<{* Font Awesome *}>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">Right-to-left (RTL) language support is essential for Arabic, Hebrew, Persian, and other RTL languages.
Create themes/yourtheme/rtl/style.css with RTL-specific overrides.
<{if $icms_language == 'ar' || $icms_language == 'he' || $icms_language == 'fa'}>
<{* RTL-specific content *}>
<div class="rtl-content">
<{$content}>
</div>
<{else}>
<{* LTR content *}>
<div class="ltr-content">
<{$content}>
</div>
<{/if}>ImpressCMS automatically loads RTL stylesheets when needed.
❌ Wrong:
<img src="{$icms_themepath}/img/logo.png">
<h1>{$icms_sitename}</h1>✅ Correct:
<img src="<{$icms_themepath}>/img/logo.png">
<h1><{$icms_sitename}></h1>❌ Wrong:
<img src="/themes/mytheme/img/logo.png">
<link rel="stylesheet" href="/themes/mytheme/style.css">✅ Correct:
<img src="<{$icms_themepath}>/img/logo.png">
<link rel="stylesheet" href="<{$icms_themepath}>/style.css">❌ Wrong:
modules/forum/templates/view.thread.html (modified directly)
✅ Correct:
themes/yourtheme/modules/forum/view.thread.html (override)
❌ Wrong:
themes/yourtheme/img/
themes/yourtheme/js/
✅ Correct:
themes/yourtheme/img/index.html
themes/yourtheme/js/index.html
❌ Wrong:
<{$thread.title}> <{* Module passes $thread_title *}>✅ Correct:
<{$thread_title}> <{* Match module's variable names *}>Always test your theme with RTL languages to ensure proper display.
❌ Wrong:
<{$user_input|smarty:nodefaults}> <{* Unsafe - allows XSS *}>✅ Correct:
<{$user_input}> <{* Auto-escaped by default *}>❌ Wrong:
<{* Inconsistent block markup *}>
<div class="block">
<{$block.content}>
</div>✅ Correct:
<{* Consistent structure for all blocks *}>
<div class="block" id="block-<{$block.bid}>">
<div class="block-header">
<h3><{$block.title}></h3>
</div>
<div class="block-content">
<{$block.content}>
</div>
</div>Step 1: Create directory structure
mkdir -p themes/mytheme/{blocks,img,icons,js,modules,rtl}
touch themes/mytheme/index.html
touch themes/mytheme/blocks/index.html
touch themes/mytheme/img/index.html
touch themes/mytheme/icons/index.html
touch themes/mytheme/js/index.html
touch themes/mytheme/rtl/index.htmlStep 2: Create core templates
Create themes/mytheme/theme.html with proper <{ and }> delimiters.
Create themes/mytheme/blocks/centerblocks.html with block structure.
Step 3: Create stylesheets
Create themes/mytheme/style.css with your design.
Step 4: Test
Switch to your theme in ImpressCMS admin panel and verify it displays correctly.
Step 1: Identify the template to override
Example: Override forum thread display
Step 2: Create override directory
mkdir -p themes/mytheme/modules/forum
touch themes/mytheme/modules/forum/index.htmlStep 3: Copy and modify template
Copy modules/forum/templates/view.thread.html to themes/mytheme/modules/forum/view.thread.html
Edit to customize appearance while keeping variable names intact and using <{ and }> delimiters.
Step 4: Test
View a forum thread and verify your custom template is used.
Step 1: Create RTL stylesheet
touch themes/mytheme/rtl/style.css
touch themes/mytheme/rtl/style_admin.cssStep 2: Add RTL-specific rules
In themes/mytheme/rtl/style.css:
body {
direction: rtl;
text-align: right;
}
/* Reverse layout-specific rules */
main {
grid-template-columns: 250px 1fr 250px;
direction: rtl;
}Step 3: Test with RTL language
Switch site language to Arabic or Hebrew and verify layout.
| Variable | Type | Description |
|---|---|---|
<{$icms_url}> |
string | Base URL of ImpressCMS installation |
<{$icms_themepath}> |
string | URL path to current theme |
<{$icms_sitename}> |
string | Site name |
<{$icms_pagetitle}> |
string | Current page title |
<{$icms_language}> |
string | Current language code |
<{$icms_contents}> |
string | Main page content |
<{$icms_lblocks}> |
string | Left sidebar blocks |
<{$icms_rblocks}> |
string | Right sidebar blocks |
<{$icms_css}> |
string | Auto-generated CSS includes |
<{$icms_meta}> |
string | Meta tags and head content |
<{$icms_footer}> |
string | Footer scripts |
<{$icms_isadmin}> |
bool | Is current user admin? |
<{$icms_userid}> |
int | Current user ID (0 if anonymous) |
<{$icms_username}> |
string | Current username |
<{* Text formatting *}>
<{$text|upper}> <{* Uppercase *}>
<{$text|lower}> <{* Lowercase *}>
<{$text|capitalize}> <{* Capitalize first letter *}>
<{$text|truncate:50}> <{* Truncate to 50 chars *}>
<{* Date formatting *}>
<{$timestamp|date_format:"%Y-%m-%d"}>
<{$timestamp|date_format:"%B %d, %Y"}>
<{* Number formatting *}>
<{$price|number_format:2}> <{* 2 decimal places *}>
<{{* HTML escaping *}>
<{$user_input|escape}> <{* Escape HTML *}>
<{$user_input|escape:'html'}> <{* Explicit HTML escape *}><{* Translate language constants *}>
<{_e('_MD_MODULENAME_TITLE')}>
<{* Format timestamps *}>
<{$timestamp|date_format:"%Y-%m-%d %H:%M"}>
<{{* Create module URLs *}>
<a href="<{$icms_url}>/modules/modulename/index.php?id=<{$item_id}>">
<{$item_title}>
</a>
<{{* Include other templates *}>
<{include file="db:modulename_header.html"}>
<{{* Conditional blocks *}>
<{if $icms_isadmin}>
<a href="<{$icms_url}>/admin/">Admin Panel</a>
<{/if}>Document your theme in themes/yourtheme/README.md:
# My Theme
## Description
A modern, responsive theme for ImpressCMS.
## Features
- Responsive design
- RTL language support
- Custom module overrides
- Dark mode support
## Requirements
- ImpressCMS 2.0+
- PHP 8.2+
## Installation
1. Extract to `themes/mytheme/`
2. Go to Admin > Themes
3. Select "My Theme" and click "Activate"
## Module Overrides
- Forum: Custom thread display
- News: Custom article layout
## Browser Support
- Chrome 90+
- Firefox 88+
- Safari 14+
- Edge 90+
## License
GPL 2.0Older ImpressCMS themes still use the old xoops variables in Smarty. Update your themes to the icms variants to remain compatible with newer releases.
| Old Variable | Replace with |
|---|---|
<{$xoops_url}> |
<{$icms_url}> |
<{$xoops_themepath}> |
<{$icms_themepath}> |
<{$xoops_sitename}> |
<{$icms_sitename}> |
<{$xoops_pagetitle}> |
<{$icms_pagetitle}> |
<{$xoops_language}> |
<{$icms_language}> |
<{$xoops_contents}> |
<{$icms_language}> |
<{$xoops_lblocks}> |
<{$icms_lblocks}> |
<{$xoops_rblocks}> |
<{$icms_rblocks}> |
<{$xoops_css}> |
<{$icms_css}> |
<{$xoops_meta}> |
<{$icms_meta}> |
<{$xoops_footer}> |
<{$icms_footer}> |
<{$xoops_isadmin}> |
<{$icms_isadmin}> |
<{$xoops_userid}> |
<{$icms_userid}> |
<{$xoops_username}> |
<{$icms_username}> |
Key Takeaways for AI Assistants:
- Theme location:
themes/{themename}/ - Core files:
theme.html,style.css,blocks/centerblocks.html - Template language: Smarty v2 with
<{and}>delimiters (NOT standard{and}) - Module overrides: Mirror module template structure in
modules/subdirectory - Asset paths: Always use
<{$icms_themepath}>variable - RTL support: Provide
rtl/directory with RTL-specific files - Security: Never modify module source; use theme overrides
- Testing: Test with multiple languages, especially RTL languages
Critical Reminders:
- ALWAYS use
<{and}>delimiters - This is ImpressCMS-specific Smarty syntax - Never use standard
{and}delimiters - They will not work in ImpressCMS - Smarty v2 syntax - Use
foreachwithitem=andfrom=parameters - Always preserve original variable names from modules
- Use Smarty's auto-escaping for security
- Keep templates focused on presentation - Complex logic belongs in PHP
- Document custom overrides in README.md
- Test responsive design and RTL support thoroughly
When working with themes:
- Check existing themes (like iTheme) for syntax examples
- Use
<{$icms_themepath}>for all asset references - Create
index.htmlfiles in all directories for security - Test with multiple languages, especially RTL languages
- Preserve module template variable names exactly
- Use consistent block structure across all blocks