Make WordPress Core

Ticket #22704: background-upgrader.2.php

File background-upgrader.2.php, 11.3 KB (added by dd32, 13 years ago)

A copy of the latest mu-plugin i was using before integrating as the patch

Line 
1<?php
2
3class WP_Background_Upgrader {
4
5 static $skin;
6
7 private function __construct() {}
8 static function init() {
9
10 // Detect updates for Core, Plugins, and, Themes
11 foreach ( array( 'update_core', 'update_plugins', 'update_themes' ) as $transient ) {
12 add_action( 'set_site_transient_' . $transient, array( 'WP_Background_Upgrader', 'queue_updates_check' ) );
13 // Uh.. Yeah, work around for #25213
14 add_action( 'set_site_transient_' . '_site_transient_' . $transient, array( 'WP_Background_Upgrader', 'queue_updates_check' ) );
15 }
16
17 // Cron Updates hook
18 add_action( 'wp_background_upgrader_process', array( 'WP_Background_Upgrader', 'perform_queued_updates' ) );
19
20 }
21
22 /**
23 * Loads the WordPress Admin environment for performing the updates.
24 * Needed because cron runs as a front-end process
25 */
26 static function load_required_admin_includes() {
27 // include ABSPATH . 'wp-admin/includes/admin.php'; // Load the whole lot of 'em
28 include ABSPATH . 'wp-admin/includes/update.php';
29 include ABSPATH . 'wp-admin/includes/plugin.php';
30 include ABSPATH . 'wp-admin/includes/plugin-install.php';
31 include ABSPATH . 'wp-admin/includes/theme.php';
32 include ABSPATH . 'wp-admin/includes/theme-install.php';
33 include ABSPATH . 'wp-admin/includes/file.php';
34 include ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
35 }
36
37 /**
38 * Finds the best auto-update available for this site.
39 * 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
40 */
41 static function find_core_auto_update() {
42 $updates = get_site_transient( 'update_core' );
43 $auto_update = false;
44 foreach ( $updates->updates as $update ) {
45 if ( 'autoupdate' != $update->response )
46 continue;
47
48 if ( ! self::should_upgrade( 'core', $update, ABSPATH ) )
49 continue;
50
51 if ( ! $auto_update || version_compare( $update->current, $auto_update->current, '>' ) )
52 $auto_update = $update;
53 }
54 return $auto_update;
55 }
56
57 static function upgrader_disabled() {
58 // That's a no if you don't want files changes
59 if ( defined( 'DISABLE_FILE_MODS' ) && DISABLE_FILE_MODS )
60 return true;
61
62 if ( defined( 'AUTOMATIC_UPDATER_DISABLED' ) && AUTOMATIC_UPDATER_DISABLED )
63 return true;
64
65 return apply_filters( 'auto_upgrader_disabled', false );
66 }
67
68 /**
69 * Tests to see if we should upgrade a specific item, does not test to see if we CAN update the item.
70 */
71 static function should_upgrade( $type, $item, $context ) {
72
73 if ( self::upgrader_disabled() )
74 return false;
75
76 // ..and also check for GIT/SVN checkouts
77 if ( ! apply_filters( 'auto_upgrade_ignore_checkout_status', false ) ) {
78 $stop_dirs = array(
79 ABSPATH,
80 untrailingslashit( $context ),
81 );
82 if ( ! file_exists( ABSPATH . '/wp-config.php' ) ) // wp-config.php up one folder in a deployment situation
83 $stop_dirs[] = dirname( ABSPATH );
84 foreach ( array_unique( $stop_dirs ) as $dir ) {
85 if ( file_exists( $dir . '/.svn' ) || file_exists( $dir . '/.git' ) )
86 return false;
87 }
88 }
89
90 // Next up, do we actually have it enabled for this type of update?
91 switch ( $type ) {
92 default: $upgrade = false; break;
93 case 'core':
94 $upgrade = self::should_upgrade_to_core_version( $item->current );
95 break;
96 case 'plugin': $upgrade = false; break;
97 case 'theme': $upgrade = false; break;
98 case 'lang': $upgrade = false; break;
99 }
100
101 // And does the user / plugins want it?
102 // Plugins may filter on 'auto_upgrade_plugin', and check the 2nd param, $item, to only enable it for certain Plugins/Themes
103 if ( ! apply_filters( 'auto_upgrade_' . $type, $upgrade, $item ) )
104 return false;
105
106 // If it's a core update, are we actually compatible with it's requirements?
107 if ( 'core' == $type ) {
108 global $wpdb;
109
110 $php_compat = version_compare( phpversion(), $item->php_version, '>=' );
111 if ( file_exists( WP_CONTENT_DIR . '/db.php' ) && empty( $wpdb->is_mysql ) )
112 $mysql_compat = true;
113 else
114 $mysql_compat = version_compare( $wpdb->db_version(), $item->mysql_version, '>=' );
115
116 if ( ! $php_compat || ! $mysql_compat )
117 return false;
118 }
119
120 return true;
121 }
122
123 // Checks to see if WP_Filesystem is setup to allow unattended upgrades
124 static function can_upgrade( $context ) {
125 if ( ! self::$skin )
126 self::$skin = new WP_Background_Upgrader_Skin();
127 return (bool) self::$skin->request_filesystem_credentials();
128 }
129
130 // Determines if this WordPress Core version should update to $offered_ver or not
131 static function should_upgrade_to_core_version( $offered_ver /* x.y.z */ ) {
132 include ABSPATH . WPINC . '/version.php'; // $wp_version; // x.y.z
133
134 $current_branch = implode( '.', array_slice( preg_split( '/[.-]/', $wp_version ), 0, 2 ) ); // x.y
135 $new_branch = implode( '.', array_slice( preg_split( '/[.-]/', $offered_ver ), 0, 2 ) ); // x.y
136 $current_is_development_version = (bool) strpos( $wp_version, '-' );
137
138 // Defaults:
139 $upgrade_dev = false;
140 $upgrade_minor = true;
141 $upgrade_major = false;
142
143 // WP_AUTO_UPDATE_CORE = true (all), 'minor', false.
144 if ( defined( 'WP_AUTO_UPDATE_CORE' ) ) {
145 if ( false === WP_AUTO_UPDATE_CORE ) {
146 // Defaults to turned off, unless a filter allows it
147 $upgrade_dev = $upgrade_minor = $upgrade_major = false;
148 } elseif ( true === WP_AUTO_UPDATE_CORE ) {
149 // ALL updates for core
150 $upgrade_dev = $upgrade_minor = $upgrade_major = true;
151 } elseif ( 'minor' === WP_AUTO_UPDATE_CORE ) {
152 // Only minor updates for core
153 $upgrade_dev = $upgrade_major = false;
154 $upgrade_minor = true;
155 }
156 }
157
158 // 1: If we're already on that version, not much point in updating?
159 if ( $offered_ver == $wp_version )
160 return false;
161
162 // 2: If we're running a newer version, that's a nope
163 if ( version_compare( $wp_version, $offered_ver, '>=' ) )
164 return false;
165
166 // 3: 3.7-alpha-25000 -> 3.7-alpha-25678 -> 3.7-beta1 -> 3.7-beta2
167 if ( $current_is_development_version ) {
168 if ( ! apply_filters( 'allow_dev_background_core_updates', $upgrade_dev ) )
169 return false;
170 // else fall through to minor + major branches below
171 }
172
173 // 4: Minor In-branch updates (3.7.0 -> 3.7.1 -> 3.7.2 -> 3.7.4)
174 if ( $current_branch == $new_branch )
175 return apply_filters( 'allow_minor_background_core_updates', $upgrade_minor );
176
177 // 5: Major version updates (3.7.0 -> 3.8.0 -> 3.9.1)
178 if ( version_compare( $new_branch, $current_branch, '>' ) )
179 return apply_filters( 'allow_major_background_core_updates', $upgrade_major );
180
181 // If we're not sure, we don't want it
182 return false;
183 }
184
185 static function upgrade( $type, $item ) {
186
187 wp_mail(
188 get_site_option( 'admin_email' ),
189 __METHOD__,
190 "Starting an upgrade for:\n\n" . var_export( compact( 'type', 'item' ), true ) . "\n\n" . wp_debug_backtrace_summary()
191 );
192
193 self::$skin = new Background_Upgrader_Skin();
194
195 switch( $type ) {
196 case 'core':
197 // Okay, Why does the Core upgrader not use the Upgrader's skin during the actual main part of the upgrade???
198 add_filter( 'update_feedback', function( $message ) {
199 WP_Background_Upgrader::$skin->feedback( $message );
200 } );
201 $upgrader = new Core_Upgrader( self::$skin );
202 $context = ABSPATH;
203 break;
204 case 'plugin':
205 $upgrader = new Plugin_Upgrader( self::$skin );
206 $context = WP_PLUGIN_DIR; // We don't support custom Plugin directories, or updates for WPMU_PLUGIN_DIR
207 break;
208 case 'theme':
209 $upgrader = new Theme_Upgrader( self::$skin );
210 $context = get_theme_root( $item );
211 break;
212 case 'lang':
213 return false; // Not quite yet!
214 // $upgrader = new Language_Upgrader( self::$skin );
215 $context = WP_LANG_DIR;
216 break;
217 }
218
219 // Determine if we can perform this upgrade or not
220 if ( ! self::should_upgrade( $type, $item, $context ) || ! self::can_upgrade( $context ) )
221 return false;
222
223 // Boom, This sites about to get a whole new splash of paint!
224 $upgrade_result = $upgrader->upgrade( $item, array(
225 'clear_update_cache' => false,
226 ) );
227
228 // Core doesn't output this, so lets append it so we don't get confused
229 if ( 'core' == $type ) {
230 if ( is_wp_error( $upgrade_result ) ) {
231 self::$skin->error( __( 'Installation Failed' ), $upgrade_result );
232 } else {
233 self::$skin->feedback( __( 'WordPress updated successfully' ) );
234 }
235 }
236
237 // Clear cache's and update results
238 switch ( $type ) {
239 case 'core':
240 delete_site_transient( 'update_core' );
241 break;
242 case 'theme':
243 wp_clean_themes_cache();
244 break;
245 case 'plugin':
246 wp_clean_plugins_cache();
247 break;
248 }
249
250 var_dump( compact( 'type', 'item', 'upgrader', 'upgrade_result' ) );
251
252 wp_mail(
253 get_site_option( 'admin_email' ),
254 __METHOD__,
255 var_export( array(
256 $upgrade_result,
257 $upgrader,
258 self::$skin,
259 ), true )
260 );
261
262 return $upgrade_result;
263 }
264
265 /**
266 * Queues a cron entry in the event that the automatic upgrader is enabled, and there's at least one potentially upgradable item
267 */
268 static function queue_updates_check( $updates ) {
269
270 if ( self::upgrader_disabled() )
271 return;
272
273 $plugin_updates = get_site_transient( 'update_plugins' );
274 $theme_updates = get_site_transient( 'update_themes' );
275 if ( ! self::find_core_auto_update() && empty( $plugin_updates->response ) && empty( $theme_updates->response ) )
276 return;
277
278 if ( ! wp_next_scheduled( 'wp_background_upgrader_process' ) ) {
279 // If the transient update was triggered by a user pageview, update in an hours time, else, now.
280 $when_to_update = get_current_user_id() ? time() + HOUR_IN_SECONDS : time();
281 $when_to_update = apply_filters( 'auto_upgrade_when_to_upgrade', $when_to_update );
282
283 wp_schedule_single_event( $when_to_update, 'wp_background_upgrader_process' );
284 }
285
286 }
287
288 /**
289 * Kicks off a upgrade request for each item in the upgrade "queue"
290 */
291 static function perform_queued_updates() {
292
293 $lock_name = 'auto_upgrader.lock';
294 if ( get_site_transient( $lock_name ) ) {
295 // Test to see if it was set more than an hour ago, if so, cleanup.
296 if ( true || get_site_transient( $lock_name ) < ( time() - HOUR_IN_SECONDS ) )
297 delete_site_transient( $lock_name );
298 else // Recent lock
299 return;
300 }
301 // Lock upgrades for us for half an hour
302 if ( ! set_site_transient( $lock_name, microtime( true ), HOUR_IN_SECONDS / 2 ) )
303 return;
304
305 // Admin-ize ourselves
306 self::load_required_admin_includes();
307
308 // Next, Plugins
309 wp_update_plugins(); // Check for Plugin updates
310 $plugin_updates = get_site_transient( 'update_plugins' );
311 if ( $plugin_updates && !empty( $plugin_updates->response ) ) {
312 foreach ( array_keys( $plugin_updates->response ) as $plugin ) {
313 self::upgrade( 'plugin', $plugin );
314 }
315 // Force refresh of plugin update information
316 wp_clean_plugins_cache();
317 }
318
319 // Next, those themes we all love
320 wp_update_themes(); // Check for Theme updates
321 $theme_updates = get_site_transient( 'update_themes' );
322 if ( $theme_updates && !empty( $theme_updates->response ) ) {
323 foreach ( array_keys( $theme_updates->response ) as $theme ) {
324 self::upgrade( 'theme', $theme );
325 }
326 // Force refresh of theme update information
327 wp_clean_themes_cache();
328 }
329
330 // Up first, Core.
331 wp_version_check(); // Check for Core updates
332 $core_update = self::find_core_auto_update();
333 if ( $core_update )
334 self::upgrade( 'core', $core_update );
335
336 // Cleanup, These won't trigger any updates this time due to the locking transient
337 wp_version_check(); // check for Core updates
338 wp_update_themes(); // Check for Theme updates
339 wp_update_plugins(); // Check for Plugin updates
340
341 delete_site_transient( $lock_name );
342
343 }
344
345}
346WP_Background_Upgrader::init();