Redirect and send "301 Moved Permanently" when permalink structure or slug has been changed WordPress plugin

WordPress logoBelieve it or not but changing WordPress permalink structure can actually temporarily remove your site from Google index. Also changing single page slug can do the same for that page. By default WordPress doesn't forgive these kind of changes and following old permalinks would usually result in "404 Not Found". In this article I'm bringing you WordPress plugin that enables you to redirect old permalinks to new ones after changing permalink structure or slug. This WordPress plugin will also send "301 Moved Permanently" headers to search engines and that would instruct Google and others to change their search index.

This plugin is based on excellent Change Permalink Helper WordPress plugin idea. I've changed this plugin to use WordPress build in functions where possible and I've added slug mapping to support slug changes. So here's the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
<?php
/**
Plugin Name: Change Permalink or Slug Helper
Plugin URI: http://www.techytalk.info/
Description: Redirect and send "301 Moved Permanently" when permalink structure or slug has been changed WordPress plugin
Version: 1.0
Author: Marko Martinović
Author URI: http://www.techytalk.info/ 
 
Copyright 2012.  Marko Martinović  (email : marko AT techytalk.info)
 
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
 
if ( !function_exists('add_action') ) {
	header('Status: 403 Forbidden');
	header('HTTP/1.1 403 Forbidden');
	exit;
}
 
if ( !class_exists('ChangePermalinkHelper') ) {
    class ChangePermalinkHelper {
        private $slugRedirect = array('old-slug' => 'new-slug');
 
        function ChangePermalinkHelper() {
 
            add_action( 'plugins_loaded', array( &$this, 'onLoad' ) );
        }
 
 
        function onLoad() {
            if ( is_admin() )
                    return;
 
            add_action( 'template_redirect', array( &$this, 'is404Permalink' ) );
            add_action( 'template_redirect', array( &$this, 'is404Slug' ) );
        }
 
        function is404Permalink() {
            global $wpdb;
 
            if ( !is_404() )
                    return;
 
            $slug = htmlspecialchars( basename( $_SERVER['REQUEST_URI'] ) );
            $id = $wpdb->get_var( 
                            $wpdb->prepare( "
                                    SELECT ID 
                                    FROM $wpdb->posts
                                    WHERE post_name = '%s'
                                    AND post_status = 'publish'
                            ", $slug )
                    );
 
            if ($id) {
                    wp_redirect(get_permalink($id), 301);
                    exit;
            } else {
                    return true;
            }
 
        }
 
        function is404Slug() {
            global $wpdb;
 
            if (!is_404())
                    return;
 
            $slug = htmlspecialchars(basename($_SERVER['REQUEST_URI']));                    
 
            if(!array_key_exists($slug, $this->slugRedirect))
                return;
 
            $id = $wpdb->get_var( 
                            $wpdb->prepare( "
                                    SELECT ID 
                                    FROM $wpdb->posts
                                    WHERE post_name = '%s'
                                    AND post_status = 'publish'
                            ", $this->slugRedirect[$slug] )
                    );
 
            if ($id) {
                wp_redirect(get_permalink($id), 301);
                exit;
            } else {
                return true;
            }
 
        }                
 
    }
 
    $ChangePermalinkHelper = new ChangePermalinkHelper();
}
?>

This plugin activates right before 404 page is displayed. It first checks database for valid page with given slug (to detect permalink structure changes) and if that is not successful then it checks slugRedirect array for given slug (to detect page slug changes). If any of those two checks is successful this plugin redirects to correct permalink and sends "301 Moved Permanently". Permalink structure changes doesn't require anything besides installing and activating this plugin. Slug changes require you to add old slug - new slug pairs to slugRedirect array before you change your page slug inside your WordPress admin interface. For example if my WordPress site had valid URL http://www.techytalk.info/second-old-slug and I want to change it to http://www.techytalk.info/second-new-slug, before doing that I'll modify my slugRedirect array like this:

private $slugRedirect = array('old-slug' => 'new-slug', 'second-old-slug' => 'second-new-slug');

After doing that I can safely change my page slug without worrying about search engines hitting "404 Not Found" for http://www.techytalk.info/second-old-slug. In the future I might add some GUI to make it possible to add slug mapping pairs without editing code. That's it, hope you find it useful.

DevGenii

A quality focused Magento specialized web development agency. Get in touch!

11 thoughts on “Redirect and send "301 Moved Permanently" when permalink structure or slug has been changed WordPress plugin

  1. Alex

    Great idea, great plugin. But doesn’t work for me 🙂

    I changed permalinks from /%postname%/ to /%postname%/%post_id%/

    Both pages give good old 200 OK

    zeleneet.com/gibkie-solnechnye-batarei/
    zeleneet.com/gibkie-solnechnye-batarei/1577/

    Is it feature of the server or something else?

    Reply
    1. Marko Author

      Hi Alex,
      both URLs work because WordPress has built in redirection that works when when middle part of URL hasn’t changed like in your case. This plugin takes care of the other cases when you change for example:

      /%year%/%monthnum%/%postname%/

      into:

      /%postname%/

      and this is something WordPress built in redirection could not handle. The only weired thing is that WordPress sends 200 OK instead of 301.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *