ElkArte Community

Title: Theme Developers Guide for ElkArte 2.0.x
Post by: Spuds on February 17, 2026, 10:42:57 am
ElkArte Theme Developer Guide: Customizing Theme Functions

Overview
This guide shows theme developers how to customize ElkArte's new modular theme system. The theme system is now organized into logical groups that are easier to understand and modify.
Quote Think of this like CSS overrides - you can customize specific parts without breaking the whole theme. Each section below handles a different aspect of your theme.

Understanding the New Structure
ElkArte themes are now organized into these main areas:



Getting Started: Your Theme File
Your theme file is located at: themes/your_theme_name/Theme.php

Here's the basic structure you'll work with:
Code: [Select]
<?php
namespace ElkArte\Themes\YourThemeName;

use ElkArte\Themes\Theme as BaseTheme;

class Theme extends BaseTheme
{
    public function getSettings()
    {
        return [
            // Your theme settings here
            'theme_version' => '2.0',
            'theme_variants' => ['light', 'dark'],
            // ... more settings
        ];
    }
   
    // Add your custom functions here
}

🎨 Customizing Template Rendering

What This Controls


Common Customization's

Adding Custom CSS to Every Page
Code: [Select]
public function template_header(): void
{
    // First, do the normal header stuff
    parent::template_header();
   
    // Now add your custom CSS
    global $context;
    $context['html_headers'] .= '
        <link rel="stylesheet" href="' . $settings['theme_url'] . '/css/my_custom.css">
        <style>
            .my_custom_class {
                background-color: #your_color;
            }
        </style>';
}

