Элементы управления активным обратным вызовом

Поэтому я включил возможность не отображать элементы управления, если один элемент управления неактивен, но проблема в том, что это работает только при обновлении страницы настройки.

В моем примере у меня есть элемент управления тегом в коробке, который является флажком (хотя я использовал собственный элемент управления, чтобы немного по-другому его разузнать, здесь вы можете найти код). Если он отключен, все связанные элементы управления, которые могут изменять ширину рамки, размер, цвет фона и т. Д., Скрыты. Если вы включите тело в коробке, вам нужно обновить страницу, чтобы увидеть те элементы управления, которые являются UX-катастрофами. Код:

НАЧАЛЬНЫЙ КОД

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 ); } 

Я пробовал следующий пример Уэстона Ратера по контекстному управлению здесь и по сути , но не повезло. Я добавил в свой 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); 

Но при настройке обновления я получаю

Uncaught TypeError: wp.customize.control не является функцией (…)

На

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

И переключатель не будет скрывать или показывать элементы управления. Я внес некоторые изменения, чтобы соответствовать настраиваемому элементу управления, поэтому я не проверяю 'blank' а скорее '' в функции isBoxedBodyToggled .

Когда я играю в DevTools, я вижу, что wp.customize – это функция, а не объект. В примере это должен быть объект (я думаю).

Любая помощь будет оценена по достоинству.

НОВЫЙ КОД

Поэтому я заметил, что мне не нужны такие элементы управления, поскольку я добавил

 add_theme_support( 'custom-background' ); 

который дает мне встроенный контроль за фоном тела, поэтому я сделал это следующим образом:

 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 ); } 

И customizer.js выглядит так

 (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); 

Я до сих пор

customizer.js? v = 1256189197 & ver = 4.7: 111 Uncaught TypeError: api.control не является функцией

при i (jquery.js? ver = 1.12.4: 2)

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

на Function.set (customize-base.min.js? ver = 4.7: 1)

в функции.d [как установлено] (jquery.js? ver = 1.12.4: 2)

в c (customize-preview.min.js? ver = 4.7: 1)

в f. (Настройки-preview.min.js вер = 4,7: 1)

при i (jquery.js? ver = 1.12.4: 2)

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

в f.trigger (customize-base.min.js? ver = 4.7: 1)

Если я добавлю 'customize-controls' в качестве зависимости, я получу ошибку:

Uncaught TypeError: Невозможно прочитать свойство «грязный» неопределенного

в Function.initialize (customize-controls.min.js? ver = 4.7: 1)

на feClass (customize-base.min.js? ver = 4.7: 1)

в f [в качестве конструктора] (customize-base.min.js? ver = 4.7: 1)

при новом f (customize-base.min.js? ver = 4.7: 1)

на Function.create (customize-base.min.js? ver = 4.7: 1)

в String.c (customize-preview.min.js? ver = 4.7: 1)

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

в f. (Настройки-preview.min.js вер = 4,7: 1)

при i (jquery.js? ver = 1.12.4: 2)

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

Все еще не уверен, что я делаю неправильно: \

РЕДАКТИРОВАТЬ

Я использовал неправильный крючок действия при вклеивании. Я создал другой файл, в который я добавил:

 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 ); } 

Это избавляет от всех ошибок. И переключение работает в первый раз, но не тогда, когда я переключаюсь обратно, но я предполагаю, что это связано с настраиваемым элементом управления, который я использую вместо обычного флажка. Скорее всего, я исправлю это скоро: D

Ответ состоял в том, чтобы «разделить» предварительный просмотр и контекстный контроль. Если я поместил их вместе, я не могу использовать один и тот же action-hook – live не будет работать с customize_controls_enqueue_scripts и контекстный контроль не будет работать на customize_preview_init .

Итак, ответ:

 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 ); } 

Контекстный код управления

 ( 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 ) ); 

Теперь проблема заключается в том, что мой пользовательский элемент управления работает неправильно, но это другая проблема, которую я могу легко решить.

Спасибо Weston Ruter за то, что он указал мне в правильном направлении 🙂

РАБОЧИЙ РЕДАКТИРОВАНИЕ

По какой-то причине вышеупомянутый код только один раз переключил элементы управления, поэтому я переписал его так

 ( 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 ) ); 

И это, кажется, работает нормально. Я использовал «Двадцать семнадцать» в качестве руководства, они так же переключали пользовательскую цветовую схему.