The problem
WordPress 2.5 introduced copy_dir() for copying a directory from one location to another. This function recursively creates the necessary subdirectories and copies files to their respective location in the new folder.
However, there was previously no function to move a directory that worked on all filesystems. This meant that Core Core is the set of software required to run WordPress. The Core Development Team builds WordPress., and extenders, had to use copy_dir(), and then delete the original version.
Moving a directory should not require so much memory, diskspace, time, or file operations. It should be quick, easy to call, and reliable.
The solution
WordPress 6.2 (#57375) introduces the move_dir()
function, which has the following parameters:
- from (string) – The current location of the directory.
- to (string) – The new location of the directory.
- overwrite (bool) – Whether to overwrite the destination. Default false.
The function will return true
on success, or a WP_Error object on failure.
Failures include:
$from
and $to
are the same.
$overwrite
is false
and the destination exists.
$overwrite
is true
, and an existing destination could not be deleted.
- If falling back to copy_dir() and the destination cannot be created.
How do you use it?
If your intent is to use move_dir()
, and the destination hasn’t already been deleted, then it must be called with $overwrite
as true
.
$result = move_dir( $from, $to, $overwrite );
if ( is_wp_error( $result ) ) {
return $result;
}
When can you start using it?
You can immediately begin replacing any combinations of copy_dir() and delete with move_dir()
in anticipation of WordPress 6.2’s release.
As always, please perform sufficient testing to ensure your code continues to work as expected before publishing it to production/users. This includes testing in all WordPress 6.2 release candidates.
Where is it used in Core?
move_dir()
has now been implemented within the WP_Upgrader::install_package() method in #57557. This affects all upgrade paths, reducing diskspace and memory usage, and improving speed to reduce timeouts on systems with lower resources when updating Plugins, Themes and Language Packs.
If an extender sets clear_working
to false
, or the destination exists and has contents, the upgrade will use copy_dir() instead.
This is not a replacement for the use of copy_dir() in Core updates, as there are several areas where specific subdirectories are not copied in the process.
Under The Hood
move_dir()
uses the ::move()
method for the WP_Filesystem_Direct, WP_Filesystem_FTPext, WP_Filesystem_ftpsockets, and WP_Filesystem_SSH2 filesystem abstractions.
Not only is this more intuitive for moving directories than a combination of copy_dir() and delete, but it’s also significantly faster, and uses less diskspace and memory on the server.
OPcache is invalidated for all of the moved files, using the newly introduced wp_opcache_invalidate_directory()
function. Find out more about this function in the Miscellaneous Dev Notes Each important change in WordPress Core is documented in a developers note, (usually called dev note). Good dev notes generally include a description of the change, the decision that led to this change, and a description of how developers are supposed to work with that change. Dev notes are published on Make/Core blog during the beta phase of WordPress release cycle. Publishing dev notes is particularly important when plugin/theme authors and WordPress developers need to be aware of those changes.In general, all dev notes are compiled into a Field Guide at the beginning of the release candidate phase. for WordPress 6.2.
Should the move operation fail, move_dir()
falls back to copy_dir(). If copy_dir() is successful, the source directory is deleted.
VirtualBox
While working on this function, Core developers encountered a well-known issue in VirtualBox, in which file existence and metadata may not be updated after a move.
This produced a highly destructive result when a combination of Move A to C, Move B to A, Delete C was used via PHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 5.6.20 or higher’s rename()
and unlink()
functions.
move_dir()
makes use of the calls to filesize() and filemtime() within the WP_Filesystem_*::dirlist() method called in wp_opcache_invalidate_directory()
to resolve delayed metadata updates. File existence warnings are resolved with a 200ms delay after moving a directory, which gives the filesystem’s cache time to update.
This bug A bug is an error or unexpected result. Performance improvements, code optimization, and are considered enhancements, not defects. After feature freeze, only bugs are dealt with, with regressions (adverse changes from the previous version) being the highest priority. was known exclusively to VirtualBox. Extensive testing in VirtualBox 6 and 7 has shown that move_dir()
does not encounter this bug, and is safe to use.
Props to @milana_cap and @webcommsat for review.
#6-2, #dev-notes, #dev-notes-6-2