PluginProbe
Redirection / 3.1
Redirection v3.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-admin.php

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

485 lines 15.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 include dirname( __FILE__ ).'/models/group.php';
4 include dirname( __FILE__ ).'/models/monitor.php';
5 include dirname( __FILE__ ).'/models/file-io.php';
6
7 define( 'RED_DEFAULT_PER_PAGE', 25 );
8 define( 'RED_MAX_PER_PAGE', 200 );
9
10 class Redirection_Admin {
11 private static $instance = null;
12 private $monitor;
13
14 static function init() {
15 if ( is_null( self::$instance ) ) {
16 self::$instance = new Redirection_Admin();
17
18 load_plugin_textdomain( 'redirection', false, dirname( plugin_basename( REDIRECTION_FILE ) ).'/locale/' );
19 }
20
21 return self::$instance;
22 }
23
24 function __construct() {
25 add_action( 'admin_menu', array( $this, 'admin_menu' ) );
26 add_action( 'plugin_action_links_'.basename( dirname( REDIRECTION_FILE ) ).'/'.basename( REDIRECTION_FILE ), array( $this, 'plugin_settings' ), 10, 4 );
27 add_filter( 'redirection_save_options', array( $this, 'flush_schedule' ) );
28 add_filter( 'set-screen-option', array( $this, 'set_per_page' ), 10, 3 );
29 add_action( 'redirection_redirect_updated', array( $this, 'set_default_group' ), 10, 2 );
30 add_action( 'wp_ajax_red_proxy', array( $this, 'red_proxy' ) );
31
32 if ( defined( 'REDIRECTION_FLYING_SOLO' ) && REDIRECTION_FLYING_SOLO ) {
33 add_filter( 'script_loader_src', array( $this, 'flying_solo' ), 10, 2 );
34 }
35
36 register_deactivation_hook( REDIRECTION_FILE, array( 'Redirection_Admin', 'plugin_deactivated' ) );
37 register_uninstall_hook( REDIRECTION_FILE, array( 'Redirection_Admin', 'plugin_uninstall' ) );
38
39 $this->monitor = new Red_Monitor( red_get_options() );
40 }
41
42 // These are only called on the single standard site, or in the network admin of the multisite - they run across all available sites
43 public static function plugin_activated() {
44 if ( is_network_admin() ) {
45 foreach ( get_sites() as $site ) {
46 switch_to_blog( $site->blog_id );
47
48 Redirection_Admin::update();
49 Red_Flusher::schedule();
50 red_set_options();
51
52 restore_current_blog();
53 }
54 } else {
55 Redirection_Admin::update();
56 Red_Flusher::schedule();
57 red_set_options();
58 }
59 }
60
61 // These are only called on the single standard site, or in the network admin of the multisite - they run across all available sites
62 public static function plugin_deactivated() {
63 if ( is_network_admin() ) {
64 foreach ( get_sites() as $site ) {
65 switch_to_blog( $site->blog_id );
66
67 Red_Flusher::clear();
68
69 restore_current_blog();
70 }
71 } else {
72 Red_Flusher::clear();
73 }
74 }
75
76 // These are only called on the single standard site, or in the network admin of the multisite - they run across all available sites
77 public static function plugin_uninstall() {
78 include_once dirname( REDIRECTION_FILE ).'/models/database.php';
79
80 $db = new RE_Database();
81
82 if ( is_network_admin() ) {
83 foreach ( get_sites() as $site ) {
84 switch_to_blog( $site->blog_id );
85
86 $db->remove( REDIRECTION_FILE );
87
88 restore_current_blog();
89 }
90 } else {
91 $db->remove( REDIRECTION_FILE );
92 }
93 }
94
95 private static function update() {
96 $version = get_option( 'redirection_version' );
97
98 Red_Flusher::schedule();
99
100 if ( $version !== REDIRECTION_DB_VERSION ) {
101 include_once dirname( REDIRECTION_FILE ).'/models/database.php';
102
103 $database = new RE_Database();
104
105 if ( $version === false ) {
106 $database->install();
107 }
108
109 $database->upgrade( $version, REDIRECTION_DB_VERSION );
110 }
111 }
112
113 // 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
114 // then this can prevent Redirection running, it's a little sensitive about that. We use the nuclear option here to disable
115 // all other JS while viewing Redirection
116 public function flying_solo( $src, $handle ) {
117 if ( isset( $_SERVER['REQUEST_URI'] ) && strpos( $_SERVER['REQUEST_URI'], 'page=redirection.php' ) !== false ) {
118 if ( substr( $src, 0, 4 ) === 'http' && $handle !== 'redirection' && strpos( $src, 'plugins' ) !== false ) {
119 if ( $this->ignore_this_plugin( $src ) ) {
120 return false;
121 }
122 }
123 }
124
125 return $src;
126 }
127
128 private function ignore_this_plugin( $src ) {
129 if ( strpos( $src, 'mootools' ) !== false ) {
130 return true;
131 }
132
133 if ( strpos( $src, 'wp-seo-' ) !== false ) {
134 return true;
135 }
136
137 return false;
138 }
139
140 public function flush_schedule( $options ) {
141 Red_Flusher::schedule();
142 return $options;
143 }
144
145 function set_per_page( $status, $option, $value ) {
146 if ( $option === 'redirection_log_per_page' ) {
147 return max( 1, min( intval( $value, 10 ), RED_MAX_PER_PAGE ) );
148 }
149
150 return $status;
151 }
152
153 function plugin_settings( $links ) {
154 $settings_link = '<a href="tools.php?page='.basename( REDIRECTION_FILE ).'&amp;sub=options">'.__( 'Settings', 'redirection' ).'</a>';
155 array_unshift( $links, $settings_link );
156 return $links;
157 }
158
159 function redirection_head() {
160 global $wp_version;
161
162 $build = REDIRECTION_VERSION.'-'.REDIRECTION_BUILD;
163 $preload = $this->get_preload_data();
164 $options = red_get_options();
165 $versions = array(
166 'Plugin: '.REDIRECTION_VERSION,
167 'WordPress: '.$wp_version.' ('.( is_multisite() ? 'multi' : 'single' ).')',
168 'PHP: '.phpversion(),
169 'Browser: '.Redirection_Request::get_user_agent(),
170 'REST API: '.red_get_rest_api(),
171 );
172
173 $this->inject();
174
175 if ( $options['rest_api'] === false ) {
176 // Compatibility fix
177 $this->initial_set_api();
178 }
179
180 if ( ! isset( $_GET['sub'] ) || ( isset( $_GET['sub'] ) && ( in_array( $_GET['sub'], array( 'log', '404s', 'groups' ) ) ) ) ) {
181 add_screen_option( 'per_page', array( 'label' => sprintf( __( 'Log entries (%d max)', 'redirection' ), RED_MAX_PER_PAGE ), 'default' => RED_DEFAULT_PER_PAGE, 'option' => 'redirection_log_per_page' ) );
182 }
183
184 if ( defined( 'REDIRECTION_DEV_MODE' ) && REDIRECTION_DEV_MODE ) {
185 wp_enqueue_script( 'redirection', 'http://localhost:3312/redirection.js', array(), $build, true );
186 } else {
187 wp_enqueue_script( 'redirection', plugin_dir_url( REDIRECTION_FILE ).'redirection.js', array(), $build, true );
188 }
189
190 wp_enqueue_style( 'redirection', plugin_dir_url( REDIRECTION_FILE ).'redirection.css', array(), $build );
191
192 if ( isset( $_POST['action'] ) && $_POST['action'] === 'fixit' && wp_verify_nonce( $_POST['_wpnonce'], 'wp_rest' ) ) {
193 $this->run_fixit();
194 }
195
196 wp_localize_script( 'redirection', 'Redirectioni10n', array(
197 'WP_API_root' => esc_url_raw( red_get_rest_api() ),
198 'WP_API_nonce' => wp_create_nonce( 'wp_rest' ),
199 'pluginBaseUrl' => plugins_url( '', REDIRECTION_FILE ),
200 'pluginRoot' => admin_url( 'tools.php?page=redirection.php' ),
201 'per_page' => $this->get_per_page(),
202 'locale' => $this->get_i18n_data(),
203 'localeSlug' => get_locale(),
204 'token' => $options['token'],
205 'autoGenerate' => $options['auto_target'],
206 'preload' => $preload,
207 'versions' => implode( "\n", $versions ),
208 'version' => REDIRECTION_VERSION,
209 ) );
210
211 $this->add_help_tab();
212 }
213
214 public function initial_set_api() {
215 include_once dirname( REDIRECTION_FILE ).'/models/fixer.php';
216
217 $fixer = new Red_Fixer();
218 $status = $fixer->get_rest_status();
219
220 if ( $status['status'] === 'problem' ) {
221 $fixer->fix_rest();
222 } else {
223 red_set_options( array( 'rest_api' => 0 ) );
224 }
225 }
226
227 private function run_fixit() {
228 if ( current_user_can( apply_filters( 'redirection_role', 'manage_options' ) ) ) {
229 include_once dirname( REDIRECTION_FILE ).'/models/fixer.php';
230
231 $fixer = new Red_Fixer();
232 $fixer->fix( $fixer->get_status() );
233 }
234 }
235
236 private function get_preload_data() {
237 $page = '';
238 if ( isset( $_GET['sub'] ) && in_array( $_GET['sub'], array( 'group', '404s', 'log', 'io', 'options', 'support' ) ) ) {
239 $page = $_GET['sub'];
240 }
241
242 if ( $page === 'support' ) {
243 $api = new Redirection_Api_Plugin( REDIRECTION_API_NAMESPACE );
244
245 return array(
246 'pluginStatus' => $api->route_status( new WP_REST_Request() )
247 );
248 }
249
250 return array();
251 }
252
253 private function add_help_tab() {
254 $title = __( 'Redirection Support', 'redirection' );
255 $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' );
256
257 $current_screen = get_current_screen();
258 $current_screen->add_help_tab( array(
259 'id' => 'redirection',
260 'title' => 'Redirection',
261 'content' => "<h2>$title</h2><p>$content</p>",
262 ) );
263 }
264
265 private function get_per_page() {
266 $per_page = intval( get_user_meta( get_current_user_id(), 'redirection_log_per_page', true ), 10 );
267
268 return $per_page > 0 ? max( 5, min( $per_page, RED_MAX_PER_PAGE ) ) : RED_DEFAULT_PER_PAGE;
269 }
270
271 private function get_i18n_data() {
272 $i18n_json = dirname( REDIRECTION_FILE ) . '/locale/json/redirection-' . get_locale() . '.json';
273
274 if ( is_file( $i18n_json ) && is_readable( $i18n_json ) ) {
275 $locale_data = @file_get_contents( $i18n_json );
276
277 if ( $locale_data ) {
278 return json_decode( $locale_data );
279 }
280 }
281
282 // Return empty if we have nothing to return so it doesn't fail when parsed in JS
283 return array();
284 }
285
286 function admin_menu() {
287 $hook = add_management_page( 'Redirection', 'Redirection', apply_filters( 'redirection_role', 'administrator' ), basename( REDIRECTION_FILE ), array( &$this, 'admin_screen' ) );
288 add_action( 'load-'.$hook, array( $this, 'redirection_head' ) );
289 }
290
291 private function check_minimum_wp() {
292 $wp_version = get_bloginfo( 'version' );
293
294 if ( version_compare( $wp_version, REDIRECTION_MIN_WP, '<' ) ) {
295 ?>
296 <div class="react-error">
297 <h1><?php _e( 'Unable to load Redirection', 'redirection' ); ?></h1>
298 <p style="text-align: left"><?php printf( __( 'Redirection requires WordPress v%1s, you are using v%2s - please update your WordPress', 'redirection' ), REDIRECTION_MIN_WP, $wp_version ); ?></p>
299 </div>
300 <?php
301 return false;
302 }
303
304 return true;
305 }
306
307 private function check_tables_exist() {
308 include_once dirname( REDIRECTION_FILE ).'/models/database.php';
309
310 $database = new RE_Database();
311 $status = $database->get_status();
312
313 if ( $status['status'] !== 'good' ) {
314 ?>
315 <div class="error">
316 <h3><?php _e( 'Redirection not installed properly', 'redirection' ); ?></h3>
317 <p style="text-align: left"><?php printf( __( 'Problems were detected with your database tables. Please visit the <a href="%s">support page</a> for more details.', 'redirection' ), 'tools.php?page=redirection.php&amp;sub=support' ); ?></p>
318 </div>
319 <?php
320
321 return false;
322 }
323
324 return true;
325 }
326
327 public function set_default_group( $id, $redirect ) {
328 red_set_options( array( 'last_group_id' => $redirect->get_group_id() ) );
329 }
330
331 function admin_screen() {
332 $version = get_plugin_data( REDIRECTION_FILE );
333 $version = $version['Version'];
334
335 Redirection_Admin::update();
336
337 if ( $this->check_minimum_wp() === false ) {
338 return;
339 }
340
341 if ( $this->check_tables_exist() === false && ( ! isset( $_GET['sub'] ) || $_GET['sub'] !== 'support' ) ) {
342 return false;
343 }
344
345 ?>
346 <div id="react-ui">
347 <div class="react-loading">
348 <h1><?php _e( 'Loading, please wait...', 'redirection' ); ?></h1>
349
350 <span class="react-loading-spinner"></span>
351 </div>
352 <noscript>Please enable JavaScript</noscript>
353
354 <div class="react-error" style="display: none">
355 <h1><?php _e( 'Unable to load Redirection ☹️', 'redirection' ); ?> v<?php echo esc_html( $version ); ?></h1>
356 <p><?php _e( "This may be caused by another plugin - look at your browser's error console for more details.", 'redirection' ); ?></p>
357 <p><?php _e( 'If you are using a page caching plugin or service (CloudFlare, OVH, etc) then you can also try clearing that cache.', 'redirection' ); ?></p>
358 <p><?php _e( 'Also check if your browser is able to load <code>redirection.js</code>:', 'redirection' ); ?></p>
359 <p><code><?php echo esc_html( plugin_dir_url( REDIRECTION_FILE ).'redirection.js?ver='.urlencode( REDIRECTION_VERSION ).'-'.urlencode( REDIRECTION_BUILD ) ); ?></code></p>
360 <p><?php _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>
361 <p><?php _e( 'Please see the <a href="https://redirection.me/support/problems/">list of common problems</a>.', 'redirection' ); ?></p>
362 <p><?php _e( "If you think Redirection is at fault then create an issue.", 'redirection' ); ?></p>
363 <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>
364 <p>
365 <a class="button-primary" target="_blank" href="https://github.com/johngodley/redirection/issues/new?title=Problem%20starting%20Redirection%20<?php echo esc_attr( $version ) ?>">
366 <?php _e( 'Create Issue', 'redirection' ); ?>
367 </a>
368 </p>
369 </div>
370 </div>
371
372 <script>
373 var prevError = window.onerror;
374 var errors = [];
375 var timeout = 0;
376 var timer = setInterval( function() {
377 if ( isRedirectionLoaded() ) {
378 resetAll();
379 } else if ( errors.length > 0 || timeout++ === 5 ) {
380 showError();
381 }
382 }, 5000 );
383
384 function isRedirectionLoaded() {
385 return typeof redirection !== 'undefined';
386 }
387
388 function showError() {
389 var errorText = "";
390
391 if ( errors.length > 0 ) {
392 errorText = "```\n" + errors.join( ',' ) + "\n```\n\n";
393 }
394
395 resetAll();
396 document.querySelector( '.react-loading' ).style.display = 'none';
397 document.querySelector( '.react-error' ).style.display = 'block';
398
399 if ( typeof Redirectioni10n !== 'undefined' ) {
400 document.querySelector( '.versions' ).innerHTML = Redirectioni10n.versions.replace( /\n/g, '<br />' );
401 document.querySelector( '.react-error .button-primary' ).href += '&body=' + encodeURIComponent( errorText ) + encodeURIComponent( Redirectioni10n.versions );
402 }
403 }
404
405 function resetAll() {
406 clearInterval( timer );
407 window.onerror = prevError;
408 }
409
410 window.onerror = function( error, url, line ) {
411 console.error( error );
412 errors.push( error + ' ' + url + ' ' + line );
413 };
414 </script>
415 <?php
416 }
417
418 /**
419 * Really wish I didnt have to do this...
420 * NOTE: nonce is checked by serve_request
421 */
422 public function red_proxy() {
423 if ( $this->user_has_access() && isset( $_GET['rest_path'] ) && substr( $_GET['rest_path'], 0, 15 ) === 'redirection/v1/' ) {
424 $server = rest_get_server();
425 $server->serve_request( '/'.$_GET['rest_path'] );
426 die();
427 }
428 }
429
430 private function user_has_access() {
431 return current_user_can( apply_filters( 'redirection_role', 'administrator' ) );
432 }
433
434 function inject() {
435 if ( isset( $_GET['page'] ) && isset( $_GET['sub'] ) && $_GET['page'] === 'redirection.php' ) {
436 $this->try_export_logs();
437 $this->try_export_redirects();
438 $this->try_export_rss();
439 }
440 }
441
442 function try_export_rss() {
443 if ( isset( $_GET['token'] ) && $_GET['sub'] === 'rss' ) {
444 $options = red_get_options();
445
446 if ( $_GET['token'] === $options['token'] && !empty( $options['token'] ) ) {
447 $items = Red_Item::get_all_for_module( intval( $_GET['module'] ) );
448
449 $exporter = Red_FileIO::create( 'rss' );
450 $exporter->force_download();
451 echo $exporter->get_data( $items, array() );
452 die();
453 }
454 }
455 }
456
457 private function try_export_logs() {
458 if ( $this->user_has_access() && isset( $_POST['export-csv'] ) && check_admin_referer( 'wp_rest' ) ) {
459 if ( isset( $_GET['sub'] ) && $_GET['sub'] === 'log' ) {
460 RE_Log::export_to_csv();
461 } else {
462 RE_404::export_to_csv();
463 }
464
465 die();
466 }
467 }
468
469 private function try_export_redirects() {
470 if ( $this->user_has_access() && $_GET['sub'] === 'io' && isset( $_GET['exporter'] ) && isset( $_GET['export'] ) ) {
471 $export = Red_FileIO::export( $_GET['export'], $_GET['exporter'] );
472
473 if ( $export !== false ) {
474 $export['exporter']->force_download();
475 echo $export['data'];
476 die();
477 }
478 }
479 }
480 }
481
482 register_activation_hook( REDIRECTION_FILE, array( 'Redirection_Admin', 'plugin_activated' ) );
483
484 add_action( 'init', array( 'Redirection_Admin', 'init' ) );
485