PluginProbe
Redirection / 5.6.0
Redirection v5.6.0
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-admin.php

redirection-admin.php in Redirection 5.6.0, at redirection-admin.php

871 lines 24.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 require_once __DIR__ . '/models/monitor.php';
4 require_once __DIR__ . '/models/file-io.php';
5 require_once __DIR__ . '/database/database.php';
6 require_once __DIR__ . '/redirection-capabilities.php';
7
8 class Redirection_Admin {
9 /**
10 * @var Redirection_Admin|null
11 */
12 private static $instance = null;
13
14 /**
15 * @var Red_Monitor|null
16 * @phpstan-ignore property.onlyWritten
17 */
18 private $monitor;
19
20 /**
21 * @var WP_Error|false
22 */
23 private $fixit_failed = false;
24
25 /**
26 * @return Redirection_Admin|null
27 */
28 public static function init() {
29 if ( is_null( self::$instance ) ) {
30 self::$instance = new Redirection_Admin();
31 }
32
33 return self::$instance;
34 }
35
36 public function __construct() {
37 add_action( 'admin_menu', [ $this, 'admin_menu' ] );
38 add_action( 'admin_notices', [ $this, 'update_nag' ] );
39 add_filter( 'plugin_action_links_' . basename( dirname( REDIRECTION_FILE ) ) . '/' . basename( REDIRECTION_FILE ), [ $this, 'plugin_settings' ] );
40 add_filter( 'plugin_row_meta', [ $this, 'plugin_row_meta' ], 10, 4 );
41 add_filter( 'redirection_save_options', [ $this, 'flush_schedule' ] );
42 add_filter( 'set-screen-option', [ $this, 'set_per_page' ], 10, 3 );
43 add_filter(
44 'set_screen_option_redirection_log_per_page',
45 function ( $ignore, $option, $value ) {
46 return $value;
47 },
48 10,
49 3
50 );
51 add_action( 'redirection_redirect_updated', [ $this, 'set_default_group' ], 10, 2 );
52 add_action( 'redirection_redirect_updated', [ $this, 'clear_cache' ] );
53
54 if ( defined( 'REDIRECTION_FLYING_SOLO' ) && REDIRECTION_FLYING_SOLO ) {
55 add_filter( 'script_loader_src', [ $this, 'flying_solo' ], 10, 2 );
56 }
57
58 register_deactivation_hook( REDIRECTION_FILE, [ 'Redirection_Admin', 'plugin_deactivated' ] );
59 register_uninstall_hook( REDIRECTION_FILE, [ 'Redirection_Admin', 'plugin_uninstall' ] );
60
61 $this->monitor = new Red_Monitor( Red_Options::get() );
62 $this->run_hacks();
63 }
64
65 /**
66 * These are only called on the single standard site, or in the network admin of the multisite - they run across all available sites
67 * @return void
68 */
69 public static function plugin_activated() {
70 Red_Database::apply_to_sites(
71 function () {
72 Red_Flusher::clear();
73 red_set_options();
74 }
75 );
76 }
77
78 /**
79 * These are only called on the single standard site, or in the network admin of the multisite - they run across all available sites
80 * @return void
81 */
82 public static function plugin_deactivated() {
83 Red_Database::apply_to_sites(
84 function () {
85 Red_Flusher::clear();
86 }
87 );
88 }
89
90 /**
91 * These are only called on the single standard site, or in the network admin of the multisite - they run across all available sites
92 * @return void
93 */
94 public static function plugin_uninstall() {
95 $database = Red_Database::get_latest_database();
96
97 Red_Database::apply_to_sites(
98 function () use ( $database ) {
99 $database->remove();
100 }
101 );
102 }
103
104 /**
105 * Show the database upgrade nag
106 *
107 * @return void
108 */
109 public function update_nag() {
110 $options = Red_Options::get();
111
112 // Is the site configured to upgrade automatically?
113 if ( $options['plugin_update'] === 'admin' ) {
114 $this->automatic_upgrade();
115 return;
116 }
117
118 // Can the user perform a manual database upgrade?
119 if ( ! Redirection_Capabilities::has_access( Redirection_Capabilities::CAP_OPTION_MANAGE ) ) {
120 return;
121 }
122
123 // Default manual update, with nag
124 $status = new Red_Database_Status();
125
126 $message = false;
127 if ( $status->needs_installing() ) {
128 /* translators: 1: URL to plugin page */
129 $message = sprintf( __( 'Please complete your <a href="%s">Redirection setup</a> to activate the plugin.', 'redirection' ), esc_url( $this->get_plugin_url() ) );
130 } elseif ( $status->needs_updating() ) {
131 /* translators: 1: URL to plugin page, 2: current version, 3: target version */
132 $message = sprintf( __( 'Redirection\'s database needs to be updated - <a href="%1$1s">click to update</a>.', 'redirection' ), esc_url( $this->get_plugin_url() ) );
133 }
134
135 if ( $message === false || strpos( Redirection_Request::get_request_url(), 'page=redirection.php' ) !== false ) {
136 return;
137 }
138
139 // Known HTML and so isn't escaped
140 // phpcs:ignore
141 echo '<div class="update-nag notice notice-warning" style="width: 95%">' . $message . '</div>';
142 }
143
144 /**
145 * Perform an automatic DB upgrade
146 *
147 * @return void
148 */
149 private function automatic_upgrade() {
150 $loop = 0;
151 $status = new Red_Database_Status();
152 $database = new Red_Database();
153
154 // Loop until the DB is upgraded, or until a max is exceeded (just in case)
155 while ( $loop < 20 ) {
156 if ( ! $status->needs_updating() ) {
157 break;
158 }
159
160 $database->apply_upgrade( $status );
161
162 if ( $status->is_error() ) {
163 // If an error occurs then switch to 'prompt' mode and let the user deal with it.
164 red_set_options( [ 'plugin_update' => 'prompt' ] );
165 return;
166 }
167
168 $loop++;
169 }
170 }
171
172
173 /**
174 * So it finally came to this... some plugins include their JS in all pages, whether they are needed or not. If there is an error
175 * then this can prevent Redirection running and it's a little sensitive about that. We use the nuclear option here to disable
176 * all other JS while viewing Redirection
177 * @param string $src
178 * @param string $handle
179 * @return string|false
180 */
181 public function flying_solo( $src, $handle ) {
182 $request = Redirection_Request::get_request_url();
183
184 if ( strpos( $request, 'page=redirection.php' ) !== false ) {
185 if ( substr( $src, 0, 4 ) === 'http' && $handle !== 'redirection' && strpos( $src, 'plugins' ) !== false ) {
186 if ( $this->ignore_this_plugin( $src ) ) {
187 return false;
188 }
189 }
190 }
191
192 return $src;
193 }
194
195 /**
196 * @param string $src
197 * @return bool
198 */
199 private function ignore_this_plugin( $src ) {
200 $ignore = array(
201 'mootools',
202 'wp-seo-',
203 'authenticate',
204 'wordpress-seo',
205 'yikes',
206 );
207
208 foreach ( $ignore as $text ) {
209 if ( strpos( $src, $text ) !== false ) {
210 return true;
211 }
212 }
213
214 return false;
215 }
216
217 /**
218 * @param mixed $options
219 * @return mixed
220 */
221 public function flush_schedule( $options ) {
222 Red_Flusher::schedule();
223 return $options;
224 }
225
226 /**
227 * @param mixed $status
228 * @param mixed $option
229 * @param mixed $value
230 * @return mixed
231 */
232 public function set_per_page( $status, $option, $value ) {
233 if ( $option === 'redirection_log_per_page' ) {
234 $value = max( 1, min( intval( $value, 10 ), Red_Log::MAX_PER_PAGE ) );
235 return $value;
236 }
237
238 return $status;
239 }
240
241 /**
242 * @param array<int|string, string> $links
243 * @return array<int|string, string>
244 */
245 public function plugin_settings( array $links ): array {
246 $status = new Red_Database_Status();
247 if ( $status->needs_updating() ) {
248 array_unshift( $links, '<a style="color: red" href="' . esc_url( $this->get_plugin_url() ) . '&amp;sub=support">' . __( 'Upgrade Database', 'redirection' ) . '</a>' );
249 }
250
251 array_unshift( $links, '<a href="' . esc_url( $this->get_plugin_url() ) . '&amp;sub=options">' . __( 'Settings', 'redirection' ) . '</a>' );
252 return $links;
253 }
254
255 /**
256 * @param mixed $plugin_meta
257 * @param mixed $plugin_file
258 * @param mixed $plugin_data
259 * @param mixed $status
260 * @return mixed
261 */
262 public function plugin_row_meta( $plugin_meta, $plugin_file, $plugin_data, $status ) {
263 if ( $plugin_file === basename( dirname( REDIRECTION_FILE ) ) . '/' . basename( REDIRECTION_FILE ) ) {
264 $plugin_data['Description'] .= '<p>' . __( 'Please upgrade your database', 'redirection' ) . '</p>';
265 }
266
267 return $plugin_meta;
268 }
269
270 /**
271 * @return string
272 */
273 private function get_plugin_url() {
274 return admin_url( 'tools.php?page=' . basename( REDIRECTION_FILE ) );
275 }
276
277 /**
278 * @return string
279 */
280 private function get_first_available_page_url() {
281 $pages = Redirection_Capabilities::get_available_pages();
282
283 if ( count( $pages ) > 0 ) {
284 return $this->get_plugin_url() . ( $pages[0] === 'redirect' ? '' : '&sub=' . rawurlencode( $pages[0] ) );
285 }
286
287 return admin_url();
288 }
289
290 /**
291 * @param mixed $name
292 * @return string|null
293 */
294 private function get_query( $name ) {
295 if ( isset( $_GET[ $name ] ) ) {
296 return sanitize_text_field( $_GET[ $name ] );
297 }
298
299 return null;
300 }
301
302 /**
303 * @return void
304 */
305 public function redirection_head() {
306 global $wp_version;
307
308 // Does user have access to this page?
309 if ( $this->get_current_page() === false ) {
310 // Redirect to root plugin page
311 wp_safe_redirect( $this->get_first_available_page_url() );
312 die();
313 }
314
315 if ( isset( $_REQUEST['action'] ) && isset( $_REQUEST['_wpnonce'] ) && is_string( $_REQUEST['action'] ) && wp_verify_nonce( $_REQUEST['_wpnonce'], 'wp_rest' ) !== false ) {
316 $action = sanitize_text_field( $_REQUEST['action'] );
317
318 if ( $action === 'fixit' ) {
319 $this->run_fixit();
320 } elseif ( $action === 'rest_api' && isset( $_REQUEST['rest_api'] ) && is_string( $_REQUEST['rest_api'] ) ) {
321 $this->set_rest_api( intval( $_REQUEST['rest_api'], 10 ) );
322 }
323 }
324
325 $build = REDIRECTION_VERSION . '-' . REDIRECTION_BUILD;
326 $preload = $this->get_preload_data();
327 $options = Red_Options::get();
328 $versions = array(
329 'Plugin: ' . REDIRECTION_VERSION . ' ' . REDIRECTION_DB_VERSION,
330 'WordPress: ' . $wp_version . ' (' . ( is_multisite() ? 'multi' : 'single' ) . ')',
331 'PHP: ' . phpversion(),
332 'Browser: ' . Redirection_Request::get_user_agent(),
333 'JavaScript: ' . plugin_dir_url( REDIRECTION_FILE ) . 'build/redirection.js?ver=' . $build,
334 'REST API: ' . red_get_rest_api(),
335 );
336
337 $this->inject();
338
339 // Add contextual help to some pages
340 if ( in_array( $this->get_current_page(), [ 'redirect', 'log', '404s', 'groups' ], true ) ) {
341 add_screen_option(
342 'per_page',
343 array(
344 /* translators: maximum number of log entries */
345 'label' => sprintf( __( 'Log entries (%d max)', 'redirection' ), Red_Log::MAX_PER_PAGE ),
346 'default' => Red_Log::DEFAULT_PER_PAGE,
347 'option' => 'redirection_log_per_page',
348 )
349 );
350 }
351
352 $assets = include plugin_dir_path( REDIRECTION_FILE ) . 'build/redirection.asset.php';
353 $dependencies = $assets['dependencies'];
354 $version = $assets['version'];
355
356 wp_enqueue_script( 'redirection', plugin_dir_url( REDIRECTION_FILE ) . 'build/redirection.js', $dependencies, $version, true );
357 wp_enqueue_style( 'redirection', plugin_dir_url( REDIRECTION_FILE ) . 'build/redirection.css', [], $version );
358
359 $is_new = false;
360 $major_version = implode( '.', array_slice( explode( '.', REDIRECTION_VERSION ), 0, 2 ) );
361
362 if ( $this->get_query( 'page' ) === 'redirection.php' && strpos( REDIRECTION_VERSION, '-beta' ) === false ) {
363 $is_new = version_compare( (string) $options['update_notice'], $major_version ) < 0;
364 }
365
366 $status = new Red_Database_Status();
367 $status->check_tables_exist();
368
369 // Fix some sites having a version set to +OK - not sure why
370 if ( $options['database'] === '+OK' ) {
371 red_set_options( [ 'database' => REDIRECTION_DB_VERSION ] );
372 $status->stop_update();
373 }
374
375 wp_localize_script(
376 'redirection',
377 'Redirectioni10n',
378 array(
379 'api' => [
380 'WP_API_root' => esc_url_raw( red_get_rest_api() ),
381 'WP_API_nonce' => wp_create_nonce( 'wp_rest' ),
382 'site_health' => admin_url( 'site-health.php' ),
383 'current' => $options['rest_api'],
384 'routes' => [
385 Red_Options::API_JSON => red_get_rest_api( Red_Options::API_JSON ),
386 Red_Options::API_JSON_INDEX => red_get_rest_api( Red_Options::API_JSON_INDEX ),
387 Red_Options::API_JSON_RELATIVE => red_get_rest_api( Red_Options::API_JSON_RELATIVE ),
388 ],
389 ],
390 'pluginBaseUrl' => plugins_url( '', REDIRECTION_FILE ),
391 'pluginRoot' => $this->get_plugin_url(),
392 'per_page' => $this->get_per_page(),
393 'locale' => implode( '-', array_slice( explode( '-', str_replace( '_', '-', get_locale() ) ), 0, 2 ) ),
394 'settings' => $options,
395 'preload' => $preload,
396 'versions' => implode( "\n", $versions ),
397 'version' => REDIRECTION_VERSION,
398 'database' => $status->get_json(),
399 'caps' => [
400 'pages' => Redirection_Capabilities::get_available_pages(),
401 'capabilities' => Redirection_Capabilities::get_all_capabilities(),
402 ],
403 'update_notice' => $is_new ? $major_version : false,
404 )
405 );
406
407 wp_set_script_translations( 'redirection', 'redirection' );
408
409 $this->add_help_tab();
410 }
411
412 /**
413 * Some plugins misbehave, so this attempts to 'fix' them so Redirection can get on with it's work
414 * @return void
415 */
416 private function run_hacks() {
417 add_filter( 'ip-geo-block-admin', array( $this, 'ip_geo_block' ) );
418 }
419
420 /**
421 * This works around the IP Geo Block plugin being very aggressive and breaking Redirection
422 *
423 * @param array<string, mixed> $validate
424 * @return array<string, mixed>
425 */
426 public function ip_geo_block( array $validate ): array {
427 $url = Redirection_Request::get_request_url();
428 $override = array(
429 'tools.php?page=redirection.php',
430 'action=red_proxy&rest_path=redirection',
431 );
432
433 foreach ( $override as $path ) {
434 if ( strpos( $url, $path ) !== false ) {
435 return array(
436 'result' => 'passed',
437 'auth' => false,
438 'asn' => false,
439 'code' => false,
440 'ip' => false,
441 );
442 }
443 }
444
445 return $validate;
446 }
447
448 /**
449 * @return void
450 */
451 private function run_fixit() {
452 if ( Redirection_Capabilities::has_access( Redirection_Capabilities::CAP_SUPPORT_MANAGE ) ) {
453 require_once dirname( REDIRECTION_FILE ) . '/models/fixer.php';
454
455 $fixer = new Red_Fixer();
456 $result = $fixer->fix( $fixer->get_status() );
457
458 if ( is_wp_error( $result ) ) {
459 $this->fixit_failed = $result;
460 }
461 }
462 }
463
464 /**
465 * @param mixed $api
466 * @return void
467 */
468 private function set_rest_api( $api ) {
469 if ( $api >= 0 && $api <= Red_Options::API_JSON_RELATIVE ) {
470 red_set_options( array( 'rest_api' => intval( $api, 10 ) ) );
471 }
472 }
473
474 /**
475 * @return array{importers: list<array{id: string, name: string, total: int}>}|array{pluginStatus: array<string, mixed>}|array{}
476 */
477 private function get_preload_data(): array {
478 $status = new Red_Database_Status();
479
480 if ( $status->needs_installing() ) {
481 include_once __DIR__ . '/models/importer.php';
482
483 return [
484 'importers' => Red_Plugin_Importer::get_plugins(),
485 ];
486 }
487
488 if ( $this->get_current_page() === 'support' ) {
489 require_once dirname( REDIRECTION_FILE ) . '/models/fixer.php';
490
491 $fixer = new Red_Fixer();
492
493 return array(
494 'pluginStatus' => $fixer->get_json(),
495 );
496 }
497
498 return [];
499 }
500
501 /**
502 * @return void
503 */
504 private function add_help_tab() {
505 /* translators: URL */
506 $content = sprintf( __( 'You can find full documentation about using Redirection on the <a href="%s" target="_blank">redirection.me</a> support site.', 'redirection' ), 'https://redirection.me/support/?utm_source=redirection&utm_medium=plugin&utm_campaign=context-help' );
507 $title = __( 'Redirection Support', 'redirection' );
508
509 $current_screen = get_current_screen();
510 if ( $current_screen === null ) {
511 return;
512 }
513
514 $current_screen->add_help_tab(
515 array(
516 'id' => 'redirection',
517 'title' => 'Redirection',
518 'content' => "<h2>$title</h2><p>$content</p>",
519 )
520 );
521 }
522
523 /**
524 * @return int
525 */
526 private function get_per_page() {
527 $per_page = intval( get_user_meta( get_current_user_id(), 'redirection_log_per_page', true ), 10 );
528
529 return $per_page > 0 ? max( 5, min( $per_page, Red_Log::MAX_PER_PAGE ) ) : Red_Log::DEFAULT_PER_PAGE;
530 }
531
532 /**
533 * @return void
534 */
535 public function admin_menu() {
536 $hook = add_management_page( 'Redirection', 'Redirection', Redirection_Capabilities::get_plugin_access(), basename( REDIRECTION_FILE ), [ $this, 'admin_screen' ] );
537 add_action( 'load-' . $hook, [ $this, 'redirection_head' ] );
538 }
539
540 /**
541 * @return bool
542 */
543 private function check_minimum_wp() {
544 $wp_version = get_bloginfo( 'version' );
545
546 if ( version_compare( $wp_version, REDIRECTION_MIN_WP, '<' ) ) {
547 return false;
548 }
549
550 return true;
551 }
552
553 /**
554 * Update the cache key when updating or creating a redirect
555 *
556 * @return void
557 */
558 public function clear_cache() {
559 $settings = Red_Options::get();
560
561 if ( $settings['cache_key'] > 0 ) {
562 red_set_options( [ 'cache_key' => time() ] );
563 }
564 }
565
566 /**
567 * @param mixed $id
568 * @param mixed $redirect
569 * @return void
570 */
571 public function set_default_group( $id, $redirect ) {
572 red_set_options( array( 'last_group_id' => $redirect->get_group_id() ) );
573 }
574
575 /**
576 * @return void
577 */
578 public function admin_screen() {
579 if ( count( Redirection_Capabilities::get_all_capabilities() ) === 0 ) {
580 die( 'You do not have sufficient permissions to access this page.' );
581 }
582
583 if ( $this->check_minimum_wp() === false ) {
584 $this->show_minimum_wordpress();
585 return;
586 }
587
588 if ( $this->fixit_failed instanceof WP_Error ) {
589 $this->show_fixit_failed();
590 }
591
592 Red_Flusher::schedule();
593
594 $this->show_main();
595 }
596
597 /**
598 * @return void
599 */
600 private function show_fixit_failed() {
601 if ( $this->fixit_failed === false ) {
602 return;
603 }
604 ?>
605 <div class="notice notice-error">
606 <h1><?php echo esc_html( $this->fixit_failed->get_error_message() ); ?></h1>
607 <p><?php echo esc_html( $this->fixit_failed->get_error_data() ); ?></p>
608 </div>
609 <?php
610 }
611
612 /**
613 * @return void
614 */
615 private function show_minimum_wordpress() {
616 global $wp_version;
617
618 /* translators: 1: Expected WordPress version, 2: Actual WordPress version */
619 $wp_requirement = sprintf( __( 'Redirection requires WordPress v%1$1s, you are using v%2$2s - please update your WordPress', 'redirection' ), REDIRECTION_MIN_WP, $wp_version );
620 ?>
621 <div class="react-error">
622 <h1><?php esc_html_e( 'Unable to load Redirection', 'redirection' ); ?></h1>
623 <p><?php echo esc_html( $wp_requirement ); ?></p>
624 </div>
625 <?php
626 }
627
628 /**
629 * @return void
630 */
631 private function show_load_fail() {
632 ?>
633 <div class="react-error" style="display: none">
634 <h1><?php esc_html_e( 'Unable to load Redirection ☹️', 'redirection' ); ?> v<?php echo esc_html( REDIRECTION_VERSION ); ?></h1>
635 <p><?php esc_html_e( "This may be caused by another plugin - look at your browser's error console for more details.", 'redirection' ); ?></p>
636 <p><?php esc_html_e( 'If you are using a page caching plugin or service (CloudFlare, OVH, etc) then you can also try clearing that cache.', 'redirection' ); ?></p>
637 <p>
638 <?php
639 echo wp_kses_post(
640 sprintf(
641 /* translators: %s: redirection script filename */
642 __( 'Also check if your browser is able to load %s:', 'redirection' ),
643 '<code>' . esc_html( 'redirection.js' ) . '</code>'
644 )
645 );
646 ?>
647 </p>
648 <p><code><?php echo esc_html( plugin_dir_url( REDIRECTION_FILE ) . 'redirection.js?ver=' . rawurlencode( REDIRECTION_VERSION ) . '-' . rawurlencode( REDIRECTION_BUILD ) ); ?></code></p>
649 <p><?php esc_html_e( 'Please note that Redirection requires the WordPress REST API to be enabled. If you have disabled this then you won\'t be able to use Redirection', 'redirection' ); ?></p>
650 <p>
651 <?php
652 echo wp_kses_post(
653 sprintf(
654 /* translators: %s: URL to common problems documentation */
655 __( 'Please see the <a href="%s">list of common problems</a>.', 'redirection' ),
656 esc_url( 'https://redirection.me/support/problems/' )
657 )
658 );
659 ?>
660 </p>
661 <p><?php esc_html_e( 'If you think Redirection is at fault then create an issue.', 'redirection' ); ?></p>
662 <p class="versions">
663 <?php
664 echo wp_kses_post(
665 __( '<code>Redirectioni10n</code> is not defined. This usually means another plugin is blocking Redirection from loading. Please disable all plugins and try again.', 'redirection' )
666 );
667 ?>
668 </p>
669 <p>
670 <a class="button-primary" target="_blank" href="https://github.com/johngodley/redirection/issues/new?title=Problem%20starting%20Redirection%20<?php echo esc_attr( REDIRECTION_VERSION ); ?>">
671 <?php esc_html_e( 'Create Issue', 'redirection' ); ?>
672 </a>
673 </p>
674 </div>
675 <?php
676 }
677
678 /**
679 * @return void
680 */
681 private function show_main() {
682 ?>
683 <div id="react-modal"></div>
684 <div id="react-ui">
685 <div class="react-loading">
686 <h1><?php esc_html_e( 'Loading, please wait...', 'redirection' ); ?></h1>
687
688 <span class="react-loading-spinner"></span>
689 </div>
690 <noscript><?php esc_html_e( 'Please enable JavaScript', 'redirection' ); ?></noscript>
691
692 <?php $this->show_load_fail(); ?>
693 </div>
694
695 <script>
696 var prevError = window.onerror;
697 var errors = [];
698 var timeout = 0;
699 var timer = setInterval( function() {
700 if ( isRedirectionLoaded() ) {
701 resetAll();
702 } else if ( errors.length > 0 || timeout++ === 5 ) {
703 showError();
704 }
705 }, 5000 );
706
707 function isRedirectionLoaded() {
708 return typeof redirection !== 'undefined';
709 }
710
711 function showError() {
712 var errorText = "";
713
714 if ( errors.length > 0 ) {
715 errorText = "```\n" + errors.join( ',' ) + "\n```\n\n";
716 }
717
718 resetAll();
719
720 if ( document.querySelector( '.react-loading' ) ) {
721 document.querySelector( '.react-loading' ).style.display = 'none';
722 document.querySelector( '.react-error' ).style.display = 'block';
723
724 if ( typeof Redirectioni10n !== 'undefined' && Redirectioni10n ) {
725 document.querySelector( '.versions' ).innerHTML = Redirectioni10n.versions.replace( /\n/g, '<br />' );
726 document.querySelector( '.react-error .button-primary' ).href += '&body=' + encodeURIComponent( errorText ) + encodeURIComponent( Redirectioni10n.versions );
727 }
728 } else {
729 document.querySelector( '#react-ui' ).innerHTML = '<p>Sorry something went very wrong.</p>';
730 }
731 }
732
733 function resetAll() {
734 clearInterval( timer );
735 window.onerror = prevError;
736 }
737
738 window.onerror = function( error, url, line ) {
739 console.error( error );
740 errors.push( error + ' ' + url + ' ' + line );
741 };
742 </script>
743 <?php
744 }
745
746 /**
747 * Get the current plugin page.
748 * Uses $_GET['sub'] to determine the current page unless a page is supplied.
749 *
750 * @param string|false $page Current page.
751 * @return string|boolean Current page, or false.
752 */
753 private function get_current_page( $page = false ) {
754 if ( $page === false ) {
755 $page = 'redirect';
756
757 if ( $this->get_query( 'sub' ) !== null ) {
758 $page = $this->get_query( 'sub' );
759 }
760 }
761
762 // Are we allowed to access this page?
763 if ( in_array( $page, Redirection_Capabilities::get_available_pages(), true ) ) {
764 return $page;
765 }
766
767 return false;
768 }
769
770 /**
771 * @return void
772 */
773 private function inject() {
774 $page = $this->get_query( 'page' );
775 $current_page = $this->get_current_page();
776
777 if ( $page !== null && $current_page !== 'redirect' && $page === 'redirection.php' ) {
778 $this->try_export_logs();
779 $this->try_export_redirects();
780 $this->try_export_rss();
781 }
782 }
783
784 /**
785 * @return void
786 */
787 public function try_export_rss() {
788 $token = $this->get_query( 'token' );
789 $sub = $this->get_query( 'sub' );
790
791 if ( $token !== null && $sub === 'rss' && Redirection_Capabilities::has_access( Redirection_Capabilities::CAP_REDIRECT_MANAGE ) ) {
792 $options = Red_Options::get();
793
794 if ( $token === $options['token'] && $options['token'] !== '' ) {
795 $module = $this->get_query( 'module' );
796
797 $items = Red_Item::get_all_for_module( intval( $module, 10 ) );
798
799 $exporter = Red_FileIO::create( 'rss' );
800 if ( $exporter !== false ) {
801 $exporter->force_download();
802
803 echo $exporter->get_data( $items, array() );
804 die();
805 }
806 }
807 }
808 }
809
810 /**
811 * @return void
812 */
813 private function try_export_logs() {
814 if ( Redirection_Capabilities::has_access( Redirection_Capabilities::CAP_IO_MANAGE ) && isset( $_POST['export-csv'] ) && check_admin_referer( 'wp_rest' ) !== false ) {
815 if ( $this->get_current_page() === 'log' ) {
816 Red_Redirect_Log::export_to_csv();
817 } elseif ( $this->get_current_page() === '404s' ) {
818 Red_404_Log::export_to_csv();
819 }
820
821 die();
822 }
823 }
824
825 /**
826 * @return void
827 */
828 private function try_export_redirects() {
829 $sub = $this->get_query( 'sub' );
830 if ( $sub !== 'io' ) {
831 return;
832 }
833
834 $export = $this->get_query( 'export' );
835 $exporter = $this->get_query( 'exporter' );
836
837 if ( Redirection_Capabilities::has_access( Redirection_Capabilities::CAP_IO_MANAGE ) && $export !== null && $exporter !== null && check_admin_referer( 'wp_rest' ) !== false ) {
838 $export = Red_FileIO::export( $export, $exporter );
839
840 if ( $export !== false ) {
841 $export['exporter']->force_download();
842
843 // This data is not displayed and will be downloaded to a file
844 echo str_replace( '&amp;', '&', wp_kses( $export['data'], 'strip' ) );
845 die();
846 }
847 }
848 }
849 }
850
851 register_activation_hook( REDIRECTION_FILE, array( 'Redirection_Admin', 'plugin_activated' ) );
852
853 // @phpstan-ignore return.void
854 add_action( 'init', array( 'Redirection_Admin', 'init' ) );
855
856 // This is causing a lot of problems with the REST API - disable qTranslate
857 add_filter(
858 'qtranslate_language_detect_redirect',
859 function ( $lang, $url ) {
860 $url = Redirection_Request::get_request_url();
861
862 if ( strpos( $url, '/wp-json/' ) !== false || strpos( $url, '?rest_route' ) !== false ) {
863 return false;
864 }
865
866 return $lang;
867 },
868 10,
869 2
870 );
871