PluginProbe ʕ •ᴥ•ʔ
Permalink Manager Lite / 2.5.4
Permalink Manager Lite v2.5.4
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 3 days ago languages 3 days ago out 3 days ago LICENSE.txt 1 year ago README.txt 1 day ago permalink-manager.php 3 days ago
permalink-manager.php
400 lines
1 <?php
2
3 /**
4 * Plugin Name: Permalink Manager Lite
5 * Plugin URI: https://permalinkmanager.pro?utm_source=plugin
6 * Description: Advanced plugin that allows to set up custom permalinks (bulk editors included), slugs and permastructures (WooCommerce compatible).
7 * Version: 2.5.4
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 * WC requires at least: 3.0.0
15 * WC tested up to: 10.9.1
16 */
17
18 // If this file is called directly or plugin is already defined, abort
19 if ( ! defined( 'WPINC' ) ) {
20 die;
21 }
22
23 if ( ! class_exists( 'Permalink_Manager_Class' ) ) {
24
25 // Define the directories used to load plugin files.
26 define( 'PERMALINK_MANAGER_PLUGIN_NAME', 'Permalink Manager' );
27 define( 'PERMALINK_MANAGER_PLUGIN_SLUG', 'permalink-manager' );
28 define( 'PERMALINK_MANAGER_VERSION', '2.5.4' );
29 define( 'PERMALINK_MANAGER_FILE', __FILE__ );
30 define( 'PERMALINK_MANAGER_DIR', untrailingslashit( dirname( __FILE__ ) ) );
31 define( 'PERMALINK_MANAGER_BASENAME', plugin_basename( __FILE__ ) );
32 define( 'PERMALINK_MANAGER_URL', untrailingslashit( plugins_url( '', __FILE__ ) ) );
33 define( 'PERMALINK_MANAGER_WEBSITE', 'https://permalinkmanager.pro?utm_source=plugin' );
34 define( 'PERMALINK_MANAGER_PROMO', 'https://permalinkmanager.pro/features/?utm_source=plugin' );
35 define( 'PERMALINK_MANAGER_DOCS', 'https://permalinkmanager.pro/get-started/?utm_source=plugin' );
36
37 /**
38 * The base class responsible for loading the plugin data as well as any plugin subclasses and additional functions
39 */
40 class Permalink_Manager_Class {
41 public $permalink_manager_options;
42 public $functions;
43
44 /**
45 * Get options from DB, load subclasses & hooks
46 */
47 public function __construct() {
48 $this->include_subclasses();
49 $this->register_init_hooks();
50 }
51
52 /**
53 * Include back-end classes and set their instances
54 */
55 function include_subclasses() {
56 // WP_List_Table needed for post types & taxonomies editors
57 if ( ! class_exists( 'WP_List_Table' ) ) {
58 require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
59 }
60
61 $classes = array(
62 'core' => array(
63 'helper-functions' => 'Permalink_Manager_Helper_Functions',
64 'uri-functions' => 'Permalink_Manager_URI_Functions',
65 'uri-functions-post' => 'Permalink_Manager_URI_Functions_Post',
66 'uri-functions-tax' => 'Permalink_Manager_URI_Functions_Tax',
67 'admin-functions' => 'Permalink_Manager_Admin_Functions',
68 'actions' => 'Permalink_Manager_Actions',
69 'core-functions' => 'Permalink_Manager_Core_Functions',
70 'permastructures-functions' => 'Permalink_Manager_Permastructure_Functions',
71 'gutenberg' => 'Permalink_Manager_Gutenberg',
72 'debug' => 'Permalink_Manager_Debug_Functions',
73 'pro-license' => 'Permalink_Manager_Pro_License',
74 'pro-functions' => 'Permalink_Manager_Pro_Functions'
75 ),
76 'integrations' => array(
77 'third-parties' => 'Permalink_Manager_Third_Parties',
78 'woocommerce' => 'Permalink_Manager_WooCommerce',
79 'seo-plugins' => 'Permalink_Manager_SEO_Plugins',
80 'language-plugins' => 'Permalink_Manager_Language_Plugins'
81 ),
82 'views' => array(
83 'ui-elements' => 'Permalink_Manager_UI_Elements',
84 'uri-editor' => 'Permalink_Manager_URI_Editor',
85 'tools' => 'Permalink_Manager_Tools',
86 'permastructures' => 'Permalink_Manager_Permastructs',
87 'settings' => 'Permalink_Manager_Settings',
88 'debug' => 'Permalink_Manager_Debug',
89 'pro-addons' => 'Permalink_Manager_Pro_Addons',
90 'help' => 'Permalink_Manager_Help',
91 'setup-wizard' => 'Permalink_Manager_Setup_Wizard',
92 'uri-editor-tax' => false,
93 'uri-editor-post' => false
94 )
95 );
96
97 // Load classes and set-up their instances
98 foreach ( $classes as $class_type => $classes_array ) {
99 foreach ( $classes_array as $class => $class_name ) {
100 $filename = PERMALINK_MANAGER_DIR . "/includes/{$class_type}/permalink-manager-{$class}.php";
101
102 if ( file_exists( $filename ) ) {
103 require_once $filename;
104 if ( $class_name ) {
105 $this->functions[ $class ] = new $class_name();
106 }
107 }
108 }
109 }
110 }
111
112 /**
113 * Register general hooks
114 */
115 public function register_init_hooks() {
116 // Localize plugin
117 add_action( 'init', array( $this, 'localize_me' ), 1 );
118
119 // Support deprecated hooks
120 add_action( 'plugins_loaded', array( $this, 'deprecated_hooks' ), 9 );
121
122 // Deactivate free version if Permalink Manager Pro is activated
123 add_action( 'plugins_loaded', array( $this, 'is_pro_activated' ), 9 );
124
125 // Load globals & options
126 add_action( 'plugins_loaded', array( $this, 'get_options_and_globals' ), 9 );
127 add_action( 'init', array( $this, 'get_output_globals' ), 9 );
128
129 // Legacy support
130 add_action( 'init', array( $this, 'legacy_support' ), 2 );
131
132 // Default settings & alerts
133 add_filter( 'permalink_manager_options', array( $this, 'default_settings' ), 1 );
134 add_filter( 'permalink_manager_alerts', array( $this, 'default_alerts' ), 1 );
135 }
136
137 /**
138 * Localize this plugin
139 */
140 function localize_me() {
141 // phpcs:ignore PluginCheck.CodeAnalysis.DiscouragedFunctions.load_plugin_textdomainFound -- Make sure that the same textdomain is loaded for both Lite and Pro versions
142 load_plugin_textdomain( 'permalink-manager', false, basename( dirname( __FILE__ ) ) . "/languages" );
143 }
144
145 /**
146 * Get options values & set global variables
147 */
148 public function get_options_and_globals() {
149 // 1. Globals with data stored in DB
150 global $permalink_manager_options, $permalink_manager_uris, $permalink_manager_permastructs, $permalink_manager_redirects, $permalink_manager_external_redirects;
151
152 $permalink_manager_options = (array) apply_filters( 'permalink_manager_options', get_option( 'permalink-manager', array() ) );
153 $permalink_manager_uris = (array) apply_filters( 'permalink_manager_uris', get_option( 'permalink-manager-uris', array() ) );
154 $permalink_manager_permastructs = (array) apply_filters( 'permalink_manager_permastructs', get_option( 'permalink-manager-permastructs', array() ) );
155 $permalink_manager_redirects = (array) apply_filters( 'permalink_manager_redirects', get_option( 'permalink-manager-redirects', array() ) );
156 $permalink_manager_external_redirects = (array) apply_filters( 'permalink_manager_external_redirects', get_option( 'permalink-manager-external-redirects', array() ) );
157 }
158
159 /**
160 * Get global variables
161 */
162 public function get_output_globals() {
163 // 2. Globals used to display additional content (e.g. alerts)
164 global $permalink_manager_alerts, $permalink_manager_before_sections_html, $permalink_manager_after_sections_html;
165
166 $permalink_manager_alerts = apply_filters( 'permalink_manager_alerts', array() );
167 $permalink_manager_before_sections_html = apply_filters( 'permalink_manager_before_sections', '' );
168 $permalink_manager_after_sections_html = apply_filters( 'permalink_manager_after_sections', '' );
169 }
170
171 /**
172 * Set the initial/default settings (including "Screen Options")
173 *
174 * @param array $settings
175 *
176 * @return array
177 */
178 public function default_settings( $settings ) {
179 $default_settings = apply_filters( 'permalink_manager_default_options', array(
180 'screen-options' => array(
181 'per_page' => 20,
182 'post_statuses' => array( 'publish' ),
183 'group' => false
184 ),
185 'general' => array(
186 'auto_update_uris' => 0,
187 'show_native_slug_field' => 0,
188 'pagination_redirect' => 0,
189 'sslwww_redirect' => 1,
190 'canonical_redirect' => 1,
191 'old_slug_redirect' => 0,
192 'setup_redirects' => 0,
193 'redirect' => '301',
194 'extra_redirects' => 1,
195 'copy_query_redirect' => 1,
196 'trailing_slashes' => 0,
197 'trailing_slash_redirect' => 1,
198 'auto_fix_duplicates' => 0,
199 'fix_language_mismatch' => 0,
200 'wpml_support' => 1,
201 'wpml_translate_mode' => 0,
202 'pmxi_support' => 1,
203 'um_support' => 1,
204 'yoast_breadcrumbs' => 0,
205 'rankmath_redirect' => 1,
206 'primary_category' => 1,
207 'force_custom_slugs' => 0,
208 'disable_slug_sanitization' => 0,
209 'keep_accents' => 0,
210 'partial_disable' => array(
211 'post_types' => array( 'attachment', 'tribe_events', 'e-landing-page' )
212 ),
213 'partial_disable_strict' => 1,
214 'ignore_drafts' => 1,
215 'edit_uris_cap' => 'publish_posts',
216 'force_unique_uris' => 0,
217 'debug_mode' => 0
218 ),
219 'licence' => array()
220 ) );
221
222 // Check if settings array is empty
223 $settings_empty = empty( $settings );
224
225 // Apply the default settings (if empty values) in all settings sections
226 foreach ( $default_settings as $group_name => $fields ) {
227 foreach ( $fields as $field_name => $field ) {
228 if ( $settings_empty || ( ! isset( $settings[ $group_name ][ $field_name ] ) && strpos( $field_name, 'partial_disable' ) === false ) ) {
229 $settings[ $group_name ][ $field_name ] = $field;
230 }
231 }
232 }
233
234 return $settings;
235 }
236
237 /**
238 * Set the initial/default admin notices
239 *
240 * @param array $alerts
241 *
242 * @return array
243 */
244 public function default_alerts( $alerts ) {
245 $default_alerts = apply_filters( 'permalink_manager_default_alerts', array(
246 'summer-promo' => array(
247 'txt' => sprintf( __( "<strong>Extra Discount</strong>: Upgrade to Permalink Manager Pro for custom taxonomy and WooCommerce support, custom fields in permalinks, and priority email support.<br /><a href=\"%s\" target=\"_blank\">Upgrade today and save 40%% with code \"MAY26\"</a>.", "permalink-manager" ), PERMALINK_MANAGER_WEBSITE ),
248 'type' => 'notice-info',
249 'show' => 'pro_hide',
250 'plugin_only' => false,
251 'until' => '2026-05-15'
252 )
253 ) );
254
255 // Apply the default settings (if empty values) in all settings sections
256 return (array) $alerts + (array) $default_alerts;
257 }
258
259 /**
260 * Make sure that the Permalink Manager options stored in DB match the new structure
261 */
262 function legacy_support() {
263 global $permalink_manager_permastructs, $permalink_manager_options;
264
265 if ( isset( $permalink_manager_options['base-editor'] ) ) {
266 $new_options['post_types'] = $permalink_manager_options['base-editor'];
267 update_option( 'permalink-manager-permastructs', $new_options );
268 } else if ( empty( $permalink_manager_permastructs['post_types'] ) && empty( $permalink_manager_permastructs['taxonomies'] ) && count( $permalink_manager_permastructs ) > 0 ) {
269 $new_options['post_types'] = $permalink_manager_permastructs;
270 update_option( 'permalink-manager-permastructs', $new_options );
271 }
272
273 // Separate "Trailing slashes" & "Trailing slashes redirect" setting fields
274 if ( ! empty( $permalink_manager_options['general']['trailing_slashes'] ) && $permalink_manager_options['general']['trailing_slashes'] >= 10 ) {
275 $permalink_manager_unfiltered_options = ( ! empty( $permalink_manager_unfiltered_options ) ) ? $permalink_manager_unfiltered_options : $permalink_manager_options;
276
277 $permalink_manager_unfiltered_options['general']['trailing_slashes_redirect'] = 1;
278 $permalink_manager_unfiltered_options['general']['trailing_slashes'] = ( $permalink_manager_options['general']['trailing_slashes'] == 10 ) ? 1 : 2;
279 }
280
281 // Save the settings in database
282 if ( ! empty( $permalink_manager_unfiltered_options ) ) {
283 update_option( 'permalink-manager', $permalink_manager_unfiltered_options );
284 }
285
286 // Remove obsolete 'permalink-manager-alerts' from wp_options table
287 if ( get_option( 'permalink-manager-alerts' ) ) {
288 delete_option( 'permalink-manager-alerts' );
289 }
290 }
291
292 /**
293 * Return the array of deprecated hooks
294 *
295 * @return array
296 */
297 function deprecated_hooks_list() {
298 return array(
299 'permalink_manager_default_options' => 'permalink-manager-default-options',
300 'permalink_manager_options' => 'permalink-manager-options',
301 'permalink_manager_uris' => 'permalink-manager-uris',
302 'permalink_manager_redirects' => 'permalink-manager-redirects',
303 'permalink_manager_external_redirects' => 'permalink-manager-external-redirects',
304 'permalink_manager_permastructs' => 'permalink-manager-permastructs',
305
306 'permalink_manager_alerts' => 'permalink-manager-alerts',
307 'permalink_manager_before_sections' => 'permalink-manager-before-sections',
308 'permalink_manager_sections' => 'permalink-manager-sections',
309 'permalink_manager_after_sections' => 'permalink-manager-after-sections',
310
311 'permalink_manager_field_args' => 'permalink-manager-field-args',
312 'permalink_manager_field_output' => 'permalink-manager-field-output',
313
314 'permalink_manager_deep_uri_detect' => 'permalink-manager-deep-uri-detect',
315 'permalink_manager_detect_uri' => 'permalink-manager-detect-uri',
316 'permalink_manager_detected_element_id' => 'permalink-manager-detected-initial-id',
317 'permalink_manager_detected_term_id' => 'permalink-manager-detected-term-id',
318 'permalink_manager_detected_post_id' => 'permalink-manager-detected-post-id',
319
320 'permalink_manager_primary_term' => 'permalink-manager-primary-term',
321 'permalink_manager_disabled_post_types' => 'permalink-manager-disabled-post-types',
322 'permalink_manager_disabled_taxonomies' => 'permalink-manager-disabled-taxonomies',
323 'permalink_manager_endpoints' => 'permalink-manager-endpoints',
324 'permalink_manager_filter_permalink_base' => 'permalink_manager-filter-permalink-base',
325 'permalink_manager_force_lowercase_uris' => 'permalink-manager-force-lowercase-uris',
326
327 'permalink_manager_uri_editor_extra_info' => 'permalink-manager-uri-editor-extra-info',
328 'permalink_manager_debug_fields' => 'permalink-manager-debug-fields',
329 'permalink_manager_permastructs_fields' => 'permalink-manager-permastructs-fields',
330 'permalink_manager_settings_fields' => 'permalink-manager-settings-fields',
331 'permalink_manager_tools_fields' => 'permalink-manager-tools-fields',
332
333 'permalink_manager_uri_editor_columns' => 'permalink-manager-uri-editor-columns',
334 'permalink_manager_uri_editor_column_content' => 'permalink-manager-uri-editor-column-content',
335
336 'permalink_manager_redirect_shop_archive' => 'permalink-manager-redirect-shop-archive'
337 );
338 }
339
340 /**
341 * Map the deprecated hooks to their relevant equivalents.
342 */
343 function deprecated_hooks() {
344 $deprecated_filters = $this->deprecated_hooks_list();
345 foreach ( $deprecated_filters as $new => $old ) {
346 add_filter( $new, array( $this, 'deprecated_hooks_mapping' ), - 1000, 8 );
347 }
348 }
349
350 /**
351 * Apply the deprecated filters to the relevant hooks
352 *
353 * @param mixed $data
354 *
355 * @return mixed
356 */
357 function deprecated_hooks_mapping( $data ) {
358 $deprecated_filters = $this->deprecated_hooks_list();
359 $filter = current_filter();
360
361 if ( isset( $deprecated_filters[ $filter ] ) ) {
362 if ( has_filter( $deprecated_filters[ $filter ] ) ) {
363 do_action( 'deprecated_function_run', $deprecated_filters[ $filter ], $filter, '2.4.3' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Use built-in mechanism for flagging
364
365 $args = func_get_args();
366 $data = apply_filters_ref_array( $deprecated_filters[ $filter ], $args ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound
367 }
368 }
369
370 return $data;
371 }
372
373 /**
374 * Deactivate Permalink Manager Lite if Permalink Manager Pro is enabled
375 */
376 function is_pro_activated() {
377 if ( function_exists( 'is_plugin_active' ) && is_plugin_active( 'permalink-manager/permalink-manager.php' ) && is_plugin_active( 'permalink-manager-pro/permalink-manager.php' ) ) {
378 deactivate_plugins( 'permalink-manager/permalink-manager.php' );
379 }
380 }
381
382 }
383
384 /**
385 * Begins execution of the plugin
386 */
387 function permalink_manager_run() {
388 global $permalink_manager;
389
390 // Do not run when Elementor is opened
391 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- No data is processed here
392 if ( ( ! empty( $_REQUEST['action'] ) && is_string( $_REQUEST['action'] ) && strpos( $_REQUEST['action'], 'elementor' ) !== false ) || isset( $_REQUEST['elementor-preview'] ) || isset( $_REQUEST['disable-pm'] ) ) {
393 return;
394 }
395
396 $permalink_manager = new Permalink_Manager_Class();
397 }
398
399 permalink_manager_run();
400 }