upgrades.php (26455B)
1 <?php 2 namespace Elementor\Core\Upgrade; 3 4 use Elementor\Core\Breakpoints\Manager as Breakpoints_Manager; 5 use Elementor\Core\Experiments\Manager as Experiments_Manager; 6 use Elementor\Core\Settings\Manager as SettingsManager; 7 use Elementor\Core\Settings\Page\Manager as SettingsPageManager; 8 use Elementor\Icons_Manager; 9 use Elementor\Modules\Usage\Module; 10 use Elementor\Plugin; 11 use Elementor\Utils; 12 13 if ( ! defined( 'ABSPATH' ) ) { 14 exit; // Exit if accessed directly. 15 } 16 17 /** 18 * Elementor upgrades. 19 * 20 * Elementor upgrades handler class is responsible for updating different 21 * Elementor versions. 22 * 23 * @since 1.0.0 24 */ 25 class Upgrades { 26 27 public static function _on_each_version( $updater ) { 28 self::recalc_usage_data( $updater ); 29 30 $uploads_manager = Plugin::$instance->uploads_manager; 31 32 $temp_dir = $uploads_manager->get_temp_dir(); 33 34 if ( file_exists( $temp_dir ) ) { 35 $uploads_manager->remove_file_or_dir( $temp_dir ); 36 } 37 } 38 39 /** 40 * Upgrade Elementor 0.3.2 41 * 42 * Change the image widget link URL, setting is to `custom` link. 43 * 44 * @since 2.0.0 45 * @static 46 * @access public 47 */ 48 public static function _v_0_3_2() { 49 global $wpdb; 50 51 $post_ids = $wpdb->get_col( 52 'SELECT `post_id` FROM `' . $wpdb->postmeta . '` 53 WHERE `meta_key` = \'_elementor_version\' 54 AND `meta_value` = \'0.1\';' 55 ); 56 57 if ( empty( $post_ids ) ) { 58 return; 59 } 60 61 foreach ( $post_ids as $post_id ) { 62 $document = Plugin::$instance->documents->get( $post_id ); 63 64 if ( $document ) { 65 $data = $document->get_elements_data(); 66 } 67 68 if ( empty( $data ) ) { 69 continue; 70 } 71 72 $data = Plugin::$instance->db->iterate_data( $data, function( $element ) { 73 if ( empty( $element['widgetType'] ) || 'image' !== $element['widgetType'] ) { 74 return $element; 75 } 76 77 if ( ! empty( $element['settings']['link']['url'] ) && ! isset( $element['settings']['link_to'] ) ) { 78 $element['settings']['link_to'] = 'custom'; 79 } 80 81 return $element; 82 } ); 83 84 $document = Plugin::$instance->documents->get( $post_id ); 85 86 $document->save( [ 87 'elements' => $data, 88 ] ); 89 } 90 } 91 92 /** 93 * Upgrade Elementor 0.9.2 94 * 95 * Change the icon widget, icon-box widget and the social-icons widget, 96 * setting their icon padding size to an empty string. 97 * 98 * Change the image widget, setting the image size to full image size. 99 * 100 * @since 2.0.0 101 * @static 102 * @access public 103 */ 104 public static function _v_0_9_2() { 105 global $wpdb; 106 107 // Fix Icon/Icon Box Widgets padding. 108 $post_ids = $wpdb->get_col( 109 'SELECT `post_id` FROM `' . $wpdb->postmeta . '` 110 WHERE `meta_key` = \'_elementor_version\' 111 AND `meta_value` = \'0.2\';' 112 ); 113 114 if ( empty( $post_ids ) ) { 115 return; 116 } 117 118 foreach ( $post_ids as $post_id ) { 119 $document = Plugin::$instance->documents->get( $post_id ); 120 121 if ( $document ) { 122 $data = $document->get_elements_data(); 123 } 124 125 if ( empty( $data ) ) { 126 continue; 127 } 128 129 $data = Plugin::$instance->db->iterate_data( $data, function( $element ) { 130 if ( empty( $element['widgetType'] ) ) { 131 return $element; 132 } 133 134 if ( in_array( $element['widgetType'], [ 'icon', 'icon-box', 'social-icons' ] ) ) { 135 if ( ! empty( $element['settings']['icon_padding']['size'] ) ) { 136 $element['settings']['icon_padding']['size'] = ''; 137 } 138 } 139 140 if ( 'image' === $element['widgetType'] ) { 141 if ( empty( $element['settings']['image_size'] ) ) { 142 $element['settings']['image_size'] = 'full'; 143 } 144 } 145 146 return $element; 147 } ); 148 149 $document = Plugin::$instance->documents->get( $post_id ); 150 151 $document->save( [ 152 'elements' => $data, 153 ] ); 154 } 155 } 156 157 /** 158 * Upgrade Elementor 0.11.0 159 * 160 * Change the button widget sizes, setting up new button sizes. 161 * 162 * @since 2.0.0 163 * @static 164 * @access public 165 */ 166 public static function _v_0_11_0() { 167 global $wpdb; 168 169 // Fix Button widget to new sizes options. 170 $post_ids = $wpdb->get_col( 171 'SELECT `post_id` FROM `' . $wpdb->postmeta . '` 172 WHERE `meta_key` = \'_elementor_version\' 173 AND `meta_value` = \'0.3\';' 174 ); 175 176 if ( empty( $post_ids ) ) { 177 return; 178 } 179 180 foreach ( $post_ids as $post_id ) { 181 $document = Plugin::$instance->documents->get( $post_id ); 182 183 if ( $document ) { 184 $data = $document->get_elements_data(); 185 } 186 187 if ( empty( $data ) ) { 188 continue; 189 } 190 191 $data = Plugin::$instance->db->iterate_data( $data, function( $element ) { 192 if ( empty( $element['widgetType'] ) ) { 193 return $element; 194 } 195 196 if ( 'button' === $element['widgetType'] ) { 197 $size_to_replace = [ 198 'small' => 'xs', 199 'medium' => 'sm', 200 'large' => 'md', 201 'xl' => 'lg', 202 'xxl' => 'xl', 203 ]; 204 205 if ( ! empty( $element['settings']['size'] ) ) { 206 $old_size = $element['settings']['size']; 207 208 if ( isset( $size_to_replace[ $old_size ] ) ) { 209 $element['settings']['size'] = $size_to_replace[ $old_size ]; 210 } 211 } 212 } 213 214 return $element; 215 } ); 216 217 $document = Plugin::$instance->documents->get( $post_id ); 218 219 $document->save( [ 220 'elements' => $data, 221 ] ); 222 } 223 } 224 225 /** 226 * Upgrade Elementor 2.0.0 227 * 228 * Fix post titles for old autosave drafts that saved with the format 'Auto Save 2018-03-18 17:24'. 229 * 230 * @static 231 * @since 2.0.0 232 * @access public 233 */ 234 public static function _v_2_0_0() { 235 global $wpdb; 236 237 $posts = $wpdb->get_results( 238 'SELECT `ID`, `post_title`, `post_parent` 239 FROM `' . $wpdb->posts . '` p 240 LEFT JOIN `' . $wpdb->postmeta . '` m ON p.ID = m.post_id 241 WHERE `post_status` = \'inherit\' 242 AND `post_title` = CONCAT(\'Auto Save \', DATE_FORMAT(post_date, "%Y-%m-%d %H:%i")) 243 AND m.`meta_key` = \'_elementor_data\';' 244 ); 245 246 if ( empty( $posts ) ) { 247 return; 248 } 249 250 foreach ( $posts as $post ) { 251 wp_update_post( [ 252 'ID' => $post->ID, 253 'post_title' => get_the_title( $post->post_parent ), 254 ] ); 255 } 256 } 257 258 /** 259 * Upgrade Elementor 2.0.1 260 * 261 * Fix post titles for old autosave drafts that saved with the format 'Auto Save...'. 262 * 263 * @since 2.0.2 264 * @static 265 * @access public 266 */ 267 public static function _v_2_0_1() { 268 global $wpdb; 269 270 $posts = $wpdb->get_results( 271 'SELECT `ID`, `post_title`, `post_parent` 272 FROM `' . $wpdb->posts . '` p 273 LEFT JOIN `' . $wpdb->postmeta . '` m ON p.ID = m.post_id 274 WHERE `post_status` = \'inherit\' 275 AND `post_title` REGEXP \'^Auto Save [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}$\' 276 AND m.`meta_key` = \'_elementor_data\';' 277 ); 278 279 if ( empty( $posts ) ) { 280 return; 281 } 282 283 foreach ( $posts as $post ) { 284 $parent = get_post( $post->post_parent ); 285 $title = isset( $parent->post_title ) ? $parent->post_title : ''; 286 287 wp_update_post( [ 288 'ID' => $post->ID, 289 'post_title' => $title, 290 ] ); 291 } 292 } 293 294 /** 295 * Upgrade Elementor 2.0.10 296 * 297 * Fix post titles for old autosave drafts that saved with the format 'Auto Save...'. 298 * Fix also Translated titles. 299 * 300 * @since 2.0.10 301 * @static 302 * @access public 303 */ 304 public static function _v_2_0_10() { 305 global $wpdb; 306 307 $posts = $wpdb->get_results( 308 'SELECT `ID`, `post_title`, `post_parent` 309 FROM `' . $wpdb->posts . '` p 310 LEFT JOIN `' . $wpdb->postmeta . '` m ON p.ID = m.post_id 311 WHERE `post_status` = \'inherit\' 312 AND `post_title` REGEXP \'[[:alnum:]]+ [[:alnum:]]+ [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}$\' 313 AND m.`meta_key` = \'_elementor_data\';' 314 ); 315 316 if ( empty( $posts ) ) { 317 return; 318 } 319 320 foreach ( $posts as $post ) { 321 $parent = get_post( $post->post_parent ); 322 $title = isset( $parent->post_title ) ? $parent->post_title : ''; 323 324 wp_update_post( [ 325 'ID' => $post->ID, 326 'post_title' => $title, 327 ] ); 328 } 329 } 330 331 public static function _v_2_1_0() { 332 global $wpdb; 333 334 // upgrade `video` widget settings (merge providers). 335 $post_ids = $wpdb->get_col( 336 'SELECT `post_id` FROM `' . $wpdb->postmeta . '` WHERE `meta_key` = "_elementor_data" AND `meta_value` LIKE \'%"widgetType":"video"%\';' 337 ); 338 339 if ( empty( $post_ids ) ) { 340 return; 341 } 342 343 foreach ( $post_ids as $post_id ) { 344 $do_update = false; 345 $document = Plugin::$instance->documents->get( $post_id ); 346 347 if ( $document ) { 348 $data = $document->get_elements_data(); 349 } 350 351 if ( empty( $data ) ) { 352 continue; 353 } 354 355 $data = Plugin::$instance->db->iterate_data( $data, function( $element ) use ( &$do_update ) { 356 if ( empty( $element['widgetType'] ) || 'video' !== $element['widgetType'] ) { 357 return $element; 358 } 359 360 $replacements = []; 361 362 if ( empty( $element['settings']['video_type'] ) || 'youtube' === $element['settings']['video_type'] ) { 363 $replacements = [ 364 'yt_autoplay' => 'autoplay', 365 'yt_controls' => 'controls', 366 'yt_mute' => 'mute', 367 'yt_rel' => 'rel', 368 'link' => 'youtube_url', 369 ]; 370 } elseif ( 'vimeo' === $element['settings']['video_type'] ) { 371 $replacements = [ 372 'vimeo_autoplay' => 'autoplay', 373 'vimeo_loop' => 'loop', 374 'vimeo_color' => 'color', 375 'vimeo_link' => 'vimeo_url', 376 ]; 377 } 378 379 // cleanup old unused settings. 380 unset( $element['settings']['yt_rel_videos'] ); 381 382 foreach ( $replacements as $old => $new ) { 383 if ( ! empty( $element['settings'][ $old ] ) ) { 384 $element['settings'][ $new ] = $element['settings'][ $old ]; 385 $do_update = true; 386 } 387 } 388 389 return $element; 390 } ); 391 392 // Only update if needed. 393 if ( ! $do_update ) { 394 continue; 395 } 396 397 // We need the `wp_slash` in order to avoid the unslashing during the `update_post_meta` 398 $json_value = wp_slash( wp_json_encode( $data ) ); 399 400 update_metadata( 'post', $post_id, '_elementor_data', $json_value ); 401 402 // Clear WP cache for next step. 403 wp_cache_flush(); 404 } // End foreach(). 405 } 406 407 /** 408 * @param Updater $updater 409 * 410 * @return bool 411 */ 412 public static function _v_2_3_0_widget_image( $updater ) { 413 global $wpdb; 414 415 // upgrade `video` widget settings (merge providers). 416 $post_ids = $updater->query_col( 417 'SELECT `post_id` FROM `' . $wpdb->postmeta . '` WHERE `meta_key` = "_elementor_data" AND ( 418 `meta_value` LIKE \'%"widgetType":"image"%\' 419 OR `meta_value` LIKE \'%"widgetType":"theme-post-featured-image"%\' 420 OR `meta_value` LIKE \'%"widgetType":"theme-site-logo"%\' 421 OR `meta_value` LIKE \'%"widgetType":"woocommerce-category-image"%\' 422 );' 423 ); 424 425 if ( empty( $post_ids ) ) { 426 return false; 427 } 428 429 $widgets = [ 430 'image', 431 'theme-post-featured-image', 432 'theme-site-logo', 433 'woocommerce-category-image', 434 ]; 435 436 foreach ( $post_ids as $post_id ) { 437 // Clear WP cache for next step. 438 wp_cache_flush(); 439 440 $do_update = false; 441 442 $document = Plugin::$instance->documents->get( $post_id ); 443 444 if ( ! $document ) { 445 continue; 446 } 447 448 $data = $document->get_elements_data(); 449 450 if ( empty( $data ) ) { 451 continue; 452 } 453 454 $data = Plugin::$instance->db->iterate_data( $data, function( $element ) use ( &$do_update, $widgets ) { 455 if ( empty( $element['widgetType'] ) || ! in_array( $element['widgetType'], $widgets ) ) { 456 return $element; 457 } 458 459 if ( ! empty( $element['settings']['caption'] ) ) { 460 if ( ! isset( $element['settings']['caption_source'] ) ) { 461 $element['settings']['caption_source'] = 'custom'; 462 463 $do_update = true; 464 } 465 } 466 467 return $element; 468 } ); 469 470 // Only update if needed. 471 if ( ! $do_update ) { 472 continue; 473 } 474 475 // We need the `wp_slash` in order to avoid the unslashing during the `update_post_meta` 476 $json_value = wp_slash( wp_json_encode( $data ) ); 477 478 update_metadata( 'post', $post_id, '_elementor_data', $json_value ); 479 } // End foreach(). 480 481 return $updater->should_run_again( $post_ids ); 482 } 483 484 /** 485 * @param Updater $updater 486 * 487 * @return bool 488 */ 489 public static function _v_2_3_0_template_type( $updater ) { 490 global $wpdb; 491 492 $post_ids = $updater->query_col( 493 'SELECT p.ID 494 FROM `' . $wpdb->posts . '` AS p 495 LEFT JOIN `' . $wpdb->postmeta . '` AS pm1 ON (p.ID = pm1.post_id) 496 LEFT JOIN `' . $wpdb->postmeta . '` AS pm2 ON (pm1.post_id = pm2.post_id AND pm2.meta_key = "_elementor_template_type") 497 WHERE p.post_status != "inherit" AND pm1.`meta_key` = "_elementor_data" AND pm2.post_id IS NULL;' 498 ); 499 500 if ( empty( $post_ids ) ) { 501 return false; 502 } 503 504 foreach ( $post_ids as $post_id ) { 505 // Clear WP cache for next step. 506 wp_cache_flush(); 507 508 $document = Plugin::$instance->documents->get( $post_id ); 509 510 if ( ! $document ) { 511 continue; 512 } 513 514 $document->save_template_type(); 515 } // End foreach(). 516 517 return $updater->should_run_again( $post_ids ); 518 } 519 520 /** 521 * Set FontAwesome Migration needed flag 522 */ 523 public static function _v_2_6_0_fa4_migration_flag() { 524 add_option( 'elementor_icon_manager_needs_update', 'yes' ); 525 add_option( 'elementor_load_fa4_shim', 'yes' ); 526 } 527 528 /** 529 * migrate Icon control string value to Icons control array value 530 * 531 * @param array $element 532 * @param array $args 533 * 534 * @return mixed 535 */ 536 public static function _migrate_icon_fa4_value( $element, $args ) { 537 $widget_id = $args['widget_id']; 538 539 if ( empty( $element['widgetType'] ) || $widget_id !== $element['widgetType'] ) { 540 return $element; 541 } 542 foreach ( $args['control_ids'] as $old_name => $new_name ) { 543 // exit if new value exists 544 if ( isset( $element['settings'][ $new_name ] ) ) { 545 continue; 546 } 547 548 // exit if no value to migrate 549 if ( ! isset( $element['settings'][ $old_name ] ) ) { 550 continue; 551 } 552 553 $element['settings'][ $new_name ] = Icons_Manager::fa4_to_fa5_value_migration( $element['settings'][ $old_name ] ); 554 $args['do_update'] = true; 555 } 556 return $element; 557 } 558 559 /** 560 * Set FontAwesome 5 value Migration on for button widget 561 * 562 * @param Updater $updater 563 */ 564 public static function _v_2_6_6_fa4_migration_button( $updater ) { 565 $changes = [ 566 [ 567 'callback' => [ 'Elementor\Core\Upgrade\Upgrades', '_migrate_icon_fa4_value' ], 568 'control_ids' => [ 569 'icon' => 'selected_icon', 570 ], 571 ], 572 ]; 573 Upgrade_Utils::_update_widget_settings( 'button', $updater, $changes ); 574 Upgrade_Utils::_update_widget_settings( 'icon-box', $updater, $changes ); 575 } 576 577 /** 578 * Update database to separate page from post. 579 * 580 * @param Updater $updater 581 * 582 * @param string $type 583 * 584 * @return bool 585 */ 586 public static function rename_document_base_to_wp( $updater, $type ) { 587 global $wpdb; 588 589 $post_ids = $updater->query_col( $wpdb->prepare( 590 "SELECT p1.ID FROM {$wpdb->posts} AS p 591 LEFT JOIN {$wpdb->posts} AS p1 ON (p.ID = p1.post_parent || p.ID = p1.ID) 592 WHERE p.post_type = %s;", $type ) ); 593 594 if ( empty( $post_ids ) ) { 595 return false; 596 } 597 598 $sql_post_ids = implode( ',', $post_ids ); 599 600 $wpdb->query( $wpdb->prepare( 601 "UPDATE $wpdb->postmeta SET meta_value = %s 602 WHERE meta_key = '_elementor_template_type' && post_id in ( %s ); 603 ", 'wp-' . $type, $sql_post_ids ) ); 604 605 return $updater->should_run_again( $post_ids ); 606 } 607 608 /** 609 * Update database to separate page from post. 610 * 611 * @param Updater $updater 612 * 613 * @return bool 614 */ 615 // Because the query is slow on large sites, temporary don't upgrade. 616 /* public static function _v_2_7_0_rename_document_types_to_wp( $updater ) { 617 return self::rename_document_base_to_wp( $updater, 'post' ) || self::rename_document_base_to_wp( $updater, 'page' ); 618 }*/ 619 620 // Upgrade code was fixed & moved to _v_2_7_1_remove_old_usage_data. 621 /* public static function _v_2_7_0_remove_old_usage_data() {} */ 622 623 // Upgrade code moved to _v_2_7_1_recalc_usage_data. 624 /* public static function _v_2_7_0_recalc_usage_data( $updater ) {} */ 625 626 /** 627 * Don't use the old data anymore. 628 * Since 2.7.1 the key was changed from `elementor_elements_usage` to `elementor_controls_usage`. 629 */ 630 public static function _v_2_7_1_remove_old_usage_data() { 631 delete_option( 'elementor_elements_usage' ); 632 delete_post_meta_by_key( '_elementor_elements_usage' ); 633 } 634 635 /** 636 * Recalc usage. 637 * 638 * @param Updater $updater 639 * 640 * @return bool 641 */ 642 public static function recalc_usage_data( $updater ) { 643 /** @var Module $module */ 644 $module = Plugin::$instance->modules_manager->get_modules( 'usage' ); 645 646 $post_count = $module->recalc_usage( $updater->get_limit(), $updater->get_current_offset() ); 647 648 return ( $post_count === $updater->get_limit() ); 649 } 650 651 public static function _v_2_7_1_recalc_usage_data( $updater ) { 652 return self::recalc_usage_data( $updater ); 653 } 654 655 public static function _v_2_8_3_recalc_usage_data( $updater ) { 656 // Re-calc since older version(s) had invalid values. 657 return self::recalc_usage_data( $updater ); 658 } 659 660 /** 661 * Move general & lightbox settings to active kit and all it's revisions. 662 * 663 * @param Updater $updater 664 * 665 * @return bool 666 */ 667 public static function _v_3_0_0_move_general_settings_to_kit( $updater ) { 668 $callback = function( $kit_id ) { 669 $kit = Plugin::$instance->documents->get( $kit_id ); 670 671 if ( ! $kit ) { 672 self::notice( 'Kit not found. nothing to do.' ); 673 return; 674 } 675 676 $meta_key = SettingsPageManager::META_KEY; 677 $current_settings = get_option( '_elementor_general_settings', [] ); 678 // Take the `space_between_widgets` from the option due to a bug on E < 3.0.0 that the value `0` is stored separated. 679 $current_settings['space_between_widgets'] = get_option( 'elementor_space_between_widgets', '' ); 680 $current_settings[ Breakpoints_Manager::BREAKPOINT_SETTING_PREFIX . 'md' ] = get_option( 'elementor_viewport_md', '' ); 681 $current_settings[ Breakpoints_Manager::BREAKPOINT_SETTING_PREFIX . 'lg' ] = get_option( 'elementor_viewport_lg', '' ); 682 683 $kit_settings = $kit->get_meta( $meta_key ); 684 685 // Already exist. 686 if ( isset( $kit_settings['default_generic_fonts'] ) ) { 687 self::notice( 'General Settings already exist. nothing to do.' ); 688 return; 689 } 690 691 if ( empty( $current_settings ) ) { 692 self::notice( 'Current settings are empty. nothing to do.' ); 693 return; 694 } 695 696 if ( ! $kit_settings ) { 697 $kit_settings = []; 698 } 699 700 // Convert some setting to Elementor slider format. 701 $settings_to_slider = [ 702 'container_width', 703 'space_between_widgets', 704 ]; 705 706 foreach ( $settings_to_slider as $setting ) { 707 if ( isset( $current_settings[ $setting ] ) ) { 708 $current_settings[ $setting ] = [ 709 'unit' => 'px', 710 'size' => $current_settings[ $setting ], 711 ]; 712 } 713 } 714 715 $kit_settings = array_merge( $kit_settings, $current_settings ); 716 717 $page_settings_manager = SettingsManager::get_settings_managers( 'page' ); 718 $page_settings_manager->save_settings( $kit_settings, $kit_id ); 719 }; 720 721 return self::move_settings_to_kit( $callback, $updater ); 722 } 723 724 /** 725 * Move default colors settings to active kit and all it's revisions. 726 * 727 * @param Updater $updater 728 * 729 * @return bool 730 */ 731 public static function _v_3_0_0_move_default_colors_to_kit( $updater, $include_revisions = true ) { 732 $callback = function( $kit_id ) { 733 if ( ! Plugin::$instance->kits_manager->is_custom_colors_enabled() ) { 734 self::notice( 'System colors are disabled. nothing to do.' ); 735 return; 736 } 737 738 $kit = Plugin::$instance->documents->get( $kit_id ); 739 740 // Already exist. use raw settings that doesn't have default values. 741 $meta_key = SettingsPageManager::META_KEY; 742 $kit_raw_settings = $kit->get_meta( $meta_key ); 743 if ( isset( $kit_raw_settings['system_colors'] ) ) { 744 self::notice( 'System colors already exist. nothing to do.' ); 745 return; 746 } 747 748 $scheme_obj = Plugin::$instance->schemes_manager->get_scheme( 'color' ); 749 750 $default_colors = $scheme_obj->get_scheme(); 751 752 $new_ids = [ 753 'primary', 754 'secondary', 755 'text', 756 'accent', 757 ]; 758 759 foreach ( $default_colors as $index => $color ) { 760 $kit->add_repeater_row( 'system_colors', [ 761 '_id' => $new_ids[ $index - 1 ], // $default_colors starts from 1. 762 'title' => $color['title'], 763 'color' => strtoupper( $color['value'] ), 764 ] ); 765 } 766 }; 767 768 return self::move_settings_to_kit( $callback, $updater, $include_revisions ); 769 } 770 771 /** 772 * Move saved colors settings to active kit and all it's revisions. 773 * 774 * @param Updater $updater 775 * 776 * @return bool 777 */ 778 public static function _v_3_0_0_move_saved_colors_to_kit( $updater, $include_revisions = true ) { 779 $callback = function( $kit_id ) { 780 $kit = Plugin::$instance->documents->get( $kit_id ); 781 782 // Already exist. use raw settings that doesn't have default values. 783 $meta_key = SettingsPageManager::META_KEY; 784 $kit_raw_settings = $kit->get_meta( $meta_key ); 785 if ( isset( $kit_raw_settings['custom_colors'] ) ) { 786 self::notice( 'Custom colors already exist. nothing to do.' ); 787 return; 788 } 789 790 $system_colors_rows = $kit->get_settings( 'system_colors' ); 791 792 if ( ! $system_colors_rows ) { 793 $system_colors_rows = []; 794 } 795 796 $system_colors = []; 797 798 foreach ( $system_colors_rows as $color_row ) { 799 $system_colors[] = strtoupper( $color_row['color'] ); 800 } 801 802 $saved_scheme_obj = Plugin::$instance->schemes_manager->get_scheme( 'color-picker' ); 803 804 $current_saved_colors_rows = $saved_scheme_obj->get_scheme(); 805 806 $current_saved_colors = []; 807 808 foreach ( $current_saved_colors_rows as $color_row ) { 809 $current_saved_colors[] = strtoupper( $color_row['value'] ); 810 } 811 812 $colors_to_save = array_diff( $current_saved_colors, $system_colors ); 813 814 if ( empty( $colors_to_save ) ) { 815 self::notice( 'Saved colors not found. nothing to do.' ); 816 return; 817 } 818 819 foreach ( $colors_to_save as $index => $color ) { 820 $kit->add_repeater_row( 'custom_colors', [ 821 '_id' => Utils::generate_random_string(), 822 'title' => esc_html__( 'Saved Color', 'elementor' ) . ' #' . ( $index + 1 ), 823 'color' => $color, 824 ] ); 825 } 826 }; 827 828 return self::move_settings_to_kit( $callback, $updater, $include_revisions ); 829 } 830 831 /** 832 * Move default typography settings to active kit and all it's revisions. 833 * 834 * @param Updater $updater 835 * 836 * @return bool 837 */ 838 public static function _v_3_0_0_move_default_typography_to_kit( $updater, $include_revisions = true ) { 839 $callback = function( $kit_id ) { 840 if ( ! Plugin::$instance->kits_manager->is_custom_typography_enabled() ) { 841 self::notice( 'System typography is disabled. nothing to do.' ); 842 return; 843 } 844 845 $kit = Plugin::$instance->documents->get( $kit_id ); 846 847 // Already exist. use raw settings that doesn't have default values. 848 $meta_key = SettingsPageManager::META_KEY; 849 $kit_raw_settings = $kit->get_meta( $meta_key ); 850 if ( isset( $kit_raw_settings['system_typography'] ) ) { 851 self::notice( 'System typography already exist. nothing to do.' ); 852 return; 853 } 854 855 $scheme_obj = Plugin::$instance->schemes_manager->get_scheme( 'typography' ); 856 857 $default_typography = $scheme_obj->get_scheme(); 858 859 $new_ids = [ 860 'primary', 861 'secondary', 862 'text', 863 'accent', 864 ]; 865 866 foreach ( $default_typography as $index => $typography ) { 867 $kit->add_repeater_row( 'system_typography', [ 868 '_id' => $new_ids[ $index - 1 ], // $default_typography starts from 1. 869 'title' => $typography['title'], 870 'typography_typography' => 'custom', 871 'typography_font_family' => $typography['value']['font_family'], 872 'typography_font_weight' => $typography['value']['font_weight'], 873 ] ); 874 } 875 }; 876 877 return self::move_settings_to_kit( $callback, $updater, $include_revisions ); 878 } 879 880 public static function v_3_1_0_move_optimized_dom_output_to_experiments() { 881 $saved_option = get_option( 'elementor_optimized_dom_output' ); 882 883 if ( $saved_option ) { 884 $new_option = 'enabled' === $saved_option ? Experiments_Manager::STATE_ACTIVE : Experiments_Manager::STATE_INACTIVE; 885 886 add_option( 'elementor_experiment-e_dom_optimization', $new_option ); 887 } 888 } 889 890 public static function _v_3_2_0_migrate_breakpoints_to_new_system( $updater, $include_revisions = true ) { 891 $callback = function( $kit_id ) { 892 $kit = Plugin::$instance->documents->get( $kit_id ); 893 894 $kit_settings = $kit->get_meta( SettingsPageManager::META_KEY ); 895 896 if ( ! $kit_settings ) { 897 // Nothing to upgrade. 898 return; 899 } 900 901 $prefix = Breakpoints_Manager::BREAKPOINT_SETTING_PREFIX; 902 $old_mobile_option_key = $prefix . 'md'; 903 $old_tablet_option_key = $prefix . 'lg'; 904 905 $breakpoint_values = [ 906 $old_mobile_option_key => Plugin::$instance->kits_manager->get_current_settings( $old_mobile_option_key ), 907 $old_tablet_option_key => Plugin::$instance->kits_manager->get_current_settings( $old_tablet_option_key ), 908 ]; 909 910 // Breakpoint values are either a number, or an empty string (empty setting). 911 array_walk( $breakpoint_values, function( &$breakpoint_value, $breakpoint_key ) { 912 if ( $breakpoint_value ) { 913 // If the saved breakpoint value is a number, 1px is reduced because the new breakpoints system is 914 // based on max-width, as opposed to the old breakpoints system that worked based on min-width. 915 $breakpoint_value--; 916 } 917 918 return $breakpoint_value; 919 } ); 920 921 $kit_settings[ $prefix . Breakpoints_Manager::BREAKPOINT_KEY_MOBILE ] = $breakpoint_values[ $old_mobile_option_key ]; 922 $kit_settings[ $prefix . Breakpoints_Manager::BREAKPOINT_KEY_TABLET ] = $breakpoint_values[ $old_tablet_option_key ]; 923 924 $page_settings_manager = SettingsManager::get_settings_managers( 'page' ); 925 $page_settings_manager->save_settings( $kit_settings, $kit_id ); 926 }; 927 928 return self::move_settings_to_kit( $callback, $updater, $include_revisions ); 929 } 930 931 /** 932 * @param callback $callback 933 * @param Updater $updater 934 * 935 * @param bool $include_revisions 936 * 937 * @return mixed 938 */ 939 private static function move_settings_to_kit( $callback, $updater, $include_revisions = true ) { 940 $active_kit_id = Plugin::$instance->kits_manager->get_active_id(); 941 if ( ! $active_kit_id ) { 942 self::notice( 'Active kit not found. nothing to do.' ); 943 return false; 944 } 945 946 $offset = $updater->get_current_offset(); 947 948 // On first iteration apply on active kit itself. 949 // (don't include it with revisions in order to avoid offset/iteration count wrong numbers) 950 if ( 0 === $offset ) { 951 $callback( $active_kit_id ); 952 } 953 954 if ( ! $include_revisions ) { 955 return false; 956 } 957 958 $revisions_ids = wp_get_post_revisions( $active_kit_id, [ 959 'fields' => 'ids', 960 'posts_per_page' => $updater->get_limit(), 961 'offset' => $offset, 962 ] ); 963 964 foreach ( $revisions_ids as $revision_id ) { 965 $callback( $revision_id ); 966 } 967 968 return $updater->should_run_again( $revisions_ids ); 969 } 970 971 private static function notice( $message ) { 972 $logger = Plugin::$instance->logger->get_logger(); 973 $logger->notice( $message ); 974 } 975 }