I have 4x custom settings within 2x custom sections, with the second setting in each section relying on an active_callback to show/hide it.

In both cases the active_callback checks the value of the first custom setting from that section, and it was working perfectly until I started using transport => postMessage for the first setting (all settings below, as it's easier to show them than it is explain them).

There are no JS errors, so I assume it must be something to do with how the active callback is fired (I.e. perhaps it's not when postMessage is used).

While I can add some additional JS to cover my requirements, I'd be curious to know whether or not this is expected behavior, and if it is, whether or not there is a way to fix my problem.

Here are the settings (registered using the customize_register action hook)...

/**
 * Create the custom 'Archive Pages' section and register settings
 */
function register_settings_archive_template($wp_customise){

    $wp_customise->add_section('section_template_archive' , array(
        'title'             => __('Archive Pages', TEXT_DOMAIN),
        'priority'          => 60
    ));

    /**
     * Link tile size (overrides General setting)
     */

    $wp_customise->add_setting('archive_link_tile_size', array(
        'default'   => 'default',
        'transport' => 'postMessage'
    ));

    $wp_customise->add_control('archive_link_tile_size', array(
        'label'         => __('Link tile size', TEXT_DOMAIN),
        'section'       => 'section_template_archive',
        'type'          => 'radio',
        'choices'       => array(
            'default'   => __('Default', TEXT_DOMAIN),
            'large'     => __('Large', TEXT_DOMAIN),
            'small'     => __('Small', TEXT_DOMAIN)
        ),
        'description'   => __('The size of link tile that you wish to dsipay on archive pages.', TEXT_DOMAIN),
    ));

    /**
     * Show 'More...' link
     */

    $wp_customise->add_setting('archive_show_more_link', array(
        'default'   => false,
        'transport' => 'postMessage'
    ));

    $wp_customise->add_control('archive_show_more_link', array(
        'label'             => __('Show link to Link/Post', TEXT_DOMAIN),
        'section'           => 'section_template_archive',
        'type'              => 'checkbox',
        'description'       => __('Whether or not to show the \'More...\' link underneath a large link tile on archive pages.  Note that links cannot be displayed in conjunction with \'Small\' Link Tiles.', TEXT_DOMAIN),
        'active_callback'   => '_check_is_link_tile_size_large'
    ));

}

/**
 * Create the custom 'Search Results' section and register settings
 */
function register_settings_search_template($wp_customise){

    $wp_customise->add_section('section_template_search' , array(
        'title'             => __('Search Results', TEXT_DOMAIN),
        'priority'          => 60
    ));

    /**
     * Link tile size (overrides General setting)
     */

    $wp_customise->add_setting('search_link_tile_size', array(
        'default'   => 'default',
        'transport' => 'postMessage'
    ));

    $wp_customise->add_control('search_link_tile_size', array(
        'label'         => __('Link tile size', TEXT_DOMAIN),
        'section'       => 'section_template_search',
        'type'          => 'radio',
        'choices'       => array(
            'default'   => __('Default', TEXT_DOMAIN),
            'large'     => __('Large', TEXT_DOMAIN),
            'small'     => __('Small', TEXT_DOMAIN)
        ),
        'description'   => __('The size of link tile that you wish to dsipay on the search results page.', TEXT_DOMAIN)
    ));

    /**
     * Show 'More...' link
     */

    $wp_customise->add_setting('search_show_more_link', array(
        'default'   => false,
        'transport' => 'postMessage'
    ));

    $wp_customise->add_control('search_show_more_link', array(
        'label'             => __('Show link to Link/Post', TEXT_DOMAIN),
        'section'           => 'section_template_search',
        'type'              => 'checkbox',
        'description'       => __('Whether or not to show the \'More...\' link underneath a large link tile on the search results page.  Note that links cannot be displayed in conjunction with \'Small\' Link Tiles.', TEXT_DOMAIN),
        'active_callback'   => '_check_is_link_tile_size_large'
    ));

}

And here is the active callback...

public function _check_is_link_tile_size_large($control){

    $control_id = $control->id;

    switch($control_id):

        case 'archive_show_more_link' :
            $validation_setting = 'archive_link_tile_size';
            break;

        case 'search_show_more_link' :
            $validation_setting = 'search_link_tile_size';
            break;

    endswitch;

    return ($control->manager->get_setting($validation_setting)->value() === 'large');

}

Update

I should have added this in the first place, but here is the JS that I am using to update the above settings via postMessage -

(function($){

    var api = wp.customize;

    CustomiseArchivePages();    // Customise settings in the Archive Pages section
    CustomiseSearchResults();   // Customise settings in the Search Results section

    /**
     * Customise settings in the Archive Pages section
     */
    function CustomiseArchivePages(){

        /** Link Tile size */
        api('archive_link_tile_size', function(value){
            value.bind(function(newval){
                PreviewLinkTile(newval, api.get().archive_show_more_link);
            });
        });

        /** Show/hide 'More...' button  */
        api('archive_show_more_link', function(value){
            value.bind(function(newval){
                PreviewLinkTile(api.get().archive_link_tile_size, newval);
            }); 
        });

    }

    /**
     * Customise settings in the Search Results section
     */
    function CustomiseSearchResults(){

        /** Search box placeholder text */
        api('search_box_placeholder', function(value){
            value.bind(function(newval){
                $('input.s').attr('placeholder', newval);
            });
        });

        /** Link Tile size */
        api('search_link_tile_size', function(value){
            value.bind(function(newval){
                PreviewLinkTile(newval, api.get().search_show_more_link);
            });
        });

        /** Show/hide 'More...' button  */
        api('search_show_more_link', function(value){
            value.bind(function(newval){
                PreviewLinkTile(api.get().search_link_tile_size, newval);
            });
        });

    }

    /**
     * Set the link tile size and show/hide the 'More...' button on link tiles
     *
     * @param required string linkTileSize          The size of the link tiles that are being displayed
     * @param required string showMoreInfoButton    Whether or not to show the 'More...' button
     */
    function PreviewLinkTile(linkTileSize, showMoreInfoButton){

        var linksContainer = $('#links-container'),         // The links container
            linkTiles = $('.link-tile', linksContainer);    // Every individual link tile

        linkTileSize = (linkTileSize !== 'default') ? linkTileSize : api.get().general_link_tile_size;  // If the new size is default, grab the default size

        /**
         * Set the link tile size
         */
        switch(linkTileSize){

            case 'large' :

                /** Set the links container classes */
                linksContainer.removeClass('uk-grid-width-1-2 uk-grid-width-small-1-3 uk-grid-width-medium-1-4 uk-grid-width-large-1-5')
                    .addClass('uk-grid-width-1-1 uk-grid-width-small-1-1 uk-grid-width-medium-1-2 uk-grid-width-large-1-3');

                /** Set the link tile class */
                linkTiles.removeClass('link-tile-small')
                    .addClass('link-tile-large');

                break;

            case 'small' :

                /** Set the links container classes */
                linksContainer.removeClass('uk-grid-width-1-1 uk-grid-width-small-1-1 uk-grid-width-medium-1-2 uk-grid-width-large-1-3')
                    .addClass('uk-grid-width-1-2 uk-grid-width-small-1-3 uk-grid-width-medium-1-4 uk-grid-width-large-1-5');

                /** Set the link tile class */
                linkTiles.removeClass('link-tile-large')
                    .addClass('link-tile-small');

                break;

            default :
                console.log('An unexpected error occured when customising the Link Tile size: The new size could not be determined.');
                break;

        }

        /**
         * Show/hide the 'More...' button
         */
        if(showMoreInfoButton && linkTileSize === 'large'){
            linkTiles.addClass('show-more-button');
        } else {
            linkTiles.removeClass('show-more-button');
        }

    }

})(jQuery);
  • Yes, it is expected that if using postMessage, the active_callback wouldn't fire because it is only called when the preview refreshes. If you want to re-evaluate the active_callback handlers, you can refresh the preview via wp.customize.previewer.refresh() – Weston Ruter Dec 15 '15 at 5:48
  • 1
    Thanks, but if I refresh then it totally destroys the point of using postMessage in the first place. Plus wp.customize.previewer.refresh() generates an error... – David Gard Dec 15 '15 at 11:02
  • Yes, good point. See my answer below. – Weston Ruter Dec 16 '15 at 6:11
up vote 5 down vote accepted

Because postMessage uses JavaScript entirely, any PHP active_callback will not get called unless the preview refreshes (e.g. via wp.customize.previewer.refresh()). So what you need to do is implement the active callback in JavaScript instead, like so:

wp.customize.bind( 'ready', function () {
    wp.customize.control( 'archive_show_more_link', function( control ) {
        var setting = wp.customize( 'archive_link_tile_size' );
        control.active.set( 'large' === setting.get() );
        setting.bind( function( value ) {
            control.active.set( 'large' === value );
        } );
    } );

    wp.customize.control( 'search_show_more_link', function( control ) {
        var setting = wp.customize( 'search_link_tile_size' );
        control.active.set( 'large' === setting.get() );
        setting.bind( function( value ) {
            control.active.set( 'large' === value );
        } );
    } );
} );

Make sure that this script gets enqueued into the Customizer pane and not the Customizer preview. In other words, enqueue the JS at the customize_controls_enqueue_scripts action.

  • Thanks for the code, but I'm getting an error - wp.customize.control() is not a function. I also get the same error when using wp.customize.previewer.refresh(). Note also that I've now updated my question to include the current JS that I am using. – David Gard Dec 16 '15 at 10:50
  • You need to make sure your code is wrapped in wp.customize.bind( 'ready', function () {} ). The function called when ready will ensure that the control and previewer are defined. – Weston Ruter Dec 16 '15 at 17:46
  • The ready state is never achieved. The closest I can get is using preview-ready, but I'm still unable to access previewer and control. Thanks. – David Gard Dec 16 '15 at 17:50
  • OK, I see. So the problem is that you are enqueueing the script into the Customizer preview when you actually need to enqueue it into the Customizer pane. In other words, just enqueue at customize_controls_enqueue_scripts. – Weston Ruter Dec 16 '15 at 19:53
  • Ah, I'm with you - your code needs to be in a completely separate file. It is working now, so thanks very much for the help. I am seeing a random error in Firebug though - TypeError: a is undefined: ...Case()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e+... - It doesn't seem to stop anything from working though. – David Gard Dec 17 '15 at 9:36

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.