Safe Redirect Manager - Version 1.6

Version Description

(Dec. 11, 2012) = * Bulk delete redirects from the Manage Redirects screen * wp-cli coverage including subcommands for creating, deleting, and listing redirects, and importing .htaccess files

Download this release

Release Info

Developer danielbachhuber
Plugin Icon 128x128 Safe Redirect Manager
Version 1.6
Comparing to
See all releases

Code changes from version 1.5 to 1.6

Files changed (3) hide show
  1. inc/wp-cli.php +180 -0
  2. readme.txt +6 -2
  3. safe-redirect-manager.php +76 -47
inc/wp-cli.php ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * wp-cli integration
4
+ */
5
+
6
+ WP_CLI::add_command( 'safe-redirect-manager', 'Safe_Redirect_Manager_CLI' );
7
+
8
+ class Safe_Redirect_Manager_CLI extends WP_CLI_Command {
9
+
10
+
11
+ /**
12
+ * List all of the currently configured redirects
13
+ *
14
+ * @subcommand list
15
+ */
16
+ public function _list() {
17
+ global $safe_redirect_manager;
18
+
19
+ $fields = array(
20
+ 'ID',
21
+ 'redirect_from',
22
+ 'redirect_to',
23
+ 'status_code',
24
+ 'enable_regex',
25
+ 'post_status',
26
+ );
27
+
28
+ $table = new \cli\Table();
29
+ $table->setHeaders( $fields );
30
+
31
+ $redirects = $safe_redirect_manager->get_redirects( array( 'post_status' => 'any' ) );
32
+ foreach( $redirects as $redirect ) {
33
+ $line = array();
34
+ foreach( $fields as $field ) {
35
+ if ( 'enable_regex' == $field )
36
+ $line[] = ( $redirect[$field] ) ? 'true' : 'false';
37
+ else
38
+ $line[] = $redirect[$field];
39
+ }
40
+ $table->addRow( $line );
41
+ }
42
+ $table->display();
43
+
44
+ WP_CLI::line( "Total of " . count( $redirects ) . " redirects" );
45
+ }
46
+
47
+ /**
48
+ * Create a redirect
49
+ *
50
+ * @subcommand create
51
+ * @synopsis <from> <to> [<status-code>] [<enable-regex>] [<post-status>]
52
+ */
53
+ public function create( $args ) {
54
+ global $safe_redirect_manager;
55
+
56
+ $defaults = array(
57
+ '',
58
+ '',
59
+ 302,
60
+ false,
61
+ 'publish',
62
+ );
63
+ // array_merge() doesn't work here because our keys are numeric
64
+ foreach( $defaults as $key => $value ) {
65
+ if ( ! isset( $args[$key] ) )
66
+ $args[$key] = $defaults[$key];
67
+ }
68
+ list( $from, $to, $status_code, $enable_regex, $post_status ) = $args;
69
+
70
+ // User might've passed as string.
71
+ if ( 'false' == $enable_regex )
72
+ $enable_regex = false;
73
+
74
+ if ( empty( $from ) || empty( $to ) )
75
+ WP_CLI::error( "<from> and <to> are required arguments." );
76
+
77
+ $ret = $safe_redirect_manager->create_redirect( $from, $to, $status_code, $enable_regex, $post_status );
78
+ if ( is_wp_error( $ret ) )
79
+ WP_CLI::error( $ret->get_error_message() );
80
+ else
81
+ WP_CLI::success( "Created redirect as #{$ret}" );
82
+ }
83
+
84
+ /**
85
+ * Delete a redirect
86
+ *
87
+ * @subcommand delete
88
+ * @synopsis <id>
89
+ */
90
+ public function delete( $args ) {
91
+ global $safe_redirect_manager;
92
+
93
+ $id = ( ! empty( $args[0] ) ) ? (int)$args[0] : 0;
94
+
95
+ $redirect = get_post( $id );
96
+ if ( ! $redirect || $safe_redirect_manager->redirect_post_type != $redirect->post_type )
97
+ WP_CLI::error( "{$id} isn't a valid redirect." );
98
+
99
+ wp_delete_post( $id );
100
+ $safe_redirect_manager->update_redirect_cache();
101
+ WP_CLI::success( "Redirect #{$id} has been deleted." );
102
+ }
103
+
104
+ /**
105
+ * Update the redirect cache
106
+ *
107
+ * @subcommand update-cache
108
+ */
109
+ public function update_cache() {
110
+ global $safe_redirect_manager;
111
+
112
+ $safe_redirect_manager->update_redirect_cache();
113
+ WP_CLI::success( "Redirect cache has been updated." );
114
+ }
115
+
116
+ /**
117
+ * Import .htaccess file redirects
118
+ *
119
+ * @subcommand import-htaccess
120
+ * @synopsis <file>
121
+ */
122
+ public function import_htaccess( $args, $assoc_args ) {
123
+ global $safe_redirect_manager;
124
+
125
+ list( $file ) = $args;
126
+
127
+ $contents = file_get_contents( $file );
128
+ if ( ! $contents )
129
+ WP_CLI::error( "Error retrieving .htaccess file" );
130
+
131
+ $pieces = explode( PHP_EOL, $contents );
132
+ $created = 0;
133
+ $skipped = 0;
134
+ foreach( $pieces as $piece ) {
135
+
136
+ // Ignore if this line isn't a redirect
137
+ if ( ! preg_match( '/^Redirect( permanent)?/i', $piece ) )
138
+ continue;
139
+
140
+ // Parse the redirect
141
+ $redirect = preg_replace( '/\s{2,}/', ' ', $piece );
142
+ $redirect = preg_replace( '/^Redirect( permanent)? (.*)$/i', '$2', trim( $redirect ) );
143
+ $redirect = explode( ' ', $redirect );
144
+
145
+ // if there are three parts to the redirect, we assume the first part is a status code
146
+ if ( 2 == count( $redirect ) ) {
147
+ $from = $redirect[0];
148
+ $to = $redirect[1];
149
+ $http_status = 301;
150
+ } elseif ( 3 == count( $redirect ) ) {
151
+ $http_status = $redirect[0];
152
+ $from = $redirect[1];
153
+ $to = $redirect[2];
154
+ } else {
155
+ continue;
156
+ }
157
+
158
+ // Validate
159
+ if ( ! $from || ! $to ) {
160
+ WP_CLI::warning( "Skipping - '{$piece}' is formatted improperly." );
161
+ continue;
162
+ }
163
+
164
+ $sanitized_redirect_from = $safe_redirect_manager->sanitize_redirect_from( $from );
165
+ $sanitized_redirect_to = $safe_redirect_manager->sanitize_redirect_to( $to );
166
+
167
+ $id = $safe_redirect_manager->create_redirect( $sanitized_redirect_from, $sanitized_redirect_to, $http_status );
168
+ if ( is_wp_error( $id ) ) {
169
+ WP_CLI::warning( "Error - " . $id->get_error_message() );
170
+ $skipped++;
171
+ } else {
172
+ WP_CLI::line( "Success - Created redirect from '{$sanitized_redirect_from}' to '{$sanitized_redirect_to}'" );
173
+ $created++;
174
+ }
175
+ }
176
+ WP_CLI::success( "All done! {$created} redirects were created, {$skipped} were skipped" );
177
+ }
178
+
179
+
180
+ }
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Contributors: tlovett1, tollmanz, taylorde, 10up, jakemgold, 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.2
6
- Stable tag: 1.5
7
 