Adding Custom JavaScript to Every Page
Code: [Select]
public function template_header(): void
{
    parent::template_header();
   
    // Add your custom JavaScript
    $this->addInlineJavascript('
        document.addEventListener("DOMContentLoaded", function() {
            console.log("My custom theme is loaded!");
            // Your custom JavaScript code here
        });
    ');
}

Customizing the Footer
Code: [Select]
public function template_footer(): void
{
    // Add custom content before the normal footer
    echo '<div class="my_custom_footer_content">
            <p>Powered by My Amazing Theme</p>
          </div>';
   
    // Then show the normal footer
    parent::template_footer();
}

Custom Copyright Message
Code: [Select]
public function theme_copyright(): void
{
    global $forum_copyright;
   
    // Replace the default copyright with your own
    $forum_copyright = 'My Custom Forum © 2026 | Powered by ElkArte';
   
    echo '<span class="my_copyright">' . $forum_copyright . '</span>';
}

Customizing User Context

What This Controls


Common Customizations

Adding Custom User Information
Code: [Select]
public function setupLoggedUserContext(): void
{
    global $context;
   
    // Do the normal user setup first
    parent::setupLoggedUserContext();
   
    // Add your custom user information
    $context['user']['custom_title'] = 'VIP Member'; // Example
    $context['user']['theme_preference'] = 'dark'; // Example
}

Customizing Page Titles
Code: [Select]
public function setContextThemeData(): void
{
    global $context, $mbname;
   
    // Do normal setup first
    parent::setContextThemeData();
   
    // Customize the page title format
    $context['page_title'] = $context['page_title'] . ' | ' . $mbname . ' - Your Custom Tagline';
   
    // Add custom meta tags
    $context['html_headers'] .= '
        <meta name="description" content="Your custom forum description">
        <meta name="keywords" content="forum, community, your, keywords">';
}

Adding Custom News Display
Code: [Select]
public function setupNewsLines(): void
{
    global $context;
   
    // Do the normal news setup
    parent::setupNewsLines();
   
    // Add your custom news processing
    if (!empty($context['news_lines'])) {
        foreach ($context['news_lines'] as $key => $news) {
            // Add custom styling to each news item
            $context['news_lines'][$key] = '<span class="my_news_style">' . $news . '</span>';
        }
    }
}

Customizing Special Features

What This Controls


Common Customization's

Customizing Video Embedding
Code: [Select]
public function autoEmbedVideo(): void
{
    global $txt, $modSettings;

    if (!empty($modSettings['enableVideoEmbeding'])) {
        // Load the video embedding script
        loadJavascriptFile('elk_jquery_embed.js', ['defer' => true]);

        // Customize the video embedding settings
        $this->addInlineJavascript('
            if (typeof oEmbedtext === "undefined") {
                var oEmbedtext = ({
                    embed_limit : 10, // Limit to 10 videos per page
                    preview_image : "▶️ Click to play video",
                    // Add your custom text
                    youtube : "YouTube Video",
                    vimeo : "Vimeo Video",
                });

                document.addEventListener("DOMContentLoaded", () => {
                    if ($.isFunction($.fn.linkifyvideo)) {
                        $().linkifyvideo(oEmbedtext);
                    }
                });
            }
        ', true);
    }
}

Adding Custom Code Highlighting
Code: [Select]
public function addCodePrettify(): void
{
    global $modSettings;

    if (!empty($modSettings['enableCodePrettify'])) {
        // Load your custom prettify theme
        $this->loadVariant('prettify');
        loadJavascriptFile('ext/prettify.min.js', ['defer' => true]);
       
        // Add custom styling
        loadCSSFile('my_code_theme.css');

        $this->addInlineJavascript('
            document.addEventListener("DOMContentLoaded", () => {
                if (typeof prettyPrint === "function") {
                    prettyPrint();
                   
                    // Add custom code block styling
                    document.querySelectorAll("pre").forEach(function(block) {
                        block.classList.add("my-custom-code-style");
                    });
                }
            });
        ', true);
    }
}

Customizing Assets (CSS/JS)

What This Controls


Common Customizations

Adding Theme-Specific CSS

Create a method that loads additional CSS for your theme:
Code: [Select]
public function loadThemeJavascript(): void
{
    // Do the normal JavaScript loading
    parent::loadThemeJavascript();
   
    // Add your theme-specific files
    loadCSSFile('my_theme_extras.css');
    loadJavascriptFile('my_theme_extras.js', ['defer' => true]);
   
    // Add theme-specific JavaScript variables
    $this->addJavascriptVar([
        'my_theme_color' => '#your_primary_color',
        'my_theme_name' => 'My Awesome Theme'
    ]);
}

Creating Custom Theme Variants

First, create variant directories in your theme:
Code: [Select]
themes/your_theme/css/
├── _light/
│   ├── index_light.css
│   └── custom_light.css
├── _dark/
│   ├── index_dark.css
│   └── custom_dark.css

Then customize the variant loading:
Code: [Select]
public function loadThemeVariant(): void
{
    global $context, $settings;
   
    // Do normal variant loading
    parent::loadThemeVariant();
   
    // Add custom variant-specific CSS
    if (!empty($context['theme_variant'])) {
        $this->loadVariant('my_custom_styles', true);
       
        // Add variant-specific JavaScript
        $this->addInlineJavascript('
            document.body.classList.add("theme-variant' . $context['theme_variant'] . '");
        ');
    }
}

Advanced Customization's

Adding Custom Settings to getSettings()
Code: [Select]
public function getSettings()
{
    // Get the default settings first
    $settings = parent::getSettings();
   
    // Add your custom settings
    return array_merge($settings, [
        // Your color scheme
        'primary_color' => '#3498db',
        'secondary_color' => '#2c3e50',
       
        // Custom theme variants
        'theme_variants' => ['light', 'dark', 'purple', 'green'],
       
        // Custom avatar settings
        'avatars_on_indexes' => 3, // Show both first and last post avatars
       
        // Custom page index styling
        'page_index_template' => [
            'base_link' => '<li class="my-page-btn"><a href="{base_link}">%2$s</a></li>',
            'current_page' => '<li class="my-current-page"><strong>%1$s</strong></li>',
        ],
       
        // Enable custom features
        'my_theme_features' => [
            'custom_header' => true,
            'animated_buttons' => true,
            'gradient_backgrounds' => true,
        ]
    ]);
}

Complete Example: Custom Theme Class

Here's a complete example showing how to create a custom theme:
Code: [Select]
<?php
namespace ElkArte\Themes\MyAwesomeTheme;

use ElkArte\Themes\Theme as BaseTheme;

class Theme extends BaseTheme
{
    public function getSettings()
    {
        return [
            'theme_version' => '2.0',
            'theme_variants' => ['light', 'dark', 'colorful'],
            'primary_color' => '#e74c3c',
            'require_theme_strings' => false,
            'avatars_on_indexes' => 1,
        ];
    }
   
    public function template_header(): void
    {
        parent::template_header();
       
        // Add custom CSS
        global $context, $settings;
        $context['html_headers'] .= '
            <link rel="stylesheet" href="' . $settings['theme_url'] . '/css/awesome.css">
            <link rel="preconnect" href="https://fonts.googleapis.com">
            <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">';
       
        // Add theme initialization
        $this->addInlineJavascript('
            document.addEventListener("DOMContentLoaded", function() {
                document.body.classList.add("awesome-theme");
                console.log("🎨 Awesome Theme Loaded!");
            });
        ');
    }
   
    public function setContextThemeData(): void
    {
        global $context;
       
        parent::setContextThemeData();
       
        // Add custom meta tags
        $context['html_headers'] .= '
            <meta name="theme-color" content="#e74c3c">
            <meta name="description" content="An awesome forum powered by ElkArte">';
       
        // Customize page title
        if (isset($context['page_title'])) {
            $context['page_title'] .= ' 🎨';
        }
    }
   
    public function theme_copyright(): void
    {
        echo '<div class="awesome-copyright">
                <p>Powered by <strong>Awesome Theme</strong> &amp; ElkArte</p>
              </div>';
    }
}

Tips for Theme Developers

1. Always Call Parent First
Code: [Select]
public function template_header(): void
{
    // Good: Call parent first
    parent::template_header();

    // Then add your customizations
}

2. Use CSS Classes for Styling
Instead of inline styles, add CSS classes:
Code: [Select]
// Avoid inline styles
echo '<div style="color: red;">Content</div>';

// Better: Use CSS classes
echo '<div class="my-theme-highlight">Content</div>';

3. Test Your Customizations
4. Use Browser Developer Tools
Common Mistakes to Avoid

1. Forgetting parent:: calls - This breaks core functionality
2. Not using global variables - Use global $context, $settings; when needed
3. Not testing thoroughly - Test different pages and user types

Remember: You're not replacing the entire system, just customizing specific parts to make your theme unique!