public function reset_customizer() { $settings = $this->wp_customize->settings(); // remove theme_mod settings registered in customizer foreach ($settings as $setting) { if ('theme_mod' == $setting->type) { remove_theme_mod($setting->id); } if ('option' == $setting->type) { global $igthemes_option; delete_option($igthemes_option); } } }
/** * Temporarily remove widget settings and controls from the Manager so that * they won't be serialized at once in _wpCustomizeSettings. This greatly * reduces the peak memory usage. * * This is only relevant in WordPress versions older than 4.4-alpha-33636-src, * with the changes introduced in Trac #33898. * * @link https://core.trac.wordpress.org/ticket/33898 */ function defer_serializing_data_until_shutdown() { $this->customize_controls = array(); $controls = $this->manager->controls(); foreach ($controls as $control) { if ($control instanceof \WP_Widget_Form_Customize_Control || $control instanceof \WP_Widget_Area_Customize_Control) { $this->customize_controls[$control->id] = $control; $this->manager->remove_control($control->id); } } /* * Note: There is currently a Core dependency issue where the control for WP_Widget_Area_Customize_Control * must be processed after the control for WP_Widget_Form_Customize_Control, as otherwise the sidebar * does not initialize properly (specifically in regards to the reorder-toggle button. So this is why * we are including the WP_Widget_Area_Customize_Controls among those which are deferred. */ $this->customize_settings = array(); $settings = $this->manager->settings(); foreach ($settings as $setting) { if (preg_match('/^(widget_.+?\\[\\d+\\]|sidebars_widgets\\[.+?\\])$/', $setting->id)) { $this->customize_settings[$setting->id] = $setting; $this->manager->remove_setting($setting->id); } } // We have to use shutdown because no action is triggered after _wpCustomizeSettings is written. add_action('shutdown', array($this, 'export_data_with_peak_memory_usage_minimized'), 10); add_action('shutdown', array($this, 'fixup_widget_control_params_for_dom_deferral'), 11); }
/** * @see Widget_Posts::register_widget_instance_settings_early() * @see Widget_Posts::register_widget_settings() */ function test_register_widget_instance_settings_early() { $wp = new \WP(); $wp->main(); foreach ($this->customize_manager->settings() as $setting_id => $setting) { if (preg_match('/^widget_/', $setting_id)) { $this->assertInstanceOf(__NAMESPACE__ . '\\WP_Customize_Widget_Setting', $setting); } } }
/** * Hooks into the customize_save action to save modifications in theme_options/mods */ public function customize_save(\WP_Customize_Manager $manager) { foreach ($manager->settings() as $key => $setting) { if ($setting->type == 'theme_mod') { // We have to call this early to make sure it is saved $setting->save(); } } $mods = get_theme_mods(); if ($mods) { ksort($mods); static::writeConfigs("theme_options/mods", array('mods' => $mods)); } }
public function action_ajax_reset() { if (!check_ajax_referer('customizer-reset', 'nonce', false)) { wp_send_json_error('invalid_nonce'); } if ($this->wp_customizer) { $settings = $this->wp_customizer->settings(); foreach ($settings as $setting) { if ('theme_mod' == $setting->type) { remove_theme_mod($setting->id); } } } wp_send_json_success(); }
/** * Hooks into the customize_save action to save modifications in options/customize */ public function customize_save(\WP_Customize_Manager $manager) { $options = array(); foreach ($manager->settings() as $key => $setting) { if ($setting->type == 'option') { // We have to call this early to make sure it is saved $setting->save(); if (preg_match('/^[a-z0-9_\\-]+/i', $key, $matches)) { // Match the option name, stripping [] // This is to get the base option name for array values $key = $matches[0]; // Fetch the whole value at once $options[$key] = get_option($key); } } } $this->options_merge_save($options); }
/** * Find and invoke the widget update and control callbacks. * * Requires that $_POST be populated with the instance data. * * @since 3.9.0 * @access public * * @global array $wp_registered_widget_updates * @global array $wp_registered_widget_controls * * @param string $widget_id Widget ID. * @return WP_Error|array Array containing the updated widget information. * A WP_Error object, otherwise. */ public function call_widget_update($widget_id) { global $wp_registered_widget_updates, $wp_registered_widget_controls; $setting_id = $this->get_setting_id($widget_id); /* * Make sure that other setting changes have previewed since this widget * may depend on them (e.g. Menus being present for Custom Menu widget). */ if (!did_action('customize_preview_init')) { foreach ($this->manager->settings() as $setting) { if ($setting->id !== $setting_id) { $setting->preview(); } } } $this->start_capturing_option_updates(); $parsed_id = $this->parse_widget_id($widget_id); $option_name = 'widget_' . $parsed_id['id_base']; /* * If a previously-sanitized instance is provided, populate the input vars * with its values so that the widget update callback will read this instance */ $added_input_vars = array(); if (!empty($_POST['sanitized_widget_setting'])) { $sanitized_widget_setting = json_decode($this->get_post_value('sanitized_widget_setting'), true); if (false === $sanitized_widget_setting) { $this->stop_capturing_option_updates(); return new WP_Error('widget_setting_malformed'); } $instance = $this->sanitize_widget_instance($sanitized_widget_setting); if (is_null($instance)) { $this->stop_capturing_option_updates(); return new WP_Error('widget_setting_unsanitized'); } if (!is_null($parsed_id['number'])) { $value = array(); $value[$parsed_id['number']] = $instance; $key = 'widget-' . $parsed_id['id_base']; $_REQUEST[$key] = $_POST[$key] = wp_slash($value); $added_input_vars[] = $key; } else { foreach ($instance as $key => $value) { $_REQUEST[$key] = $_POST[$key] = wp_slash($value); $added_input_vars[] = $key; } } } // Invoke the widget update callback. foreach ((array) $wp_registered_widget_updates as $name => $control) { if ($name === $parsed_id['id_base'] && is_callable($control['callback'])) { ob_start(); call_user_func_array($control['callback'], $control['params']); ob_end_clean(); break; } } // Clean up any input vars that were manually added foreach ($added_input_vars as $key) { unset($_POST[$key]); unset($_REQUEST[$key]); } // Make sure the expected option was updated. if (0 !== $this->count_captured_options()) { if ($this->count_captured_options() > 1) { $this->stop_capturing_option_updates(); return new WP_Error('widget_setting_too_many_options'); } $updated_option_name = key($this->get_captured_options()); if ($updated_option_name !== $option_name) { $this->stop_capturing_option_updates(); return new WP_Error('widget_setting_unexpected_option'); } } // Obtain the widget instance. $option = $this->get_captured_option($option_name); if (null !== $parsed_id['number']) { $instance = $option[$parsed_id['number']]; } else { $instance = $option; } /* * Override the incoming $_POST['customized'] for a newly-created widget's * setting with the new $instance so that the preview filter currently * in place from WP_Customize_Setting::preview() will use this value * instead of the default widget instance value (an empty array). */ $this->manager->set_post_value($setting_id, $instance); // Obtain the widget control with the updated instance in place. ob_start(); $form = $wp_registered_widget_controls[$widget_id]; if ($form) { call_user_func_array($form['callback'], $form['params']); } $form = ob_get_clean(); $this->stop_capturing_option_updates(); return compact('instance', 'form'); }
/** * Keep track of which settings were actually saved. * * Note that the footwork with id_bases is needed because there is no * action for customize_save_{$setting_id}. * * @access private * @param \WP_Customize_Manager $wp_customize Customize manager. * @action customize_save */ public function _add_actions_for_flagging_saved_settings(\WP_Customize_Manager $wp_customize) { $seen_id_bases = array(); foreach ($wp_customize->settings() as $setting) { $id_data = $setting->id_data(); if (!isset($seen_id_bases[$id_data['base']])) { add_action('customize_save_' . $id_data['base'], array($this, '_flag_saved_setting_value')); $seen_id_bases[$id_data['base']] = true; } } }
/** * Test WP_Customize_Manager::save_changeset_post(). * * @ticket 30937 * @covers WP_Customize_Manager::save_changeset_post() */ function test_save_changeset_post_without_theme_activation() { global $wp_customize; wp_set_current_user(self::$admin_user_id); $did_action = array('customize_save_validation_before' => did_action('customize_save_validation_before'), 'customize_save' => did_action('customize_save'), 'customize_save_after' => did_action('customize_save_after')); $uuid = wp_generate_uuid4(); $wp_customize = $manager = new WP_Customize_Manager(array('changeset_uuid' => $uuid)); $wp_customize = $manager; $manager->register_controls(); $manager->set_post_value('blogname', 'Changeset Title'); $manager->set_post_value('blogdescription', 'Changeset Tagline'); $pre_saved_data = array('blogname' => array('value' => 'Overridden Changeset Title'), 'blogdescription' => array('custom' => 'something')); $date = gmdate('Y') + 1 . '-12-01 00:00:00'; $r = $manager->save_changeset_post(array('status' => 'auto-draft', 'title' => 'Auto Draft', 'date_gmt' => $date, 'data' => $pre_saved_data)); $this->assertInternalType('array', $r); $this->assertEquals($did_action['customize_save_validation_before'] + 1, did_action('customize_save_validation_before')); $post_id = $manager->find_changeset_post_id($uuid); $this->assertNotNull($post_id); $saved_data = json_decode(get_post($post_id)->post_content, true); $this->assertEquals($manager->unsanitized_post_values(), wp_list_pluck($saved_data, 'value')); $this->assertEquals($pre_saved_data['blogname']['value'], $saved_data['blogname']['value']); $this->assertEquals($pre_saved_data['blogdescription']['custom'], $saved_data['blogdescription']['custom']); foreach ($saved_data as $setting_id => $setting_params) { $this->assertArrayHasKey('type', $setting_params); $this->assertEquals('option', $setting_params['type']); $this->assertArrayHasKey('user_id', $setting_params); $this->assertEquals(self::$admin_user_id, $setting_params['user_id']); } $this->assertEquals('Auto Draft', get_post($post_id)->post_title); $this->assertEquals('auto-draft', get_post($post_id)->post_status); $this->assertEquals($date, get_post($post_id)->post_date_gmt); $this->assertNotEquals('Changeset Title', get_option('blogname')); $this->assertArrayHasKey('setting_validities', $r); // Test saving with invalid settings, ensuring transaction blocked. $previous_saved_data = $saved_data; $manager->add_setting('foo_unauthorized', array('capability' => 'do_not_allow')); $manager->add_setting('baz_illegal', array('validate_callback' => array($this, 'return_illegal_error'))); $r = $manager->save_changeset_post(array('status' => 'auto-draft', 'data' => array('blogname' => array('value' => 'OK'), 'foo_unauthorized' => array('value' => 'No'), 'bar_unknown' => array('value' => 'No'), 'baz_illegal' => array('value' => 'No')))); $this->assertInstanceOf('WP_Error', $r); $this->assertEquals('transaction_fail', $r->get_error_code()); $this->assertInternalType('array', $r->get_error_data()); $this->assertArrayHasKey('setting_validities', $r->get_error_data()); $error_data = $r->get_error_data(); $this->assertArrayHasKey('blogname', $error_data['setting_validities']); $this->assertTrue($error_data['setting_validities']['blogname']); $this->assertArrayHasKey('foo_unauthorized', $error_data['setting_validities']); $this->assertInstanceOf('WP_Error', $error_data['setting_validities']['foo_unauthorized']); $this->assertEquals('unauthorized', $error_data['setting_validities']['foo_unauthorized']->get_error_code()); $this->assertArrayHasKey('bar_unknown', $error_data['setting_validities']); $this->assertInstanceOf('WP_Error', $error_data['setting_validities']['bar_unknown']); $this->assertEquals('unrecognized', $error_data['setting_validities']['bar_unknown']->get_error_code()); $this->assertArrayHasKey('baz_illegal', $error_data['setting_validities']); $this->assertInstanceOf('WP_Error', $error_data['setting_validities']['baz_illegal']); $this->assertEquals('illegal', $error_data['setting_validities']['baz_illegal']->get_error_code()); // Since transactional, ensure no changes have been made. $this->assertEquals($previous_saved_data, json_decode(get_post($post_id)->post_content, true)); // Attempt a non-transactional/incremental update. $wp_customize = $manager = new WP_Customize_Manager(array('changeset_uuid' => $uuid)); $wp_customize = $manager; $manager->register_controls(); // That is, register settings. $r = $manager->save_changeset_post(array('status' => null, 'data' => array('blogname' => array('value' => 'Non-Transactional \\o/ <script>unsanitized</script>'), 'bar_unknown' => array('value' => 'No')))); $this->assertInternalType('array', $r); $this->assertArrayHasKey('setting_validities', $r); $this->assertTrue($r['setting_validities']['blogname']); $this->assertInstanceOf('WP_Error', $r['setting_validities']['bar_unknown']); $saved_data = json_decode(get_post($post_id)->post_content, true); $this->assertNotEquals($previous_saved_data, $saved_data); $this->assertEquals('Non-Transactional \\o/ <script>unsanitized</script>', $saved_data['blogname']['value']); // Ensure the filter applies. $customize_changeset_save_data_call_count = $this->customize_changeset_save_data_call_count; add_filter('customize_changeset_save_data', array($this, 'filter_customize_changeset_save_data'), 10, 2); $manager->save_changeset_post(array('status' => null, 'data' => array('blogname' => array('value' => 'Filtered')))); $this->assertEquals($customize_changeset_save_data_call_count + 1, $this->customize_changeset_save_data_call_count); // Publish the changeset: actions will be doubled since also trashed. $expected_actions = array('wp_trash_post' => 1, 'clean_post_cache' => 2, 'transition_post_status' => 2, 'publish_to_trash' => 1, 'trash_customize_changeset' => 1, 'edit_post' => 2, 'save_post_customize_changeset' => 2, 'save_post' => 2, 'wp_insert_post' => 2, 'trashed_post' => 1); $action_counts = array(); foreach (array_keys($expected_actions) as $action_name) { $action_counts[$action_name] = did_action($action_name); } $wp_customize = $manager = new WP_Customize_Manager(array('changeset_uuid' => $uuid)); do_action('customize_register', $wp_customize); $manager->add_setting('scratchpad', array('type' => 'option', 'capability' => 'exist')); $manager->get_setting('blogname')->capability = 'exist'; $original_capabilities = wp_list_pluck($manager->settings(), 'capability'); wp_set_current_user(self::$subscriber_user_id); $r = $manager->save_changeset_post(array('status' => 'publish', 'data' => array('blogname' => array('value' => 'Do it live \\o/'), 'scratchpad' => array('value' => '<script>console.info( "HELLO" )</script>')))); $this->assertInternalType('array', $r); $this->assertEquals('Do it live \\o/', get_option('blogname')); $this->assertEquals('trash', get_post_status($post_id)); // Auto-trashed. $this->assertEquals($original_capabilities, wp_list_pluck($manager->settings(), 'capability')); $this->assertContains('<script>', get_post($post_id)->post_content); $this->assertEquals($manager->changeset_uuid(), get_post($post_id)->post_name, 'Expected that the "__trashed" suffix to not be added.'); wp_set_current_user(self::$admin_user_id); $this->assertEquals('publish', get_post_meta($post_id, '_wp_trash_meta_status', true)); $this->assertTrue(is_numeric(get_post_meta($post_id, '_wp_trash_meta_time', true))); foreach (array_keys($expected_actions) as $action_name) { $this->assertEquals($expected_actions[$action_name] + $action_counts[$action_name], did_action($action_name), "Action: {$action_name}"); } // Test revisions. add_post_type_support('customize_changeset', 'revisions'); $uuid = wp_generate_uuid4(); $wp_customize = $manager = new WP_Customize_Manager(array('changeset_uuid' => $uuid)); do_action('customize_register', $manager); $manager->set_post_value('blogname', 'Hello Surface'); $manager->save_changeset_post(array('status' => 'auto-draft')); $manager->set_post_value('blogname', 'Hello World'); $manager->save_changeset_post(array('status' => 'draft')); $this->assertTrue(wp_revisions_enabled(get_post($manager->changeset_post_id()))); $manager->set_post_value('blogname', 'Hello Solar System'); $manager->save_changeset_post(array('status' => 'draft')); $manager->set_post_value('blogname', 'Hello Galaxy'); $manager->save_changeset_post(array('status' => 'draft')); $this->assertCount(3, wp_get_post_revisions($manager->changeset_post_id())); }
/** * Register section and controls for REST resources. * * Note that this needs to happen at a priority greater than 11 for * customize_register so that dynamic settings will have been registered via * {@see \WP_Customize_Manager::register_dynamic_settings}. * * @param \WP_Customize_Manager $wp_customize Manager. */ public function customize_register(\WP_Customize_Manager $wp_customize) { $wp_customize->register_control_type(__NAMESPACE__ . '\\WP_Customize_REST_Resource_Control'); $section_id = 'rest_resources'; $section = new WP_Customize_REST_Resources_Section($wp_customize, $section_id, array('title' => __('REST Resources', 'customize-rest-resources'))); $wp_customize->add_section($section); // @todo Create a panel with multiple sections correspondng to each endpoint. // @todo Mirror this in JS. $i = 0; foreach ($wp_customize->settings() as $setting) { $needs_rest_control = $setting instanceof WP_Customize_REST_Resource_Setting && !$wp_customize->get_control($setting->id); if ($needs_rest_control) { $control = new WP_Customize_REST_Resource_Control($wp_customize, $setting->id, array('section' => $section_id, 'settings' => $setting->id, 'priority' => $i)); $wp_customize->add_control($control); $i += 1; } } }
/** * Add Custom CSS section and controls. * * @param WP_Customize_Manager $wp_customize WP_Customize_Manager instance. */ public static function customize_register($wp_customize) { /** * SETTINGS. */ $wp_customize->add_setting('jetpack_custom_css[preprocessor]', array('default' => '', 'transport' => 'postMessage', 'sanitize_callback' => array(__CLASS__, 'sanitize_preprocessor'))); $wp_customize->add_setting('jetpack_custom_css[replace]', array('default' => false, 'transport' => 'refresh')); $wp_customize->add_setting('jetpack_custom_css[content_width]', array('default' => '', 'transport' => 'refresh', 'sanitize_callback' => array(__CLASS__, 'intval_base10'))); // Add custom sanitization to the core css customizer setting. foreach ($wp_customize->settings() as $setting) { if ($setting instanceof WP_Customize_Custom_CSS_Setting) { add_filter("customize_sanitize_{$setting->id}", array(__CLASS__, 'sanitize_css_callback'), 10, 2); } } /** * CONTROLS. */ // Overwrite the Core Control. $core_custom_css = $wp_customize->get_control('custom_css'); if ($core_custom_css) { $wp_customize->remove_control('custom_css'); $core_custom_css->type = 'jetpackCss'; $wp_customize->add_control($core_custom_css); } $wp_customize->selective_refresh->add_partial('custom_css', array('type' => 'custom_css', 'selector' => '#wp-custom-css', 'container_inclusive' => false, 'fallback_refresh' => false, 'settings' => array('custom_css[' . $wp_customize->get_stylesheet() . ']', 'jetpack_custom_css[preprocessor]'), 'render_callback' => array(__CLASS__, 'echo_custom_css_partial'))); $wp_customize->add_control('wpcom_custom_css_content_width_control', array('type' => 'text', 'label' => __('Media Width', 'jetpack'), 'section' => 'custom_css', 'settings' => 'jetpack_custom_css[content_width]')); $wp_customize->add_control('jetpack_css_mode_control', array('type' => 'checkbox', 'label' => __('Don\'t use the theme\'s original CSS.', 'jetpack'), 'section' => 'custom_css', 'settings' => 'jetpack_custom_css[replace]')); /** * An action to grab on to if another Jetpack Module would like to add its own controls. * * @module custom-css * * @since 4.4.2 * * @param $wp_customize The WP_Customize object. */ do_action('jetpack_custom_css_customizer_controls', $wp_customize); /** This filter is documented in modules/custom-css/custom-css.php */ $preprocessors = apply_filters('jetpack_custom_css_preprocessors', array()); if (!empty($preprocessors)) { $preprocessor_choices = array('' => __('None', 'jetpack')); foreach ($preprocessors as $preprocessor_key => $processor) { $preprocessor_choices[$preprocessor_key] = $processor['name']; } $wp_customize->add_control('jetpack_css_preprocessors_control', array('type' => 'select', 'choices' => $preprocessor_choices, 'label' => __('Preprocessor', 'jetpack'), 'section' => 'custom_css', 'settings' => 'jetpack_custom_css[preprocessor]')); } }
/** * Get only the CSS settings of type `Setting\DynamicCSS`. * * @see is_dynamic_css_setting * @return array */ private function get_dynamic_css_settings() { return array_filter($this->wp_customize->settings(), array($this, 'is_dynamic_css_setting')); }