Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 21 additions & 9 deletions src/lib/import-export/import/importers/importer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,17 +179,20 @@ abstract class BaseBackupImporter extends BaseImporter {
if ( ! fs.existsSync( wpContentDir ) ) {
return;
}
const contentToKeep = [ 'mu-plugins', 'database', 'db.php' ];
const contentToKeep = [
/^mu-plugins$/, // Match mu-plugins directory exactly
/^mu-plugins(\/|\\)sqlite-database-integration(\/|\\)?.*/, // Match sqlite-database-integration dir and contents
/^database(\/|\\)?.*/, // Match database dir and all contents
/^db\.php$/, // Exact match for db.php
];

const contents = await fsPromises.readdir( wpContentDir );
const contents = await fsPromises.readdir( wpContentDir, { recursive: true } );

for ( const content of contents ) {
const contentPath = path.join( wpContentDir, content );

if ( contentToKeep.includes( content ) ) {
if ( contentToKeep.some( ( pattern ) => pattern.test( content ) ) ) {
continue;
}
await this.safelyDeletePath( contentPath );
await this.safelyDeletePath( path.join( wpContentDir, content ) );
}
} catch {
return;
Expand All @@ -215,9 +218,18 @@ abstract class BaseBackupImporter extends BaseImporter {
const wpContentDestDir = path.join( rootPath, 'wp-content' );
for ( const files of Object.values( wpContent ) ) {
for ( const file of files ) {
const stats = await lstat( file );
// Skip if it's a directory
if ( stats.isDirectory() ) {
try {
const stats = await lstat( file );
// Skip if it's a directory
if ( stats.isDirectory() ) {
continue;
}
} catch {
/**
* If the file does not exist, skip it.
* This can happen if a empty directory is included in the backup
* because the empty directory won't be included in the extraction.
*/
Comment on lines +228 to +232

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I discovered this issue in a Local export.
The uploads/2025/01 folder was empty on the site and the 01 folder is missing from the extracted ZIP.
This caused lstat to fail because the directory didn't exist.

continue;
}
const relativePath = path.relative(
Expand Down
1 change: 1 addition & 0 deletions src/lib/import-export/import/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export interface WpContent {
uploads: string[];
plugins: string[];
themes: string[];
muPlugins?: string[];

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I make muPlugins mandatory?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep it optional, as none of the supported backup formats includes it by default.

}

export interface BackupContents {
Expand Down
3 changes: 3 additions & 0 deletions src/lib/import-export/import/validators/jetpack-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export class JetpackValidator extends EventEmitter implements Validator {
uploads: [],
plugins: [],
themes: [],
muPlugins: [],
},
wpContentDirectory: 'wp-content',
};
Expand All @@ -47,6 +48,8 @@ export class JetpackValidator extends EventEmitter implements Validator {
extractedBackup.wpContent.plugins.push( fullPath );
} else if ( file.startsWith( 'wp-content/themes/' ) ) {
extractedBackup.wpContent.themes.push( fullPath );
} else if ( file.startsWith( 'wp-content/mu-plugins/' ) ) {
extractedBackup.wpContent.muPlugins!.push( fullPath );
} else if ( file === 'studio.json' || file === 'meta.json' ) {
extractedBackup.metaFile = fullPath;
}
Expand Down
3 changes: 3 additions & 0 deletions src/lib/import-export/import/validators/local-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export class LocalValidator extends EventEmitter implements Validator {
uploads: [],
plugins: [],
themes: [],
muPlugins: [],
},
wpContentDirectory: path.normalize( 'app/public/wp-content' ),
};
Expand All @@ -52,6 +53,8 @@ export class LocalValidator extends EventEmitter implements Validator {
extractedBackup.wpContent.plugins.push( fullPath );
} else if ( file.startsWith( 'app/public/wp-content/themes/' ) ) {
extractedBackup.wpContent.themes.push( fullPath );
} else if ( file.startsWith( 'app/public/wp-content/mu-plugins/' ) ) {
extractedBackup.wpContent.muPlugins!.push( fullPath );
} else if ( file === 'local-site.json' ) {
extractedBackup.metaFile = fullPath;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export class PlaygroundValidator extends EventEmitter implements Validator {
uploads: [],
plugins: [],
themes: [],
muPlugins: [],
},
wpContentDirectory: 'wp-content',
};
Expand All @@ -55,6 +56,8 @@ export class PlaygroundValidator extends EventEmitter implements Validator {
extractedBackup.wpContent.plugins.push( fullPath );
} else if ( file.startsWith( 'wp-content/themes/' ) ) {
extractedBackup.wpContent.themes.push( fullPath );
} else if ( file.startsWith( 'wp-content/mu-plugins/' ) ) {
extractedBackup.wpContent.muPlugins!.push( fullPath );
}
}
this.emit( ImportEvents.IMPORT_VALIDATION_COMPLETE );
Expand Down
3 changes: 3 additions & 0 deletions src/lib/import-export/import/validators/wpress-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export class WpressValidator extends EventEmitter implements Validator {
uploads: [],
plugins: [],
themes: [],
muPlugins: [],
},
wpContentDirectory: '',
};
Expand All @@ -43,6 +44,8 @@ export class WpressValidator extends EventEmitter implements Validator {
extractedBackup.wpContent.plugins.push( fullPath );
} else if ( file.startsWith( 'themes' + path.sep ) ) {
extractedBackup.wpContent.themes.push( fullPath );
} else if ( file.startsWith( 'mu-plugins' + path.sep ) ) {
extractedBackup.wpContent.muPlugins!.push( fullPath );
} else if ( file === 'package.json' ) {
extractedBackup.metaFile = fullPath;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ platformTestSuite( 'JetpackValidator', ( { normalize } ) => {
'wp-content/uploads/2023/image.jpg',
'wp-content/plugins/jetpack/jetpack.php',
'wp-content/themes/twentytwentyone/style.css',
'wp-content/mu-plugins/hello.php',
];
expect( validator.canHandle( fileList ) ).toBe( true );
} );
Expand All @@ -28,6 +29,7 @@ platformTestSuite( 'JetpackValidator', ( { normalize } ) => {
'wp-content/uploads/2023/image.jpg',
'wp-content/plugins/jetpack/jetpack.php',
'wp-content/themes/twentytwentyone/style.css',
'wp-content/mu-plugins/hello.php',
];
expect( validator.canHandle( fileList ) ).toBe( true );
} );
Expand All @@ -45,6 +47,7 @@ platformTestSuite( 'JetpackValidator', ( { normalize } ) => {
'wp-content/uploads/2023/image.jpg',
'wp-content/plugins/jetpack/jetpack.php',
'wp-content/themes/twentytwentyone/style.css',
'wp-content/mu-plugins/hello.php',
'meta.json',
];
const extractionDirectory = '/tmp/extracted';
Expand All @@ -58,6 +61,7 @@ platformTestSuite( 'JetpackValidator', ( { normalize } ) => {
uploads: [ normalize( '/tmp/extracted/wp-content/uploads/2023/image.jpg' ) ],
plugins: [ normalize( '/tmp/extracted/wp-content/plugins/jetpack/jetpack.php' ) ],
themes: [ normalize( '/tmp/extracted/wp-content/themes/twentytwentyone/style.css' ) ],
muPlugins: [ normalize( '/tmp/extracted/wp-content/mu-plugins/hello.php' ) ],
},
wpContentDirectory: normalize( 'wp-content' ),
metaFile: normalize( '/tmp/extracted/meta.json' ),
Expand All @@ -76,6 +80,7 @@ platformTestSuite( 'JetpackValidator', ( { normalize } ) => {
'wp-content/uploads/2023/image.jpg',
'wp-content/plugins/jetpack/jetpack.php',
'wp-content/themes/twentytwentyone/style.css',
'wp-content/mu-plugins/hello.php',
'meta.json',
];
const extractionDirectory = '/tmp/extracted';
Expand All @@ -89,6 +94,7 @@ platformTestSuite( 'JetpackValidator', ( { normalize } ) => {
uploads: [ normalize( '/tmp/extracted/wp-content/uploads/2023/image.jpg' ) ],
plugins: [ normalize( '/tmp/extracted/wp-content/plugins/jetpack/jetpack.php' ) ],
themes: [ normalize( '/tmp/extracted/wp-content/themes/twentytwentyone/style.css' ) ],
muPlugins: [ normalize( '/tmp/extracted/wp-content/mu-plugins/hello.php' ) ],
},
wpContentDirectory: normalize( 'wp-content' ),
metaFile: normalize( '/tmp/extracted/meta.json' ),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ platformTestSuite( 'LocalValidator', ( { normalize } ) => {
'app/public/wp-content/uploads/2023/image.jpg',
'app/public/wp-content/plugins/jetpack/jetpack.php',
'app/public/wp-content/themes/twentytwentyone/style.css',
'app/public/wp-content/mu-plugins/hello.php',
];
expect( validator.canHandle( fileList ) ).toBe( true );
} );
Expand All @@ -28,6 +29,7 @@ platformTestSuite( 'LocalValidator', ( { normalize } ) => {
'app/public/wp-content/uploads/2023/image.jpg',
'app/public/wp-content/plugins/jetpack/jetpack.php',
'app/public/wp-content/themes/twentytwentyone/style.css',
'app/public/wp-content/mu-plugins/hello.php',
];
expect( validator.canHandle( fileList ) ).toBe( true );
} );
Expand All @@ -45,6 +47,7 @@ platformTestSuite( 'LocalValidator', ( { normalize } ) => {
'app/public/wp-content/uploads/2023/image.jpg',
'app/public/wp-content/plugins/jetpack/jetpack.php',
'app/public/wp-content/themes/twentytwentyone/style.css',
'app/public/wp-content/mu-plugins/hello.php',
'local-site.json',
];
const extractionDirectory = '/tmp/extracted';
Expand All @@ -62,6 +65,7 @@ platformTestSuite( 'LocalValidator', ( { normalize } ) => {
themes: [
normalize( '/tmp/extracted/app/public/wp-content/themes/twentytwentyone/style.css' ),
],
muPlugins: [ normalize( '/tmp/extracted/app/public/wp-content/mu-plugins/hello.php' ) ],
},
wpContentDirectory: normalize( 'app/public/wp-content' ),
metaFile: normalize( '/tmp/extracted/local-site.json' ),
Expand All @@ -78,6 +82,7 @@ platformTestSuite( 'LocalValidator', ( { normalize } ) => {
'app/public/wp-content/uploads/2023/image.jpg',
'app/public/wp-content/plugins/jetpack/jetpack.php',
'app/public/wp-content/themes/twentytwentyone/style.css',
'app/public/wp-content/mu-plugins/hello.php',
'local-site.json',
];
const extractionDirectory = '/tmp/extracted';
Expand All @@ -95,6 +100,7 @@ platformTestSuite( 'LocalValidator', ( { normalize } ) => {
themes: [
normalize( '/tmp/extracted/app/public/wp-content/themes/twentytwentyone/style.css' ),
],
muPlugins: [ normalize( '/tmp/extracted/app/public/wp-content/mu-plugins/hello.php' ) ],
},
wpContentDirectory: normalize( 'app/public/wp-content' ),
metaFile: normalize( '/tmp/extracted/local-site.json' ),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ platformTestSuite( 'PlaygroundValidator', ( { normalize } ) => {
'wp-content/uploads/2023/image.jpg',
'wp-content/plugins/jetpack/jetpack.php',
'wp-content/themes/twentytwentyone/style.css',
'wp-content/mu-plugins/hello.php',
];
expect( validator.canHandle( fileList ) ).toBe( true );
} );
Expand All @@ -24,6 +25,7 @@ platformTestSuite( 'PlaygroundValidator', ( { normalize } ) => {
'wp-content/uploads/2023/image.jpg',
'wp-content/plugins/jetpack/jetpack.php',
'wp-content/themes/twentytwentyone/style.css',
'wp-content/mu-plugins/hello.php',
];
expect( validator.canHandle( fileList ) ).toBe( true );
} );
Expand All @@ -36,6 +38,7 @@ platformTestSuite( 'PlaygroundValidator', ( { normalize } ) => {
'wp-content/uploads/2023/image.jpg',
'wp-content/plugins/jetpack/jetpack.php',
'wp-content/themes/twentytwentyone/style.css',
'wp-content/mu-plugins/hello.php',
'random.txt',
'another-file.js',
];
Expand All @@ -50,6 +53,7 @@ platformTestSuite( 'PlaygroundValidator', ( { normalize } ) => {
'wp-content/uploads/2023/image.jpg',
'wp-content/plugins/jetpack/jetpack.php',
'wp-content/themes/twentytwentyone/style.css',
'wp-content/mu-plugins/hello.php',
];
const extractionDirectory = normalize( '/tmp/extracted' );
const result = validator.parseBackupContents( fileList, extractionDirectory );
Expand All @@ -62,6 +66,7 @@ platformTestSuite( 'PlaygroundValidator', ( { normalize } ) => {
uploads: [ normalize( '/tmp/extracted/wp-content/uploads/2023/image.jpg' ) ],
plugins: [ normalize( '/tmp/extracted/wp-content/plugins/jetpack/jetpack.php' ) ],
themes: [ normalize( '/tmp/extracted/wp-content/themes/twentytwentyone/style.css' ) ],
muPlugins: [ normalize( '/tmp/extracted/wp-content/mu-plugins/hello.php' ) ],
},
wpContentDirectory: 'wp-content',
} );
Expand All @@ -77,6 +82,7 @@ platformTestSuite( 'PlaygroundValidator', ( { normalize } ) => {
'wp-content/uploads/2023/image.jpg',
'wp-content/plugins/jetpack/jetpack.php',
'wp-content/themes/twentytwentyone/style.css',
'wp-content/mu-plugins/hello.php',
];
const extractionDirectory = normalize( '/tmp/extracted' );
const result = validator.parseBackupContents( fileList, extractionDirectory );
Expand All @@ -89,6 +95,7 @@ platformTestSuite( 'PlaygroundValidator', ( { normalize } ) => {
uploads: [ normalize( '/tmp/extracted/wp-content/uploads/2023/image.jpg' ) ],
plugins: [ normalize( '/tmp/extracted/wp-content/plugins/jetpack/jetpack.php' ) ],
themes: [ normalize( '/tmp/extracted/wp-content/themes/twentytwentyone/style.css' ) ],
muPlugins: [ normalize( '/tmp/extracted/wp-content/mu-plugins/hello.php' ) ],
},
wpContentDirectory: 'wp-content',
} );
Expand Down