Edit an Existing Preset
This tutorial covers the most common edits you will make to an existing preset — adding a new configurable setting, changing how the template renders it, and adjusting the CSS. The examples use the default header preset, but the same steps apply to any preset type.
Adding a New Slot (Configurable Setting)
A slot is one configurable setting exposed to the user in the Header & Footer admin panel. Adding a slot is a three-part change: manifest → template → CSS.
Part 1 — Add the slot to manifest.json
Open public/presets/header/default/manifest.json and add the new slot to the appropriate slot_groups entry. If no suitable group exists, add a new group.
Example: adding a "Logo Max Height" text field to a new "Logo" group.
{
"label": "Logo",
"slots": [
{
"id": "logo_max_height",
"type": "text",
"label": "Max Height",
"default": "50px",
"breakpoints": ["desktop", "tablet", "mobile"]
}
]
}
Checklist before saving:
- The
idmust be unique within this preset. Check all other slots in the file. - The
breakpointsarray must be non-empty. A slot without breakpoints is silently ignored. - The
defaultvalue is what the user sees before they have saved any changes. - If the slot is purely desktop-only (like a desktop nav menu), use
["desktop"]. - If the value needs different defaults per breakpoint, use an object:
"default": { "desktop": "50px", "tablet": "40px", "mobile": "30px" }.
Part 2 — Read the slot value in index.php
Open public/presets/header/default/index.php.
For a responsive slot (breakpoints includes more than just "desktop"), use get_bp_var():
$logo_max_height = get_bp_var( $settings, 'logo_max_height' );
// Returns: ['desktop' => '50px', 'tablet' => '40px', 'mobile' => '30px']
Then emit it as a CSS custom property inside the existing breakpoint loop. Find the section of index.php that loops over $breakpoints and echoes the <style> block, and add your new property there:
echo "--sanilwb-logo-max-height: {$logo_max_height[$bp]};\n";
For a non-responsive slot (breakpoints is ["desktop"] only), read the value directly from $settings:
$primary_menu_id = (int) ( $settings['primary_menu'] ?? 0 );
Part 3 — Use the CSS custom property in style.scss
Open public/presets/header/default/style.scss and use the custom property you just emitted:
.sanilwb-header {
.header-main-logo img {
max-height: var(--sanilwb-logo-max-height);
}
}
Then compile:
npm run build:css
Changing a Slot Default
Open manifest.json and change the default value for the slot. The new default takes effect immediately for users who have never saved that setting. Users who have already saved a value will continue to see their saved value — the default is only used when there is no saved entry in the database.
If you want to reset all users back to the new default, the user can click Reset to Defaults in the admin panel. You cannot do this programmatically without wiping the saved settings option (sanilwb_{type}_preset_settings).
Renaming or Removing a Slot
Renaming a slot id: The saved settings in the database are keyed by the old id. After renaming, existing users will see the new default (the old saved value is orphaned). If this is a concern, write a one-time migration that reads the old key and writes it to the new key in sanilwb_{type}_preset_settings. Otherwise simply rename the id in manifest.json, update all references in index.php and style.scss, and compile.
Removing a slot: Delete it from manifest.json, remove all references in index.php and style.scss, and compile. The orphaned value in the database is harmless — it will be ignored on the next load because the key no longer appears in the manifest's defaults map.
Editing the HTML Template (index.php)
Open public/presets/header/default/index.php. This file is a standard PHP template — edit the HTML markup directly. A few things to keep in mind:
Use $settings for all slot values. Never call get_option() to read a slot value that belongs to this preset. The slot value is already in $settings, merged with defaults, ready to use.
Use $common for site-wide data. The $common array contains:
$common['logo_html']— ready-to-echo logo markup$common['logo_url']— raw logo URL$common['site_name']— blog name$common['nav_menus']— all registered nav menus as[{id, name}]$common['widget_areas']— all registered sidebars as[{id, name}]
Check is_preview() for widget areas. When the template is rendered inside the admin preview iframe, empty widget areas would be invisible and confusing. Show a placeholder instead:
if ( is_active_sidebar( 'sanilwb_header_sidebar' ) ) {
dynamic_sidebar( 'sanilwb_header_sidebar' );
} elseif ( SANILWB_SL_Renderer::is_preview() ) {
echo '<div class="sanilwb-sidebar-placeholder">Header Sidebar — <a href="/wp-admin/widgets.php" target="_blank">Add Widgets</a></div>';
}
Responsive classes. The preset already emits CSS custom properties per breakpoint via the <style> block. For Bootstrap-based show/hide logic (like hiding an element at certain breakpoints), use Bootstrap utility classes (d-none, d-xl-block, etc.) directly in the markup.
Editing the Stylesheet (style.scss)
Open public/presets/header/default/style.scss. Edit the SCSS freely — it is scoped to this preset's HTML and does not affect any other preset.
After any SCSS change, compile:
npm run build:css
Or run the watcher to compile on every save:
npm run watch:css
Important: Do not add breakpoint media queries for slot values in style.scss. Slot values that vary by breakpoint are handled by the CSS custom property pattern in index.php — the <style> block loops over breakpoints and emits the correct value per media query. The style.scss just references var(--your-property) and the browser handles the rest.
Editing hooks.php (Nav Menus and Widget Areas)
Open public/presets/header/default/hooks.php to add, rename, or remove nav menu locations and widget area registrations.
Adding a new widget area:
add_action( 'widgets_init', function () {
register_sidebar( [
'id' => 'sanilwb_header_promo_bar',
'name' => 'Sanil WB Header Promo Bar',
'description' => 'Used by the Default header preset — promo bar above the logo.',
'before_widget' => '<div class="sanilwb-widget">',
'after_widget' => '</div>',
'before_title' => '',
'after_title' => '',
] );
} );
After adding the widget area, reference it in index.php using dynamic_sidebar( 'sanilwb_header_promo_bar' ).
Removing a widget area: Delete its register_sidebar() call from hooks.php. The widget area will disappear from Appearance → Widgets. Any content users had added to it will remain in the database but will no longer be displayed. Clean it up manually via the Widgets screen if needed.
Renaming a widget area's name or description: Safe to do at any time. The id is what links saved widget content to the sidebar — changing id breaks that link, so only change it if you intend to start fresh.
Adding Demo Content for a New Widget Area
If you added a new widget area in hooks.php, you can provide default content for it via manifest.json. Open the manifest and add or extend the demo_sidebars key:
"demo_sidebars": {
"sanilwb_header_promo_bar": [
{
"type": "block",
"content": "<!-- wp:paragraph {\"align\":\"center\"} --><p class=\"has-text-align-center\">Free shipping on orders over $50!</p><!-- /wp:paragraph -->"
}
]
}
The user imports this by clicking Import Demo Content in the Header & Footer admin panel. The import replaces whatever is currently in the sidebar with the demo content.
Adding an Optional script.js
If your preset needs JavaScript on the frontend, create public/presets/header/minimal/script.js. The plugin enqueues it automatically in the footer when the preset is active — no registration or wp_enqueue_script() call is needed. It has no script dependencies — jQuery is not available or used anywhere in this plugin's frontend, so write vanilla JS.
Write plain JavaScript. Do not use ES modules or modern import/export syntax — the file is served as-is without any bundling.
After Every Edit — Checklist
| Task | Done? |
|---|---|
Run npm run build:css if you changed any .scss file |
|
| Verify the preset appears in the Header & Footer admin panel | |
| Open the Preview iframe and check desktop, tablet, and mobile views | |
| Check the frontend with the preset active as a logged-out user | |
| If you added a slot, confirm its default looks correct before a user has saved anything | |
If you added a widget area, check that is_preview() shows a useful placeholder |