Title: WP_Customize_Widgets::call_widget_update
Published: April 25, 2014
Last modified: February 24, 2026

---

# WP_Customize_Widgets::call_widget_update( string $widget_id ): array|󠀁[WP_Error](https://developer.wordpress.org/reference/classes/wp_error/)󠁿

## In this article

 * [Description](https://developer.wordpress.org/reference/classes/wp_customize_widgets/call_widget_update/?output_format=md#description)
 * [Parameters](https://developer.wordpress.org/reference/classes/wp_customize_widgets/call_widget_update/?output_format=md#parameters)
 * [Return](https://developer.wordpress.org/reference/classes/wp_customize_widgets/call_widget_update/?output_format=md#return)
 * [Source](https://developer.wordpress.org/reference/classes/wp_customize_widgets/call_widget_update/?output_format=md#source)
 * [Related](https://developer.wordpress.org/reference/classes/wp_customize_widgets/call_widget_update/?output_format=md#related)
 * [Changelog](https://developer.wordpress.org/reference/classes/wp_customize_widgets/call_widget_update/?output_format=md#changelog)

[ Back to top](https://developer.wordpress.org/reference/classes/wp_customize_widgets/call_widget_update/?output_format=md#wp--skip-link--target)

Finds and invokes the widget update and control callbacks.

## 󠀁[Description](https://developer.wordpress.org/reference/classes/wp_customize_widgets/call_widget_update/?output_format=md#description)󠁿

Requires that `$_POST` be populated with the instance data.

## 󠀁[Parameters](https://developer.wordpress.org/reference/classes/wp_customize_widgets/call_widget_update/?output_format=md#parameters)󠁿

 `$widget_id`stringrequired

Widget ID.

## 󠀁[Return](https://developer.wordpress.org/reference/classes/wp_customize_widgets/call_widget_update/?output_format=md#return)󠁿

 array|[WP_Error](https://developer.wordpress.org/reference/classes/wp_error/) Array
containing the updated widget information.
 A [WP_Error](https://developer.wordpress.org/reference/classes/wp_error/)
object, otherwise.

## 󠀁[Source](https://developer.wordpress.org/reference/classes/wp_customize_widgets/call_widget_update/?output_format=md#source)󠁿

    ```php
    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 Navigation 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, $parsed_id['id_base'] );
    		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 ]              = wp_slash( $value );
    			$_POST[ $key ]                 = $_REQUEST[ $key ];
    			$added_input_vars[]            = $key;
    		} else {
    			foreach ( $instance as $key => $value ) {
    				$_REQUEST[ $key ]   = wp_slash( $value );
    				$_POST[ $key ]      = $_REQUEST[ $key ];
    				$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, $this->sanitize_widget_js_instance( $instance, $parsed_id['id_base'] ) );

    	// 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' );
    }
    ```

[View all references](https://developer.wordpress.org/reference/files/wp-includes/class-wp-customize-widgets.php/)
[View on Trac](https://core.trac.wordpress.org/browser/tags/6.9.4/src/wp-includes/class-wp-customize-widgets.php#L1577)
[View on GitHub](https://github.com/WordPress/wordpress-develop/blob/6.9.4/src/wp-includes/class-wp-customize-widgets.php#L1577-L1689)

## 󠀁[Related](https://developer.wordpress.org/reference/classes/wp_customize_widgets/call_widget_update/?output_format=md#related)󠁿

| Uses | Description | 
| [WP_Customize_Widgets::get_captured_option()](https://developer.wordpress.org/reference/classes/wp_customize_widgets/get_captured_option/)`wp-includes/class-wp-customize-widgets.php` |

Retrieves the option that was captured from being saved.

  | 
| [did_action()](https://developer.wordpress.org/reference/functions/did_action/)`wp-includes/plugin.php` |

Retrieves the number of times an action has been fired during the current request.

  | 
| [WP_Customize_Widgets::start_capturing_option_updates()](https://developer.wordpress.org/reference/classes/wp_customize_widgets/start_capturing_option_updates/)`wp-includes/class-wp-customize-widgets.php` |

Begins keeping track of changes to widget options, caching new values.

  | 
| [WP_Customize_Widgets::stop_capturing_option_updates()](https://developer.wordpress.org/reference/classes/wp_customize_widgets/stop_capturing_option_updates/)`wp-includes/class-wp-customize-widgets.php` |

Undoes any changes to the options since options capture began.

  | 
| [WP_Customize_Widgets::sanitize_widget_instance()](https://developer.wordpress.org/reference/classes/wp_customize_widgets/sanitize_widget_instance/)`wp-includes/class-wp-customize-widgets.php` |

Sanitizes a widget instance.

  | 
| [WP_Customize_Widgets::count_captured_options()](https://developer.wordpress.org/reference/classes/wp_customize_widgets/count_captured_options/)`wp-includes/class-wp-customize-widgets.php` |

Retrieves the number of captured widget option updates.

  | 
| [WP_Customize_Widgets::get_captured_options()](https://developer.wordpress.org/reference/classes/wp_customize_widgets/get_captured_options/)`wp-includes/class-wp-customize-widgets.php` |

Retrieves captured widget option updates.

  | 
| [WP_Customize_Widgets::sanitize_widget_js_instance()](https://developer.wordpress.org/reference/classes/wp_customize_widgets/sanitize_widget_js_instance/)`wp-includes/class-wp-customize-widgets.php` |

Converts a widget instance into JSON-representable format.

  | 
| [WP_Customize_Widgets::get_setting_id()](https://developer.wordpress.org/reference/classes/wp_customize_widgets/get_setting_id/)`wp-includes/class-wp-customize-widgets.php` |

Converts a widget_id into its corresponding Customizer setting ID (option name).

  | 
| [WP_Customize_Widgets::parse_widget_id()](https://developer.wordpress.org/reference/classes/wp_customize_widgets/parse_widget_id/)`wp-includes/class-wp-customize-widgets.php` |

Converts a widget ID into its id_base and number components.

  | 
| [WP_Customize_Widgets::get_post_value()](https://developer.wordpress.org/reference/classes/wp_customize_widgets/get_post_value/)`wp-includes/class-wp-customize-widgets.php` |

Retrieves an unslashed post value or return a default.

  | 
| [wp_slash()](https://developer.wordpress.org/reference/functions/wp_slash/)`wp-includes/formatting.php` |

Adds slashes to a string or recursively adds slashes to strings within an array.

  | 
| [WP_Error::__construct()](https://developer.wordpress.org/reference/classes/wp_error/__construct/)`wp-includes/class-wp-error.php` |

Initializes the error.

  |

[Show 8 more](https://developer.wordpress.org/reference/classes/wp_customize_widgets/call_widget_update/?output_format=md#)
[Show less](https://developer.wordpress.org/reference/classes/wp_customize_widgets/call_widget_update/?output_format=md#)

| Used by | Description | 
| [WP_Customize_Widgets::wp_ajax_update_widget()](https://developer.wordpress.org/reference/classes/wp_customize_widgets/wp_ajax_update_widget/)`wp-includes/class-wp-customize-widgets.php` |

Updates widget settings asynchronously.

  |

## 󠀁[Changelog](https://developer.wordpress.org/reference/classes/wp_customize_widgets/call_widget_update/?output_format=md#changelog)󠁿

| Version | Description | 
| [3.9.0](https://developer.wordpress.org/reference/since/3.9.0/) | Introduced. |

## User Contributed Notes

You must [log in](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Fclasses%2Fwp_customize_widgets%2Fcall_widget_update%2F)
before being able to contribute a note or feedback.