Flywheel, a managed WordPress hosting company, is known for its speed and reliability. However, we’ve observed a specific issue that has been causing trouble for many users – Flywheel modifies the core WordPress files. While this might not be a problem if you’re staying with Flywheel forever, the issue emerges when you move to another hosting provider.
In this post, we are going to shed light on a common error that arises due to Flywheel’s modifications and provide a solution to fix it.
The Flywheel Error
Users moving their WordPress site from Flywheel to another hosting provider often encounter a PHP fatal error that prevents certain plugins from updating. The error shows up for most users when an Automated WordPress update fails or when attempting to update a plugin from the WordPress Dashboard and seeing an unable to Update Plugin error message.
Checking the PHP Error log will show an error message that looks something like this:
error_log:[08-Nov-2022 07:12:08 UTC] PHP Fatal error: Uncaught Error: Call to undefined function fcp_copy_dir() in /home/mysite/public_html/wp-admin/includes/file.php:1896
The Culprit fcp_copy_dir
The problematic code lies within the WordPress core file file.php and looks like this:
**
* 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;
$files = fcp_copy_dir($from, $to, FS_CHMOD_FILE, FS_CHMOD_DIR, $skip_list);
if ( false !== strpos( $files, 'FCP Operation Error' ) ) {
return new WP_Error($files, $to);
}
$file_list = explode("\n", $files);
foreach ($file_list as &$file) {
wp_opcache_invalidate($file);
}
return true;
/* $dirlist = $wp_filesystem->dirlist( $from );
if ( false === $dirlist ) {
return new WP_Error( 'dirlist_failed_copy_dir', __( 'Directory listing failed.' ), basename( $to ) );
}
$from = trailingslashit( $from );
$to = trailingslashit( $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 ( 0 === strpos( $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; */
}
The fcp_copy_dir() function is unique to Flywheel’s environment and is not a part of the standard WordPress core files. Therefore, when you migrate your website to a different hosting provider, the fcp_copy_dir() function becomes undefined, causing the fatal error when it is called upon.
The Solution
The resolution to this issue is quite simple – reinstall the WordPress core files. Unfortunately in some versions the broken code will prevent you from using WordPress to re-install core file. So the first step is to manually change the code in wp-admin/includes/file.php. Navigate to the function copy_dir( $from, $to, $skip_list = array() )
comment out or delete the FlyWheel custom code
/** Commenting out FlyWheel Custom Code
$files = fcp_copy_dir($from, $to, FS_CHMOD_FILE, FS_CHMOD_DIR, $skip_list);
if ( false !== strpos( $files, 'FCP Operation Error' ) ) {
return new WP_Error($files, $to);
}
$file_list = explode("\n", $files);
foreach ($file_list as &$file) {
wp_opcache_invalidate($file);
}
return true;
*/
uncomment the original WordPress code so that the full function is as follows.
**
* 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;
/** Commenting out FlyWheel Custom Code
$files = fcp_copy_dir($from, $to, FS_CHMOD_FILE, FS_CHMOD_DIR, $skip_list);
if ( false !== strpos( $files, 'FCP Operation Error' ) ) {
return new WP_Error($files, $to);
}
$file_list = explode("\n", $files);
foreach ($file_list as &$file) {
wp_opcache_invalidate($file);
}
return true;
*/
$dirlist = $wp_filesystem->dirlist( $from );
if ( false === $dirlist ) {
return new WP_Error( 'dirlist_failed_copy_dir', __( 'Directory listing failed.' ), basename( $to ) );
}
$from = trailingslashit( $from );
$to = trailingslashit( $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 ( 0 === strpos( $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;
}
Now you can reinstall the WordPress core files.
To reinstall WordPress core files:
- Log into your WordPress admin panel.
- Go to Dashboard > Updates.
- You’ll see a button saying ‘Re-install Now’ under the ‘Update WordPress’ option. Click on it.
- The system will download and replace the WordPress core files without affecting your content or customization.
Please note that this process should not affect your website’s data, but it’s always a good practice to back up your website before making any major changes.
Conclusion
While Flywheel’s modifications aim to provide a better hosting environment, they can cause issues when moving to a different hosting provider. By understanding the nature of these modifications and how to rectify the resulting errors, you can ensure a smoother transition for your WordPress website. Always remember to back up your site before making significant changes, and do not hesitate to seek professional help if you encounter any difficulties.