WP 404 Auto Redirect to Similar Post - Version 0.7

Version Description

  • Reworked code
  • Added settings page
  • Added Debug mode for administrators (settings page)
  • Added the ability to disable "Redirect to Homepage" if nothing found (settings page)
  • Added the ability to choose between 301 or 302 HTTP Headers (settings page)
  • Added the ability preview URL Redirections (settings page)
Download this release

Release Info

Developer hwk-fr
Plugin Icon 128x128 WP 404 Auto Redirect to Similar Post
Version 0.7
Comparing to
See all releases

Code changes from version 0.4.0.2 to 0.7

logo.png ADDED
Binary file
readme.txt CHANGED
@@ -3,26 +3,28 @@ Contributors: hwk-fr
3
  Donate link: http://hwk.fr/
4
  Tags: 404, Redirect, 301, Similar Post, SEO, Broken Link, Webmaster Tools
5
  Requires at least: 4.0
6
- Tested up to: 4.7.4
7
- Stable tag: 0.4.0.2
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
11
- Automatically Redirect any 404 to a Similar Post based on the Title, Post Type, Category & Taxonomy using 301 Redirects!
12
 
13
  == Description ==
14
 
15
  Welcome to WP 404 Auto Redirect to Similar Post!
16
 
17
- This plugin will automatically redirect all your 404 to a similar post, based on the Title, Post Type, Category & Taxonomy. If nothing similar is found, the plugin will redirect to your homepage. All redirects are done via 301 HTTP Status Code.
18
 
19
  = Features: =
20
 
21
- * Easy to Install / Uninstall. No data saved in DB
22
  * Automatically detect any 404
23
- * Automatically search a similar post based on Title, Post Type, Category & Taxonomy
24
- * Redirect to homepage if nothing found
25
- * All redirects are using 301 status code
 
 
26
 
27
  = Requirements: =
28
 
@@ -34,18 +36,24 @@ This plugin will automatically redirect all your 404 to a similar post, based on
34
 
35
  1. Upload the plugin files to the `/wp-content/plugins/wp-404-auto-redirect-similar-post` directory, or install the plugin through the WordPress plugins screen directly.
36
  2. Activate the plugin through the 'Plugins' screen in WordPress.
37
- 3. Everything is ready! Modify an url in your browser to try to trigger a 404.
 
38
 
39
- == Frequently Asked Questions ==
40
 
41
- = What are the redirect priorities? =
42
-
43
- 1. Post Title + Post Type
44
- 2. Category / Taxonomy
45
- 4. Homepage
46
 
47
  == Changelog ==
48
 
 
 
 
 
 
 
 
 
49
  = 0.4.0.2 =
50
  * Fixed sanitization bug
51
  * Fixed debug typo
3
  Donate link: http://hwk.fr/
4
  Tags: 404, Redirect, 301, Similar Post, SEO, Broken Link, Webmaster Tools
5
  Requires at least: 4.0
6
+ Tested up to: 4.8.2
7
+ Stable tag: 0.7
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
11
+ Automatically Redirect any 404 to a Similar Post based on the Requested URL Title & Post Type using 301 or 302 Redirects!
12
 
13
  == Description ==
14
 
15
  Welcome to WP 404 Auto Redirect to Similar Post!
16
 
17
+ This plugin will automatically redirect all your 404 to a similar post based on Title & Post Types. If nothing similar is found, the plugin will redirect the 404 to the homepage.
18
 
19
  = Features: =
20
 
21
+ * Easy to Install / Uninstall.
22
  * Automatically detect any 404
23
+ * Automatically search a similar post based on the Title, Post Type, Category & Taxonomy
24
+ * **NEW** Redirect to Homepage if no similar post is found (can be disabled)
25
+ * **NEW** Choose the redirection HTTP header code: 301 or 302
26
+ * **NEW** Debug console for administrators
27
+ * **NEW** Preview URL directly from the admin panel
28
 
29
  = Requirements: =
30
 
36
 
37
  1. Upload the plugin files to the `/wp-content/plugins/wp-404-auto-redirect-similar-post` directory, or install the plugin through the WordPress plugins screen directly.
38
  2. Activate the plugin through the 'Plugins' screen in WordPress.
39
+ 3. Go to Settings > WP 404 Auto Redirect to change your settings.
40
+ 4. Everything is ready! Modify an url in your browser to try to trigger a 404.
41
 
42
+ == Screenshots ==
43
 
44
+ 1. WP 404 Auto Redirect to Similar Post: Settings Page
45
+ 2. WP 404 Auto Redirect to Similar Post: Front Debug Console (for administrators)
 
 
 
46
 
47
  == Changelog ==
48
 
49
+ = 0.7 =
50
+ * Reworked code
51
+ * Added settings page
52
+ * Added Debug mode for administrators (settings page)
53
+ * Added the ability to disable "Redirect to Homepage" if nothing found (settings page)
54
+ * Added the ability to choose between 301 or 302 HTTP Headers (settings page)
55
+ * Added the ability preview URL Redirections (settings page)
56
+
57
  = 0.4.0.2 =
58
  * Fixed sanitization bug
59
  * Fixed debug typo
