During the final moments of a WordPress release development cycle I was asked a very simple question:
How do I test the changes to
src/wp-admin/includes/update-core.php
before they’re committed to trunk?
One method that others have resorted to is to build a custom WordPress release zip and hack WordPress to always install from that custom zip file – It’s not hard to do that, but it’s a real pain when your development workflow includes testing things time and time again. [note: I’ve used this method in the past, before Grunt was “a thing”]
So, here’s my current solution: Use grunt build
and hit Update, something we all use already, coupled with WordPress’s own update routines!
The way that I do it, is that I apply the patch to /src/
, and then alter class-wp-upgrader.php
to use the local copy of update-core.php
instead of the one from the zip file it’ll download, and then just hit Update on the dashboard.
This takes very little effort to pull off – below is an example of the code changes needed to cause it to abort a update early on with a custom message, all that’s left to do is to run grunt build and hit the update button! – Just make sure you’re in /build/
rather than /src/
, as it could quickly lead to custom code going missing.. I know this from experience!
Index: src/wp-admin/includes/class-wp-upgrader.php ================================================================== @@ class Core_Upgrader extends WP_Upgrader $working_dir = $this->unpack_package( $download ); if ( is_wp_error($working_dir) ) return $working_dir; // Copy update-core.php from the new version into place. -if ( !$wp_filesystem->copy($working_dir . '/wordpress/wp-admin/includes/update-core.php', $wp_dir . 'wp-admin/includes/update-core.php', true) ) { +if ( false && !$wp_filesystem->copy($working_dir . '/wordpress/wp-admin/includes/update-core.php', $wp_dir . 'wp-admin/includes/update-core.php', true) ) { $wp_filesystem->delete($working_dir, true); return new WP_Error( 'copy_failed_for_update_core_file', __( 'The update cannot be installed because we will be unable to copy some files. This is usually due to inconsistent file permissions.' ), 'wp-admin/includes/update-core.php' ); } $wp_filesystem->chmod($wp_dir . 'wp-admin/includes/update-core.php', FS_CHMOD_FILE); require_once( ABSPATH . 'wp-admin/includes/update-core.php' ); Index: src/wp-admin/includes/update-core.php ================================================================== * @param string $from New release unzipped path. * @param string $to Path to old WordPress installation. * @return WP_Error|null WP_Error on failure, null on success. */ function update_core($from, $to) { global $wp_filesystem, $_old_files, $_new_bundled_files, $wpdb; + // Demo code to show that this process works + echo "Hi! This is text to confirm that I'm using a custom update-core.php file during the update!"; + die(); + @set_time_limit( 300 );
A few frequently asked questions that have come up in the past with this method:
- Question: It’s still downloading the zip file from the internet though!
Answer: Yes, it does. However my internet connections are usually fast enough that this isn’t a problem. - Question: What if there’s other alterations needed in other update related files?
Answer: It doesn’t actually matter, update-core.php is the only file from the zip that’s used during update, all the other files (WP_Upgrader / WP_Filesystem / etc) use what’s installed, they’re only overwritten once the update commences using the old code. - Question: How do I stop it from redirecting after the update?
Answer: When you find out, let me know! I’ve resorted to simply adding adie();
after the debug code I’m using. - Question: Why isn’t there a grunt task to build the WordPress zips?
Answer: Haven’t needed one yet I guess? Why don’t you submit a patch on Trac for it? :)