I am migrating a site which will require about 5000 redirects, in a format such as
http://www.acme.org/content/item.aspx?id=123
redirects to
http://www.acme.org/resources/articles/why-acme-is-great
Normally I would accomplish this through .htaccess or an nginx module. However I'm on a WordPress specific host, Pantheon, which does not allow access to that.
Therefore the only solution I could think of is to use PHP. The following is working. There's some WordPress specific code in there to prevent WordPress from just throwing a 404.
add_filter('template_redirect', 'my_404_override');
function my_404_override()
{
global $wp_query;
if (strpos($_SERVER['REQUEST_URI'], 'issues') !== false) {
$redirectURL = "/resources";
if (strpos($_SERVER['REQUEST_URI'], '123') !== false) {
$redirectURL .= "/articles/why-acme-is-great/";
}
}
if (!empty($redirectURL)) {
status_header(200);
$wp_query->is_404 = false;
header('HTTP/1.0 301 Moved Permanently');
header('Location: http://www.acme.org' . $redirectURL);
}
}
This works fine. However I have two concerns:
/resources
before looking at specific IDs. Your problem is that you will need to make a map of old content to new. Adding a custom field to each post content to the effect of "old_url=123", then doing a wp_query for the post-slug. I would assume your old ID's (ie 123) wouldn't necessarily match up with new ones. The approach of adding conditionals for every possible URL is unfeasible and difficult to maintain.
When you add a field for each new post / page that has "old content" then your code can be something like this:
add_filter('template_redirect', 'my_404_override');
function my_404_override()
{
global $wp_query;
$old_url = $_SERVER['REQUEST_URI'];
$results = $wpdb->get_results(
$wpdb->prepare( "SELECT wp_posts.guid, redirect_url FROM wp_posts LEFT JOIN wp_post_meta ON wp_posts.ID = wp_post_meta.post_id WHERE wp_post_meta.old_url = %s LIMIT 1", $old_url ));
$redirectURL = $results[0]['guid'];
}
if (!empty($redirectURL)) {
status_header(200);
$wp_query->is_404 = false;
header('HTTP/1.0 301 Moved Permanently');
header('Location: ' . $redirectURL);
}
}
This is pseudo code; but the general idea is that you query one row no matter what; and the impact on performance is negligible, as only in the case of 404, you check to find if a redirect exists and that query returns only one row.
There are problems to this approach, namely if someone enters for example the same number on two posts, there is no method for prioritizing which is the most important redirect. You might also consider to use a plugin to solve this problem.