PluginProbe
Redirection / 5.8.1
Redirection v5.8.1
5.10.0 5.9.0 5.8.1 5.8.0 3.7.2 3.7.3 4.0 4.0.1 4.1 4.1.1 4.2 4.2.1 4.2.2 4.2.3 4.3 4.3.1 4.3.2 4.3.3 4.4 4.4.1 4.4.2 4.5 4.5.1 4.6.2 4.7.1 All 130 releases
redirection / redirection-cli.php

redirection-cli.php in Redirection 5.8.1, at redirection-cli.php

434 lines 11.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Implements example command.
5 */
6 class Redirection_Cli extends WP_CLI_Command {
7 /**
8 * Resolve a group ID, or return the first available group.
9 *
10 * @param int $group_id Group ID, or 0 to auto-select the first group.
11 * @return int|false Group ID or false when not available.
12 */
13 private function get_group( $group_id ) {
14 if ( $group_id === 0 ) {
15 $groups = Red_Group::get_filtered( array() );
16
17 if ( count( $groups['items'] ) > 0 ) {
18 return $groups['items'][0]['id'];
19 }
20 } else {
21 $groups = Red_Group::get( $group_id );
22 if ( $groups !== false ) {
23 return $group_id;
24 }
25 }
26
27 return false;
28 }
29
30 /**
31 * Import from another plugin to Redirection.
32 *
33 * Supports:
34 * - wp-simple-redirect
35 * - seo-redirection
36 * - safe-redirect-manager
37 * - wordpress-old-slugs
38 * - rank-math
39 * - quick-redirects
40 *
41 * ## OPTIONS
42 *
43 * <name>
44 * : The plugin name to import from (see above)
45 *
46 * [--group=<groupid>]
47 * : The group ID to import into. Defaults to the first available group.
48 *
49 * ## EXAMPLES
50 *
51 * wp redirection plugin quick-redirects
52 *
53 * @param list<string> $args Positional arguments.
54 * @param array<string, mixed> $extra Associative flags.
55 * @return void
56 */
57 public function plugin( $args, $extra ) {
58 include_once __DIR__ . '/models/importer.php';
59
60 $name = $args[0];
61 $group = $this->get_group( isset( $extra['group'] ) ? intval( $extra['group'], 10 ) : 0 );
62
63 $importer = Red_Plugin_Importer::get_importer( $name );
64 if ( $importer !== false && $group !== false ) {
65 $count = $importer->import_plugin( $group );
66 WP_CLI::success( sprintf( 'Imported %d redirects from plugin %s', $count, $name ) );
67 return;
68 }
69
70 WP_CLI::error( 'Invalid plugin name' );
71 }
72
73 /**
74 * Get or set a Redirection setting
75 *
76 * ## OPTIONS
77 *
78 * <name>
79 * : The setting name to get or set
80 *
81 * [--set=<value>]
82 * : The value to set. Use true/false for boolean settings, or JSON for complex values.
83 *
84 * [--verbose]
85 * : Display setting name along with value (e.g., "flag_case: true" instead of just "true")
86 *
87 * ## EXAMPLES
88 *
89 * wp redirection setting flag_case
90 * wp redirection setting flag_case --verbose
91 * wp redirection setting flag_case --set=true
92 * wp redirection setting cache_key --set=false
93 * wp redirection setting aliases --set='["example.com"]'
94 *
95 * @param list<string> $args Positional arguments.
96 * @param array<string, mixed> $extra Associative flags.
97 * @return void
98 */
99 public function setting( $args, $extra ) {
100 $name = $args[0];
101 $set = isset( $extra['set'] ) ? $extra['set'] : null;
102 $verbose = isset( $extra['verbose'] );
103
104 $options = Red_Options::get();
105
106 if ( ! array_key_exists( $name, $options ) ) {
107 WP_CLI::error( 'Unsupported setting: ' . $name );
108 return;
109 }
110
111 $old_value = $options[ $name ];
112
113 if ( $set !== null ) {
114 if ( ! is_string( $set ) ) {
115 WP_CLI::error( 'No value provided for --set; please provide a value, for example: --set=true or --set=\'["example.com"]\'.' );
116 return;
117 }
118
119 $decoded = $this->parse_setting_value( $set );
120
121 $update = [];
122 $update[ $name ] = $decoded;
123
124 $options = Red_Options::save( $update );
125 $new_value = array_key_exists( $name, $options ) ? $options[ $name ] : null;
126
127 $this->display_setting_result( $name, $old_value, $new_value );
128 return;
129 }
130
131 // Just display the current value
132 $this->display_setting_value( $name, $old_value, $verbose );
133 }
134
135 /**
136 * Parse a setting value from CLI input.
137 *
138 * @param string $value The raw CLI value.
139 * @return mixed The parsed value.
140 */
141 private function parse_setting_value( $value ) {
142 // Handle explicit boolean strings
143 if ( $value === 'true' ) {
144 return true;
145 }
146 if ( $value === 'false' ) {
147 return false;
148 }
149
150 // Try JSON decode for arrays/objects (but not null, which should be literal string "null")
151 $decoded = json_decode( $value, true );
152 if ( $decoded !== null ) {
153 return $decoded;
154 }
155
156 // Return as-is (string value, including literal "null")
157 return $value;
158 }
159
160 /**
161 * Display a setting value.
162 *
163 * @param string $name Setting name.
164 * @param mixed $value Setting value.
165 * @param bool $verbose Whether to include setting name in output.
166 * @return void
167 */
168 private function display_setting_value( $name, $value, $verbose = false ) {
169 $display = $this->format_value_for_display( $value );
170 if ( $verbose ) {
171 WP_CLI::success( sprintf( '%s: %s', $name, $display ) );
172 } else {
173 WP_CLI::success( $display );
174 }
175 }
176
177 /**
178 * Display the result of setting a value.
179 *
180 * @param string $name Setting name.
181 * @param mixed $old_value Previous value.
182 * @param mixed $new_value New value.
183 * @return void
184 */
185 private function display_setting_result( $name, $old_value, $new_value ) {
186 $old_display = $this->format_value_for_display( $old_value );
187 $new_display = $this->format_value_for_display( $new_value );
188
189 // Compare raw values to avoid issues with formatted display strings
190 if ( $old_value === $new_value ) {
191 WP_CLI::success( sprintf( '%s is already set to: %s', $name, $new_display ) );
192 } else {
193 WP_CLI::success( sprintf( '%s updated: %s → %s', $name, $old_display, $new_display ) );
194 }
195 }
196
197 /**
198 * Format a value for display in CLI output.
199 *
200 * @param mixed $value The value to format.
201 * @return string Formatted string for display.
202 */
203 private function format_value_for_display( $value ) {
204 if ( is_bool( $value ) ) {
205 return $value ? 'true' : 'false';
206 }
207 if ( is_array( $value ) ) {
208 $encoded = wp_json_encode( $value );
209 return is_string( $encoded ) ? $encoded : '[]';
210 }
211 if ( $value === '' ) {
212 return '(empty)';
213 }
214 return (string) $value;
215 }
216
217 /**
218 * Import redirections from a JSON, CSV, or .htaccess file
219 *
220 * ## OPTIONS
221 *
222 * <file>
223 * : The name of the file to import.
224 *
225 * [--group=<groupid>]
226 * : The group ID to import into. Defaults to the first available group. JSON
227 * contains it's own group
228 *
229 * [--format=<importformat>]
230 * : The import format - csv, apache, or json. Defaults to json
231 *
232 * ## EXAMPLES
233 *
234 * wp redirection import .htaccess --format=apache
235 *
236 * @param list<string> $args Positional arguments.
237 * @param array<string, mixed> $extra Associative flags.
238 * @return void
239 */
240 public function import( $args, $extra ) {
241 $format = isset( $extra['format'] ) ? $extra['format'] : 'json';
242 $group = $this->get_group( isset( $extra['group'] ) ? intval( $extra['group'], 10 ) : 0 );
243
244 if ( $group === false ) {
245 WP_CLI::error( 'Invalid group' );
246 return;
247 }
248
249 $importer = Red_FileIO::create( $format );
250
251 if ( $importer === false ) {
252 WP_CLI::error( 'Invalid import format - csv, json, or apache supported' );
253 return;
254 }
255
256 if ( $format === 'csv' ) {
257 $file = fopen( $args[0], 'r' );
258
259 if ( $file !== false ) {
260 $count = $importer->load( $group, $args[0], '' );
261
262 WP_CLI::success( 'Imported ' . $count . ' as ' . $format );
263 } else {
264 WP_CLI::error( 'Invalid import file' );
265 }
266 } else {
267 $data = @file_get_contents( $args[0] );
268
269 if ( $data !== false ) {
270 $count = $importer->load( $group, $args[0], $data );
271 WP_CLI::success( 'Imported ' . $count . ' redirects as ' . $format );
272 } else {
273 WP_CLI::error( 'Invalid import file' );
274 }
275 }
276 }
277
278 /**
279 * Export redirections to a CSV, JSON, .htaccess, or rewrite.rules file
280 *
281 * ## OPTIONS
282 *
283 * <module>
284 * : The module to export - wordpress, apache, nginx, or all
285 *
286 * <filename>
287 * : The file to export to, or - for stdout
288 *
289 * [--format=<exportformat>]
290 * : The export format. One of json, csv, apache, or nginx. Defaults to json
291 *
292 * ## EXAMPLES
293 *
294 * wp redirection export wordpress --format=apache
295 *
296 * @param list<string> $args Positional arguments.
297 * @param array<string, mixed> $extra Associative flags.
298 * @return void
299 */
300 public function export( $args, $extra ) {
301 $format = isset( $extra['format'] ) ? $extra['format'] : 'json';
302 $exporter = Red_FileIO::create( $format );
303
304 if ( $exporter === false ) {
305 WP_CLI::error( 'Invalid export format - json, csv, apache, or nginx supported' );
306 return;
307 }
308
309 $file = fopen( $args[1] === '-' ? 'php://stdout' : $args[1], 'w' );
310 if ( $file !== false ) {
311 $export = Red_FileIO::export( $args[0], $format );
312
313 if ( $export === false ) {
314 // phpcs:ignore
315 WP_CLI::error( 'Invalid module - must be wordpress, apache, nginx, or all' );
316 return;
317 }
318
319 fwrite( $file, $export['data'] );
320 fclose( $file );
321
322 WP_CLI::success( 'Exported ' . $export['total'] . ' to ' . $format );
323 } else {
324 WP_CLI::error( 'Invalid output file' );
325 }
326 }
327
328 /**
329 * Perform Redirection database actions
330 *
331 * ## OPTIONS
332 *
333 * <action>
334 * : The database action to perform: install, remove, upgrade
335 *
336 * [--skip-errors]
337 * : Skip errors and keep on upgrading
338 *
339 * ## EXAMPLES
340 *
341 * wp redirection database install
342 *
343 * @param list<string> $args Positional arguments.
344 * @param array<string, mixed> $extra Associative flags.
345 * @return void
346 */
347 public function database( $args, $extra ) {
348 $skip = isset( $extra['skip-errors'] ) ? true : false;
349
350 if ( count( $args ) === 0 || ! in_array( $args[0], array( 'install', 'remove', 'upgrade' ), true ) ) {
351 WP_CLI::error( 'Invalid database action - please use install, remove, or upgrade' );
352 return;
353 }
354
355 if ( $args[0] === 'install' ) {
356 Red_Database::apply_to_sites(
357 function () {
358 $latest = Red_Database::get_latest_database();
359 $latest->install();
360
361 WP_CLI::success( 'Site ' . get_current_blog_id() . ' database is installed' );
362 }
363 );
364
365 WP_CLI::success( 'Database install finished' );
366 } elseif ( $args[0] === 'upgrade' ) {
367 global $wpdb;
368
369 $wpdb->show_errors( false );
370
371 Red_Database::apply_to_sites(
372 function () use ( $skip ) {
373 $database = new Red_Database();
374 $status = new Red_Database_Status();
375
376 if ( ! $status->needs_updating() ) {
377 WP_CLI::success( 'Site ' . get_current_blog_id() . ' database is already the latest version' );
378 return;
379 }
380
381 $loop = 0;
382
383 while ( $loop < 50 ) {
384 $database->apply_upgrade( $status );
385 $info = $status->get_json();
386
387 if ( ! $info['inProgress'] ) {
388 break;
389 }
390
391 if ( isset( $info['result'] ) && $info['result'] === 'error' && isset( $info['reason'] ) && isset( $info['debug'] ) ) {
392 if ( $skip === false ) {
393 WP_CLI::error( 'Site ' . get_current_blog_id() . ' database failed to upgrade: ' . $info['reason'] . ' - ' . $info['debug'][0] );
394 return;
395 }
396
397 WP_CLI::warning( 'Site ' . get_current_blog_id() . ' database failed to upgrade: ' . $info['reason'] . ' - ' . $info['debug'][0] );
398 $status->set_next_stage();
399 }
400
401 $loop++;
402 }
403
404 WP_CLI::success( 'Site ' . get_current_blog_id() . ' database upgraded' );
405 }
406 );
407
408 WP_CLI::success( 'Database upgrade finished' );
409 } elseif ( $args[0] === 'remove' ) {
410 Red_Database::apply_to_sites(
411 function () {
412 $latest = Red_Database::get_latest_database();
413 $latest->remove();
414 }
415 );
416
417 WP_CLI::success( 'Database removed' );
418 }
419 }
420 }
421
422 if ( defined( 'WP_CLI' ) && WP_CLI ) {
423 // Register "redirection" as top-level command, and all public methods as sub-commands
424 WP_CLI::add_command( 'redirection', 'Redirection_Cli' );
425
426 add_action(
427 Red_Flusher::DELETE_HOOK,
428 function () {
429 $flusher = new Red_Flusher();
430 $flusher->flush();
431 }
432 );
433 }
434