WordPress Version: 6.3
/**
* Copies a directory from one location to another via the WordPress Filesystem
* Abstraction.
*
* Assumes that WP_Filesystem() has already been called and setup.
*
* @since 2.5.0
*
* @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
*
* @param string $from Source directory.
* @param string $to Destination directory.
* @param string[] $skip_list An array of files/folders to skip copying.
* @return true|WP_Error True on success, WP_Error on failure.
*/
function copy_dir($from, $to, $skip_list = array())
{
global $wp_filesystem;
$dirlist = $wp_filesystem->dirlist($from);
if (false === $dirlist) {
return new WP_Error('dirlist_failed_copy_dir', __('Directory listing failed.'), basename($from));
}
$from = trailingslashit($from);
$to = trailingslashit($to);
if (!$wp_filesystem->exists($to) && !$wp_filesystem->mkdir($to)) {
return new WP_Error('mkdir_destination_failed_copy_dir', __('Could not create the destination directory.'), basename($to));
}
foreach ((array) $dirlist as $filename => $fileinfo) {
if (in_array($filename, $skip_list, true)) {
continue;
}
if ('f' === $fileinfo['type']) {
if (!$wp_filesystem->copy($from . $filename, $to . $filename, true, FS_CHMOD_FILE)) {
// If copy failed, chmod file to 0644 and try again.
$wp_filesystem->chmod($to . $filename, FS_CHMOD_FILE);
if (!$wp_filesystem->copy($from . $filename, $to . $filename, true, FS_CHMOD_FILE)) {
return new WP_Error('copy_failed_copy_dir', __('Could not copy file.'), $to . $filename);
}
}
wp_opcache_invalidate($to . $filename);
} elseif ('d' === $fileinfo['type']) {
if (!$wp_filesystem->is_dir($to . $filename)) {
if (!$wp_filesystem->mkdir($to . $filename, FS_CHMOD_DIR)) {
return new WP_Error('mkdir_failed_copy_dir', __('Could not create directory.'), $to . $filename);
}
}
// Generate the $sub_skip_list for the subdirectory as a sub-set of the existing $skip_list.
$sub_skip_list = array();
foreach ($skip_list as $skip_item) {
if (str_starts_with($skip_item, $filename . '/')) {
$sub_skip_list[] = preg_replace('!^' . preg_quote($filename, '!') . '/!i', '', $skip_item);
}
}
$result = copy_dir($from . $filename, $to . $filename, $sub_skip_list);
if (is_wp_error($result)) {
return $result;
}
}
}
return true;
}