Skip to content

Theme Settings (Customize) ​

Introduction ​

A theme offers its owner a few settings that need no code: the accent colour, the logo, a line in the footer, a sidebar on the left or right. The owner changes them on Appearance → Customize, looks at the site with the change before anyone else sees it, and publishes. It is WordPress's Customizer, kept to what a theme declares.

Settings are part of the core (kitloom/site), not a module: a theme reads them even when nobody has changed anything, so they are always there.

For the site's owner ​

Appearance → Customize (Filament and Nova) shows the active theme's settings on the left, grouped the way the theme groups them, and the site in a frame on the right. The active theme's card on Appearance → Themes has a Customize button too.

Customize: a colour, a font, the tagline and the footer, then Publish
  • A colour changes in the frame at once, as you pick it.
  • Anything else — a text, a picture, a switch — redraws the page in the frame.
  • Nobody else sees the changes yet. They are your draft for an hour, shown only to you, also in another tab. The page you see is never cached and never indexed by search engines.
  • Publish saves them for every visitor. Discard changes throws the draft away.

A picture comes from the media library. A site moved from WordPress keeps its logo: if the theme has no logo of its own yet, it shows the one WordPress had (custom_logo).

Who may: users with Edit theme options (edit_theme_options, as in WordPress) — administrators by default. Switching themes stays a separate permission.

A child theme has its parent's settings, with values of its own. The first time it is activated, it starts from the parent's values.

For theme authors ​

Declare the settings ​

A theme declares its settings in its service provider:

php
use Kitloom\Site\Themes\Settings\ThemeSetting;

protected function settings(): iterable
{
    return [
        ThemeSetting::color('accent', '#c2410c')->label(__('Accent'))->section(__('Colors'))->css('--accent'),
        ThemeSetting::font('heading_font', 'serif', [
            'serif' => ['label' => 'Serif', 'stack' => 'Georgia, serif'],
            'sans' => ['label' => __('Sans-serif'), 'stack' => 'system-ui, sans-serif'],
        ])->label(__('Heading font'))->section(__('Typography'))->css('--heading-font'),
        ThemeSetting::image('custom_logo')->label(__('Logo'))->section(__('Header')),
        ThemeSetting::toggle('show_tagline', true)->label(__('Show the tagline'))->section(__('Header')),
        ThemeSetting::text('footer_text')->label(__('Footer text'))->section(__('Footer'))
            ->description(__('Empty: the year and the site\'s name.')),
    ];
}

settings() runs only when something needs it, so labels can go through __() there.

TypeValueNotes
color#rrggbb or #rgb
imageAn attachment IDName the logo custom_logo, as WordPress does, so a moved site keeps its logo
textUp to 255 characters
textareaUp to 5,000 characters
toggletrue / false
choiceOne of its optionschoice('sidebar', 'right', ['left' => __('Left'), 'right' => __('Right')])
numberWithin its boundsnumber('font_size', 17, 14, 22, 'px')
fontOne of the theme's fontsEach a CSS font stack; nothing is loaded from elsewhere

Read them ​

CSS. A setting with css('--accent') is printed into every page's head, in @siteHead, as :root{--accent:#c2410c}. Every layout puts @siteHead after the theme's own styles, so the theme writes:

css
.button { background: var(--accent, #c2410c); }

Only checked values get there: a colour is a hex code, a font one of the theme's stacks, a choice one of its plain-word values. A text setting cannot become CSS at all.

Blade:

blade
@use('Kitloom\Site\Facades\Theme')

@if ($logo = Theme::image('custom_logo'))
    <img src="{{ $logo->url }}" alt="{{ $logo->alt }}">
@endif
<footer>{{ Theme::setting('footer_text') ?: '© '.date('Y') }}</footer>

Vue and React: list the theme part among the theme's parts (Kitloom\Site\Page\Parts\ThemeSettings). The template gets theme, with images as images (theme.custom_logo.url). A headless front end asks for it with ?include=theme.

Where they are kept ​

In the theme_mods_<theme> option (theme_mods_Journal), a map by setting name, as JSON — the way WordPress keeps a theme's mods. What nobody has changed is the declared default. A value the declaration no longer accepts (you renamed a font) falls back to the default instead of breaking the page.

Every write goes through the settings writer with the user who made it, so the activity log shows who changed the colours. The console and imports get the same checks.

For AI agents ​

describe_site lists the active theme's settings — type, options, bounds, current value — under theme_settings. theme_customize changes them as the agent's user, with the same checks as the screen:

json
{ "values": { "accent": "#1d4ed8", "footer_text": "Printed in the hills" } }

The change is published at once: agents do not work with drafts. null brings a setting back to its default.

Next ​

kitloom — modules and themes for Laravel.
Pricing · Services · License · Refunds · Privacy · Community · [email protected]