PluginProbe ʕ •ᴥ•ʔ
Permalink Manager Lite / 2.5.5
Permalink Manager Lite v2.5.5
2.6.0 2.5.5 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 1 month ago languages 1 month ago out 1 month ago LICENSE.txt 1 year ago README.txt 1 month ago permalink-manager.php 1 month 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.5
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: 11.0.0
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.5' );
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' );
34
35 /**
36 * The base class responsible for loading the plugin data as well as any plugin subclasses and additional functions
37 */
38 class Permalink_Manager_Class {
39 public $permalink_manager_options;
40 public $functions;
41
42 /**
43 * Get options from DB, load subclasses & hooks
44 */
45 public function __construct() {
46 $this->include_subclasses();
47 $this->register_init_hooks();
48 }
49
50 /**
51 * Include back-end classes and set their instances
52 */
53 function include_subclasses() {
54 // WP_List_Table needed for post types & taxonomies editors
55 if ( ! class_exists( 'WP_List_Table' ) ) {
56 require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
57 }
58
59 $classes = array(
60 'core' => array(
61 'helper-functions' => 'Permalink_Manager_Helper_Functions',
62 'uri-functions' => 'Permalink_Manager_URI_Functions',
63 'uri-functions-post' => 'Permalink_Manager_URI_Functions_Post',
64 'uri-functions-tax' => 'Permalink_Manager_URI_Functions_Tax',
65 'admin-functions' => 'Permalink_Manager_Admin_Functions',
66 'actions' => 'Permalink_Manager_Actions',
67 'core-functions' => 'Permalink_Manager_Core_Functions',
68 'permastructures-functions' => 'Permalink_Manager_Permastructure_Functions',
69 'gutenberg' => 'Permalink_Manager_Gutenberg',
70 'debug' => 'Permalink_Manager_Debug_Functions',
71 'pro-license' => 'Permalink_Manager_Pro_License',
72 'pro-functions' => 'Permalink_Manager_Pro_Functions'
73 ),
74 'integrations' => array(
75 'third-parties' => 'Permalink_Manager_Third_Parties',
76 'woocommerce' => 'Permalink_Manager_WooCommerce',
77 'seo-plugins' => 'Permalink_Manager_SEO_Plugins',
78 'language-plugins' => 'Permalink_Manager_Language_Plugins'
79 ),
80 'views' => array(
81 'ui-elements' => 'Permalink_Manager_UI_Elements',
82 'uri-editor' => 'Permalink_Manager_URI_Editor',
83 'tools' => 'Permalink_Manager_Tools',
84 'permastructures' => 'Permalink_Manager_Permastructs',
85 'settings' => 'Permalink_Manager_Settings',
86 'debug' => 'Permalink_Manager_Debug',
87 'pro-addons' => 'Permalink_Manager_Pro_Addons',
88 'help' => 'Permalink_Manager_Help',
89 'setup-wizard' => 'Permalink_Manager_Setup_Wizard',
90 'uri-editor-tax' => false,
91 'uri-editor-post' => false
92 )
93 );
94
95 // Load classes and set-up their instances
96 foreach ( $classes as $class_type => $classes_array ) {
97 foreach ( $classes_array as $class => $class_name ) {
98 $filename = PERMALINK_MANAGER_DIR . "/includes/{$class_type}/permalink-manager-{$class}.php";
99
100 if ( file_exists( $filename ) ) {
101 require_once $filename;
102 if ( $class_name ) {
103 $this->functions[ $class ] = new $class_name();
104 }
105 }
106 }
107 }
108 }
109
110 /**
111 * Register general hooks
112 */
113 public function register_init_hooks() {
114 // Localize plugin
115 add_action( 'init', array( $this, 'localize_me' ), 1 );
116
117 // Support deprecated hooks
118 add_action( 'plugins_loaded', array( $this, 'deprecated_hooks' ), 9 );
119
120 // Deactivate free version if Permalink Manager Pro is activated
121 add_action( 'plugins_loaded', array( $this, 'is_pro_activated' ), 9 );
122
123 // Load globals & options
124 add_action( 'plugins_loaded', array( $this, 'get_options_and_globals' ), 9 );
125 add_action( 'init', array( $this, 'get_output_globals' ), 9 );
126
127 // Legacy support
128 add_action( 'init', array( $this, 'legacy_support' ), 2 );
129
130 // Default settings & alerts
131 add_filter( 'permalink_manager_options', array( $this, 'default_settings' ), 1 );
132 add_filter( 'permalink_manager_alerts', array( $this, 'default_alerts' ), 1 );
133 }
134
135 /**
136 * Localize this plugin
137 */
138 function localize_me() {
139 // phpcs:ignore PluginCheck.CodeAnalysis.DiscouragedFunctions.load_plugin_textdomainFound -- Make sure that the same textdomain is loaded for both Lite and Pro versions
140 load_plugin_textdomain( 'permalink-manager', false, basename( dirname( __FILE__ ) ) . "/languages" );
141 }
142
143 /**
144 * Get options values & set global variables
145 */
146 public function get_options_and_globals() {
147 // 1. Globals with data stored in DB
148 global $permalink_manager_options, $permalink_manager_uris, $permalink_manager_permastructs, $permalink_manager_redirects, $permalink_manager_external_redirects;
149
150 $permalink_manager_options = (array) apply_filters( 'permalink_manager_options', get_option( 'permalink-manager', array() ) );
151 $permalink_manager_uris = (array) apply_filters( 'permalink_manager_uris', get_option( 'permalink-manager-uris', array() ) );
152 $permalink_manager_permastructs = (array) apply_filters( 'permalink_manager_permastructs', get_option( 'permalink-manager-permastructs', array() ) );
153 $permalink_manager_redirects = (array) apply_filters( 'permalink_manager_redirects', get_option( 'permalink-manager-redirects', array() ) );
154 $permalink_manager_external_redirects = (array) apply_filters( 'permalink_manager_external_redirects', get_option( 'permalink-manager-external-redirects', array() ) );
155 }
156
157 /**
158 * Get global variables
159 */
160 public function get_output_globals() {
161 // 2. Globals used to display additional content (e.g. alerts)
162 global $permalink_manager_alerts, $permalink_manager_before_sections_html, $permalink_manager_after_sections_html;
163
164 $permalink_manager_alerts = apply_filters( 'permalink_manager_alerts', array() );
165 $permalink_manager_before_sections_html = apply_filters( 'permalink_manager_before_sections', '' );
166 $permalink_manager_after_sections_html = apply_filters( 'permalink_manager_after_sections', '' );
167 }
168
169 /**
170 * Set the initial/default settings (including "Screen Options")
171 *
172 * @param array $settings
173 *
174 * @return array
175 */
176 public function default_settings( $settings ) {
177 $default_settings = apply_filters( 'permalink_manager_default_options', array(
178 'screen-options' => array(
179 'per_page' => 20,
180 'post_statuses' => array( 'publish' ),
181 'group' => false
182 ),
183 'general' => array(
184 'auto_update_uris' => 0,
185 'show_native_slug_field' => 0,
186 'pagination_redirect' => 0,
187 'sslwww_redirect' => 1,
188 'canonical_redirect' => 1,
189 'old_slug_redirect' => 0,
190 'setup_redirects' => 0,
191 'redirect' => '301',
192 'extra_redirects' => 1,
193 'copy_query_redirect' => 1,
194 'trailing_slashes' => 0,
195 'trailing_slash_redirect' => 1,
196 'auto_fix_duplicates' => 0,
197 'fix_language_mismatch' => 0,
198 'wpml_support' => 1,
199 'wpml_translate_mode' => 0,
200 'pmxi_support' => 1,
201 'um_support' => 1,
202 'yoast_breadcrumbs' => 0,
203 'rankmath_redirect' => 1,
204 'primary_category' => 1,
205 'force_custom_slugs' => 0,
206 'disable_slug_sanitization' => 0,
207 'keep_accents' => 0,
208 'partial_disable' => array(
209 'post_types' => array( 'attachment', 'tribe_events', 'e-landing-page' )
210 ),
211 'partial_disable_strict' => 1,
212 'ignore_drafts' => 1,
213 'edit_uris_cap' => 'publish_posts',
214 'force_unique_uris' => 0,
215 'debug_mode' => 0
216 ),
217 'licence' => array()
218 ) );
219
220 // Check if settings array is empty
221 $settings_empty = empty( $settings );
222
223 // Apply the default settings (if empty values) in all settings sections
224 foreach ( $default_settings as $group_name => $fields ) {
225 foreach ( $fields as $field_name => $field ) {
226 if ( $settings_empty || ( ! isset( $settings[ $group_name ][ $field_name ] ) && strpos( $field_name, 'partial_disable' ) === false ) ) {
227 $settings[ $group_name ][ $field_name ] = $field;
228 }
229 }
230 }
231
232 return $settings;
233 }
234
235 /**
236 * Set the initial/default admin notices
237 *
238 * @param array $alerts
239 *
240 * @return array
241 */
242 public function default_alerts( $alerts ) {
243 $website_url = Permalink_Manager_Admin_Functions::get_plugin_website_url( 'pricing' );
244
245 $default_alerts = apply_filters( 'permalink_manager_default_alerts', array(
246 'aug26-promo' => array(
247 'txt' => sprintf( "<strong>Save 30%% on Permalink Manager Pro</strong><br />Get custom taxonomy and WooCommerce support, custom fields in permalinks, and priority email support. <a href=\"%s\" target=\"_blank\">Upgrade today</a> and save 30%% with code <code>SUMMER26</code>.", $website_url ),
248 'type' => 'notice-info',
249 'show' => 'pro_hide',
250 'plugin_only' => false,
251 'until' => '2026-08-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 }