Skip to content

Commit 06ec18a

Browse files
authored
feat(content-distribution): migrator (#185)
1 parent c93084d commit 06ec18a

File tree

6 files changed

+639
-5
lines changed

6 files changed

+639
-5
lines changed

includes/class-accepted-actions.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class Accepted_Actions {
4242
'newspack_network_membership_plan_updated' => 'Membership_Plan_Updated',
4343
'network_post_updated' => 'Network_Post_Updated',
4444
'network_post_deleted' => 'Network_Post_Deleted',
45+
'newspack_network_distributor_migrate_incoming_posts' => 'Distributor_Migrate_Incoming_Posts',
4546
];
4647

4748
/**
@@ -65,5 +66,6 @@ class Accepted_Actions {
6566
'newspack_network_membership_plan_updated',
6667
'network_post_updated',
6768
'network_post_deleted',
69+
'newspack_network_distributor_migrate_incoming_posts',
6870
];
6971
}

includes/class-content-distribution.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Newspack_Network\Content_Distribution\Canonical_Url;
1616
use Newspack_Network\Content_Distribution\Incoming_Post;
1717
use Newspack_Network\Content_Distribution\Outgoing_Post;
18+
use Newspack_Network\Content_Distribution\Distributor_Migrator;
1819
use WP_Post;
1920

2021
/**
@@ -58,8 +59,8 @@ public static function init() {
5859
CLI::init();
5960
API::init();
6061
Editor::init();
61-
6262
Canonical_Url::init();
63+
Distributor_Migrator::init();
6364
}
6465

6566
/**

includes/content-distribution/class-cli.php

Lines changed: 133 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Newspack_Network\Utils\Network;
1212
use WP_CLI;
1313
use WP_CLI\ExitException;
14+
use WP_Error;
1415

1516
/**
1617
* Class Distribution.
@@ -38,13 +39,14 @@ public static function register_commands(): void {
3839
'newspack network distribute post',
3940
[ __CLASS__, 'cmd_distribute_post' ],
4041
[
41-
'shortdesc' => __( 'Distribute a post to all the network or the specified sites' ),
42+
'shortdesc' => __( 'Distribute a post to all the network or the specified sites', 'newspack-network' ),
4243
'synopsis' => [
4344
[
4445
'type' => 'positional',
4546
'name' => 'post-id',
4647
'description' => sprintf(
47-
'The ID of the post to distribute. Supported post types are: %s',
48+
// translators: %s: list of supported post types.
49+
__( 'The ID of the post to distribute. Supported post types are: %s', 'newspack-network' ),
4850
implode(
4951
', ',
5052
Content_Distribution::get_distributed_post_types()
@@ -56,7 +58,7 @@ public static function register_commands(): void {
5658
[
5759
'type' => 'assoc',
5860
'name' => 'sites',
59-
'description' => __( "Networked site url(s) comma separated to distribute the post to – or 'all' to distribute to all sites in the network." ),
61+
'description' => __( "Networked site url(s) comma separated to distribute the post to – or 'all' to distribute to all sites in the network.", 'newspack-network' ),
6062
'optional' => false,
6163
],
6264
[
@@ -68,6 +70,47 @@ public static function register_commands(): void {
6870
],
6971
]
7072
);
73+
WP_CLI::add_command(
74+
'newspack network distributor migrate',
75+
[ __CLASS__, 'cmd_distributor_migrate' ],
76+
[
77+
'shortdesc' => __( 'Migrate posts from Distributor to Newspack Network\'s content distribution', 'newspack-network' ),
78+
'synopsis' => [
79+
[
80+
'type' => 'positional',
81+
'name' => 'post-id',
82+
'description' => __( 'The ID of the post to migrate.', 'newspack-network' ),
83+
'repeating' => false,
84+
'optional' => true,
85+
],
86+
[
87+
'type' => 'flag',
88+
'name' => 'all',
89+
'description' => __( 'Migrate all posts.', 'newspack-network' ),
90+
'optional' => true,
91+
],
92+
[
93+
'type' => 'assoc',
94+
'name' => 'batch-size',
95+
'description' => __( 'Number of posts to migrate in each batch.', 'newspack-network' ),
96+
'optional' => true,
97+
'default' => 50,
98+
],
99+
[
100+
'type' => 'flag',
101+
'name' => 'strict',
102+
'description' => __( 'Whether to only migrate if all distributed posts can be migrated.', 'newspack-network' ),
103+
'optional' => true,
104+
],
105+
[
106+
'type' => 'flag',
107+
'name' => 'delete',
108+
'description' => __( 'Whether to deactivate and delete the Distributor plugin after migrating all posts. This will only take effect if all posts were able to migrate.', 'newspack-network' ),
109+
'optional' => true,
110+
],
111+
],
112+
]
113+
);
71114
}
72115

73116
/**
@@ -107,4 +150,91 @@ public function cmd_distribute_post( array $pos_args, array $assoc_args ): void
107150
WP_CLI::error( $e->getMessage() );
108151
}
109152
}
153+
154+
/**
155+
* Callback for the `newspack-network distributor migrate` command.
156+
*
157+
* @param array $pos_args Positional arguments.
158+
* @param array $assoc_args Associative arguments.
159+
*
160+
* @throws ExitException If something goes wrong.
161+
*/
162+
public function cmd_distributor_migrate( array $pos_args, array $assoc_args ): void {
163+
$post_id = $pos_args[0] ?? null;
164+
if ( ! is_numeric( $post_id ) && ! isset( $assoc_args['all'] ) ) {
165+
WP_CLI::error( 'Post ID must be a number.' );
166+
}
167+
168+
if ( is_numeric( $post_id ) && isset( $assoc_args['all'] ) ) {
169+
WP_CLI::error( 'The --all flag cannot be used with a post ID.' );
170+
}
171+
172+
if ( ! isset( $assoc_args['all'] ) && isset( $assoc_args['delete'] ) ) {
173+
WP_CLI::error( 'The --delete flag can only be used with the --all flag.' );
174+
}
175+
176+
if ( isset( $assoc_args['batch-size'] ) && ! is_numeric( $assoc_args['batch-size'] ) ) {
177+
WP_CLI::error( 'Batch size must be a number.' );
178+
}
179+
180+
if ( isset( $assoc_args['all'] ) ) {
181+
$strict = isset( $assoc_args['strict'] );
182+
183+
$post_ids = Distributor_Migrator::get_posts_with_distributor_subscriptions();
184+
185+
if ( empty( $post_ids ) ) {
186+
WP_CLI::success( 'No distributed posts found.' );
187+
return;
188+
}
189+
190+
WP_CLI::line( sprintf( 'Found %d posts.', count( $post_ids ) ) );
191+
192+
// In strict mode, only continue if all posts can be migrated.
193+
if ( $strict ) {
194+
$errors = [];
195+
foreach ( $post_ids as $post_id ) {
196+
$can_migrate = Distributor_Migrator::can_migrate_outgoing_post( $post_id );
197+
if ( is_wp_error( $can_migrate ) ) {
198+
$errors[] = sprintf( 'Unable to migrate post %d: %s', $post_id, $can_migrate->get_error_message() );
199+
}
200+
}
201+
if ( ! empty( $errors ) ) {
202+
WP_CLI::error( 'Strict mode is enabled: ' . PHP_EOL . implode( PHP_EOL, $errors ) );
203+
}
204+
}
205+
206+
// Migrate posts.
207+
$errors = new WP_Error();
208+
$batch_size = $assoc_args['batch-size'] ?? 50;
209+
$batches = array_chunk( $post_ids, $batch_size );
210+
211+
foreach ( $batches as $i => $batch ) {
212+
$result = Distributor_Migrator::migrate_outgoing_posts( $batch );
213+
if ( is_wp_error( $result ) ) {
214+
$message = sprintf( '(%d/%d) Error migrating batch: %s', $i + 1, count( $batches ), $result->get_error_message() );
215+
if ( $strict ) {
216+
WP_CLI::error( $message );
217+
} else {
218+
$errors->add( $result->get_error_code(), $result->get_error_message() );
219+
WP_CLI::line( $message );
220+
}
221+
} else {
222+
WP_CLI::line( sprintf( '(%d/%d) Batch migrated.', $i + 1, count( $batches ) ) );
223+
}
224+
}
225+
226+
if ( isset( $assoc_args['delete'] ) && ! $errors->has_errors() ) {
227+
deactivate_plugins( [ 'distributor/distributor.php' ] );
228+
delete_plugins( [ 'distributor/distributor.php' ] );
229+
WP_CLI::line( 'Distributor plugin is deactivated and deleted.' );
230+
}
231+
} else {
232+
$result = Distributor_Migrator::migrate_outgoing_post( $post_id );
233+
if ( is_wp_error( $result ) ) {
234+
WP_CLI::error( $result->get_error_message() );
235+
}
236+
}
237+
238+
WP_CLI::success( 'Migration completed.' );
239+
}
110240
}

0 commit comments

Comments
 (0)