WordPress: Automatic 301 redirects for 404 SPAM pages

If your WordPress website has ever been hacked, you know there is a lot of cleaning up to do. Many hackers use the hacked website to inject spammy urls containing pharmaceutical or other content on your website.

Once you have cleaned up, you are left with a lot of 404 errors on your website. If you are not sure what that means you can read an explanation here – What is a 404 error.

Spam urls you hate to see on your website.

One thing is cleaning up the hack, removing all the bad code and securing your website for future attacks. But what about the spammy urls?

I use the Redirection plugin by John Godley at urbangiraffe.com when I need to handle redirects. I have used it for years, its easy to use, stable and flexible.

The problem is when you have been hacked and have thousands of bad urls you want to redirect, it is a hassle to do manually.

So, I decided to create a solution that automatically creates a 301 redirect for 404 pages.

There are several ways this can be implemented, I created a 404.php page in my theme folder to contain this code.

This means the first time a visitor (or robot) visits the url, the 404 page is presented, as well as a 404 http status. On any future visits to that url, a 301 redirect is sent to the url of your choice.

First visit to domain.com/buy-pills-of-some-kind.html :

A 404 page is presented, and the code below creates a redirect that is then handled by the Redirection plugin in the future.

[box type=”warning”] Disclaimer: I take NO responsibility for your implementation on your website.

Only use this code if you understand what is going on. Be careful![/box]

Enough with the disclaimer, here is the code. If you do not have a 404.php file in your WordPress theme, create it.

&lt;?php
$redirectto='https://cleverplugins.com/'; // This is where the redirect will go, change as you see fit.
global $wpdb;
$newpos='';
$badurl='';
$redirtable=$wpdb-&gt;prefix.&quot;redirection_items&quot;; // The table containing the redirects...
$oldpos=$wpdb-&gt;get_var(&quot;SELECT `position` FROM `$redirtable` ORDER BY `position` DESC limit 1;&quot;); // for finding the HIGHEST number...
if (!$oldpos) $oldpos='0'; // set to 0 if its the first redirect ever done!
$newpos =$oldpos+1; // Found the old one, let's add 1.
$badurl= $_SERVER[&quot;REQUEST_URI&quot;]; // This is the bad url, the current one.
if (($newpos) AND ($badurl)) { // Only run if we have the bad url and the next redirect number
$blogtime = strtotime(current_time('mysql')); // Get the time
$mysqldate = date( 'Y-m-d H:i:s', $blogtime ); // Proper formatting of the time
$result=$wpdb-&gt;query(&quot;INSERT INTO `$redirtable` (`id`,
`url`,
`regex`,
`position`,
`last_count`,
`last_access`,
`group_id`, `status`, `action_type`, `action_code`, `action_data`, `match_type`, `title`)
VALUES
(NULL, '$badurl', '0', '$newpos', '0', '$mysqldate', '1', 'enabled', 'url', '301', '$redirectto', 'url', NULL);&quot;);
}
?&gt;

[box type=”info”] Remember to change the url in the first line ($redirectto) to your website. Otherwise you will redirect your visitors to cleverwp.com :-)[/box]

Important technical detail: The Redirection plugin runs and handles redirects before the 404.php template is called.

Spammy urls automatically redirected

Under normal circumstances I would have had to create redirects manually for the spammy urls above. By using this code the redirects was created automatically.

A few technical notes

Notice the last_count column? The ones that has “0”, means the redirect has been created, but no subsequent visits made to that url.

The ones with “1” means the page has been accessed twice. The first time just creates the redirect and presents a normal 404 page. The second time the redirect kicks in, and the “last_count” is updated. All of this is handled by the Redirection plugin… Thank you John for the great plugin 🙂

Cleaning up old redirects

As you can imagine, there can quickly be a lot of redirects filling up in your database. The Redirection plugin monitors not only the number of redirects, but also when the redirect was last accessed.

This means we can create a small piece of code that checks and deletes all redirects more than x days old.

I think 21 days (3 weeks) is a fair limit. The code below checks if there are any redirects that have not been accessed/used in more than 21 days, and then just remove them.

&lt;?php
$oldredirsagelimit=21; // How many days before we delete from the redirection table.
$oldredirscount=$wpdb-&gt;get_var(&quot;SELECT count(*) FROM `$redirtable` WHERE DATE_SUB(CURDATE(),INTERVAL $oldredirsagelimit DAY)&gt;last_access; &quot;);
if ($oldredirscount&gt;0) { // old redirections, not accessed in x days
$wpdb-&gt;query(&quot;DELETE FROM `$redirtable` WHERE DATE_SUB(CURDATE(),INTERVAL $oldredirsagelimit DAY)&gt;last_access&quot;);
//echo &quot;Deleted $oldredirscount redirects that has not been used for over $oldredirsagelimit days.&quot;;
}
?&gt;

I have put the code that cleans the database table in the 404.php template file as well. Both pieces of code run very quickly and puts very little pressure on the server.

[box type=”warning”] Let me repeat: Be very careful when you implement this. If you mess up you can set up redirect loops that prevent you and your visitors from accessing your website completely. [/box]

[box type=”info”] If you should be so unlucky to create a redirect loop, you fix the problem by using PHPMyadmin or similar tool to access your database. Look for the table normally called “wp_redirection_items” (the wp_ part might differ).

The redirects are in there. You can locate the faulty redirect(s) here and remove them, restoring your website. [/box]