8
  Safely and easily manage your website's HTTP redirects.
9
 
@@ -24,6 +24,10 @@ Extract the zip file and just drop the contents in the wp-content/plugins/ direc
24
 
25
  == Changelog ==
26
 
 
 
 
 
27
  = 1.5 (Nov. 7 2012) =
28
  * Regular expressions allowed in redirects
29
  * New filter 'srm_registered_redirects' allows you to conditionally unset redirects based on context, user permissions, etc. Thanks [jtsternberg](https://github.com/jtsternberg) for the pull request.
2
  Contributors: tlovett1, tollmanz, taylorde, 10up, jakemgold, danielbachhuber, VentureBeat
3
  Tags: http redirects, redirect manager, url redirection, safe http redirection
4
  Requires at least: 3.1
5
+ Tested up to: 3.5
6
+ Stable tag: 1.6
7
 
8
  Safely and easily manage your website's HTTP redirects.
9
 
24
 
25
  == Changelog ==
26
 
27
+ = 1.6 (Dec. 11, 2012) =
28
+ * Bulk delete redirects from the Manage Redirects screen
29
+ * wp-cli coverage including subcommands for creating, deleting, and listing redirects, and importing .htaccess files
30
+
31
  = 1.5 (Nov. 7 2012) =
32
  * Regular expressions allowed in redirects
33
  * New filter 'srm_registered_redirects' allows you to conditionally unset redirects based on context, user permissions, etc. Thanks [jtsternberg](https://github.com/jtsternberg) for the pull request.
safe-redirect-manager.php CHANGED
@@ -4,7 +4,7 @@ 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.5
8
  Author URI: http://www.10up.com
9
 
10
  GNU General Public License, Free Software Foundation <http://creativecommons.org/licenses/GPL/2.0/>
@@ -25,6 +25,9 @@ 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';
@@ -63,7 +66,7 @@ class SRM_Safe_Redirect_Manager {
63
  add_filter( 'post_updated_messages', array( $this, 'filter_redirect_updated_messages' ) );
64
  add_action( 'admin_notices', array( $this, 'action_redirect_chain_alert' ) );
65
  add_filter( 'the_title', array( $this, 'filter_admin_title' ), 100, 2 );
66
- add_filter( 'bulk_actions-' . 'edit-redirect_rule', array( $this, 'filter_bulk_actions' ) );
67
  add_action( 'admin_print_styles-edit.php', array( $this, 'action_print_logo_css' ), 10, 1 );
68
  add_action( 'admin_print_styles-post.php', array( $this, 'action_print_logo_css' ), 10, 1 );
69
  add_action( 'admin_print_styles-post-new.php', array( $this, 'action_print_logo_css' ), 10, 1 );
@@ -188,13 +191,17 @@ class SRM_Safe_Redirect_Manager {
188
  }
189
 
190
  /**
191
- * Removes bulk actions from post manager
192
  *
193
  * @since 1.0
194
  * @return array
195
  */
196
- public function filter_bulk_actions() {
197
- return array();
 
 
 
 
198
  }
199
 
200
  /**
@@ -203,35 +210,49 @@ class SRM_Safe_Redirect_Manager {
203
  * @param string $redirect_from
204
  * @param string $redirect_to
205
  * @param int $status_code
 
 
206
  * @since 1.3
207
  * @uses wp_insert_post, update_post_meta
208
- * @return int
209
  */
210
- public function create_redirect( $redirect_from, $redirect_to, $status_code ) {
 
 
211
  $sanitized_redirect_from = $this->sanitize_redirect_from( $redirect_from );
212
  $sanitized_redirect_to = $this->sanitize_redirect_to( $redirect_to );
213
  $sanitized_status_code = absint( $status_code );
 
 
214
 
215
  // check and make sure no parameters are empty or invalid after sanitation
216
- if ( empty( $sanitized_redirect_from ) || empty( $sanitized_redirect_to ) || ! in_array( $sanitized_status_code, $this->valid_status_codes ) )
217
- return 0;
 
 
 
 
 
 
 
218
 
219
  // create the post
220
  $post_args = array(
221
  'post_type' => $this->redirect_post_type,
222
- 'post_status' => 'publish',
223
  'post_author' => 1
224
  );
225
 
226
- $post_id = wp_insert_post( $post_args );
227
 
228
  if ( 0 >= $post_id )
229
- return 0;
230
 
231
  // update the posts meta info
232
  update_post_meta( $post_id, $this->meta_key_redirect_from, $sanitized_redirect_from );
233
  update_post_meta( $post_id, $this->meta_key_redirect_to, $sanitized_redirect_to );
234
  update_post_meta( $post_id, $this->meta_key_redirect_status_code, $sanitized_status_code );
 
235
 
236
  // We need to update the cache after creating this redirect
237
  $this->update_redirect_cache();
@@ -452,9 +473,6 @@ class SRM_Safe_Redirect_Manager {
452
  unset( $columns['date'] );
453
  $columns['date'] = __( 'Date', 'safe-redirect-manager' );
454
 
455
- // get rid of checkboxes
456
- unset( $columns['cb'] );
457
-
458
  return $columns;
459
  }
460
 
@@ -648,6 +666,46 @@ class SRM_Safe_Redirect_Manager {
648
  return $content;
649
  }
650
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
651
  /**
652
  * Force update on the redirect cache and return cache
653
  *
@@ -656,39 +714,9 @@ class SRM_Safe_Redirect_Manager {
656
  * @return array
657
  */
658
  public function update_redirect_cache() {
659
- global $post;
660
- $old_post = $post;
661
 
662
- $args = array(
663
- 'posts_per_page' => 1000,
664
- 'post_type' => $this->redirect_post_type,
665
- 'no_found_rows' => true,
666
- 'update_term_cache' => false,
667
- 'post_status' => 'publish'
668
- );
669
- $redirect_query = new WP_Query( $args );
670
- $redirect_cache = array();
671
-
672
- if ( $redirect_query->have_posts() ) {
673
- while ( $redirect_query->have_posts() ) {
674
- $redirect_query->the_post();
675
-
676
- $redirect_from = get_post_meta( get_the_ID(), $this->meta_key_redirect_from, true );
677
- $redirect_to = get_post_meta( get_the_ID(), $this->meta_key_redirect_to, true );
678
- $status_code = get_post_meta( get_the_ID(), $this->meta_key_redirect_status_code, true );
679
- $enable_regex = get_post_meta( get_the_ID(), $this->meta_key_enable_redirect_from_regex, true );
680
-
681
- if ( ! empty( $redirect_from ) && ! empty( $redirect_to ) ) {
682
- $redirect_cache[] = array(
683
- 'redirect_from' => $redirect_from,
684
- 'redirect_to' => $redirect_to,
685
- 'status_code' => absint( $status_code ),
686
- 'enable_regex' => (bool) $enable_regex
687
- );
688
- }
689
- }
690
- }
691
- $post = $old_post;
692
  set_transient( $this->cache_key_redirects, $redirect_cache );
693
 
694
  return $redirect_cache;
@@ -714,6 +742,7 @@ class SRM_Safe_Redirect_Manager {
714
 
715
  // get requested path and add a / before it
716
  $requested_path = sanitize_text_field( $_SERVER['REQUEST_URI'] );
 
717
 
718
  /**
719
  * If WordPress resides in a directory that is not the public root, we have to chop
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.6
8
  Author URI: http://www.10up.com
9
 
10
  GNU General Public License, Free Software Foundation <http://creativecommons.org/licenses/GPL/2.0/>
25
 
26
  */
27
 
28
+ if ( defined( 'WP_CLI' ) && WP_CLI )
29
+ require_once dirname( __FILE__ ) . '/inc/wp-cli.php';
30
+
31
  class SRM_Safe_Redirect_Manager {
32
 
33
  public $redirect_post_type = 'redirect_rule';
66
  add_filter( 'post_updated_messages', array( $this, 'filter_redirect_updated_messages' ) );
67
  add_action( 'admin_notices', array( $this, 'action_redirect_chain_alert' ) );
68
  add_filter( 'the_title', array( $this, 'filter_admin_title' ), 100, 2 );
69
+ add_filter( 'bulk_actions-edit-' . $this->redirect_post_type, array( $this, 'filter_bulk_actions' ) );
70
  add_action( 'admin_print_styles-edit.php', array( $this, 'action_print_logo_css' ), 10, 1 );
71
  add_action( 'admin_print_styles-post.php', array( $this, 'action_print_logo_css' ), 10, 1 );
72
  add_action( 'admin_print_styles-post-new.php', array( $this, 'action_print_logo_css' ), 10, 1 );
191
  }
192
 
193
  /**
194
+ * Limit the bulk actions available in the Manage Redirects view
195
  *
196
  * @since 1.0
197
  * @return array
198
  */
199
+ public function filter_bulk_actions( $actions ) {
200
+
201
+ // No bulk editing at this time
202
+ unset( $actions['edit'] );
203
+
204
+ return $actions;
205
  }
206
 
207
  /**
210
  * @param string $redirect_from
211
  * @param string $redirect_to
212
  * @param int $status_code
213
+ * @param bool $enable_regex
214
+ * @param string $post_status
215
  * @since 1.3
216
  * @uses wp_insert_post, update_post_meta
217
+ * @return int|WP_Error
218
  */
219
+ public function create_redirect( $redirect_from, $redirect_to, $status_code = 302, $enable_regex = false, $post_status = 'publish' ) {
220
+ global $wpdb;
221
+
222
  $sanitized_redirect_from = $this->sanitize_redirect_from( $redirect_from );
223
  $sanitized_redirect_to = $this->sanitize_redirect_to( $redirect_to );
224
  $sanitized_status_code = absint( $status_code );
225
+ $sanitized_enable_regex = (bool)$enable_regex;
226
+ $sanitized_post_status = sanitize_key( $post_status );
227
 
228
  // check and make sure no parameters are empty or invalid after sanitation
229
+ if ( empty( $sanitized_redirect_from ) || empty( $sanitized_redirect_to ) )
230
+ return new WP_Error( 'invalid-argument', __( 'Redirect from and/or redirect to arguments are invalid.', 'safe-redirect-manager' ) );
231
+
232
+ if ( ! in_array( $sanitized_status_code, $this->valid_status_codes ) )
233
+ return new WP_Error( 'invalid-argument', __( 'Invalid status code.', 'safe-redirect-manager' ) );
234
+
235
+ // Check to ensure this redirect doesn't already exist
236
+ if ( $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key=%s AND meta_value=%s", $this->meta_key_redirect_from, $sanitized_redirect_from ) ) )
237
+ return new WP_Error( 'duplicate-redirect', sprintf( __( 'Redirect already exists for %s', 'safe-redirect-manager' ), $sanitized_redirect_from ) );
238
 
239
  // create the post
240
  $post_args = array(
241
  'post_type' => $this->redirect_post_type,
242
+ 'post_status' => $sanitized_post_status,
243
  'post_author' => 1
244
  );
245
 
246
+ $post_id = wp_insert_post( $post_args );
247
 
248
  if ( 0 >= $post_id )
249
+ return new WP_Error( 'error-creating', __( 'An error occurred creating the redirect.', 'safe-redirect-manager' ) );
250
 
251
  // update the posts meta info
252
  update_post_meta( $post_id, $this->meta_key_redirect_from, $sanitized_redirect_from );
253
  update_post_meta( $post_id, $this->meta_key_redirect_to, $sanitized_redirect_to );
254
  update_post_meta( $post_id, $this->meta_key_redirect_status_code, $sanitized_status_code );
255
+ update_post_meta( $post_id, $this->meta_key_enable_redirect_from_regex, $sanitized_enable_regex );
256
 
257
  // We need to update the cache after creating this redirect
258
  $this->update_redirect_cache();
473
  unset( $columns['date'] );
474
  $columns['date'] = __( 'Date', 'safe-redirect-manager' );
475
 
 
 
 
476
  return $columns;
477
  }
478
 
666
  return $content;
667
  }
668
 
669
+ /**
670
+ * Get redirects from the database
671
+ *
672
+ * @since 1.6
673
+ * @param array $args Any arguments to filter by
674
+ * @return array $redirects An array of redirects
675
+ */
676
+ public function get_redirects( $args = array() ) {
677
+
678
+ $defaults = array(
679
+ 'posts_per_page' => 1000,
680
+ 'post_status' => 'publish',
681
+ );
682
+
683
+ $query_args = array_merge( $defaults, $args );
684
+
685
+ // Some arguments that don't need to be configurable
686
+ $query_args['post_type'] = $this->redirect_post_type;
687
+ $query_args['no_found_rows'] = false;
688
+ $query_args['update_term_cache'] = false;
689
+
690
+ $redirect_query = new WP_Query( $query_args );
691
+
692
+ if ( empty( $redirect_query->posts ) )
693
+ return array();
694
+
695
+ $redirects = array();
696
+ foreach( $redirect_query->posts as $redirect ) {
697
+ $redirects[] = array(
698
+ 'ID' => $redirect->ID,
699
+ 'post_status' => $redirect->post_status,
700
+ 'redirect_from' => get_post_meta( $redirect->ID, $this->meta_key_redirect_from, true ),
701
+ 'redirect_to' => get_post_meta( $redirect->ID, $this->meta_key_redirect_to, true ),
702
+ 'status_code' => (int)get_post_meta( $redirect->ID, $this->meta_key_redirect_status_code, true ),
703
+ 'enable_regex' => (bool)get_post_meta( $redirect->ID, $this->meta_key_enable_redirect_from_regex, true ),
704
+ );
705
+ }
706
+ return $redirects;
707
+ }
708
+
709
  /**
710
  * Force update on the redirect cache and return cache
711
  *
714
  * @return array
715
  */
716
  public function update_redirect_cache() {
717
+
718
+ $redirect_cache = $this->get_redirects();
719
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
720
  set_transient( $this->cache_key_redirects, $redirect_cache );
721
 
722
  return $redirect_cache;
742
 
743
  // get requested path and add a / before it
744
  $requested_path = sanitize_text_field( $_SERVER['REQUEST_URI'] );
745
+ $requested_path = stripslashes( $requested_path );
746
 
747
  /**
748
  * If WordPress resides in a directory that is not the public root, we have to chop