PluginProbe ʕ •ᴥ•ʔ
Permalink Manager Lite / 2.2.2
Permalink Manager Lite v2.2.2
2.5.4 2.5.3.4 2.2.18 2.2.19.2 2.2.19.3 2.2.19.3.1 2.2.2 2.2.20 2.2.20.1 2.2.20.3 2.2.4 2.2.5 2.2.6 2.2.7.2 2.2.7.3 2.2.7.5 2.2.7.6 2.2.8.4 2.2.8.5 2.2.8.6 2.2.8.7 2.2.8.9 2.2.9.1 2.2.9.2 2.2.9.2.1 2.2.9.3 2.2.9.4 2.2.9.6 2.2.9.7 2.2.9.9 2.3.0 2.3.1.1 2.4.0 2.4.1 2.4.1.2 2.4.1.3 2.4.1.4 2.4.1.5 2.4.1.6 2.4.2 2.4.2.1 2.4.3 2.4.3.1 2.4.3.2 2.4.3.3 2.4.3.4 2.4.4 2.4.4.1 2.4.4.2 2.4.4.3 2.5.0 2.5.1 2.5.1.1 2.5.1.2 2.5.1.3 2.5.1.4 2.5.2 2.5.2.1 2.5.2.2 2.5.2.3 2.5.2.4 2.5.3 2.5.3.1 2.5.3.2 2.5.3.3 trunk 0.2 0.3 0.3.1 0.3.2 0.3.3 0.3.4 0.4 0.4.1 0.4.2 0.4.3 0.4.4 0.4.6 0.4.7 0.4.8 0.4.9 0.5.3 0.5.4 1.0.0 1.0.1 1.0.4 1.1.0 1.1.1 1.1.2 1.11.6.3 2.0.0 2.0.3 2.0.4 2.0.4.3 2.0.5.1 2.0.5.2 2.0.5.3 2.0.5.3.1 2.0.5.4 2.0.5.4a 2.0.5.5 2.0.5.6 2.0.5.6.1 2.0.5.7 2.0.5.9a 2.0.6.2.1 2.0.6.2a 2.0.6.3 2.1.0 2.1.1 2.1.2.4 2.2.0 2.2.1.1 2.2.1.2 2.2.11 2.2.12 2.2.13.1 2.2.14 2.2.15.1 2.2.16 2.2.17
permalink-manager / includes / core / permalink-manager-core-functions.php
permalink-manager / includes / core Last commit date
permalink-manager-actions.php 7 years ago permalink-manager-admin-functions.php 7 years ago permalink-manager-core-functions.php 7 years ago permalink-manager-gutenberg.php 7 years ago permalink-manager-helper-functions.php 7 years ago permalink-manager-third-parties.php 7 years ago permalink-manager-uri-functions-post.php 7 years ago
permalink-manager-core-functions.php
723 lines
1 <?php
2
3 /**
4 * Core function
5 */
6 class Permalink_Manager_Core_Functions extends Permalink_Manager_Class {
7
8 public function __construct() {
9 add_action( 'init', array($this, 'init_hooks'), 99);
10 }
11
12 function init_hooks() {
13 global $permalink_manager_options;
14
15 // Trigger only in front-end
16 if(!is_admin() && (function_exists('is_customize_preview') && is_customize_preview()) == false) {
17 // Use the URIs set in this plugin
18 add_filter( 'request', array($this, 'detect_post'), 0, 1 );
19
20 // Redirect from old URIs to new URIs + adjust canonical redirect settings
21 add_action( 'template_redirect', array($this, 'new_uri_redirect_and_404'), 1);
22 add_action( 'wp', array($this, 'adjust_canonical_redirect'), 0, 1);
23
24 // Case insensitive permalinks
25 if(!empty($permalink_manager_options['general']['case_insensitive_permalinks'])) {
26 add_action( 'parse_request', array($this, 'case_insensitive_permalinks'), 0);
27 }
28 // Force 404 on non-existing pagination pages
29 if(!empty($permalink_manager_options['general']['pagination_redirect'])) {
30 add_action( 'wp', array($this, 'fix_pagination_pages'), 0);
31 }
32 }
33
34 // Trailing slashes
35 add_filter( 'permalink_manager_filter_final_term_permalink', array($this, 'control_trailing_slashes'), 9);
36 add_filter( 'permalink_manager_filter_final_post_permalink', array($this, 'control_trailing_slashes'), 9);
37 add_filter( 'permalink_manager_filter_post_sample_uri', array($this, 'control_trailing_slashes'), 9);
38
39 // Replace empty placeholder tags & remove BOM
40 add_filter( 'permalink_manager_filter_default_post_uri', array($this, 'replace_empty_placeholder_tags'), 10, 5 );
41 add_filter( 'permalink_manager_filter_default_term_uri', array($this, 'replace_empty_placeholder_tags'), 10, 5 );
42 }
43
44 /**
45 * The most important Permalink Manager function
46 */
47 public static function detect_post($query, $request_url = false, $return_object = false) {
48 global $wpdb, $wp, $wp_rewrite, $permalink_manager, $permalink_manager_uris, $wp_filter, $permalink_manager_options, $pm_query, $pm_uri_parts;
49
50 // Check if the array with custom URIs is set
51 //if(!(is_array($permalink_manager_uris)) || (empty($query) && empty($request_url))) return $query;
52 if(!(is_array($permalink_manager_uris))) return $query;
53
54 // Used in debug mode & endpoints
55 $old_query = $query;
56
57 /**
58 * 1. Prepare URL and check if it is correct (make sure that both requested URL & home_url share the same protoocl and get rid of www prefix)
59 */
60 $request_url = (!empty($request_url)) ? parse_url($request_url, PHP_URL_PATH) : $_SERVER['REQUEST_URI'];
61 $request_url = strtok($request_url, "?");
62
63 $request_url = sprintf("http://%s%s", str_replace("www.", "", $_SERVER['HTTP_HOST']), $request_url);
64 $raw_home_url = trim(get_option('home'));
65 $home_url = preg_replace("/http(s)?:\/\/(www\.)?(.+?)\/?$/", "http://$3", $raw_home_url);
66
67 if(filter_var($request_url, FILTER_VALIDATE_URL)) {
68 // Check if "Deep Detect" is enabled
69 $deep_detect_enabled = apply_filters('permalink_manager_deep_uri_detect', $permalink_manager_options['general']['deep_detect']);
70
71 // Keep only the URI
72 $request_url = str_replace($home_url, "", $request_url);
73
74 // Hotfix for language plugins
75 if(filter_var($request_url, FILTER_VALIDATE_URL)) {
76 $request_url = parse_url($request_url, PHP_URL_PATH);
77 }
78
79 $request_url = trim($request_url, "/");
80
81 // Get all the endpoints & pattern
82 $endpoints = Permalink_Manager_Helper_Functions::get_endpoints();
83 $pattern = "/^(.+?)(?|\/({$endpoints})(?|\/(.*)|$)|\/()([\d]+)\/?)?$/i";
84
85 // Use default REGEX to detect post
86 preg_match($pattern, $request_url, $regex_parts);
87 $uri_parts['lang'] = false;
88 $uri_parts['uri'] = (!empty($regex_parts[1])) ? $regex_parts[1] : "";
89 $uri_parts['endpoint'] = (!empty($regex_parts[2])) ? $regex_parts[2] : "";
90 $uri_parts['endpoint_value'] = (!empty($regex_parts[3])) ? $regex_parts[3] : "";
91
92 // Allow to filter the results by third-parties + store the URI parts with $pm_query global
93 $uri_parts = $pm_query = apply_filters('permalink_manager_detect_uri', $uri_parts, $request_url, $endpoints);
94
95 // Support comment pages
96 preg_match("/(.*)\/{$wp_rewrite->comments_pagination_base}-([\d]+)/", $request_url, $regex_parts);
97 if(!empty($regex_parts[2])) {
98 $uri_parts['uri'] = $regex_parts[1];
99 $uri_parts['endpoint'] = 'cpage';
100 $uri_parts['endpoint_value'] = $regex_parts[2];
101 }
102
103 // Support pagination endpoint
104 if($uri_parts['endpoint'] == $wp_rewrite->pagination_base) {
105 $uri_parts['endpoint'] = 'page';
106 }
107
108 // Stop the function if $uri_parts is empty
109 if(empty($uri_parts)) return $query;
110
111 // Get the URI parts from REGEX parts
112 $lang = $uri_parts['lang'];
113 $uri = $uri_parts['uri'];
114 $endpoint = $uri_parts['endpoint'];
115 $endpoint_value = $uri_parts['endpoint_value'];
116
117 // Trim slashes
118 $uri = trim($uri, "/");
119
120 // Ignore URLs with no URI grabbed
121 if(empty($uri)) return $query;
122
123 // Flip array for better performance
124 $all_uris = array_flip($permalink_manager_uris);
125
126 // Attempt 1.
127 // Find the element ID
128 $element_id = isset($all_uris[$uri]) ? $all_uris[$uri] : false;
129
130 // Atempt 2.
131 // Decode both request URI & URIs array & make them lowercase (and save in a separate variable)
132 if(empty($element_id)) {
133 $uri = strtolower(urldecode($uri));
134
135 foreach($all_uris as $raw_uri => $uri_id) {
136 $raw_uri = strtolower(urldecode($raw_uri));
137 $all_uris[$raw_uri] = $uri_id;
138 }
139
140 $element_id = isset($all_uris[$uri]) ? $all_uris[$uri] : $element_id;
141 }
142
143 // Atempt 3.
144 // Check again in case someone used post/tax IDs instead of slugs
145 //if(empty($element_id) && $deep_detect_enabled && (isset($old_query['page']))) {
146 if($deep_detect_enabled && is_numeric($endpoint_value) && isset($all_uris["{$uri}/{$endpoint_value}"])) {
147 $element_id = $all_uris["{$uri}/{$endpoint_value}"];
148 $endpoint_value = $endpoint = "";
149 }
150
151 // Atempt 4.
152 // Check again for attachment custom URIs
153 if(empty($element_id) && isset($old_query['attachment'])) {
154 $element_id = isset($all_uris["{$uri}/{$endpoint}/{$endpoint_value}"]) ? $all_uris["{$uri}/{$endpoint}/{$endpoint_value}"] : $element_id;
155
156 if($element_id) {
157 $endpoint_value = $endpoint = "";
158 }
159 }
160
161 // Allow to filter the item_id by third-parties after initial detection
162 $element_id = apply_filters('permalink_manager_detected_element_id', $element_id, $uri_parts, $request_url);
163
164 // Clear the original query before it is filtered
165 $query = ($element_id) ? array() : $query;
166
167 /**
168 * 3A. Custom URI assigned to taxonomy
169 */
170 if(strpos($element_id, 'tax-') !== false) {
171 // Remove the "tax-" prefix
172 $term_id = intval(preg_replace("/[^0-9]/", "", $element_id));
173
174 // Filter detected post ID
175 $term_id = apply_filters('permalink_manager_detected_term_id', intval($term_id), $uri_parts, true);
176
177 // Get the variables to filter wp_query and double-check if taxonomy exists
178 $term = get_term($term_id);
179 $term_taxonomy = (!empty($term->taxonomy)) ? $term->taxonomy : false;
180
181 // Check if taxonomy is allowed
182 $disabled = (Permalink_Manager_Helper_Functions::is_disabled($term_taxonomy, 'taxonomy')) ? true : false;
183
184 // Proceed only if the term is not removed and its taxonomy is not disabled
185 if(!$disabled && $term_taxonomy) {
186 // Get some term data
187 if($term_taxonomy == 'category') {
188 $query_parameter = 'category_name';
189 } else if($term_taxonomy == 'post_tag') {
190 $query_parameter = 'tag';
191 } else {
192 $query["taxonomy"] = $term_taxonomy;
193 $query_parameter = $term_taxonomy;
194 }
195 $term_ancestors = get_ancestors($term_id, $term_taxonomy);
196 $final_uri = $term->slug;
197
198 // Fix for hierarchical terms
199 if(empty($term_ancestors)) {
200 foreach ($term_ancestors as $parent) {
201 $parent = get_term($parent, $term_taxonomy);
202 if(!empty($parent->slug)) {
203 $final_uri = $parent->slug . '/' . $final_uri;
204 }
205 }
206 }
207
208 $query["term"] = $final_uri;
209 $query[$query_parameter] = $final_uri;
210 } else {
211 $broken_uri = true;
212 }
213 }
214 /**
215 * 3B. Custom URI assigned to post/page/cpt item
216 */
217 else if(isset($element_id) && is_numeric($element_id)) {
218 // Fix for revisions
219 $is_revision = wp_is_post_revision($element_id);
220 $element_id = ($is_revision) ? $is_revision : $element_id;
221
222 // Filter detected post ID
223 $element_id = apply_filters('permalink_manager_detected_post_id', $element_id, $uri_parts);
224
225 $post_to_load = get_post($element_id);
226 $final_uri = (!empty($post_to_load->post_name)) ? $post_to_load->post_name : false;
227 $post_type = (!empty($post_to_load->post_type)) ? $post_to_load->post_type : false;
228
229 // Check if post type is allowed
230 $disabled = (Permalink_Manager_Helper_Functions::is_disabled($post_type, 'post_type')) ? true : false;
231
232 // Proceed only if the term is not removed and its taxonomy is not disabled
233 if(!$disabled && $post_type) {
234 $post_type_object = get_post_type_object($post_type);
235
236 // Fix for hierarchical CPT & pages
237 if(!(empty($post_to_load->ancestors)) && !empty($post_type_object->hierarchical)) {
238 foreach ($post_to_load->ancestors as $parent) {
239 $parent = get_post( $parent );
240 if($parent && $parent->post_name) {
241 $final_uri = $parent->post_name . '/' . $final_uri;
242 }
243 }
244 }
245
246 // Alter query parameters + support drafts URLs
247 if($post_to_load->post_status == 'draft') {
248 $query['p'] = $element_id;
249 $query['preview'] = true;
250 $query['post_type'] = $post_type;
251 } else if($post_type == 'page') {
252 $query['pagename'] = $final_uri;
253 // $query['post_type'] = $post_type;
254 } else if($post_type == 'post') {
255 $query['name'] = $final_uri;
256 } else if($post_type == 'attachment') {
257 $query['attachment'] = $final_uri;
258 } else {
259 // Get the query var
260 $query_var = (!empty($post_type_object->query_var)) ? $post_type_object->query_var : $post_type;
261
262 $query['name'] = $final_uri;
263 $query['post_type'] = $post_type;
264 $query[$query_var] = $final_uri;
265 }
266 } else {
267 $broken_uri = true;
268 }
269 }
270
271 /**
272 * 4. Auto-remove removed term custom URI & redirects (works if enabled in plugin settings)
273 */
274 if(!empty($broken_uri) && !empty($permalink_manager_options['general']['auto_remove_duplicates'])) {
275 $remove_broken_uri = Permalink_Manager_Actions::clear_single_element_uris_and_redirects($element_id);
276
277 // Reload page if success
278 if($remove_broken_uri) {
279 header("Refresh:0");
280 exit();
281 }
282 }
283
284 /**
285 * 5A. Endpoints
286 */
287 if(!empty($element_id) && (!empty($endpoint) || !empty($endpoint_value))) {
288 if(is_array($endpoint)) {
289 foreach($endpoint as $endpoint_name => $endpoint_value) {
290 $query[$endpoint_name] = $endpoint_value;
291 }
292 } else if($endpoint == 'feed') {
293 $query[$endpoint] = 'feed';
294 } else if($endpoint == 'page') {
295 $endpoint = 'paged';
296 $query[$endpoint] = $endpoint_value;
297 } else if($endpoint == 'trackback') {
298 $endpoint = 'tb';
299 $query[$endpoint] = 1;
300 } else if(!$endpoint && is_numeric($endpoint_value)) {
301 $query['page'] = $endpoint_value;
302 } else {
303 $query[$endpoint] = $endpoint_value;
304 }
305
306 // Fix for attachments
307 if(!empty($query['attachment'])) {
308 $query = array('attachment' => $query['attachment'], 'do_not_redirect' => 1);
309 }
310 }
311
312 /**
313 * 5B. Endpoints - check if any endpoint is set with $_GET parameter
314 */
315 if(!empty($element_id) && $deep_detect_enabled && !empty($_GET)) {
316 $get_endpoints = array_intersect($wp->public_query_vars, array_keys($_GET));
317
318 if(!empty($get_endpoints)) {
319 // Append query vars from $_GET parameters
320 foreach($get_endpoints as $endpoint) {
321 // Numeric endpoints
322 $endpoint_value = (in_array($endpoint, array('page', 'paged', 'attachment_id'))) ? filter_var($_GET[$endpoint], FILTER_SANITIZE_NUMBER_INT) : $_GET[$endpoint];
323 $query[$endpoint] = sanitize_text_field($endpoint_value);
324 }
325 }
326 }
327
328 /**
329 * 6. WWW prefix mismatch detect
330 */
331 $home_url_has_www = (strpos($raw_home_url, 'www.') !== false) ? true : false;
332 $requested_url_has_www = (strpos($_SERVER['HTTP_HOST'], 'www.') !== false) ? true : false;
333
334 if($home_url_has_www != $requested_url_has_www) {
335 unset($query['do_not_redirect']);
336 }
337
338 /**
339 * 7. Set global with detected item id
340 */
341 if(!empty($element_id)) {
342 $pm_query['id'] = $element_id;
343
344 // Make the redirects more clever - see new_uri_redirect_and_404() method
345 $query['do_not_redirect'] = 1;
346 }
347 }
348
349 /**
350 * 8. Debug mode
351 */
352 if(isset($_REQUEST['debug_url'])) {
353 $debug_info['uri_parts'] = $uri_parts;
354 $debug_info['old_query_vars'] = $old_query;
355 $debug_info['new_query_vars'] = $query;
356 $debug_info['detected_id'] = (!empty($pm_query['id'])) ? $pm_query['id'] : "-";
357
358 if(isset($post_type)) {
359 $debug_info['post_type'] = $post_type;
360 } else if(isset($term_taxonomy)) {
361 $debug_info['taxonomy'] = $term_taxonomy;
362 }
363
364 // License key info
365 if(class_exists('Permalink_Manager_Pro_Functions')) {
366 $license_key = $permalink_manager->functions['pro-functions']->get_license_key();
367
368 // Mask the license key
369 $debug_info['license_key'] = preg_replace('/([^-]+)-([^-]+)-([^-]+)-([^-]+)$/', '***-***-$3', $license_key);
370 }
371
372 $debug_txt = sprintf("<pre style=\"display:block;\">%s</pre>", print_r($debug_info, true));
373 wp_die($debug_txt);
374 }
375
376 if($return_object && !empty($term)) {
377 return $term;
378 } else if($return_object && !empty($post_to_load)) {
379 return $post_to_load;
380 } else {
381 return $query;
382 }
383 }
384
385 /**
386 * Trailing slash & remove BOM and double slashes
387 */
388 function control_trailing_slashes($permalink) {
389 global $permalink_manager_options;
390
391 // Ignore empty permalinks
392 if(empty($permalink)) { return $permalink; }
393
394 $trailing_slash_setting = (!empty($permalink_manager_options['general']['trailing_slashes'])) ? $permalink_manager_options['general']['trailing_slashes'] : "";
395
396 // Do not append the trailing slash if permalink contains hashtag or get parameters
397 $url_parsed = parse_url($permalink);
398
399 if(!empty($url_parsed['query']) || !empty($url_parsed['fragment']) || preg_match("/.*\.([a-zA-Z]{3,4})\/?$/", $permalink)) {
400 $permalink = untrailingslashit($permalink);
401 } else if(in_array($trailing_slash_setting, array(1, 10))) {
402 $permalink = trailingslashit($permalink);
403 } else if(in_array($trailing_slash_setting, array(2, 20))) {
404 $permalink = untrailingslashit($permalink);
405 }
406
407 // Remove double slashes
408 $permalink = preg_replace('/([^:])(\/{2,})/', '$1/', $permalink);
409
410 // Remove trailing slashes from URLs with extensions
411 $permalink = preg_replace("/(\.[a-z]{3,4})\/$/i", "$1", $permalink);
412
413 return $permalink;
414 }
415
416 /**
417 * Display 404 if requested page does not exist in pagination
418 */
419 function fix_pagination_pages() {
420 global $wp_query;
421
422 // 1. Get the post object
423 $post = get_queried_object();
424
425 // 2. Check if post object is defined
426 if(empty($post->post_type)) { return; }
427
428 // 3. Check if pagination is detected
429 $current_page = (!empty($wp_query->query_vars['page'])) ? $wp_query->query_vars['page'] : 1;
430 $current_page = (empty($wp_query->query_vars['page']) && !empty($wp_query->query_vars['paged'])) ? $wp_query->query_vars['paged'] : $current_page;
431
432 // 4. Count post pages
433 $num_pages = substr_count(strtolower($post->post_content), '<!--nextpage-->') + 1;
434
435 // 5. Block non-existent pages (Force 404 error)
436 if($current_page > 1 && ($current_page > $num_pages)) {
437 $wp_query->is_404 = true;
438 $wp_query->query = $wp_query->queried_object = $wp_query->queried_object_id = null;
439 $wp_query->set_404();
440
441 status_header(404);
442 nocache_headers();
443 include(get_query_template('404'));
444
445 die();
446 }
447 }
448
449 /**
450 * Redirects
451 */
452 function new_uri_redirect_and_404() {
453 global $wp_query, $permalink_manager_uris, $permalink_manager_redirects, $permalink_manager_external_redirects, $permalink_manager_options, $wp, $pm_query, $pm_uri_parts;
454
455 // Do not redirect on author pages & front page
456 if(is_author() || is_front_page() || is_home() || is_feed()) { return false; }
457
458 // Unset 404 if custom URI is detected
459 if(isset($pm_query['id'])) {
460 $wp_query->is_404 = false;
461 }
462
463 // Sometimes $wp_query indicates the wrong object if requested directly
464 $queried_object = get_queried_object();
465
466 // Get the redirection mode & trailing slashes settings
467 $redirect_mode = (!empty($permalink_manager_options['general']['redirect'])) ? $permalink_manager_options['general']['redirect'] : false;
468 $trailing_slashes_mode = (!empty($permalink_manager_options['general']['trailing_slashes'])) ? $permalink_manager_options['general']['trailing_slashes'] : false;
469 $trailing_slashes_redirect_mode = (!empty($permalink_manager_options['general']['trailing_slashes_redirect'])) ? $permalink_manager_options['general']['trailing_slashes_redirect'] : 301;
470 $redirect_type = '-';
471
472 // Get query string & URI
473 $query_string = $_SERVER['QUERY_STRING'];
474 $old_uri = $_SERVER['REQUEST_URI'];
475
476 // Get home URL
477 $home_url = rtrim(get_option('home'), "/");
478 $home_dir = parse_url($home_url, PHP_URL_PATH);
479
480 // Fix for WP installed in directories (remove the directory name from the URI)
481 if(!empty($home_dir)) {
482 $home_dir_regex = preg_quote(trim($home_dir), "/");
483 $old_uri = preg_replace("/{$home_dir_regex}/", "", $old_uri, 1);
484 }
485
486 /**
487 * 1A. External redirect
488 */
489 if(!empty($pm_query['id']) && !empty($permalink_manager_external_redirects[$pm_query['id']])) {
490 $external_url = $permalink_manager_external_redirects[$pm_query['id']];
491
492 if(filter_var($external_url, FILTER_VALIDATE_URL)) {
493 // Allow redirect
494 $wp_query->query_vars['do_not_redirect'] = 0;
495
496 wp_redirect($external_url, 301);
497 exit();
498 }
499 }
500
501 /**
502 * 1B. Custom redirects
503 */
504 if(empty($wp_query->query_vars['do_not_redirect']) && !empty($permalink_manager_redirects) && is_array($permalink_manager_redirects) && !empty($wp->request) && !empty($pm_query['uri'])) {
505 $uri = $pm_query['uri'];
506
507 // Make sure that URIs with non-ASCII characters are also detected
508 $decoded_url = urldecode($uri);
509
510 // Check if the URI is not assigned to any post/term's redirects
511 foreach($permalink_manager_redirects as $element => $redirects) {
512 if(is_array($redirects) && (in_array($uri, $redirects) || in_array($decoded_url, $redirects))) {
513
514 // Post is detected
515 if(is_numeric($element)) {
516 $correct_permalink = get_permalink($element);
517 }
518 // Term is detected
519 else {
520 $term_id = intval(preg_replace("/[^0-9]/", "", $element));
521 $correct_permalink = get_term_link($term_id);
522 }
523 }
524 }
525
526 $redirect_type = (!empty($correct_permalink)) ? 'custom_redirect' : $redirect_type;
527 }
528
529 // Ignore WP-Content links
530 if(!empty($_SERVER['REQUEST_URI']) && (strpos($_SERVER['REQUEST_URI'], '/wp-content') !== false)) { return false; }
531
532 /**
533 * 1C. Enhance native redirect
534 */
535 if(empty($wp_query->query_vars['do_not_redirect']) && $redirect_mode && !empty($queried_object) && empty($correct_permalink)) {
536
537 // Affect only posts with custom URI and old URIs
538 if(!empty($queried_object->ID) && isset($permalink_manager_uris[$queried_object->ID]) && empty($wp_query->query['preview'])) {
539 // Ignore posts with specific statuses
540 if(!(empty($queried_object->post_status)) && in_array($queried_object->post_status, array('draft', 'pending', 'auto-draft', 'future'))) {
541 return '';
542 }
543
544 // Check if post type is allowed
545 if(Permalink_Manager_Helper_Functions::is_disabled($queried_object->post_type, 'post_type')) { return ''; }
546
547 // Get the real URL
548 $correct_permalink = get_permalink($queried_object->ID);
549 }
550 // Affect only terms with custom URI and old URIs
551 else if(!empty($queried_object->term_id) && isset($permalink_manager_uris["tax-{$queried_object->term_id}"]) && defined('PERMALINK_MANAGER_PRO')) {
552 // Check if taxonomy is allowed
553 if(Permalink_Manager_Helper_Functions::is_disabled($queried_object->taxonomy, "taxonomy")) { return ''; }
554
555 // Get the real URL
556 $correct_permalink = get_term_link($queried_object->term_id, $queried_object->taxonomy);
557 }
558
559 $redirect_type = (!empty($correct_permalink)) ? 'native_redirect' : $redirect_type;
560 }
561
562 /**
563 * 2. Check trailing slashes (ignore links with query parameters)
564 */
565 if($trailing_slashes_mode && empty($_SERVER['QUERY_STRING']) && !empty($_SERVER['REQUEST_URI'])) {
566 // Check if $old_uri ends with slash or not
567 $ends_with_slash = (substr($old_uri, -1) == "/") ? true : false;
568 $trailing_slashes_mode = (preg_match("/.*\.([a-zA-Z]{3,4})\/?$/", $old_uri) && $trailing_slashes_mode == 10) ? 20 : $trailing_slashes_mode;
569
570 // Ignore empty URIs
571 if($old_uri != "/") {
572 // Remove the trailing slashes (and add them again if needed below)
573 $old_uri = trim($old_uri, "/");
574 $correct_permalink = (!empty($correct_permalink)) ? trim($correct_permalink, "/") : "";
575
576 // 2A. Force trailing slashes
577 if($trailing_slashes_mode == 10 && $ends_with_slash == false) {
578 $correct_permalink = (!empty($correct_permalink)) ? "{$correct_permalink}/" : "{$home_url}/{$old_uri}/";
579 }
580 // 2B. Remove trailing slashes
581 else if($trailing_slashes_mode == 20 && $ends_with_slash == true) {
582 $correct_permalink = (!empty($correct_permalink)) ? $correct_permalink : "{$home_url}/{$old_uri}";
583 $correct_permalink = trim($correct_permalink, "/");
584 }
585
586 // Use redirect mode set for trailing slash redirect
587 if(($trailing_slashes_mode == 20 && $ends_with_slash == true) || ($trailing_slashes_mode == 10 && $ends_with_slash == false)) {
588 $redirect_mode = $trailing_slashes_redirect_mode;
589 }
590 }
591
592 $redirect_type = (!empty($correct_permalink)) ? 'slash_redirect' : '-';
593 }
594
595 /**
596 * 3. Check if URL contains duplicated slashes
597 */
598 if(!empty($old_uri) && ($old_uri != '/') && preg_match('/\/{2,}/', $old_uri)) {
599 $new_uri = ltrim(preg_replace('/([^:])([\/]+)/', '$1/', $old_uri), "/");
600 $correct_permalink = "{$home_url}/{$new_uri}";
601 }
602
603 /**
604 * 4. Prevent redirect loop
605 */
606 if(!empty($correct_permalink) && is_string($correct_permalink) && !empty($wp->request) && !empty($redirect_type) && $redirect_type != 'slash_redirect') {
607 $current_uri = trim($wp->request, "/");
608 $redirect_uri = trim(parse_url($correct_permalink, PHP_URL_PATH), "/");
609
610 $correct_permalink = ($redirect_uri == $current_uri) ? null : $correct_permalink;
611 }
612
613 /**
614 * 5. Debug redirect
615 */
616 if(isset($_REQUEST['debug_redirect'])) {
617 $debug_info['query_vars'] = $wp_query->query_vars;
618 $debug_info['redirect_url'] = (!empty($correct_permalink)) ? $correct_permalink : '-';
619 $debug_info['redirect_mode'] = (!empty($redirect_mode)) ? $redirect_mode : "-";
620 $debug_info['queried_object'] = (!empty($queried_object)) ? $queried_object : "-";
621
622 $debug_txt = sprintf("<pre style=\"display:block;\">%s</pre>", print_r($debug_info, true));
623 wp_die($debug_txt);
624 }
625
626 /**
627 * 6. Ignore default URIs (or do nothing if redirects are disabled)
628 */
629 if(!empty($correct_permalink) && is_string($correct_permalink) && !empty($redirect_mode)) {
630 // Allow redirect
631 $wp_query->query_vars['do_not_redirect'] = 0;
632
633 // Append query string
634 $correct_permalink = (!empty($query_string)) ? sprintf("%s?%s", strtok($correct_permalink, "?"), $query_string) : $correct_permalink;
635
636 // Remove double slash
637 $correct_permalink = preg_replace('~(?<!https:|http:)[/\\\\]+~', "/", trim($correct_permalink));
638
639 wp_safe_redirect($correct_permalink, $redirect_mode);
640 exit();
641 }
642 }
643
644 function adjust_canonical_redirect() {
645 global $permalink_manager_options, $permalink_manager_uris, $wp, $wp_rewrite;
646
647 // Adjust rewrite settings for trailing slashes
648 $trailing_slash_setting = (!empty($permalink_manager_options['general']['trailing_slashes'])) ? $permalink_manager_options['general']['trailing_slashes'] : "";
649 if(in_array($trailing_slash_setting, array(1, 10))) {
650 $wp_rewrite->use_trailing_slashes = true;
651 } else if(in_array($trailing_slash_setting, array(2, 20))) {
652 $wp_rewrite->use_trailing_slashes = false;
653 }
654
655 // Get endpoints
656 $endpoints = Permalink_Manager_Helper_Functions::get_endpoints();
657 $endpoints_array = ($endpoints) ? explode("|", $endpoints) : array();
658
659 // Check if any endpoint is called (fix for feed and similar endpoints)
660 foreach($endpoints_array as $endpoint) {
661 if(!empty($wp->query_vars[$endpoint])) {
662 $wp->query_vars['do_not_redirect'] = 1;
663 break;
664 }
665 }
666
667 // Do nothing for posts and terms without custom URIs (when canonical redirect is enabled)
668 if(is_singular() || is_tax() || is_category() || is_tag()) {
669 $element = get_queried_object();
670 if(!empty($element->ID)) {
671 $custom_uri = (!empty($permalink_manager_uris[$element->ID])) ? $permalink_manager_uris[$element->ID] : "";
672 } else if(!empty($element->term_id)) {
673 $custom_uri = (!empty($permalink_manager_uris["tax-{$element->term_id}"])) ? $permalink_manager_uris["tax-{$element->term_id}"] : "";
674 }
675 }
676
677 if(!($permalink_manager_options['general']['canonical_redirect']) || !empty($wp->query_vars['do_not_redirect'])) {
678 remove_action('template_redirect', 'wp_old_slug_redirect');
679 remove_action('template_redirect', 'redirect_canonical');
680 add_filter('wpml_is_redirected', '__return_false', 99, 2);
681 add_filter('pll_check_canonical_url', '__return_false', 99, 2);
682 }
683 }
684
685 /**
686 * Case insensitive permalinks
687 */
688 function case_insensitive_permalinks() {
689 global $permalink_manager_options, $permalink_manager_uris;
690
691 if(!empty($_SERVER['REQUEST_URI'])) {
692 $_SERVER['REQUEST_URI'] = strtolower($_SERVER['REQUEST_URI']);
693 $permalink_manager_uris = array_map('strtolower', $permalink_manager_uris);
694 }
695 }
696
697 /**
698 * Replace empty placeholder tags & remove BOM
699 */
700 public static function replace_empty_placeholder_tags($default_uri, $native_slug = "", $element = "", $slug = "", $native_uri = "") {
701 // Do not affect native URIs
702 if($native_uri == true) { return $default_uri; }
703
704 // Remove the BOM
705 $default_uri = str_replace(array("\xEF\xBB\xBF", "%ef%bb%bf"), '', $default_uri);
706
707 // Encode the URI before placeholders are removed
708 $chunks = explode('/', $default_uri);
709 foreach ($chunks as &$chunk) {
710 if(preg_match("/^(%.+?%)$/", $chunk) == false) {
711 $chunk = urldecode($chunk);
712 }
713 }
714 $default_uri = implode("/", $chunks);
715
716 $empty_tag_replacement = apply_filters('permalink_manager_empty_tag_replacement', null, $element);
717 $default_uri = ($empty_tag_replacement || is_null($empty_tag_replacement)) ? str_replace("//", "/", preg_replace("/%(.+?)%/", $empty_tag_replacement, $default_uri)) : $default_uri;
718
719 return trim($default_uri, "/");
720 }
721
722 }
723