How to Easily Setup 301 Redirects for WordPress Sites / Permalink Changes

WordPress does a pretty good job at trying to prevent 404s, but it’s powers are, alas, limited. Here I’ll show you how to use built in WP functionality to quickly setup a list of 301 redirects.

What we’re going to do is:

  1. Setup a WP_Query to loop through all of our posts.
  2. Configure that loop to output 301 Redirect commands.
  3. Paste it all into an .htaccess file.

So, if you’re using NGINX instead of Apache, or any other scenario, this may not work for you. Most people are still on an Apache server, though. You’ll also need to be comfortable with FTP and at least copy/pasting PHP code.

Setup our Loop

Go into your WordPress install and create a new Page. Give it any title you want, but don’t give it any content. Publish it or “Save Draft” > “Preview” it. We can delete this page down the road, we’re just using it to more easily setup our redirects. Once you’ve saved or published it, look in your browser’s address bar. You should see something like this:

http://yourwebsite.com/wp-admin/post.php?post=6783&action=edit&message=10

That highlighted number there is something you’ll need to remember, this is the Page’s ID.

Next up, open up your theme’s page.php file. I recommend you do this via FTP but if you go to Appearance > Editor in WordPress you can typically edit it there as well. In that file, look for a call to the_content();

Just below that, and outside of any other PHP tags, paste the following:

<?php if (is_page(6783)) { // setting up redirects
$args = array(
'post_type' => 'post',
'posts_per_page' => -1
);
$the_query = new WP_Query($args);
while ($the_query->have_posts()) : $the_query->the_post(); ?>
<p>Redirect 301 /<?php the_date('Y/m/d'); ?>/<?php echo $post->post_name;?> <?php the_permalink(); ?></p>
<?php endwhile;
} ?>

Save the file.

Note that what I’m specifically doing in this case is setting up redirects for the old /YEAR/MONTH/DAY/POST-SLUG permalink structure that was popular in WordPress years back with the new, simpler, /POST-SLUG structure.

Go back and view that Page we created in WordPress. The content should now look something like this:

Redirect 301 /2004/04/20/some-post-slug http://yourwebsite.com/some-post-slug
Redirect 301 /2004/04/21/another-post-slug http://yourwebsite.com/another-post-slug
Redirect 301 /2005/04/20/its-been-awhile http://yourwebsite.com/its-been-awhile
Redirect 301 /2005/09/15/my-summer-vacation http://yourwebsite.com/my-summer-vacation
Redirect 301 /2005/10/10/my-thoughts-on-politics-and-religion http://yourwebsite.com/my-thoughts-on-politics-and-religion

Digging Deeper: What are we actually doing here?

You can skip this section if the above worked fine for you and you don’t care what we’re doing, but if you have other needs, you might want to read along.

In our WP_Query up there, we’re essentially saying, “Hey WordPress, get me all of the posts ('posts_per_page' => -1 where -1 is WP’s way of saying “all of them”)” in the $args section, then the 6th & 7th lines setup our Loop. The Loop, in WordPress, is just a list of posts. You can modify what posts get outputted, even change it to Pages or custom post types, eliminate posts from certain categories or tags, and lots more, read up on WP_Query for more info.

The <?php endwhile; closes the Loop. Everything in between is what gets displayed for each valid post that is pulled out of our database. In this case, it’s this:

<p>Redirect 301 /<?php the_date('Y/m/d'); ?>/<?php echo $post->post_name;?> <?php the_permalink(); ?></p>

We’re putting everything in <p> tags so that each post is displayed on its own line.

“Redirect 301” is an .htaccess command, which says “If someone visits the first page we’re about to mention, send them to the second page instead.”

/<?php the_date('Y/m/d'); ?>/<?php echo $post->post_name;?>

There we’re just outputting the /YEAR/MONTH/DAY/POST-SLUG of our old permalink structure. If yours was something different, modify that code as appropriate. For example, if you were previously using the /YEAR/MONTH/POST-SLUG structure, you’d just drop the last /d from the the_date() function call.

Then with echo $post->post_name; we are outputting this post’s current URL. There’s no reason to change that.

Setup .htaccess

Okay, we’re almost finished. Final step is to copy all of those 301 Redirects from your new WordPress Page to your .htaccess file. You’ll need FTP access for this, and the .htaccess file is usually in the root directory (that is, the main directory where you’ll also find the wp-content, wp-includes, wp-admin folders and wp-config.php file). Open it up, and below everything else just paste all of those 301 Redirects.

Save and check your site out. If you’ve done everything correctly, your site will still load and you should be good to go with the redirects. If you end up with a 500 error, that means there’s something wrong with the syntax of those redirects. You can paste it all into this handy website to find out where the errors are.

There you go! This was particularly useful for me when I needed to setup redirects where thisonewebsite.com was forwarding to theirnewwebsite.com, but thisonewebsite.com used the older YEAR/MONTH/DAY permalink structure and the new one used the simpler format. Hopefully it proves useful to you as well!

Up Next: How to Allow Subscribers to Delete Posts from the Front End while Still Blocking the Admin Area