Customizer JS API: Adding Setting Dynamically Not Working

I’m using the JS & PHP code displayed below to add a customizer setting dynamically. I know that saving the setting works because when I echo get_theme_mod('mySetting') within a theme template file, the saved value is returned. However, after a browser refresh within the customizer, the input does not display the saved value but rather the value used when the setting is instantiated (JS Default Value?). What am I doing wrong?

Note: Please read first comment as well.

// JS enqueued via action hook: customize_controls_enqueue_scripts
(function( $, api ) {
api.bind( 'ready', function() {

    var section = new api.Section( 'my-section', {
        title           : 'Dynamic Setting Section',
        priority        : 1,
        customizeAction : 'Customizing'
    });

    var setting = new api.Setting( 'mySetting', 'JS Default Value?' );

    var control = new api.Control( 'my-control', {
        type    : 'text',
        section : 'my-section',
        setting : setting
    });

    api.section.add( section );

    api.add( setting );

    api.control.add( control );

});
})( jQuery, wp.customize );

As explained by Weston Ruter in more detail here and here, dynamically created settings must also be registered in PHP because:

In order for a setting to be safely stored it must be sanitized and validated by the server. Relying on client-side sanitization and validation is dangerous.

<?php
add_filter( 'customize_dynamic_setting_args',function( $setting_args, $setting_id )
{
    if ( 'mySetting' == $setting_id ) {
        $setting_args = array(
            'transport'         => 'postMessage',
            'default'           => 'PHP Default Value!',
            'sanitize_callback' => 'wp_strip_all_tags',
        );
    }

    return $setting_args;
});
?>

1 Answer
1

When you register the setting in JS, you need to supply the current value saved in the DB as the value, not some default value. So instead of:

var setting = new api.Setting( 'mySetting', 'JS Default Value?' );

You would need to obtain the value via some means like the REST API and then use it when instantiating. You also need to provide the transport. So it would look like this:

var setting = new api.Setting( 'mySetting', someResponse.value, { transport: 'postMessage' } );

Here are some examples of doing this:

  • in Customize Featured Content Demo
  • in Customize Posts
  • in Customize REST Resources

Leave a Comment