Como extender el Customizer con secciones y controles en PHP en WordPress

Contents

Introducción

El WordPress Customizer es la interfaz nativa que permite a los usuarios modificar aspectos del tema con vista previa en vivo. Extender el Customizer con secciones y controles personalizados en PHP proporciona una forma estructurada y segura de exponer opciones del tema, integrar una experiencia de edición en tiempo real y aplicar selective refresh para actualizaciones parciales de la página.

Visión general de los conceptos clave

  • Sección: agrupación lógica de controles dentro del Customizer.
  • Setting: el valor persistente almacenado en la base de datos (opción o metadata del theme).
  • Control: la interfaz visual que permite al usuario cambiar un setting (texto, select, color, etc.).
  • Sanitización: validación y limpieza de los valores antes de guardarlos.
  • Transport: forma de enviar cambios a la vista previa (refresh o postMessage).
  • Selectvie Refresh: actualización parcial del DOM, más eficiente que recargar la página completa.

Hooks y acciones relevantes

  • customize_register: para registrar secciones, settings y controles (PHP).
  • customize_preview_init: para encolar scripts de vista previa que usan postMessage (JS).
  • customize_controls_enqueue_scripts: para encolar scripts y estilos del panel del Customizer.

1) Registrar una sección, setting y control básicos

Ejemplo mínimo que añade una sección Header Options con un control de texto y un control color. Se recomienda usar prefijos para evitar colisiones de nombres.

add_section( mi_tema_header_section, array(
        title    => __( Header Options, mi-tema ),
        priority => 30,
    ) )

    // Añadir setting: título del header
    wp_customize->add_setting( mi_tema_header_title, array(
        default           => Bienvenido,
        sanitize_callback => sanitize_text_field,
        transport         => postMessage, // para vista previa en vivo con JS
    ) )

    // Añadir control de texto
    wp_customize->add_control( mi_tema_header_title, array(
        label    => __( Header Title, mi-tema ),
        section  => mi_tema_header_section,
        type     => text,
    ) )

    // Añadir setting: color de fondo del header
    wp_customize->add_setting( mi_tema_header_bg, array(
        default           => #ffffff,
        sanitize_callback => sanitize_hex_color,
        transport         => postMessage,
    ) )

    // Control de color nativo
    wp_customize->add_control( new WP_Customize_Color_Control(
        wp_customize,
        mi_tema_header_bg,
        array(
            label   => __( Header Background, mi-tema ),
            section => mi_tema_header_section,
        )
    ) )
}
add_action( customize_register, mi_tema_customize_register )
?>

Explicación

  • El setting define la persistencia y la sanitización.
  • Transport postMessage permite cambios en vivo sin recargar requiere un script JS para aplicar los cambios instantáneamente en la vista previa.
  • WP_Customize_Color_Control es una clase nativa usada para controles complejos.

2) Sanitización y validación

Siempre sanitiza cualquier dato que entre al sistema. Aquí unos ejemplos de funciones de sanitización personalizadas y comprobaciones de capacidad.


3) Tipos de controles comunes

Resumen de controles nativos que puedes usar. Algunos requieren clases específicas (por ejemplo el control de color).

Tipo Uso
text Entrada de texto simple
textarea Bloque de texto
checkbox Booleano
select Lista desplegable
radio Opciones exclusivas
color Selector de color (WP_Customize_Color_Control)
image / upload Subida de imágenes (usar WP_Customize_Image_Control)
dropdown-pages Selector de página
range Rango numérico (puede requerir control personalizado)

4) Control personalizado (ejemplo)

Crear controles personalizados permite mostrar interfaces más ricas (un switch, un control repetidor simple, select con íconos, etc.). A continuación un ejemplo de un control tipo switch (toggle) que hereda de WP_Customize_Control.


            
            add_setting( mi_tema_show_title, array(
            default           => 1,
            sanitize_callback => mi_tema_sanitize_int,
            transport         => postMessage,
        ) )

        wp_customize->add_control( new Mi_Tema_Toggle_Control(
            wp_customize,
            mi_tema_show_title,
            array(
                label   => __( Mostrar título, mi-tema ),
                section => mi_tema_header_section,
            )
        ) )
    }
    add_action( customize_register, mi_tema_add_toggle_control )
}
?>

5) Selective Refresh y callbacks de render

Selective Refresh permite actualizar solo una parte del DOM. Es más eficiente que recargar toda la vista previa y no requiere escribir tanto JS como postMessage.

selective_refresh ) ) {
        wp_customize->selective_refresh->add_partial( mi_tema_header_title, array(
            selector            => .site-header .site-title,
            settings            => array( mi_tema_header_title ),
            render_callback     => mi_tema_render_header_title,
        ) )
    }
}
add_action( customize_register, mi_tema_selective_refresh )

