PluginProbe ʕ •ᴥ•ʔ
Permalink Manager Lite / 1.1.1
Permalink Manager Lite v1.1.1
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 / permalink-manager.php
permalink-manager Last commit date
includes 8 years ago languages 8 years ago out 8 years ago LICENSE.txt 8 years ago README.txt 8 years ago permalink-manager.php 8 years ago
permalink-manager.php
479 lines
1 <?php
2
3 /**
4 * Plugin Name: Permalink Manager Lite
5 * Plugin URI: https://permalinkmanager.pro?utm_source=plugin
6 * Description: Most advanced Permalink utility for Wordpress. It allows to bulk edit the permalinks & permastructures and regenerate/reset all the URIs in your Wordpress instance.
7 * Version: 1.1.1
8 * Author: Maciej Bis
9 * Author URI: http://maciejbis.net/
10 * License: GPL-2.0+
11 * License URI: http://www.gnu.org/licenses/gpl-2.0.txt
12 * Text Domain: permalink-manager
13 * Domain Path: /languages
14 */
15
16 // If this file is called directly or plugin is already defined, abort.
17 if (!defined('WPINC')) {
18 die;
19 }
20
21 // Define the directories used to load plugin files.
22 define( 'PERMALINK_MANAGER_PLUGIN_NAME', 'Permalink Manager' );
23 define( 'PERMALINK_MANAGER_PLUGIN_SLUG', 'permalink-manager' );
24 define( 'PERMALINK_MANAGER_VERSION', '1.1.1' );
25 define( 'PERMALINK_MANAGER_DIR', untrailingslashit( dirname( __FILE__ ) ) );
26 define( 'PERMALINK_MANAGER_BASENAME', plugin_basename(__FILE__) );
27 define( 'PERMALINK_MANAGER_URL', untrailingslashit( plugins_url( '', __FILE__ ) ) );
28 define( 'PERMALINK_MANAGER_WEBSITE', 'http://permalinkmanager.pro?utm_source=plugin' );
29 define( 'PERMALINK_MANAGER_DONATE', 'https://www.paypal.me/Bismit' );
30
31 class Permalink_Manager_Class {
32
33 public $permalink_manager, $permalink_manager_options_page, $permalink_manager_options;
34 public $sections, $functions, $permalink_manager_before_sections_html, $permalink_manager_after_sections_html;
35
36 /**
37 * Get options from DB, load subclasses & hooks
38 */
39 public function __construct() {
40 $this->include_subclassess();
41 $this->register_init_hooks();
42 }
43
44 /**
45 * Include back-end classess and set their instances
46 */
47 function include_subclassess() {
48 // WP_List_Table needed for post types & taxnomies editors
49 if( ! class_exists( 'WP_List_Table' ) ) {
50 require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
51 }
52
53 $classes = array(
54 'core' => array(
55 'helper-functions' => 'Permalink_Manager_Helper_Functions',
56 'uri-functions-post' => 'Permalink_Manager_URI_Functions_Post',
57 'uri-functions-tax' => 'Permalink_Manager_URI_Functions_Tax',
58 'admin-functions' => 'Permalink_Manager_Admin_Functions',
59 'actions' => 'Permalink_Manager_Actions',
60 'third-parties' => 'Permalink_Manager_Third_Parties',
61 'pro-functions' => 'Permalink_Manager_Pro_Functions'
62 ),
63 'views' => array(
64 'uri-editor' => 'Permalink_Manager_Uri_Editor',
65 'tools' => 'Permalink_Manager_Tools',
66 'permastructs' => 'Permalink_Manager_Permastructs',
67 'settings' => 'Permalink_Manager_Settings',
68 'debug' => 'Permalink_Manager_Debug',
69 'pro-addons' => 'Permalink_Manager_Pro_Addons',
70 'upgrade' => 'Permalink_Manager_Upgrade',
71 'uri-editor-tax' => false,
72 'uri-editor-post' => false
73 )
74 );
75
76 // Load classes and set-up their instances
77 foreach($classes as $class_type => $classes_array) {
78 foreach($classes_array as $class => $class_name) {
79 $filename = PERMALINK_MANAGER_DIR . "/includes/{$class_type}/permalink-manager-{$class}.php";
80
81 if(file_exists($filename)) {
82 require_once $filename;
83 if($class_name) { $this->functions[$class] = new $class_name(); }
84 }
85 }
86 }
87 }
88
89 /**
90 * Register general hooks
91 */
92 public function register_init_hooks() {
93 // Localize plugin
94 add_action( 'plugins_loaded', array($this, 'localize_me'), 1 );
95
96 // Load options
97 add_action( 'init', array($this, 'get_options_and_globals'), 1 );
98
99 // Use the URIs set in this plugin + redirect from old URIs to new URIs + adjust canonical redirect settings
100 add_action( 'template_redirect', array($this, 'redirect_to_new_uri'), 999);
101 add_filter( 'request', array($this, 'detect_post'), 0, 1 );
102 add_action( 'parse_request', array($this, 'disable_canonical_redirect'), 0, 1 );
103
104 // Legacy support
105 add_action( 'init', array($this, 'legacy_support'), 2 );
106
107 // Check for updates
108 add_action( 'init', array($this, 'check_for_updates'), 999 );
109
110 // Default settings & alerts
111 add_filter( 'permalink-manager-options', array($this, 'default_settings'), 1 );
112 add_filter( 'permalink-manager-alerts', array($this, 'default_alerts'), 1 );
113 }
114
115 /**
116 * Localize this plugin
117 */
118 function localize_me() {
119 load_plugin_textdomain( 'permalink-manager', false, PERMALINK_MANAGER_DIR );
120 }
121
122 /**
123 * Get options values & set global
124 */
125 public function get_options_and_globals() {
126 // 1. Globals with data stored in DB
127 global $permalink_manager_options, $permalink_manager_uris, $permalink_manager_permastructs;
128
129 $this->permalink_manager_options = $permalink_manager_options = apply_filters('permalink-manager-options', get_option('permalink-manager', array()));
130 $this->permalink_manager_uris = $permalink_manager_uris = apply_filters('permalink-manager-uris', get_option('permalink-manager-uris', array()));
131 $this->permalink_manager_permastructs = $permalink_manager_permastructs = apply_filters('permalink-manager-permastructs', get_option('permalink-manager-permastructs', array()));
132
133 // 2. Globals used to display additional content (eg. alerts)
134 global $permalink_manager_alerts, $permalink_manager_before_sections_html, $permalink_manager_after_sections_html;
135
136 $this->permalink_manager_alerts = $permalink_manager_alerts = apply_filters('permalink-manager-alerts', get_option('permalink-manager-alerts', array()));
137 $this->permalink_manager_before_sections_html = $permalink_manager_before_sections_html = apply_filters('permalink-manager-before-sections', '');
138 $this->permalink_manager_after_sections_html = $permalink_manager_after_sections_html = apply_filters('permalink-manager-after-sections', '');
139 }
140
141 /**
142 * Set the initial/default settings (including "Screen Options")
143 */
144 public function default_settings($settings) {
145 $all_taxonomies = Permalink_Manager_Helper_Functions::get_taxonomies_array();
146 $all_post_types = Permalink_Manager_Helper_Functions::get_post_types_array();
147
148 $default_settings = apply_filters('permalink-manager-default-options', array(
149 'screen-options' => array(
150 'per_page' => 20,
151 'post_statuses' => array('publish')
152 ),
153 'general' => array(
154 'force_custom_slugs' => 0,
155 'auto_update_uris' => 0,
156 'case_insensitive_permalinks' => 0,
157 'decode_uris' => 0
158 ),
159 'miscellaneous' => array(
160 'yoast_primary_term' => 1,
161 'redirect' => "302",
162 'canonical_redirect' => 1
163 )
164 ));
165
166 // Apply the default settings (if empty values) in all settings sections
167 foreach($default_settings as $group_name => $fields) {
168 foreach($fields as $field_name => $field) {
169 if(!isset($settings[$group_name][$field_name])) {
170 $settings[$group_name][$field_name] = $field;
171 }
172 }
173 }
174
175 return $settings;
176 }
177
178 /**
179 * Set the initial/default admin notices
180 */
181 public function default_alerts($alerts) {
182 $default_alerts = apply_filters('permalink-manager-default-alerts', array(
183 'july-2017' => array(
184 'txt' => sprintf(__("Need to change the permalinks for categories, tags, custom taxonomies or WooCommerce?<br /><strong>Buy Permalink Manager Pro <a href=\"%s\" target=\"_blank\">here</a> and save 20&#37; using \"SUMMER\" coupon code!</strong>", "permalink-manager"),
185 PERMALINK_MANAGER_WEBSITE),
186 'type' => 'notice-info',
187 'show' => 'pro_hide',
188 'plugin_only' => true,
189 'until' => '2017-09-01'
190 )
191 ));
192
193 // Apply the default settings (if empty values) in all settings sections
194 return $alerts + $default_alerts;
195 }
196
197 /**
198 * Used to optimize SQL queries amount instead of rewrite rules - the essential part of this plugin
199 */
200 function detect_post($query) {
201 global $wpdb, $permalink_manager_uris, $wp_filter, $permalink_manager_options;
202
203 // Check if any custom URI is used
204 if(!(is_array($permalink_manager_uris)) || empty($query)) return $query;
205
206 // Used in debug mode
207 $old_query = $query;
208
209 /**
210 * 1. Prepare URL and check if it is correct
211 */
212 $protocol = stripos($_SERVER['SERVER_PROTOCOL'], 'https') === true ? 'https://' : 'http://';
213 $request_url = "{$protocol}{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}";
214 $home_url = trim(rtrim(get_option('home'), '/'));
215 $home_url = ($protocol == 'https://') ? str_replace("http://", "https://", $home_url) : str_replace("https://", "http://", $home_url); // Adjust prefix (it should be the same in both request & home_url)
216
217 if (filter_var($request_url, FILTER_VALIDATE_URL)) {
218 /**
219 * 1. Process URL & find the URI
220 */
221 // Remove .html suffix and domain name from URL and query (URLs ended with .html will work as aliases)
222 $request_url = trim(str_replace($home_url, "", $request_url), "/");
223
224 // Remove querystrings from URI
225 $request_url = strtok($request_url, '?');
226
227 // Use default REGEX to detect post
228 preg_match("/^(.+?)\/?(page|feed|embed|attachment|track)?(?:\/([\d+]))?\/?$/i", $request_url, $regex_parts);
229 $uri_parts['lang'] = false;
230 $uri_parts['uri'] = (!empty($regex_parts[1])) ? $regex_parts[1] : "";
231 $uri_parts['endpoint'] = (!empty($regex_parts[2])) ? $regex_parts[2] : "";
232 $uri_parts['endpoint_value'] = (!empty($regex_parts[3])) ? $regex_parts[3] : "";
233
234 // Allow to filter the results by third-parties
235 $uri_parts = apply_filters('permalink-manager-detect-uri', $uri_parts, $request_url);
236
237 // Stop the function if $uri_parts is empty
238 if(empty($uri_parts)) return $query;
239
240 // Get the URI parts from REGEX parts
241 $lang = $uri_parts['lang'];
242 $uri = $uri_parts['uri'];
243 $endpoint = $uri_parts['endpoint'];
244 $endpoint_value = $uri_parts['endpoint_value'];
245
246 // Trim slashes
247 $uri = trim($uri, "/");
248
249 // Decode both Request URI & URIs array
250 $uri = urldecode($uri);
251 foreach ($permalink_manager_uris as $key => $value) {
252 $permalink_manager_uris[$key] = urldecode($value);
253 }
254
255 // Ignore URLs with no URI grabbed
256 if(empty($uri)) return $query;
257
258 /**
259 * 2. Check if found URI matches any element from custom uris array
260 */
261 $item_id = array_search($uri, $permalink_manager_uris);
262
263 // Check again in case someone added .html suffix to particular post (with .html suffix)
264 $item_id = (empty($item_id)) ? array_search("{$uri}.html", $permalink_manager_uris) : $item_id;
265
266 // Check again in case someone used post/tax IDs instead of slugs
267 $deep_detect_enabled = apply_filters('permalink-manager-deep-uri-detect', false);
268 if($deep_detect_enabled && (empty($item_id)) && isset($old_query['page'])) {
269 $item_id = array_search("{$uri}/{$endpoint_value}", $permalink_manager_uris);
270 $endpoint_value = $endpoint = "";
271 }
272
273 // Allow to filter the item_id by third-parties after initial detection
274 $item_id = apply_filters('permalink-manager-detected-initial-id', $item_id, $uri_parts, $request_url);
275
276 // Clear the original query before it is filtered
277 $query = ($item_id) ? array() : $query;
278
279 /**
280 * 3A. Custom URI assigned to taxonomy
281 */
282 if(strpos($item_id, 'tax-') !== false) {
283 // Remove the "tax-" prefix
284 $item_id = preg_replace("/[^0-9]/", "", $item_id);
285
286 // Filter detected post ID
287 $item_id = apply_filters('permalink-manager-detected-term-id', intval($item_id), $uri_parts, true);
288
289 // Get the variables to filter wp_query and double-check if tax exists
290 $term = get_term(intval($item_id));
291 if(empty($term->taxonomy)) { return $query; }
292
293 // Get some term data
294 $query_parameter = ($term->taxonomy == 'category') ? 'category_name' : $term->taxonomy;
295 $term_ancestors = get_ancestors($item_id, $term->taxonomy);
296 $final_uri = $term->slug;
297
298 // Fix for hierarchical CPT & pages
299 if(empty($term_ancestors)) {
300 foreach ($term_ancestors as $parent) {
301 $parent = get_term($parent, $term->taxonomy);
302 if(!empty($parent->slug)) {
303 $final_uri = $parent->slug . '/' . $final_uri;
304 }
305 }
306 }
307
308 // Make the redirects more clever - see redirect_to_new_uri() method
309 $query['do_not_redirect'] = 1;
310 $query[$query_parameter] = $final_uri;
311 }
312 /**
313 * 3B. Custom URI assigned to post/page/cpt item
314 */
315 else if(isset($item_id) && is_numeric($item_id)) {
316 // Fix for revisions
317 $is_revision = wp_is_post_revision($item_id);
318 $item_id = ($is_revision) ? $is_revision : $item_id;
319
320 // Filter detected post ID
321 $item_id = apply_filters('permalink-manager-detected-post-id', $item_id, $uri_parts);
322
323 $post_to_load = get_post($item_id);
324 $final_uri = $post_to_load->post_name;
325 $post_type = $post_to_load->post_type;
326
327 // Fix for hierarchical CPT & pages
328 if(!(empty($post_to_load->ancestors))) {
329 foreach ($post_to_load->ancestors as $parent) {
330 $parent = get_post( $parent );
331 if($parent && $parent->post_name) {
332 $final_uri = $parent->post_name . '/' . $final_uri;
333 }
334 }
335 }
336
337 // Alter query parameters
338 if($post_to_load->post_type == 'page') {
339 $query['pagename'] = $final_uri;
340 } else if($post_to_load->post_type == 'post') {
341 $query['name'] = $final_uri;
342 } else if($post_to_load->post_type == 'attachment') {
343 $query['attachment'] = $final_uri;
344 } else {
345 $query['name'] = $final_uri;
346 $query['post_type'] = $post_type;
347 $query[$post_type] = $final_uri;
348 }
349
350 // Make the redirects more clever - see redirect_to_new_uri() method
351 $query['do_not_redirect'] = 1;
352 }
353
354 /**
355 * 2C. Endpoints
356 */
357 if($item_id && !(empty($endpoint_value))) {
358 $endpoint = ($endpoint) ? str_replace(array('page', 'trackback'), array('paged', 'tb'), $endpoint) : "page";
359 $query[$endpoint] = $endpoint_value;
360 }
361
362 }
363
364 // Debug mode
365 if(isset($_REQUEST['debug_url'])) {
366 $debug_info['old_query_vars'] = $old_query;
367 $debug_info['new_query_vars'] = $query;
368
369 $debug_txt = json_encode($debug_info);
370 $debug_txt = "<textarea style=\"width:100%;height:300px\">{$debug_txt}</textarea>";
371 wp_die($debug_txt);
372 }
373
374 return $query;
375 }
376
377 function redirect_to_new_uri() {
378 global $wp_query, $permalink_manager_uris, $permalink_manager_options;
379
380 // Sometimes $wp_query indicates the wrong object if requested directly
381 $queried_object = get_queried_object();
382
383 if(!empty($permalink_manager_options['miscellaneous']['redirect']) && !empty($queried_object)) {
384
385 // Affect only posts with custom URI and old URIs
386 if(!empty($queried_object->ID) && isset($permalink_manager_uris[$queried_object->ID]) && empty($wp_query->query['do_not_redirect']) && empty($wp_query->query['preview'])) {
387 // Ignore posts with specific statuses
388 if(!(empty($queried_object->post_status)) && in_array($queried_object->post_status, array('draft', 'pending', 'auto-draft', 'future'))) {
389 return '';
390 }
391
392 // Get the real URL
393 $correct_permalink = get_permalink($queried_object->ID);
394 }
395 // Affect only terms with custom URI and old URIs
396 else if(!empty($queried_object->term_id) && isset($permalink_manager_uris["tax-{$queried_object->term_id}"]) && empty($wp_query->query['do_not_redirect'])) {
397 // Get the real URL
398 $correct_permalink = get_term_link($queried_object->term_id, $queried_object->taxonomy);
399 }
400
401 // Get the redirection mode
402 $redirect_mode = $permalink_manager_options['miscellaneous']['redirect'];
403
404 // Ignore default URIs (or do nothing if redirects are disabled)
405 if(!empty($correct_permalink) && !empty($redirect_mode)) {
406 wp_safe_redirect($correct_permalink, $redirect_mode);
407 exit();
408 }
409 }
410 }
411
412 function disable_canonical_redirect() {
413 global $permalink_manager_options, $wp_filter;
414 if(!($permalink_manager_options['miscellaneous']['canonical_redirect'])) {
415 remove_action('template_redirect', 'redirect_canonical');
416 add_filter('wpml_is_redirected', '__return_false', 99, 2);
417 }
418 }
419
420 function decode_uris_array($uris) {
421 if(!is_array($uris)) { return $uris; }
422
423 foreach ($uris as $key => $value) {
424 if(preg_match('/[^\x20-\x7f]/', $value)) {
425 $uris[$key] = implode('/', array_map('rawurlencode', explode('/', $value)));
426 }
427 }
428 return $uris;
429 }
430
431 /**
432 * Temporary hook
433 */
434 function legacy_support() {
435 global $permalink_manager_permastructs, $permalink_manager_options;
436
437 if(isset($permalink_manager_options['base-editor'])) {
438 $new_options['post_types'] = $permalink_manager_options['base-editor'];
439 update_option('permalink-manager-permastructs', $new_options);
440 }
441 else if(empty($permalink_manager_permastructs['post_types']) && count($permalink_manager_permastructs) > 0) {
442 $new_options['post_types'] = $permalink_manager_permastructs;
443 update_option('permalink-manager-permastructs', $new_options);
444 }
445 }
446
447 /**
448 * Update check
449 */
450 public function check_for_updates() {
451 global $permalink_manager_options;
452
453 if(defined('PERMALINK_MANAGER_PRO')) {
454 // Get the licence key
455 $license_key = (!empty($permalink_manager_options['miscellaneous']['license_key'])) ? $permalink_manager_options['miscellaneous']['license_key'] : "";
456
457 // Load Plugin Update Checker by YahnisElsts
458 require_once PERMALINK_MANAGER_DIR . '/includes/ext/plugin-update-checker/plugin-update-checker.php';
459
460 $UpdateChecker = Puc_v4_Factory::buildUpdateChecker(
461 "https://updates.permalinkmanager.pro/?action=get_metadata&slug=permalink-manager-pro&license_key={$license_key}",
462 __FILE__,
463 "permalink-manager-pro"
464 );
465
466 $file = PERMALINK_MANAGER_BASENAME;
467 }
468 }
469
470 }
471
472 /**
473 * Begins execution of the plugin.
474 */
475 function run_permalink_manager() {
476 $Permalink_Manager_Class = new Permalink_Manager_Class();
477 }
478 run_permalink_manager();
479