-
-
Save mkdizajn/7084ad7dd4989341cfd8109ce4be0c4b to your computer and use it in GitHub Desktop.
WordPress plugin to redirect old URLs when a site is refreshed. Uses a JSON file on activate to import into the DB. If Activation fails because of an error in the JSON file just deactivate, edit the file and then reactivate.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Plugin Name: Redirect Old URLs | |
* Description: Supports redirecting from an old site's URL to a new site on same domain. | |
* Version: 0.1.0 | |
* Author: The WPLib Team | |
* Author URI: http://github.com/wplib | |
* Author Email: [email protected] | |
* License: GPL2 | |
* License URI: https://www.gnu.org/licenses/gpl-2.0.html | |
* | |
* Looks for a redirects.json file in the WP_CONTENT_DIR directory (typically /wp-content) on plugin activation | |
* that contains an array of two dimensional arrays where: | |
* | |
* [0] The old URL path from the root but w/o a leading slash. | |
* [1] The new URL path to 301 redirect to. | |
* | |
* It then loads this into the wp_terms table where the name is prefixed with 'redirect:'. | |
* | |
* This will support URLs up to 200 characters in length. | |
* | |
* @example: | |
* | |
* [ | |
* [ 'old-foo/', 'new-foo/' ], | |
* [ 'old-bar/', 'new-bar/' ], | |
* ... | |
* ] | |
* | |
* @note Yes, this uses the wp_terms in a non-standard way. But it is better than creating a | |
* custom table as it should not affect anything because it will be an orphan term from | |
* the perspective of WordPress as it will have no associated taxonomy and thus these | |
* terms will be ignored. | |
* | |
* Just DO NOT RUN any plugin that DELETES ORPHAN TERMS! | |
* | |
*/ | |
class Redirect_Old_Urls { | |
const REDIRECTS_FILE = '/redirects.json'; | |
/** | |
* | |
*/ | |
static function on_load() { | |
add_action( 'template_redirect', array( __CLASS__, '_template_redirect') ); | |
add_action( 'pre_current_active_plugins', array( __CLASS__, '_pre_current_active_plugins') ); | |
register_activation_hook( __FILE__, array( __CLASS__, '_activate') ); | |
} | |
/** | |
* | |
*/ | |
static function _template_redirect() { | |
if ( is_404() || is_feed() ) { | |
/** | |
* Only attempt to redirect if on a 404 | |
* | |
* First, get the incoming URL path, stripping it of leading and trailing slashes, | |
* | |
* @example http://example.com/foo/bar/baz/ --> 'foo/bar/baz' | |
*/ | |
$url_path = trim( $_SERVER['REQUEST_URI'], '/\\' ); | |
if ( $new_path = self::lookup_url_redirect( $url_path ) ) { | |
/** | |
* If we found a URL to redirect, do so. | |
*/ | |
wp_safe_redirect( "/{$new_path}", 301 ); | |
die; | |
} | |
/** | |
* If no redirect found then continue on and let WordPress display a 404 page. | |
*/ | |
} | |
} | |
/** | |
* Retrieves a new url path given an old url path from the wp_terms table. | |
* | |
* @param string|array $old_path | |
* | |
* @return string | |
*/ | |
static function lookup_url_redirect( $old_path ) { | |
/** | |
* @var wpdb $wpdb | |
*/ | |
global $wpdb; | |
$sql = $wpdb->prepare( | |
"SELECT slug FROM {$wpdb->terms} WHERE name = '%s' LIMIT 1", | |
"redirect:{$old_path}" | |
); | |
return $wpdb->get_var( $sql ); | |
} | |
/** | |
* | |
*/ | |
static function _activate() { | |
do { | |
$errors = array(); | |
if ( ! is_file( $redirects_filepath = self::redirects_filepath() ) ) { | |
$err_msg = "Import Terminated; no redirect file found: %s."; | |
$errors[] = sprintf( $err_msg, $redirects_filepath ); | |
break; | |
} | |
if ( ! ( $redirects_json = json_decode( file_get_contents( $redirects_filepath ) ) ) ) { | |
$err_msg = "Import Terminated; redirects file appears to be invalid JSON: %s."; | |
$errors[] = sprintf( $err_msg, $redirects_filepath ); | |
break; | |
} | |
if ( ! is_array( $redirects_json ) ) { | |
$err_msg = "Import Terminated; redirects file does not return an array of redirects: %s."; | |
$errors[] = sprintf( $err_msg, $redirects_filepath ); | |
break; | |
} | |
global $wpdb; | |
/** | |
* Delete all the old URL redirects, if there are any... | |
*/ | |
$sql = "DELETE FROM {$wpdb->terms} WHERE name LIKE 'redirect:%'"; | |
$wpdb->query( $sql ); | |
foreach( $redirects_json as $index => $redirect_pair ) { | |
if ( ! isset( $redirect_pair[0] ) || ! isset( $redirect_pair[1] ) ) { | |
$err_msg = "Redirect #%d Failed; not a valid two element array in %s."; | |
$errors[] = sprintf( $err_msg, $index, $redirects_filepath ); | |
continue; | |
} | |
if ( 191 < strlen( $redirect_pair[0] ) ) { | |
$err_msg = "Redirect #%d Failed; URL path '%s' is too long in %s (max 191 chars allowed.)"; | |
$errors[] = sprintf( $err_msg, $index, $redirect_pair[0], $redirects_filepath ); | |
continue; | |
} | |
if ( 200 < strlen( $redirect_pair[1] ) ) { | |
$err_msg = "Redirect #%d Failed; URL path '%s' is too long in %s (max 200 chars allowed.)"; | |
$errors[] = sprintf( $err_msg, $index, $redirect_pair[1], $redirects_filepath ); | |
continue; | |
} | |
$redirects_json[ $index ] = $wpdb->prepare( "('%s','%s')", "redirect:{$redirect_pair[0]}", $redirect_pair[1] ); | |
} | |
if ( count( $errors ) ) { | |
break; | |
} | |
$sql = "INSERT INTO {$wpdb->terms} (name,slug) VALUES \n\t" . implode( ",\n\t", $redirects_json ); | |
$wpdb->query( $sql ); | |
} while ( false ); | |
if ( count( $errors ) ) { | |
$errors = implode( '</li><li>', $errors ); | |
$err_msg = sprintf( '<p>Errors while attempting to activate plugin:</p><ul><li>%s</li></ul>', $errors ); | |
set_transient( 'rou_activate_errors', $err_msg, 30 ); | |
} | |
} | |
/** | |
* | |
*/ | |
static function _pre_current_active_plugins() { | |
do { | |
$err_msg = get_transient( 'rou_activate_errors' ); | |
/** | |
* If no errors, exit | |
*/ | |
if ( ! $err_msg ) { | |
break; | |
} | |
/** | |
* Output the error messages | |
*/ | |
echo '<div id="rou-message" class="error below-h2">'; | |
echo wp_kses_post( $err_msg ); | |
echo '</div>'; | |
/** | |
* Clear the error message | |
*/ | |
delete_transient( 'rou_activate_errors' ); | |
/** | |
* Unhook notices to avoid dups | |
*/ | |
remove_action( 'pre_current_active_plugins', array( __CLASS__, __FUNCTION__ ) ); | |
} while ( false ); | |
} | |
/** | |
* | |
*/ | |
static function redirects_filepath() { | |
return WP_CONTENT_DIR . self::REDIRECTS_FILE; | |
} | |
} | |
Redirect_Old_Urls::on_load(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[ | |
[ "page/13", "about-us/"], | |
[ "page/42", "public art page (tbd)/"], | |
[ "etc", "new-etc/"], | |
[ | |
"Store this file as /wp-content/redirects.json, or wherever you changed content to.", | |
"File is only needed during activation." | |
] | |
] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment