web-dev-qa-db-fra.com

Commandes actives à bascule de rappel automatique du Customizer

J'ai donc activé l'option de ne pas afficher les contrôles si le contrôle n'est pas actif, mais le problème est que cela ne fonctionne que lorsque vous actualisez la page de personnalisation.

Dans mon exemple, j'ai un contrôle de corps encadré, qui est une case à cocher (bien que j'aie utilisé le contrôle personnalisé pour le styler un peu différemment, vous pouvez trouver le code ici ). Si cette option est désactivée, les contrôles associés pouvant modifier la largeur, la couleur, la couleur de fond, etc. de la bordure du corps encadré sont tous masqués. Si vous activez le corps encadré, vous devez actualiser la page pour voir ces contrôles, ce qui est un sinistre UX. Le code est:

CODE INITIAL

add_action( 'customize_register', 'mytheme_customize_register' );
/**
 * Register customizer settings
 *
 * @see add_action('customize_register',$func)
 * @param  \WP_Customize_Manager $wp_customize WP Customize object.
 * @since 1.0.0
 */
function mytheme_customize_register( WP_Customize_Manager $wp_customize ) {

    /**
    Boxed Body
    */
    $wp_customize->add_setting( 'boxed_body', array(
        'default'           => false,
        'transport'         => 'postMessage',
        'sanitize_callback' => 'mytheme_checkbox_sanitization',
    ) );
    $wp_customize->add_control(new Toggle_Checkbox_Custom_Control( $wp_customize, 'boxed_body', array(
        'label'       => esc_html__( 'Boxed Body', 'mytheme' ),
        'description' => esc_html__( 'Check this to enable boxed body layout', 'mytheme' ),
        'type'        => 'checkbox',
        'section'     => 'section_general',
    ) ) );

    /**
     * Callback function for boxed body choice
     *
     * @param  object $control Control object.
     * @return boolean
     */
    function boxed_body_choice( $control ) {
        if ( 1 === $control->manager->get_setting( 'boxed_body' )->value() ) {
            return true;
        } else {
            return false;
        }
    }

    /**
    Boxed Body Border Color
    */
    $wp_customize->add_setting( 'boxed_body_border_color', array(
        'default'           => '',
        'transport'         => 'postMessage',
        'sanitize_callback' => 'sanitize_hex_color',
    ) );
    $wp_customize->add_control(new WP_Customize_Color_Control( $wp_customize, 'boxed_body_border_color', array(
        'label'    => esc_html__( 'Boxed Body Border Color', 'mytheme' ),
        'settings' => 'boxed_body_border_color',
        'section'  => 'section_general',
        'active_callback' => 'boxed_body_choice',
    ) ) );

}

add_action( 'customize_preview_init', 'mytheme_customizer_live_preview' );
/**
 * Live preview script enqueue
 *
 * @since 1.0.0
 */
function mytheme_customizer_live_preview() {
    wp_enqueue_script( 'mytheme-themecustomizer', get_template_directory_uri() . '/inc/customizer/js/customizer.js?v=' . Rand(), array( 'jquery', 'customize-preview' ), '', true );
}

J'ai essayé de suivre l'exemple de Weston Ruter sur les contrôles contextuels ici et Gist , mais pas de chance. J'ai ajouté dans mon customizer.js

(function($) {

    // Add callback for when the boxed_body setting is toggled.
    wp.customize( 'boxed_body', function(setting) {
        var isBoxedBodyToggled, linkSettingValueToControlActiveState;

        /**
         * Determine whether the boxed body associated options should be displayed.
         *
         * @returns {boolean} Is toggled?
         */
        isBoxedBodyToggled = function() {
            return '' !== setting.get();
        };

        /**
         * Update a control's active state according to the boxed_body setting's value.
         *
         * @param {wp.customize.Control} control Boxed body control.
         */
        linkSettingValueToControlActiveState = function( control ) {
            var setActiveState = function() {
                control.active.set( isBoxedBodyToggled() );
            };

            // FYI: With the following we can eliminate all of our PHP active_callback code.
            control.active.validate = isBoxedBodyToggled;

            // Set initial active state.
            setActiveState();

            /*
             * Update activate state whenever the setting is changed.
             * Even when the setting does have a refresh transport where the
             * server-side active callback will manage the active state upon
             * refresh, having this JS management of the active state will
             * ensure that controls will have their visibility toggled
             * immediately instead of waiting for the preview to load.
             * This is especially important if the setting has a postMessage
             * transport where changing the setting wouldn't normally cause
             * the preview to refresh and thus the server-side active_callbacks
             * would not get invoked.
             */
            setting.bind( setActiveState );
        };

        // Call linkSettingValueToControlActiveState on the site title and tagline controls when they exist.
        wp.customize.control( 'boxed_body_border_width', linkSettingValueToControlActiveState );
        wp.customize.control( 'boxed_body_border_color', linkSettingValueToControlActiveState );
        wp.customize.control( 'boxed_body_border_style', linkSettingValueToControlActiveState );
        wp.customize.control( 'boxed_body_bg_image', linkSettingValueToControlActiveState );
        wp.customize.control( 'boxed_body_bg_image_repeat', linkSettingValueToControlActiveState );
        wp.customize.control( 'boxed_body_bg_image_size', linkSettingValueToControlActiveState );
        wp.customize.control( 'boxed_body_bg_image_position', linkSettingValueToControlActiveState );
        wp.customize.control( 'boxed_body_bg_image_attachment', linkSettingValueToControlActiveState );

    });

})(jQuery);

Mais lors de l'actualisation du personnalisateur, je reçois

Uncaught TypeError: wp.customize.control n'est pas une fonction (…)

Sur le

wp.customize.control( 'boxed_body_border_width', linkSettingValueToControlActiveState );

Et la bascule ne cachera pas ou ne montrera pas les contrôles. Certaines modifications ont été apportées pour correspondre au contrôle de bascule personnalisé. Je ne vérifie donc pas 'blank', mais plutôt '' dans la fonction isBoxedBodyToggled.

Quand je bricole dans DevTools, je peux voir que wp.customize est une fonction, pas un objet. Dans l'exemple, cela devrait être un objet (je suppose).

Toute aide serait appréciée.

NOUVEAU CODE

J'ai donc remarqué que je n'ai pas besoin de beaucoup de contrôles depuis que j'ai ajouté

add_theme_support( 'custom-background' );

ce qui me donne un contrôle intégré pour l'arrière-plan du corps, alors je l'ai fait comme ceci:

add_action( 'customize_register', 'mytheme_customize_register' );
/**
 * Register customizer settings
 *
 * @see add_action('customize_register',$func)
 * @param  \WP_Customize_Manager $wp_customize WP Customize object.
 * @since 1.0.0
 */
function mytheme_customize_register( WP_Customize_Manager $wp_customize ) {

    /**
    ------------------------------------------------------------
    SECTION: Body Settings
    ------------------------------------------------------------
    */
    $wp_customize->add_section( 'background_image', array(
        'title'    => esc_html__( 'Body Settings', 'mytheme' ),
        'priority' => 0,
    ) );

    /**
    Boxed Body
    */
    $wp_customize->add_setting( 'boxed_body', array(
        'default'           => false,
        'transport'         => 'postMessage',
        'sanitize_callback' => 'mytheme_checkbox_sanitization',
    ) );
    $wp_customize->add_control(new Toggle_Checkbox_Custom_Control( $wp_customize, 'boxed_body', array(
        'label'       => esc_html__( 'Boxed Body', 'mytheme' ),
        'description' => esc_html__( 'Check this to enable boxed body layout', 'mytheme' ),
        'type'        => 'checkbox',
        'section'     => 'background_image',
        'priority'    => 0,
    ) ) );

    /**
     * Callback function for boxed body choice
     *
     * @param  object $control Control object.
     * @return boolean
     */
    function boxed_body_choice( $control ) {
        if ( 1 === $control->manager->get_setting( 'boxed_body' )->value() ) {
            return true;
        } else {
            return false;
        }
    }

    /**
    Boxed Body Border Color
    */
    $wp_customize->add_setting( 'boxed_body_border_color', array(
        'default'           => '',
        'transport'         => 'postMessage',
        'sanitize_callback' => 'sanitize_hex_color',
    ) );
    $wp_customize->add_control(new WP_Customize_Color_Control( $wp_customize, 'boxed_body_border_color', array(
        'label'           => esc_html__( 'Boxed Body Border Color', 'mytheme' ),
        'settings'        => 'boxed_body_border_color',
        'section'         => 'background_image',
        'active_callback' => 'boxed_body_choice',
        'priority'        => 0,
    ) ) );

}

add_action( 'customize_preview_init', 'mytheme_customizer_live_preview' );
/**
 * Live preview script enqueue
 *
 * @since 1.0.0
 */
function mytheme_customizer_live_preview() {
    wp_enqueue_script( 'mytheme-themecustomizer', get_template_directory_uri() . '/inc/customizer/js/customizer.js?v=' . Rand(), array( 'jquery', 'customize-preview' ), '', true );
}

Et le customizer.js ressemble à ceci

(function($, api) {
    'use strict';

    //Boxed Body Toggle
    api( 'boxed_body', function(value) {
        value.bind(function(newval) {
            if (newval) {
                $('body').wrapInner('<div class="boxed_body_wrapper" />');
            } else {
                $('.boxed_body_wrapper').contents().unwrap();
            }
        });
    });

    // Add callback for when the boxed_body setting is toggled.
    api( 'boxed_body', function(value) {
        value.bind(function(setting){
            var isBoxedBodyToggled, linkSettingValueToControlActiveState;

            /**
             * Determine whether the boxed body associated options should be displayed.
             *
             * @returns {boolean} Is toggled?
             */
            isBoxedBodyToggled = function() {
                return '' !== setting.get();
            };

            /**
             * Update a control's active state according to the boxed_body setting's value.
             *
             * @param {api.Control} control Boxed body control.
             */
            linkSettingValueToControlActiveState = function( control ) {
                var setActiveState = function() {
                    control.active.set( isBoxedBodyToggled() );
                };

                // FYI: With the following we can eliminate all of our PHP active_callback code.
                control.active.validate = isBoxedBodyToggled;
                // Set initial active state.
                setActiveState();

                /*
                 * Update activate state whenever the setting is changed.
                 * Even when the setting does have a refresh transport where the
                 * server-side active callback will manage the active state upon
                 * refresh, having this JS management of the active state will
                 * ensure that controls will have their visibility toggled
                 * immediately instead of waiting for the preview to load.
                 * This is especially important if the setting has a postMessage
                 * transport where changing the setting wouldn't normally cause
                 * the preview to refresh and thus the server-side active_callbacks
                 * would not get invoked.
                 */

                setting.bind( setActiveState );
            };

            // Call linkSettingValueToControlActiveState on the site title and tagline controls when they exist.
            api.control( 'boxed_body_border_color', linkSettingValueToControlActiveState );
        });
    });

})(jQuery, wp.customize);

Je reçois encore

customizer.js? v = 1256189197 & ver = 4.7: 111 TypeError non capturé: api.control n'est pas une fonction

à i (jquery.js? ver = 1.12.4: 2)

à Object.fireWith (jquery.js? ver = 1.12.4: 2)

at Function.set (personnaliser-base.min.js? ver = 4.7: 1)

at Function.d [en tant que jeu] (jquery.js? ver = 1.12.4: 2)

en c (personnaliser-preview.min.js? ver = 4.7: 1)

à f. (personnaliser-preview.min.js? ver = 4.7: 1)

à i (jquery.js? ver = 1.12.4: 2)

à Object.fireWith (jquery.js? ver = 1.12.4: 2)

at f.trigger (personnaliser-base.min.js? ver = 4.7: 1)

Si j'ajoute 'customize-controls' comme dépendance, j'obtiens l'erreur:

Uncaught TypeError: Impossible de lire la propriété 'dirty' of indéfinie

à Function.initialize (personnaliser-controls.min.js? ver = 4.7: 1)

at f.e.Class (personnaliser-base.min.js? ver = 4.7: 1)

at f [en tant que constructeur] (personnaliser-base.min.js? ver = 4.7: 1)

at new f (personnaliser-base.min.js? ver = 4.7: 1)

à Function.create (personnaliser-base.min.js? ver = 4.7: 1)

at String.c (personnaliser-preview.min.js? ver = 4.7: 1)

à Function.each (jquery.js? ver = 1.12.4: 2)

à f. (personnaliser-preview.min.js? ver = 4.7: 1)

à i (jquery.js? ver = 1.12.4: 2)

à Object.fireWith (jquery.js? ver = 1.12.4: 2)

Toujours pas sûr de ce que je fais mal: \

EDIT

J'ai utilisé le mauvais crochet d'action lors de la mise en file d'attente. J'ai créé un autre fichier dans lequel j'ai ajouté:

add_action( 'customize_controls_enqueue_scripts', 'utter_customizer_control_toggle' );

/**
 * Custom contextual controls
 *
 * @since 1.0.0
 */
function utter_customizer_control_toggle() {
    wp_enqueue_script( 'utter-contextualcontrols', UTTER_TEMPPATH . '/inc/customizer/js/customizer-contextual.js?v=' . Rand(), array( 'customize-controls' ), false );
}

Cela supprime toutes les erreurs. Et la bascule fonctionne la première fois, mais pas lorsque je bascule en arrière, mais je suppose que cela a à voir avec le contrôle personnalisé que j'utilise plutôt que la case à cocher standard. Je vais probablement résoudre ce problème bientôt: D

