Safe Redirect Manager - Version 1.0

Version Description

Download this release

Release Info

Developer tlovett1
Plugin Icon 128x128 Safe Redirect Manager
Version 1.0
Comparing to
See all releases

Version 1.0

Files changed (3) hide show
  1. images/icon32x32.png +0 -0
  2. readme.txt +16 -0
  3. safe-redirect-manager.php +598 -0
images/icon32x32.png ADDED
Binary file
readme.txt ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Safe Redirect Manager ===
2
+ Contributors: tlovett1, tollmanz, tddewey, 10up, danielbachhuber, VentureBeat
3
+ Tags: http redirects, redirect manager, url redirection, safe http redirection
4
+ Requires at least: 3.1
5
+ Tested up to: 3.4.1
6
+ Stable tag: trunk
7
+
8
+ Safely and easily manage your websites HTTP redirects.
9
+
10
+ == Description ==
11
+
12
+ Safe Redirect Manager is a HTTP redirect manager for WordPress. An easy-to-use UI allows you to redirect locations to new URL's with the HTTP status codes of your chosing. The plugin uses the wp_safe_redirect function which only allows redirects to whitelisted hosts for security purposes. The plugin automatically handles whitelisting hosts for you.
13
+
14
+ == Installation ==
15
+
16
+ Extract the zip file and just drop the contents in the wp-content/plugins/ directory of your WordPress installation and then activate the Plugin from Plugins page.
safe-redirect-manager.php ADDED
@@ -0,0 +1,598 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: Safe Redirect Manager
4
+ Plugin URI: http://www.10up.com
5
+ Description: Easily and safely manage HTTP redirects.
6
+ Author: Taylor Lovett (10up LLC), VentureBeat
7
+ Version: 1.0
8
+ Author URI: http://www.10up.com
9
+
10
+ GNU General Public License, Free Software Foundation <http://creativecommons.org/licenses/GPL/2.0/>
11
+
12
+ This program is free software; you can redistribute it and/or modify
13
+ it under the terms of the GNU General Public License as published by
14
+ the Free Software Foundation; either version 2 of the License, or
15
+ (at your option) any later version.
16
+
17
+ This program is distributed in the hope that it will be useful,
18
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
+ GNU General Public License for more details.
21
+
22
+ You should have received a copy of the GNU General Public License
23
+ along with this program; if not, write to the Free Software
24
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
+
26
+ */
27
+
28
+ class SRM_Safe_Redirect_Manager {
29
+
30
+ public $redirect_post_type = 'redirect_rule';
31
+ private $redirect_nonce_name = 'srm_redirect_nonce';
32
+ private $redirect_nonce_action = 'srm-save-redirect-meta';
33
+
34
+ public $meta_key_redirect_from = '_redirect_rule_from';
35
+ public $meta_key_redirect_to = '_redirect_rule_to';
36
+ public $meta_key_redirect_status_code = '_redirect_rule_status_code';
37
+
38
+ public $cache_key_redirects = '_srm_redirects';
39
+
40
+ public $valid_status_codes = array( 301, 302, 303, 403, 404 );
41
+
42
+ private $whitelist_hosts = array();
43
+
44
+ public $default_max_redirects = 150;
45
+
46
+ /**
47
+ * Sets up redirect manager
48
+ *
49
+ * @since 1.0
50
+ * @uses add_action, add_filter
51
+ * @return object
52
+ */
53
+ public function __construct() {
54
+ add_action( 'init', array( $this, 'action_register_post_types' ) );
55
+ add_action( 'parse_request', array( $this, 'action_parse_request' ), 0 );
56
+ add_action( 'after_theme_setup', array( $this, 'action_load_texthost' ) );
57
+ add_action( 'save_post', array( $this, 'action_save_post' ) );
58
+ add_filter( 'manage_' . $this->redirect_post_type . '_posts_columns' , array( $this, 'filter_redirect_columns' ) );
59
+ add_action( 'manage_' . $this->redirect_post_type . '_posts_custom_column' , array( $this, 'action_custom_redirect_columns' ), 10, 2 );
60
+ add_action( 'transition_post_status', array( $this, 'action_transition_post_status' ), 10, 3 );
61
+ add_filter( 'post_updated_messages', array( $this, 'filter_redirect_updated_messages' ) );
62
+ add_action( 'admin_notices', array( $this, 'action_redirect_chain_alert' ) );
63
+ add_filter( 'the_title', array( $this, 'filter_admin_title' ), 100, 2 );
64
+ add_action( 'admin_init', array( $this, 'action_admin_init' ) );
65
+ add_filter( 'bulk_actions-' . 'edit-redirect_rule', array( $this, 'filter_bulk_actions' ) );
66
+ add_action( 'admin_print_styles-edit.php', array( $this, 'action_print_logo_css' ), 10, 1 );
67
+ add_action( 'admin_print_styles-post.php', array( $this, 'action_print_logo_css' ), 10, 1 );
68
+ add_action( 'admin_print_styles-post-new.php', array( $this, 'action_print_logo_css' ), 10, 1 );
69
+ }
70
+
71
+ /**
72
+ * Swap tools logo for plugin logo
73
+ *
74
+ * @uses plugins_url
75
+ * @return void
76
+ */
77
+ public function action_print_logo_css() {
78
+ global $post;
79
+ if ( is_object( $post ) && $this->redirect_post_type == $post->post_type ) {
80
+ ?>
81
+ <style type="text/css">
82
+ #icon-tools {
83
+ background: url("<?php echo plugins_url(); ?>/safe-redirect-manager/images/icon32x32.png") no-repeat top left !important;
84
+ margin-right: 0;
85
+ }
86
+ #visibility {
87
+ display: none;
88
+ }
89
+ </style>
90
+ <?php
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Removes bulk actions from post manager
96
+ *
97
+ * @return array
98
+ */
99
+ public function filter_bulk_actions() {
100
+ return array();
101
+ }
102
+
103
+ /**
104
+ * Echoes admin message if redirect chains exist
105
+ *
106
+ * @since 1.0
107
+ * @uses current_user_can
108
+ * @return void
109
+ */
110
+ public function action_redirect_chain_alert() {
111
+ global $post, $hook_suffix;
112
+ if ( is_object( $post ) && $this->redirect_post_type == $post->post_type ) {
113
+ if ( $this->check_for_possible_redirect_loops() ) {
114
+ ?>
115
+ <div class="updated">
116
+ <p><?php _e( 'Safe Redirect Manager Warning: Possible redirect loops and/or chains have been created.', 'safe-redirect-manager' ); ?></p>
117
+ </div>
118
+ <?php
119
+ } if ( $this->max_redirects_reached() ) {
120
+ ?>
121
+ <?php if ( 'post-new.php' == $hook_suffix ) : ?><style type="text/css">#post { display: none; }</style><?php endif; ?>
122
+ <div class="error">
123
+ <p><?php _e( 'Safe Redirect Manager Error: You have reached the maximum allowable number of redirects', 'safe-redirect-manager' ); ?></p>
124
+ </div>
125
+ <?php
126
+ }
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Returns true if max redirects have been reached
132
+ *
133
+ * @since 1.0
134
+ * @uses apply_filters
135
+ * @return bool
136
+ */
137
+ public function max_redirects_reached() {
138
+ $redirects = $this->update_redirect_cache();
139
+ $max_redirects = apply_filters( 'srm_max_redirects', $this->default_max_redirects );
140
+
141
+ return ( count( $redirects ) >= $max_redirects );
142
+ }
143
+
144
+ /**
145
+ * Check for potential redirect loops or chains
146
+ *
147
+ * @since 1.0
148
+ * @uses home_url
149
+ * @return boolean
150
+ */
151
+ public function check_for_possible_redirect_loops() {
152
+ $redirects = $this->update_redirect_cache();
153
+
154
+ $current_url = parse_url( home_url() );
155
+ $this_host = ( is_array( $current_url ) && ! empty( $current_url['host'] ) ) ? $current_url['host'] : '';
156
+
157
+ foreach ( $redirects as $redirect ) {
158
+ $redirect_from = $redirect['redirect_from'];
159
+
160
+ // check redirect from against all redirect to's
161
+ foreach ( $redirects as $compare_redirect ) {
162
+ $redirect_to = $compare_redirect['redirect_to'];
163
+
164
+ $redirect_url = parse_url( $redirect_to );
165
+ $redirect_host = ( is_array( $redirect_url ) && ! empty( $redirect_url['host'] ) ) ? $redirect_url['host'] : '';
166
+
167
+ // check if we are redirecting locally
168
+ if ( empty( $redirect_host ) || $redirect_host == $this_host ) {
169
+ $redirect_from_url = preg_replace( '/(http:\/\/|https:\/\/|www\.)/i', '', home_url() . $redirect_from );
170
+ $redirect_to_url = $redirect_to;
171
+ if ( ! preg_match( '/https?:\/\//i', $redirect_to_url ) )
172
+ $redirect_to_url = $this_host . $redirect_to_url;
173
+ else
174
+ $redirect_to_url = preg_replace( '/(http:\/\/|https:\/\/|www\.)/i', '', $redirect_to_url );
175
+
176
+ // possible loop/chain found
177
+ if ( $redirect_to_url == $redirect_from_url )
178
+ return true;
179
+ }
180
+ }
181
+ }
182
+
183
+ return false;
184
+ }
185
+
186
+ /**
187
+ * Filters title out for redirect from in post manager
188
+ *
189
+ * @since 1.0
190
+ * @param string $title
191
+ * @param int $post_id
192
+ * @uses is_admin
193
+ * @return string
194
+ */
195
+ public function filter_admin_title( $title, $post_id ) {
196
+ if ( ! is_admin() || false === ( $redirect = get_post( $post_id ) ) || $redirect->post_type != $this->redirect_post_type )
197
+ return $title;
198
+
199
+ $redirect_from = get_post_meta( $post_id, $this->meta_key_redirect_from, true );
200
+ if ( ! empty( $redirect_from ) )
201
+ return $redirect_from;
202
+
203
+ return $title;
204
+ }
205
+
206
+ /**
207
+ * Customizes updated messages for redirects
208
+ *
209
+ * @since 1.0
210
+ * @param array $messages
211
+ * @uses esc_url, get_permalink, add_query_var, wp_post_revision_title
212
+ * @return array
213
+ */
214
+ public function filter_redirect_updated_messages( $messages ) {
215
+ global $post, $post_ID;
216
+
217
+ $messages[$this->redirect_post_type] = array(
218
+ 0 => '', // Unused. Messages start at index 1.
219
+ 1 => sprintf( __( 'Redirect rule updated.', 'safe-redirect-manager' ), esc_url( get_permalink( $post_ID ) ) ),
220
+ 2 => __( 'Custom field updated.', 'safe-redirect-manager' ),
221
+ 3 => __( 'Custom field deleted.', 'safe-redirect-manager' ),
222
+ 4 => __( 'Redirect rule updated.', 'safe-redirect-manager' ),
223
+ /* translators: %s: date and time of the revision */
224
+ 5 => isset( $_GET['revision'] ) ? sprintf( __('Redirect rule restored to revision from %s', 'safe-redirect-manager' ), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
225
+ 6 => sprintf( __( 'Redirect rule published.', 'safe-redirect-manager' ), esc_url( get_permalink( $post_ID ) ) ),
226
+ 7 => __( 'Redirect rule saved.', 'safe-redirect-manager' ),
227
+ 8 => sprintf( __( 'Redirect rule submitted.', 'safe-redirect-manager' ), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post_ID ) ) ) ),
228
+ 9 => sprintf( __( 'Redirect rule scheduled for: <strong>%1$s</strong>.', 'safe-redirect-manager' ),
229
+ // translators: Publish box date format, see http://php.net/date
230
+ date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post_ID) ) ),
231
+ 10 => sprintf( __( 'Redirect rule draft updated.', 'safe-redirect-manager' ), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post_ID ) ) ) ),
232
+ );
233
+
234
+ return $messages;
235
+ }
236
+
237
+ /**
238
+ * Clear redirect cache if appropriate post type is transitioned
239
+ *
240
+ * @since 1.0
241
+ * @param string $new_status
242
+ * @param string $old_status
243
+ * @param object $post
244
+ * @uses delete_transient
245
+ * @return void
246
+ */
247
+ public function action_transition_post_status( $new_status, $old_status, $post ) {
248
+ if ( ! is_object( $post ) )
249
+ return;
250
+
251
+ // recreate redirect cache
252
+ if ( $this->redirect_post_type == $post->post_type ) {
253
+ delete_transient( $this->cache_key_redirects );
254
+ $this->update_redirect_cache();
255
+ }
256
+ }
257
+
258
+ /**
259
+ * Displays custom columns on redirect manager screen
260
+ *
261
+ * @since 1.0
262
+ * @param string $column
263
+ * @param int $post_id
264
+ * @uses get_post_meta, esc_html, admin_url
265
+ * @return void
266
+ */
267
+ public function action_custom_redirect_columns( $column, $post_id ) {
268
+ if ( 'srm' . $this->meta_key_redirect_to == $column ) {
269
+ echo esc_html( get_post_meta( $post_id, $this->meta_key_redirect_to, true ) );
270
+ } elseif ( 'srm' . $this->meta_key_redirect_status_code == $column ) {
271
+ echo absint( get_post_meta( $post_id, $this->meta_key_redirect_status_code, true ) );
272
+ }
273
+ }
274
+
275
+ /**
276
+ * Add new columns to manage redirect screen
277
+ *
278
+ * @since 1.0
279
+ * @param array $columns
280
+ * @return array
281
+ */
282
+ public function filter_redirect_columns( $columns ) {
283
+ $columns['srm' . $this->meta_key_redirect_to] = __( 'Redirect To', 'safe-redirect-manager' );
284
+ $columns['srm'. $this->meta_key_redirect_status_code] = __( 'HTTP Status Code', 'safe-redirect-manager' );
285
+
286
+ // Change the title column
287
+ $columns['title'] = __( 'Redirect From', 'safe-redirect-manager' );
288
+
289
+ // Move date column to the back
290
+ unset($columns['date']);
291
+ $columns['date'] = __( 'Date', 'safe-redirect-manager' );
292
+
293
+ return $columns;
294
+ }
295
+
296
+ /**
297
+ * Saves meta info for redirect rules
298
+ *
299
+ * @since 1.0
300
+ * @param int $post_id
301
+ * @uses current_user_can, get_post_type, wp_verify_nonce, update_post_meta, delete_post_meta
302
+ * @return void
303
+ */
304
+ public function action_save_post( $post_id ) {
305
+ if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || ! current_user_can( 'edit_post', $post_id ) || 'revision' == get_post_type( $post_id ) )
306
+ return;
307
+
308
+ // Update post meta for redirect rules
309
+ if ( ! empty( $_POST[$this->redirect_nonce_name] ) && wp_verify_nonce( $_POST[$this->redirect_nonce_name], $this->redirect_nonce_action ) ) {
310
+
311
+ if ( ! empty( $_POST['srm' . $this->meta_key_redirect_from] ) ) {
312
+ update_post_meta( $post_id, $this->meta_key_redirect_from, $this->sanitize_redirect_from( $_POST['srm' . $this->meta_key_redirect_from] ) );
313
+ } else {
314
+ delete_post_meta( $post_id, $this->meta_key_redirect_from );
315
+ }
316
+
317
+ if ( ! empty( $_POST['srm' . $this->meta_key_redirect_to] ) ) {
318
+ update_post_meta( $post_id, $this->meta_key_redirect_to, $this->sanitize_redirect_to( $_POST['srm' . $this->meta_key_redirect_to] ) );
319
+ } else {
320
+ delete_post_meta( $post_id, $this->meta_key_redirect_to );
321
+ }
322
+
323
+ if ( ! empty( $_POST['srm' . $this->meta_key_redirect_status_code] ) ) {
324
+ update_post_meta( $post_id, $this->meta_key_redirect_status_code, absint( $_POST['srm' . $this->meta_key_redirect_status_code] ) );
325
+ } else {
326
+ delete_post_meta( $post_id, $this->meta_key_redirect_status_code );
327
+ }
328
+ }
329
+ }
330
+
331
+ /**
332
+ * Registers post types for plugin
333
+ *
334
+ * @since 1.0
335
+ * @uses register_post_type, _x, plugins_url
336
+ * @return void
337
+ */
338
+ public function action_register_post_types() {
339
+ $redirect_labels = array(
340
+ 'name' => _x( 'Safe Redirect Manager', 'post type general name' ),
341
+ 'singular_name' => _x( 'Redirect', 'post type singular name' ),
342
+ 'add_new' => _x( 'Create Redirect Rule', $this->redirect_post_type ),
343
+ 'add_new_item' => __( 'Safe Redirect Manager', 'safe-redirect-manager' ),
344
+ 'edit_item' => __( 'Edit Redirect Rule', 'safe-redirect-manager' ),
345
+ 'new_item' => __( 'New Redirect Rule', 'safe-redirect-manager' ),
346
+ 'all_items' => __( 'Safe Redirect Manager', 'safe-redirect-manager' ),
347
+ 'view_item' => __( 'View Redirect Rule', 'safe-redirect-manager' ),
348
+ 'search_items' => __( 'Search Redirects', 'safe-redirect-manager' ),
349
+ 'not_found' => __( 'No redirect rules found.', 'safe-redirect-manager' ),
350
+ 'not_found_in_trash' => __( 'No redirect rules found in trash.', 'safe-redirect-manager' ),
351
+ 'parent_item_colon' => '',
352
+ 'menu_name' => __( 'Safe Redirect Manager', 'safe-redirect-manager' )
353
+ );
354
+ $redirect_args = array(
355
+ 'labels' => $redirect_labels,
356
+ 'public' => false,
357
+ 'publicly_queryable' => true,
358
+ 'show_ui' => true,
359
+ 'show_in_menu' => 'tools.php',
360
+ 'query_var' => false,
361
+ 'rewrite' => false,
362
+ 'capability_type' => 'post',
363
+ 'has_archive' => false,
364
+ 'hierarchical' => false,
365
+ 'register_meta_box_cb' => array( $this, 'action_redirect_rule_metabox' ),
366
+ 'menu_position' => 80,
367
+ 'supports' => array( '' )
368
+ );
369
+ register_post_type( $this->redirect_post_type, $redirect_args );
370
+ }
371
+
372
+ /**
373
+ * Registers meta boxes for redirect rule post type
374
+ *
375
+ * @since 1.0
376
+ * @uses add_meta_box
377
+ * @return void
378
+ */
379
+ public function action_redirect_rule_metabox() {
380
+ add_meta_box( 'redirect_settings', __( 'Redirect Settings', 'safe-redirect-manager' ), array( $this, 'redirect_rule_metabox' ), $this->redirect_post_type, 'normal', 'core' );
381
+ }
382
+
383
+ /**
384
+ * Echoes HTML for redirect rule meta box
385
+ *
386
+ * @since 1.0
387
+ * @param object $post
388
+ * @uses wp_nonce_field, get_post_meta, esc_attr, selected
389
+ * @return void
390
+ */
391
+ public function redirect_rule_metabox( $post ) {
392
+ wp_nonce_field( $this->redirect_nonce_action, $this->redirect_nonce_name );
393
+
394
+ $redirect_from = get_post_meta( $post->ID, $this->meta_key_redirect_from, true );
395
+ $redirect_to = get_post_meta( $post->ID, $this->meta_key_redirect_to, true );
396
+ $status_code = get_post_meta( $post->ID, $this->meta_key_redirect_status_code, true );
397
+ if ( empty( $status_code ) )
398
+ $status_code = 302;
399
+ ?>
400
+ <p>
401
+ <label for="srm<?php echo $this->meta_key_redirect_from; ?>"><?php _e( 'Redirect From:', 'safe-redirect-manager' ); ?></label><br />
402
+ <input class="widefat" type="text" name="srm<?php echo $this->meta_key_redirect_from; ?>" id="srm<?php echo $this->meta_key_redirect_from; ?>" value="<?php echo esc_attr( $redirect_from ); ?>" /><br />
403
+ <em><?php _e( 'This path should be relative to the root of this WordPress installation (or the sub-site, if you are running a multi-site).', 'safe-redirect-manager' ); ?></em>
404
+ </p>
405
+
406
+ <p>
407
+ <label for="srm<?php echo $this->meta_key_redirect_to; ?>"><?php _e( 'Redirect To:', 'safe-redirect-manager' ); ?></label><br />
408
+ <input class="widefat" type="text" name="srm<?php echo $this->meta_key_redirect_to; ?>" id="srm<?php echo $this->meta_key_redirect_to; ?>" value="<?php echo esc_attr( $redirect_to ); ?>" /><br />
409
+ <em><?php _e( 'This can be a URL or a path relative to the root of your website (not your WordPress installation).', 'safe-redirect-manager'); ?></em>
410
+ </p>
411
+
412
+ <p>
413
+ <label for="srm<?php echo $this->meta_key_redirect_status_code; ?>"><?php _e( 'HTTP Status Code:', 'safe-redirect-manager' ); ?></label>
414
+ <select name="srm<?php echo $this->meta_key_redirect_status_code; ?>" id="srm<?php echo $this->meta_key_redirect_status_code; ?>">
415
+ <?php foreach ( $this->valid_status_codes as $code ) : ?>
416
+ <option <?php selected( $status_code, $code ); ?>><?php echo $code; ?></option>
417
+ <?php endforeach; ?>
418
+ </select>
419
+ <em><?php _e( "If you don't know what this is, leave it as is.", 'safe-redirect-manager' ); ?></em>
420
+ </p>
421
+ <?php
422
+ }
423
+
424
+ /**
425
+ * Localize plugin
426
+ *
427
+ * @since 1.0
428
+ * @uses load_plugin_textdomain, plugin_basename
429
+ * @return void
430
+ */
431
+ public function action_admin_init() {
432
+ load_plugin_textdomain( 'safe-redirect-manager', false, dirname( plugin_basename( __FILE__ ) ) . '/localization/' );
433
+ }
434
+
435
+ /**
436
+ * Apply whitelisted hosts to allowed_redirect_hosts filter
437
+ *
438
+ * @since 1.0
439
+ * @param array $content
440
+ * @return array
441
+ */
442
+ public function filter_allowed_redirect_hosts( $content ) {
443
+
444
+ foreach ( $this->whitelist_hosts as $host ) {
445
+ $without_www = preg_replace( '/^www\./i', '', $host );
446
+ $with_www = 'www.' . $without_www;
447
+
448
+ if ( ! in_array( $without_www, $content ) ) $content[] = $without_www;
449
+ if ( ! in_array( $with_www, $content ) ) $content[] = $with_www;
450
+ }
451
+
452
+ return $content;
453
+ }
454
+
455
+ /**
456
+ * Force update on the redirect cache and return cache
457
+ *
458
+ * @since 1.0
459
+ * @uses set_transient, get_post_meta, the_post, have_posts, get_the_ID
460
+ * @return array
461
+ */
462
+ public function update_redirect_cache() {
463
+ global $post;
464
+ $old_post = $post;
465
+
466
+ $args = array(
467
+ 'posts_per_page' => 1000,
468
+ 'post_type' => $this->redirect_post_type,
469
+ 'no_found_rows' => true,
470
+ 'update_term_cache' => false,
471
+ );
472
+ $redirect_query = new WP_Query( $args );
473
+ $redirect_cache = array();
474
+
475
+ if ( $redirect_query->have_posts() ) {
476
+ while ( $redirect_query->have_posts() ) {
477
+ $redirect_query->the_post();
478
+
479
+ $redirect_from = get_post_meta( get_the_ID(), $this->meta_key_redirect_from, true );
480
+ $redirect_to = get_post_meta( get_the_ID(), $this->meta_key_redirect_to, true );
481
+ $status_code = get_post_meta( get_the_ID(), $this->meta_key_redirect_status_code, true );
482
+
483
+ if ( ! empty( $redirect_from ) && ! empty( $redirect_to ) ) {
484
+ $redirect_cache[] = array(
485
+ 'redirect_from' => $redirect_from,
486
+ 'redirect_to' => $redirect_to,
487
+ 'status_code' => absint( $status_code )
488
+ );
489
+ }
490
+ }
491
+ }
492
+ $post = $old_post;
493
+ set_transient( $this->cache_key_redirects, $redirect_cache );
494
+
495
+ return $redirect_cache;
496
+ }
497
+
498
+ /**
499
+ * Check current url against redirects
500
+ *
501
+ * @since 1.0
502
+ * @param object $current_request
503
+ * @uses esc_url_raw, wp_safe_redirect, untrailingslashit, get_transient, add_filter
504
+ * @return void
505
+ */
506
+ public function action_parse_request( $current_request ) {
507
+
508
+ // get requested path and add a / before it
509
+ $requested_path = '/' . ltrim( trim( $current_request->request ), '/' );
510
+
511
+ // get redirects from cache or recreate it
512
+ if ( false === ( $redirects = get_transient( $this->cache_key_redirects ) ) ) {
513
+ $redirects = $this->update_redirect_cache();
514
+ }
515
+
516
+ foreach ( $redirects as $redirect ) {
517
+
518
+ $redirect_from = untrailingslashit( $redirect['redirect_from'] );
519
+ if ( empty( $redirect_from ) )
520
+ $redirect_from = '/'; // this only happens in the case where there is a redirect on the root
521
+
522
+ $redirect_to = $redirect['redirect_to'];
523
+ $status_code = $redirect['status_code'];
524
+
525
+ // check if requested path is the same as the redirect from path
526
+ if ( $requested_path == $redirect_from ) {
527
+
528
+ // whitelist redirect to host if necessary
529
+ $parsed_redirect = parse_url( $redirect_to );
530
+ if ( is_array( $parsed_redirect ) && ! empty( $parsed_redirect['host'] ) ) {
531
+ $this->whitelist_hosts[] = $parsed_redirect['host'];
532
+ add_filter( 'allowed_redirect_hosts' , array( $this, 'filter_allowed_redirect_hosts' ) );
533
+ }
534
+
535
+ // if we have a valid status code, then redirect with it
536
+ if ( in_array( $status_code, $this->valid_status_codes ) )
537
+ wp_safe_redirect( esc_url_raw( $redirect_to ), $status_code );
538
+ else
539
+ wp_safe_redirect( esc_url_raw( $redirect_to ) );
540
+ exit;
541
+ }
542
+ }
543
+ }
544
+
545
+ /**
546
+ * Sanitize redirect to path
547
+ *
548
+ * The only difference between this function and just calling esc_url_raw is
549
+ * esc_url_raw( 'test' ) == 'http://test', whereas sanitize_redirect_path( 'test' ) == '/test'
550
+ *
551
+ * @since 1.0
552
+ * @param string $path
553
+ * @uses esc_url_raw
554
+ * @return string
555
+ */
556
+ public function sanitize_redirect_to( $path ) {
557
+ $path = trim( $path );
558
+
559
+ if ( preg_match( '/^www\./i', $path ) )
560
+ $path = 'http://' . $path;
561
+
562
+ if ( ! preg_match( '/^https?:\/\//i', $path ) )
563
+ if ( strpos( $path, '/' ) !== 0 )
564
+ $path = '/' . $path;
565
+
566
+ return esc_url_raw( $path );
567
+ }
568
+
569
+ /**
570
+ * Sanitize redirect from path
571
+ *
572
+ * @since 1.0
573
+ * @param string $path
574
+ * @uses esc_url_raw
575
+ * @return string
576
+ */
577
+ public function sanitize_redirect_from( $path ) {
578
+
579
+ $path = trim( $path );
580
+
581
+ if ( empty( $path ) )
582
+ return '';
583
+
584
+ // dont accept paths starting with a .
585
+ if ( strpos( $path, '.' ) === 0 )
586
+ return '';
587
+
588
+ // turn path in to absolute
589
+ if ( preg_match( '/https?:\/\//i', $path ) )
590
+ $path = preg_replace( '/^(http:\/\/|https:\/\/)(www\.)?[^\/?]+\/?(.*)/i', '/$3', $path );
591
+ elseif ( strpos( $path, '/' ) !== 0 )
592
+ $path = '/' . $path;
593
+
594
+ return esc_url_raw( $path );
595
+ }
596
+ }
597
+
598
+ new SRM_Safe_Redirect_Manager();