wp-404-auto-redirect-similar-post.js ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function($){
2
+ var ajaxurl = '/wp-admin/admin-ajax.php';
3
+
4
+ if($('#wp404arsp_settings_test').length > 0){
5
+ $('#wp404arsp_settings_test .button').click(function(){
6
+ $request = $('#wp404arsp_settings_test input[type=text]').val();
7
+ if($request.length == 0)
8
+ return;
9
+
10
+ if($request.substring(0,1) != '/'){
11
+ $request = '/' + $request;
12
+ $('#wp404arsp_settings_test input[type=text]').val($request)
13
+ }
14
+
15
+ data = {
16
+ action: 'wp404arsp_ajax_test',
17
+ request: $request,
18
+ };
19
+ $.post(ajaxurl, data)
20
+ .done(
21
+ function(response){
22
+ $('#wp404arsp_settings_test .results').html(response);
23
+ }
24
+ );
25
+ });
26
+ }
27
+
28
+ });
wp-404-auto-redirect-similar-post.php CHANGED
@@ -3,110 +3,301 @@
3
  * Plugin Name: WP 404 Auto Redirect to Similar Post
4
  * Description: Automatically Redirect any 404 to a Similar Post based on the Title, Post Type, Category & Taxonomy using 301 Redirects!
5
  * Author: hwk-fr
6
- * Version: 0.4.0.2
7
  * Author URI: http://hwk.fr
8
  */
9
 
10
  if(!defined('ABSPATH'))
11
  die('You are not allowed to call this page directly.');
12
 
13
- function wp404arsp_settings(){
14
- $return['debug'] = false;
15
- return $return;
 
 
 
 
 
16
  }
17
 
18
- add_action('template_redirect', 'wp404arsp');
19
- function wp404arsp(){
20
-
21
- if(!is_404() || (defined('DOING_AJAX') && DOING_AJAX))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  return;
23
 
24
- $query = wp404arsp_query_setup($_SERVER['REQUEST_URI']);
25
- wp404arsp_search($query);
26
 
27
  }
28
 