1
dingo_d

La solution consistait à "découpler" l'aperçu en direct et le contrôle contextuel. Si je les place ensemble, je ne peux pas utiliser le même crochet d’action - live ne fonctionnera pas sur customize_controls_enqueue_scripts et le contrôle contextuel ne fonctionnera pas sur customize_preview_init.

Donc, la réponse est:

add_action( 'customize_controls_enqueue_scripts', 'mytheme_customizer_control_toggle' );
add_action( 'customize_preview_init', 'mytheme_customizer_live_preview' );
/**
 * Live preview script enqueue
 *
 * @since 1.0.0
 */
function mytheme_customizer_live_preview() {
    wp_enqueue_script( 'mytheme-themecustomizer', get_template_directory_uri() . '/inc/customizer/js/customizer.js?v=' . Rand(), array( 'jquery', 'customize-preview' ), false );
}

/**
 * Custom contextual controls
 *
 * @since 1.0.0
 */
function mytheme_customizer_control_toggle() {
    wp_enqueue_script( 'mytheme-contextualcontrols', get_template_directory_uri() . '/inc/customizer/js/customizer-contextual.js?v=' . Rand(), array( 'customize-controls' ), false );
}

Le code de contrôle contextuel est

( function( api ) {
    'use strict';

    api( 'boxed_body', function(setting) {
        var isBoxedBodyToggled, linkSettingValueToControlActiveState;

        /**
         * Determine whether the boxed body associated options should be displayed.
         *
         * @returns {boolean} Is toggled?
         */
        isBoxedBodyToggled = function() {
            return '' !== setting.get();
        };

        /**
         * Update a control's active state according to the boxed_body setting's value.
         *
         * @param {api.Control} control Boxed body control.
         */
        linkSettingValueToControlActiveState = function( control ) {
            var setActiveState = function() {
                control.active.set( isBoxedBodyToggled() );
            };

            // FYI: With the following we can eliminate all of our PHP active_callback code.
            control.active.validate = isBoxedBodyToggled;
            // Set initial active state.
            setActiveState();

            /*
             * Update activate state whenever the setting is changed.
             * Even when the setting does have a refresh transport where the
             * server-side active callback will manage the active state upon
             * refresh, having this JS management of the active state will
             * ensure that controls will have their visibility toggled
             * immediately instead of waiting for the preview to load.
             * This is especially important if the setting has a postMessage
             * transport where changing the setting wouldn't normally cause
             * the preview to refresh and thus the server-side active_callbacks
             * would not get invoked.
             */

            setting.bind( setActiveState );
        };

        // Call linkSettingValueToControlActiveState on the site title and tagline controls when they exist.
        api.control( 'boxed_body_border_width', linkSettingValueToControlActiveState );
        api.control( 'boxed_body_border_color', linkSettingValueToControlActiveState );
        api.control( 'boxed_body_border_style', linkSettingValueToControlActiveState );
    });

}( wp.customize ) );

Le problème que j'ai maintenant est que mon contrôle personnalisé ne fonctionne pas correctement, mais c'est un problème différent que je peux facilement résoudre.

Merci à Weston Ruter de m'avoir orienté dans la bonne direction :)

Édition de travail

Pour une raison quelconque, le code ci-dessus n'a basculé les contrôles qu'une seule fois. Je l'ai donc réécrit comme ceci.

( function( api ) {
    'use strict';

    api.bind( 'ready', function() {

        api( 'boxed_body', function(setting) {
            var linkSettingValueToControlActiveState;

            /**
             * Update a control's active state according to the boxed_body setting's value.
             *
             * @param {api.Control} control Boxed body control.
             */
            linkSettingValueToControlActiveState = function( control ) {
                var visibility = function() {
                    if ( true === setting.get() || 1 === setting.get() ) {
                        control.container.slideDown( 180 );
                    } else {
                        control.container.slideUp( 180 );
                    }
                };

                // Set initial active state.
                visibility();
                //Update activate state whenever the setting is changed.
                setting.bind( visibility );
            };

            // Call linkSettingValueToControlActiveState on the border controls when they exist.
            api.control( 'boxed_body_border_width', linkSettingValueToControlActiveState );
            api.control( 'boxed_body_border_color', linkSettingValueToControlActiveState );
            api.control( 'boxed_body_border_style', linkSettingValueToControlActiveState );
        });

    });

}( wp.customize ) );

Et cela semble bien fonctionner. J'ai utilisé les Twenty Seventeen comme guide, ils basculent la palette de couleurs personnalisée de la même manière.

2
dingo_d