Safe Redirect Manager - Version 1.7.6

Version Description

(Feb. 13, 2015) = * Use home_url() instead of site_url(). Props swalkinshaw * Don't redirect if redirect to location is invalid. Props vaurdan * Redirection plugin importer. Props eugene-manuilov

Download this release

Release Info

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

Code changes from version 1.7.5 to 1.7.6

.gitignore DELETED
@@ -1 +0,0 @@
1
- .svn
 
assets/banner-772x250.png DELETED
Binary file
assets/icon-256x256.png DELETED
Binary file
inc/wp-cli.php CHANGED
@@ -132,7 +132,7 @@ class Safe_Redirect_Manager_CLI extends WP_CLI_Command {
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;
@@ -141,7 +141,7 @@ class Safe_Redirect_Manager_CLI extends WP_CLI_Command {
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];
@@ -176,5 +176,73 @@ class Safe_Redirect_Manager_CLI extends WP_CLI_Command {
176
  WP_CLI::success( "All done! {$created} redirects were created, {$skipped} were skipped" );
177
  }
178
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
 
180
  }
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;
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];
176
  WP_CLI::success( "All done! {$created} redirects were created, {$skipped} were skipped" );
177
  }
178
 
179
+ /**
180
+ * Imports redirects from CSV file.
181
+ *
182
+ * ## OPTIONS
183
+ *
184
+ * <file>
185
+ * : Path to one or more valid CSV file for import. This file should contain
186
+ * redirection from and to URLs, regex flag and HTTP redirection code. Here
187
+ * is example table:
188
+ *
189
+ * | source | target | regex | code |
190
+ * |----------------------------|--------------------|-------|------|
191
+ * | /legacy-url | /new-url | 0 | 301 |
192
+ * | /category-1 | /new-category-slug | 0 | 302 |
193
+ * | /tes?t/[0-9]+/path/[^/]+/? | /go/here | 1 | 302 |
194
+ * | ... | ... | ... | ... |
195
+ *
196
+ * You can also use exported redirects from "Redirection" plugin, which you
197
+ * can download here: /wp-admin/tools.php?page=redirection.php&sub=modules
198
+ *
199
+ * <source-column>
200
+ * : Header title for sources column mapping.
201
+ *
202
+ * <target-column>
203
+ * : Header title for target column mapping.
204
+ *
205
+ * <regex-column>
206
+ * : Header title for regex column mapping.
207
+ *
208
+ * <code-column>
209
+ * : Header title for code column mapping.
210
+ *
211
+ * ## EXAMPLE
212
+ *
213
+ * wp safe-redirect-manager import redirections.csv
214
+ *
215
+ * @synopsis <file> [--source=<source-column>] [--target=<target-column>] [--regex=<regex-column>] [--code=<code-column>]
216
+ *
217
+ * @since 1.7.6
218
+ *
219
+ * @access public
220
+ * @global SRM_Safe_Redirect_Manager $safe_redirect_manager The plugin instance.
221
+ * @param array $args The array of input files.
222
+ * @param array $assoc_args The array of column mappings.
223
+ */
224
+ public function import( $args, $assoc_args ) {
225
+ global $safe_redirect_manager;
226
+
227
+ $mapping = wp_parse_args( $assoc_args, array(
228
+ 'source' => 'source',
229
+ 'target' => 'target',
230
+ 'regex' => 'regex',
231
+ 'code' => 'code',
232
+ ) );
233
+
234
+ $created = $skipped = 0;
235
+ foreach ( $args as $file ) {
236
+ $processed = $safe_redirect_manager->import_file( $file, $mapping );
237
+ if ( ! empty( $processed ) ) {
238
+ $created += $processed['created'];
239
+ $skipped += $processed['skipped'];
240
+
241
+ WP_CLI::success( basename( $file ) . ' file processed successfully.' );
242
+ }
243
+ }
244
+
245
+ WP_CLI::success( "All done! {$created} redirects were imported, {$skipped} were skipped" );
246
+ }
247
 
248
  }
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, multisite redirects
4
  Requires at least: 3.1
5
- Tested up to: 4.0
6
- Stable tag: 1.7.5
7
 
8
  Safely and easily manage your website's HTTP redirects.
9
 
@@ -24,6 +24,11 @@ Extract the zip file and just drop the contents in the wp-content/plugins/ direc
24
 
25
  == Changelog ==
26
 
 
 
 
 
 
27
  = 1.7.5 (Sept. 9, 2014) =