function mi_tema_render_header_title() {
    echo esc_html( get_theme_mod( mi_tema_header_title, Bienvenido ) )
}
?>

6) Vista previa en vivo con postMessage (JavaScript)

Si usas transport postMessage, añade un script que actualice el DOM cuando el usuario cambie el setting. Encolar ese script en customize_preview_init.

( function( wp ) {
    wp.customize( mi_tema_header_title, function( value ) {
        value.bind( function( newval ) {
            var el = document.querySelector( .site-header .site-title )
            if ( el ) {
                el.textContent = newval
            }
        } )
    } )

    wp.customize( mi_tema_header_bg, function( value ) {
        value.bind( function( newval ) {
            var el = document.querySelector( .site-header )
            if ( el ) {
                el.style.backgroundColor = newval
            }
        } )
    } )
} )( wp )

7) Encolar scripts y estilos del panel de control (opcional)

Si tu control personalizado necesita CSS o JS en el panel del Customizer, enquéalo usando customize_controls_enqueue_scripts.


/ assets/css/customizer-controls.css /
.mi-toggle { display: inline-block margin-left: 10px }

8) Ejemplo completo: sección Header con logo, toggle, color y layout

Archivo functions.php o un archivo incluido desde el tema.

add_section( mi_tema_header, array(
        title    => __( Header, mi-tema ),
        priority => 30,
    ) )

    // Logo (image control)
    wp_customize->add_setting( mi_tema_logo, array(
        sanitize_callback => absint,
        transport         => refresh,
    ) )
    wp_customize->add_control( new WP_Customize_Media_Control( wp_customize, mi_tema_logo, array(
        label    => __( Logo, mi-tema ),
        section  => mi_tema_header,
        mime_type=> image,
    ) ) )

    // Mostrar título (toggle)
    wp_customize->add_setting( mi_tema_show_title, array(
        default           => 1,
        sanitize_callback => mi_tema_sanitize_int,
        transport         => postMessage,
    ) )
    wp_customize->add_control( mi_tema_show_title, array(
        label    => __( Mostrar título del sitio, mi-tema ),
        section  => mi_tema_header,
        type     => checkbox,
    ) )

    // Color de fondo
    wp_customize->add_setting( mi_tema_header_bg, array(
        default           => #ffffff,
        sanitize_callback => sanitize_hex_color,
        transport         => postMessage,
    ) )
    wp_customize->add_control( new WP_Customize_Color_Control( wp_customize, mi_tema_header_bg, array(
        label   => __( Background, mi-tema ),
        section => mi_tema_header,
    ) ) )

    // Layout del header (select)
    wp_customize->add_setting( mi_tema_header_layout, array(
        default           => default,
        sanitize_callback => mi_tema_sanitize_layout,
        transport         => refresh,
    ) )
    wp_customize->add_control( mi_tema_header_layout, array(
        label    => __( Layout, mi-tema ),
        section  => mi_tema_header,
        type     => select,
        choices  => array(
            default    => __( Default, mi-tema ),
            centered   => __( Centered, mi-tema ),
            full-width => __( Full Width, mi-tema ),
        ),
    ) )
}
add_action( customize_register, mi_tema_customize_header )
?>

9) Buenas prácticas y recomendaciones

  • Prefija tus funciones, clases y opciones (ej. mi_tema_…) para evitar conflictos con plugins o temas hijos.
  • Sanitiza siempre con callbacks específicos según el tipo del dato (sanitize_text_field, sanitize_hex_color, esc_url_raw, absint, etc.).
  • Usa postMessage JS para una experiencia en vivo fluida y selective_refresh cuando necesites render parcial sin escribir mucho JS.
  • Evita guardar datos innecesarios. Para valores simples considera get_theme_mod / set_theme_mod.
  • Comprueba capacidades (current_user_can) si guardas datos sensibles o permites opciones avanzadas.
  • Optimiza assets: solo encola scripts y estilos cuando el Customizer esté activo.

10) Diagnóstico y depuración

  1. Si los cambios no se reflejan con postMessage, asegúrate de que el script está encolado en customize_preview_init y que usa el handle customize-preview como dependencia.
  2. Si selective refresh no funciona, confirma que el selector CSS coincide exactamente con el elemento en la plantilla y que el render_callback devuelve el HTML correcto.
  3. Revisa la consola del navegador por errores JS y los logs PHP si hay errores fatales.

Conclusión

Extender el Customizer en PHP te permite ofrecer una experiencia de personalización potente y segura. Combinando settings, controles, sanitización, selective refresh y postMessage obtendrás una interfaz atractiva y eficiente. Implementa controles personalizados cuando las opciones nativas no cubran tus necesidades y siempre sigue buenas prácticas de sanitización y prefijado para mantener compatibilidad y seguridad.



Acepto donaciones de BAT's mediante el navegador Brave 🙂



Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *