| [ Index ] |
PHP Cross Reference of WordPress |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * A File upgrader class for WordPress. 4 * 5 * This set of classes are designed to be used to upgrade/install a local set of files on the filesystem via the Filesystem Abstraction classes. 6 * 7 * @link http://trac.wordpress.org/ticket/7875 consolidate plugin/theme/core upgrade/install functions 8 * 9 * @package WordPress 10 * @subpackage Upgrader 11 * @since 2.8.0 12 */ 13 14 /** 15 * WordPress Upgrader class for Upgrading/Installing a local set of files via the Filesystem Abstraction classes from a Zip file. 16 * 17 * @TODO More Detailed docs, for methods as well. 18 * 19 * @package WordPress 20 * @subpackage Upgrader 21 * @since 2.8.0 22 */ 23 class WP_Upgrader { 24 var $strings = array(); 25 var $skin = null; 26 var $result = array(); 27 28 function __construct($skin = null) { 29 if ( null == $skin ) 30 $this->skin = new WP_Upgrader_Skin(); 31 else 32 $this->skin = $skin; 33 } 34 35 function init() { 36 $this->skin->set_upgrader($this); 37 $this->generic_strings(); 38 } 39 40 function generic_strings() { 41 $this->strings['bad_request'] = __('Invalid Data provided.'); 42 $this->strings['fs_unavailable'] = __('Could not access filesystem.'); 43 $this->strings['fs_error'] = __('Filesystem error.'); 44 $this->strings['fs_no_root_dir'] = __('Unable to locate WordPress Root directory.'); 45 $this->strings['fs_no_content_dir'] = __('Unable to locate WordPress Content directory (wp-content).'); 46 $this->strings['fs_no_plugins_dir'] = __('Unable to locate WordPress Plugin directory.'); 47 $this->strings['fs_no_themes_dir'] = __('Unable to locate WordPress Theme directory.'); 48 /* translators: %s: directory name */ 49 $this->strings['fs_no_folder'] = __('Unable to locate needed folder (%s).'); 50 51 $this->strings['download_failed'] = __('Download failed.'); 52 $this->strings['installing_package'] = __('Installing the latest version…'); 53 $this->strings['folder_exists'] = __('Destination folder already exists.'); 54 $this->strings['mkdir_failed'] = __('Could not create directory.'); 55 $this->strings['incompatible_archive'] = __('The package could not be installed.'); 56 57 $this->strings['maintenance_start'] = __('Enabling Maintenance mode…'); 58 $this->strings['maintenance_end'] = __('Disabling Maintenance mode…'); 59 } 60 61 function fs_connect( $directories = array() ) { 62 global $wp_filesystem; 63 64 if ( false === ($credentials = $this->skin->request_filesystem_credentials()) ) 65 return false; 66 67 if ( ! WP_Filesystem($credentials) ) { 68 $error = true; 69 if ( is_object($wp_filesystem) && $wp_filesystem->errors->get_error_code() ) 70 $error = $wp_filesystem->errors; 71 $this->skin->request_filesystem_credentials($error); //Failed to connect, Error and request again 72 return false; 73 } 74 75 if ( ! is_object($wp_filesystem) ) 76 return new WP_Error('fs_unavailable', $this->strings['fs_unavailable'] ); 77 78 if ( is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code() ) 79 return new WP_Error('fs_error', $this->strings['fs_error'], $wp_filesystem->errors); 80 81 foreach ( (array)$directories as $dir ) { 82 switch ( $dir ) { 83 case ABSPATH: 84 if ( ! $wp_filesystem->abspath() ) 85 return new WP_Error('fs_no_root_dir', $this->strings['fs_no_root_dir']); 86 break; 87 case WP_CONTENT_DIR: 88 if ( ! $wp_filesystem->wp_content_dir() ) 89 return new WP_Error('fs_no_content_dir', $this->strings['fs_no_content_dir']); 90 break; 91 case WP_PLUGIN_DIR: 92 if ( ! $wp_filesystem->wp_plugins_dir() ) 93 return new WP_Error('fs_no_plugins_dir', $this->strings['fs_no_plugins_dir']); 94 break; 95 case WP_CONTENT_DIR . '/themes': 96 if ( ! $wp_filesystem->find_folder(WP_CONTENT_DIR . '/themes') ) 97 return new WP_Error('fs_no_themes_dir', $this->strings['fs_no_themes_dir']); 98 break; 99 default: 100 if ( ! $wp_filesystem->find_folder($dir) ) 101 return new WP_Error('fs_no_folder', sprintf($this->strings['fs_no_folder'], $dir)); 102 break; 103 } 104 } 105 return true; 106 } //end fs_connect(); 107 108 function download_package($package) { 109 110 if ( ! preg_match('!^(http|https|ftp)://!i', $package) && file_exists($package) ) //Local file or remote? 111 return $package; //must be a local file.. 112 113 if ( empty($package) ) 114 return new WP_Error('no_package', $this->strings['no_package']); 115 116 $this->skin->feedback('downloading_package', $package); 117 118 $download_file = download_url($package); 119 120 if ( is_wp_error($download_file) ) 121 return new WP_Error('download_failed', $this->strings['download_failed'], $download_file->get_error_message()); 122 123 return $download_file; 124 } 125 126 function unpack_package($package, $delete_package = true) { 127 global $wp_filesystem; 128 129 $this->skin->feedback('unpack_package'); 130 131 $upgrade_folder = $wp_filesystem->wp_content_dir() . 'upgrade/'; 132 133 //Clean up contents of upgrade directory beforehand. 134 $upgrade_files = $wp_filesystem->dirlist($upgrade_folder); 135 if ( !empty($upgrade_files) ) { 136 foreach ( $upgrade_files as $file ) 137 $wp_filesystem->delete($upgrade_folder . $file['name'], true); 138 } 139 140 //We need a working directory 141 $working_dir = $upgrade_folder . basename($package, '.zip'); 142 143 // Clean up working directory 144 if ( $wp_filesystem->is_dir($working_dir) ) 145 $wp_filesystem->delete($working_dir, true); 146 147 // Unzip package to working directory 148 $result = unzip_file($package, $working_dir); //TODO optimizations, Copy when Move/Rename would suffice? 149 150 // Once extracted, delete the package if required. 151 if ( $delete_package ) 152 unlink($package); 153 154 if ( is_wp_error($result) ) { 155 $wp_filesystem->delete($working_dir, true); 156 if ( 'incompatible_archive' == $result->get_error_code() ) { 157 return new WP_Error( 'incompatible_archive', $this->strings['incompatible_archive'], $result->get_error_data() ); 158 } 159 return $result; 160 } 161 162 return $working_dir; 163 } 164 165 function install_package($args = array()) { 166 global $wp_filesystem; 167 $defaults = array( 'source' => '', 'destination' => '', //Please always pass these 168 'clear_destination' => false, 'clear_working' => false, 169 'hook_extra' => array()); 170 171 $args = wp_parse_args($args, $defaults); 172 extract($args); 173 174 @set_time_limit( 300 ); 175 176 if ( empty($source) || empty($destination) ) 177 return new WP_Error('bad_request', $this->strings['bad_request']); 178 179 $this->skin->feedback('installing_package'); 180 181 $res = apply_filters('upgrader_pre_install', true, $hook_extra); 182 if ( is_wp_error($res) ) 183 return $res; 184 185 //Retain the Original source and destinations 186 $remote_source = $source; 187 $local_destination = $destination; 188 189 $source_files = array_keys( $wp_filesystem->dirlist($remote_source) ); 190 $remote_destination = $wp_filesystem->find_folder($local_destination); 191 192 //Locate which directory to copy to the new folder, This is based on the actual folder holding the files. 193 if ( 1 == count($source_files) && $wp_filesystem->is_dir( trailingslashit($source) . $source_files[0] . '/') ) //Only one folder? Then we want its contents. 194 $source = trailingslashit($source) . trailingslashit($source_files[0]); 195 elseif ( count($source_files) == 0 ) 196 return new WP_Error( 'incompatible_archive', $this->strings['incompatible_archive'], __( 'The plugin contains no files.' ) ); //There are no files? 197 else //Its only a single file, The upgrader will use the foldername of this file as the destination folder. foldername is based on zip filename. 198 $source = trailingslashit($source); 199 200 //Hook ability to change the source file location.. 201 $source = apply_filters('upgrader_source_selection', $source, $remote_source, $this); 202 if ( is_wp_error($source) ) 203 return $source; 204 205 //Has the source location changed? If so, we need a new source_files list. 206 if ( $source !== $remote_source ) 207 $source_files = array_keys( $wp_filesystem->dirlist($source) ); 208 209 //Protection against deleting files in any important base directories. 210 if ( in_array( $destination, array(ABSPATH, WP_CONTENT_DIR, WP_PLUGIN_DIR, WP_CONTENT_DIR . '/themes') ) ) { 211 $remote_destination = trailingslashit($remote_destination) . trailingslashit(basename($source)); 212 $destination = trailingslashit($destination) . trailingslashit(basename($source)); 213 } 214 215 if ( $clear_destination ) { 216 //We're going to clear the destination if there's something there 217 $this->skin->feedback('remove_old'); 218 $removed = true; 219 if ( $wp_filesystem->exists($remote_destination) ) 220 $removed = $wp_filesystem->delete($remote_destination, true); 221 $removed = apply_filters('upgrader_clear_destination', $removed, $local_destination, $remote_destination, $hook_extra); 222 223 if ( is_wp_error($removed) ) 224 return $removed; 225 else if ( ! $removed ) 226 return new WP_Error('remove_old_failed', $this->strings['remove_old_failed']); 227 } elseif ( $wp_filesystem->exists($remote_destination) ) { 228 //If we're not clearing the destination folder and something exists there already, Bail. 229 //But first check to see if there are actually any files in the folder. 230 $_files = $wp_filesystem->dirlist($remote_destination); 231 if ( ! empty($_files) ) { 232 $wp_filesystem->delete($remote_source, true); //Clear out the source files. 233 return new WP_Error('folder_exists', $this->strings['folder_exists'], $remote_destination ); 234 } 235 } 236 237 //Create destination if needed 238 if ( !$wp_filesystem->exists($remote_destination) ) 239 if ( !$wp_filesystem->mkdir($remote_destination, FS_CHMOD_DIR) ) 240 return new WP_Error('mkdir_failed', $this->strings['mkdir_failed'], $remote_destination); 241 242 // Copy new version of item into place. 243 $result = copy_dir($source, $remote_destination); 244 if ( is_wp_error($result) ) { 245 if ( $clear_working ) 246 $wp_filesystem->delete($remote_source, true); 247 return $result; 248 } 249 250 //Clear the Working folder? 251 if ( $clear_working ) 252 $wp_filesystem->delete($remote_source, true); 253 254 $destination_name = basename( str_replace($local_destination, '', $destination) ); 255 if ( '.' == $destination_name ) 256 $destination_name = ''; 257 258 $this->result = compact('local_source', 'source', 'source_name', 'source_files', 'destination', 'destination_name', 'local_destination', 'remote_destination', 'clear_destination', 'delete_source_dir'); 259 260 $res = apply_filters('upgrader_post_install', true, $hook_extra, $this->result); 261 if ( is_wp_error($res) ) { 262 $this->result = $res; 263 return $res; 264 } 265 266 //Bombard the calling function will all the info which we've just used. 267 return $this->result; 268 } 269 270 function run($options) { 271 272 $defaults = array( 'package' => '', //Please always pass this. 273 'destination' => '', //And this 274 'clear_destination' => false, 275 'clear_working' => true, 276 'is_multi' => false, 277 'hook_extra' => array() //Pass any extra $hook_extra args here, this will be passed to any hooked filters. 278 ); 279 280 $options = wp_parse_args($options, $defaults); 281 extract($options); 282 283 //Connect to the Filesystem first. 284 $res = $this->fs_connect( array(WP_CONTENT_DIR, $destination) ); 285 if ( ! $res ) //Mainly for non-connected filesystem. 286 return false; 287 288 if ( is_wp_error($res) ) { 289 $this->skin->error($res); 290 return $res; 291 } 292 293 if ( !$is_multi ) // call $this->header separately if running multiple times 294 $this->skin->header(); 295 296 $this->skin->before(); 297 298 //Download the package (Note, This just returns the filename of the file if the package is a local file) 299 $download = $this->download_package( $package ); 300 if ( is_wp_error($download) ) { 301 $this->skin->error($download); 302 $this->skin->after(); 303 return $download; 304 } 305 306 $delete_package = ($download != $package); // Do not delete a "local" file 307 308 //Unzips the file into a temporary directory 309 $working_dir = $this->unpack_package( $download, $delete_package ); 310 if ( is_wp_error($working_dir) ) { 311 $this->skin->error($working_dir); 312 $this->skin->after(); 313 return $working_dir; 314 } 315 316 //With the given options, this installs it to the destination directory. 317 $result = $this->install_package( array( 318 'source' => $working_dir, 319 'destination' => $destination, 320 'clear_destination' => $clear_destination, 321 'clear_working' => $clear_working, 322 'hook_extra' => $hook_extra 323 ) ); 324 $this->skin->set_result($result); 325 if ( is_wp_error($result) ) { 326 $this->skin->error($result); 327 $this->skin->feedback('process_failed'); 328 } else { 329 //Install Succeeded 330 $this->skin->feedback('process_success'); 331 } 332 $this->skin->after(); 333 334 if ( !$is_multi ) 335 $this->skin->footer(); 336 337 return $result; 338 } 339 340 function maintenance_mode($enable = false) { 341 global $wp_filesystem; 342 $file = $wp_filesystem->abspath() . '.maintenance'; 343 if ( $enable ) { 344 $this->skin->feedback('maintenance_start'); 345 // Create maintenance file to signal that we are upgrading 346 $maintenance_string = '<?php $upgrading = ' . time() . '; ?>'; 347 $wp_filesystem->delete($file); 348 $wp_filesystem->put_contents($file, $maintenance_string, FS_CHMOD_FILE); 349 } else if ( !$enable && $wp_filesystem->exists($file) ) { 350 $this->skin->feedback('maintenance_end'); 351 $wp_filesystem->delete($file); 352 } 353 } 354 355 } 356 357 /** 358 * Plugin Upgrader class for WordPress Plugins, It is designed to upgrade/install plugins from a local zip, remote zip URL, or uploaded zip file. 359 * 360 * @TODO More Detailed docs, for methods as well. 361 * 362 * @package WordPress 363 * @subpackage Upgrader 364 * @since 2.8.0 365 */ 366 class Plugin_Upgrader extends WP_Upgrader { 367 368 var $result; 369 var $bulk = false; 370 var $show_before = ''; 371 372 function upgrade_strings() { 373 $this->strings['up_to_date'] = __('The plugin is at the latest version.'); 374 $this->strings['no_package'] = __('Update package not available.'); 375 $this->strings['downloading_package'] = __('Downloading update from <span class="code">%s</span>…'); 376 $this->strings['unpack_package'] = __('Unpacking the update…'); 377 $this->strings['remove_old'] = __('Removing the old version of the plugin…'); 378 $this->strings['remove_old_failed'] = __('Could not remove the old plugin.'); 379 $this->strings['process_failed'] = __('Plugin update failed.'); 380 $this->strings['process_success'] = __('Plugin updated successfully.'); 381 } 382 383 function install_strings() { 384 $this->strings['no_package'] = __('Install package not available.'); 385 $this->strings['downloading_package'] = __('Downloading install package from <span class="code">%s</span>…'); 386 $this->strings['unpack_package'] = __('Unpacking the package…'); 387 $this->strings['installing_package'] = __('Installing the plugin…'); 388 $this->strings['process_failed'] = __('Plugin install failed.'); 389 $this->strings['process_success'] = __('Plugin installed successfully.'); 390 } 391 392 function install($package) { 393 394 $this->init(); 395 $this->install_strings(); 396 397 add_filter('upgrader_source_selection', array(&$this, 'check_package') ); 398 399 $this->run(array( 400 'package' => $package, 401 'destination' => WP_PLUGIN_DIR, 402 'clear_destination' => false, //Do not overwrite files. 403 'clear_working' => true, 404 'hook_extra' => array() 405 )); 406 407 remove_filter('upgrader_source_selection', array(&$this, 'check_package') ); 408 409 if ( ! $this->result || is_wp_error($this->result) ) 410 return $this->result; 411 412 // Force refresh of plugin update information 413 delete_site_transient('update_plugins'); 414 wp_cache_delete( 'plugins', 'plugins' ); 415 416 return true; 417 } 418 419 function upgrade($plugin) { 420 421 $this->init(); 422 $this->upgrade_strings(); 423 424 $current = get_site_transient( 'update_plugins' ); 425 if ( !isset( $current->response[ $plugin ] ) ) { 426 $this->skin->before(); 427 $this->skin->set_result(false); 428 $this->skin->error('up_to_date'); 429 $this->skin->after(); 430 return false; 431 } 432 433 // Get the URL to the zip file 434 $r = $current->response[ $plugin ]; 435 436 add_filter('upgrader_pre_install', array(&$this, 'deactivate_plugin_before_upgrade'), 10, 2); 437 add_filter('upgrader_clear_destination', array(&$this, 'delete_old_plugin'), 10, 4); 438 //'source_selection' => array(&$this, 'source_selection'), //there's a trac ticket to move up the directory for zip's which are made a bit differently, useful for non-.org plugins. 439 440 $this->run(array( 441 'package' => $r->package, 442 'destination' => WP_PLUGIN_DIR, 443 'clear_destination' => true, 444 'clear_working' => true, 445 'hook_extra' => array( 446 'plugin' => $plugin 447 ) 448 )); 449 450 // Cleanup our hooks, in case something else does a upgrade on this connection. 451 remove_filter('upgrader_pre_install', array(&$this, 'deactivate_plugin_before_upgrade')); 452 remove_filter('upgrader_clear_destination', array(&$this, 'delete_old_plugin')); 453 454 if ( ! $this->result || is_wp_error($this->result) ) 455 return $this->result; 456 457 // Force refresh of plugin update information 458 delete_site_transient('update_plugins'); 459 wp_cache_delete( 'plugins', 'plugins' ); 460 } 461 462 function bulk_upgrade($plugins) { 463 464 $this->init(); 465 $this->bulk = true; 466 $this->upgrade_strings(); 467 468 $current = get_site_transient( 'update_plugins' ); 469 470 add_filter('upgrader_clear_destination', array(&$this, 'delete_old_plugin'), 10, 4); 471 472 $this->skin->header(); 473 474 // Connect to the Filesystem first. 475 $res = $this->fs_connect( array(WP_CONTENT_DIR, WP_PLUGIN_DIR) ); 476 if ( ! $res ) { 477 $this->skin->footer(); 478 return false; 479 } 480 481 $this->skin->bulk_header(); 482 483 // Only start maintenance mode if running in Multisite OR the plugin is in use 484 $maintenance = is_multisite(); // @TODO: This should only kick in for individual sites if at all possible. 485 foreach ( $plugins as $plugin ) 486 $maintenance = $maintenance || (is_plugin_active($plugin) && isset($current->response[ $plugin ]) ); // Only activate Maintenance mode if a plugin is active AND has an update available 487 if ( $maintenance ) 488 $this->maintenance_mode(true); 489 490 $results = array(); 491 492 $this->update_count = count($plugins); 493 $this->update_current = 0; 494 foreach ( $plugins as $plugin ) { 495 $this->update_current++; 496 $this->skin->plugin_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin, false, true); 497 498 if ( !isset( $current->response[ $plugin ] ) ) { 499 $this->skin->set_result(false); 500 $this->skin->before(); 501 $this->skin->error('up_to_date'); 502 $this->skin->after(); 503 $results[$plugin] = false; 504 continue; 505 } 506 507 // Get the URL to the zip file 508 $r = $current->response[ $plugin ]; 509 510 $this->skin->plugin_active = is_plugin_active($plugin); 511 512 $result = $this->run(array( 513 'package' => $r->package, 514 'destination' => WP_PLUGIN_DIR, 515 'clear_destination' => true, 516 'clear_working' => true, 517 'is_multi' => true, 518 'hook_extra' => array( 519 'plugin' => $plugin 520 ) 521 )); 522 523 $results[$plugin] = $this->result; 524 525 // Prevent credentials auth screen from displaying multiple times 526 if ( false === $result ) 527 break; 528 } //end foreach $plugins 529 530 $this->maintenance_mode(false); 531 532 $this->skin->bulk_footer(); 533 534 $this->skin->footer(); 535 536 // Cleanup our hooks, in case something else does a upgrade on this connection. 537 remove_filter('upgrader_clear_destination', array(&$this, 'delete_old_plugin')); 538 539 // Force refresh of plugin update information 540 delete_site_transient('update_plugins'); 541 wp_cache_delete( 'plugins', 'plugins' ); 542 543 return $results; 544 } 545 546 function check_package($source) { 547 global $wp_filesystem; 548 549 if ( is_wp_error($source) ) 550 return $source; 551 552 $working_directory = str_replace( $wp_filesystem->wp_content_dir(), trailingslashit(WP_CONTENT_DIR), $source); 553 if ( ! is_dir($working_directory) ) // Sanity check, if the above fails, lets not prevent installation. 554 return $source; 555 556 // Check the folder contains at least 1 valid plugin. 557 $plugins_found = false; 558 foreach ( glob( $working_directory . '*.php' ) as $file ) { 559 $info = get_plugin_data($file, false, false); 560 if ( !empty( $info['Name'] ) ) { 561 $plugins_found = true; 562 break; 563 } 564 } 565 566 if ( ! $plugins_found ) 567 return new WP_Error( 'incompatible_archive', $this->strings['incompatible_archive'], __('No valid plugins were found.') ); 568 569 return $source; 570 } 571 572 //return plugin info. 573 function plugin_info() { 574 if ( ! is_array($this->result) ) 575 return false; 576 if ( empty($this->result['destination_name']) ) 577 return false; 578 579 $plugin = get_plugins('/' . $this->result['destination_name']); //Ensure to pass with leading slash 580 if ( empty($plugin) ) 581 return false; 582 583 $pluginfiles = array_keys($plugin); //Assume the requested plugin is the first in the list 584 585 return $this->result['destination_name'] . '/' . $pluginfiles[0]; 586 } 587 588 //Hooked to pre_install 589 function deactivate_plugin_before_upgrade($return, $plugin) { 590 591 if ( is_wp_error($return) ) //Bypass. 592 return $return; 593 594 $plugin = isset($plugin['plugin']) ? $plugin['plugin'] : ''; 595 if ( empty($plugin) ) 596 return new WP_Error('bad_request', $this->strings['bad_request']); 597 598 if ( is_plugin_active($plugin) ) { 599 //Deactivate the plugin silently, Prevent deactivation hooks from running. 600 deactivate_plugins($plugin, true); 601 } 602 } 603 604 //Hooked to upgrade_clear_destination 605 function delete_old_plugin($removed, $local_destination, $remote_destination, $plugin) { 606 global $wp_filesystem; 607 608 if ( is_wp_error($removed) ) 609 return $removed; //Pass errors through. 610 611 $plugin = isset($plugin['plugin']) ? $plugin['plugin'] : ''; 612 if ( empty($plugin) ) 613 return new WP_Error('bad_request', $this->strings['bad_request']); 614 615 $plugins_dir = $wp_filesystem->wp_plugins_dir(); 616 $this_plugin_dir = trailingslashit( dirname($plugins_dir . $plugin) ); 617 618 if ( ! $wp_filesystem->exists($this_plugin_dir) ) //If its already vanished. 619 return $removed; 620 621 // If plugin is in its own directory, recursively delete the directory. 622 if ( strpos($plugin, '/') && $this_plugin_dir != $plugins_dir ) //base check on if plugin includes directory separator AND that its not the root plugin folder 623 $deleted = $wp_filesystem->delete($this_plugin_dir, true); 624 else 625 $deleted = $wp_filesystem->delete($plugins_dir . $plugin); 626 627 if ( ! $deleted ) 628 return new WP_Error('remove_old_failed', $this->strings['remove_old_failed']); 629 630 return true; 631 } 632 } 633 634 /** 635 * Theme Upgrader class for WordPress Themes, It is designed to upgrade/install themes from a local zip, remote zip URL, or uploaded zip file. 636 * 637 * @TODO More Detailed docs, for methods as well. 638 * 639 * @package WordPress 640 * @subpackage Upgrader 641 * @since 2.8.0 642 */ 643 class Theme_Upgrader extends WP_Upgrader { 644 645 var $result; 646 var $bulk = false; 647 648 function upgrade_strings() { 649 $this->strings['up_to_date'] = __('The theme is at the latest version.'); 650 $this->strings['no_package'] = __('Update package not available.'); 651 $this->strings['downloading_package'] = __('Downloading update from <span class="code">%s</span>…'); 652 $this->strings['unpack_package'] = __('Unpacking the update…'); 653 $this->strings['remove_old'] = __('Removing the old version of the theme…'); 654 $this->strings['remove_old_failed'] = __('Could not remove the old theme.'); 655 $this->strings['process_failed'] = __('Theme update failed.'); 656 $this->strings['process_success'] = __('Theme updated successfully.'); 657 } 658 659 function install_strings() { 660 $this->strings['no_package'] = __('Install package not available.'); 661 $this->strings['downloading_package'] = __('Downloading install package from <span class="code">%s</span>…'); 662 $this->strings['unpack_package'] = __('Unpacking the package…'); 663 $this->strings['installing_package'] = __('Installing the theme…'); 664 $this->strings['process_failed'] = __('Theme install failed.'); 665 $this->strings['process_success'] = __('Theme installed successfully.'); 666 /* translators: 1: theme name, 2: version */ 667 $this->strings['process_success_specific'] = __('Successfully installed the theme <strong>%1$s %2$s</strong>.'); 668 $this->strings['parent_theme_search'] = __('This theme requires a parent theme. Checking if it is installed…'); 669 /* translators: 1: theme name, 2: version */ 670 $this->strings['parent_theme_prepare_install'] = __('Preparing to install <strong>%1$s %2$s</strong>…'); 671 /* translators: 1: theme name, 2: version */ 672 $this->strings['parent_theme_currently_installed'] = __('The parent theme, <strong>%1$s %2$s</strong>, is currently installed.'); 673 /* translators: 1: theme name, 2: version */ 674 $this->strings['parent_theme_install_success'] = __('Successfully installed the parent theme, <strong>%1$s %2$s</strong>.'); 675 $this->strings['parent_theme_not_found'] = __('<strong>The parent theme could not be found.</strong> You will need to install the parent theme, <strong>%s</strong>, before you can use this child theme.'); 676 } 677 678 function check_parent_theme_filter($install_result, $hook_extra, $child_result) { 679 // Check to see if we need to install a parent theme 680 $theme_info = $this->theme_info(); 681 682 if ( ! $theme_info->parent() ) 683 return $install_result; 684 685 $this->skin->feedback( 'parent_theme_search' ); 686 687 if ( ! $theme_info->parent()->errors() ) { 688 $this->skin->feedback( 'parent_theme_currently_installed', $theme_info->parent()->display('Name'), $theme_info->parent()->display('Version') ); 689 // We already have the theme, fall through. 690 return $install_result; 691 } 692 693 // We don't have the parent theme, lets install it 694 $api = themes_api('theme_information', array('slug' => $theme_info->get('Template'), 'fields' => array('sections' => false, 'tags' => false) ) ); //Save on a bit of bandwidth. 695 696 if ( ! $api || is_wp_error($api) ) { 697 $this->skin->feedback( 'parent_theme_not_found', $theme_info->get('Template') ); 698 // Don't show activate or preview actions after install 699 add_filter('install_theme_complete_actions', array(&$this, 'hide_activate_preview_actions') ); 700 return $install_result; 701 } 702 703 // Backup required data we're going to override: 704 $child_api = $this->skin->api; 705 $child_success_message = $this->strings['process_success']; 706 707 // Override them 708 $this->skin->api = $api; 709 $this->strings['process_success_specific'] = $this->strings['parent_theme_install_success'];//, $api->name, $api->version); 710 711 $this->skin->feedback('parent_theme_prepare_install', $api->name, $api->version); 712 713 add_filter('install_theme_complete_actions', '__return_false', 999); // Don't show any actions after installing the theme. 714 715 // Install the parent theme 716 $parent_result = $this->run( array( 717 'package' => $api->download_link, 718 'destination' => WP_CONTENT_DIR . '/themes', 719 'clear_destination' => false, //Do not overwrite files. 720 'clear_working' => true 721 ) ); 722 723 if ( is_wp_error($parent_result) ) 724 add_filter('install_theme_complete_actions', array(&$this, 'hide_activate_preview_actions') ); 725 726 // Start cleaning up after the parents installation 727 remove_filter('install_theme_complete_actions', '__return_false', 999); 728 729 // Reset child's result and data 730 $this->result = $child_result; 731 $this->skin->api = $child_api; 732 $this->strings['process_success'] = $child_success_message; 733 734 return $install_result; 735 } 736 737 function hide_activate_preview_actions($actions) { 738 unset($actions['activate'], $actions['preview']); 739 return $actions; 740 } 741 742 function install($package) { 743 744 $this->init(); 745 $this->install_strings(); 746 747 add_filter('upgrader_source_selection', array(&$this, 'check_package') ); 748 add_filter('upgrader_post_install', array(&$this, 'check_parent_theme_filter'), 10, 3); 749 750 $options = array( 751 'package' => $package, 752 'destination' => WP_CONTENT_DIR . '/themes', 753 'clear_destination' => false, //Do not overwrite files. 754 'clear_working' => true 755 ); 756 757 $this->run($options); 758 759 remove_filter('upgrader_source_selection', array(&$this, 'check_package') ); 760 remove_filter('upgrader_post_install', array(&$this, 'check_parent_theme_filter'), 10, 3); 761 762 if ( ! $this->result || is_wp_error($this->result) ) 763 return $this->result; 764 765 // Force refresh of theme update information 766 delete_site_transient('update_themes'); 767 foreach ( wp_get_themes() as $theme ) 768 $theme->cache_delete(); 769 770 return true; 771 } 772 773 function upgrade($theme) { 774 775 $this->init(); 776 $this->upgrade_strings(); 777 778 // Is an update available? 779 $current = get_site_transient( 'update_themes' ); 780 if ( !isset( $current->response[ $theme ] ) ) { 781 $this->skin->before(); 782 $this->skin->set_result(false); 783 $this->skin->error('up_to_date'); 784 $this->skin->after(); 785 return false; 786 } 787 788 $r = $current->response[ $theme ]; 789 790 add_filter('upgrader_pre_install', array(&$this, 'current_before'), 10, 2); 791 add_filter('upgrader_post_install', array(&$this, 'current_after'), 10, 2); 792 add_filter('upgrader_clear_destination', array(&$this, 'delete_old_theme'), 10, 4); 793 794 $options = array( 795 'package' => $r['package'], 796 'destination' => WP_CONTENT_DIR . '/themes', 797 'clear_destination' => true, 798 'clear_working' => true, 799 'hook_extra' => array( 800 'theme' => $theme 801 ) 802 ); 803 804 $this->run($options); 805 806 remove_filter('upgrader_pre_install', array(&$this, 'current_before'), 10, 2); 807 remove_filter('upgrader_post_install', array(&$this, 'current_after'), 10, 2); 808 remove_filter('upgrader_clear_destination', array(&$this, 'delete_old_theme'), 10, 4); 809 810 if ( ! $this->result || is_wp_error($this->result) ) 811 return $this->result; 812 813 // Force refresh of theme update information 814 delete_site_transient('update_themes'); 815 foreach ( wp_get_themes() as $theme ) 816 $theme->cache_delete(); 817 818 return true; 819 } 820 821 function bulk_upgrade($themes) { 822 823 $this->init(); 824 $this->bulk = true; 825 $this->upgrade_strings(); 826 827 $current = get_site_transient( 'update_themes' ); 828 829 add_filter('upgrader_pre_install', array(&$this, 'current_before'), 10, 2); 830 add_filter('upgrader_post_install', array(&$this, 'current_after'), 10, 2); 831 add_filter('upgrader_clear_destination', array(&$this, 'delete_old_theme'), 10, 4); 832 833 $this->skin->header(); 834 835 // Connect to the Filesystem first. 836 $res = $this->fs_connect( array(WP_CONTENT_DIR) ); 837 if ( ! $res ) { 838 $this->skin->footer(); 839 return false; 840 } 841 842 $this->skin->bulk_header(); 843 844 // Only start maintenance mode if running in Multisite OR the theme is in use 845 $maintenance = is_multisite(); // @TODO: This should only kick in for individual sites if at all possible. 846 foreach ( $themes as $theme ) 847 $maintenance = $maintenance || $theme == get_stylesheet() || $theme == get_template(); 848 if ( $maintenance ) 849 $this->maintenance_mode(true); 850 851 $results = array(); 852 853 $this->update_count = count($themes); 854 $this->update_current = 0; 855 foreach ( $themes as $theme ) { 856 $this->update_current++; 857 858 if ( !isset( $current->response[ $theme ] ) ) { 859 $this->skin->set_result(false); 860 $this->skin->before(); 861 $this->skin->error('up_to_date'); 862 $this->skin->after(); 863 $results[$theme] = false; 864 continue; 865 } 866 867 $this->skin->theme_info = $this->theme_info($theme); 868 869 // Get the URL to the zip file 870 $r = $current->response[ $theme ]; 871 872 $options = array( 873 'package' => $r['package'], 874 'destination' => WP_CONTENT_DIR . '/themes', 875 'clear_destination' => true, 876 'clear_working' => true, 877 'hook_extra' => array( 878 'theme' => $theme 879 ) 880 ); 881 882 $result = $this->run($options); 883 884 $results[$theme] = $this->result; 885 886 // Prevent credentials auth screen from displaying multiple times 887 if ( false === $result ) 888 break; 889 } //end foreach $plugins 890 891 $this->maintenance_mode(false); 892 893 $this->skin->bulk_footer(); 894 895 $this->skin->footer(); 896 897 // Cleanup our hooks, in case something else does a upgrade on this connection. 898 remove_filter('upgrader_pre_install', array(&$this, 'current_before'), 10, 2); 899 remove_filter('upgrader_post_install', array(&$this, 'current_after'), 10, 2); 900 remove_filter('upgrader_clear_destination', array(&$this, 'delete_old_theme'), 10, 4); 901 902 // Force refresh of theme update information 903 delete_site_transient('update_themes'); 904 foreach ( wp_get_themes() as $theme ) 905 $theme->cache_delete(); 906 907 return $results; 908 } 909 910 function check_package($source) { 911 global $wp_filesystem; 912 913 if ( is_wp_error($source) ) 914 return $source; 915 916 // Check the folder contains a valid theme 917 $working_directory = str_replace( $wp_filesystem->wp_content_dir(), trailingslashit(WP_CONTENT_DIR), $source); 918 if ( ! is_dir($working_directory) ) // Sanity check, if the above fails, lets not prevent installation. 919 return $source; 920 921 // A proper archive should have a style.css file in the single subdirectory 922 if ( ! file_exists( $working_directory . 'style.css' ) ) 923 return new WP_Error( 'incompatible_archive', $this->strings['incompatible_archive'], __('The theme is missing the <code>style.css</code> stylesheet.') ); 924 925 $info = get_file_data( $working_directory . 'style.css', array( 'Name' => 'Theme Name', 'Template' => 'Template' ) ); 926 927 if ( empty( $info['Name'] ) ) 928 return new WP_Error( 'incompatible_archive', $this->strings['incompatible_archive'], __("The <code>style.css</code> stylesheet doesn't contain a valid theme header.") ); 929 930 // If it's not a child theme, it must have at least an index.php to be legit. 931 if ( empty( $info['Template'] ) && ! file_exists( $working_directory . 'index.php' ) ) 932 return new WP_Error( 'incompatible_archive', $this->strings['incompatible_archive'], __('The theme is missing the <code>index.php</code> file.') ); 933 934 return $source; 935 } 936 937 function current_before($return, $theme) { 938 939 if ( is_wp_error($return) ) 940 return $return; 941 942 $theme = isset($theme['theme']) ? $theme['theme'] : ''; 943 944 if ( $theme != get_stylesheet() ) //If not current 945 return $return; 946 //Change to maintenance mode now. 947 if ( ! $this->bulk ) 948 $this->maintenance_mode(true); 949 950 return $return; 951 } 952 953 function current_after($return, $theme) { 954 if ( is_wp_error($return) ) 955 return $return; 956 957 $theme = isset($theme['theme']) ? $theme['theme'] : ''; 958 959 if ( $theme != get_stylesheet() ) // If not current 960 return $return; 961 962 // Ensure stylesheet name hasnt changed after the upgrade: 963 // @TODO: Note, This doesn't handle the Template changing, or the Template name changing. 964 if ( $theme == get_stylesheet() && $theme != $this->result['destination_name'] ) { 965 $theme_info = $this->theme_info(); 966 $stylesheet = $this->result['destination_name']; 967 $template = $theme_info->get_template(); 968 switch_theme($template, $stylesheet, true); 969 } 970 971 //Time to remove maintenance mode 972 if ( ! $this->bulk ) 973 $this->maintenance_mode(false); 974 return $return; 975 } 976 977 function delete_old_theme($removed, $local_destination, $remote_destination, $theme) { 978 global $wp_filesystem; 979 980 $theme = isset($theme['theme']) ? $theme['theme'] : ''; 981 982 if ( is_wp_error($removed) || empty($theme) ) 983 return $removed; //Pass errors through. 984 985 $themes_dir = $wp_filesystem->wp_themes_dir(); 986 if ( $wp_filesystem->exists( trailingslashit($themes_dir) . $theme ) ) 987 if ( ! $wp_filesystem->delete( trailingslashit($themes_dir) . $theme, true ) ) 988 return false; 989 return true; 990 } 991 992 function theme_info($theme = null) { 993 994 if ( empty($theme) ) { 995 if ( !empty($this->result['destination_name']) ) 996 $theme = $this->result['destination_name']; 997 else 998 return false; 999 } 1000 return wp_get_theme( $theme, WP_CONTENT_DIR . '/themes/' ); 1001 } 1002 1003 } 1004 1005 /** 1006 * Core Upgrader class for WordPress. It allows for WordPress to upgrade itself in combination with the wp-admin/includes/update-core.php file 1007 * 1008 * @TODO More Detailed docs, for methods as well. 1009 * 1010 * @package WordPress 1011 * @subpackage Upgrader 1012 * @since 2.8.0 1013 */ 1014 class Core_Upgrader extends WP_Upgrader { 1015 1016 function upgrade_strings() { 1017 $this->strings['up_to_date'] = __('WordPress is at the latest version.'); 1018 $this->strings['no_package'] = __('Update package not available.'); 1019 $this->strings['downloading_package'] = __('Downloading update from <span class="code">%s</span>…'); 1020 $this->strings['unpack_package'] = __('Unpacking the update…'); 1021 $this->strings['copy_failed'] = __('Could not copy files.'); 1022 $this->strings['copy_failed_space'] = __('Could not copy files. You may have run out of disk space.' ); 1023 } 1024 1025 function upgrade($current) { 1026 global $wp_filesystem, $wp_version; 1027 1028 $this->init(); 1029 $this->upgrade_strings(); 1030 1031 if ( !empty($feedback) ) 1032 add_filter('update_feedback', $feedback); 1033 1034 // Is an update available? 1035 if ( !isset( $current->response ) || $current->response == 'latest' ) 1036 return new WP_Error('up_to_date', $this->strings['up_to_date']); 1037 1038 $res = $this->fs_connect( array(ABSPATH, WP_CONTENT_DIR) ); 1039 if ( is_wp_error($res) ) 1040 return $res; 1041 1042 $wp_dir = trailingslashit($wp_filesystem->abspath()); 1043 1044 // If partial update is returned from the API, use that, unless we're doing a reinstall. 1045 // If we cross the new_bundled version number, then use the new_bundled zip. 1046 // Don't though if the constant is set to skip bundled items. 1047 // If the API returns a no_content zip, go with it. Finally, default to the full zip. 1048 if ( $current->packages->partial && 'reinstall' != $current->response && $wp_version == $current->partial_version ) 1049 $to_download = 'partial'; 1050 elseif ( $current->packages->new_bundled && version_compare( $wp_version, $current->new_bundled, '<' ) 1051 && ( ! defined( 'CORE_UPGRADE_SKIP_NEW_BUNDLED' ) || ! CORE_UPGRADE_SKIP_NEW_BUNDLED ) ) 1052 $to_download = 'new_bundled'; 1053 elseif ( $current->packages->no_content ) 1054 $to_download = 'no_content'; 1055 else 1056 $to_download = 'full'; 1057 1058 $download = $this->download_package( $current->packages->$to_download ); 1059 if ( is_wp_error($download) ) 1060 return $download; 1061 1062 $working_dir = $this->unpack_package( $download ); 1063 if ( is_wp_error($working_dir) ) 1064 return $working_dir; 1065 1066 // Copy update-core.php from the new version into place. 1067 if ( !$wp_filesystem->copy($working_dir . '/wordpress/wp-admin/includes/update-core.php', $wp_dir . 'wp-admin/includes/update-core.php', true) ) { 1068 $wp_filesystem->delete($working_dir, true); 1069 return new WP_Error('copy_failed', $this->strings['copy_failed']); 1070 } 1071 $wp_filesystem->chmod($wp_dir . 'wp-admin/includes/update-core.php', FS_CHMOD_FILE); 1072 1073 require (ABSPATH . 'wp-admin/includes/update-core.php'); 1074 1075 if ( ! function_exists( 'update_core' ) ) 1076 return new WP_Error( 'copy_failed_space', $this->strings['copy_failed_space'] ); 1077 1078 return update_core($working_dir, $wp_dir); 1079 } 1080 1081 } 1082 1083 /** 1084 * Generic Skin for the WordPress Upgrader classes. This skin is designed to be extended for specific purposes. 1085 * 1086 * @TODO More Detailed docs, for methods as well. 1087 * 1088 * @package WordPress 1089 * @subpackage Upgrader 1090 * @since 2.8.0 1091 */ 1092 class WP_Upgrader_Skin { 1093 1094 var $upgrader; 1095 var $done_header = false; 1096 var $result = false; 1097 1098 function __construct($args = array()) { 1099 $defaults = array( 'url' => '', 'nonce' => '', 'title' => '', 'context' => false ); 1100 $this->options = wp_parse_args($args, $defaults); 1101 } 1102 1103 function set_upgrader(&$upgrader) { 1104 if ( is_object($upgrader) ) 1105 $this->upgrader =& $upgrader; 1106 $this->add_strings(); 1107 } 1108 1109 function add_strings() { 1110 } 1111 1112 function set_result($result) { 1113 $this->result = $result; 1114 } 1115 1116 function request_filesystem_credentials($error = false) { 1117 $url = $this->options['url']; 1118 $context = $this->options['context']; 1119 if ( !empty($this->options['nonce']) ) 1120 $url = wp_nonce_url($url, $this->options['nonce']); 1121 return request_filesystem_credentials($url, '', $error, $context); //Possible to bring inline, Leaving as is for now. 1122 } 1123 1124 function header() { 1125 if ( $this->done_header ) 1126 return; 1127 $this->done_header = true; 1128 echo '<div class="wrap">'; 1129 echo screen_icon(); 1130 echo '<h2>' . $this->options['title'] . '</h2>'; 1131 } 1132 function footer() { 1133 echo '</div>'; 1134 } 1135 1136 function error($errors) { 1137 if ( ! $this->done_header ) 1138 $this->header(); 1139 if ( is_string($errors) ) { 1140 $this->feedback($errors); 1141 } elseif ( is_wp_error($errors) && $errors->get_error_code() ) { 1142 foreach ( $errors->get_error_messages() as $message ) { 1143 if ( $errors->get_error_data() ) 1144 $this->feedback($message . ' ' . $errors->get_error_data() ); 1145 else 1146 $this->feedback($message); 1147 } 1148 } 1149 } 1150 1151 function feedback($string) { 1152 if ( isset( $this->upgrader->strings[$string] ) ) 1153 $string = $this->upgrader->strings[$string]; 1154 1155 if ( strpos($string, '%') !== false ) { 1156 $args = func_get_args(); 1157 $args = array_splice($args, 1); 1158 if ( !empty($args) ) 1159 $string = vsprintf($string, $args); 1160 } 1161 if ( empty($string) ) 1162 return; 1163 show_message($string); 1164 } 1165 function before() {} 1166 function after() {} 1167 1168 } 1169 1170 /** 1171 * Plugin Upgrader Skin for WordPress Plugin Upgrades. 1172 * 1173 * @TODO More Detailed docs, for methods as well. 1174 * 1175 * @package WordPress 1176 * @subpackage Upgrader 1177 * @since 2.8.0 1178 */ 1179 class Plugin_Upgrader_Skin extends WP_Upgrader_Skin { 1180 var $plugin = ''; 1181 var $plugin_active = false; 1182 var $plugin_network_active = false; 1183 1184 function __construct($args = array()) { 1185 $defaults = array( 'url' => '', 'plugin' => '', 'nonce' => '', 'title' => __('Update Plugin') ); 1186 $args = wp_parse_args($args, $defaults); 1187 1188 $this->plugin = $args['plugin']; 1189 1190 $this->plugin_active = is_plugin_active( $this->plugin ); 1191 $this->plugin_network_active = is_plugin_active_for_network( $this->plugin ); 1192 1193 parent::__construct($args); 1194 } 1195 1196 function after() { 1197 $this->plugin = $this->upgrader->plugin_info(); 1198 if ( !empty($this->plugin) && !is_wp_error($this->result) && $this->plugin_active ){ 1199 echo '<iframe style="border:0;overflow:hidden" width="100%" height="170px" src="' . wp_nonce_url('update.php?action=activate-plugin&networkwide=' . $this->plugin_network_active . '&plugin=' . $this->plugin, 'activate-plugin_' . $this->plugin) .'"></iframe>'; 1200 } 1201 1202 $update_actions = array( 1203 'activate_plugin' => '<a href="' . wp_nonce_url('plugins.php?action=activate&plugin=' . $this->plugin, 'activate-plugin_' . $this->plugin) . '" title="' . esc_attr__('Activate this plugin') . '" target="_parent">' . __('Activate Plugin') . '</a>', 1204 'plugins_page' => '<a href="' . self_admin_url('plugins.php') . '" title="' . esc_attr__('Go to plugins page') . '" target="_parent">' . __('Return to Plugins page') . '</a>' 1205 ); 1206 if ( $this->plugin_active ) 1207 unset( $update_actions['activate_plugin'] ); 1208 if ( ! $this->result || is_wp_error($this->result) ) 1209 unset( $update_actions['activate_plugin'] ); 1210 1211 $update_actions = apply_filters('update_plugin_complete_actions', $update_actions, $this->plugin); 1212 if ( ! empty($update_actions) ) 1213 $this->feedback(implode(' | ', (array)$update_actions)); 1214 } 1215 1216 function before() { 1217 if ( $this->upgrader->show_before ) { 1218 echo $this->upgrader->show_before; 1219 $this->upgrader->show_before = ''; 1220 } 1221 } 1222 } 1223 1224 /** 1225 * Plugin Upgrader Skin for WordPress Plugin Upgrades. 1226 * 1227 * @package WordPress 1228 * @subpackage Upgrader 1229 * @since 3.0.0 1230 */ 1231 class Bulk_Upgrader_Skin extends WP_Upgrader_Skin { 1232 var $in_loop = false; 1233 var $error = false; 1234 1235 function __construct($args = array()) { 1236 $defaults = array( 'url' => '', 'nonce' => '' ); 1237 $args = wp_parse_args($args, $defaults); 1238 1239 parent::__construct($args); 1240 } 1241 1242 function add_strings() { 1243 $this->upgrader->strings['skin_upgrade_start'] = __('The update process is starting. This process may take a while on some hosts, so please be patient.'); 1244 $this->upgrader->strings['skin_update_failed_error'] = __('An error occurred while updating %1$s: <strong>%2$s</strong>.'); 1245 $this->upgrader->strings['skin_update_failed'] = __('The update of %1$s failed.'); 1246 $this->upgrader->strings['skin_update_successful'] = __('%1$s updated successfully.').' <a onclick="%2$s" href="#" class="hide-if-no-js"><span>'.__('Show Details').'</span><span class="hidden">'.__('Hide Details').'</span>.</a>'; 1247 $this->upgrader->strings['skin_upgrade_end'] = __('All updates have been completed.'); 1248 } 1249 1250 function feedback($string) { 1251 if ( isset( $this->upgrader->strings[$string] ) ) 1252 $string = $this->upgrader->strings[$string]; 1253 1254 if ( strpos($string, '%') !== false ) { 1255 $args = func_get_args(); 1256 $args = array_splice($args, 1); 1257 if ( !empty($args) ) 1258 $string = vsprintf($string, $args); 1259 } 1260 if ( empty($string) ) 1261 return; 1262 if ( $this->in_loop ) 1263 echo "$string<br />\n"; 1264 else 1265 echo "<p>$string</p>\n"; 1266 } 1267 1268 function header() { 1269 // Nothing, This will be displayed within a iframe. 1270 } 1271 1272 function footer() { 1273 // Nothing, This will be displayed within a iframe. 1274 } 1275 function error($error) { 1276 if ( is_string($error) && isset( $this->upgrader->strings[$error] ) ) 1277 $this->error = $this->upgrader->strings[$error]; 1278 1279 if ( is_wp_error($error) ) { 1280 foreach ( $error->get_error_messages() as $emessage ) { 1281 if ( $error->get_error_data() ) 1282 $messages[] = $emessage . ' ' . $error->get_error_data(); 1283 else 1284 $messages[] = $emessage; 1285 } 1286 $this->error = implode(', ', $messages); 1287 } 1288 echo '<script type="text/javascript">jQuery(\'.waiting-' . esc_js($this->upgrader->update_current) . '\').hide();</script>'; 1289 } 1290 1291 function bulk_header() { 1292 $this->feedback('skin_upgrade_start'); 1293 } 1294 1295 function bulk_footer() { 1296 $this->feedback('skin_upgrade_end'); 1297 } 1298 1299 function before($title = '') { 1300 $this->in_loop = true; 1301 printf( '<h4>' . $this->upgrader->strings['skin_before_update_header'] . ' <img alt="" src="' . admin_url( 'images/wpspin_light.gif' ) . '" class="hidden waiting-' . $this->upgrader->update_current . '" style="vertical-align:middle;" /></h4>', $title, $this->upgrader->update_current, $this->upgrader->update_count); 1302 echo '<script type="text/javascript">jQuery(\'.waiting-' . esc_js($this->upgrader->update_current) . '\').show();</script>'; 1303 echo '<div class="update-messages hide-if-js" id="progress-' . esc_attr($this->upgrader->update_current) . '"><p>'; 1304 $this->flush_output(); 1305 } 1306 1307 function after($title = '') { 1308 echo '</p></div>'; 1309 if ( $this->error || ! $this->result ) { 1310 if ( $this->error ) 1311 echo '<div class="error"><p>' . sprintf($this->upgrader->strings['skin_update_failed_error'], $title, $this->error) . '</p></div>'; 1312 else 1313 echo '<div class="error"><p>' . sprintf($this->upgrader->strings['skin_update_failed'], $title) . '</p></div>'; 1314 1315 echo '<script type="text/javascript">jQuery(\'#progress-' . esc_js($this->upgrader->update_current) . '\').show();</script>'; 1316 } 1317 if ( !empty($this->result) && !is_wp_error($this->result) ) { 1318 echo '<div class="updated"><p>' . sprintf($this->upgrader->strings['skin_update_successful'], $title, 'jQuery(\'#progress-' . esc_js($this->upgrader->update_current) . '\').toggle();jQuery(\'span\', this).toggle(); return false;') . '</p></div>'; 1319 echo '<script type="text/javascript">jQuery(\'.waiting-' . esc_js($this->upgrader->update_current) . '\').hide();</script>'; 1320 } 1321 1322 $this->reset(); 1323 $this->flush_output(); 1324 } 1325 1326 function reset() { 1327 $this->in_loop = false; 1328 $this->error = false; 1329 } 1330 1331 function flush_output() { 1332 wp_ob_end_flush_all(); 1333 flush(); 1334 } 1335 } 1336 1337 class Bulk_Plugin_Upgrader_Skin extends Bulk_Upgrader_Skin { 1338 var $plugin_info = array(); // Plugin_Upgrader::bulk() will fill this in. 1339 1340 function __construct($args = array()) { 1341 parent::__construct($args); 1342 } 1343 1344 function add_strings() { 1345 parent::add_strings(); 1346 $this->upgrader->strings['skin_before_update_header'] = __('Updating Plugin %1$s (%2$d/%3$d)'); 1347 } 1348 1349 function before() { 1350 parent::before($this->plugin_info['Title']); 1351 } 1352 1353 function after() { 1354 parent::after($this->plugin_info['Title']); 1355 } 1356 function bulk_footer() { 1357 parent::bulk_footer(); 1358 $update_actions = array( 1359 'plugins_page' => '<a href="' . self_admin_url('plugins.php') . '" title="' . esc_attr__('Go to plugins page') . '" target="_parent">' . __('Return to Plugins page') . '</a>', 1360 'updates_page' => '<a href="' . self_admin_url('update-core.php') . '" title="' . esc_attr__('Go to WordPress Updates page') . '" target="_parent">' . __('Return to WordPress Updates') . '</a>' 1361 ); 1362 1363 $update_actions = apply_filters('update_bulk_plugins_complete_actions', $update_actions, $this->plugin_info); 1364 if ( ! empty($update_actions) ) 1365 $this->feedback(implode(' | ', (array)$update_actions)); 1366 } 1367 } 1368 1369 class Bulk_Theme_Upgrader_Skin extends Bulk_Upgrader_Skin { 1370 var $theme_info = array(); // Theme_Upgrader::bulk() will fill this in. 1371 1372 function __construct($args = array()) { 1373 parent::__construct($args); 1374 } 1375 1376 function add_strings() { 1377 parent::add_strings(); 1378 $this->upgrader->strings['skin_before_update_header'] = __('Updating Theme %1$s (%2$d/%3$d)'); 1379 } 1380 1381 function before() { 1382 parent::before( $this->theme_info->display('Name') ); 1383 } 1384 1385 function after() { 1386 parent::after( $this->theme_info->display('Name') ); 1387 } 1388 1389 function bulk_footer() { 1390 parent::bulk_footer(); 1391 $update_actions = array( 1392 'themes_page' => '<a href="' . self_admin_url('themes.php') . '" title="' . esc_attr__('Go to themes page') . '" target="_parent">' . __('Return to Themes page') . '</a>', 1393 'updates_page' => '<a href="' . self_admin_url('update-core.php') . '" title="' . esc_attr__('Go to WordPress Updates page') . '" target="_parent">' . __('Return to WordPress Updates') . '</a>' 1394 ); 1395 1396 $update_actions = apply_filters('update_bulk_theme_complete_actions', $update_actions, $this->theme_info ); 1397 if ( ! empty($update_actions) ) 1398 $this->feedback(implode(' | ', (array)$update_actions)); 1399 } 1400 } 1401 1402 /** 1403 * Plugin Installer Skin for WordPress Plugin Installer. 1404 * 1405 * @TODO More Detailed docs, for methods as well. 1406 * 1407 * @package WordPress 1408 * @subpackage Upgrader 1409 * @since 2.8.0 1410 */ 1411 class Plugin_Installer_Skin extends WP_Upgrader_Skin { 1412 var $api; 1413 var $type; 1414 1415 function __construct($args = array()) { 1416 $defaults = array( 'type' => 'web', 'url' => '', 'plugin' => '', 'nonce' => '', 'title' => '' ); 1417 $args = wp_parse_args($args, $defaults); 1418 1419 $this->type = $args['type']; 1420 $this->api = isset($args['api']) ? $args['api'] : array(); 1421 1422 parent::__construct($args); 1423 } 1424 1425 function before() { 1426 if ( !empty($this->api) ) 1427 $this->upgrader->strings['process_success'] = sprintf( __('Successfully installed the plugin <strong>%s %s</strong>.'), $this->api->name, $this->api->version); 1428 } 1429 1430 function after() { 1431 1432 $plugin_file = $this->upgrader->plugin_info(); 1433 1434 $install_actions = array(); 1435 1436 $from = isset($_GET['from']) ? stripslashes($_GET['from']) : 'plugins'; 1437 1438 if ( 'import' == $from ) 1439 $install_actions['activate_plugin'] = '<a href="' . wp_nonce_url('plugins.php?action=activate&from=import&plugin=' . $plugin_file, 'activate-plugin_' . $plugin_file) . '" title="' . esc_attr__('Activate this plugin') . '" target="_parent">' . __('Activate Plugin & Run Importer') . '</a>'; 1440 else 1441 $install_actions['activate_plugin'] = '<a href="' . wp_nonce_url('plugins.php?action=activate&plugin=' . $plugin_file, 'activate-plugin_' . $plugin_file) . '" title="' . esc_attr__('Activate this plugin') . '" target="_parent">' . __('Activate Plugin') . '</a>'; 1442 1443 if ( is_multisite() && current_user_can( 'manage_network_plugins' ) ) { 1444 $install_actions['network_activate'] = '<a href="' . wp_nonce_url('plugins.php?action=activate&networkwide=1&plugin=' . $plugin_file, 'activate-plugin_' . $plugin_file) . '" title="' . esc_attr__('Activate this plugin for all sites in this network') . '" target="_parent">' . __('Network Activate') . '</a>'; 1445 unset( $install_actions['activate_plugin'] ); 1446 } 1447 1448 if ( 'import' == $from ) 1449 $install_actions['importers_page'] = '<a href="' . admin_url('import.php') . '" title="' . esc_attr__('Return to Importers') . '" target="_parent">' . __('Return to Importers') . '</a>'; 1450 else if ( $this->type == 'web' ) 1451 $install_actions['plugins_page'] = '<a href="' . self_admin_url('plugin-install.php') . '" title="' . esc_attr__('Return to Plugin Installer') . '" target="_parent">' . __('Return to Plugin Installer') . '</a>'; 1452 else 1453 $install_actions['plugins_page'] = '<a href="' . self_admin_url('plugins.php') . '" title="' . esc_attr__('Return to Plugins page') . '" target="_parent">' . __('Return to Plugins page') . '</a>'; 1454 1455 if ( ! $this->result || is_wp_error($this->result) ) { 1456 unset( $install_actions['activate_plugin'] ); 1457 unset( $install_actions['network_activate'] ); 1458 } 1459 $install_actions = apply_filters('install_plugin_complete_actions', $install_actions, $this->api, $plugin_file); 1460 if ( ! empty($install_actions) ) 1461 $this->feedback(implode(' | ', (array)$install_actions)); 1462 } 1463 } 1464 1465 /** 1466 * Theme Installer Skin for the WordPress Theme Installer. 1467 * 1468 * @TODO More Detailed docs, for methods as well. 1469 * 1470 * @package WordPress 1471 * @subpackage Upgrader 1472 * @since 2.8.0 1473 */ 1474 class Theme_Installer_Skin extends WP_Upgrader_Skin { 1475 var $api; 1476 var $type; 1477 1478 function __construct($args = array()) { 1479 $defaults = array( 'type' => 'web', 'url' => '', 'theme' => '', 'nonce' => '', 'title' => '' ); 1480 $args = wp_parse_args($args, $defaults); 1481 1482 $this->type = $args['type']; 1483 $this->api = isset($args['api']) ? $args['api'] : array(); 1484 1485 parent::__construct($args); 1486 } 1487 1488 function before() { 1489 if ( !empty($this->api) ) 1490 $this->upgrader->strings['process_success'] = sprintf( $this->upgrader->strings['process_success_specific'], $this->api->name, $this->api->version); 1491 } 1492 1493 function after() { 1494 if ( empty($this->upgrader->result['destination_name']) ) 1495 return; 1496 1497 $theme_info = $this->upgrader->theme_info(); 1498 if ( empty( $theme_info ) ) 1499 return; 1500 1501 $name = $theme_info->display('Name'); 1502 $stylesheet = $this->upgrader->result['destination_name']; 1503 $template = $theme_info->get_template(); 1504 1505 $preview_link = add_query_arg( array( 1506 'preview' => 1, 1507 'template' => $template, 1508 'stylesheet' => $stylesheet, 1509 ), trailingslashit( get_home_url() ) ); 1510 1511 $activate_link = add_query_arg( array( 1512 'action' => 'activate', 1513 'template' => $template, 1514 'stylesheet' => $stylesheet, 1515 ), admin_url('themes.php') ); 1516 $activate_link = wp_nonce_url( $activate_link, 'switch-theme_' . $template ); 1517 1518 $install_actions = array(); 1519 $install_actions['preview'] = '<a href="' . esc_url( $preview_link ) . '" class="hide-if-customize" title="' . esc_attr(sprintf(__('Preview “%s”'), $name ) ) . '">' . __('Preview') . '</a>'; 1520 $install_actions['preview'] .= '<a href="' . wp_customize_url( $stylesheet ) . '" class="hide-if-no-customize load-customize">' . __('Customize') . '</a>'; 1521 $install_actions['activate'] = '<a href="' . esc_url( $activate_link ) . '" class="activatelink" title="' . esc_attr( sprintf( __('Activate “%s”'), $name ) ) . '">' . __('Activate') . '</a>'; 1522 1523 if ( is_network_admin() && current_user_can( 'manage_network_themes' ) ) 1524 $install_actions['network_enable'] = '<a href="' . esc_url( wp_nonce_url( 'themes.php?action=enable&theme=' . $template, 'enable-theme_' . $template ) ) . '" title="' . esc_attr__( 'Enable this theme for all sites in this network' ) . '" target="_parent">' . __( 'Network Enable' ) . '</a>'; 1525 1526 if ( $this->type == 'web' ) 1527 $install_actions['themes_page'] = '<a href="' . self_admin_url('theme-install.php') . '" title="' . esc_attr__('Return to Theme Installer') . '" target="_parent">' . __('Return to Theme Installer') . '</a>'; 1528 else 1529 $install_actions['themes_page'] = '<a href="' . self_admin_url('themes.php') . '" title="' . esc_attr__('Themes page') . '" target="_parent">' . __('Return to Themes page') . '</a>'; 1530 1531 if ( ! $this->result || is_wp_error($this->result) || is_network_admin() ) 1532 unset( $install_actions['activate'], $install_actions['preview'] ); 1533 1534 $install_actions = apply_filters('install_theme_complete_actions', $install_actions, $this->api, $stylesheet, $theme_info); 1535 if ( ! empty($install_actions) ) 1536 $this->feedback(implode(' | ', (array)$install_actions)); 1537 } 1538 } 1539 1540 /** 1541 * Theme Upgrader Skin for WordPress Theme Upgrades. 1542 * 1543 * @TODO More Detailed docs, for methods as well. 1544 * 1545 * @package WordPress 1546 * @subpackage Upgrader 1547 * @since 2.8.0 1548 */ 1549 class Theme_Upgrader_Skin extends WP_Upgrader_Skin { 1550 var $theme = ''; 1551 1552 function __construct($args = array()) { 1553 $defaults = array( 'url' => '', 'theme' => '', 'nonce' => '', 'title' => __('Update Theme') ); 1554 $args = wp_parse_args($args, $defaults); 1555 1556 $this->theme = $args['theme']; 1557 1558 parent::__construct($args); 1559 } 1560 1561 function after() { 1562 1563 $update_actions = array(); 1564 if ( ! empty( $this->upgrader->result['destination_name'] ) && $theme_info = $this->upgrader->theme_info() ) { 1565 $name = $theme_info->display('Name'); 1566 $stylesheet = $this->upgrader->result['destination_name']; 1567 $template = $theme_info->get_template(); 1568 1569 $preview_link = add_query_arg( array( 1570 'preview' => 1, 1571 'template' => $template, 1572 'stylesheet' => $stylesheet, 1573 ), trailingslashit( get_home_url() ) ); 1574 1575 $activate_link = add_query_arg( array( 1576 'action' => 'activate', 1577 'template' => $template, 1578 'stylesheet' => $stylesheet, 1579 ), admin_url('themes.php') ); 1580 $activate_link = wp_nonce_url( $activate_link, 'switch-theme_' . $template ); 1581 1582 $update_actions['preview'] = '<a href="' . esc_url( $preview_link ) . '" class="hide-if-customize" title="' . esc_attr(sprintf(__('Preview “%s”'), $name ) ) . '">' . __('Preview') . '</a>'; 1583 $update_actions['preview'] .= '<a href="' . wp_customize_url( $stylesheet ) . '" class="hide-if-no-customize load-customize">' . __('Customize') . '</a>'; 1584 $update_actions['activate'] = '<a href="' . esc_url( $activate_link ) . '" class="activatelink" title="' . esc_attr( sprintf( __('Activate “%s”'), $name ) ) . '">' . __('Activate') . '</a>'; 1585 1586 if ( ( ! $this->result || is_wp_error( $this->result ) ) || $stylesheet == get_stylesheet() ) 1587 unset($update_actions['preview'], $update_actions['activate']); 1588 } 1589 1590 $update_actions['themes_page'] = '<a href="' . self_admin_url('themes.php') . '" title="' . esc_attr__('Return to Themes page') . '" target="_parent">' . __('Return to Themes page') . '</a>'; 1591 1592 $update_actions = apply_filters('update_theme_complete_actions', $update_actions, $this->theme); 1593 if ( ! empty($update_actions) ) 1594 $this->feedback(implode(' | ', (array)$update_actions)); 1595 } 1596 } 1597 1598 /** 1599 * Upgrade Skin helper for File uploads. This class handles the upload process and passes it as if its a local file to the Upgrade/Installer functions. 1600 * 1601 * @TODO More Detailed docs, for methods as well. 1602 * 1603 * @package WordPress 1604 * @subpackage Upgrader 1605 * @since 2.8.0 1606 */ 1607 class File_Upload_Upgrader { 1608 var $package; 1609 var $filename; 1610 var $id = 0; 1611 1612 function __construct($form, $urlholder) { 1613 1614 if ( empty($_FILES[$form]['name']) && empty($_GET[$urlholder]) ) 1615 wp_die(__('Please select a file')); 1616 1617 //Handle a newly uploaded file, Else assume its already been uploaded 1618 if ( ! empty($_FILES) ) { 1619 $overrides = array( 'test_form' => false, 'test_type' => false ); 1620 $file = wp_handle_upload( $_FILES[$form], $overrides ); 1621 1622 if ( isset( $file['error'] ) ) 1623 wp_die( $file['error'] ); 1624 1625 $this->filename = $_FILES[$form]['name']; 1626 $this->package = $file['file']; 1627 1628 // Construct the object array 1629 $object = array( 1630 'post_title' => $this->filename, 1631 'post_content' => $file['url'], 1632 'post_mime_type' => $file['type'], 1633 'guid' => $file['url'], 1634 'context' => 'upgrader', 1635 'post_status' => 'private' 1636 ); 1637 1638 // Save the data 1639 $this->id = wp_insert_attachment( $object, $file['file'] ); 1640 1641 // schedule a cleanup for 2 hours from now in case of failed install 1642 wp_schedule_single_event( time() + 7200, 'upgrader_scheduled_cleanup', array( $this->id ) ); 1643 1644 } elseif ( is_numeric( $_GET[$urlholder] ) ) { 1645 // Numeric Package = previously uploaded file, see above. 1646 $this->id = (int) $_GET[$urlholder]; 1647 $attachment = get_post( $this->id ); 1648 if ( empty($attachment) ) 1649 wp_die(__('Please select a file')); 1650 1651 $this->filename = $attachment->post_title; 1652 $this->package = get_attached_file( $attachment->ID ); 1653 } else { 1654 // Else, It's set to something, Back compat for plugins using the old (pre-3.3) File_Uploader handler. 1655 if ( ! ( ( $uploads = wp_upload_dir() ) && false === $uploads['error'] ) ) 1656 wp_die( $uploads['error'] ); 1657 1658 $this->filename = $_GET[$urlholder]; 1659 $this->package = $uploads['basedir'] . '/' . $this->filename; 1660 } 1661 } 1662 1663 function cleanup() { 1664 if ( $this->id ) 1665 wp_delete_attachment( $this->id ); 1666 1667 elseif ( file_exists( $this->package ) ) 1668 return @unlink( $this->package ); 1669 1670 return true; 1671 } 1672 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Fri May 25 03:56:23 2012 | Hosted by follow the white rabbit. |