| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Upgrade API: Theme_Upgrader class 4 * 5 * @package WordPress 6 * @subpackage Upgrader 7 * @since 4.6.0 8 */ 9 10 /** 11 * Core class used for upgrading/installing themes. 12 * 13 * It is designed to upgrade/install themes from a local zip, remote zip URL, 14 * or uploaded zip file. 15 * 16 * @since 2.8.0 17 * @since 4.6.0 Moved to its own file from wp-admin/includes/class-wp-upgrader.php. 18 * 19 * @see WP_Upgrader 20 */ 21 class Theme_Upgrader extends WP_Upgrader { 22 23 /** 24 * Result of the theme upgrade offer. 25 * 26 * @since 2.8.0 27 * @var array|WP_Error|null $result 28 * @phpstan-var non-empty-array<string, mixed>|WP_Error|null 29 * @see WP_Upgrader::$result 30 */ 31 public $result; 32 33 /** 34 * Whether multiple themes are being upgraded/installed in bulk. 35 * 36 * @since 2.9.0 37 * @var bool $bulk 38 */ 39 public $bulk = false; 40 41 /** 42 * New theme info. 43 * 44 * @since 5.5.0 45 * @var array $new_theme_data 46 * 47 * @see check_package() 48 */ 49 public $new_theme_data = array(); 50 51 /** 52 * Initializes the upgrade strings. 53 * 54 * @since 2.8.0 55 */ 56 public function upgrade_strings() { 57 $this->strings['up_to_date'] = __( 'The theme is at the latest version.' ); 58 $this->strings['no_package'] = __( 'Update package not available.' ); 59 /* translators: %s: Package URL. */ 60 $this->strings['downloading_package'] = sprintf( __( 'Downloading update from %s…' ), '<span class="code pre">%s</span>' ); 61 $this->strings['unpack_package'] = __( 'Unpacking the update…' ); 62 $this->strings['remove_old'] = __( 'Removing the old version of the theme…' ); 63 $this->strings['remove_old_failed'] = __( 'Could not remove the old theme.' ); 64 $this->strings['process_failed'] = __( 'Theme update failed.' ); 65 $this->strings['process_success'] = __( 'Theme updated successfully.' ); 66 } 67 68 /** 69 * Initializes the installation strings. 70 * 71 * @since 2.8.0 72 */ 73 public function install_strings() { 74 $this->strings['no_package'] = __( 'Installation package not available.' ); 75 /* translators: %s: Package URL. */ 76 $this->strings['downloading_package'] = sprintf( __( 'Downloading installation package from %s…' ), '<span class="code pre">%s</span>' ); 77 $this->strings['unpack_package'] = __( 'Unpacking the package…' ); 78 $this->strings['installing_package'] = __( 'Installing the theme…' ); 79 $this->strings['remove_old'] = __( 'Removing the old version of the theme…' ); 80 $this->strings['remove_old_failed'] = __( 'Could not remove the old theme.' ); 81 $this->strings['no_files'] = __( 'The theme contains no files.' ); 82 $this->strings['process_failed'] = __( 'Theme installation failed.' ); 83 $this->strings['process_success'] = __( 'Theme installed successfully.' ); 84 /* translators: 1: Theme name, 2: Theme version. */ 85 $this->strings['process_success_specific'] = __( 'Successfully installed the theme <strong>%1$s %2$s</strong>.' ); 86 $this->strings['parent_theme_search'] = __( 'This theme requires a parent theme. Checking if it is installed…' ); 87 /* translators: 1: Theme name, 2: Theme version. */ 88 $this->strings['parent_theme_prepare_install'] = __( 'Preparing to install <strong>%1$s %2$s</strong>…' ); 89 /* translators: 1: Theme name, 2: Theme version. */ 90 $this->strings['parent_theme_currently_installed'] = __( 'The parent theme, <strong>%1$s %2$s</strong>, is currently installed.' ); 91 /* translators: 1: Theme name, 2: Theme version. */ 92 $this->strings['parent_theme_install_success'] = __( 'Successfully installed the parent theme, <strong>%1$s %2$s</strong>.' ); 93 /* translators: %s: Theme name. */ 94 $this->strings['parent_theme_not_found'] = sprintf( __( '<strong>The parent theme could not be found.</strong> You will need to install the parent theme, %s, before you can use this child theme.' ), '<strong>%s</strong>' ); 95 /* translators: %s: Theme error. */ 96 $this->strings['current_theme_has_errors'] = __( 'The active theme has the following error: "%s".' ); 97 98 if ( ! empty( $this->skin->overwrite ) ) { 99 if ( 'update-theme' === $this->skin->overwrite ) { 100 $this->strings['installing_package'] = __( 'Updating the theme…' ); 101 $this->strings['process_failed'] = __( 'Theme update failed.' ); 102 $this->strings['process_success'] = __( 'Theme updated successfully.' ); 103 } 104 105 if ( 'downgrade-theme' === $this->skin->overwrite ) { 106 $this->strings['installing_package'] = __( 'Downgrading the theme…' ); 107 $this->strings['process_failed'] = __( 'Theme downgrade failed.' ); 108 $this->strings['process_success'] = __( 'Theme downgraded successfully.' ); 109 } 110 } 111 } 112 113 /** 114 * Checks if a child theme is being installed and its parent also needs to be installed. 115 * 116 * Hooked to the {@see 'upgrader_post_install'} filter by Theme_Upgrader::install(). 117 * 118 * @since 3.4.0 119 * 120 * @param bool $install_result 121 * @param array $hook_extra 122 * @param array $child_result 123 * @return bool 124 * 125 * @phpstan-param non-empty-array<string, mixed> $child_result 126 */ 127 public function check_parent_theme_filter( $install_result, $hook_extra, $child_result ) { 128 // Check to see if we need to install a parent theme. 129 $theme_info = $this->theme_info(); 130 131 if ( ! $theme_info->parent() ) { 132 return $install_result; 133 } 134 135 $this->skin->feedback( 'parent_theme_search' ); 136 137 if ( ! $theme_info->parent()->errors() ) { 138 $this->skin->feedback( 'parent_theme_currently_installed', $theme_info->parent()->display( 'Name' ), $theme_info->parent()->display( 'Version' ) ); 139 // We already have the theme, fall through. 140 return $install_result; 141 } 142 143 // We don't have the parent theme, let's install it. 144 $api = themes_api( 145 'theme_information', 146 array( 147 'slug' => $theme_info->get( 'Template' ), 148 'fields' => array( 149 'sections' => false, 150 'tags' => false, 151 ), 152 ) 153 ); // Save on a bit of bandwidth. 154 155 if ( ! $api || is_wp_error( $api ) ) { 156 $this->skin->feedback( 'parent_theme_not_found', $theme_info->get( 'Template' ) ); 157 // Don't show activate or preview actions after installation. 158 add_filter( 'install_theme_complete_actions', array( $this, 'hide_activate_preview_actions' ) ); 159 return $install_result; 160 } 161 162 // Backup required data we're going to override: 163 $child_api = $this->skin->api; 164 $child_success_message = $this->strings['process_success']; 165 166 // Override them. 167 $this->skin->api = $api; 168 169 $this->strings['process_success_specific'] = $this->strings['parent_theme_install_success']; 170 171 $this->skin->feedback( 'parent_theme_prepare_install', $api->name, $api->version ); 172 173 add_filter( 'install_theme_complete_actions', '__return_false', 999 ); // Don't show any actions after installing the theme. 174 175 // Install the parent theme. 176 $parent_result = $this->run( 177 array( 178 'package' => $api->download_link, 179 'destination' => get_theme_root(), 180 'clear_destination' => false, // Do not overwrite files. 181 'clear_working' => true, 182 ) 183 ); 184 185 if ( is_wp_error( $parent_result ) ) { 186 add_filter( 'install_theme_complete_actions', array( $this, 'hide_activate_preview_actions' ) ); 187 } 188 189 // Start cleaning up after the parent's installation. 190 remove_filter( 'install_theme_complete_actions', '__return_false', 999 ); 191 192 // Reset child's result and data. 193 $this->result = $child_result; 194 $this->skin->api = $child_api; 195 $this->strings['process_success'] = $child_success_message; 196 197 return $install_result; 198 } 199 200 /** 201 * Don't display the activate and preview actions to the user. 202 * 203 * Hooked to the {@see 'install_theme_complete_actions'} filter by 204 * Theme_Upgrader::check_parent_theme_filter() when installing 205 * a child theme and installing the parent theme fails. 206 * 207 * @since 3.4.0 208 * 209 * @param array $actions Preview actions. 210 * @return array 211 */ 212 public function hide_activate_preview_actions( $actions ) { 213 unset( $actions['activate'], $actions['preview'] ); 214 return $actions; 215 } 216 217 /** 218 * Install a theme package. 219 * 220 * @since 2.8.0 221 * @since 3.7.0 The `$args` parameter was added, making clearing the update cache optional. 222 * 223 * @param string $package The full local path or URI of the package. 224 * @param array $args { 225 * Optional. Other arguments for installing a theme package. Default empty array. 226 * 227 * @type bool $clear_update_cache Whether to clear the updates cache if successful. 228 * Default true. 229 * } 230 * 231 * @return bool|WP_Error|null True if the installation was successful, false or a WP_Error object otherwise. 232 * Null if the installation failed before the package was installed, for 233 * example when the package could not be downloaded. 234 */ 235 public function install( $package, $args = array() ) { 236 $defaults = array( 237 'clear_update_cache' => true, 238 'overwrite_package' => false, // Do not overwrite files. 239 ); 240 $parsed_args = wp_parse_args( $args, $defaults ); 241 242 $this->init(); 243 $this->install_strings(); 244 245 add_filter( 'upgrader_source_selection', array( $this, 'check_package' ) ); 246 add_filter( 'upgrader_post_install', array( $this, 'check_parent_theme_filter' ), 10, 3 ); 247 248 if ( $parsed_args['clear_update_cache'] ) { 249 // Clear cache so wp_update_themes() knows about the new theme. 250 add_action( 'upgrader_process_complete', 'wp_clean_themes_cache', 9, 0 ); 251 } 252 253 $this->run( 254 array( 255 'package' => $package, 256 'destination' => get_theme_root(), 257 'clear_destination' => $parsed_args['overwrite_package'], 258 'clear_working' => true, 259 'hook_extra' => array( 260 'type' => 'theme', 261 'action' => 'install', 262 ), 263 ) 264 ); 265 266 remove_action( 'upgrader_process_complete', 'wp_clean_themes_cache', 9 ); 267 remove_filter( 'upgrader_source_selection', array( $this, 'check_package' ) ); 268 remove_filter( 'upgrader_post_install', array( $this, 'check_parent_theme_filter' ) ); 269 270 if ( ! $this->result || is_wp_error( $this->result ) ) { 271 return $this->result; 272 } 273 274 // Refresh the Theme Update information. 275 wp_clean_themes_cache( $parsed_args['clear_update_cache'] ); 276 277 if ( $parsed_args['overwrite_package'] ) { 278 /** This action is documented in wp-admin/includes/class-plugin-upgrader.php */ 279 do_action( 'upgrader_overwrote_package', $package, $this->new_theme_data, 'theme' ); 280 } 281 282 return true; 283 } 284 285 /** 286 * Upgrades a theme. 287 * 288 * @since 2.8.0 289 * @since 3.7.0 The `$args` parameter was added, making clearing the update cache optional. 290 * 291 * @param string $theme The theme slug. 292 * @param array $args { 293 * Optional. Other arguments for upgrading a theme. Default empty array. 294 * 295 * @type bool $clear_update_cache Whether to clear the update cache if successful. 296 * Default true. 297 * } 298 * @return bool|WP_Error|null True if the upgrade was successful, false or a WP_Error object otherwise. 299 * Null if the upgrade failed before the package was installed, for example 300 * when the package could not be downloaded. 301 */ 302 public function upgrade( $theme, $args = array() ) { 303 $defaults = array( 304 'clear_update_cache' => true, 305 ); 306 $parsed_args = wp_parse_args( $args, $defaults ); 307 308 $this->init(); 309 $this->upgrade_strings(); 310 311 // Is an update available? 312 $current = get_site_transient( 'update_themes' ); 313 if ( ! isset( $current->response[ $theme ] ) ) { 314 $this->skin->before(); 315 $this->skin->set_result( false ); 316 $this->skin->error( 'up_to_date' ); 317 $this->skin->after(); 318 return false; 319 } 320 321 $upgrade_data = $current->response[ $theme ]; 322 323 add_filter( 'upgrader_pre_install', array( $this, 'current_before' ), 10, 2 ); 324 add_filter( 'upgrader_post_install', array( $this, 'current_after' ), 10, 2 ); 325 add_filter( 'upgrader_clear_destination', array( $this, 'delete_old_theme' ), 10, 4 ); 326 if ( $parsed_args['clear_update_cache'] ) { 327 // Clear cache so wp_update_themes() knows about the new theme. 328 add_action( 'upgrader_process_complete', 'wp_clean_themes_cache', 9, 0 ); 329 } 330 331 $this->run( 332 array( 333 'package' => $upgrade_data['package'], 334 'destination' => get_theme_root( $theme ), 335 'clear_destination' => true, 336 'clear_working' => true, 337 'hook_extra' => array( 338 'theme' => $theme, 339 'type' => 'theme', 340 'action' => 'update', 341 'temp_backup' => array( 342 'slug' => $theme, 343 'src' => get_theme_root( $theme ), 344 'dir' => 'themes', 345 ), 346 ), 347 ) 348 ); 349 350 remove_action( 'upgrader_process_complete', 'wp_clean_themes_cache', 9 ); 351 remove_filter( 'upgrader_pre_install', array( $this, 'current_before' ) ); 352 remove_filter( 'upgrader_post_install', array( $this, 'current_after' ) ); 353 remove_filter( 'upgrader_clear_destination', array( $this, 'delete_old_theme' ) ); 354 355 if ( ! $this->result || is_wp_error( $this->result ) ) { 356 return $this->result; 357 } 358 359 wp_clean_themes_cache( $parsed_args['clear_update_cache'] ); 360 361 /* 362 * Ensure any future auto-update failures trigger a failure email by removing 363 * the last failure notification from the list when themes update successfully. 364 */ 365 $past_failure_emails = get_option( 'auto_plugin_theme_update_emails', array() ); 366 367 if ( isset( $past_failure_emails[ $theme ] ) ) { 368 unset( $past_failure_emails[ $theme ] ); 369 update_option( 'auto_plugin_theme_update_emails', $past_failure_emails ); 370 } 371 372 return true; 373 } 374 375 /** 376 * Upgrades several themes at once. 377 * 378 * @since 3.0.0 379 * @since 3.7.0 The `$args` parameter was added, making clearing the update cache optional. 380 * 381 * @param string[] $themes Array of the theme slugs. 382 * @param array $args { 383 * Optional. Other arguments for upgrading several themes at once. Default empty array. 384 * 385 * @type bool $clear_update_cache Whether to clear the update cache if successful. 386 * Default true. 387 * } 388 * @return array[]|false An array of results, or false if unable to connect to the filesystem. 389 */ 390 public function bulk_upgrade( $themes, $args = array() ) { 391 $wp_version = wp_get_wp_version(); 392 $defaults = array( 393 'clear_update_cache' => true, 394 ); 395 $parsed_args = wp_parse_args( $args, $defaults ); 396 397 $this->init(); 398 $this->bulk = true; 399 $this->upgrade_strings(); 400 401 $current = get_site_transient( 'update_themes' ); 402 403 add_filter( 'upgrader_pre_install', array( $this, 'current_before' ), 10, 2 ); 404 add_filter( 'upgrader_post_install', array( $this, 'current_after' ), 10, 2 ); 405 add_filter( 'upgrader_clear_destination', array( $this, 'delete_old_theme' ), 10, 4 ); 406 407 $this->skin->header(); 408 409 // Connect to the filesystem first. 410 $connected = $this->fs_connect( array( WP_CONTENT_DIR ) ); 411 if ( ! $connected ) { 412 $this->skin->footer(); 413 return false; 414 } 415 416 $this->skin->bulk_header(); 417 418 /* 419 * Only start maintenance mode if: 420 * - running Multisite and there are one or more themes specified, OR 421 * - a theme with an update available is currently in use. 422 * @todo For multisite, maintenance mode should only kick in for individual sites if at all possible. 423 */ 424 $maintenance = ( is_multisite() && ! empty( $themes ) ); 425 foreach ( $themes as $theme ) { 426 $maintenance = $maintenance || get_stylesheet() === $theme || get_template() === $theme; 427 } 428 if ( $maintenance ) { 429 $this->maintenance_mode( true ); 430 } 431 432 $results = array(); 433 434 $this->update_count = count( $themes ); 435 $this->update_current = 0; 436 foreach ( $themes as $theme ) { 437 ++$this->update_current; 438 439 $this->skin->theme_info = $this->theme_info( $theme ); 440 441 if ( ! isset( $current->response[ $theme ] ) ) { 442 $this->skin->set_result( true ); 443 $this->skin->before(); 444 $this->skin->feedback( 'up_to_date' ); 445 $this->skin->after(); 446 $results[ $theme ] = true; 447 continue; 448 } 449 450 // Get the URL to the zip file. 451 $upgrade_data = $current->response[ $theme ]; 452 453 if ( isset( $upgrade_data['requires'] ) && ! is_wp_version_compatible( $upgrade_data['requires'] ) ) { 454 $result = new WP_Error( 455 'incompatible_wp_required_version', 456 sprintf( 457 /* translators: 1: Current WordPress version, 2: WordPress version required by the new theme version. */ 458 __( 'Your WordPress version is %1$s, however the new theme version requires %2$s.' ), 459 $wp_version, 460 $upgrade_data['requires'] 461 ) 462 ); 463 464 $this->skin->before(); 465 $this->skin->error( $result ); 466 $this->skin->after(); 467 } elseif ( isset( $upgrade_data['requires_php'] ) && ! is_php_version_compatible( $upgrade_data['requires_php'] ) ) { 468 $result = new WP_Error( 469 'incompatible_php_required_version', 470 sprintf( 471 /* translators: 1: Current PHP version, 2: PHP version required by the new theme version. */ 472 __( 'The PHP version on your server is %1$s, however the new theme version requires %2$s.' ), 473 PHP_VERSION, 474 $upgrade_data['requires_php'] 475 ) 476 ); 477 478 $this->skin->before(); 479 $this->skin->error( $result ); 480 $this->skin->after(); 481 } else { 482 add_filter( 'upgrader_source_selection', array( $this, 'check_package' ) ); 483 $result = $this->run( 484 array( 485 'package' => $upgrade_data['package'], 486 'destination' => get_theme_root( $theme ), 487 'clear_destination' => true, 488 'clear_working' => true, 489 'is_multi' => true, 490 'hook_extra' => array( 491 'theme' => $theme, 492 'temp_backup' => array( 493 'slug' => $theme, 494 'src' => get_theme_root( $theme ), 495 'dir' => 'themes', 496 ), 497 ), 498 ) 499 ); 500 remove_filter( 'upgrader_source_selection', array( $this, 'check_package' ) ); 501 } 502 503 $results[ $theme ] = $result; 504 505 // Prevent credentials auth screen from displaying multiple times. 506 if ( false === $result ) { 507 break; 508 } 509 } // End foreach $themes. 510 511 $this->maintenance_mode( false ); 512 513 // Refresh the Theme Update information. 514 wp_clean_themes_cache( $parsed_args['clear_update_cache'] ); 515 516 /** This action is documented in wp-admin/includes/class-wp-upgrader.php */ 517 do_action( 518 'upgrader_process_complete', 519 $this, 520 array( 521 'action' => 'update', 522 'type' => 'theme', 523 'bulk' => true, 524 'themes' => $themes, 525 ) 526 ); 527 528 $this->skin->bulk_footer(); 529 530 $this->skin->footer(); 531 532 // Cleanup our hooks, in case something else does an upgrade on this connection. 533 remove_filter( 'upgrader_pre_install', array( $this, 'current_before' ) ); 534 remove_filter( 'upgrader_post_install', array( $this, 'current_after' ) ); 535 remove_filter( 'upgrader_clear_destination', array( $this, 'delete_old_theme' ) ); 536 537 /* 538 * Ensure any future auto-update failures trigger a failure email by removing 539 * the last failure notification from the list when themes update successfully. 540 */ 541 $past_failure_emails = get_option( 'auto_plugin_theme_update_emails', array() ); 542 543 foreach ( $results as $theme => $result ) { 544 // Maintain last failure notification when themes failed to update manually. 545 if ( ! $result || is_wp_error( $result ) || ! isset( $past_failure_emails[ $theme ] ) ) { 546 continue; 547 } 548 549 unset( $past_failure_emails[ $theme ] ); 550 } 551 552 update_option( 'auto_plugin_theme_update_emails', $past_failure_emails ); 553 554 return $results; 555 } 556 557 /** 558 * Checks that the package source contains a valid theme. 559 * 560 * Hooked to the {@see 'upgrader_source_selection'} filter by Theme_Upgrader::install(). 561 * 562 * @since 3.3.0 563 * 564 * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass. 565 * 566 * @param string $source The path to the downloaded package source. 567 * @return string|WP_Error The source as passed, or a WP_Error object on failure. 568 */ 569 public function check_package( $source ) { 570 global $wp_filesystem; 571 572 $wp_version = wp_get_wp_version(); 573 $this->new_theme_data = array(); 574 575 if ( is_wp_error( $source ) ) { 576 return $source; 577 } 578 579 // Check that the folder contains a valid theme. 580 $working_directory = str_replace( $wp_filesystem->wp_content_dir(), trailingslashit( WP_CONTENT_DIR ), $source ); 581 if ( ! is_dir( $working_directory ) ) { // Confidence check, if the above fails, let's not prevent installation. 582 return $source; 583 } 584 585 // A proper archive should have a style.css file in the single subdirectory. 586 if ( ! file_exists( $working_directory . 'style.css' ) ) { 587 return new WP_Error( 588 'incompatible_archive_theme_no_style', 589 $this->strings['incompatible_archive'], 590 sprintf( 591 /* translators: %s: style.css */ 592 __( 'The theme is missing the %s stylesheet.' ), 593 '<code>style.css</code>' 594 ) 595 ); 596 } 597 598 // All these headers are needed on Theme_Installer_Skin::do_overwrite(). 599 $new_theme_data = get_file_data( 600 $working_directory . 'style.css', 601 array( 602 'Name' => 'Theme Name', 603 'Version' => 'Version', 604 'Author' => 'Author', 605 'Template' => 'Template', 606 'RequiresWP' => 'Requires at least', 607 'RequiresPHP' => 'Requires PHP', 608 ) 609 ); 610 611 if ( empty( $new_theme_data['Name'] ) ) { 612 return new WP_Error( 613 'incompatible_archive_theme_no_name', 614 $this->strings['incompatible_archive'], 615 sprintf( 616 /* translators: %s: style.css */ 617 __( 'The %s stylesheet does not contain a valid theme header.' ), 618 '<code>style.css</code>' 619 ) 620 ); 621 } 622 623 /* 624 * Parent themes must contain an index file: 625 * - classic themes require /index.php 626 * - block themes require /templates/index.html or block-templates/index.html (deprecated 5.9.0). 627 */ 628 if ( 629 empty( $new_theme_data['Template'] ) && 630 ! file_exists( $working_directory . 'index.php' ) && 631 ! file_exists( $working_directory . 'templates/index.html' ) && 632 ! file_exists( $working_directory . 'block-templates/index.html' ) 633 ) { 634 return new WP_Error( 635 'incompatible_archive_theme_no_index', 636 $this->strings['incompatible_archive'], 637 sprintf( 638 /* translators: 1: templates/index.html, 2: index.php, 3: Documentation URL, 4: Template, 5: style.css */ 639 __( 'Template is missing. Standalone themes need to have a %1$s or %2$s template file. <a href="%3$s">Child themes</a> need to have a %4$s header in the %5$s stylesheet.' ), 640 '<code>templates/index.html</code>', 641 '<code>index.php</code>', 642 __( 'https://developer.wordpress.org/themes/advanced-topics/child-themes/' ), 643 '<code>Template</code>', 644 '<code>style.css</code>' 645 ) 646 ); 647 } 648 649 $requires_php = $new_theme_data['RequiresPHP'] ?? null; 650 $requires_wp = $new_theme_data['RequiresWP'] ?? null; 651 652 if ( ! is_php_version_compatible( $requires_php ) ) { 653 $error = sprintf( 654 /* translators: 1: Current PHP version, 2: Version required by the uploaded theme. */ 655 __( 'The PHP version on your server is %1$s, however the uploaded theme requires %2$s.' ), 656 PHP_VERSION, 657 $requires_php 658 ); 659 660 return new WP_Error( 'incompatible_php_required_version', $this->strings['incompatible_archive'], $error ); 661 } 662 if ( ! is_wp_version_compatible( $requires_wp ) ) { 663 $error = sprintf( 664 /* translators: 1: Current WordPress version, 2: Version required by the uploaded theme. */ 665 __( 'Your WordPress version is %1$s, however the uploaded theme requires %2$s.' ), 666 $wp_version, 667 $requires_wp 668 ); 669 670 return new WP_Error( 'incompatible_wp_required_version', $this->strings['incompatible_archive'], $error ); 671 } 672 673 $this->new_theme_data = $new_theme_data; 674 675 return $source; 676 } 677 678 /** 679 * Turns on maintenance mode before attempting to upgrade the active theme. 680 * 681 * Hooked to the {@see 'upgrader_pre_install'} filter by Theme_Upgrader::upgrade() and 682 * Theme_Upgrader::bulk_upgrade(). 683 * 684 * @since 2.8.0 685 * 686 * @param bool|WP_Error $response The installation response before the installation has started. 687 * @param array $theme Theme arguments. 688 * @return bool|WP_Error The original `$response` parameter or WP_Error. 689 */ 690 public function current_before( $response, $theme ) { 691 if ( is_wp_error( $response ) ) { 692 return $response; 693 } 694 695 $theme = $theme['theme'] ?? ''; 696 697 // Only run if active theme. 698 if ( get_stylesheet() !== $theme ) { 699 return $response; 700 } 701 702 // Change to maintenance mode. Bulk edit handles this separately. 703 if ( ! $this->bulk ) { 704 $this->maintenance_mode( true ); 705 } 706 707 return $response; 708 } 709 710 /** 711 * Turns off maintenance mode after upgrading the active theme. 712 * 713 * Hooked to the {@see 'upgrader_post_install'} filter by Theme_Upgrader::upgrade() 714 * and Theme_Upgrader::bulk_upgrade(). 715 * 716 * @since 2.8.0 717 * 718 * @param bool|WP_Error $response The installation response after the installation has finished. 719 * @param array $theme Theme arguments. 720 * @return bool|WP_Error The original `$response` parameter or WP_Error. 721 */ 722 public function current_after( $response, $theme ) { 723 if ( is_wp_error( $response ) ) { 724 return $response; 725 } 726 727 $theme = $theme['theme'] ?? ''; 728 729 // Only run if active theme. 730 if ( get_stylesheet() !== $theme ) { 731 return $response; 732 } 733 734 // Ensure stylesheet name hasn't changed after the upgrade: 735 if ( get_stylesheet() === $theme && $theme !== $this->result['destination_name'] ) { 736 wp_clean_themes_cache(); 737 $stylesheet = $this->result['destination_name']; 738 switch_theme( $stylesheet ); 739 } 740 741 // Time to remove maintenance mode. Bulk edit handles this separately. 742 if ( ! $this->bulk ) { 743 $this->maintenance_mode( false ); 744 } 745 return $response; 746 } 747 748 /** 749 * Deletes the old theme during an upgrade. 750 * 751 * Hooked to the {@see 'upgrader_clear_destination'} filter by Theme_Upgrader::upgrade() 752 * and Theme_Upgrader::bulk_upgrade(). 753 * 754 * @since 2.8.0 755 * 756 * @global WP_Filesystem_Base $wp_filesystem Filesystem subclass. 757 * 758 * @param bool $removed 759 * @param string $local_destination 760 * @param string $remote_destination 761 * @param array $theme 762 * @return bool 763 */ 764 public function delete_old_theme( $removed, $local_destination, $remote_destination, $theme ) { 765 global $wp_filesystem; 766 767 if ( is_wp_error( $removed ) ) { 768 return $removed; // Pass errors through. 769 } 770 771 if ( ! isset( $theme['theme'] ) ) { 772 return $removed; 773 } 774 775 $theme = $theme['theme']; 776 $themes_dir = trailingslashit( $wp_filesystem->wp_themes_dir( $theme ) ); 777 if ( $wp_filesystem->exists( $themes_dir . $theme ) ) { 778 if ( ! $wp_filesystem->delete( $themes_dir . $theme, true ) ) { 779 return false; 780 } 781 } 782 783 return true; 784 } 785 786 /** 787 * Gets the WP_Theme object for a theme. 788 * 789 * @since 2.8.0 790 * @since 3.0.0 The `$theme` argument was added. 791 * 792 * @param string $theme The directory name of the theme. This is optional, and if not supplied, 793 * the directory name from the last result will be used. 794 * @return WP_Theme|false The theme's info object, or false `$theme` is not supplied 795 * and the last result isn't set. 796 */ 797 public function theme_info( $theme = null ) { 798 if ( empty( $theme ) ) { 799 if ( ! empty( $this->result['destination_name'] ) ) { 800 $theme = $this->result['destination_name']; 801 } else { 802 return false; 803 } 804 } 805 806 $theme = wp_get_theme( $theme ); 807 $theme->cache_delete(); 808 809 return $theme; 810 } 811 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Tue Oct 20 08:20:34 2026 | Cross-referenced by PHPXref |