28
  * Don't always lowercase matched parts in redirect to replace. Props[francescolaffi](https://github.com/francescolaffi)
29
  * Plugin icon/banner
2
  Contributors: tlovett1, tollmanz, taylorde, 10up, jakemgold, danielbachhuber, VentureBeat
3
  Tags: http redirects, redirect manager, url redirection, safe http redirection, multisite redirects
4
  Requires at least: 3.1
5
+ Tested up to: 4.2
6
+ Stable tag: 1.7.6
7
 
8
  Safely and easily manage your website's HTTP redirects.
9
 
24
 
25
  == Changelog ==
26
 
27
+ = 1.7.6 (Feb. 13, 2015) =
28
+ * Use home_url() instead of site_url(). Props [swalkinshaw](https://github.com/swalkinshaw)
29
+ * Don't redirect if redirect to location is invalid. Props [vaurdan](https://github.com/vaurdan)
30
+ * Redirection plugin importer. Props [eugene-manuilov](https://github.com/eugene-manuilov)
31
+
32
  = 1.7.5 (Sept. 9, 2014) =
33
  * Don't always lowercase matched parts in redirect to replace. Props[francescolaffi](https://github.com/francescolaffi)
34
  * Plugin icon/banner
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)
7
- Version: 1.7.5
8
  Author URI: http://www.10up.com
9
 
10
  GNU General Public License, Free Software Foundation <http://creativecommons.org/licenses/GPL/2.0/>
@@ -805,9 +805,9 @@ class SRM_Safe_Redirect_Manager {
805
  * If WordPress resides in a directory that is not the public root, we have to chop
806
  * the pre-WP path off the requested path.
807
  */
808
- $parsed_site_url = parse_url( site_url() );
809
- if ( isset( $parsed_site_url['path'] ) && '/' != $parsed_site_url['path'] ) {
810
- $requested_path = preg_replace( '@' . $parsed_site_url['path'] . '@i', '', $requested_path, 1 );
811
  }
812
 
813
  // Allow redirects to be filtered
@@ -834,6 +834,10 @@ class SRM_Safe_Redirect_Manager {
834
  $status_code = $redirect['status_code'];
835
  $enable_regex = ( isset( $redirect['enable_regex'] ) ) ? $redirect['enable_regex'] : false;
836
 
 
 
 
 
837
  // check if requested path is the same as the redirect from path
838
  if ( $enable_regex ) {
839
  $matched_path = preg_match( '@' . $redirect_from . '@' . $regex_flag, $requested_path );
@@ -977,7 +981,81 @@ class SRM_Safe_Redirect_Manager {
977
 
978
  return home_url( $redirect_from );
979
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
980
  }
981
 
982
  global $safe_redirect_manager;
983
- $safe_redirect_manager = new SRM_Safe_Redirect_Manager();
4
  Plugin URI: http://www.10up.com
5
  Description: Easily and safely manage HTTP redirects.
6
  Author: Taylor Lovett (10up)
7
+ Version: 1.7.6
8
  Author URI: http://www.10up.com
9
 
10
  GNU General Public License, Free Software Foundation <http://creativecommons.org/licenses/GPL/2.0/>
805
  * If WordPress resides in a directory that is not the public root, we have to chop
806
  * the pre-WP path off the requested path.
807
  */
808
+ $parsed_home_url = parse_url( home_url() );
809
+ if ( isset( $parsed_home_url['path'] ) && '/' != $parsed_home_url['path'] ) {
810
+ $requested_path = preg_replace( '@' . $parsed_home_url['path'] . '@i', '', $requested_path, 1 );
811
  }
812
 
813
  // Allow redirects to be filtered
834
  $status_code = $redirect['status_code'];
835
  $enable_regex = ( isset( $redirect['enable_regex'] ) ) ? $redirect['enable_regex'] : false;
836
 
837
+ // check if the redirection destination is valid, otherwise just skip it
838
+ if ( empty( $redirect_to ) )
839
+ continue;
840
+
841
  // check if requested path is the same as the redirect from path
842
  if ( $enable_regex ) {
843
  $matched_path = preg_match( '@' . $redirect_from . '@' . $regex_flag, $requested_path );
981
 
982
  return home_url( $redirect_from );
983
  }
984
+
985
+ /**
986
+ * Imports redirects from CSV file or stream.
987
+ *
988
+ * @since 1.7.6
989
+ *
990
+ * @access public
991
+ * @param string|resource $file File path, file pointer or stream to read redirects from.
992
+ * @param array $args The array of arguments. Includes column mapping and CSV settings.
993
+ * @return array Returns importing statistic on success, otherwise FALSE.
994
+ */
995
+ public function import_file( $file, $args ) {
996
+ $handle = $file;
997
+ $close_handle = false;
998
+ $doing_wp_cli = defined( 'WP_CLI' ) && WP_CLI;
999
+
1000
+ // filter arguments
1001
+ $args = apply_filters( 'srm_import_file_args', $args );
1002
+
1003
+ // enable line endings auto detection
1004
+ @ini_set( 'auto_detect_line_endings', true );
1005
+
1006
+ // open file pointer if $file is not a resource
1007
+ if ( ! is_resource( $file ) ) {
1008
+ $handle = fopen( $file, 'rb' );
1009
+ if ( ! $handle ) {
1010
+ $doing_wp_cli && WP_CLI::error( sprintf( "Error retrieving %s file", basename( $file ) ) );
1011
+ return false;
1012
+ }
1013
+
1014
+ $close_handle = true;
1015
+ }
1016
+
1017
+ // process all rows of the file
1018
+ $created = $skipped = 0;
1019
+ $headers = fgetcsv( $handle );
1020
+ while( ( $row = fgetcsv( $handle ) ) ) {
1021
+ // validate
1022
+ $rule = array_combine( $headers, $row );
1023
+ if ( empty( $rule[$args['source']] ) || empty( $rule[$args['target']] ) ) {
1024
+ $doing_wp_cli && WP_CLI::warning( "Skipping - redirection rule is formatted improperly." );
1025
+ $skipped++;
1026
+ continue;
1027
+ }
1028
+
1029
+ // sanitize
1030
+ $redirect_from = $this->sanitize_redirect_from( $rule[$args['source']] );
1031
+ $redirect_to = $this->sanitize_redirect_to( $rule[$args['target']] );
1032
+ $status_code = ! empty( $rule[$args['code']] ) ? $rule[$args['code']] : 302;
1033
+ $regex = ! empty( $rule[$args['regex']] ) ? filter_var( $rule[$args['regex']], FILTER_VALIDATE_BOOLEAN ) : false;
1034
+
1035
+ // import
1036
+ $id = $this->create_redirect( $redirect_from, $redirect_to, $status_code, $regex );
1037
+ if ( is_wp_error( $id ) ) {
1038
+ $doing_wp_cli && WP_CLI::error( $id );
1039
+ $skipped++;
1040
+ } else {
1041
+ $doing_wp_cli && WP_CLI::line( "Success - Created redirect from '{$redirect_from}' to '{$redirect_to}'" );
1042
+ $created++;
1043
+ }
1044
+ }
1045
+
1046
+ // close an open file pointer if we've opened it
1047
+ if ( $close_handle ) {
1048
+ fclose( $handle );
1049
+ }
1050
+
1051
+ // return result statistic
1052
+ return array(
1053
+ 'created' => $created,
1054
+ 'skipped' => $skipped,
1055
+ );
1056
+ }
1057
+
1058
  }
1059
 
1060
  global $safe_redirect_manager;
1061
+ $safe_redirect_manager = new SRM_Safe_Redirect_Manager();
tests/test-core.php CHANGED
@@ -396,44 +396,89 @@ class SRMTestCore extends WP_UnitTestCase {
396
  $this->assertTrue( ! $redirected );
397
  }
398
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399
  /**
400
- * Test that replace (both wildcard and regex) doesn't change the casing on the matched part
 
 
401
  *
402
- * @since 1.7.5
 
403
  */
404
- public function testReplaceCasing() {
405
  global $safe_redirect_manager;
406
 
407
- // with wildcard
408
- $_SERVER['REQUEST_URI'] = '/myfiles1/FooBar.JPEG';
409
- $redirected = false;
410
- $redirect_to = '/images1/*';
411
- $safe_redirect_manager->create_redirect( '/myfiles1/*', $redirect_to );
412
-
413
- add_action( 'srm_do_redirect', function( $requested_path, $redirected_to, $status_code ) use ( &$redirect_to, &$redirected ) {
414
- if ( $redirected_to === '/images1/FooBar.JPEG' ) {
415
- $redirected = true;
416
- }
417
- }, 10, 3 );
418
-
419
- $safe_redirect_manager->action_parse_request();
420
-
421
- $this->assertTrue( $redirected );
422
-
423
- // with regex
424
- $_SERVER['REQUEST_URI'] = '/myfiles2/FooBar.JPEG';
425
- $redirected = false;
426
- $redirect_to = '/images2/$1';
427
- $safe_redirect_manager->create_redirect( '/myfiles2/(.*\.jpe?g)', $redirect_to, 301, true );
428
-
429
- add_action( 'srm_do_redirect', function( $requested_path, $redirected_to, $status_code ) use ( &$redirect_to, &$redirected ) {
430
- if ( $redirected_to === '/images2/FooBar.JPEG' ) {
431
- $redirected = true;
432
- }
433
- }, 10, 3 );
434
-
435
- $safe_redirect_manager->action_parse_request();
436
-
437
- $this->assertTrue( $redirected );
438
  }
 
439
  }
396
  $this->assertTrue( ! $redirected );
397
  }
398
 
399
+ /**
400
+ * Test that replace (both wildcard and regex) doesn't change the casing on the matched part
401
+ *
402
+ * @since 1.7.5
403
+ */
404
+ public function testReplaceCasing() {
405
+ global $safe_redirect_manager;
406
+
407
+ // with wildcard
408
+ $_SERVER['REQUEST_URI'] = '/myfiles1/FooBar.JPEG';
409
+ $redirected = false;
410
+ $redirect_to = '/images1/*';
411
+ $safe_redirect_manager->create_redirect( '/myfiles1/*', $redirect_to );
412
+
413
+ add_action( 'srm_do_redirect', function( $requested_path, $redirected_to, $status_code ) use ( &$redirect_to, &$redirected ) {
414
+ if ( $redirected_to === '/images1/FooBar.JPEG' ) {
415
+ $redirected = true;
416
+ }
417
+ }, 10, 3 );
418
+
419
+ $safe_redirect_manager->action_parse_request();
420
+
421
+ $this->assertTrue( $redirected );
422
+
423
+ // with regex
424
+ $_SERVER['REQUEST_URI'] = '/myfiles2/FooBar.JPEG';
425
+ $redirected = false;
426
+ $redirect_to = '/images2/$1';
427
+ $safe_redirect_manager->create_redirect( '/myfiles2/(.*\.jpe?g)', $redirect_to, 301, true );
428
+
429
+ add_action( 'srm_do_redirect', function( $requested_path, $redirected_to, $status_code ) use ( &$redirect_to, &$redirected ) {
430
+ if ( $redirected_to === '/images2/FooBar.JPEG' ) {
431
+ $redirected = true;
432
+ }
433
+ }, 10, 3 );
434
+
435
+ $safe_redirect_manager->action_parse_request();
436
+
437
+ $this->assertTrue( $redirected );
438
+ }
439
+
440
  /**
441
+ * Tests import redirects from file.
442
+ *
443
+ * @since 1.7.6
444
  *
445
+ * @access public
446
+ * @global SRM_Safe_Redirect_Manager $safe_redirect_manager The plugin instance.
447
  */
448
+ public function testFileImport() {
449
  global $safe_redirect_manager;
450
 
451
+ // create temp file and fill up it with redirects
452
+ $tmp_file = tmpfile();
453
+
454
+ $redirects = array(
455
+ // headers
456
+ array( 'http code', 'legacy url', 'new url', 'is_regex' ),
457
+ // redirects
458
+ array( 302, '/some-url', '/new-url', 0 ),
459
+ array( 301, '/broken-url', '/fixed-url', 0 ),
460
+ array( 301, '/reg?ex/\d+/path', '/go/here', 1 ),
461
+ );
462
+
463
+ foreach ( $redirects as $row ) {
464
+ fputcsv( $tmp_file, $row );
465
+ }
466
+
467
+ // let's import it
468
+ fseek( $tmp_file, 0 );
469
+ $processed = $safe_redirect_manager->import_file( $tmp_file, array(
470
+ 'source' => 'legacy url',
471
+ 'target' => 'new url',
472
+ 'regex' => 'is_regex',
473
+ 'code' => 'http code',
474
+ ) );
475
+
476
+ // assert results
477
+ $this->assertTrue( is_array( $processed ) && ! empty( $processed['created'] ) );
478
+ $this->assertEquals( count( $redirects ) - 1, $processed['created'] );
479
+
480
+ // close temp file
481
+ fclose( $tmp_file );
482
  }
483
+
484
  }