permalink-manager
Last commit date
includes
9 years ago
languages
9 years ago
out
9 years ago
LICENSE.txt
9 years ago
README.txt
9 years ago
permalink-manager.php
9 years ago
permalink-manager.php
424 lines
| 1 | <?php |
| 2 | |
| 3 | /** |
| 4 | * Plugin Name: Permalink Manager |
| 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.0 |
| 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.0' ); |
| 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 | 'uri-editor-tax' => false, |
| 71 | 'uri-editor-post' => false |
| 72 | ) |
| 73 | ); |
| 74 | |
| 75 | // Load classes and set-up their instances |
| 76 | foreach($classes as $class_type => $classes_array) { |
| 77 | foreach($classes_array as $class => $class_name) { |
| 78 | $filename = PERMALINK_MANAGER_DIR . "/includes/{$class_type}/permalink-manager-{$class}.php"; |
| 79 | |
| 80 | if(file_exists($filename)) { |
| 81 | require_once $filename; |
| 82 | if($class_name) { $this->functions[$class] = new $class_name(); } |
| 83 | } |
| 84 | } |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | /** |
| 89 | * Register general hooks |
| 90 | */ |
| 91 | public function register_init_hooks() { |
| 92 | // Localize plugin |
| 93 | add_action( 'plugins_loaded', array($this, 'localize_me'), 1 ); |
| 94 | |
| 95 | // Load options |
| 96 | add_action( 'init', array($this, 'get_options_and_globals'), 1 ); |
| 97 | |
| 98 | // Use the URIs set in this plugin + redirect from old URIs to new URIs + adjust canonical redirect settings |
| 99 | add_action( 'wp', array($this, 'disable_canonical_redirect'), 0, 1 ); |
| 100 | add_action( 'template_redirect', array($this, 'redirect_to_new_uri'), 999); |
| 101 | add_filter( 'request', array($this, 'detect_post'), 0, 1 ); |
| 102 | |
| 103 | // Legacy support |
| 104 | add_action( 'init', array($this, 'legacy_support'), 2 ); |
| 105 | |
| 106 | // Check for updates |
| 107 | // add_action( 'init', array($this, 'check_for_updates'), 999 ); |
| 108 | |
| 109 | // Default settings & alerts |
| 110 | add_filter( 'permalink-manager-options', array($this, 'default_settings'), 1 ); |
| 111 | add_filter( 'permalink-manager-alerts', array($this, 'default_alerts'), 1 ); |
| 112 | } |
| 113 | |
| 114 | /** |
| 115 | * Localize this plugin |
| 116 | */ |
| 117 | function localize_me() { |
| 118 | load_plugin_textdomain( 'permalink-manager', false, PERMALINK_MANAGER_DIR ); |
| 119 | } |
| 120 | |
| 121 | /** |
| 122 | * Get options values & set global |
| 123 | */ |
| 124 | public function get_options_and_globals() { |
| 125 | // 1. Globals with data stored in DB |
| 126 | global $permalink_manager_options, $permalink_manager_uris, $permalink_manager_permastructs; |
| 127 | |
| 128 | $this->permalink_manager_options = $permalink_manager_options = apply_filters('permalink-manager-options', get_option('permalink-manager', array())); |
| 129 | $this->permalink_manager_uris = $permalink_manager_uris = apply_filters('permalink-manager-uris', get_option('permalink-manager-uris', array())); |
| 130 | $this->permalink_manager_permastructs = $permalink_manager_permastructs = apply_filters('permalink-manager-permastructs', get_option('permalink-manager-permastructs', array())); |
| 131 | |
| 132 | // 2. Globals used to display additional content (eg. alerts) |
| 133 | global $permalink_manager_alerts, $permalink_manager_before_sections_html, $permalink_manager_after_sections_html; |
| 134 | |
| 135 | $this->permalink_manager_alerts = $permalink_manager_alerts = apply_filters('permalink-manager-alerts', get_option('permalink-manager-alerts', array())); |
| 136 | $this->permalink_manager_before_sections_html = $permalink_manager_before_sections_html = apply_filters('permalink-manager-before-sections', ''); |
| 137 | $this->permalink_manager_after_sections_html = $permalink_manager_after_sections_html = apply_filters('permalink-manager-after-sections', ''); |
| 138 | } |
| 139 | |
| 140 | /** |
| 141 | * Set the initial/default settings (including "Screen Options") |
| 142 | */ |
| 143 | public function default_settings($settings) { |
| 144 | $all_taxonomies = Permalink_Manager_Helper_Functions::get_taxonomies_array(); |
| 145 | $all_post_types = Permalink_Manager_Helper_Functions::get_post_types_array(); |
| 146 | |
| 147 | $default_settings = apply_filters('permalink-manager-default-options', array( |
| 148 | 'screen-options' => array( |
| 149 | 'per_page' => 20, |
| 150 | 'post_statuses' => array('publish') |
| 151 | ), |
| 152 | 'general' => array( |
| 153 | 'force_custom_slugs' => 0, |
| 154 | 'auto_update_uris' => 0, |
| 155 | ), |
| 156 | 'miscellaneous' => array( |
| 157 | 'yoast_primary_term' => 1, |
| 158 | 'redirect' => "302", |
| 159 | 'canonical_redirect' => 1, |
| 160 | ) |
| 161 | )); |
| 162 | |
| 163 | // Apply the default settings (if empty values) in all settings sections |
| 164 | return $settings + $default_settings; |
| 165 | } |
| 166 | |
| 167 | /** |
| 168 | * Set the initial/default admin notices |
| 169 | */ |
| 170 | public function default_alerts($alerts) { |
| 171 | $default_alerts = apply_filters('permalink-manager-default-alerts', array( |
| 172 | // 'pro' => array('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 enjoy the additional features!</strong>", "permalink-manager"), PERMALINK_MANAGER_WEBSITE), 'type' => 'notice-info', 'show' => 1) |
| 173 | )); |
| 174 | |
| 175 | // Apply the default settings (if empty values) in all settings sections |
| 176 | return $alerts + $default_alerts; |
| 177 | } |
| 178 | |
| 179 | /** |
| 180 | * Used to optimize SQL queries amount instead of rewrite rules - the essential part of this plugin |
| 181 | */ |
| 182 | function detect_post($query) { |
| 183 | global $wpdb, $permalink_manager_uris, $wp_filter; |
| 184 | |
| 185 | // Check if any custom URI is used |
| 186 | if(!(is_array($permalink_manager_uris))) return $query; |
| 187 | |
| 188 | // Used in debug mode |
| 189 | $old_query = $query; |
| 190 | |
| 191 | /** |
| 192 | * 1. Prepare URL and check if it is correct |
| 193 | */ |
| 194 | $protocol = stripos($_SERVER['SERVER_PROTOCOL'], 'https') === true ? 'https://' : 'http://'; |
| 195 | $request_url = "{$protocol}{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}"; |
| 196 | $home_url = trim(rtrim(get_option('home'), '/')); |
| 197 | $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) |
| 198 | |
| 199 | if (filter_var($request_url, FILTER_VALIDATE_URL)) { |
| 200 | /** |
| 201 | * 1. Process URL & find the URI |
| 202 | */ |
| 203 | // Remove .html suffix and domain name from URL and query (URLs ended with .html will work as aliases) |
| 204 | $request_url = trim(str_replace($home_url, "", $request_url), "/"); |
| 205 | |
| 206 | // Remove querystrings from URI |
| 207 | $request_url = strtok($request_url, '?'); |
| 208 | |
| 209 | // Use default REGEX to detect post |
| 210 | preg_match("/^(.+?)\/?(page|feed|embed|attachment|track)?(?:\/([\d+]))?\/?$/i", $request_url, $regex_parts); |
| 211 | $uri_parts['lang'] = false; |
| 212 | $uri_parts['uri'] = (!empty($regex_parts[1])) ? $regex_parts[1] : ""; |
| 213 | $uri_parts['endpoint'] = (!empty($regex_parts[2])) ? $regex_parts[2] : ""; |
| 214 | $uri_parts['endpoint_value'] = (!empty($regex_parts[3])) ? $regex_parts[3] : ""; |
| 215 | |
| 216 | // Allow to filter the results by third-parties |
| 217 | $uri_parts = apply_filters('permalink-manager-detect-uri', $uri_parts, $request_url); |
| 218 | |
| 219 | // Stop the function if $uri_parts is empty |
| 220 | if(empty($uri_parts)) return $query; |
| 221 | |
| 222 | // Get the URI parts from REGEX parts |
| 223 | $lang = $uri_parts['lang']; |
| 224 | $uri = $uri_parts['uri']; |
| 225 | $endpoint = $uri_parts['endpoint']; |
| 226 | $endpoint_value = $uri_parts['endpoint_value']; |
| 227 | |
| 228 | // Trim slashes |
| 229 | $uri = trim($uri, "/"); |
| 230 | |
| 231 | // Ignore URLs with no URI grabbed |
| 232 | if(empty($uri)) return $query; |
| 233 | |
| 234 | /** |
| 235 | * 2. Check if found URI matches any element from custom uris array |
| 236 | */ |
| 237 | $item_id = array_search($uri, $permalink_manager_uris); |
| 238 | |
| 239 | // Check again in case someone added .html suffix to particular post (with .html suffix) |
| 240 | $item_id = (empty($item_id)) ? array_search("{$uri}.html", $permalink_manager_uris) : $item_id; |
| 241 | |
| 242 | // Check again in case someone used post/tax IDs instead of slugs |
| 243 | $deep_detect_enabled = apply_filters('permalink-manager-deep-uri-detect', false); |
| 244 | if($deep_detect_enabled && (empty($item_id)) && isset($old_query['page'])) { |
| 245 | $item_id = array_search("{$uri}/{$endpoint_value}", $permalink_manager_uris); |
| 246 | $endpoint_value = $endpoint = ""; |
| 247 | } |
| 248 | |
| 249 | // Clear the original query before it is filtered |
| 250 | $query = ($item_id) ? array() : $query; |
| 251 | |
| 252 | /** |
| 253 | * 3A. Custom URI assigned to taxonomy |
| 254 | */ |
| 255 | if(strpos($item_id, 'tax-') !== false) { |
| 256 | // Remove the "tax-" prefix |
| 257 | $item_id = preg_replace("/[^0-9]/", "", $item_id); |
| 258 | |
| 259 | // Filter detected post ID |
| 260 | $item_id = apply_filters('permalink-manager-detected-term-id', $item_id, $uri_parts); |
| 261 | |
| 262 | // Get the variables to filter wp_query and double-check if tax exists |
| 263 | $term = get_term($item_id); |
| 264 | if(empty($term->taxonomy)) { return $query; } |
| 265 | |
| 266 | // Get some term data |
| 267 | $query_parameter = ($term->taxonomy == 'category') ? 'category_name' : $term->taxonomy; |
| 268 | $term_ancestors = get_ancestors($item_id, $term->taxonomy); |
| 269 | $final_uri = $term->slug; |
| 270 | |
| 271 | // Fix for hierarchical CPT & pages |
| 272 | if(empty($term_ancestors)) { |
| 273 | foreach ($term_ancestors as $parent) { |
| 274 | $parent = get_term($parent, $term->taxonomy); |
| 275 | if(!empty($parent->slug)) { |
| 276 | $final_uri = $parent->slug . '/' . $final_uri; |
| 277 | } |
| 278 | } |
| 279 | } |
| 280 | |
| 281 | // Alter query parameters |
| 282 | $query[$query_parameter] = $final_uri; |
| 283 | } |
| 284 | /** |
| 285 | * 3B. Custom URI assigned to post/page/cpt item |
| 286 | */ |
| 287 | else if(isset($item_id) && is_numeric($item_id)) { |
| 288 | // Fix for revisions |
| 289 | $is_revision = wp_is_post_revision($item_id); |
| 290 | $item_id = ($is_revision) ? $is_revision : $item_id; |
| 291 | |
| 292 | // Filter detected post ID |
| 293 | $item_id = apply_filters('permalink-manager-detected-post-id', $item_id, $uri_parts); |
| 294 | |
| 295 | $post_to_load = get_post($item_id); |
| 296 | $final_uri = $post_to_load->post_name; |
| 297 | $post_type = $post_to_load->post_type; |
| 298 | |
| 299 | // Fix for hierarchical CPT & pages |
| 300 | if(!(empty($post_to_load->ancestors))) { |
| 301 | foreach ($post_to_load->ancestors as $parent) { |
| 302 | $parent = get_post( $parent ); |
| 303 | if($parent && $parent->post_name) { |
| 304 | $final_uri = $parent->post_name . '/' . $final_uri; |
| 305 | } |
| 306 | } |
| 307 | } |
| 308 | |
| 309 | // Alter query parameters |
| 310 | if($post_to_load->post_type == 'page') { |
| 311 | $query['pagename'] = $final_uri; |
| 312 | } else if($post_to_load->post_type == 'post') { |
| 313 | $query['name'] = $final_uri; |
| 314 | } else { |
| 315 | $query['name'] = $final_uri; |
| 316 | $query['post_type'] = $post_type; |
| 317 | $query[$post_type] = $final_uri; |
| 318 | } |
| 319 | |
| 320 | // Make the redirects more clever - see redirect_to_new_uri() method |
| 321 | $query['do_not_redirect'] = 1; |
| 322 | } |
| 323 | |
| 324 | /** |
| 325 | * 2C. Endpoints |
| 326 | */ |
| 327 | if($item_id && !(empty($endpoint_value))) { |
| 328 | $endpoint = ($endpoint) ? str_replace(array('page', 'trackback'), array('paged', 'tb'), $endpoint) : "page"; |
| 329 | $query[$endpoint] = $endpoint_value; |
| 330 | } |
| 331 | |
| 332 | } |
| 333 | |
| 334 | // Debug mode |
| 335 | if(isset($_REQUEST['debug_url'])) { |
| 336 | $debug_info['old_query_vars'] = $old_query; |
| 337 | $debug_info['new_query_vars'] = $query; |
| 338 | |
| 339 | $debug_txt = json_encode($debug_info); |
| 340 | $debug_txt = "<textarea style=\"width:100%;height:300px\">{$debug_txt}</textarea>"; |
| 341 | wp_die($debug_txt); |
| 342 | } |
| 343 | |
| 344 | return $query; |
| 345 | } |
| 346 | |
| 347 | function redirect_to_new_uri() { |
| 348 | global $wp, $wp_query, $permalink_manager_uris, $permalink_manager_options; |
| 349 | |
| 350 | // Affect only posts with custom URI and old URIs |
| 351 | if(is_singular() && isset($permalink_manager_uris[$wp_query->queried_object_id]) && empty($wp_query->query['do_not_redirect']) && empty($wp_query->query['preview'])) { |
| 352 | // Ignore posts with specific statuses |
| 353 | if(!(empty($wp_query->queried_object->post_status)) && in_array($wp_query->queried_object->post_status, array('draft', 'pending', 'auto-draft', 'future'))) { |
| 354 | return ''; |
| 355 | } |
| 356 | |
| 357 | // Get the real URL |
| 358 | $correct_permalink = get_permalink($wp_query->queried_object_id); |
| 359 | } |
| 360 | |
| 361 | // Get the redirection mode |
| 362 | $redirect_mode = $permalink_manager_options['miscellaneous']['redirect']; |
| 363 | |
| 364 | // Ignore default URIs (or do nothing if redirects are disabled) |
| 365 | if(!empty($correct_permalink) && !empty($redirect_mode)) { |
| 366 | wp_safe_redirect($correct_permalink, $redirect_mode); |
| 367 | exit(); |
| 368 | } |
| 369 | } |
| 370 | |
| 371 | function disable_canonical_redirect() { |
| 372 | global $permalink_manager_options; |
| 373 | if(!($permalink_manager_options['miscellaneous']['canonical_redirect'])) { |
| 374 | remove_action('template_redirect', 'redirect_canonical'); |
| 375 | } |
| 376 | } |
| 377 | |
| 378 | /** |
| 379 | * Temporary hook |
| 380 | */ |
| 381 | function legacy_support() { |
| 382 | global $permalink_manager_permastructs, $permalink_manager_options; |
| 383 | |
| 384 | if(isset($permalink_manager_options['base-editor'])) { |
| 385 | $new_options['post_types'] = $permalink_manager_options['base-editor']; |
| 386 | update_option('permalink-manager-permastructs', $new_options); |
| 387 | } |
| 388 | else if(empty($permalink_manager_permastructs['post_types']) && count($permalink_manager_permastructs) > 0) { |
| 389 | $new_options['post_types'] = $permalink_manager_permastructs; |
| 390 | update_option('permalink-manager-permastructs', $new_options); |
| 391 | } |
| 392 | } |
| 393 | |
| 394 | /** |
| 395 | * Update check |
| 396 | */ |
| 397 | public function check_for_updates() { |
| 398 | global $permalink_manager_options; |
| 399 | |
| 400 | // Load Plugin Update Checker by YahnisElsts |
| 401 | require_once PERMALINK_MANAGER_DIR . '/includes/ext/plugin-update-checker/plugin-update-checker.php'; |
| 402 | |
| 403 | // Get the licence key |
| 404 | $license_key = (!empty($permalink_manager_options['miscellaneous']['license_key'])) ? $permalink_manager_options['miscellaneous']['license_key'] : ""; |
| 405 | |
| 406 | $UpdateChecker = Puc_v4_Factory::buildUpdateChecker( |
| 407 | "https://updates.permalinkmanager.pro/?action=get_metadata&slug=permalink-manager-pro&license_key={$license_key}", |
| 408 | __FILE__, |
| 409 | "permalink-manager-pro" |
| 410 | ); |
| 411 | |
| 412 | $file = PERMALINK_MANAGER_BASENAME; |
| 413 | } |
| 414 | |
| 415 | } |
| 416 | |
| 417 | /** |
| 418 | * Begins execution of the plugin. |
| 419 | */ |
| 420 | function run_permalink_manager() { |
| 421 | $Permalink_Manager_Class = new Permalink_Manager_Class(); |
| 422 | } |
| 423 | run_permalink_manager(); |
| 424 |