diff --git a/Puc/v5p4/UpdateChecker.php b/Puc/v5p4/UpdateChecker.php
index 8833547..890f581 100644
--- a/Puc/v5p4/UpdateChecker.php
+++ b/Puc/v5p4/UpdateChecker.php
@@ -924,23 +924,66 @@ if ( !class_exists(UpdateChecker::class, false) ):
return $source;
}
+ // Fix the remote source structure if necessary.
+ //The update archive should contain a single directory that contains the rest of plugin/theme files.
+ //Otherwise, WordPress will try to copy the entire working directory ($source == $remoteSource).
+ //We can't rename $remoteSource because that would break WordPress code that cleans up temporary files
+ //after update.
+ if ( $this->isBadDirectoryStructure($remoteSource) ) {
+
+ // Create a new folder using plugin slug.
+ $new_directory = trailingslashit( $remoteSource ) . $this->slug . '/';
+
+ if ( ! $wp_filesystem->is_dir( $new_directory ) ) {
+ $wp_filesystem->mkdir( $new_directory );
+
+ // Move all files inside newly created directory.
+ $sourceFiles = $wp_filesystem->dirlist($remoteSource);
+ if ( is_array($sourceFiles) ) {
+ $sourceFiles = array_keys($sourceFiles);
+ $allMoved = true;
+ foreach ($sourceFiles as $filename) {
+
+ // Skip for our newly created folder.
+ if ( $filename === $this->slug ) {
+ continue;
+ }
+
+ $previousSource = trailingslashit( $remoteSource ) . $filename;
+ $newSource = trailingslashit( $new_directory ) . $filename;
+
+ if ( !$wp_filesystem->move($previousSource, $newSource, true) ) {
+ $allMoved = false;
+ break;
+ }
+ }
+
+ if ( $allMoved ) {
+ // Rename source.
+ $source = $new_directory;
+ }
+ else {
+ // Delete our newly created folder including all files in it.
+ $wp_filesystem->rmdir( $new_directory, true );
+
+ // And return a relevant error.
+ return new WP_Error(
+ 'puc-incorrect-directory-structure',
+ sprintf(
+ 'The directory structure of the update was incorrect. All files should be inside ' .
+ 'a directory named %s, not at the root of the ZIP archive. Plugin Update Checker tried to fix the directory structure, but failed.',
+ htmlentities($this->slug)
+ )
+ );
+ }
+ }
+ }
+ }
+
//Rename the source to match the existing directory.
$correctedSource = trailingslashit($remoteSource) . $this->directoryName . '/';
if ( $source !== $correctedSource ) {
- //The update archive should contain a single directory that contains the rest of plugin/theme files.
- //Otherwise, WordPress will try to copy the entire working directory ($source == $remoteSource).
- //We can't rename $remoteSource because that would break WordPress code that cleans up temporary files
- //after update.
- if ( $this->isBadDirectoryStructure($remoteSource) ) {
- return new WP_Error(
- 'puc-incorrect-directory-structure',
- sprintf(
- 'The directory structure of the update is incorrect. All files should be inside ' .
- 'a directory named %s, not at the root of the ZIP archive.',
- htmlentities($this->slug)
- )
- );
- }
+
/** @var \WP_Upgrader_Skin $upgrader ->skin */
$upgrader->skin->feedback(sprintf(