WP_REST_Widgets_Controller::save_widget( WP_REST_Request $request, string $sidebar_id )

Saves the widget in the request object.

Parameters

$request

(WP_REST_Request) (Required) Full details about the request.

$sidebar_id

(string) (Required) ID of the sidebar the widget belongs to.

Return

(string|WP_Error) The saved widget ID.

Source

File: wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php

protected function save_widget( $request, $sidebar_id ) {
		global $wp_widget_factory, $wp_registered_widget_updates;

		require_once ABSPATH . 'wp-admin/includes/widgets.php'; // For next_widget_id_number().

		if ( isset( $request['id'] ) ) {
			// Saving an existing widget.
			$id            = $request['id'];
			$parsed_id     = wp_parse_widget_id( $id );
			$id_base       = $parsed_id['id_base'];
			$number        = isset( $parsed_id['number'] ) ? $parsed_id['number'] : null;
			$widget_object = $wp_widget_factory->get_widget_object( $id_base );
			$creating      = false;
		} elseif ( $request['id_base'] ) {
			// Saving a new widget.
			$id_base       = $request['id_base'];
			$widget_object = $wp_widget_factory->get_widget_object( $id_base );
			$number        = $widget_object ? next_widget_id_number( $id_base ) : null;
			$id            = $widget_object ? $id_base . '-' . $number : $id_base;
			$creating      = true;
		} else {
			return new WP_Error(
				'rest_invalid_widget',
				__( 'Widget type (id_base) is required.' ),
				array( 'status' => 400 )
			);
		}

		if ( ! isset( $wp_registered_widget_updates[ $id_base ] ) ) {
			return new WP_Error(
				'rest_invalid_widget',
				__( 'The provided widget type (id_base) cannot be updated.' ),
				array( 'status' => 400 )
			);
		}

		if ( isset( $request['instance'] ) ) {
			if ( ! $widget_object ) {
				return new WP_Error(
					'rest_invalid_widget',
					__( 'Cannot set instance on a widget that does not extend WP_Widget.' ),
					array( 'status' => 400 )
				);
			}

			if ( isset( $request['instance']['raw'] ) ) {
				if ( empty( $widget_object->widget_options['show_instance_in_rest'] ) ) {
					return new WP_Error(
						'rest_invalid_widget',
						__( 'Widget type does not support raw instances.' ),
						array( 'status' => 400 )
					);
				}
				$instance = $request['instance']['raw'];
			} elseif ( isset( $request['instance']['encoded'], $request['instance']['hash'] ) ) {
				$serialized_instance = base64_decode( $request['instance']['encoded'] );
				if ( ! hash_equals( wp_hash( $serialized_instance ), $request['instance']['hash'] ) ) {
					return new WP_Error(
						'rest_invalid_widget',
						__( 'The provided instance is malformed.' ),
						array( 'status' => 400 )
					);
				}
				$instance = unserialize( $serialized_instance );
			} else {
				return new WP_Error(
					'rest_invalid_widget',
					__( 'The provided instance is invalid. Must contain raw OR encoded and hash.' ),
					array( 'status' => 400 )
				);
			}

			$form_data = array(
				"widget-$id_base" => array(
					$number => $instance,
				),
				'sidebar'         => $sidebar_id,
			);
		} elseif ( isset( $request['form_data'] ) ) {
			$form_data = $request['form_data'];
		} else {
			$form_data = array();
		}

		$original_post    = $_POST;
		$original_request = $_REQUEST;

		foreach ( $form_data as $key => $value ) {
			$slashed_value    = wp_slash( $value );
			$_POST[ $key ]    = $slashed_value;
			$_REQUEST[ $key ] = $slashed_value;
		}

		$callback = $wp_registered_widget_updates[ $id_base ]['callback'];
		$params   = $wp_registered_widget_updates[ $id_base ]['params'];

		if ( is_callable( $callback ) ) {
			ob_start();
			call_user_func_array( $callback, $params );
			ob_end_clean();
		}

		$_POST    = $original_post;
		$_REQUEST = $original_request;

		if ( $widget_object ) {
			// Register any multi-widget that the update callback just created.
			$widget_object->_set( $number );
			$widget_object->_register_one( $number );

			/*
			 * WP_Widget sets `updated = true` after an update to prevent more than one widget
			 * from being saved per request. This isn't what we want in the REST API, though,
			 * as we support batch requests.
			 */
			$widget_object->updated = false;
		}

		/**
		 * Fires after a widget is created or updated via the REST API.
		 *
		 * @since 5.8.0
		 *
		 * @param string          $id         ID of the widget being saved.
		 * @param string          $sidebar_id ID of the sidebar containing the widget being saved.
		 * @param WP_REST_Request $request    Request object.
		 * @param bool            $creating   True when creating a widget, false when updating.
		 */
		do_action( 'rest_after_save_widget', $id, $sidebar_id, $request, $creating );

		return $id;
	}

Changelog

Version Description
5.8.0 Introduced.

© 2003–2021 WordPress Foundation
Licensed under the GNU GPLv2+ License.
https://developer.wordpress.org/reference/classes/wp_rest_widgets_controller/save_widget