PluginProbe
Redirection / 4.9
Redirection v4.9
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 4.9, at redirection-admin.php

620 lines 20.3 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/group.php';
4 require_once __DIR__ . '/models/monitor.php';
5 require_once __DIR__ . '/models/file-io.php';
6 require_once __DIR__ . '/database/database.php';
7 require_once __DIR__ . '/redirection-capabilities.php';
8
9 define( 'RED_DEFAULT_PER_PAGE', 25 );
10 define( 'RED_MAX_PER_PAGE', 200 );
11
12 class Redirection_Admin {
13 private static $instance = null;
14 private $monitor;
15 private $fixit_failed = false;
16
17 public static function init() {
18 if ( is_null( self::$instance ) ) {
19 self::$instance = new Redirection_Admin();
20 }
21
22 return self::$instance;
23 }
24
25 public function __construct() {
26 add_action( 'admin_menu', [ $this, 'admin_menu' ] );
27 add_action( 'admin_notices', [ $this, 'update_nag' ] );
28 add_action( 'plugin_action_links_' . basename( dirname( REDIRECTION_FILE ) ) . '/' . basename( REDIRECTION_FILE ), [ $this, 'plugin_settings' ], 10, 4 );
29 add_filter( 'plugin_row_meta', [ $this, 'plugin_row_meta' ], 10, 4 );
30 add_filter( 'redirection_save_options', [ $this, 'flush_schedule' ] );
31 add_filter( 'set-screen-option', [ $this, 'set_per_page' ], 10, 3 );
32 add_filter( 'set_screen_option_redirection_log_per_page', function( $ignore, $option, $value ) {
33 return $value;
34 }, 10, 3 );
35 add_action( 'redirection_redirect_updated', [ $this, 'set_default_group' ], 10, 2 );
36
37 if ( defined( 'REDIRECTION_FLYING_SOLO' ) && REDIRECTION_FLYING_SOLO ) {
38 add_filter( 'script_loader_src', [ $this, 'flying_solo' ], 10, 2 );
39 }
40
41 register_deactivation_hook( REDIRECTION_FILE, [ 'Redirection_Admin', 'plugin_deactivated' ] );
42 register_uninstall_hook( REDIRECTION_FILE, [ 'Redirection_Admin', 'plugin_uninstall' ] );
43
44 $this->monitor = new Red_Monitor( red_get_options() );
45 $this->run_hacks();
46 }
47
48 // These are only called on the single standard site, or in the network admin of the multisite - they run across all available sites
49 public static function plugin_activated() {
50 Red_Database::apply_to_sites( function() {
51 Red_Flusher::clear();
52 red_set_options();
53 } );
54 }
55
56 // These are only called on the single standard site, or in the network admin of the multisite - they run across all available sites
57 public static function plugin_deactivated() {
58 Red_Database::apply_to_sites( function() {
59 Red_Flusher::clear();
60 } );
61 }
62
63 // These are only called on the single standard site, or in the network admin of the multisite - they run across all available sites
64 public static function plugin_uninstall() {
65 $database = Red_Database::get_latest_database();
66
67 Red_Database::apply_to_sites( function() use ( $database ) {
68 $database->remove();
69 } );
70 }
71
72 public function update_nag() {
73 if ( ! Redirection_Capabilities::has_access( Redirection_Capabilities::CAP_OPTION_MANAGE ) ) {
74 return;
75 }
76
77 $status = new Red_Database_Status();
78
79 $message = false;
80 if ( $status->needs_installing() ) {
81 /* translators: 1: URL to plugin page */
82 $message = sprintf( __( 'Please complete your <a href="%s">Redirection setup</a> to activate the plugin.', 'redirection' ), esc_url( $this->get_plugin_url() ) );
83 } elseif ( $status->needs_updating() ) {
84 /* translators: 1: URL to plugin page, 2: current version, 3: target version */
85 $message = sprintf( __( 'Redirection\'s database needs to be updated - <a href="%1$1s">click to update</a>.', 'redirection' ), esc_url( $this->get_plugin_url() ) );
86 }
87
88 if ( ! $message || strpos( Redirection_Request::get_request_url(), 'page=redirection.php' ) !== false ) {
89 return;
90 }
91
92 // Known HTML and so isn't escaped
93 // phpcs:ignore
94 echo '<div class="update-nag notice notice-warning" style="width: 95%">' . $message . '</div>';
95 }
96
97 // 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
98 // then this can prevent Redirection running and it's a little sensitive about that. We use the nuclear option here to disable
99 // all other JS while viewing Redirection
100 public function flying_solo( $src, $handle ) {
101 if ( isset( $_SERVER['REQUEST_URI'] ) && strpos( $_SERVER['REQUEST_URI'], 'page=redirection.php' ) !== false ) {
102 if ( substr( $src, 0, 4 ) === 'http' && $handle !== 'redirection' && strpos( $src, 'plugins' ) !== false ) {
103 if ( $this->ignore_this_plugin( $src ) ) {
104 return false;
105 }
106 }
107 }
108
109 return $src;
110 }
111
112 private function ignore_this_plugin( $src ) {
113 $ignore = array(
114 'mootools',
115 'wp-seo-',
116 'authenticate',
117 'wordpress-seo',
118 'yikes',
119 );
120
121 foreach ( $ignore as $text ) {
122 if ( strpos( $src, $text ) !== false ) {
123 return true;
124 }
125 }
126
127 return false;
128 }
129
130 public function flush_schedule( $options ) {
131 Red_Flusher::schedule();
132 return $options;
133 }
134
135 public function set_per_page( $status, $option, $value ) {
136 if ( $option === 'redirection_log_per_page' ) {
137 $value = max( 1, min( intval( $value, 10 ), RED_MAX_PER_PAGE ) );
138 return $value;
139 }
140
141 return $status;
142 }
143
144 public function plugin_settings( $links ) {
145 $status = new Red_Database_Status();
146 if ( $status->needs_updating() ) {
147 array_unshift( $links, '<a style="color: red" href="' . esc_url( $this->get_plugin_url() ) . '&amp;sub=support">' . __( 'Upgrade Database', 'redirection' ) . '</a>' );
148 }
149
150 array_unshift( $links, '<a href="' . esc_url( $this->get_plugin_url() ) . '&amp;sub=options">' . __( 'Settings', 'redirection' ) . '</a>' );
151 return $links;
152 }
153
154 public function plugin_row_meta( $plugin_meta, $plugin_file, $plugin_data, $status ) {
155 if ( $plugin_file === basename( dirname( REDIRECTION_FILE ) ) . '/' . basename( REDIRECTION_FILE ) ) {
156 $plugin_data['Description'] .= '<p>' . __( 'Please upgrade your database', 'redirection' ) . '</p>';
157 }
158
159 return $plugin_meta;
160 }
161
162 private function get_plugin_url() {
163 return admin_url( 'tools.php?page=' . basename( REDIRECTION_FILE ) );
164 }
165
166 private function get_first_available_page_url() {
167 $pages = Redirection_Capabilities::get_available_pages();
168
169 if ( count( $pages ) > 0 ) {
170 return $this->get_plugin_url() . ( $pages[0] === 'redirect' ? '' : '&sub=' . rawurlencode( $pages[0] ) );
171 }
172
173 return admin_url();
174 }
175
176 public function redirection_head() {
177 global $wp_version;
178
179 // Does user have access to this page?
180 if ( $this->get_current_page() === false ) {
181 // Redirect to root plugin page
182 wp_safe_redirect( $this->get_first_available_page_url() );
183 die();
184 }
185
186 if ( isset( $_REQUEST['action'] ) && isset( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( $_REQUEST['_wpnonce'], 'wp_rest' ) ) {
187 if ( $_REQUEST['action'] === 'fixit' ) {
188 $this->run_fixit();
189 } elseif ( $_REQUEST['action'] === 'rest_api' ) {
190 $this->set_rest_api( intval( $_REQUEST['rest_api'], 10 ) );
191 }
192 }
193
194 $build = REDIRECTION_VERSION . '-' . REDIRECTION_BUILD;
195 $preload = $this->get_preload_data();
196 $options = red_get_options();
197 $versions = array(
198 'Plugin: ' . REDIRECTION_VERSION,
199 'WordPress: ' . $wp_version . ' (' . ( is_multisite() ? 'multi' : 'single' ) . ')',
200 'PHP: ' . phpversion(),
201 'Browser: ' . Redirection_Request::get_user_agent(),
202 'JavaScript: ' . plugin_dir_url( REDIRECTION_FILE ) . 'redirection.js?ver=' . $build,
203 'REST API: ' . red_get_rest_api(),
204 );
205
206 $this->inject();
207
208 // Add contextual help to some pages
209 if ( in_array( $this->get_current_page(), [ 'redirect', 'log', '404s', 'groups' ], true ) ) {
210 add_screen_option( 'per_page', array(
211 /* translators: maximum number of log entries */
212 'label' => sprintf( __( 'Log entries (%d max)', 'redirection' ), RED_MAX_PER_PAGE ),
213 'default' => RED_DEFAULT_PER_PAGE,
214 'option' => 'redirection_log_per_page',
215 ) );
216 }
217
218 if ( defined( 'REDIRECTION_DEV_MODE' ) && REDIRECTION_DEV_MODE ) {
219 wp_enqueue_script( 'redirection', 'http://localhost:3312/redirection.js', array(), $build, true );
220 } else {
221 wp_enqueue_script( 'redirection', plugin_dir_url( REDIRECTION_FILE ) . 'redirection.js', array(), $build, true );
222 }
223
224 wp_enqueue_style( 'redirection', plugin_dir_url( REDIRECTION_FILE ) . 'redirection.css', array(), $build );
225
226 $status = new Red_Database_Status();
227 $status->check_tables_exist();
228
229 $translations = $this->get_i18n_data();
230
231 wp_localize_script( 'redirection', 'Redirectioni10n', array(
232 'api' => [
233 'WP_API_root' => esc_url_raw( red_get_rest_api() ),
234 'WP_API_nonce' => wp_create_nonce( 'wp_rest' ),
235 'site_health' => admin_url( 'site-health.php' ),
236 'current' => $options['rest_api'],
237 'routes' => [
238 REDIRECTION_API_JSON => red_get_rest_api( REDIRECTION_API_JSON ),
239 REDIRECTION_API_JSON_INDEX => red_get_rest_api( REDIRECTION_API_JSON_INDEX ),
240 REDIRECTION_API_JSON_RELATIVE => red_get_rest_api( REDIRECTION_API_JSON_RELATIVE ),
241 ],
242 ],
243 'pluginBaseUrl' => plugins_url( '', REDIRECTION_FILE ),
244 'pluginRoot' => $this->get_plugin_url(),
245 'per_page' => $this->get_per_page(),
246 'locale' => [
247 'translations' => $translations,
248 'localeSlug' => get_locale(),
249 'Plural-Forms' => isset( $translations['plural-forms'] ) ? $translations['plural-forms'] : 'nplurals=2; plural=n != 1;',
250 ],
251 'settings' => $options,
252 'preload' => $preload,
253 'versions' => implode( "\n", $versions ),
254 'version' => REDIRECTION_VERSION,
255 'database' => $status->get_json(),
256 'caps' => [
257 'pages' => Redirection_Capabilities::get_available_pages(),
258 'capabilities' => Redirection_Capabilities::get_all_capabilities(),
259 ],
260 ) );
261
262 $this->add_help_tab();
263 }
264
265 // Some plugins misbehave, so this attempts to 'fix' them so Redirection can get on with it's work
266 private function run_hacks() {
267 add_filter( 'ip-geo-block-admin', array( $this, 'ip_geo_block' ) );
268 }
269
270 /*
271 * This works around the IP Geo Block plugin being very aggressive and breaking Redirection
272 */
273 public function ip_geo_block( $validate ) {
274 $url = Redirection_Request::get_request_url();
275 $override = array(
276 'tools.php?page=redirection.php',
277 'action=red_proxy&rest_path=redirection',
278 );
279
280 foreach ( $override as $path ) {
281 if ( strpos( $url, $path ) !== false ) {
282 return array(
283 'result' => 'passed',
284 'auth' => false,
285 'asn' => false,
286 'code' => false,
287 'ip' => false,
288 );
289 }
290 }
291
292 return $validate;
293 }
294
295 private function run_fixit() {
296 if ( Redirection_Capabilities::has_access( Redirection_Capabilities::CAP_SUPPORT_MANAGE ) ) {
297 require_once dirname( REDIRECTION_FILE ) . '/models/fixer.php';
298
299 $fixer = new Red_Fixer();
300 $result = $fixer->fix( $fixer->get_status() );
301
302 if ( is_wp_error( $result ) ) {
303 $this->fixit_failed = $result;
304 }
305 }
306 }
307
308 private function set_rest_api( $api ) {
309 if ( $api >= 0 && $api <= REDIRECTION_API_JSON_RELATIVE ) {
310 red_set_options( array( 'rest_api' => intval( $api, 10 ) ) );
311 }
312 }
313
314 private function get_preload_data() {
315 $status = new Red_Database_Status();
316
317 if ( $status->needs_installing() ) {
318 include_once __DIR__ . '/models/importer.php';
319
320 return [
321 'importers' => Red_Plugin_Importer::get_plugins(),
322 ];
323 }
324
325 if ( $this->get_current_page() === 'support' ) {
326 require_once dirname( REDIRECTION_FILE ) . '/models/fixer.php';
327
328 $fixer = new Red_Fixer();
329
330 return array(
331 'pluginStatus' => $fixer->get_json(),
332 );
333 }
334
335 return [];
336 }
337
338 private function add_help_tab() {
339 /* translators: URL */
340 $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' );
341 $title = __( 'Redirection Support', 'redirection' );
342
343 $current_screen = get_current_screen();
344 $current_screen->add_help_tab( array(
345 'id' => 'redirection',
346 'title' => 'Redirection',
347 'content' => "<h2>$title</h2><p>$content</p>",
348 ) );
349 }
350
351 private function get_per_page() {
352 $per_page = intval( get_user_meta( get_current_user_id(), 'redirection_log_per_page', true ), 10 );
353
354 return $per_page > 0 ? max( 5, min( $per_page, RED_MAX_PER_PAGE ) ) : RED_DEFAULT_PER_PAGE;
355 }
356
357 private function get_i18n_data() {
358 $locale = get_locale();
359
360 // WP 4.7
361 if ( function_exists( 'get_user_locale' ) ) {
362 $locale = get_user_locale();
363 }
364
365 $i18n_json = dirname( REDIRECTION_FILE ) . '/locale/json/redirection-' . $locale . '.json';
366
367 if ( is_file( $i18n_json ) && is_readable( $i18n_json ) ) {
368 // phpcs:ignore
369 $locale_data = @file_get_contents( $i18n_json );
370
371 if ( $locale_data ) {
372 return json_decode( $locale_data, true );
373 }
374 }
375
376 // Return empty if we have nothing to return so it doesn't fail when parsed in JS
377 return array();
378 }
379
380 public function admin_menu() {
381 $hook = add_management_page( 'Redirection', 'Redirection', Redirection_Capabilities::get_plugin_access(), basename( REDIRECTION_FILE ), [ $this, 'admin_screen' ] );
382 add_action( 'load-' . $hook, [ $this, 'redirection_head' ] );
383 }
384
385 private function check_minimum_wp() {
386 $wp_version = get_bloginfo( 'version' );
387
388 if ( version_compare( $wp_version, REDIRECTION_MIN_WP, '<' ) ) {
389 return false;
390 }
391
392 return true;
393 }
394
395 public function set_default_group( $id, $redirect ) {
396 red_set_options( array( 'last_group_id' => $redirect->get_group_id() ) );
397 }
398
399 public function admin_screen() {
400 if ( count( Redirection_Capabilities::get_all_capabilities() ) === 0 ) {
401 die( 'You do not have sufficient permissions to access this page.' );
402 }
403
404 if ( $this->check_minimum_wp() === false ) {
405 return $this->show_minimum_wordpress();
406 }
407
408 if ( $this->fixit_failed ) {
409 $this->show_fixit_failed();
410 }
411
412 Red_Flusher::schedule();
413
414 $this->show_main();
415 }
416
417 private function show_fixit_failed() {
418 ?>
419 <div class="notice notice-error">
420 <h1><?php echo esc_html( $this->fixit_failed->get_error_message() ); ?></h1>
421 <p><?php echo esc_html( $this->fixit_failed->get_error_data() ); ?></p>
422 </div>
423 <?php
424 }
425
426 private function show_minimum_wordpress() {
427 global $wp_version;
428
429 /* translators: 1: Expected WordPress version, 2: Actual WordPress version */
430 $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 );
431 ?>
432 <div class="react-error">
433 <h1><?php esc_html_e( 'Unable to load Redirection', 'redirection' ); ?></h1>
434 <p><?php echo esc_html( $wp_requirement ); ?></p>
435 </div>
436 <?php
437 }
438
439 private function show_load_fail() {
440 ?>
441 <div class="react-error" style="display: none">
442 <h1><?php esc_html_e( 'Unable to load Redirection ☹️', 'redirection' ); ?> v<?php echo esc_html( REDIRECTION_VERSION ); ?></h1>
443 <p><?php esc_html_e( "This may be caused by another plugin - look at your browser's error console for more details.", 'redirection' ); ?></p>
444 <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>
445 <p><?php _e( 'Also check if your browser is able to load <code>redirection.js</code>:', 'redirection' ); ?></p>
446 <p><code><?php echo esc_html( plugin_dir_url( REDIRECTION_FILE ) . 'redirection.js?ver=' . rawurlencode( REDIRECTION_VERSION ) . '-' . rawurlencode( REDIRECTION_BUILD ) ); ?></code></p>
447 <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>
448 <p><?php _e( 'Please see the <a href="https://redirection.me/support/problems/">list of common problems</a>.', 'redirection' ); ?></p>
449 <p><?php esc_html_e( 'If you think Redirection is at fault then create an issue.', 'redirection' ); ?></p>
450 <p class="versions"><?php _e( '<code>Redirectioni10n</code> is not defined. This usually means another plugin is blocking Redirection from loading. Please disable all plugins and try again.', 'redirection' ); ?></p>
451 <p>
452 <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 ); ?>">
453 <?php esc_html_e( 'Create Issue', 'redirection' ); ?>
454 </a>
455 </p>
456 </div>
457 <?php
458 }
459
460 private function show_main() {
461 ?>
462 <div id="react-modal"></div>
463 <div id="react-ui">
464 <div class="react-loading">
465 <h1><?php esc_html_e( 'Loading, please wait...', 'redirection' ); ?></h1>
466
467 <span class="react-loading-spinner"></span>
468 </div>
469 <noscript><?php esc_html_e( 'Please enable JavaScript', 'redirection' ); ?></noscript>
470
471 <?php $this->show_load_fail(); ?>
472 </div>
473
474 <script>
475 var prevError = window.onerror;
476 var errors = [];
477 var timeout = 0;
478 var timer = setInterval( function() {
479 if ( isRedirectionLoaded() ) {
480 resetAll();
481 } else if ( errors.length > 0 || timeout++ === 5 ) {
482 showError();
483 }
484 }, 5000 );
485
486 function isRedirectionLoaded() {
487 return typeof redirection !== 'undefined';
488 }
489
490 function showError() {
491 var errorText = "";
492
493 if ( errors.length > 0 ) {
494 errorText = "```\n" + errors.join( ',' ) + "\n```\n\n";
495 }
496
497 resetAll();
498 document.querySelector( '.react-loading' ).style.display = 'none';
499 document.querySelector( '.react-error' ).style.display = 'block';
500
501 if ( typeof Redirectioni10n !== 'undefined' && Redirectioni10n ) {
502 document.querySelector( '.versions' ).innerHTML = Redirectioni10n.versions.replace( /\n/g, '<br />' );
503 document.querySelector( '.react-error .button-primary' ).href += '&body=' + encodeURIComponent( errorText ) + encodeURIComponent( Redirectioni10n.versions );
504 }
505 }
506
507 function resetAll() {
508 clearInterval( timer );
509 window.onerror = prevError;
510 }
511
512 window.onerror = function( error, url, line ) {
513 console.error( error );
514 errors.push( error + ' ' + url + ' ' + line );
515 };
516 </script>
517 <?php
518 }
519
520 /**
521 * Get the current plugin page.
522 * Uses $_GET['sub'] to determine the current page unless a page is supplied.
523 *
524 * @param string $page Current page.
525 *
526 * @return string|boolean Current page, or false.
527 */
528 private function get_current_page( $page = false ) {
529 // $_GET['sub'] is validated below
530 // phpcs:ignore
531 if ( ! $page ) {
532 // phpcs:ignore
533 $page = isset( $_GET['sub'] ) ? $_GET['sub'] : 'redirect';
534 }
535
536 // Are we allowed to access this page?
537 if ( in_array( $page, Redirection_Capabilities::get_available_pages(), true ) ) {
538 // phpcs:ignore
539 return $page;
540 }
541
542 return false;
543 }
544
545 private function inject() {
546 // phpcs:ignore
547 if ( isset( $_GET['page'] ) && $this->get_current_page() !== 'redirect' && $_GET['page'] === 'redirection.php' ) {
548 $this->try_export_logs();
549 $this->try_export_redirects();
550 $this->try_export_rss();
551 }
552 }
553
554 public function try_export_rss() {
555 // phpcs:ignore
556 if ( isset( $_GET['token'] ) && isset( $_GET['sub'] ) && $_GET['sub'] === 'rss' && Redirection_Capabilities::has_access( Redirection_Capabilities::CAP_REDIRECT_MANAGE ) ) {
557 $options = red_get_options();
558
559 // phpcs:ignore
560 if ( $_GET['token'] === $options['token'] && ! empty( $options['token'] ) ) {
561 // phpcs:ignore
562 $items = Red_Item::get_all_for_module( intval( $_GET['module'], 10 ) );
563
564 $exporter = Red_FileIO::create( 'rss' );
565 $exporter->force_download();
566
567 // phpcs:ignore
568 echo $exporter->get_data( $items, array() );
569 die();
570 }
571 }
572 }
573
574 private function try_export_logs() {
575 if ( Redirection_Capabilities::has_access( Redirection_Capabilities::CAP_IO_MANAGE ) && isset( $_POST['export-csv'] ) && check_admin_referer( 'wp_rest' ) ) {
576 if ( $this->get_current_page() === 'log' ) {
577 Red_Redirect_Log::export_to_csv();
578 } elseif ( $this->get_current_page() === '404s' ) {
579 Red_404_Log::export_to_csv();
580 }
581
582 die();
583 }
584 }
585
586 private function try_export_redirects() {
587 // phpcs:ignore
588 if ( ! isset( $_GET['sub'] ) || $_GET['sub'] !== 'io' ) {
589 return;
590 }
591
592 if ( Redirection_Capabilities::has_access( Redirection_Capabilities::CAP_IO_MANAGE ) && isset( $_GET['exporter'] ) && isset( $_GET['export'] ) && check_admin_referer( 'wp_rest' ) ) {
593 $export = Red_FileIO::export( $_GET['export'], $_GET['exporter'] );
594
595 if ( $export !== false ) {
596 $export['exporter']->force_download();
597
598 // phpcs:ignore
599 echo $export['data'];
600 die();
601 }
602 }
603 }
604 }
605
606 register_activation_hook( REDIRECTION_FILE, array( 'Redirection_Admin', 'plugin_activated' ) );
607
608 add_action( 'init', array( 'Redirection_Admin', 'init' ) );
609
610 // This is causing a lot of problems with the REST API - disable qTranslate
611 add_filter( 'qtranslate_language_detect_redirect', function( $lang, $url ) {
612 $url = Redirection_Request::get_request_url();
613
614 if ( strpos( $url, '/wp-json/' ) !== false || strpos( $url, '?rest_route' ) !== false ) {
615 return false;
616 }
617
618 return $lang;
619 }, 10, 2 );
620