WordPress.org

Make WordPress Core

Changeset 25421


Ignore:
Timestamp:
09/13/2013 06:18:16 AM (5 years ago)
Author:
dd32
Message:

WordPress Core Automatic Updates: Add the first slice of Automatic Upgrades, This is presently disabled, and requires a filter to enable ( 'auto_upgrade_core' ). See #22704

Location:
trunk/src
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/class-wp-upgrader-skins.php

    r25228 r25421  
    530530
    531531/**
    532  * Upgrader Skin for Background WordPress Upgrades
     532 * Upgrader Skin for Automatic WordPress Upgrades
    533533 *
    534534 * This skin is designed to be used when no output is intended, all output
     
    539539 * @since 3.7.0
    540540 */
    541 class Background_Upgrader_Skin extends WP_Upgrader_Skin {
     541class Automatic_Upgrader_Skin extends WP_Upgrader_Skin {
    542542    var $messages = array();
    543543
  • trunk/src/wp-admin/includes/class-wp-upgrader.php

    r25370 r25421  
    11381138    }
    11391139
     1140    // Determines if this WordPress Core version should update to $offered_ver or not
     1141    static function should_upgrade_to_version( $offered_ver /* x.y.z */ ) {
     1142        include ABSPATH . WPINC . '/version.php'; // $wp_version; // x.y.z
     1143
     1144        $current_branch = implode( '.', array_slice( preg_split( '/[.-]/', $wp_version  ), 0, 2 ) ); // x.y
     1145        $new_branch     = implode( '.', array_slice( preg_split( '/[.-]/', $offered_ver ), 0, 2 ) ); // x.y
     1146        $current_is_development_version = (bool) strpos( $wp_version, '-' );
     1147
     1148        // Defaults:
     1149        $upgrade_dev   = false;
     1150        $upgrade_minor = false; // @TODO: Update for release by toggling to true.
     1151        $upgrade_major = false;
     1152
     1153        // WP_AUTO_UPDATE_CORE = true (all), 'minor', false.
     1154        if ( defined( 'WP_AUTO_UPDATE_CORE' ) ) {
     1155            if ( false === WP_AUTO_UPDATE_CORE ) {
     1156                // Defaults to turned off, unless a filter allows it
     1157                $upgrade_dev = $upgrade_minor = $upgrade_major = false;
     1158            } elseif ( true === WP_AUTO_UPDATE_CORE ) {
     1159                // ALL updates for core
     1160                $upgrade_dev = $upgrade_minor = $upgrade_major = true;
     1161            } elseif ( 'minor' === WP_AUTO_UPDATE_CORE ) {
     1162                // Only minor updates for core
     1163                $upgrade_dev = $upgrade_major = false;
     1164                $upgrade_minor = true;
     1165            }
     1166        }
     1167
     1168        // 1: If we're already on that version, not much point in updating?
     1169        if ( $offered_ver == $wp_version )
     1170            return false;
     1171
     1172        // 2: If we're running a newer version, that's a nope
     1173        if ( version_compare( $wp_version, $offered_ver, '>=' ) )
     1174            return false;
     1175
     1176        // 3: 3.7-alpha-25000 -> 3.7-alpha-25678 -> 3.7-beta1 -> 3.7-beta2
     1177        if ( $current_is_development_version ) {
     1178            if ( ! apply_filters( 'allow_dev_auto_core_updates', $upgrade_dev ) )
     1179                return false;
     1180            // else fall through to minor + major branches below
     1181        }
     1182
     1183        // 4: Minor In-branch updates (3.7.0 -> 3.7.1 -> 3.7.2 -> 3.7.4)
     1184        if ( $current_branch == $new_branch )
     1185            return apply_filters( 'allow_minor_auto_core_updates', $upgrade_minor );
     1186
     1187        // 5: Major version updates (3.7.0 -> 3.8.0 -> 3.9.1)
     1188        if ( version_compare( $new_branch, $current_branch, '>' ) )
     1189            return apply_filters( 'allow_major_auto_core_updates', $upgrade_major );
     1190
     1191        // If we're not sure, we don't want it
     1192        return false;
     1193    }
     1194
    11401195}
    11411196
     
    12131268    }
    12141269}
     1270
     1271/**
     1272 * WordPress Automatic Upgrader helper class
     1273 *
     1274 * @since 3.7.0
     1275 */
     1276class WP_Automatic_Upgrader {
     1277
     1278    static $skin;
     1279
     1280    static function upgrader_disabled() {
     1281        // That's a no if you don't want files changes
     1282        if ( defined( 'DISABLE_FILE_MODS' ) && DISABLE_FILE_MODS )
     1283            return true;
     1284
     1285        // More fine grained control can be done through the WP_AUTO_UPDATE_CORE constant and filters
     1286        if ( defined( 'AUTOMATIC_UPDATER_DISABLED' ) && AUTOMATIC_UPDATER_DISABLED )
     1287            return true;
     1288
     1289        if ( defined( 'WP_INSTALLING' ) )
     1290            return true;
     1291
     1292        return apply_filters( 'auto_upgrader_disabled', false );
     1293    }
     1294
     1295    /**
     1296     * Tests to see if we should upgrade a specific item, does not test to see if we CAN update the item.
     1297     */
     1298    static function should_auto_update( $type, $item, $context ) {
     1299
     1300        if ( self::upgrader_disabled() )
     1301            return false;
     1302
     1303        // ..and also check for GIT/SVN checkouts
     1304        if ( ! apply_filters( 'auto_upgrade_ignore_checkout_status', false ) ) {
     1305            $stop_dirs = array(
     1306                ABSPATH,
     1307                untrailingslashit( $context ),
     1308            );
     1309            if ( ! file_exists( ABSPATH . '/wp-config.php' ) ) // wp-config.php up one folder in a deployment situation
     1310                $stop_dirs[] = dirname( ABSPATH );
     1311            foreach ( array_unique( $stop_dirs ) as $dir ) {
     1312                if ( file_exists( $dir . '/.svn' ) || file_exists( $dir . '/.git' ) )
     1313                    return false;
     1314            }
     1315        }
     1316
     1317        // Next up, do we actually have it enabled for this type of update?
     1318        switch ( $type ) {
     1319            case 'core':
     1320                $upgrade = Core_Upgrader::should_upgrade_to_version( $item->current );
     1321                break;
     1322            default:
     1323            case 'plugin':
     1324            case 'theme':
     1325                $upgrade = false;
     1326                break;
     1327        }
     1328
     1329        // And does the user / plugins want it?
     1330        // Plugins may filter on 'auto_upgrade_plugin', and check the 2nd param, $item, to only enable it for certain Plugins/Themes
     1331        if ( ! apply_filters( 'auto_upgrade_' . $type, $upgrade, $item ) )
     1332            return false;
     1333
     1334        // If it's a core update, are we actually compatible with it's requirements?
     1335        if ( 'core' == $type ) {
     1336            global $wpdb;
     1337
     1338            $php_compat = version_compare( phpversion(), $item->php_version, '>=' );
     1339            if ( file_exists( WP_CONTENT_DIR . '/db.php' ) && empty( $wpdb->is_mysql ) )
     1340                $mysql_compat = true;
     1341            else
     1342                $mysql_compat = version_compare( $wpdb->db_version(), $item->mysql_version, '>=' );
     1343
     1344            if ( ! $php_compat || ! $mysql_compat )
     1345                return false;
     1346        }
     1347
     1348        return true;
     1349    }
     1350
     1351    // Checks to see if WP_Filesystem is setup to allow unattended upgrades
     1352    static function can_auto_update( $context ) {
     1353        if ( ! self::$skin )
     1354            self::$skin = new Automatic_Upgrader_Skin();
     1355        return (bool) self::$skin->request_filesystem_credentials();
     1356    }
     1357
     1358    static function upgrade( $type, $item ) {
     1359
     1360        self::$skin = new Automatic_Upgrader_Skin();
     1361
     1362        switch ( $type ) {
     1363            case 'core':
     1364                // The Core upgrader doesn't use the Upgrader's skin during the actual main part of the upgrade, instead, firing a filter
     1365                add_filter( 'update_feedback', function( $message ) {
     1366                    WP_Background_Upgrader::$skin->feedback( $message );
     1367                    return $message;
     1368                } );
     1369                $upgrader = new Core_Upgrader( self::$skin );
     1370                $context  = ABSPATH;
     1371                break;
     1372            case 'plugin':
     1373                $upgrader = new Plugin_Upgrader( self::$skin );
     1374                $context  = WP_PLUGIN_DIR; // We don't support custom Plugin directories, or updates for WPMU_PLUGIN_DIR
     1375                break;
     1376            case 'theme':
     1377                $upgrader = new Theme_Upgrader( self::$skin );
     1378                $context  = get_theme_root( $item );
     1379                break;
     1380        }
     1381
     1382        // Determine if we can perform this upgrade or not
     1383        if ( ! self::should_auto_update( $type, $item, $context )  || ! self::can_auto_update( $context ) )
     1384            return false;
     1385
     1386        /*wp_mail(
     1387            get_site_option( 'admin_email' ),
     1388            __METHOD__,
     1389            "Starting an upgrade for:\n\n" . var_export( compact( 'type', 'item' ), true ) . "\n\n" . wp_debug_backtrace_summary()
     1390        );*/
     1391
     1392        // Boom, This sites about to get a whole new splash of paint!
     1393        $upgrade_result = $upgrader->upgrade( $item, array(
     1394            'clear_update_cache' => false,
     1395        ) );
     1396
     1397        // Core doesn't output this, so lets append it so we don't get confused
     1398        if ( 'core' == $type ) {
     1399            if ( is_wp_error( $upgrade_result ) ) {
     1400                self::$skin->error( __( 'Installation Failed' ), $upgrade_result );
     1401            } else {
     1402                self::$skin->feedback( __( 'WordPress updated successfully' ) );
     1403            }
     1404        }
     1405
     1406        // Clear cache's and transients
     1407        switch ( $type ) {
     1408            case 'core':
     1409                delete_site_transient( 'update_core' );
     1410                break;
     1411            case 'theme':
     1412                wp_clean_themes_cache();
     1413                break;
     1414            case 'plugin':
     1415                wp_clean_plugins_cache();
     1416                break;
     1417        }
     1418
     1419        //var_dump( compact( 'type', 'item', 'upgrader', 'upgrade_result' ) );
     1420
     1421        wp_mail(
     1422            get_site_option( 'admin_email' ),
     1423            __METHOD__,
     1424            var_export( array(
     1425                $upgrade_result,
     1426                $upgrader,
     1427                self::$skin,
     1428            ), true )
     1429        );
     1430
     1431        return $upgrade_result;
     1432    }
     1433
     1434    /**
     1435     * Kicks off a upgrade request for each item in the upgrade "queue"
     1436     */
     1437    static function perform_auto_updates() {
     1438
     1439        $lock_name = 'auto_upgrader.lock';
     1440        if ( get_site_transient( $lock_name ) ) {
     1441            // Test to see if it was set more than an hour ago, if so, cleanup.
     1442            if ( true || get_site_transient( $lock_name ) < ( time() - HOUR_IN_SECONDS ) )
     1443                delete_site_transient( $lock_name );
     1444            else // Recent lock
     1445                return;
     1446        }
     1447        // Lock upgrades for us for half an hour
     1448        if ( ! set_site_transient( $lock_name, microtime( true ), HOUR_IN_SECONDS / 2 ) )
     1449            return;
     1450
     1451        // Next, Plugins
     1452        wp_update_plugins(); // Check for Plugin updates
     1453        $plugin_updates = get_site_transient( 'update_plugins' );
     1454        if ( $plugin_updates && !empty( $plugin_updates->response ) ) {
     1455            foreach ( array_keys( $plugin_updates->response ) as $plugin ) {
     1456                self::upgrade( 'plugin', $plugin );
     1457            }
     1458            // Force refresh of plugin update information
     1459            wp_clean_plugins_cache();
     1460        }
     1461
     1462        // Next, those themes we all love
     1463        wp_update_themes();  // Check for Theme updates
     1464        $theme_updates = get_site_transient( 'update_themes' );
     1465        if ( $theme_updates && !empty( $theme_updates->response ) ) {
     1466            foreach ( array_keys( $theme_updates->response ) as $theme ) {
     1467                self::upgrade( 'theme', $theme );
     1468            }
     1469            // Force refresh of theme update information
     1470            wp_clean_themes_cache();
     1471        }
     1472
     1473        // Finally, Process any core upgrade
     1474        wp_version_check(); // Check for Core updates
     1475        $core_update = find_core_auto_update();
     1476        if ( $core_update )
     1477            self::upgrade( 'core', $core_update );
     1478
     1479        // Cleanup, These won't trigger any updates this time due to the locking transient
     1480        wp_version_check();  // check for Core updates
     1481        wp_update_themes();  // Check for Theme updates
     1482        wp_update_plugins(); // Check for Plugin updates
     1483
     1484        // TODO The core database upgrade has already cleared this transient..
     1485        delete_site_transient( $lock_name );
     1486
     1487    }
     1488
     1489}
  • trunk/src/wp-admin/includes/update.php

    r25307 r25421  
    5858}
    5959
     60/**
     61 * Gets the best available (and enabled) Auto-Update for WordPress Core.
     62 *
     63 * If there's 1.2.3 and 1.3 on offer, it'll choose 1.3 if the install allows it, else, 1.2.3
     64 *
     65 * @since 3.7.0
     66 *
     67 * @return bool|array False on failure, otherwise the core update offering.
     68 */
     69function find_core_auto_update() {
     70    $updates = get_site_transient( 'update_core' );
     71    if ( ! $updates || empty( $updates->updates ) )
     72        return false;
     73
     74    include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
     75
     76    $auto_update = false;
     77    foreach ( $updates->updates as $update ) {
     78        if ( 'autoupdate' != $update->response )
     79            continue;
     80
     81        if ( ! WP_Automatic_Upgrader::should_auto_update( 'core', $update, ABSPATH ) )
     82            continue;
     83
     84        if ( ! $auto_update || version_compare( $update->current, $auto_update->current, '>' ) )
     85            $auto_update = $update;
     86    }
     87    return $auto_update;
     88}
     89
    6090function dismiss_core_update( $update ) {
    6191    $dismissed = get_site_option( 'dismissed_update_core' );
  • trunk/src/wp-includes/update.php

    r25308 r25421  
    121121    $updates->version_checked = $wp_version;
    122122    set_site_transient( 'update_core',  $updates);
     123
     124    wp_auto_updates_maybe_queue( 'core' );
    123125}
    124126
     
    222224
    223225    set_site_transient( 'update_plugins', $new_option );
     226
     227    wp_auto_updates_maybe_queue( 'plugins' );
    224228}
    225229
     
    332336
    333337    set_site_transient( 'update_themes', $new_update );
     338
     339    wp_auto_updates_maybe_queue( 'themes' );
     340}
     341
     342/**
     343 * Queues a cron entry if a potentially upgrade is detected.
     344 *
     345 * @since 3.7.0
     346 *
     347 * @param string $type The type of update to check for, may be 'core', 'plugins', or, 'themes'.
     348 */
     349function wp_auto_updates_maybe_queue( $type = 'core' ) {
     350    include_once ABSPATH . '/wp-admin/includes/class-wp-upgrader.php';
     351    include_once ABSPATH . '/wp-admin/includes/update.php';
     352
     353    if ( WP_Automatic_Upgrader::upgrader_disabled() )
     354        return;
     355
     356    $updates_available = false;
     357    if ( 'core' == $type ) {
     358        $updates_available = (bool) find_core_auto_update();
     359    } elseif ( 'plugins' == $type ) {
     360        $plugin_updates = get_site_transient( 'update_plugins' );
     361        $updates_available = !empty( $plugin_updates->response );
     362    } elseif ( 'themes' == $type ) {
     363        $theme_updates = get_site_transient( 'update_themes' );
     364        $updates_available = empty( $theme_updates->response );
     365    }
     366
     367    if ( $updates_available && ! wp_next_scheduled( 'wp_auto_updates_execute' ) ) {
     368        // If the transient update was triggered by a user pageview, update in an hours time, else, now.
     369        $when_to_update = get_current_user_id() ? time() + HOUR_IN_SECONDS : time();
     370        $when_to_update = apply_filters( 'auto_upgrade_when_to_upgrade', $when_to_update );
     371
     372        wp_schedule_single_event( $when_to_update, 'wp_auto_updates_execute' );
     373    }
     374
     375}
     376
     377function wp_auto_updates_execute() {
     378    include_once ABSPATH . '/wp-admin/includes/admin.php';
     379    include_once ABSPATH . '/wp-admin/includes/class-wp-upgrader.php';
     380
     381    if ( WP_Automatic_Upgrader::upgrader_disabled() )
     382        return;
     383
     384    WP_Automatic_Upgrader::perform_auto_updates();
    334385}
    335386
     
    457508add_action( 'wp_update_themes', 'wp_update_themes' );
    458509
     510// Automatic Updates - Cron callback
     511add_action( 'wp_auto_updates_execute', 'wp_auto_updates_execute' );
     512
    459513add_action('init', 'wp_schedule_update_checks');
Note: See TracChangeset for help on using the changeset viewer.