agentsclimarketplace

Classic theme customizer

Skill Lonsdale201/wp-agent-skills/theme-development/classic-theme-customizer

A community-maintained collection of agent skills for WordPress plugin and theme development.

Install
npx -y skills add Lonsdale201/wp-agent-skills --skill classic-theme-customizer

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 21 stars21 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Add or audit WordPress Customizer options for classic PHP themes on WP 7.0. Covers `customize_register`, `WP_Customize_Manager`, settings, sections, controls, `theme_mod` vs `option`, option-backed Customizer autoload, multidimensional setting IDs, `sanitize_callback`, `validate_callback`, `WP_Customize_Color_Control`, allowlisted select values, `postMessage`, `customize_preview_init`, selective refresh partials, escaping `get_theme_mod()` output in templates, and common bugs such as raw Customizer values, missing sanitization, or `postMessage` without preview JavaScript.

SKILL.md

9.4 KB, as published. Nobody here has run it

Classic Theme Customizer

Use this when adding or reviewing Customizer settings for a classic PHP theme. This is for theme presentation choices such as colors, layout toggles, logo-adjacent display settings, and small design options.

Do not use theme Customizer settings for plugin-like business data, payment credentials, complex content models, or cross-theme application state.

When to Use This Skill

  • Adding customize_register code to a classic theme.
  • Creating a color, select, checkbox, text, image, or layout option.
  • Reviewing get_theme_mod() output in templates.
  • Adding live preview with postMessage or selective refresh.
  • Fixing unsanitized Customizer settings or controls registered outside the correct hook.

Registration Hook

Register settings, sections, and controls on customize_register.

add_action( 'customize_register', 'mytheme_customize_register' );

function mytheme_customize_register( WP_Customize_Manager $wp_customize ) {
	$wp_customize->add_section(
		'mytheme_layout',
		array(
			'title'    => __( 'Layout', 'textdomain' ),
			'priority' => 160,
		)
	);
}

Rules:

  • Use the WP_Customize_Manager instance passed to the hook.
  • Prefix setting IDs with the theme slug.
  • Keep Customizer setup in inc/customizer.php or a similarly scoped include, loaded from functions.php.
  • Do not register controls during normal template rendering.

Settings Must Sanitize

Every custom setting needs a sanitize_callback.

$wp_customize->add_setting(
	'mytheme_accent_color',
	array(
		'default'           => '#0a7a75',
		'type'              => 'theme_mod',
		'capability'        => 'edit_theme_options',
		'transport'         => 'refresh',
		'sanitize_callback' => 'sanitize_hex_color',
	)
);

Rules:

  • Prefer type => 'theme_mod' for theme design settings.
  • Use type => 'option' only when the value is intentionally shared beyond the active theme.
  • When using type => 'option', set autoload => false for values that are not needed on most requests; core's multidimensional option save defaults to autoloading unless an autoload arg is supplied.
  • The default capability is edit_theme_options; set it explicitly when clarity helps.
  • Use transport => 'refresh' unless live preview is actually implemented.
  • Add validate_callback when a value can be syntactically valid but semantically unacceptable.

Common sanitizers:

ValueSanitizer
Hex colorsanitize_hex_color
Plain textsanitize_text_field
Textareasanitize_textarea_field
URLesc_url_raw
CheckboxCustom boolean sanitizer
Select/radioCustom allowlist sanitizer
Integerabsint

Controls

Use core controls where they fit.

$wp_customize->add_control(
	new WP_Customize_Color_Control(
		$wp_customize,
		'mytheme_accent_color',
		array(
			'label'   => __( 'Accent color', 'textdomain' ),
			'section' => 'mytheme_layout',
		)
	)
);

Select controls must pair with an allowlist sanitizer:

function mytheme_sanitize_layout( $value ) {
	$allowed = array( 'full', 'boxed', 'narrow' );

	if ( in_array( $value, $allowed, true ) ) {
		return $value;
	}

	return 'full';
}
$wp_customize->add_setting(
	'mytheme_site_layout',
	array(
		'default'           => 'full',
		'sanitize_callback' => 'mytheme_sanitize_layout',
	)
);

$wp_customize->add_control(
	'mytheme_site_layout',
	array(
		'label'   => __( 'Site layout', 'textdomain' ),
		'section' => 'mytheme_layout',
		'type'    => 'select',
		'choices' => array(
			'full'   => __( 'Full width', 'textdomain' ),
			'boxed'  => __( 'Boxed', 'textdomain' ),
			'narrow' => __( 'Narrow', 'textdomain' ),
		),
	)
);

