Skip to content

Commit a44731d

Browse files
committed
Display WXR importing progress in the Playground loading bar
1 parent e6896c6 commit a44731d

File tree

5 files changed

+132
-83
lines changed

5 files changed

+132
-83
lines changed

packages/php-wasm/universal/src/lib/php-worker.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -229,8 +229,8 @@ export class PHPWorker implements LimitedPHPApi {
229229
}
230230

231231
/** @inheritDoc @php-wasm/universal!/PHP.onMessage */
232-
onMessage(listener: MessageListener): void {
233-
_private.get(this)!.php!.onMessage(listener);
232+
onMessage(listener: MessageListener): () => Promise<void> {
233+
return _private.get(this)!.php!.onMessage(listener);
234234
}
235235

236236
/** @inheritDoc @php-wasm/universal!/PHP.defineConstant */

packages/php-wasm/universal/src/lib/php.ts

+5
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,11 @@ export class PHP implements Disposable {
160160
*/
161161
onMessage(listener: MessageListener) {
162162
this.#messageListeners.push(listener);
163+
return () => {
164+
this.#messageListeners = this.#messageListeners.filter(
165+
(l) => l !== listener
166+
);
167+
};
163168
}
164169

165170
async setSpawnHandler(handler: SpawnHandler | string) {

packages/playground/blueprints/src/lib/steps/import-wxr.ts

+106-81
Original file line numberDiff line numberDiff line change
@@ -36,102 +36,127 @@ export const importWxr: StepHandler<ImportWxrStep<File>> = async (
3636
{ file },
3737
progress?
3838
) => {
39-
progress?.tracker?.setCaption('Importing content');
39+
progress?.tracker?.setCaption('Preparing content import');
4040
await writeFile(playground, {
4141
path: '/tmp/import.wxr',
4242
data: file,
4343
});
4444
const docroot = await playground.documentRoot;
45-
playground.onMessage((messageString) => {
46-
const message = JSON.parse(messageString) as any;
47-
if (message?.type === 'import-wxr-progress') {
48-
progress?.tracker?.setCaption(message.progress);
49-
} else if (message?.type === 'console.log') {
50-
console.log(message.data);
45+
/**
46+
* Surface the import progress information in the Blueprint progress bar.
47+
* This temporary message handler is cleared at the end of this step.
48+
*/
49+
const clearProgressListener = await playground.onMessage(
50+
(messageString) => {
51+
const message = JSON.parse(messageString) as any;
52+
if (message?.type === 'import-wxr-progress') {
53+
progress?.tracker?.setCaption(message.progress);
54+
}
5155
}
52-
});
56+
);
5357
try {
54-
const r = await playground.run({
58+
await playground.run({
5559
code: `<?php
56-
require ${phpVar(docroot)} . '/wp-load.php';
57-
require ${phpVar(docroot)} . '/wp-admin/includes/admin.php';
60+
require ${phpVar(docroot)} . '/wp-load.php';
61+
require ${phpVar(docroot)} . '/wp-admin/includes/admin.php';
5862
59-
// Defines the constants expected by the Box .phar stub when "cli" is used
60-
// as the SAPI name.
61-
// @TODO: Don't use the "cli" SAPI string and don't allow composer to run platform checks.
62-
if(!defined('STDERR')) {
63-
define('STDERR', fopen('php://stderr', 'w'));
64-
}
65-
if(!defined('STDIN')) {
66-
define('STDIN', fopen('php://stdin', 'r'));
67-
}
68-
if(!defined('STDOUT')) {
69-
define('STDOUT', fopen('php://stdout', 'w'));
70-
}
71-
// Preloaded by the Blueprint compile() function
72-
require '/internal/shared/data-liberation-core.phar';
63+
// Defines the constants expected by the Box .phar stub when "cli" is used
64+
// as the SAPI name.
65+
// @TODO: Don't use the "cli" SAPI string and don't allow composer to run platform checks.
66+
if(!defined('STDERR')) define('STDERR', fopen('php://stderr', 'w'));
67+
if(!defined('STDIN')) define('STDIN', fopen('php://stdin', 'r'));
68+
if(!defined('STDOUT')) define('STDOUT', fopen('php://stdout', 'w'));
69+
70+
// Preloaded by the Blueprint compile() function
71+
require '/internal/shared/data-liberation-core.phar';
7372
74-
$admin_id = get_users(array('role' => 'Administrator') )[0]->ID;
75-
wp_set_current_user( $admin_id );
73+
$admin_id = get_users(array('role' => 'Administrator') )[0]->ID;
74+
wp_set_current_user( $admin_id );
7675
77-
$new_site_url = get_site_url();
78-
$importer = WP_Stream_Importer::create_for_wxr_file(
79-
'/tmp/import.wxr',
80-
array(
81-
'new_site_url' => $new_site_url,
82-
)
83-
);
84-
while ( true ) {
85-
if ( true === $importer->next_step() ) {
86-
$mapping_candidates = $importer->get_site_url_mapping_candidates();
87-
if (count($mapping_candidates) > 0) {
88-
/**
89-
* Auto-maps the theme unit test attachments domain
90-
* to the wp-content/uploads directory on the current site.
91-
* @TODO: remove it before merging.
92-
*/
93-
$importer->add_site_url_mapping(
94-
$mapping_candidates[0],
95-
$new_site_url . '/wp-content/uploads'
76+
$new_site_url = get_site_url();
77+
$importer = WP_Stream_Importer::create_for_wxr_file(
78+
'/tmp/import.wxr',
79+
array(
80+
'new_site_url' => $new_site_url,
81+
)
82+
);
83+
$session = WP_Import_Session::create(
84+
array(
85+
'data_source' => 'wxr_file',
86+
'file_name' => '/tmp/import.wxr',
87+
)
88+
);
89+
while ( true ) {
90+
if ( true === $importer->next_step() ) {
91+
/**
92+
* We're ignoring any importing errors.
93+
* This script is a part of Blueprints and is expected to finish
94+
* without stopping. We won't be gathering additional user input
95+
* along the way. Instead, we'll just decide not to ignore the
96+
* errors.
97+
*
98+
* @TODO: Consider extracting this code into a CLI script and
99+
* using it here instead of this custom script. Note it's
100+
* about a simple CLI script, not a WP-CLI command, as the
101+
* latter would require downloading 5MB of WP-CLI code.
102+
*/
103+
switch ( $importer->get_stage() ) {
104+
case WP_Stream_Importer::STAGE_INITIAL:
105+
$message = 'Preparing content import';
106+
break;
107+
108+
case WP_Stream_Importer::STAGE_INDEX_ENTITIES:
109+
// Bump the total number of entities to import.
110+
$indexed = $session->count_all_total_entities();
111+
$message = 'Content import 1/4: Indexing records (' . $indexed . ' so far)';
112+
$session->create_frontloading_placeholders( $importer->get_indexed_assets_urls() );
113+
$session->bump_total_number_of_entities(
114+
$importer->get_indexed_entities_counts()
96115
);
97-
post_message_to_js(json_encode([
98-
'type' => 'console.log',
99-
'data' => $importer->get_site_url_mapping_candidates(),
100-
]));
101-
}
102-
// Note we're simply ignoring any frontloading errors.
103-
switch($importer->get_stage()) {
104-
case WP_Stream_Importer::STAGE_FRONTLOAD_ASSETS:
105-
$message = 'Frontloading assets';
106-
break;
107-
case WP_Stream_Importer::STAGE_IMPORT_ENTITIES:
108-
$message = 'Importing entities';
109-
break;
110-
default:
111-
$message = 'Stage: ' . $importer->get_stage();
112-
break;
113-
}
116+
break;
114117
115-
// Report progress to the UI
116-
// @TODO: Use a reporter that can report progress to the UI,
117-
// CLI, wp-admin page, and any other runtime.
118-
post_message_to_js(json_encode([
119-
'type' => 'import-wxr-progress',
120-
'progress' => $message,
121-
]));
122-
continue;
123-
}
124-
if ( $importer->advance_to_next_stage() ) {
125-
continue;
118+
case WP_Stream_Importer::STAGE_TOPOLOGICAL_SORT:
119+
$message = 'Content import 2/4: Indexing data';
120+
break;
121+
122+
case WP_Stream_Importer::STAGE_FRONTLOAD_ASSETS:
123+
$session->bump_frontloading_progress(
124+
$importer->get_frontloading_progress(),
125+
$importer->get_frontloading_events()
126+
);
127+
$nb_media = $session->count_awaiting_frontloading_placeholders();
128+
$message = 'Content import 3/4: Downloading media (' . $nb_media . ' remaining)';
129+
break;
130+
131+
case WP_Stream_Importer::STAGE_IMPORT_ENTITIES:
132+
$session->bump_imported_entities_counts(
133+
$importer->get_imported_entities_counts()
134+
);
135+
$nb_remaining_entities = $session->count_remaining_entities();
136+
$message = 'Content import 4/4: Inserting data (' . $nb_remaining_entities . ' remaining)';
137+
break;
138+
139+
default:
140+
$message = 'Importing content';
141+
break;
126142
}
127-
// Import finished
128-
break;
143+
144+
// Report progress to the UI
145+
post_message_to_js(json_encode([
146+
'type' => 'import-wxr-progress',
147+
'progress' => $message,
148+
]));
149+
continue;
150+
}
151+
if ( $importer->advance_to_next_stage() ) {
152+
continue;
129153
}
130-
`,
154+
// Import finished
155+
break;
156+
}
157+
`,
131158
});
132-
console.log(r.text);
133-
} catch (error) {
134-
console.dir('PHP error :(');
135-
console.error(error);
159+
} finally {
160+
await clearProgressListener();
136161
}
137162
};
Binary file not shown.

packages/playground/data-liberation/src/import/WP_Import_Session.php

+19
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,11 @@ public function count_all_total_entities() {
238238
return array_sum( array_column( $counts, 'total' ) );
239239
}
240240

241+
public function count_remaining_entities() {
242+
$counts = $this->count_imported_entities();
243+
return array_sum( array_column( $counts, 'total' ) ) - array_sum( array_column( $counts, 'imported' ) );
244+
}
245+
241246
/**
242247
* Cache of imported entity counts to avoid repeated database queries
243248
* @var array
@@ -287,6 +292,20 @@ public function bump_imported_entities_counts( $newly_imported_entities ) {
287292
}
288293
}
289294

295+
public function count_awaiting_frontloading_placeholders() {
296+
global $wpdb;
297+
return (int) $wpdb->get_var(
298+
$wpdb->prepare(
299+
"SELECT COUNT(*) FROM $wpdb->posts
300+
WHERE post_type = 'frontloading_placeholder'
301+
AND post_parent = %d
302+
AND post_status = %s",
303+
$this->post_id,
304+
self::FRONTLOAD_STATUS_AWAITING_DOWNLOAD,
305+
)
306+
);
307+
}
308+
290309
public function count_unfinished_frontloading_placeholders() {
291310
global $wpdb;
292311
return (int) $wpdb->get_var(

0 commit comments

Comments
 (0)