From 51566162ada80eb16ac79c4b4b04434dadd7fdc6 Mon Sep 17 00:00:00 2001 From: Brandon Payton Date: Thu, 12 Dec 2024 22:50:03 -0500 Subject: [PATCH 1/6] Add WP_Exporter class --- .../playground/data-liberation/bootstrap.php | 5 ++ .../src/export/WP_Exporter.php | 62 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 packages/playground/data-liberation/src/export/WP_Exporter.php diff --git a/packages/playground/data-liberation/bootstrap.php b/packages/playground/data-liberation/bootstrap.php index 8b5910c217..6dbe09c7be 100644 --- a/packages/playground/data-liberation/bootstrap.php +++ b/packages/playground/data-liberation/bootstrap.php @@ -10,6 +10,10 @@ require_once __DIR__ . '/blueprints-library/src/WordPress/AsyncHttp/HttpError.php'; require_once __DIR__ . '/blueprints-library/src/WordPress/AsyncHttp/Connection.php'; require_once __DIR__ . '/blueprints-library/src/WordPress/AsyncHttp/Client.php'; +require_once __DIR__ . '/blueprints-library/src/WordPress/Zip/ZipStreamWriter.php'; +require_once __DIR__ . '/blueprints-library/src/WordPress/Zip/ZipFileEntry.php'; +require_once __DIR__ . '/blueprints-library/src/WordPress/Zip/ZipCentralDirectoryEntry.php'; +require_once __DIR__ . '/blueprints-library/src/WordPress/Zip/ZipEndCentralDirectoryEntry.php'; require_once __DIR__ . '/src/byte-readers/WP_Byte_Reader.php'; require_once __DIR__ . '/src/byte-readers/WP_File_Reader.php'; @@ -64,6 +68,7 @@ require_once __DIR__ . '/src/import/WP_Entity_Iterator_Chain.php'; require_once __DIR__ . '/src/import/WP_Retry_Frontloading_Iterator.php'; require_once __DIR__ . '/src/import/WP_Markdown_Importer.php'; +require_once __DIR__ . '/src/export/WP_Exporter.php'; require_once __DIR__ . '/src/utf8_decoder.php'; diff --git a/packages/playground/data-liberation/src/export/WP_Exporter.php b/packages/playground/data-liberation/src/export/WP_Exporter.php new file mode 100644 index 0000000000..40012fbab7 --- /dev/null +++ b/packages/playground/data-liberation/src/export/WP_Exporter.php @@ -0,0 +1,62 @@ +writeFileFromString( 'META-INF/export.wxr', $wxr_content ); + + $uploads = wp_upload_dir(); + $uploads_path = $uploads['basedir']; + + $flags = \FilesystemIterator::SKIP_DOTS; + $recursive_dir_iterator = new \RecursiveDirectoryIterator( + $uploads_path, + $flags + ); + $uploads_iterator = new \RecursiveIteratorIterator( + $recursive_dir_iterator + ); + + foreach ( $uploads_iterator as $file ) { + if ( $file->isDir() ) { + continue; + } + $absolute_path = $file->getPathname(); + $relative_path = substr( $absolute_path, strlen($uploads_path) + 1 ); + $zip_writer->writeFileFromPath( $relative_path, $absolute_path ); + } + + $zip_writer->finish(); + // TODO: Is this necessary? + fflush( $output_stream ); + } +} \ No newline at end of file From 7988e230632c2b2cf0b0021d8e84af12de2ec275 Mon Sep 17 00:00:00 2001 From: Brandon Payton Date: Thu, 12 Dec 2024 22:51:00 -0500 Subject: [PATCH 2/6] Add temp test endpoint for getting export package --- packages/playground/data-liberation/plugin.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/playground/data-liberation/plugin.php b/packages/playground/data-liberation/plugin.php index f17704ebcc..5aeed6cbd2 100644 --- a/packages/playground/data-liberation/plugin.php +++ b/packages/playground/data-liberation/plugin.php @@ -657,3 +657,15 @@ function () { ); } ); + +add_action('wp_loaded', 'data_liberation_maybe_test_export'); +function data_liberation_maybe_test_export() { + $request_path = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH); + if( $request_path !== '/_data_liberation_test_export' ) { + return; + } + + $exporter = new WP_Exporter(); + $exporter->stream_export(); + die(); +} \ No newline at end of file From 3a1f2e91b35b682262d69e391a3c77f9793a9069 Mon Sep 17 00:00:00 2001 From: Brandon Payton Date: Thu, 12 Dec 2024 23:07:25 -0500 Subject: [PATCH 3/6] Try to flush output per file --- .../playground/data-liberation/src/export/WP_Exporter.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/playground/data-liberation/src/export/WP_Exporter.php b/packages/playground/data-liberation/src/export/WP_Exporter.php index 40012fbab7..1ea2a135ae 100644 --- a/packages/playground/data-liberation/src/export/WP_Exporter.php +++ b/packages/playground/data-liberation/src/export/WP_Exporter.php @@ -53,10 +53,11 @@ public static function stream_export( $output_stream = false ) { $absolute_path = $file->getPathname(); $relative_path = substr( $absolute_path, strlen($uploads_path) + 1 ); $zip_writer->writeFileFromPath( $relative_path, $absolute_path ); + + // TODO: Is this necessary to make sure per-file output is flushed? + fflush( $output_stream ); } $zip_writer->finish(); - // TODO: Is this necessary? - fflush( $output_stream ); } } \ No newline at end of file From dcdccc843d196033e278ec1036e7361b2220f40b Mon Sep 17 00:00:00 2001 From: Brandon Payton Date: Thu, 12 Dec 2024 23:22:08 -0500 Subject: [PATCH 4/6] Place uploads under wp-content/uploads in zip --- .../data-liberation/src/export/WP_Exporter.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/playground/data-liberation/src/export/WP_Exporter.php b/packages/playground/data-liberation/src/export/WP_Exporter.php index 1ea2a135ae..a927de4928 100644 --- a/packages/playground/data-liberation/src/export/WP_Exporter.php +++ b/packages/playground/data-liberation/src/export/WP_Exporter.php @@ -38,12 +38,11 @@ public static function stream_export( $output_stream = false ) { $uploads_path = $uploads['basedir']; $flags = \FilesystemIterator::SKIP_DOTS; - $recursive_dir_iterator = new \RecursiveDirectoryIterator( - $uploads_path, - $flags - ); $uploads_iterator = new \RecursiveIteratorIterator( - $recursive_dir_iterator + new \RecursiveDirectoryIterator( + $uploads_path, + $flags + ) ); foreach ( $uploads_iterator as $file ) { @@ -52,7 +51,11 @@ public static function stream_export( $output_stream = false ) { } $absolute_path = $file->getPathname(); $relative_path = substr( $absolute_path, strlen($uploads_path) + 1 ); - $zip_writer->writeFileFromPath( $relative_path, $absolute_path ); + $zip_writer->writeFileFromPath( + // TODO: How to handle unconventional upload locations? + "wp-content/uploads/$relative_path", + $absolute_path + ); // TODO: Is this necessary to make sure per-file output is flushed? fflush( $output_stream ); From a651b4dbc67ebc7abf1b494ef3604a712c900985 Mon Sep 17 00:00:00 2001 From: Brandon Payton Date: Thu, 12 Dec 2024 23:23:54 -0500 Subject: [PATCH 5/6] Remove unused use declaration --- packages/playground/data-liberation/src/export/WP_Exporter.php | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/playground/data-liberation/src/export/WP_Exporter.php b/packages/playground/data-liberation/src/export/WP_Exporter.php index a927de4928..a327078625 100644 --- a/packages/playground/data-liberation/src/export/WP_Exporter.php +++ b/packages/playground/data-liberation/src/export/WP_Exporter.php @@ -1,6 +1,5 @@ Date: Thu, 12 Dec 2024 23:30:20 -0500 Subject: [PATCH 6/6] Add temporary attachment URL substitution hack --- .../data-liberation/src/export/WP_Exporter.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/playground/data-liberation/src/export/WP_Exporter.php b/packages/playground/data-liberation/src/export/WP_Exporter.php index a327078625..d751830098 100644 --- a/packages/playground/data-liberation/src/export/WP_Exporter.php +++ b/packages/playground/data-liberation/src/export/WP_Exporter.php @@ -21,6 +21,14 @@ public static function stream_export( $output_stream = false ) { // @TODO: Replace upload URLs with relative file URLs. + $uploads = wp_upload_dir(); + // @TODO: This is a hack and kind of broken. Replace attachment URLs using proper XML and URL parsing libraries. + $wxr_content = str_replace( + trailingslashit( $uploads['baseurl'] ), + 'file://./wp-content/uploads/', + $wxr_content + ); + header('Content-Type: application/zip'); // @TODO: Can we get rid of this open-stdout-on-demand workaround? @@ -33,7 +41,6 @@ public static function stream_export( $output_stream = false ) { $zip_writer = new ZipStreamWriter( $output_stream ); $zip_writer->writeFileFromString( 'META-INF/export.wxr', $wxr_content ); - $uploads = wp_upload_dir(); $uploads_path = $uploads['basedir']; $flags = \FilesystemIterator::SKIP_DOTS;