Reading Values in Templates

Customizer values are stored data. Sanitize on save and escape on output.

$layout = get_theme_mod( 'mytheme_site_layout', 'full' );

if ( in_array( $layout, array( 'full', 'boxed', 'narrow' ), true ) ) {
	printf(
		'<div class="site-layout site-layout-%s">',
		esc_attr( $layout )
	);
}

Rules:

  • Always pass a default to get_theme_mod().
  • Escape by output context: esc_html(), esc_attr(), esc_url(), or controlled KSES.
  • Do not echo raw Customizer values into HTML, attributes, CSS, or JavaScript.
  • For CSS variables or inline CSS, validate allowed formats tightly before output.
  • Multidimensional setting IDs such as mytheme_options[color] are one root value plus subkeys. Keep the root option array small and typed; do not use it as a dumping ground for unrelated data.

Live Preview with postMessage

Use postMessage only when preview JavaScript is registered.

$wp_customize->get_setting( 'blogname' )->transport = 'postMessage';

add_action( 'customize_preview_init', 'mytheme_customize_preview_js' );

function mytheme_customize_preview_js() {
	wp_enqueue_script(
		'mytheme-customize-preview',
		get_theme_file_uri( 'assets/js/customize-preview.js' ),
		array( 'customize-preview' ),
		mytheme_asset_version( 'assets/js/customize-preview.js' ),
		array( 'in_footer' => true )
	);
}

Preview script:

( function ( wp ) {
	wp.customize( 'blogname', function ( value ) {
		value.bind( function ( nextValue ) {
			var siteTitle = document.querySelector( '.site-title a' );

			if ( siteTitle ) {
				siteTitle.textContent = nextValue;
			}
		} );
	} );
}( window.wp ) );

Rules:

  • Preview JS depends on customize-preview.
  • Controls-pane JS belongs on customize_controls_enqueue_scripts.
  • If there is no preview JS, leave transport as refresh.

Selective Refresh

Use selective refresh when a small server-rendered fragment can be updated without refreshing the whole preview.

if ( isset( $wp_customize->selective_refresh ) ) {
	$wp_customize->selective_refresh->add_partial(
		'blogname',
		array(
			'selector'        => '.site-title a',
			'render_callback' => 'mytheme_render_site_title',
		)
	);
}

function mytheme_render_site_title() {
	echo esc_html( get_bloginfo( 'name' ) );
}

Rules:

  • The selector must match stable frontend markup.
  • The render callback must output or return safe, escaped markup.
  • Do not use selective refresh for large, fragile page sections unless the markup is stable and tested.

Theme Boundary

Good Customizer settings:

  • Accent color.
  • Header layout.
  • Sidebar position.
  • Footer text when it is purely theme presentation.
  • Archive excerpt length when it is theme display behavior.

Bad Customizer settings:

  • API keys and secrets.
  • Checkout/business rules.
  • CPT data models.
  • Email templates owned by a plugin.
  • Anything that should survive theme switching as application state.

Review Checklist

  • Settings are registered on customize_register.
  • Every custom setting has sanitize_callback.
  • Select/radio values are allowlisted.
  • theme_mod is used for theme-specific presentation settings.
  • Templates escape get_theme_mod() output by context.
  • postMessage settings have preview JS.
  • Preview JS uses customize_preview_init and depends on customize-preview.
  • Controls JS/CSS uses customize_controls_enqueue_scripts.
  • Selective refresh partials use stable selectors and safe render callbacks.
  • Theme does not store plugin-like data in Customizer settings.
  • Option-backed settings have an intentional autoload value.

Common Mistakes

  • Adding controls without sanitizers because the UI "only has safe choices".
  • Using postMessage but not enqueueing preview JavaScript.
  • Echoing get_theme_mod() raw inside a class attribute or style attribute.
  • Registering Customizer objects on init.
  • Using option storage for values that should be theme-specific.
  • Letting a Customizer control write arbitrary CSS without validation.

Cross-References

  • Use wp-settings-storage-audit to review the broader persistence contract: theme_mod vs option, array shape, defaults, autoload, REST exposure, and migration.
  • Use wp-plugin-options-storage when the value is plugin-owned or should survive theme switching.

References

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.