?
Current Path : /home1/savoy/public_html/wp-content/themes/Divi/includes/builder/feature/global-presets/ |
Linux gator3171.hostgator.com 4.19.286-203.ELK.el7.x86_64 #1 SMP Wed Jun 14 04:33:55 CDT 2023 x86_64 |
Current File : /home1/savoy/public_html/wp-content/themes/Divi/includes/builder/feature/global-presets/History.php |
<?php class ET_Builder_Global_Presets_History { const CUSTOM_DEFAULTS_HISTORY_OPTION = 'builder_custom_defaults_history'; const GLOBAL_PRESETS_HISTORY_OPTION_LEGACY = 'builder_global_presets_history'; const GLOBAL_PRESETS_HISTORY_OPTION = 'builder_global_presets_history_ng'; const GLOBAL_PRESETS_HISTORY_META = 'builder_presets_history_meta'; const GLOBAL_PRESETS_HISTORY_ITEM = 'builder_presets_history_item'; const HISTORY_STORAGE_MIGRATED_FLAG = 'builder_global_presets_history_migrated'; const GLOBAL_PRESETS_HISTORY_LENGTH = 100; private static $instance; private function __construct() { $this->_migrate_history_storage(); $this->_split_history_storage(); $this->_register_ajax_callbacks(); $this->_register_hooks(); } /** * Returns instance of the singleton class * * @since 4.5.0 * * @return ET_Builder_Global_Presets_History */ public static function instance() { if ( ! isset( self::$instance ) ) { self::$instance = new self(); } return self::$instance; } private function _register_ajax_callbacks() { add_action( 'wp_ajax_et_builder_save_global_presets_history', array( $this, 'ajax_save_global_presets_history', ) ); add_action( 'wp_ajax_et_builder_retrieve_global_presets_history', array( $this, 'ajax_retrieve_global_presets_history', ) ); } private function _register_hooks() { add_action( 'et_after_version_rollback', array( $this, 'after_version_rollback' ), 10, 3 ); // If migration is needed, ensure that all modules get fully loaded. // phpcs:disable PEAR.Functions.FunctionCallSignature -- Anonymous functions. add_action( 'et_builder_framework_loaded', function() { if ( ! ET_Builder_Global_Presets_Settings::are_custom_defaults_migrated() ) { add_filter( 'et_builder_should_load_all_module_data', '__return_true' ); } }); // phpcs:enable add_action( 'et_builder_ready', array( $this, 'migrate_custom_defaults_history' ), 99 ); } /** * Handles AJAX requests to save history of Global Presets settings changes * * @since 4.5.0 * * @return void */ public function ajax_save_global_presets_history() { // Allow saving Global Presets for admins and support elevated users only if ( ! et_core_security_check_passed( 'switch_themes', 'et_builder_save_global_presets_history' ) ) { wp_send_json_error( array( 'code' => 'et_forbidden', 'message' => esc_html__( 'You do not have sufficient permissions to edit Divi Presets.', 'et_builder' ), ) ); } $history = self::_get_global_presets_history(); $history_update = empty( $_POST['history'] ) ? (object) array() : json_decode( stripslashes( $_POST['history'] ) ); // phpcs:ignore ET.Sniffs.ValidatedSanitizedInput.InputNotSanitized -- self::sanitize_and_validate function does sanitization. if ( empty( $history_update->current_state ) ) { et_core_die( esc_html__( 'Global History data is empty.', 'et_builder' ) ); } $history->index = $history_update->index; if ( $history_update->is_new_record ) { $history->history[ $history->index ] = $history_update->current_state; if ( count( $history->history ) > self::GLOBAL_PRESETS_HISTORY_LENGTH ) { self::_slide_history_records(); $history->history = array_slice( $history->history, -self::GLOBAL_PRESETS_HISTORY_LENGTH ); $history->index = min( $history->index, self::GLOBAL_PRESETS_HISTORY_LENGTH - 1 ); } } if ( self::sanitize_and_validate( $history ) ) { $current_settings = $history->history[ $history->index ]; // Update option for product setting (last attr in args list). et_update_option( ET_Builder_Global_Presets_Settings::GLOBAL_PRESETS_OPTION, $current_settings->settings, false, '', '', true ); $history_meta = array( 'index' => $history->index, ); et_update_option( self::GLOBAL_PRESETS_HISTORY_META, $history_meta, false, '', '', true ); et_update_option( self::GLOBAL_PRESETS_HISTORY_ITEM . '_' . $history->index, $history->history[ $history->index ], false, '', '', true ); ET_Core_PageResource::remove_static_resources( 'all', 'all' ); if ( et_get_option( ET_Builder_Global_Presets_Settings::CUSTOM_DEFAULTS_UNMIGRATED_OPTION, false ) ) { et_delete_option( ET_Builder_Global_Presets_Settings::CUSTOM_DEFAULTS_UNMIGRATED_OPTION ); et_fb_delete_builder_assets(); } ET_Builder_Ajax_Cache::instance()->unset_( 'ET_Builder_Global_Presets_History' ); wp_send_json_success(); } else { et_core_die( esc_html__( 'Global History data is corrupt.', 'et_builder' ) ); } } /** * Handles AJAX requests to retrieve history of Global Presets settings changes * * @since 4.5.0 * * @return void */ public function ajax_retrieve_global_presets_history() { if ( ! et_core_security_check_passed( 'edit_posts', 'et_builder_retrieve_global_presets_history' ) ) { wp_send_json_error(); } $history = $this->_get_global_presets_history(); ET_Builder_Ajax_Cache::instance()->set( 'ET_Builder_Global_Presets_History', $history ); wp_send_json_success( $history ); } /** * Adds a new Global Presets settings history record * * @since 4.5.0 * * @param {Object} $defaults */ public function add_global_history_record( $defaults ) { if ( empty( $defaults ) ) { return; } $new_record = (object) array( 'settings' => $defaults, 'time' => time() * 1000, 'label' => esc_html__( 'Imported From Layout', 'et_builder' ), ); $history_index = (int) self::get_global_history_index(); $new_index = (int) $history_index + 1; if ( $new_index >= self::GLOBAL_PRESETS_HISTORY_LENGTH ) { self::_slide_history_records(); $new_index = min( $new_index, self::GLOBAL_PRESETS_HISTORY_LENGTH - 1 ); } $history_meta = array( 'index' => $new_index, ); et_update_option( self::GLOBAL_PRESETS_HISTORY_META, $history_meta, false, '', '', true ); et_update_option( self::GLOBAL_PRESETS_HISTORY_ITEM . '_' . $new_index, $new_record, false, '', '', true ); ET_Core_PageResource::remove_static_resources( 'all', 'all' ); } /** * Get the active Global Presets settings history index * * @since 4.10.0 * * @return int History index. */ public function get_global_history_index() { $history_meta = et_get_option( self::GLOBAL_PRESETS_HISTORY_META, false, '', false, false, '', '', true ); return isset( $history_meta['index'] ) ? $history_meta['index'] : -1; } /** * Performs validation and sanitizing history object. * Returns false if data is invalid or corrupt. * * @since 4.5.0 * * @param $data * * @return bool */ public static function sanitize_and_validate( &$data ) { if ( ! is_object( $data ) ) { return false; } $properties = array( 'history', 'index', ); foreach ( $properties as $property ) { if ( ! property_exists( $data, $property ) ) { return false; } } if ( ! is_array( $data->history ) ) { return false; } foreach ( $data->history as &$record ) { if ( ! is_object( $record ) ) { return false; } $properties = array( 'settings', 'time', 'label', ); if ( count( (array) $record ) !== count( $properties ) ) { return false; } foreach ( $properties as $property ) { if ( ! property_exists( $record, $property ) ) { return false; } } foreach ( $record->settings as &$module ) { if ( ! is_object( $module ) ) { return false; } } if ( ! is_numeric( $record->time ) ) { return false; } $record->label = sanitize_text_field( $record->label ); } $data->index = sanitize_text_field( $data->index ); return true; } /** * Handles History Storage Rollback. * * @since 4.19.3 * * @param string $product_name - The short name of the product rolling back. * @param string $rollback_from_version - Rollback from version. * @param string $rollback_to_version - Rollback to version. */ public function rollback_history_storage( $product_name, $rollback_from_version, $rollback_to_version ) { if ( ! isset( ET_Builder_Global_Presets_Settings::$allowed_products['storage_migration'][ $product_name ] ) ) { return; } if ( 0 > version_compare( $rollback_to_version, ET_Builder_Global_Presets_Settings::$allowed_products['storage_migration'][ $product_name ] ) ) { // Get option from product setting (last attr in args list). $global_history_ng = et_get_option( self::GLOBAL_PRESETS_HISTORY_OPTION, array(), '', true, false, '', '', true ); // Nothing to rollback, just reset the flag. if ( empty( $global_history_ng ) ) { et_update_option( self::HISTORY_STORAGE_MIGRATED_FLAG, false ); return; } // Remove data from the new storage and reset flag. et_update_option( self::GLOBAL_PRESETS_HISTORY_OPTION, array(), false, '', '', true ); et_update_option( self::HISTORY_STORAGE_MIGRATED_FLAG, false ); // Save history to legacy setting. et_update_option( self::GLOBAL_PRESETS_HISTORY_OPTION_LEGACY, $global_history_ng ); } } /** * Handles theme version rollback. * * @since 4.5.0 * * @param string $product_name - The short name of the product rolling back. * @param string $rollback_from_version * @param string $rollback_to_version */ public function after_version_rollback( $product_name, $rollback_from_version, $rollback_to_version ) { // Rollback starage migration. self::rollback_history_storage( $product_name, $rollback_from_version, $rollback_to_version ); if ( ! isset( ET_Builder_Global_Presets_Settings::$allowed_products['customizer_settings'][ $product_name ] ) ) { return; } if ( 0 > version_compare( $rollback_to_version, ET_Builder_Global_Presets_Settings::$allowed_products['customizer_settings'][ $product_name ] ) ) { et_delete_option( self::GLOBAL_PRESETS_HISTORY_OPTION_LEGACY ); } } /** * Slides history records to the left. * I.e. remove the old record and recalculate indexes to fit into GLOBAL_PRESETS_HISTORY_LENGTH. * * @since 4.26.1 * * @return void */ private function _slide_history_records() { for ( $i = 1; $i <= self::GLOBAL_PRESETS_HISTORY_LENGTH; $i++ ) { $history_record = et_get_option( self::GLOBAL_PRESETS_HISTORY_ITEM . '_' . $i, false, '', false, false, '', '', true ); $new_index = $i - 1; // Slide history records to the left. if ( ! empty( $history_record ) ) { et_update_option( self::GLOBAL_PRESETS_HISTORY_ITEM . '_' . $new_index, $history_record, false, '', '', true ); } // Remove extra record. if ( self::GLOBAL_PRESETS_HISTORY_LENGTH === $i ) { et_delete_option( self::GLOBAL_PRESETS_HISTORY_ITEM . '_' . $i ); } } } /** * Returns the Global Presets history object from DB * * @since 4.5.0 * * @return object */ private function _get_global_presets_history() { $history_meta = et_get_option( self::GLOBAL_PRESETS_HISTORY_META, false, '', false, false, '', '', true ); $history_records = array(); for ( $i = 0; $i < self::GLOBAL_PRESETS_HISTORY_LENGTH; $i++ ) { $history_record = et_get_option( self::GLOBAL_PRESETS_HISTORY_ITEM . '_' . $i, false, '', false, false, '', '', true ); if ( ! $history_record ) { break; } array_push( $history_records, $history_record ); } $history = (object) array( 'history' => $history_records, 'index' => isset( $history_meta['index'] ) ? $history_meta['index'] : -1, ); // Ensure history is an object. $history = is_object( $history ) ? $history : (object) $history; $this->_apply_attribute_migrations( $history ); return $history; } /** * Split history storage into separate records in DB. * * @since 4.26.1 * * @return void */ protected function _split_history_storage() { if ( self::_is_history_split() ) { return; } $history_meta = array( 'index' => -1, 'size' => 0, ); // Get option from product setting (last attr in args list). $global_history_ng = et_get_option( self::GLOBAL_PRESETS_HISTORY_OPTION, array(), '', true, false, '', '', true ); if ( ! $global_history_ng ) { et_update_option( self::GLOBAL_PRESETS_HISTORY_META, $history_meta, false, '', '', true ); return; } $history_index = (int) $global_history_ng->index; $history_size = ! empty( $global_history_ng->history ) ? count( $global_history_ng->history ) : 0; $history_meta['index'] = $history_index; $history_meta['size'] = $history_size; et_update_option( self::GLOBAL_PRESETS_HISTORY_META, $history_meta, false, '', '', true ); if ( ! empty( $global_history_ng->history ) ) { foreach ( $global_history_ng->history as $history_index => $presets_settings ) { et_update_option( self::GLOBAL_PRESETS_HISTORY_ITEM . '_' . $history_index, $presets_settings, false, '', '', true ); } } } /** * Migrates global presets history into a separate setting. * * @since 4.19.3 * * @return void */ protected function _migrate_history_storage() { if ( self::_is_history_storage_migrated() ) { return; } $global_history_legacy = et_get_option( self::GLOBAL_PRESETS_HISTORY_OPTION_LEGACY, array(), '', true ); // Get option from product setting (last attr in args list). $global_history_ng = et_get_option( self::GLOBAL_PRESETS_HISTORY_OPTION, array(), '', true, false, '', '', true ); // Nothing to migrate or history already exist in new storage. if ( empty( $global_history_legacy ) || ! empty( $global_history_ng ) ) { et_update_option( self::HISTORY_STORAGE_MIGRATED_FLAG, true ); return; } $global_history_legacy_fixed = self::_fix_presets_history_before_migration( $global_history_legacy ); // Update option for product setting (last attr in args list). et_update_option( self::GLOBAL_PRESETS_HISTORY_OPTION, $global_history_legacy_fixed, false, '', '', true ); $global_history_ng_migrated = et_get_option( self::GLOBAL_PRESETS_HISTORY_OPTION, array(), '', true, false, '', '', true ); // Remove old option if presets migrated. if ( ! empty( $global_history_ng_migrated ) ) { et_update_option( self::HISTORY_STORAGE_MIGRATED_FLAG, true ); // Remove legacy history from settings. et_delete_option( self::GLOBAL_PRESETS_HISTORY_OPTION_LEGACY ); } } /** * Fix global colors in Global Presets History. * Clean up global_colors_info array which may contain duplicates. * * @since 4.19.3 * * @param object|array $history The object representing Global Presets History. * * @return object */ protected function _fix_presets_history_before_migration( $history ) { $result = $history; if ( isset( $history->history ) ) { foreach ( $history->history as $history_index => $presets_settings ) { foreach ( $presets_settings->settings as $module => $preset_structure ) { if ( isset( $preset_structure->presets ) ) { foreach ( $preset_structure->presets as $preset_id => $preset ) { if ( isset( $preset->settings ) ) { // Look for settings in this module that use global colors. if ( isset( $preset->settings->global_colors_info ) ) { $module_global_colors_info = json_decode( $preset->settings->global_colors_info, true ); } else { // Nothing more to be done here if this module's `global_colors_info` setting is empty, // so advance the `$preset_structure->presets as $preset_id => $preset` loop. continue; } $fixed_global_colors_info = array(); foreach ( $module_global_colors_info as $gcid => $settings_that_use_this_gcid_raw ) { if ( empty( $settings_that_use_this_gcid_raw ) ) { continue; } // Fix possible issue with duplicated gc in global_colors_info field. $settings_that_use_this_gcid = array_values( array_unique( $settings_that_use_this_gcid_raw ) ); $fixed_global_colors_info[ $gcid ] = $settings_that_use_this_gcid; } // Insert fixed global_colors_info into preset settings. if ( ! empty( $fixed_global_colors_info ) ) { $result->history[ $history_index ]->settings->$module->presets->$preset_id->settings->global_colors_info = wp_json_encode( $fixed_global_colors_info ); } } } } } } } return $result; } /** * Checks whether history storage migrated or not. * * @since 4.19.3 * * @return bool */ protected function _is_history_storage_migrated() { return et_get_option( self::HISTORY_STORAGE_MIGRATED_FLAG, false ); } /** * Check whether history was migrated into separate records in DB. * * @since 4.26.1 * * @return boolean */ protected function _is_history_split() { return ! empty( et_get_option( self::GLOBAL_PRESETS_HISTORY_META, false, '', false, false, '', '', true ) ); } /** * Migrates Custom Defaults history format to Global Presets history format * * @since 4.5.0 */ public static function migrate_custom_defaults_history() { if ( et_is_builder_plugin_active() || ET_Builder_Global_Presets_Settings::are_custom_defaults_migrated() ) { return; } $history = et_get_option( self::CUSTOM_DEFAULTS_HISTORY_OPTION, false ); if ( ! $history ) { return; } $all_modules = ET_Builder_Element::get_modules(); $migrated_history = (object) array(); $migrated_history->history = array(); foreach ( $history->history as $record ) { $migrated_record = (object) array(); $migrated_record->settings = (object) array(); foreach ( $record->settings as $module => $settings ) { $migrated_record->settings->$module = ET_Builder_Global_Presets_Settings::generate_module_initial_presets_structure( $module, $all_modules ); foreach ( $settings as $setting => $value ) { $migrated_record->settings->$module->presets->_initial->settings->$setting = $value; } } $migrated_record->time = $record->time; $migrated_record->label = $record->label; $migrated_history->history[] = $migrated_record; } $migrated_history->index = $history->index; et_update_option( self::GLOBAL_PRESETS_HISTORY_OPTION, $migrated_history, false, '', '', true ); } /** * Fire migration via "ET_Builder_Global_Presets_Settings::migrate_settings_as_module_attributes". * * @since ? * * @param object $history History object. * * @return void */ protected function _apply_attribute_migrations( $history ) { if ( empty( $history->history ) ) { return; } foreach ( $history->history as $record ) { if ( empty( $record->settings ) ) { continue; } foreach ( $record->settings as $module => $preset_structure ) { foreach ( $preset_structure->presets as $preset_id => $preset ) { ET_Builder_Global_Presets_Settings::migrate_settings_as_module_attributes( $preset, $module ); } } } } } ET_Builder_Global_Presets_History::instance();