diff --git a/includes/RestApi/Themes/ThemeVariationsController.php b/includes/RestApi/Themes/ThemeVariationsController.php index bd8cf8260..3b18c1423 100644 --- a/includes/RestApi/Themes/ThemeVariationsController.php +++ b/includes/RestApi/Themes/ThemeVariationsController.php @@ -1,9 +1,10 @@ namespace, $this->rest_base . $this->rest_extended_base, array( @@ -54,6 +55,19 @@ public function register_routes() { ), ) ); + + register_rest_route( + $this->namespace, + $this->rest_base . $this->rest_extended_base . '/update', + array( + array( + 'methods' => \WP_REST_Server::EDITABLE, + 'args' => $this->get_update_diy_global_style_variation_args(), + 'callback' => array( $this, 'update_diy_global_style_variation' ), + 'permission_callback' => array( Permissions::class, 'rest_is_authorized_admin' ), + ), + ) + ); } /** @@ -89,6 +103,31 @@ public function set_pattern_args() { ); } + /** + * Gets the arguments for updating DIY global style variations. + * + * @return array An array of argument definitions for the REST API request. + */ + public function get_update_diy_global_style_variation_args() { + return array( + 'id' => array( + 'description' => __( 'The id of a template', 'wp-module-onboarding' ), + 'type' => 'integer', + 'default' => GlobalStylesService::get_active_custom_global_styles_post_id(), + ), + 'styles' => array( + 'description' => __( 'The custom styles', 'wp-module-onboarding' ), + 'default' => array(), + 'required' => false, + ), + 'settings' => array( + 'description' => __( 'The custom settings', 'wp-module-onboarding' ), + 'default' => array(), + 'required' => false, + ), + ); + } + /** * Translate decoded json file. * @@ -140,9 +179,9 @@ public function get_theme_variations( \WP_REST_Request $request ) { $default = $request->get_param( 'variations' ); // If there exists an old Custom Theme then return that - if ( false === $default && false !== \get_option( Options::get_option_name( 'theme_settings' ) ) ) { + if ( false === $default && false !== Themes::get_selected_diy_theme_settings() ) { return array( - \get_option( Options::get_option_name( 'theme_settings' ) ), + Themes::get_selected_diy_theme_settings(), ); } @@ -174,7 +213,7 @@ public function set_theme_variation( \WP_REST_Request $request ) { if ( $theme_data ) { // Save the new Theme style into the db - \update_option( Options::get_option_name( 'theme_settings' ), $theme_data ); + Themes::set_diy_theme_settings( $theme_data ); return new \WP_REST_Response( $theme_data, @@ -188,4 +227,31 @@ public function set_theme_variation( \WP_REST_Request $request ) { 'Settings parameter is found to be missing' ); } + + /** + * Handles the update DIY global style variation request. + * + * @param \WP_REST_Request $request The REST API request object containing the parameters. + * + * @return \WP_REST_Response|\WP_Error Returns a WP_REST_Response on success, or a WP_Error on failure. + */ + public function update_diy_global_style_variation( \WP_REST_Request $request ) { + $request_data = $request->get_params(); + $id = $request_data['id']; + $styles = $request_data['styles']; + $settings = $request_data['settings']; + + $status = GlobalStylesService::update_diy_global_style_variation( $id, $styles, $settings ); + + if ( is_wp_error( $status ) ) { + return $status; + } + + return new \WP_REST_Response( + array( + 'message' => __( 'Global style customization created.', 'wp-module-onboarding' ), + ), + 201 + ); + } } diff --git a/includes/Services/GlobalStylesService.php b/includes/Services/GlobalStylesService.php new file mode 100644 index 000000000..2fd36072b --- /dev/null +++ b/includes/Services/GlobalStylesService.php @@ -0,0 +1,158 @@ + 404 ) + ); + } + + // If styles are empty, use styles from user-selected theme settings. + if ( empty( $styles ) ) { + if ( empty( $user_selected_theme_settings['styles'] ) ) { + return new \WP_Error( + 'nfd_onboarding_error', + __( 'Styles does not exist under the selected theme settings.', 'wp-module-onboarding' ), + array( 'status' => 400 ) + ); + } + + $styles = $user_selected_theme_settings['styles']; + } + + // If settings are empty, use settings from user-selected theme settings. + if ( empty( $settings ) ) { + if ( empty( $user_selected_theme_settings['settings'] ) ) { + return new \WP_Error( + 'nfd_onboarding_error', + __( 'Settings does not exist under the selected theme settings.', 'wp-module-onboarding' ), + array( 'status' => 400 ) + ); + } + + // Remove specific keys from the settings before using them as these are large and unnecessary. + unset( $user_selected_theme_settings['settings']['styles'] ); + unset( $user_selected_theme_settings['settings']['__unstableResolvedAssets'] ); + unset( $user_selected_theme_settings['settings']['__experimentalFeatures'] ); + $settings = $user_selected_theme_settings['settings']; + } + + // Update the global style variation with the prepared styles and settings. + return self::update_global_style_variation( + $id, + $styles, + $settings + ); + } + + /** + * Updates the global style variation given the id. + * + * This private function sends a POST request to update the global style using the provided + * styles and settings. + * + * @param string $id The ID of the global style variation to update. + * @param array $styles The styles to apply. + * @param array $settings The settings to apply. + * @return true|\WP_Error Returns true on success, or a WP_Error on failure. + */ + private static function update_global_style_variation( $id, $styles, $settings ) { + // Create a REST request to update global styles. + $update_active_global_style_request = new \WP_REST_Request( + 'POST', + "/wp/v2/global-styles/$id" + ); + $update_active_global_style_request->set_header( 'Content-Type', 'application/json' ); + // Generate custom theme.json data. + $custom_theme_json = self::create_custom_theme_json( $styles, $settings ); + if ( ! isset( $custom_theme_json['styles'] ) || ! isset( $custom_theme_json['settings'] ) ) { + return new \WP_Error( + 'nfd_onboarding_error', + __( 'There is an error with your styles or settings.', 'wp-module-onboarding' ), + array( 'status' => 400 ) + ); + } + // Set the request body parameters. + $update_active_global_style_request->set_body_params( + array( + 'id' => $id, + 'styles' => $custom_theme_json['styles'], + 'settings' => $custom_theme_json['settings'], + ) + ); + + // Execute the REST request. + $update_active_global_style_response = rest_do_request( $update_active_global_style_request ); + if ( $update_active_global_style_response->is_error() ) { + return $update_active_global_style_response->as_error(); + } + + return true; + } + + /** + * Retrieves the post ID of the active/parent custom global styles. + * + * @return int The post ID of the active custom global styles. + */ + public static function get_active_custom_global_styles_post_id() { + return \WP_Theme_JSON_Resolver::get_user_global_styles_post_id(); + } + + /** + * Creates a custom theme.json array. + * + * This function generates a theme.json structure based on the provided styles and settings. + * + * @param array $styles The styles to include in the theme.json. + * @param array $settings The settings to include in the theme.json. + * @param int $version The version of the theme.json schema. Defaults to the latest schema. + * @return array The raw theme.json data. + */ + public static function create_custom_theme_json( $styles, $settings, $version = \WP_Theme_JSON::LATEST_SCHEMA ) { + $theme_json = new \WP_Theme_JSON( + array( + 'version' => $version, + 'styles' => $styles, + 'settings' => $settings, + ) + ); + + return $theme_json->get_raw_data(); + } +}