29
- function wp404arsp_query_setup($request){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
  $path = pathinfo(urldecode(htmlspecialchars(strtok($request, '?'))));
32
- $path['filename'] = sanitize_title(pathinfo(basename($request), PATHINFO_FILENAME));
33
- $path['dirname'] = ltrim($path['dirname'], '/');
34
- $path['dirname'] = ltrim($path['dirname'], '\\');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
- if(!empty($path['dirname'])){
 
 
 
 
 
 
 
 
37
 
38
- if(strpos($path['dirname'], '/') !== false){
39
- $path['directories'] = explode('/', $path['dirname']);
40
- foreach($path['directories'] as $k => $v){
41
- $path['directories'][$k] = sanitize_title($v);
42
- }
43
- }else{
44
- $path['directories'][] = sanitize_title($path['dirname']);
45
- }
46
 
 
 
47
  }
48
 
49
- $path['directories'][] = $path['filename'];
50
 
51
- $keywords['split'] = $path['directories'];
52
- $keywords['split'] = wp404arsp_remove_stop_words($keywords['split']);
 
 
 
53
 
54
- $keywords['full'] = implode('/', $keywords['split']);
55
 
56
- $return = array();
57
- $return['keywords']['split'] = $keywords['split'];
58
- $return['keywords']['full'] = $keywords['full'];
 
 
 
 
 
 
 
 
 
 
 
 
59
 
60
- if(!empty($return['keywords']['split'])){
61
- $i=0; foreach($return['keywords']['split'] as $keyword){
62
-
63
- // Test: Post
64
- $get_posts_types = get_post_types(array('public' => true), 'names');
65
- foreach($get_posts_types as $post_type){
66
- if($post = get_page_by_path($keyword, 'object', $post_type)){
67
- $return['known'][$i]['slug'] = $keyword;
68
- $return['known'][$i]['type'] = 'post';
69
- $return['known'][$i]['data']['post_type'] = $post->post_type;
70
- $return['known'][$i]['data']['ID'] = $post->ID;
71
- break;
72
- }
73
- }
74
-
75
- if(empty($return['known'][$i]['type'])){
76
-
77
- // Test: Post Type
78
- $get_posts_types = get_post_types(array('public' => true), 'names');
79
- foreach($get_posts_types as $post_type){
80
- $post_type = get_post_type_object($post_type);
81
- if($post_type->rewrite['slug'] == $keyword || $post_type->has_archive == $keyword){
82
- $return['known'][$i]['slug'] = $keyword;
83
- $return['known'][$i]['type'] = 'post_type';
84
- $return['known'][$i]['data']['post_type'] = $post_type->name;
85
- break;
86
- }
87
- }
88
-
89
- }
90
-
91
- if(empty($return['known'][$i]['type'])){
92
-
93
- // Test: Taxonomy
94
- $get_taxonomies = get_taxonomies(array('public' => true), 'names');
95
- foreach($get_taxonomies as $taxonomy){
96
- if($tax = get_term_by('slug', $keyword, $taxonomy)){
97
- $return['known'][$i]['slug'] = $keyword;
98
- $return['known'][$i]['type'] = 'term';
99
- $return['known'][$i]['data']['taxonomy'] = $taxonomy;
100
- break;
101
- }
102
- }
103
-
104
- }
105
 
106
- if(empty($return['known'][$i]['slug']))
107
- $return['unknown'][]['slug'] = $keyword;
108
 
109
- $i++;
110
  }
111
 
112
  }
@@ -115,189 +306,119 @@ function wp404arsp_query_setup($request){
115
 
116
  }
117
 
118
- function wp404arsp_search($query){
119
 
120
- global $wpdb;
 
 
121
 
122
- if(empty($query))
123
- return false;
124
 
125
- $known = (!empty($query['known'])) ? array_reverse($query['known']) : '';
126
- $unknown = (!empty($query['unknown'])) ? array_reverse($query['unknown']) : '';
127
 
128
- $debug['query'] = $query;
 
129
 
130
- if(empty($unknown) && !empty($known)){
131
- foreach($known as $slug){
132
-
133
- $get_permalink = false;
134
-
135
- if($slug['type'] == 'post')
136
- $get_permalink = get_permalink($slug['data']['ID']);
137
-
138
- if($slug['type'] == 'post_type')
139
- $get_permalink = get_post_type_archive_link($slug['data']['post_type']);
140
-
141
- if($slug['type'] == 'term')
142
- $get_permalink = get_term_link($slug['slug'], $slug['data']['taxonomy']);
143
-
144
- wp404arsp_redirect($get_permalink, $debug);
145
- }
146
- }
147
 
148
- if(empty($known) && !empty($unknown)){
149
- foreach($unknown as $word){
150
- $collapse[] = $word['slug'];
151
- }
152
- $explode = explode('-', implode('-', $collapse));
153
-
154
- $get_permalink = false;
155
-
156
- $sql = "SELECT p.ID, ";
157
- foreach($explode as $word){
158
- $sql .= " if(INSTR(LCASE(p.post_name),'" . $word . "'), 1, 0) + ";
159
- }
160
- $sql .= "0 as score FROM " . $wpdb->posts . " AS p
161
- WHERE p.post_status = 'publish' AND p.post_type <> 'attachment' AND p.post_type <> 'nav_menu_item'
162
- ORDER BY score DESC, post_modified DESC LIMIT 1";
163
-
164
- $debug['sql'] = $sql;
165
-
166
- $get_post = $wpdb->get_row($sql);
167
- if(!empty($get_post)){
168
- $debug['result'] = array('score' => $get_post->score, 'id' => (int)$get_post->ID, 'url' => get_permalink($get_post->ID));
169
- if($get_post->score > 0){
170
- $get_permalink = get_permalink((int)$get_post->ID);
171
- }
172
- }
173
-
174
- wp404arsp_redirect($get_permalink, $debug);
175
-
176
- /*
177
- $sql = "SELECT t.term_id, ";
178
-
179
- foreach(wp404arsp_remove_stop_words($search) as $word){
180
- $sql .= " if(INSTR(LCASE(t.slug),'" . $word . "'), 1, 0) + ";
181
- }
182
-
183
- $sql .= "0 as score FROM " . $wpdb->terms . " AS t
184
- INNER JOIN $wpdb->term_taxonomy AS tt ON (t.term_id = tt.term_id)
185
- WHERE tt.taxonomy = '".$query['wp_query']['taxonomy']."'
186
- ORDER BY score DESC LIMIT 1";
187
-
188
- $debug['sql'] = $sql;
189
 
190
- $get_term = $wpdb->get_row($sql);
191
- if(!empty($get_term)){
192
- $debug['results'][] = array('id' => (int)$get_term->term_id, 'url' => get_term_link((int)$get_term->term_id, $query['wp_query']['taxonomy']), 'score' => $get_term->score);
193
- $post = (int)$get_term->term_id;
194
- }
195
- */
196
 
197
- // TODO
198
- // Search Term and compare with Post search
199
 
200
  }
201
 
202
- if(!empty($known) && !empty($unknown)){
203
- foreach($known as $slug){
204
-
205
- foreach($unknown as $word){
206
- $collapse[] = $word['slug'];
207
- }
208
- $explode = explode('-', implode('-', $collapse));
209
-
210
- $get_permalink = false;
211
-
212
- if($slug['type'] == 'post_type'){
213
-
214
- $sql = "SELECT p.ID, ";
215
- foreach($explode as $word){
216
- $sql .= " if(INSTR(LCASE(p.post_name),'" . $word . "'), 1, 0) + ";
217
- }
218
- $sql .= "0 as score FROM " . $wpdb->posts . " AS p
219
- WHERE
220
- p.post_type = '".$slug['data']['post_type']."'
221
- AND p.post_status = 'publish' AND p.post_type <> 'attachment' AND p.post_type <> 'nav_menu_item'
222
- ORDER BY score DESC, post_modified DESC LIMIT 1";
223
-
224
- $debug['sql'] = $sql;
225
-
226
- $get_post = $wpdb->get_row($sql);
227
- if(!empty($get_post)){
228
- $debug['result'] = array('score' => $get_post->score, 'id' => (int)$get_post->ID, 'url' => get_permalink($get_post->ID));
229
- if($get_post->score > 0){
230
- $get_permalink = get_permalink((int)$get_post->ID);
231
- }
232
- }
233
-
234
- wp404arsp_redirect($get_permalink, $debug);
235
-
236
- }
237
-
238
- if($slug['type'] == 'term'){
239
-
240
- $sql = "SELECT p.ID, ";
241
- foreach($explode as $word){
242
- $sql .= " if(INSTR(LCASE(p.post_name),'" . $word . "'), 1, 0) + ";
243
- }
244
- $sql .= "0 as score FROM " . $wpdb->posts . " AS p
245
- INNER JOIN $wpdb->term_relationships AS tr ON (p.ID = tr.object_id)
246
- INNER JOIN $wpdb->term_taxonomy AS tt ON (tr.term_taxonomy_id = tt.term_taxonomy_id)
247
- INNER JOIN $wpdb->terms AS t ON (t.term_id = tt.term_id)
248
- WHERE
249
- tt.taxonomy = '".$slug['data']['taxonomy']."' AND t.slug = '".$slug['slug']."'
250
- AND p.post_status = 'publish' AND p.post_type <> 'attachment' AND p.post_type <> 'nav_menu_item'
251
- ORDER BY score DESC, post_modified DESC LIMIT 1";
252
-
253
- $debug['sql'] = $sql;
254
-
255
- $get_post = $wpdb->get_row($sql);
256
- if(!empty($get_post)){
257
- $debug['result'] = array('score' => $get_post->score, 'id' => (int)$get_post->ID, 'url' => get_permalink($get_post->ID));
258
- if($get_post->score > 0){
259
- $get_permalink = get_permalink((int)$get_post->ID);
260
- }
261
- }
262
-
263
- wp404arsp_redirect($get_permalink, $debug);
264
-
265
- }
266
-
267
- }
268
-
269
- unset($query['unknown']);
270
- wp404arsp_search($query, $debug);
271
-
272
- }
273
 
274
- wp404arsp_redirect(home_url(), 'Go home, you\'re drunk...');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275
 
 
276
  }
277
 
278
- function wp404arsp_redirect($url = '', $debug = ''){
279
-
280
- $wp404arsp_settings = wp404arsp_settings();
281
-
282
- if(is_super_admin() && $wp404arsp_settings['debug']){
283
- echo "<pre>"; echo 'Redirect to: ' . ((!empty($url)) ? $url : '<span>Empty</span>') . "</pre>";
284
 
285
- if(!empty($debug))
286
- echo "<pre>"; print_r($debug); echo "</pre>";
 
 
 
 
 
 
 
287
 
288
- echo "<hr />";
 
 
 
 
 
 
 
 
 
 
 
 
289
  return;
290
- }
291
 
292
- if(!empty($url)){
293
- wp_redirect($url, 301);
294
- exit;
295
- }
296
 
297
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
 
299
  function wp404arsp_remove_stop_words($input){
300
-
301
  $words = array('a', 'about', 'above', 'after', 'again', 'against', 'all', 'am', 'an', 'and', 'any', 'are', 'arent', 'as', 'at', 'be', 'because', 'been', 'before', 'being', 'below', 'between', 'both', 'but', 'by', 'cant', 'cannot', 'could', 'couldnt', 'did', 'didnt', 'do', 'does', 'doesnt', 'doing', 'dont', 'down', 'during', 'each', 'few', 'for', 'from', 'further', 'had', 'hadnt', 'has', 'hasnt', 'have', 'havent', 'having', 'he', 'hed', 'hell', 'hes', 'her', 'here', 'heres', 'hers', 'herself', 'him', 'himself', 'his', 'how', 'hows', 'i', 'id', 'ill', 'im', 'ive', 'if', 'in', 'into', 'is', 'isnt', 'it', 'its', 'itself', 'lets', 'me', 'more', 'most', 'mustnt', 'my', 'myself', 'no', 'nor', 'not', 'of', 'off', 'on', 'once', 'only', 'or', 'other', 'ought', 'our', 'ours', 'ourselves', 'out', 'over', 'own', 'same', 'shant', 'she', 'shed', 'shell', 'shes', 'should', 'shouldnt', 'so', 'some', 'such', 'than', 'that', 'thats', 'the', 'their', 'theirs', 'them', 'themselves', 'then', 'there', 'theres', 'these', 'they', 'theyd', 'theyll', 'theyre', 'theyve', 'this', 'those', 'to', 'too', 'under', 'until', 'up', 'very', 'was', 'wasnt', 'we', 'wed', 'well', 'were', 'weve', 'werent', 'what', 'whats', 'when', 'whens', 'where', 'wheres', 'which', 'while', 'who', 'whos', 'whom', 'why', 'whys', 'with', 'wont', 'would', 'wouldnt', 'you', 'youd', 'youll', 'youre', 'youve', 'your', 'yours', 'category', 'page', 'paged');
302
 
303
  if(is_array($input)){
@@ -314,4 +435,12 @@ function wp404arsp_remove_stop_words($input){
314
  return preg_replace('/\b('.implode('|', $words).')\b/', '', $input);
315
 
316
  }
 
 
 
 
 
 
 
 
317
  }
3
  * Plugin Name: WP 404 Auto Redirect to Similar Post
4
  * Description: Automatically Redirect any 404 to a Similar Post based on the Title, Post Type, Category & Taxonomy using 301 Redirects!
5
  * Author: hwk-fr
6
+ * Version: 0.7
7
  * Author URI: http://hwk.fr
8
  */
9
 
10
  if(!defined('ABSPATH'))
11
  die('You are not allowed to call this page directly.');
12
 
13
+ add_action('admin_menu', 'wp404arsp_admin_menu');
14
+ function wp404arsp_admin_menu(){
15
+ $menu = add_submenu_page('options-general.php', 'WP 404 Auto Redirect', 'WP 404 Auto Redirect', 'manage_options', 'wp-404-auto-redirect', 'wp404arsp_admin_page_html');
16
+
17
+ add_action('admin_print_scripts-' . $menu, function(){
18
+ wp_enqueue_script('wp404arsp_admin_js', plugins_url('wp-404-auto-redirect-similar-post.js', __FILE__), array('jquery'));
19
+ });
20
+
21
  }
22
 
23
+ add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'wp404arsp_plugin_link');
24
+ function wp404arsp_plugin_link($links){
25
+ return array_merge($links, array('<a href="' . admin_url('options-general.php?page=wp-404-auto-redirect') . '">Settings</a>'));
26
+ }
27
+
28
+ add_action('admin_init', 'wp404arsp_admin_settings');
29
+ function wp404arsp_admin_settings(){
30
+ register_setting('wp404arsp_settings', 'wp404arsp_settings');
31
+ }
32
+
33
+ function wp404arsp_admin_page_html(){
34
+ ?>
35
+ <div class="wrap">
36
+ <h1 class="wp-heading-inline">WP 404 Auto Redirect to Similar Post</h1>
37
+ <hr class="wp-header-end">
38
+
39
+ <div id="poststuff">
40
+ <div id="post-body" class="metabox-holder columns-2">
41
+
42
+ <div id="post-body-content">
43
+ <div class="meta-box-sortables ui-sortable">
44
+
45
+ <div class="postbox">
46
+ <h2 class="hndle"><span>Settings</span></h2>
47
+ <form method="post" action="options.php">
48
+ <?php
49
+ settings_fields('wp404arsp_settings');
50
+ do_settings_sections('wp404arsp_settings');
51
+ $wp404arsp_settings = wp404arsp_get_settings();
52
+ ?>
53
+
54
+ <div class="inside">
55
+ <table class="form-table">
56
+ <tbody>
57
+
58
+ <tr>
59
+ <th scope="row">Debug Mode</th>
60
+ <td>
61
+ <fieldset>
62
+ <legend class="screen-reader-text"><span>Debug</span></legend>
63
+ <label for="wp404arsp_settings[debug]">
64
+ <input name="wp404arsp_settings[debug]" id="wp404arsp_settings[debug]" value="1" type="checkbox" <?php if($wp404arsp_settings['debug'] == "1") echo "checked"; ?>>
65
+ Activate
66
+ </label>
67
+ </fieldset>
68
+ <p class="description" id="tagline-description">Administrators will get the debug console instead of being redirected.</p>
69
+ </td>
70
+ </tr>
71
+
72
+ <tr>
73
+ <th scope="row">Redirect to Home</th>
74
+ <td>
75
+ <fieldset>
76
+ <legend class="screen-reader-text"><span>Do not redirect to Home</span></legend>
77
+ <label for="wp404arsp_settings[home]">
78
+ <input name="wp404arsp_settings[home]" id="wp404arsp_settings[home]" value="1" type="checkbox" <?php if($wp404arsp_settings['home'] == "1") echo "checked"; ?>>
79
+ Disable
80
+ </label>
81
+ </fieldset>
82
+ <p class="description" id="tagline-description">Do not redirect to <a href="<?php echo home_url(); ?>"><?php echo home_url(); ?></a> if no similar post is found.</p>
83
+ </td>
84
+ </tr>
85
+
86
+ <tr>
87
+ <th scope="row">Redirect Headers</th>
88
+ <td>
89
+ <select name="wp404arsp_settings[method]" id="wp404arsp_settings[method]">
90
+ <option value="" <?php if(!$wp404arsp_settings['method']) echo "selected"; ?>>301 method</option>
91
+ <option value="302" <?php if($wp404arsp_settings['method'] == "302") echo "selected"; ?>>302 method</option>
92
+ </select>
93
+ <p class="description" id="tagline-description">Learn more about <a href="https://en.wikipedia.org/wiki/List_of_HTTP_status_codes" target="_blank">HTTP headers & redirections</a>.</p>
94
+ </td>
95
+ </tr>
96
+
97
+ </tbody>
98
+ </table>
99
+
100
+ <p class="submit" style="padding:0;">
101
+ <?php submit_button('Save Settings', 'primary', '', false); ?>
102
+ </p>
103
+ </div>
104
+ </form>
105
+ </div>
106
+
107
+ <div id="wp404arsp_settings_test">
108
+ <div class="postbox">
109
+ <h2 class="hndle"><span>Redirection Preview</span></h2>
110
+ <div class="inside">
111
+ <table class="form-table">
112
+ <tbody>
113
+
114
+ <tr>
115
+ <th scope="row"><?php echo home_url(); ?></th>
116
+ <td>
117
+ <input class="request" type="text" value="/example-url" style="width:500px;" />
118
+ <p class="description" id="tagline-description">Enter the URL you would like to test, starting with <code>/</code></p>
119
+ </td>
120
+ </tr>
121
+ </tbody>
122
+ </table>
123
+
124
+ <p class="submit" style="padding:0;">
125
+ <?php submit_button('Preview URL', 'secondary', '', false); ?>
126
+ </p>
127
+
128
+ <div class="results"></div>
129
+
130
+ </div>
131
+ </div>
132
+ </div>
133
+
134
+ </div>
135
+
136
+ </div>
137
+
138
+ <div id="postbox-container-1" class="postbox-container">
139
+ <div class="meta-box-sortables">
140
+ <div class="postbox">
141
+
142
+ <div class="inside">
143
+ <img src="<?php echo plugins_url('logo.png', __FILE__); ?>" style="max-width:100%; height:auto; margin:20px auto 30px; display:block;" />
144
+
145
+
146
+
147
+ <p>Found a bug? Need help? Head over the <a href="https://wordpress.org/plugins/wp-404-auto-redirect-to-similar-post/" target="_blank">official plugin page</a>.</p>
148
+
149
+ <hr />
150
+
151
+ <p>Enjoying this plugin? Please rate it. It's always much appreciated!</p>
152
+ <p>
153
+ <a href="https://wordpress.org/support/plugin/wp-404-auto-redirect-to-similar-post/reviews/#new-post" target="_blank" class="button">Rate the plugin</a>
154
+ </p>
155
+ </div>
156
+
157
+ </div>
158
+ </div>
159
+ </div>
160
+
161
+ </div>
162
+ <br class="clear">
163
+
164
+ </div>
165
+ </div>
166
+ <?php }
167
+
168
+ add_action('template_redirect', 'wp404arsp_init');
169
+ function wp404arsp_init(){
170
+
171
+ if( !is_404() || wp_doing_ajax() || is_admin() || $_SERVER['SCRIPT_URI'] == admin_url('admin-ajax.php') || (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') )
172
  return;
173
 
174
+ wp404arsp_request($_SERVER['REQUEST_URI']);
 
175
 
176
  }
177
 
178
+ function wp404arsp_request($request, $preview = false){
179
+
180
+ $query = array();
181
+ $query['request']['full'] = urldecode(htmlspecialchars($request));
182
+
183
+ if($preview)
184
+ $query['preview'] = true;
185
+
186
+ if(preg_match('#/(?<slug>page|paged)/(?<page>[0-9]+)/?$#i', $request, $pagination)){
187
+ $request_no_pagination = str_replace($pagination[0], '', $request);
188
+ $query['request']['pagination'] = array(
189
+ 'full' => $pagination[0],
190
+ 'slug' => $pagination['slug'],
191
+ 'page' => $pagination['page']
192
+ );
193
+ }
194
 
195
  $path = pathinfo(urldecode(htmlspecialchars(strtok($request, '?'))));
196
+ $path['filename'] = wp404arsp_sanitize(pathinfo(basename($request), PATHINFO_FILENAME));
197
+ $path['dirname'] = trim($path['dirname'], '/');
198
+ $path['dirname'] = trim($path['dirname'], '\\');
199
+
200
+ $query['request']['dirname'] = $path['dirname'];
201
+ $query['request']['filename'] = $path['filename'];
202
+ $query['request']['extension'] = (!empty($path['extension'])) ? $path['extension'] : '';
203
+
204
+
205
+ // Pagination found, try the URL without pagination
206
+ if(!empty($query['request']['pagination']))
207
+ return wp404arsp_redirect(array_merge( $query, array(
208
+ 'url' => home_url() . $request_no_pagination,
209
+ 'why' => "Pagination found in the requested url. Trying to reach same url without pagination."
210
+ ))
211
+ );
212
+
213
+ wp404arsp_setup($query);
214
+
215
+ }
216
+
217
+ function wp404arsp_setup($query){
218
 
219
+ if(!isset($query['request']['full']) || empty($query['request']['full']))
220
+ return;
221
+
222
+ $query['process']['request'] = $query['request']['full'];
223
+
224
+ global $wp_query;
225
+ $wp_query = $wp_query->query;
226
+
227
+ if(isset($wp_query['post_type'])){
228
 
229
+ $query['process']['post_type'] = $wp_query['post_type'];
230
+ $post_type = get_post_type_object($wp_query['post_type']);
231
+ if( stripos($query['request']['full'], $post_type->rewrite['slug']) !== false )
232
+ $query['process']['request'] = str_replace('//', '/', substr_replace($query['request']['full'], '', stripos($query['request']['full'], $post_type->rewrite['slug']), strlen($post_type->rewrite['slug'])));
 
 
 
 
233
 
234
+ elseif( stripos($query['request']['full'], $post_type->has_archive) !== false )
235
+ $query['process']['request'] = str_replace('//', '/', substr_replace($query['request']['full'], '', stripos($query['request']['full'], $post_type->has_archive), strlen($post_type->has_archive)));
236
  }
237
 
238
+ $query['process']['keywords']['sanitized'] = wp404arsp_sanitize(str_replace('.' . $query['request']['extension'], '', $query['process']['request']));
239
 
240
+ $keywords = explode('/', trim($query['process']['request'], '/'));
241
+ foreach($keywords as $keyword){
242
+ $query['process']['keywords']['explode'][] = str_replace('.' . $query['request']['extension'], '', $keyword);
243
+ }
244
+ $query['process']['keywords']['explode'] = array_reverse($query['process']['keywords']['explode']);
245
 
 
246
 
247
+ foreach($query['process']['keywords']['explode'] as $keyword){
248
+ $get_posts_types = get_post_types(array('public' => true), 'names');
249
+ foreach($get_posts_types as $post_type){
250
+ if($post = get_page_by_path($keyword, 'object', $post_type))
251
+ return wp404arsp_redirect(array_merge( $query, array(
252
+ 'score' => 'direct',
253
+ 'id' => (int)$post->ID,
254
+ 'url' => get_permalink((int)$post->ID),
255
+ 'why' => "The request url already exist as post of the post type " . get_post_type((int)$post->ID)
256
+ ))
257
+ );
258
+ }
259
+ }
260
+
261
+ return wp404arsp_redirect(wp404arsp_search($query));
262
 
263
+ }
264
+
265
+ function wp404arsp_search($query){
266
+
267
+ $keywords = explode('-', $query['process']['keywords']['sanitized']);
268
+ $post_type = (isset($query['process']['post_type']) && !empty($query['process']['post_type'])) ? $query['process']['post_type'] : '';
269
+
270
+ $sql = wp404arsp_search_sql($keywords, '');
271
+ if(empty($sql['post']) || $sql['post']['score'] < 1)
272
+ return array_merge( $query, array(
273
+ 'why' => "Nothing found in DB matching the request url"
274
+ )
275
+ );
276
+
277
+ $return = array_merge( $query, array(
278
+ 'score' => $sql['post']['score'],
279
+ 'id' => (int)$sql['post']['ID'],
280
+ 'url' => get_permalink((int)$sql['post']['ID']),
281
+ 'why' => "Highest score based on the requested url was found"
282
+ )
283
+ );
284
+
285
+ // If Post Type found, check other post types & compare score
286
+ if(!empty($post_type)){
287
+
288
+ $sql = wp404arsp_search_sql($keywords, $post_type);
289
+ if(!empty($sql['post']) && $sql['post']['score'] >= 1 && $sql['post']['score'] >= $return['score']){
290
+ $return = array_merge( $query, array(
291
+ 'score' => $sql['post']['score'],
292
+ 'id' => (int)$sql['post']['ID'],
293
+ 'url' => get_permalink((int)$sql['post']['ID']),
294
+ 'why' => "Highest score based on the requested url was found"
295
+ )
296
+ );
 
 
 
 
 
 
 
 
 
 
 
297
 
298
+ }else{
299
+ $return['why'] = "Post type " . $query['process']['post_type'] . " found, but the highest score based on the requested url was found within the post type " . get_post_type($return['id']);
300
 
 
301
  }
302
 
303
  }
306
 
307
  }
308
 
309
+ function wp404arsp_redirect($args){
310
 
311
+ $wp404arsp_settings = wp404arsp_get_settings();
312
+ $method = (!$wp404arsp_settings['method']) ? 301 : $wp404arsp_settings['method'];
313
+ $home_url = (!$wp404arsp_settings['home']) ? home_url() : false;
314
 
315
+ if( is_user_logged_in() && current_user_can('manage_options') && ($wp404arsp_settings['debug'] || $args['preview']) )
316
+ return wp404arsp_debug($args);
317
 
318
+ if(isset($args['url']) && !empty($args['url']))
319
+ return wp_redirect($args['url'], $method);
320
 
321
+ if($home_url)
322
+ return wp_redirect($home_url, $method);
323
 
324
+ return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
325
 
326
+ }
327
+
328
+ function wp404arsp_debug($args){
329
+ $wp404arsp_settings = wp404arsp_get_settings();
330
+ $method = (!$wp404arsp_settings['method']) ? 301 : $wp404arsp_settings['method'];
331
+
332
+ $title = '';
333
+ if(isset($args['url']) && !empty($args['url'])){
334
+ $title = 'Redirection to: ' . "<a href='" . $args['url'] . "'>" . $args['url'] . "</a>" . ' (' . $method . ' Headers)';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
335
 
336
+ }elseif($wp404arsp_settings['home'] == "1"){
337
+ $title = 'Redirect to Home disabled. Displaying 404.';
 
 
 
 
338
 
339
+ }else{
340
+ $title = 'Redirection to: ' . "<a href='" . home_url() . "'>" . home_url() . "</a>" . ' (' . $method . ' Headers)';
341
 
342
  }
343
 
344
+ ob_start(); ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
345
 
346
+ <style type="text/css">
347
+ .wp404arsp_debug_page{margin:0 auto; max-width:1150px; font-family: arial, sans-serif;}
348
+ .wp404arsp_debug_page h2,
349
+ .wp404arsp_debug_page h4{text-align:center;}
350
+ .wp404arsp_debug_page pre{background:#f4f4f4; padding:15px; overflow:auto;}
351
+ .wp404arsp_debug_page a{color:blue;}
352
+ .wp404arsp_debug_page p{font-size:12px;}
353
+ </style>
354
+ <div class="wp404arsp_debug_page">
355
+ <?php if(!isset($args['preview'])){ ?>
356
+ <h2>WP 404 Auto Redirect to Similar Post</h2>
357
+ <p>This is the <strong>debug console</strong> of WP 404 Auto redirect to Similar Post Plugin which is only visible to administrators. If you would like to to disable the Debug mode, please head over your <a href="<?php echo admin_url('options-general.php?page=wp-404-auto-redirect'); ?>">Settings page</a>.</p>
358
+ <hr />
359
+ <?php } ?>
360
+ <pre>Requested URL: <a href="<?php echo home_url(); ?><?php echo $args['request']['full']; ?>"><?php echo home_url(); ?><?php echo $args['request']['full']; ?></a><br />
361
+ <?php echo $title; ?><br />
362
+ Details: <?php echo $args['why']; ?>
363
+ </pre>
364
+ <pre><?php print_r($args); ?></pre>
365
+ </div>
366
 
367
+ <?php echo ob_get_clean(); exit;
368
  }
369
 
370
+ function wp404arsp_search_sql($keywords, $post_type = ''){
371
+ global $wpdb;
 
 
 
 
372
 
373
+ $sql = "SELECT p.ID, ";
374
+ foreach($keywords as $k){
375
+ $sql .= "if(INSTR(LCASE(p.post_name),'" . $k . "'), 1, 0) + ";
376
+ }
377
+ $sql .= "0 as score FROM " . $wpdb->posts . " AS p
378
+ WHERE p.post_status = 'publish' AND ";
379
+
380
+ if(!empty($post_type))
381
+ $sql .= "p.post_type = '" . $post_type . "'";
382
 
383
+ else
384
+ $sql .= "p.post_type <> 'attachment' AND p.post_type <> 'nav_menu_item'";
385
+
386
+ $sql .= " ORDER BY score DESC, post_modified DESC LIMIT 1";
387
+
388
+ return array(
389
+ 'post' => $wpdb->get_row($sql, 'ARRAY_A'),
390
+ 'dump' => $sql
391
+ );
392
+ }
393
+
394
+ function wp404arsp_ajax_test() {
395
+ if( !defined('DOING_AJAX') || !DOING_AJAX || !isset($_POST['action']) || !current_user_can('manage_options') )
396
  return;
 
397
 
398
+ $request = $_POST['request'];
399
+ wp404arsp_request($request, true);
400
+ die();
 
401
 
402
  }
403
+ add_action('wp_ajax_wp404arsp_ajax_test', 'wp404arsp_ajax_test');
404
+
405
+ function wp404arsp_sanitize($input){
406
+ return sanitize_title(str_replace(array('_', '/'), '-', $input));
407
+ }
408
+
409
+ function wp404arsp_get_settings(){
410
+ return wp_parse_args(get_option('wp404arsp_settings'),
411
+ array(
412
+ 'debug' => null,
413
+ 'logs' => null,
414
+ 'home' => null,
415
+ 'method' => null
416
+ )
417
+ );
418
+ }
419
 
420
  function wp404arsp_remove_stop_words($input){
421
+
422
  $words = array('a', 'about', 'above', 'after', 'again', 'against', 'all', 'am', 'an', 'and', 'any', 'are', 'arent', 'as', 'at', 'be', 'because', 'been', 'before', 'being', 'below', 'between', 'both', 'but', 'by', 'cant', 'cannot', 'could', 'couldnt', 'did', 'didnt', 'do', 'does', 'doesnt', 'doing', 'dont', 'down', 'during', 'each', 'few', 'for', 'from', 'further', 'had', 'hadnt', 'has', 'hasnt', 'have', 'havent', 'having', 'he', 'hed', 'hell', 'hes', 'her', 'here', 'heres', 'hers', 'herself', 'him', 'himself', 'his', 'how', 'hows', 'i', 'id', 'ill', 'im', 'ive', 'if', 'in', 'into', 'is', 'isnt', 'it', 'its', 'itself', 'lets', 'me', 'more', 'most', 'mustnt', 'my', 'myself', 'no', 'nor', 'not', 'of', 'off', 'on', 'once', 'only', 'or', 'other', 'ought', 'our', 'ours', 'ourselves', 'out', 'over', 'own', 'same', 'shant', 'she', 'shed', 'shell', 'shes', 'should', 'shouldnt', 'so', 'some', 'such', 'than', 'that', 'thats', 'the', 'their', 'theirs', 'them', 'themselves', 'then', 'there', 'theres', 'these', 'they', 'theyd', 'theyll', 'theyre', 'theyve', 'this', 'those', 'to', 'too', 'under', 'until', 'up', 'very', 'was', 'wasnt', 'we', 'wed', 'well', 'were', 'weve', 'werent', 'what', 'whats', 'when', 'whens', 'where', 'wheres', 'which', 'while', 'who', 'whos', 'whom', 'why', 'whys', 'with', 'wont', 'would', 'wouldnt', 'you', 'youd', 'youll', 'youre', 'youve', 'your', 'yours', 'category', 'page', 'paged');
423
 
424
  if(is_array($input)){
435
  return preg_replace('/\b('.implode('|', $words).')\b/', '', $input);
436
 
437
  }
438
+ }
439
+
440
+ function wp404arsp_search_array($array, $key, $value) {
441
+ foreach($array as $k => $v){
442
+ if ($v[$key] === $value)
443
+ return $k;
444
+ }
445
+ return null;
446
  }