add_dynamic_settings() публичный Метод

This is a mechanism to "wake up" settings that have been dynamically created on the front end and have been sent to WordPress in $_POST['customized']. When WP loads, the dynamically-created settings then will get created and previewed even though they are not directly created statically with code.
С версии: 4.2.0
public add_dynamic_settings ( array $setting_ids ) : array
$setting_ids array The setting IDs to add.
Результат array The WP_Customize_Setting objects added.
	/**
	 * Inspect the incoming customized data for any widget settings, and dynamically add them up-front so widgets will be initialized properly.
	 *
	 * @since 4.2.0
	 * @access public
	 */
	public function register_settings() {
		$widget_setting_ids = array();
		$incoming_setting_ids = array_keys( $this->manager->unsanitized_post_values() );
		foreach ( $incoming_setting_ids as $setting_id ) {
			if ( ! is_null( $this->get_setting_type( $setting_id ) ) ) {
				$widget_setting_ids[] = $setting_id;
			}
		}
		if ( $this->manager->doing_ajax( 'update-widget' ) && isset( $_REQUEST['widget-id'] ) ) {
			$widget_setting_ids[] = $this->get_setting_id( wp_unslash( $_REQUEST['widget-id'] ) );
		}

		$settings = $this->manager->add_dynamic_settings( array_unique( $widget_setting_ids ) );

		/*
		 * Preview settings right away so that widgets and sidebars will get registered properly.
		 * But don't do this if a customize_save because this will cause WP to think there is nothing
		 * changed that needs to be saved.
		 */
		if ( ! $this->manager->doing_ajax( 'customize_save' ) ) {
			foreach ( $settings as $setting ) {
				$setting->preview();
			}
		}
	}
 private function _save()
 {
     $post_values = $this->_customize->unsanitized_post_values();
     $key = '_' . static::KEY;
     if (isset($post_values[$key])) {
         $this->_customize->add_dynamic_settings(array_map('sanitize_key', $post_values[$key]));
     }
 }
 /**
  * Publish snapshot changes when snapshot post is being published.
  *
  * The logic in here is the inverse of to publish_snapshot_with_customize_save_after.
  *
  * The meat of the logic that manipulates the post_content and validates the settings
  * needs to be done in wp_insert_post_data filter in like a
  * filter_insert_post_data_to_validate_published_snapshot method? This would
  * have the benefit of reducing one wp_insert_post() call.
  *
  * @todo Consider using wp_insert_post_data to prevent double calls to wp_insert_post().
  * @see Customize_Snapshot_Manager::publish_snapshot_with_customize_save_after()
  *
  * @param string   $new_status New status.
  * @param string   $old_status Old status.
  * @param \WP_Post $post       Post object.
  * @return bool Whether the settings were saved.
  */
 public function save_settings_with_publish_snapshot($new_status, $old_status, $post)
 {
     // Abort if not transitioning a snapshot post to publish from a non-publish status.
     if (Post_Type::SLUG !== $post->post_type || 'publish' !== $new_status || $new_status === $old_status) {
         return false;
     }
     $this->ensure_customize_manager();
     if ($this->doing_customize_save_ajax()) {
         // Short circuit because customize_save ajax call is changing status.
         return false;
     }
     if (!did_action('customize_register')) {
         /*
          * When running from CLI or Cron, we have to remove the action because
          * it will get added with a default priority of 10, after themes and plugins
          * have already done add_action( 'customize_register' ), resulting in them
          * being called first at the priority 10. So we manually call the
          * prerequisite function WP_Customize_Manager::register_controls() and
          * remove it from being called when the customize_register action fires.
          */
         remove_action('customize_register', array($this->customize_manager, 'register_controls'));
         $this->customize_manager->register_controls();
         /*
          * Unfortunate hack to prevent \WP_Customize_Widgets::customize_register()
          * from calling preview() on settings. This needs to be cleaned up in core.
          * It is important for previewing to be prevented because if an option has
          * a filter it will short-circuit when an update is attempted since it
          * detects that there is no change to be put into the DB.
          * See: https://github.com/xwp/wordpress-develop/blob/e8c58c47db1421a1d0b2afa9ad4b9eb9e1e338e0/src/wp-includes/class-wp-customize-widgets.php#L208-L217
          */
         if (!defined('DOING_AJAX')) {
             define('DOING_AJAX', true);
         }
         $_REQUEST['action'] = 'customize_save';
         /** This action is documented in wp-includes/class-wp-customize-manager.php */
         do_action('customize_register', $this->customize_manager);
         // undefine( 'DOING_AJAX' )... just kidding. This is the end of the unfortunate hack and it should be fixed in Core.
         unset($_REQUEST['action']);
     }
     $snapshot_content = $this->post_type->get_post_content($post);
     if (method_exists($this->customize_manager, 'validate_setting_values')) {
         /** This action is documented in wp-includes/class-wp-customize-manager.php */
         do_action('customize_save_validation_before', $this->customize_manager);
     }
     $setting_ids = array_keys($snapshot_content);
     $this->customize_manager->add_dynamic_settings($setting_ids);
     /** This action is documented in wp-includes/class-wp-customize-manager.php */
     do_action('customize_save', $this->customize_manager);
     /**
      * Settings to save.
      *
      * @var \WP_Customize_Setting[]
      */
     $settings = array();
     $publish_error_count = 0;
     foreach ($snapshot_content as $setting_id => &$setting_params) {
         // Missing value error.
         if (!isset($setting_params['value']) || is_null($setting_params['value'])) {
             if (!is_array($setting_params)) {
                 if (!empty($setting_params)) {
                     $setting_params = array('value' => $setting_params);
                 } else {
                     $setting_params = array();
                 }
             }
             $setting_params['publish_error'] = 'null_value';
             $publish_error_count += 1;
             continue;
         }
         // Unrecognized setting error.
         $this->customize_manager->set_post_value($setting_id, $setting_params['value']);
         $setting = $this->customize_manager->get_setting($setting_id);
         if (!$setting instanceof \WP_Customize_Setting) {
             $setting_params['publish_error'] = 'unrecognized_setting';
             $publish_error_count += 1;
             continue;
         }
         // Validate setting value.
         if (method_exists($setting, 'validate')) {
             $validity = $setting->validate($setting_params['value']);
             if (is_wp_error($validity)) {
                 $setting_params['publish_error'] = $validity->get_error_code();
                 $publish_error_count += 1;
                 continue;
             }
         }
         // Validate sanitized setting value.
         $sanitized_value = $setting->sanitize($setting_params['value']);
         if (is_null($sanitized_value) || is_wp_error($sanitized_value)) {
             $setting_params['publish_error'] = is_wp_error($sanitized_value) ? $sanitized_value->get_error_code() : 'invalid_value';
             $publish_error_count += 1;
             continue;
         }
         $settings[] = $setting;
         unset($setting_params['publish_error']);
     }
     // Handle error scenarios.
     if ($publish_error_count > 0) {
         $update_setting_args = array('ID' => $post->ID, 'post_content' => Customize_Snapshot_Manager::encode_json($snapshot_content), 'post_status' => 'pending');
         wp_update_post(wp_slash($update_setting_args));
         update_post_meta($post->ID, 'snapshot_error_on_publish', $publish_error_count);
         add_filter('redirect_post_location', function ($location) {
             $location = add_query_arg('snapshot_error_on_publish', '1', $location);
             return $location;
         });
         return false;
     }
     /*
      * Change all setting capabilities temporarily to 'exist' to allow them to
      * be saved regardless of current user, such as when WP-Cron is publishing
      * the snapshot post if it was scheduled. It is safe to do this because
      * a setting can only be written into a snapshot by users who have the
      * capability, so after it has been added to a snapshot it is good to commit.
      */
     $existing_caps = wp_list_pluck($settings, 'capability');
     foreach ($settings as $setting) {
         $setting->capability = 'exist';
     }
     // Persist the settings in the DB.
     foreach ($settings as $setting) {
         $setting->save();
     }
     // Restore setting capabilities.
     foreach ($existing_caps as $setting_id => $existing_cap) {
         $settings[$setting_id]->capability = $existing_cap;
     }
     /** This action is documented in wp-includes/class-wp-customize-manager.php */
     do_action('customize_save_after', $this->customize_manager);
     // Remove any previous error on setting.
     delete_post_meta($post->ID, 'snapshot_error_on_publish');
     return true;
 }
 /**
  * Add the customizer settings and controls.
  *
  * @since 4.3.0
  * @access public
  */
 public function customize_register()
 {
     // Preview settings for nav menus early so that the sections and controls will be added properly.
     $nav_menus_setting_ids = array();
     foreach (array_keys($this->manager->unsanitized_post_values()) as $setting_id) {
         if (preg_match('/^(nav_menu_locations|nav_menu|nav_menu_item)\\[/', $setting_id)) {
             $nav_menus_setting_ids[] = $setting_id;
         }
     }
     $this->manager->add_dynamic_settings($nav_menus_setting_ids);
     if (!$this->manager->doing_ajax('customize_save')) {
         foreach ($nav_menus_setting_ids as $setting_id) {
             $setting = $this->manager->get_setting($setting_id);
             if ($setting) {
                 $setting->preview();
             }
         }
     }
     // Require JS-rendered control types.
     $this->manager->register_panel_type('WP_Customize_Nav_Menus_Panel');
     $this->manager->register_control_type('WP_Customize_Nav_Menu_Control');
     $this->manager->register_control_type('WP_Customize_Nav_Menu_Name_Control');
     $this->manager->register_control_type('WP_Customize_Nav_Menu_Auto_Add_Control');
     $this->manager->register_control_type('WP_Customize_Nav_Menu_Item_Control');
     // Create a panel for Menus.
     $description = '<p>' . __('This panel is used for managing navigation menus for content you have already published on your site. You can create menus and add items for existing content such as pages, posts, categories, tags, formats, or custom links.') . '</p>';
     if (current_theme_supports('widgets')) {
         /* translators: URL to the widgets panel of the customizer */
         $description .= '<p>' . sprintf(__('Menus can be displayed in locations defined by your theme or in <a href="%s">widget areas</a> by adding a &#8220;Custom Menu&#8221; widget.'), "javascript:wp.customize.panel( 'widgets' ).focus();") . '</p>';
     } else {
         $description .= '<p>' . __('Menus can be displayed in locations defined by your theme.') . '</p>';
     }
     $this->manager->add_panel(new WP_Customize_Nav_Menus_Panel($this->manager, 'nav_menus', array('title' => __('Menus'), 'description' => $description, 'priority' => 100)));
     $menus = wp_get_nav_menus();
     // Menu locations.
     $locations = get_registered_nav_menus();
     $num_locations = count(array_keys($locations));
     if (1 == $num_locations) {
         $description = '<p>' . __('Your theme supports one menu. Select which menu you would like to use.') . '</p>';
     } else {
         /* translators: %s: number of menu locations */
         $description = '<p>' . sprintf(_n('Your theme supports %s menu. Select which menu appears in each location.', 'Your theme supports %s menus. Select which menu appears in each location.', $num_locations), number_format_i18n($num_locations)) . '</p>';
     }
     if (current_theme_supports('widgets')) {
         /* translators: URL to the widgets panel of the customizer */
         $description .= '<p>' . sprintf(__('You can also place menus in <a href="%s">widget areas</a> with the &#8220;Custom Menu&#8221; widget.'), "javascript:wp.customize.panel( 'widgets' ).focus();") . '</p>';
     }
     $this->manager->add_section('menu_locations', array('title' => __('Menu Locations'), 'panel' => 'nav_menus', 'priority' => 5, 'description' => $description));
     $choices = array('0' => __('&mdash; Select &mdash;'));
     foreach ($menus as $menu) {
         $choices[$menu->term_id] = wp_html_excerpt($menu->name, 40, '&hellip;');
     }
     foreach ($locations as $location => $description) {
         $setting_id = "nav_menu_locations[{$location}]";
         $setting = $this->manager->get_setting($setting_id);
         if ($setting) {
             $setting->transport = 'postMessage';
             remove_filter("customize_sanitize_{$setting_id}", 'absint');
             add_filter("customize_sanitize_{$setting_id}", array($this, 'intval_base10'));
         } else {
             $this->manager->add_setting($setting_id, array('sanitize_callback' => array($this, 'intval_base10'), 'theme_supports' => 'menus', 'type' => 'theme_mod', 'transport' => 'postMessage', 'default' => 0));
         }
         $this->manager->add_control(new WP_Customize_Nav_Menu_Location_Control($this->manager, $setting_id, array('label' => $description, 'location_id' => $location, 'section' => 'menu_locations', 'choices' => $choices)));
     }
     // Register each menu as a Customizer section, and add each menu item to each menu.
     foreach ($menus as $menu) {
         $menu_id = $menu->term_id;
         // Create a section for each menu.
         $section_id = 'nav_menu[' . $menu_id . ']';
         $this->manager->add_section(new WP_Customize_Nav_Menu_Section($this->manager, $section_id, array('title' => html_entity_decode($menu->name, ENT_QUOTES, get_bloginfo('charset')), 'priority' => 10, 'panel' => 'nav_menus')));
         $nav_menu_setting_id = 'nav_menu[' . $menu_id . ']';
         $this->manager->add_setting(new WP_Customize_Nav_Menu_Setting($this->manager, $nav_menu_setting_id, array('transport' => 'postMessage')));
         // Add the menu contents.
         $menu_items = (array) wp_get_nav_menu_items($menu_id);
         foreach (array_values($menu_items) as $i => $item) {
             // Create a setting for each menu item (which doesn't actually manage data, currently).
             $menu_item_setting_id = 'nav_menu_item[' . $item->ID . ']';
             $value = (array) $item;
             if (empty($value['post_title'])) {
                 $value['title'] = '';
             }
             $value['nav_menu_term_id'] = $menu_id;
             $this->manager->add_setting(new WP_Customize_Nav_Menu_Item_Setting($this->manager, $menu_item_setting_id, array('value' => $value, 'transport' => 'postMessage')));
             // Create a control for each menu item.
             $this->manager->add_control(new WP_Customize_Nav_Menu_Item_Control($this->manager, $menu_item_setting_id, array('label' => $item->title, 'section' => $section_id, 'priority' => 10 + $i)));
         }
         // Note: other controls inside of this section get added dynamically in JS via the MenuSection.ready() function.
     }
     // Add the add-new-menu section and controls.
     $this->manager->add_section(new WP_Customize_New_Menu_Section($this->manager, 'add_menu', array('title' => __('Add a Menu'), 'panel' => 'nav_menus', 'priority' => 999)));
     $this->manager->add_control('new_menu_name', array('label' => '', 'section' => 'add_menu', 'type' => 'text', 'settings' => array(), 'input_attrs' => array('class' => 'menu-name-field', 'placeholder' => __('New menu name'))));
     $this->manager->add_control(new WP_Customize_New_Menu_Control($this->manager, 'create_new_menu', array('section' => 'add_menu', 'settings' => array())));
     $this->manager->add_setting(new WP_Customize_Filter_Setting($this->manager, 'nav_menus_created_posts', array('transport' => 'postMessage', 'type' => 'option', 'default' => array(), 'sanitize_callback' => array($this, 'sanitize_nav_menus_created_posts'))));
 }