Permalink Manager Lite - Version 2.0.5.1

Version Description

  • Hotfix for REGEX rule
Download this release

Release Info

Developer mbis
Plugin Icon 128x128 Permalink Manager Lite
Version 2.0.5.1
Comparing to
See all releases

Code changes from version 2.0.4.3 to 2.0.5.1

README.txt CHANGED
@@ -3,12 +3,13 @@ Contributors: mbis
3
  Donate link: https://www.paypal.me/Bismit
4
  License: GPLv3
5
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
6
- Tags: urls, permalinks, slugs, custom url, custom permalinks, uris, url, slug, permalink
7
- Requires at least: 4.0
8
- Tested up to: 4.8
9
- Stable tag: 2.0.4.3
 
10
 
11
- Most advanced yet easy-to-use permalink plugin that helps to maintain & bulk change your URLs & slugs.
12
 
13
  == Description ==
14
 
@@ -97,9 +98,26 @@ A. Currently there is no 100% guarantee that Permalink Manager will work correct
97
 
98
  == Changelog ==
99
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  = 2.0.4.3 =
101
  * Hotfix for problem with custom URIs for new terms & posts
102
 
 
 
 
103
  = 2.0.4.1 =
104
  * Hotfix for Elementor and another visual editor plugins
105
  * Support for endpoints parsed as $_GET parameters
3
  Donate link: https://www.paypal.me/Bismit
4
  License: GPLv3
5
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
6
+ Tags: urls, permalinks, custom permalinks, url, permalink, woocommerce permalinks
7
+ Requires at least: 4.0
8
+ Requires PHP: 5.4
9
+ Tested up to: 4.9
10
+ Stable tag: 2.0.5.1
11
 
12
+ Advanced plugin that allows to set-up custom permalinks (bulk editors included), slugs and permastructures (WooCommerce compatible).
13
 
14
  == Description ==
15
 
98
 
99
  == Changelog ==
100
 
101
+ = 2.0.5.1 =
102
+ * Hotfix for REGEX rule
103
+
104
+ = 2.0.5 =
105
+ * Now, the duplicates and unused custom permalinks can be automatically removed
106
+ * Better support for endpoints
107
+ * "Disable slug appendix" field is no longer needed
108
+ * %{taxonomy}_flat% tag enhanced for post types permastructures
109
+ * Fix for WPML language prefixes in REGEX rule used to detect URIs
110
+ * Possibility to disable Permalink Manager functions for particular post types or taxonomies
111
+
112
+ = 2.0.5 =
113
+ * Hotfix for Yoast's SEO attachment redirect
114
+
115
  = 2.0.4.3 =
116
  * Hotfix for problem with custom URIs for new terms & posts
117
 
118
+ = 2.0.4.2 =
119
+ * Trailing slashes redirect adjustment
120
+
121
  = 2.0.4.1 =
122
  * Hotfix for Elementor and another visual editor plugins
123
  * Support for endpoints parsed as $_GET parameters
includes/core/permalink-manager-actions.php CHANGED
@@ -99,10 +99,10 @@ class Permalink_Manager_Actions extends Permalink_Manager_Class {
99
  if(isset($_GET['flush_sitemaps'])) {
100
  self::flush_sitemaps();
101
  } else if(isset($_GET['clear-permalink-manager-uris'])) {
102
- self::clear_uris();
103
  } else if(!empty($_REQUEST['remove-uri'])) {
104
  $uri_key = sanitize_text_field($_REQUEST['remove-uri']);
105
- self::remove_uri($uri_key);
106
  } else if(!empty($_POST['screen-options-apply'])) {
107
  self::save_screen_options();
108
  }
@@ -159,52 +159,142 @@ class Permalink_Manager_Actions extends Permalink_Manager_Class {
159
  }
160
 
161
  /**
162
- * Remove URI from options array after post is moved to the trash
163
- */
164
- public static function clear_uris() {
165
- global $permalink_manager_uris, $permalink_manager_before_sections_html, $wpdb;
166
 
 
167
  if(empty($permalink_manager_uris)) { return; }
168
 
 
 
 
 
169
  foreach($permalink_manager_uris as $element_id => $uri) {
170
- // Loop only through post URIs
171
- if(is_numeric($element_id)) {
172
- $post_status = get_post_status($element_id);
173
- if(in_array($post_status, array('auto-draft', 'trash', '')) || $post_status == false) {
174
- unset($permalink_manager_uris[$element_id]);
175
- }
176
- } else if(strpos($element_id, 'tax-') !== false) {
177
- $term_id = preg_replace("/[^0-9]/", "", $element_id);
178
- $term = $wpdb->get_row($wpdb->prepare("SELECT t.* FROM $wpdb->terms AS t WHERE t.term_id = %s LIMIT 1", $term_id));
179
 
180
- if(empty($term)) {
181
- // print_r('dupa');
182
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
  }
184
  }
185
 
186
- update_option('permalink-manager-uris', array_filter($permalink_manager_uris));
187
- $permalink_manager_before_sections_html .= Permalink_Manager_Admin_Functions::get_alert_message(__( 'URI array is cleared!', 'permalink-manager' ), 'updated');
 
 
 
 
 
188
  }
189
 
190
  /**
191
- * Remove URI from options array after post is moved to the trash
192
- */
193
- public static function remove_uri($uri_key) {
194
- global $permalink_manager_uris, $permalink_manager_before_sections_html;
195
 
196
- if(empty($permalink_manager_uris)) { return; }
 
 
 
 
 
 
 
 
 
 
 
 
197
 
198
- // Check if key exists
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
  if(isset($permalink_manager_uris[$uri_key])) {
200
  $uri = $permalink_manager_uris[$uri_key];
201
- unset($permalink_manager_uris[$uri_key]);
202
 
 
203
  update_option('permalink-manager-uris', $permalink_manager_uris);
204
 
205
  $permalink_manager_before_sections_html .= Permalink_Manager_Admin_Functions::get_alert_message(sprintf(__( 'URI "%s" was removed successfully!', 'permalink-manager' ), $uri), 'updated');
206
- } else {
207
- $permalink_manager_before_sections_html .= Permalink_Manager_Admin_Functions::get_alert_message(__( 'URI does not exist or was already removed!', 'permalink-manager' ), 'error');
 
 
 
 
 
 
 
 
 
 
 
 
208
  }
209
  }
210
 
99
  if(isset($_GET['flush_sitemaps'])) {
100
  self::flush_sitemaps();
101
  } else if(isset($_GET['clear-permalink-manager-uris'])) {
102
+ self::clear_all_uris();
103
  } else if(!empty($_REQUEST['remove-uri'])) {
104
  $uri_key = sanitize_text_field($_REQUEST['remove-uri']);
105
+ self::force_clear_single_element_uris_and_redirects($uri_key);
106
  } else if(!empty($_POST['screen-options-apply'])) {
107
  self::save_screen_options();
108
  }
159
  }
160
 
161
  /**
162
+ * Clear URIs
163
+ */
164
+ public static function clear_all_uris() {
165
+ global $permalink_manager_uris, $permalink_manager_redirects, $wpdb, $permalink_manager_before_sections_html;
166
 
167
+ // Check if array with custom URIs exists
168
  if(empty($permalink_manager_uris)) { return; }
169
 
170
+ // Count removed URIs & redirects
171
+ $removed_uris = 0;
172
+ $removed_redirects = 0;
173
+
174
  foreach($permalink_manager_uris as $element_id => $uri) {
175
+ $count = self::clear_single_element_uris_and_redirects($element_id, true);
 
 
 
 
 
 
 
 
176
 
177
+ $removed_uris = (!empty($count[0])) ? $count[0] + $removed_uris : $removed_uris;
178
+ $removed_redirects = (!empty($count[1])) ? $count[1] + $removed_redirects : $removed_redirects;
179
+ }
180
+
181
+ // Save cleared URIs & Redirects
182
+ if($removed_uris > 0 || $removed_redirects > 0) {
183
+ update_option('permalink-manager-uris', array_filter($permalink_manager_uris));
184
+ update_option('permalink-manager-redirects', array_filter($permalink_manager_redirects));
185
+
186
+ $permalink_manager_before_sections_html .= Permalink_Manager_Admin_Functions::get_alert_message(sprintf(__( '%d Custom URIs and %d Custom Redirects were removed!', 'permalink-manager' ), $removed_uris, $removed_redirects), 'updated');
187
+ } else {
188
+ $permalink_manager_before_sections_html .= Permalink_Manager_Admin_Functions::get_alert_message(__( 'No Custom URIs or Custom Redirects were removed!', 'permalink-manager' ), 'error');
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Check if the post/term uses the same URI for both permalink & custom redirects
194
+ */
195
+ public static function clear_single_element_duplicated_redirect($element_id, $count_removed = false) {
196
+ global $permalink_manager_uris, $permalink_manager_redirects;
197
+
198
+ if(!empty($permalink_manager_uris[$element_id]) && !empty($permalink_manager_redirects[$element_id])) {
199
+ $custom_uri = $permalink_manager_uris[$element_id];
200
+
201
+ if(in_array($custom_uri, $permalink_manager_redirects[$element_id])) {
202
+ $duplicated_redirect_id = array_search($custom_uri, $permalink_manager_redirects[$element_id]);
203
+ unset($permalink_manager_redirects[$element_id][$duplicated_redirect_id]);
204
  }
205
  }
206
 
207
+ // Check if function should only return the counts or update
208
+ if($count_removed) {
209
+ return (isset($duplicated_redirect_id)) ? 1 : 0;
210
+ } else if(isset($duplicated_redirect_id)) {
211
+ update_option('permalink-manager-redirects', array_filter($permalink_manager_redirects));
212
+ return true;
213
+ }
214
  }
215
 
216
  /**
217
+ * Remove unused custom URI & redirects for deleted post or term
218
+ */
219
+ public static function clear_single_element_uris_and_redirects($element_id, $count_removed = false) {
220
+ global $wpdb, $permalink_manager_uris, $permalink_manager_redirects;
221
 
222
+ // Count removed URIs & redirects
223
+ $removed_uris = 0;
224
+ $removed_redirects = 0;
225
+
226
+ // 1. Check if element exists
227
+ if(is_numeric($element_id)) {
228
+ $post_type = $wpdb->get_var("SELECT post_type FROM {$wpdb->prefix}posts WHERE ID = {$element_id} AND post_status NOT IN ('auto-draft', 'trash') AND post_type != 'nav_menu_item'");
229
+
230
+ // Remove custom URIs for removed, auto-draft posts or disabled post types
231
+ $remove = (!empty($post_type)) ? Permalink_Manager_Helper_Functions::is_disabled($post_type, 'post_type') : true;
232
+ } else if(strpos($element_id, 'tax-') !== false) {
233
+ $term_id = preg_replace("/[^0-9]/", "", $element_id);
234
+ $taxonomy = $wpdb->get_var($wpdb->prepare("SELECT t.taxonomy FROM $wpdb->term_taxonomy AS t WHERE t.term_id = %s LIMIT 1", $term_id));
235
 
236
+ // Remove custom URIs for removed terms or disabled taxonomies
237
+ $remove = (!empty($taxonomy)) ? Permalink_Manager_Helper_Functions::is_disabled($taxonomy) : true;
238
+ }
239
+
240
+ // 2A. Remove ALL unused custom permalinks & redirects
241
+ if(!empty($remove)) {
242
+ // Remove URI
243
+ if(!empty($permalink_manager_uris[$element_id])) {
244
+ $removed_uris = 1;
245
+ unset($permalink_manager_uris[$element_id]);
246
+ }
247
+
248
+ // Remove all custom redirects
249
+ if(!empty($permalink_manager_redirects[$element_id]) && is_array($permalink_manager_redirects[$element_id])) {
250
+ $removed_redirects = count($permalink_manager_redirects[$element_id]);
251
+ unset($permalink_manager_redirects[$element_id]);;
252
+ }
253
+ }
254
+ // 2B. Check if the post/term uses the same URI for both permalink & custom redirects
255
+ else {
256
+ $removed_redirect = self::clear_single_element_duplicated_redirect($element_id, true);
257
+ $removed_redirects = (!empty($removed_redirect)) ? 1 : 0;
258
+ }
259
+
260
+ // Check if function should only return the counts or update
261
+ if($count_removed) {
262
+ return array($removed_uris, $removed_redirects);
263
+ } else if(!empty($removed_uris) || !empty($removed_redirects)) {
264
+ update_option('permalink-manager-uris', array_filter($permalink_manager_uris));
265
+ update_option('permalink-manager-redirects', array_filter($permalink_manager_redirects));
266
+ return true;
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Remove custom URI & redirects for any requested post or term
272
+ */
273
+ public static function force_clear_single_element_uris_and_redirects($uri_key) {
274
+ global $permalink_manager_uris, $permalink_manager_redirects, $permalink_manager_before_sections_html;
275
+
276
+ // Check if custom URI is set
277
  if(isset($permalink_manager_uris[$uri_key])) {
278
  $uri = $permalink_manager_uris[$uri_key];
 
279
 
280
+ unset($permalink_manager_uris[$uri_key]);
281
  update_option('permalink-manager-uris', $permalink_manager_uris);
282
 
283
  $permalink_manager_before_sections_html .= Permalink_Manager_Admin_Functions::get_alert_message(sprintf(__( 'URI "%s" was removed successfully!', 'permalink-manager' ), $uri), 'updated');
284
+ $updated = true;
285
+ }
286
+
287
+ // Check if custom redirects are set
288
+ if(isset($permalink_manager_redirects[$uri_key])) {
289
+ unset($permalink_manager_redirects[$uri_key]);
290
+ update_option('permalink-manager-redirects', $permalink_manager_redirects);
291
+
292
+ $permalink_manager_before_sections_html .= Permalink_Manager_Admin_Functions::get_alert_message(__( 'Broken redirects were removed successfully!', 'permalink-manager' ), 'updated');
293
+ $updated = true;
294
+ }
295
+
296
+ if(empty($updated)) {
297
+ $permalink_manager_before_sections_html .= Permalink_Manager_Admin_Functions::get_alert_message(__( 'URI and/or custom redirects does not exist or were already removed!', 'permalink-manager' ), 'error');
298
  }
299
  }
300
 
includes/core/permalink-manager-admin-functions.php CHANGED
@@ -21,8 +21,8 @@ class Permalink_Manager_Admin_Functions extends Permalink_Manager_Class {
21
  }
22
 
23
  /**
24
- * Hooks that should be triggered with "admin_init"
25
- */
26
  public function init() {
27
  // Additional link in "Plugins" page
28
  add_filter( "plugin_action_links_{$this->plugin_basename}", array($this, "plugins_page_links") );
@@ -33,8 +33,8 @@ class Permalink_Manager_Admin_Functions extends Permalink_Manager_Class {
33
  }
34
 
35
  /**
36
- * Get current section (only in plugin sections)
37
- */
38
  public function get_current_section() {
39
  global $active_section, $active_subsection, $current_admin_tax;
40
 
@@ -75,8 +75,8 @@ class Permalink_Manager_Admin_Functions extends Permalink_Manager_Class {
75
  }
76
 
77
  /**
78
- * Add menu page.
79
- */
80
  public function add_menu_page() {
81
  $this->menu_name = add_management_page( __('Permalink Manager', 'permalink-manager'), __('Permalink Manager', 'permalink-manager'), 'manage_options', $this->plugin_slug, array($this, 'display_section') );
82
 
@@ -85,16 +85,16 @@ class Permalink_Manager_Admin_Functions extends Permalink_Manager_Class {
85
  }
86
 
87
  /**
88
- * Register the CSS file for the dashboard.
89
- */
90
  public function enqueue_styles() {
91
  wp_enqueue_style( 'permalink-manager-plugins', PERMALINK_MANAGER_URL . '/out/permalink-manager-plugins.css', array(), PERMALINK_MANAGER_VERSION, 'all' );
92
  wp_enqueue_style( 'permalink-manager', PERMALINK_MANAGER_URL . '/out/permalink-manager-admin.css', array('permalink-manager-plugins'), PERMALINK_MANAGER_VERSION, 'all' );
93
  }
94
 
95
  /**
96
- * Register the JavaScript file for the dashboard.
97
- */
98
  public function enqueue_scripts() {
99
  wp_enqueue_script( 'permalink-manager-plugins', PERMALINK_MANAGER_URL . '/out/permalink-manager-plugins.js', array( 'jquery', ), PERMALINK_MANAGER_VERSION, false );
100
  wp_enqueue_script( 'permalink-manager', PERMALINK_MANAGER_URL . '/out/permalink-manager-admin.js', array( 'jquery', 'permalink-manager-plugins' ), PERMALINK_MANAGER_VERSION, false );
@@ -121,8 +121,8 @@ class Permalink_Manager_Admin_Functions extends Permalink_Manager_Class {
121
  }
122
 
123
  /**
124
- * Generate the fields
125
- */
126
  static public function generate_option_field($input_name, $args) {
127
  global $permalink_manager_options;
128
 
@@ -170,11 +170,23 @@ class Permalink_Manager_Admin_Functions extends Permalink_Manager_Class {
170
  case 'checkbox' :
171
  $fields .= '<div class="checkboxes">';
172
  foreach($args['choices'] as $choice_value => $choice) {
173
- $label = (is_array($choice)) ? $choice['label'] : $choice;
174
- $atts = (is_array($value) && in_array($choice_value, $value)) ? "checked='checked'" : "";
175
- $atts .= (!empty($choice['atts'])) ? " {$choice['atts']}" : "";
176
-
177
- $fields .= "<label for='{$input_name}[]'><input type='checkbox' {$input_atts} value='{$choice_value}' name='{$input_name}[]' {$atts} /> {$label}</label>";
 
 
 
 
 
 
 
 
 
 
 
 
178
  }
179
  $fields .= '</div>';
180
 
@@ -283,15 +295,15 @@ class Permalink_Manager_Admin_Functions extends Permalink_Manager_Class {
283
  }
284
 
285
  /**
286
- * Display hidden field to indicate posts or taxonomies admin sections
287
- */
288
  static public function section_type_field($type = 'post') {
289
  return self::generate_option_field('content_type', array('value' => $type, 'type' => 'hidden'));
290
  }
291
 
292
  /**
293
- * Display the form
294
- */
295
  static public function get_the_form($fields = array(), $container = '', $button = array(), $sidebar = '', $nonce = array(), $wrap = false) {
296
  // 1. Check if the content will be displayed in columns and button details
297
  switch($container) {
@@ -382,8 +394,8 @@ class Permalink_Manager_Admin_Functions extends Permalink_Manager_Class {
382
  }
383
 
384
  /**
385
- * Display the plugin sections.
386
- */
387
  public function display_section() {
388
  global $wpdb, $permalink_manager_before_sections_html, $permalink_manager_after_sections_html;
389
 
@@ -452,8 +464,8 @@ class Permalink_Manager_Admin_Functions extends Permalink_Manager_Class {
452
  }
453
 
454
  /**
455
- * Display error/info message
456
- */
457
  public static function get_alert_message($alert_content = "", $alert_type = "", $dismissable = true, $id = false) {
458
  // Ignore empty messages (just in case)
459
  if(empty($alert_content) || empty($alert_type)) {
@@ -475,16 +487,16 @@ class Permalink_Manager_Admin_Functions extends Permalink_Manager_Class {
475
  }
476
 
477
  /**
478
- * Help tooltip
479
- */
480
  static function help_tooltip($text = '') {
481
  $html = " <a href=\"#\" title=\"{$text}\" class=\"help_tooltip\"><span class=\"dashicons dashicons-editor-help\"></span></a>";
482
  return $html;
483
  }
484
 
485
  /**
486
- * Display the table with updated slugs after one of the actions is triggered
487
- */
488
  static function display_updated_slugs($updated_array, $uri_type = 'post') {
489
  // Check if slugs should be displayed
490
  $first_slug = reset($updated_array);
@@ -531,7 +543,7 @@ class Permalink_Manager_Admin_Functions extends Permalink_Manager_Class {
531
  }
532
 
533
  /**
534
- * Quick Edit Box
535
  */
536
  public static function quick_edit_column_form($is_taxonomy = false) {
537
  $html = Permalink_Manager_Admin_Functions::generate_option_field('permalink-manager-quick-edit', array('value' => true, 'type' => 'hidden'));
@@ -594,7 +606,7 @@ class Permalink_Manager_Admin_Functions extends Permalink_Manager_Class {
594
  Permalink_Manager_Admin_Functions::generate_option_field("custom_uri", array("extra_atts" => "data-default=\"{$default_uri}\"", "input_class" => "widefat custom_uri", "value" => urldecode($uri)))
595
  );
596
 
597
- // 5. Custom URI
598
  if(!empty($auto_update_choices)) {
599
  $html .= sprintf("<div><label for=\"auto_auri\" class=\"strong\">%s %s</label><span>%s</span></div>",
600
  __("Auto-update the URI", "permalink-manager"),
@@ -627,7 +639,7 @@ class Permalink_Manager_Admin_Functions extends Permalink_Manager_Class {
627
  $html .= "</div>";
628
 
629
  // 9. Append nonce field
630
- $html .= wp_nonce_field( 'permalink-manager-edit-uri-box', 'permalink-manager-nonce', true, false );
631
 
632
  return $html;
633
  }
21
  }
22
 
23
  /**
24
+ * Hooks that should be triggered with "admin_init"
25
+ */
26
  public function init() {
27
  // Additional link in "Plugins" page
28
  add_filter( "plugin_action_links_{$this->plugin_basename}", array($this, "plugins_page_links") );
33
  }
34
 
35
  /**
36
+ * Get current section (only in plugin sections)
37
+ */
38
  public function get_current_section() {
39
  global $active_section, $active_subsection, $current_admin_tax;
40
 
75
  }
76
 
77
  /**
78
+ * Add menu page.
79
+ */
80
  public function add_menu_page() {
81
  $this->menu_name = add_management_page( __('Permalink Manager', 'permalink-manager'), __('Permalink Manager', 'permalink-manager'), 'manage_options', $this->plugin_slug, array($this, 'display_section') );
82
 
85
  }
86
 
87
  /**
88
+ * Register the CSS file for the dashboard.
89
+ */
90
  public function enqueue_styles() {
91
  wp_enqueue_style( 'permalink-manager-plugins', PERMALINK_MANAGER_URL . '/out/permalink-manager-plugins.css', array(), PERMALINK_MANAGER_VERSION, 'all' );
92
  wp_enqueue_style( 'permalink-manager', PERMALINK_MANAGER_URL . '/out/permalink-manager-admin.css', array('permalink-manager-plugins'), PERMALINK_MANAGER_VERSION, 'all' );
93
  }
94
 
95
  /**
96
+ * Register the JavaScript file for the dashboard.
97
+ */
98
  public function enqueue_scripts() {
99
  wp_enqueue_script( 'permalink-manager-plugins', PERMALINK_MANAGER_URL . '/out/permalink-manager-plugins.js', array( 'jquery', ), PERMALINK_MANAGER_VERSION, false );
100
  wp_enqueue_script( 'permalink-manager', PERMALINK_MANAGER_URL . '/out/permalink-manager-admin.js', array( 'jquery', 'permalink-manager-plugins' ), PERMALINK_MANAGER_VERSION, false );
121
  }
122
 
123
  /**
124
+ * Generate the fields
125
+ */
126
  static public function generate_option_field($input_name, $args) {
127
  global $permalink_manager_options;
128
 
170
  case 'checkbox' :
171
  $fields .= '<div class="checkboxes">';
172
  foreach($args['choices'] as $choice_value => $choice) {
173
+ $input_template = "<label for='%s[]'><input type='checkbox' %s value='%s' name='%s[]' %s /> %s</label>";
174
+
175
+ if(empty($choice['label']) && is_array($choice)) {
176
+ foreach($choice as $sub_choice_value => $sub_choice) {
177
+ $label = (!empty($sub_choice['label'])) ? $sub_choice['label'] : $sub_choice;
178
+ $atts = (!empty($value[$choice_value]) && in_array($sub_choice_value, $value[$choice_value])) ? "checked='checked'" : "";
179
+ $atts .= (!empty($sub_choice['atts'])) ? " {$sub_choice['atts']}" : "";
180
+
181
+ $fields .= sprintf($input_template, $input_name, $input_atts, $sub_choice_value, "{$input_name}[{$choice_value}]", $atts, $label);
182
+ }
183
+ } else {
184
+ $label = (!empty($choice['label'])) ? $choice['label'] : $choice;
185
+ $atts = (is_array($value) && in_array($choice_value, $value)) ? "checked='checked'" : "";
186
+ $atts .= (!empty($choice['atts'])) ? " {$choice['atts']}" : "";
187
+
188
+ $fields .= sprintf($input_template, $input_name, $input_atts, $choice_value, $input_name, $atts, $label);
189
+ }
190
  }
191
  $fields .= '</div>';
192
 
295
  }
296
 
297
  /**
298
+ * Display hidden field to indicate posts or taxonomies admin sections
299
+ */
300
  static public function section_type_field($type = 'post') {
301
  return self::generate_option_field('content_type', array('value' => $type, 'type' => 'hidden'));
302
  }
303
 
304
  /**
305
+ * Display the form
306
+ */
307
  static public function get_the_form($fields = array(), $container = '', $button = array(), $sidebar = '', $nonce = array(), $wrap = false) {
308
  // 1. Check if the content will be displayed in columns and button details
309
  switch($container) {
394
  }
395
 
396
  /**
397
+ * Display the plugin sections.
398
+ */
399
  public function display_section() {
400
  global $wpdb, $permalink_manager_before_sections_html, $permalink_manager_after_sections_html;
401
 
464
  }
465
 
466
  /**
467
+ * Display error/info message
468
+ */
469
  public static function get_alert_message($alert_content = "", $alert_type = "", $dismissable = true, $id = false) {
470
  // Ignore empty messages (just in case)
471
  if(empty($alert_content) || empty($alert_type)) {
487
  }
488
 
489
  /**
490
+ * Help tooltip
491
+ */
492
  static function help_tooltip($text = '') {
493
  $html = " <a href=\"#\" title=\"{$text}\" class=\"help_tooltip\"><span class=\"dashicons dashicons-editor-help\"></span></a>";
494
  return $html;
495
  }
496
 
497
  /**
498
+ * Display the table with updated slugs after one of the actions is triggered
499
+ */
500
  static function display_updated_slugs($updated_array, $uri_type = 'post') {
501
  // Check if slugs should be displayed
502
  $first_slug = reset($updated_array);
543
  }
544
 
545
  /**
546
+ * "Quick Edit" Box
547
  */
548
  public static function quick_edit_column_form($is_taxonomy = false) {
549
  $html = Permalink_Manager_Admin_Functions::generate_option_field('permalink-manager-quick-edit', array('value' => true, 'type' => 'hidden'));
606
  Permalink_Manager_Admin_Functions::generate_option_field("custom_uri", array("extra_atts" => "data-default=\"{$default_uri}\"", "input_class" => "widefat custom_uri", "value" => urldecode($uri)))
607
  );
608
 
609
+ // 5. Auto-update URI
610
  if(!empty($auto_update_choices)) {
611
  $html .= sprintf("<div><label for=\"auto_auri\" class=\"strong\">%s %s</label><span>%s</span></div>",
612
  __("Auto-update the URI", "permalink-manager"),
639
  $html .= "</div>";
640
 
641
  // 9. Append nonce field
642
+ $html .= wp_nonce_field('permalink-manager-edit-uri-box', 'permalink-manager-nonce', true, false);
643
 
644
  return $html;
645
  }
includes/core/permalink-manager-core-functions.php CHANGED
@@ -25,14 +25,14 @@ class Permalink_Manager_Core_Functions extends Permalink_Manager_Class {
25
 
26
  // Case insensitive permalinks
27
  add_action( 'parse_request', array($this, 'case_insensitive_permalinks'), 0);
28
- add_action( 'template_redirect', array($this, 'fix_pagination_pages'), 0);
29
  }
30
 
31
  /**
32
  * The most important Permalink Manager function
33
  */
34
  function detect_post($query) {
35
- global $wpdb, $wp, $permalink_manager_uris, $wp_filter, $permalink_manager_options, $pm_item_id;
36
 
37
  // Check if any custom URI is used
38
  if(!(is_array($permalink_manager_uris)) || empty($query)) return $query;
@@ -48,12 +48,8 @@ class Permalink_Manager_Core_Functions extends Permalink_Manager_Class {
48
  $home_url = trim(rtrim(get_option('home'), '/'));
49
  $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)
50
 
51
- if (filter_var($request_url, FILTER_VALIDATE_URL)) {
52
- /**
53
- * 1. Process URL & find the URI
54
- */
55
-
56
- // Check if Deep Detect is enabled
57
  $deep_detect_enabled = apply_filters('permalink-manager-deep-uri-detect', $permalink_manager_options['general']['deep_detect']);
58
 
59
  // Remove .html suffix and domain name from URL and query (URLs ended with .html will work as aliases)
@@ -62,11 +58,11 @@ class Permalink_Manager_Core_Functions extends Permalink_Manager_Class {
62
  // Remove querystrings from URI
63
  $request_url = urldecode(strtok($request_url, '?'));
64
 
65
- // Filter endpoints
66
- $endpoints = apply_filters("permalink-manager-endpoints", "page|feed|embed|attachment|track");
67
 
68
  // Use default REGEX to detect post
69
- preg_match("/^(.+?)(?:\/($endpoints))?(?:\/([\d]+))?\/?$/i", $request_url, $regex_parts);
70
  $uri_parts['lang'] = false;
71
  $uri_parts['uri'] = (!empty($regex_parts[1])) ? $regex_parts[1] : "";
72
  $uri_parts['endpoint'] = (!empty($regex_parts[2])) ? $regex_parts[2] : "";
@@ -88,10 +84,10 @@ class Permalink_Manager_Core_Functions extends Permalink_Manager_Class {
88
  $uri = trim($uri, "/");
89
 
90
  // Decode both Request URI & URIs array
91
- $uri = urldecode($uri);
92
  foreach ($permalink_manager_uris as $key => $value) {
93
  $permalink_manager_uris[$key] = urldecode($value);
94
- }
95
 
96
  // Ignore URLs with no URI grabbed
97
  if(empty($uri)) return $query;
@@ -99,114 +95,141 @@ class Permalink_Manager_Core_Functions extends Permalink_Manager_Class {
99
  /**
100
  * 2. Check if found URI matches any element from custom uris array
101
  */
102
- $item_id = array_search($uri, $permalink_manager_uris);
103
 
104
  // Check again in case someone added .html suffix to particular post (with .html suffix)
105
- $item_id = (empty($item_id)) ? array_search("{$uri}.html", $permalink_manager_uris) : $item_id;
106
 
107
  // Check again in case someone used post/tax IDs instead of slugs
108
  if($deep_detect_enabled && isset($old_query['page'])) {
109
 
110
  $new_item_id = array_search("{$uri}/{$endpoint_value}", $permalink_manager_uris);
111
  if($new_item_id) {
112
- $item_id = $new_item_id;
113
  $endpoint_value = $endpoint = "";
114
  }
115
  }
116
 
117
  // Allow to filter the item_id by third-parties after initial detection
118
- $item_id = apply_filters('permalink-manager-detected-initial-id', $item_id, $uri_parts, $request_url);
119
 
120
  // Clear the original query before it is filtered
121
- $query = ($item_id) ? array() : $query;
122
 
123
  /**
124
  * 3A. Custom URI assigned to taxonomy
125
  */
126
- if(strpos($item_id, 'tax-') !== false) {
127
  // Remove the "tax-" prefix
128
- $item_id = preg_replace("/[^0-9]/", "", $item_id);
129
 
130
  // Filter detected post ID
131
- $item_id = apply_filters('permalink-manager-detected-term-id', intval($item_id), $uri_parts, true);
132
-
133
- // Get the variables to filter wp_query and double-check if tax exists
134
- $term = get_term(intval($item_id));
135
- if(empty($term->taxonomy)) { return $query; }
136
-
137
- // Get some term data
138
- if($term->taxonomy == 'category') {
139
- $query_parameter = 'category_name';
140
- } else if($term->taxonomy == 'post_tag') {
141
- $query_parameter = 'tag';
142
- } else {
143
- $query_parameter = $term->taxonomy;
144
- }
145
- $term_ancestors = get_ancestors($item_id, $term->taxonomy);
146
- $final_uri = $term->slug;
147
-
148
- // Fix for hierarchical CPT & pages
149
- if(empty($term_ancestors)) {
150
- foreach ($term_ancestors as $parent) {
151
- $parent = get_term($parent, $term->taxonomy);
152
- if(!empty($parent->slug)) {
153
- $final_uri = $parent->slug . '/' . $final_uri;
 
 
 
 
 
 
154
  }
155
  }
156
- }
157
 
158
- // Make the redirects more clever - see redirect_to_new_uri() method
159
- $query['do_not_redirect'] = 1;
160
- $query[$query_parameter] = $final_uri;
 
 
 
161
  }
162
  /**
163
  * 3B. Custom URI assigned to post/page/cpt item
164
  */
165
- else if(isset($item_id) && is_numeric($item_id)) {
166
  // Fix for revisions
167
- $is_revision = wp_is_post_revision($item_id);
168
- $item_id = ($is_revision) ? $is_revision : $item_id;
169
 
170
  // Filter detected post ID
171
- $item_id = apply_filters('permalink-manager-detected-post-id', $item_id, $uri_parts);
172
-
173
- $post_to_load = get_post($item_id);
174
- $final_uri = $post_to_load->post_name;
175
- $post_type = $post_to_load->post_type;
176
-
177
- // Fix for hierarchical CPT & pages
178
- if(!(empty($post_to_load->ancestors))) {
179
- foreach ($post_to_load->ancestors as $parent) {
180
- $parent = get_post( $parent );
181
- if($parent && $parent->post_name) {
182
- $final_uri = $parent->post_name . '/' . $final_uri;
 
 
 
 
 
 
183
  }
184
  }
185
- }
186
 
187
- // Alter query parameters
188
- if($post_to_load->post_type == 'page') {
189
- $query['pagename'] = $final_uri;
190
- } else if($post_to_load->post_type == 'post') {
191
- $query['name'] = $final_uri;
192
- } else if($post_to_load->post_type == 'attachment') {
193
- $query['attachment'] = $final_uri;
 
 
 
 
 
 
 
 
194
  } else {
195
- $query['name'] = $final_uri;
196
- $query['post_type'] = $post_type;
197
- $query[$post_type] = $final_uri;
198
  }
199
-
200
- // Make the redirects more clever - see redirect_to_new_uri() method
201
- $query['do_not_redirect'] = 1;
202
  }
203
 
 
 
 
 
 
204
 
 
 
 
 
 
 
205
 
206
  /**
207
- * 2C. Endpoints
208
  */
209
- if($item_id && (!empty($endpoint)) || !empty($endpoint_value)) {
210
  $endpoint = ($endpoint) ? str_replace(array('page', 'trackback'), array('paged', 'tb'), $endpoint) : "page";
211
 
212
  if($endpoint == 'feed') {
@@ -237,8 +260,8 @@ class Permalink_Manager_Core_Functions extends Permalink_Manager_Class {
237
  /**
238
  * Global with detected item id
239
  */
240
- if(!empty($item_id)) {
241
- $pm_item_id = $item_id;
242
  }
243
  }
244
 
@@ -272,6 +295,31 @@ class Permalink_Manager_Core_Functions extends Permalink_Manager_Class {
272
  return $permalink;
273
  }
274
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275
  /**
276
  * Redirects
277
  */
@@ -284,10 +332,16 @@ class Permalink_Manager_Core_Functions extends Permalink_Manager_Class {
284
  // Sometimes $wp_query indicates the wrong object if requested directly
285
  $queried_object = get_queried_object();
286
 
287
- // Get the redirection mode
288
  $redirect_mode = (!empty($permalink_manager_options['general']['redirect'])) ? $permalink_manager_options['general']['redirect'] : false;
 
289
 
290
- // A. Custom redirects
 
 
 
 
 
291
  if(empty($wp_query->query['do_not_redirect']) && !empty($permalink_manager_redirects) && is_array($permalink_manager_redirects) && !empty($wp->request)) {
292
  $uri = urldecode(trim($wp->request, "/ "));
293
 
@@ -302,52 +356,81 @@ class Permalink_Manager_Core_Functions extends Permalink_Manager_Class {
302
 
303
  // Post is detected
304
  if(is_numeric($element)) {
305
- $redirect_to = get_permalink($element);
306
  }
307
  // Term is detected
308
  else {
309
  $term_id = intval(preg_replace("/[^0-9]/", "", $element));
310
- $redirect_to = get_term_link($term_id);
311
- }
312
-
313
- if(!empty($redirect_to)) {
314
- wp_safe_redirect($redirect_to, $redirect_mode);
315
- exit();
316
  }
317
  }
318
  }
319
  }
320
 
321
- // B. Native redirect
322
- if($redirect_mode && !empty($queried_object)) {
 
 
323
  // Affect only posts with custom URI and old URIs
324
- if(!empty($queried_object->ID) && isset($permalink_manager_uris[$queried_object->ID]) && empty($wp_query->query['do_not_redirect']) && empty($wp_query->query['preview'])) {
325
  // Ignore posts with specific statuses
326
  if(!(empty($queried_object->post_status)) && in_array($queried_object->post_status, array('draft', 'pending', 'auto-draft', 'future'))) {
327
  return '';
328
  }
329
 
 
 
 
330
  // Get the real URL
331
  $correct_permalink = get_permalink($queried_object->ID);
332
  }
333
  // Affect only terms with custom URI and old URIs
334
- else if(!empty($queried_object->term_id) && isset($permalink_manager_uris["tax-{$queried_object->term_id}"]) && empty($wp_query->query['do_not_redirect'])) {
 
 
 
335
  // Get the real URL
336
  $correct_permalink = get_term_link($queried_object->term_id, $queried_object->taxonomy);
337
  }
338
-
339
- // Ignore default URIs (or do nothing if redirects are disabled)
340
- if(!empty($correct_permalink) && !empty($redirect_mode)) {
341
- wp_safe_redirect($correct_permalink, $redirect_mode);
342
- exit();
343
- }
344
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
345
  }
346
 
347
  function fix_canonical_redirect($redirect_url, $requested_url) {
348
  global $permalink_manager_options;
349
 
350
- // Trailing slash
351
  if(substr($redirect_url, 0, -1) != '/' && $permalink_manager_options['general']['trailing_slashes'] > 1) {
352
  $redirect_url = false;
353
  }
@@ -375,110 +458,4 @@ class Permalink_Manager_Core_Functions extends Permalink_Manager_Class {
375
  }
376
  }
377
 
378
- /**
379
- * Display 404 if requested page does not exist in pagination
380
- */
381
- function fix_pagination_pages() {
382
- global $wp_query;
383
-
384
- // 1. Get the post object
385
- $post = get_queried_object();
386
-
387
- // 2. Check if post object is defined
388
- if(empty($post->ID)) { return; }
389
-
390
- // 3. Check if pagination is detected
391
- if(empty($wp_query->query_vars['page'])) { return; }
392
-
393
- // 4. Count post pages
394
- $num_pages = substr_count(strtolower($post->post_content), '<!--nextpage-->') + 1;
395
- if($wp_query->query_vars['page'] > $num_pages) {
396
- $wp_query->set('p', null);
397
- $wp_query->set('pagename', null);
398
- $wp_query->set('page_id', null);
399
- $wp_query->set_404();
400
- }
401
- }
402
-
403
- /**
404
- * Detect duplicates
405
- */
406
- public static function detect_duplicates() {
407
- global $permalink_manager_uris, $permalink_manager_redirects, $permalink_manager_options, $wpdb;
408
-
409
- // Make sure that both variables are arrays
410
- $all_uris = (is_array($permalink_manager_uris)) ? $permalink_manager_uris : array();
411
- $permalink_manager_redirects = (is_array($permalink_manager_redirects)) ? $permalink_manager_redirects : array();
412
-
413
- // Convert redirects list, so it can be merged with $permalink_manager_uris
414
- foreach($permalink_manager_redirects as $element_id => $redirects) {
415
- if(is_array($redirects)) {
416
- foreach($redirects as $index => $uri) {
417
- $all_uris["redirect-{$index}_{$element_id}"] = $uri;
418
- }
419
- }
420
- }
421
-
422
- // Count duplicates
423
- $duplicates_removed = 0;
424
- $duplicates_groups = array();
425
- $duplicates_list = array_count_values($all_uris);
426
- $duplicates_list = array_filter($duplicates_list, function ($x) { return $x >= 2; });
427
-
428
- // Assign keys to duplicates (group them)
429
- if(count($duplicates_list) > 0) {
430
- foreach($duplicates_list as $duplicated_uri => $count) {
431
- $duplicates_array = array_keys($all_uris, $duplicated_uri);
432
-
433
- // Remove the URIs for removed posts & terms
434
- if(!empty($permalink_manager_options['general']['auto_remove_duplicates'])) {
435
- foreach($duplicates_array as $index => $raw_item_id) {
436
- $item_id = preg_replace("/(?:redirect-[\d]+_)?(.*)/", "$1", $raw_item_id);
437
-
438
- if(strpos($item_id, 'tax-') !== false) {
439
- $term_id = intval(preg_replace("/[^0-9]/", "", $item_id));
440
- $element_exists = $wpdb->get_var( "SELECT * FROM {$wpdb->prefix}terms WHERE term_id = {$term_id}" );
441
- } else {
442
- $element_exists = $wpdb->get_var( "SELECT * FROM {$wpdb->prefix}posts WHERE ID = {$item_id} AND post_status NOT IN ('auto-draft', 'trash') AND post_type != 'nav_menu_item'" );
443
- }
444
-
445
- if(empty($element_exists)) {
446
- // Detect the type of URI
447
- preg_match("/(redirect-([\d]+)_)?((?:tax-)?[\d]*)/", $raw_item_id, $parts);
448
-
449
- $detected_redirect = $parts[1];
450
- $detected_id = $parts[3];
451
- $detected_index = $parts[2];
452
-
453
- // A. Redirect
454
- if($detected_redirect && $detected_index && $detected_id) {
455
- unset($permalink_manager_redirects[$detected_id][$detected_index]);
456
- }
457
- // B. Custom URI
458
- else if($detected_id) {
459
- unset($permalink_manager_uris[$detected_id]);
460
- }
461
-
462
- if($detected_id) {
463
- unset($duplicates_array[$index]);
464
- $duplicates_removed++;
465
- }
466
- }
467
- }
468
- }
469
-
470
- $duplicates_groups[$duplicated_uri] = $duplicates_array;
471
- }
472
-
473
- // Save cleared URIs & Redirects
474
- if($duplicates_removed > 0 && !empty($permalink_manager_options['general']['auto_remove_duplicates'])) {
475
- update_option('permalink-manager-uris', $permalink_manager_uris);
476
- update_option('permalink-manager-redirects', $permalink_manager_redirects);
477
- }
478
- }
479
-
480
- return $duplicates_groups;
481
- }
482
-
483
  }
484
- ?>
25
 
26
  // Case insensitive permalinks
27
  add_action( 'parse_request', array($this, 'case_insensitive_permalinks'), 0);
28
+ add_action( 'parse_request', array($this, 'fix_pagination_pages'), 0);
29
  }
30
 
31
  /**
32
  * The most important Permalink Manager function
33
  */
34
  function detect_post($query) {
35
+ global $wpdb, $wp, $wp_rewrite, $permalink_manager_uris, $wp_filter, $permalink_manager_options, $pm_item_id;
36
 
37
  // Check if any custom URI is used
38
  if(!(is_array($permalink_manager_uris)) || empty($query)) return $query;
48
  $home_url = trim(rtrim(get_option('home'), '/'));
49
  $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)
50
 
51
+ if(filter_var($request_url, FILTER_VALIDATE_URL)) {
52
+ // Check if "Deep Detect" is enabled
 
 
 
 
53
  $deep_detect_enabled = apply_filters('permalink-manager-deep-uri-detect', $permalink_manager_options['general']['deep_detect']);
54
 
55
  // Remove .html suffix and domain name from URL and query (URLs ended with .html will work as aliases)
58
  // Remove querystrings from URI
59
  $request_url = urldecode(strtok($request_url, '?'));
60
 
61
+ // Get all the endpoints
62
+ $endpoints = Permalink_Manager_Helper_Functions::get_endpoints();
63
 
64
  // Use default REGEX to detect post
65
+ preg_match("/^(.+?)(?|\/({$endpoints})\/([^\/]+)|()\/([\d+]))?\/?$/i", $request_url, $regex_parts);
66
  $uri_parts['lang'] = false;
67
  $uri_parts['uri'] = (!empty($regex_parts[1])) ? $regex_parts[1] : "";
68
  $uri_parts['endpoint'] = (!empty($regex_parts[2])) ? $regex_parts[2] : "";
84
  $uri = trim($uri, "/");
85
 
86
  // Decode both Request URI & URIs array
87
+ /*$uri = urldecode($uri);
88
  foreach ($permalink_manager_uris as $key => $value) {
89
  $permalink_manager_uris[$key] = urldecode($value);
90
+ }*/
91
 
92
  // Ignore URLs with no URI grabbed
93
  if(empty($uri)) return $query;
95
  /**
96
  * 2. Check if found URI matches any element from custom uris array
97
  */
98
+ $element_id = array_search($uri, $permalink_manager_uris);
99
 
100
  // Check again in case someone added .html suffix to particular post (with .html suffix)
101
+ $element_id = (empty($element_id)) ? array_search("{$uri}.html", $permalink_manager_uris) : $element_id;
102
 
103
  // Check again in case someone used post/tax IDs instead of slugs
104
  if($deep_detect_enabled && isset($old_query['page'])) {
105
 
106
  $new_item_id = array_search("{$uri}/{$endpoint_value}", $permalink_manager_uris);
107
  if($new_item_id) {
108
+ $element_id = $new_item_id;
109
  $endpoint_value = $endpoint = "";
110
  }
111
  }
112
 
113
  // Allow to filter the item_id by third-parties after initial detection
114
+ $element_id = apply_filters('permalink-manager-detected-initial-id', $element_id, $uri_parts, $request_url);
115
 
116
  // Clear the original query before it is filtered
117
+ $query = ($element_id) ? array() : $query;
118
 
119
  /**
120
  * 3A. Custom URI assigned to taxonomy
121
  */
122
+ if(strpos($element_id, 'tax-') !== false) {
123
  // Remove the "tax-" prefix
124
+ $term_id = intval(preg_replace("/[^0-9]/", "", $element_id));
125
 
126
  // Filter detected post ID
127
+ $term_id = apply_filters('permalink-manager-detected-term-id', intval($term_id), $uri_parts, true);
128
+
129
+ // Get the variables to filter wp_query and double-check if taxonomy exists
130
+ $term = get_term($term_id);
131
+ $term_taxonomy = (!empty($term->taxonomy)) ? $term->taxonomy : false;
132
+
133
+ // Check if taxonomy is allowed
134
+ $disabled = (Permalink_Manager_Helper_Functions::is_disabled($term_taxonomy, 'taxonomy')) ? true : false;
135
+
136
+ // Proceed only if the term is not removed and its taxonomy is not disabled
137
+ if(!$disabled && $term_taxonomy) {
138
+ // Get some term data
139
+ if($term_taxonomy == 'category') {
140
+ $query_parameter = 'category_name';
141
+ } else if($term_taxonomy == 'post_tag') {
142
+ $query_parameter = 'tag';
143
+ } else {
144
+ $query_parameter = $term_taxonomy;
145
+ }
146
+ $term_ancestors = get_ancestors($term_id, $term_taxonomy);
147
+ $final_uri = $term->slug;
148
+
149
+ // Fix for hierarchical terms
150
+ if(empty($term_ancestors)) {
151
+ foreach ($term_ancestors as $parent) {
152
+ $parent = get_term($parent, $term_taxonomy);
153
+ if(!empty($parent->slug)) {
154
+ $final_uri = $parent->slug . '/' . $final_uri;
155
+ }
156
  }
157
  }
 
158
 
159
+ // Make the redirects more clever - see redirect_to_new_uri() method
160
+ $query['do_not_redirect'] = 1;
161
+ $query[$query_parameter] = $final_uri;
162
+ } else {
163
+ $broken_uri = true;
164
+ }
165
  }
166
  /**
167
  * 3B. Custom URI assigned to post/page/cpt item
168
  */
169
+ else if(isset($element_id) && is_numeric($element_id)) {
170
  // Fix for revisions
171
+ $is_revision = wp_is_post_revision($element_id);
172
+ $element_id = ($is_revision) ? $is_revision : $element_id;
173
 
174
  // Filter detected post ID
175
+ $element_id = apply_filters('permalink-manager-detected-post-id', $element_id, $uri_parts);
176
+
177
+ $post_to_load = get_post($element_id);
178
+ $final_uri = (!empty($post_to_load->post_name)) ? $post_to_load->post_name : false;
179
+ $post_type = (!empty($post_to_load->post_type)) ? $post_to_load->post_type : false;
180
+
181
+ // Check if post type is allowed
182
+ $disabled = (Permalink_Manager_Helper_Functions::is_disabled($post_type, 'post_type')) ? true : false;
183
+
184
+ // Proceed only if the term is not removed and its taxonomy is not disabled
185
+ if(!$disabled && $post_type) {
186
+ // Fix for hierarchical CPT & pages
187
+ if(!(empty($post_to_load->ancestors))) {
188
+ foreach ($post_to_load->ancestors as $parent) {
189
+ $parent = get_post( $parent );
190
+ if($parent && $parent->post_name) {
191
+ $final_uri = $parent->post_name . '/' . $final_uri;
192
+ }
193
  }
194
  }
 
195
 
196
+ // Alter query parameters
197
+ if($post_to_load->post_type == 'page') {
198
+ $query['pagename'] = $final_uri;
199
+ } else if($post_to_load->post_type == 'post') {
200
+ $query['name'] = $final_uri;
201
+ } else if($post_to_load->post_type == 'attachment') {
202
+ $query['attachment'] = $final_uri;
203
+ } else {
204
+ $query['name'] = $final_uri;
205
+ $query['post_type'] = $post_type;
206
+ $query[$post_type] = $final_uri;
207
+ }
208
+
209
+ // Make the redirects more clever - see redirect_to_new_uri() method
210
+ $query['do_not_redirect'] = 1;
211
  } else {
212
+ $broken_uri = true;
 
 
213
  }
 
 
 
214
  }
215
 
216
+ /**
217
+ * 2C. Auto-remove removed term custom URI & redirects (works if enabled in plugin settings)
218
+ */
219
+ if(!empty($broken_uri) && !empty($permalink_manager_options['general']['auto_remove_duplicates'])) {
220
+ $remove_broken_uri = Permalink_Manager_Actions::clear_single_element_uris_and_redirects($element_id);
221
 
222
+ // Reload page if success
223
+ if($remove_broken_uri) {
224
+ header("Refresh:0");
225
+ exit();
226
+ }
227
+ }
228
 
229
  /**
230
+ * 2D. Endpoints
231
  */
232
+ if($element_id && (!empty($endpoint)) || !empty($endpoint_value)) {
233
  $endpoint = ($endpoint) ? str_replace(array('page', 'trackback'), array('paged', 'tb'), $endpoint) : "page";
234
 
235
  if($endpoint == 'feed') {
260
  /**
261
  * Global with detected item id
262
  */
263
+ if(!empty($element_id)) {
264
+ $pm_item_id = $element_id;
265
  }
266
  }
267
 
295
  return $permalink;
296
  }
297
 
298
+ /**
299
+ * Display 404 if requested page does not exist in pagination
300
+ */
301
+ function fix_pagination_pages() {
302
+ global $wp_query;
303
+
304
+ // 1. Get the post object
305
+ $post = get_queried_object();
306
+
307
+ // 2. Check if post object is defined
308
+ if(empty($post->ID)) { return; }
309
+
310
+ // 3. Check if pagination is detected
311
+ if(empty($wp_query->query_vars['page'])) { return; }
312
+
313
+ // 4. Count post pages
314
+ $num_pages = substr_count(strtolower($post->post_content), '<!--nextpage-->') + 1;
315
+ if($wp_query->query_vars['page'] > $num_pages) {
316
+ $wp_query->set('p', null);
317
+ $wp_query->set('pagename', null);
318
+ $wp_query->set('page_id', null);
319
+ $wp_query->set_404();
320
+ }
321
+ }
322
+
323
  /**
324
  * Redirects
325
  */
332
  // Sometimes $wp_query indicates the wrong object if requested directly
333
  $queried_object = get_queried_object();
334
 
335
+ // Get the redirection mode & trailing slashes settings
336
  $redirect_mode = (!empty($permalink_manager_options['general']['redirect'])) ? $permalink_manager_options['general']['redirect'] : false;
337
+ $trailing_slashes_mode = (!empty($permalink_manager_options['general']['trailing_slashes'])) ? $permalink_manager_options['general']['trailing_slashes'] : false;
338
 
339
+ // Get query string
340
+ $query_string = $_SERVER['QUERY_STRING'];
341
+
342
+ /**
343
+ * 1A. Custom redirects
344
+ */
345
  if(empty($wp_query->query['do_not_redirect']) && !empty($permalink_manager_redirects) && is_array($permalink_manager_redirects) && !empty($wp->request)) {
346
  $uri = urldecode(trim($wp->request, "/ "));
347
 
356
 
357
  // Post is detected
358
  if(is_numeric($element)) {
359
+ $correct_permalink = get_permalink($element);
360
  }
361
  // Term is detected
362
  else {
363
  $term_id = intval(preg_replace("/[^0-9]/", "", $element));
364
+ $correct_permalink = get_term_link($term_id);
 
 
 
 
 
365
  }
366
  }
367
  }
368
  }
369
 
370
+ /**
371
+ * 1B. Enhance native redirect
372
+ */
373
+ if(empty($wp_query->query['do_not_redirect']) && $redirect_mode && !empty($queried_object) && empty($correct_permalink)) {
374
  // Affect only posts with custom URI and old URIs
375
+ if(!empty($queried_object->ID) && isset($permalink_manager_uris[$queried_object->ID]) && empty($wp_query->query['preview'])) {
376
  // Ignore posts with specific statuses
377
  if(!(empty($queried_object->post_status)) && in_array($queried_object->post_status, array('draft', 'pending', 'auto-draft', 'future'))) {
378
  return '';
379
  }
380
 
381
+ // Check if post type is allowed
382
+ if(Permalink_Manager_Helper_Functions::is_disabled($queried_object->post_type, 'post_type')) { return ''; }
383
+
384
  // Get the real URL
385
  $correct_permalink = get_permalink($queried_object->ID);
386
  }
387
  // Affect only terms with custom URI and old URIs
388
+ else if(!empty($queried_object->term_id) && isset($permalink_manager_uris["tax-{$queried_object->term_id}"])) {
389
+ // Check if taxonomy is allowed
390
+ if(Permalink_Manager_Helper_Functions::is_disabled($queried_object->taxonomy, "taxonomy")) { return ''; }
391
+
392
  // Get the real URL
393
  $correct_permalink = get_term_link($queried_object->term_id, $queried_object->taxonomy);
394
  }
 
 
 
 
 
 
395
  }
396
+
397
+ /**
398
+ * 2. Check trailing slashes
399
+ */
400
+ if($trailing_slashes_mode) {
401
+ $old_request = strtok($_SERVER['REQUEST_URI'], "?");
402
+ $ends_with_slash = (substr($old_request, -1) == "/") ? true : false;
403
+
404
+ // Homepage should be ignored
405
+ if($old_request != "/") {
406
+ // 2A. Force trailing slashes
407
+ if($trailing_slashes_mode == 10 && $ends_with_slash == false) {
408
+ $correct_permalink = (!empty($correct_permalink)) ? "{$correct_permalink}/" : rtrim(get_option('home'), "/") . $old_request . "/";
409
+ }
410
+ // 2B. Remove trailing slashes
411
+ else if($trailing_slashes_mode == 20 && $ends_with_slash == true) {
412
+ $correct_permalink = (!empty($correct_permalink)) ? $correct_permalink : rtrim(get_option('home'), "/") . $old_request;
413
+ $correct_permalink = rtrim($correct_permalink, "/");
414
+ }
415
+ }
416
+ }
417
+
418
+ /**
419
+ * 3. Ignore default URIs (or do nothing if redirects are disabled)
420
+ */
421
+ if(!empty($correct_permalink) && !empty($redirect_mode)) {
422
+ // Append query string
423
+ $correct_permalink = (!empty($query_string)) ? "{$correct_permalink}?{$query_string}" : $correct_permalink;
424
+
425
+ wp_safe_redirect($correct_permalink, $redirect_mode);
426
+ exit();
427
+ }
428
  }
429
 
430
  function fix_canonical_redirect($redirect_url, $requested_url) {
431
  global $permalink_manager_options;
432
 
433
+ // Trailing slash (use redirect_to_new_uri() function instead)
434
  if(substr($redirect_url, 0, -1) != '/' && $permalink_manager_options['general']['trailing_slashes'] > 1) {
435
  $redirect_url = false;
436
  }
458
  }
459
  }
460
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
461
  }
 
includes/core/permalink-manager-helper-functions.php CHANGED
@@ -33,6 +33,7 @@ class Permalink_Manager_Helper_Functions extends Permalink_Manager_Class {
33
  if($permalink_manager_options['general']['yoast_primary_term'] == 1 && class_exists('WPSEO_Primary_Term')) {
34
  $primary_term = new WPSEO_Primary_Term($taxonomy, $post_id);
35
  $primary_term = get_term($primary_term->get_primary_term());
 
36
  if(!is_wp_error($primary_term)) {
37
  return ($slug_only) ? $primary_term->slug : $primary_term;
38
  }
@@ -40,11 +41,43 @@ class Permalink_Manager_Helper_Functions extends Permalink_Manager_Class {
40
  return '';
41
  }
42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  /**
44
  * Get post_types array
45
  */
46
- static function get_post_types_array($format = null, $cpt = null) {
47
- $post_types = apply_filters('permalink-manager-post-types', get_post_types( array('public' => true), 'objects'));
 
48
 
49
  $post_types_array = array();
50
  if($format == 'full') {
@@ -57,14 +90,22 @@ class Permalink_Manager_Helper_Functions extends Permalink_Manager_Class {
57
  }
58
  }
59
 
 
 
 
 
 
 
 
60
  return (empty($cpt)) ? $post_types_array : $post_types_array[$cpt];
61
  }
62
 
63
  /**
64
  * Get array with all taxonomies
65
  */
66
- static function get_taxonomies_array($format = null, $tax = null, $prefix = false) {
67
- $taxonomies = apply_filters('permalink-manager-taxonomies', get_taxonomies(array('public' => true, 'rewrite' => true), 'objects'));
 
68
 
69
  $taxonomies_array = array();
70
 
@@ -77,6 +118,13 @@ class Permalink_Manager_Helper_Functions extends Permalink_Manager_Class {
77
  }
78
  }
79
 
 
 
 
 
 
 
 
80
  return (empty($tax)) ? $taxonomies_array : $taxonomies_array[$tax];
81
  }
82
 
@@ -98,6 +146,24 @@ class Permalink_Manager_Helper_Functions extends Permalink_Manager_Class {
98
  return ($remove_post_tag) ? trim(str_replace(array("%postname%", "%pagename%", "%{$post_type}%"), "", $permastruct), "/") : $permastruct;
99
  }
100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  /**
102
  * Remove post tag from permastructure
103
  */
@@ -227,7 +293,7 @@ class Permalink_Manager_Helper_Functions extends Permalink_Manager_Class {
227
  /**
228
  * Force custom slugs
229
  */
230
- public static function force_custom_slugs($slug, $object) {
231
  global $permalink_manager_options;
232
 
233
  if(!empty($permalink_manager_options['general']['force_custom_slugs'])) {
@@ -237,7 +303,59 @@ class Permalink_Manager_Helper_Functions extends Permalink_Manager_Class {
237
  $slug = ($old_slug != $new_slug) ? str_replace($old_slug, $new_slug, $slug) : $slug;
238
  }
239
 
 
 
 
 
240
  return $slug;
241
  }
242
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
243
  }
33
  if($permalink_manager_options['general']['yoast_primary_term'] == 1 && class_exists('WPSEO_Primary_Term')) {
34
  $primary_term = new WPSEO_Primary_Term($taxonomy, $post_id);
35
  $primary_term = get_term($primary_term->get_primary_term());
36
+
37
  if(!is_wp_error($primary_term)) {
38
  return ($slug_only) ? $primary_term->slug : $primary_term;
39
  }
41
  return '';
42
  }
43
 
44
+ /**
45
+ * Allow to disable post types and taxonomies
46
+ */
47
+ static function get_disabled_post_types() {
48
+ global $permalink_manager_options;
49
+
50
+ $disabled_post_types = (!empty($permalink_manager_options['general']['partial_disable']['post_types'])) ? (array) $permalink_manager_options['general']['partial_disable']['post_types'] : array();
51
+ return apply_filters('permalink-manager-disabled-post-types', $disabled_post_types);
52
+ }
53
+
54
+ static function get_disabled_taxonomies() {
55
+ global $permalink_manager_options;
56
+
57
+ $disabled_taxonomies = (!empty($permalink_manager_options['general']['partial_disable']['taxonomies'])) ? (array) $permalink_manager_options['general']['partial_disable']['taxonomies'] : array();
58
+ return apply_filters('permalink-manager-disabled-taxonomies', $disabled_taxonomies);
59
+ }
60
+
61
+ static public function is_disabled($content_name, $content_type = 'post_type') {
62
+ $out = false;
63
+
64
+ if($content_type == 'post_type') {
65
+ $disabled_post_types = self::get_disabled_post_types();
66
+ $out = (is_array($disabled_post_types) && in_array($content_name, $disabled_post_types)) ? true : false;
67
+ } else {
68
+ $disabled_taxonomies = self::get_disabled_taxonomies();
69
+ $out = (is_array($disabled_taxonomies) && in_array($content_name, $disabled_taxonomies)) ? true : false;
70
+ }
71
+
72
+ return $out;
73
+ }
74
+
75
  /**
76
  * Get post_types array
77
  */
78
+ static function get_post_types_array($format = null, $cpt = null, $all = false) {
79
+ $post_types = get_post_types(array('public' => true), 'objects');
80
+ $disabled_post_types = self::get_disabled_post_types();
81
 
82
  $post_types_array = array();
83
  if($format == 'full') {
90
  }
91
  }
92
 
93
+ // Disable post types
94
+ if(!$all && is_array($disabled_post_types)) {
95
+ foreach($disabled_post_types as $post_type) {
96
+ if(!empty($post_types_array[$post_type])) { unset($post_types_array[$post_type]); }
97
+ }
98
+ }
99
+
100
  return (empty($cpt)) ? $post_types_array : $post_types_array[$cpt];
101
  }
102
 
103
  /**
104
  * Get array with all taxonomies
105
  */
106
+ static function get_taxonomies_array($format = null, $tax = null, $prefix = false, $all = false) {
107
+ $taxonomies = get_taxonomies(array('public' => true, 'rewrite' => true), 'objects');
108
+ $disabled_taxonomies = self::get_disabled_taxonomies();
109
 
110
  $taxonomies_array = array();
111
 
118
  }
119
  }
120
 
121
+ // Disable taxonomies
122
+ if(!$all && is_array($disabled_taxonomies)) {
123
+ foreach($disabled_taxonomies as $taxonomy) {
124
+ if(!empty($taxonomies_array[$taxonomy])) { unset($taxonomies_array[$taxonomy]); }
125
+ }
126
+ }
127
+
128
  return (empty($tax)) ? $taxonomies_array : $taxonomies_array[$tax];
129
  }
130
 
146
  return ($remove_post_tag) ? trim(str_replace(array("%postname%", "%pagename%", "%{$post_type}%"), "", $permastruct), "/") : $permastruct;
147
  }
148
 
149
+ /**
150
+ * Get all endpoints
151
+ */
152
+ static function get_endpoints() {
153
+ global $wp_rewrite;
154
+
155
+ // Start with default endpoints
156
+ $endpoints = "page|feed|embed|attachment|track|filter";
157
+
158
+ if(!empty($wp_rewrite->endpoints)) {
159
+ foreach($wp_rewrite->endpoints as $endpoint) {
160
+ $endpoints .= "|{$endpoint[1]}";
161
+ }
162
+ }
163
+
164
+ return apply_filters("permalink-manager-endpoints", str_replace("/", "\/", $endpoints));
165
+ }
166
+
167
  /**
168
  * Remove post tag from permastructure
169
  */
293
  /**
294
  * Force custom slugs
295
  */
296
+ public static function force_custom_slugs($slug, $object, $flat = false) {
297
  global $permalink_manager_options;
298
 
299
  if(!empty($permalink_manager_options['general']['force_custom_slugs'])) {
303
  $slug = ($old_slug != $new_slug) ? str_replace($old_slug, $new_slug, $slug) : $slug;
304
  }
305
 
306
+ if($flat) {
307
+ $slug = preg_replace("/([^\/]+)(.*)/", "$1", $slug);
308
+ }
309
+
310
  return $slug;
311
  }
312
 
313
+ public static function element_exists($element_id) {
314
+ global $wpdb;
315
+
316
+ if(strpos($element_id, 'tax-') !== false) {
317
+ $term_id = intval(preg_replace("/[^0-9]/", "", $element_id));
318
+ $element_exists = $wpdb->get_var( "SELECT * FROM {$wpdb->prefix}terms WHERE term_id = {$term_id}" );
319
+ } else {
320
+ $element_exists = $wpdb->get_var( "SELECT * FROM {$wpdb->prefix}posts WHERE ID = {$element_id} AND post_status NOT IN ('auto-draft', 'trash') AND post_type != 'nav_menu_item'" );
321
+ }
322
+
323
+ return (!empty($element_exists)) ? $element_exists : false;
324
+ }
325
+
326
+ /**
327
+ * Detect duplicates
328
+ */
329
+ public static function get_all_duplicates() {
330
+ global $permalink_manager_uris, $permalink_manager_redirects, $permalink_manager_options, $wpdb;
331
+
332
+ // Make sure that both variables are arrays
333
+ $all_uris = (is_array($permalink_manager_uris)) ? $permalink_manager_uris : array();
334
+ $permalink_manager_redirects = (is_array($permalink_manager_redirects)) ? $permalink_manager_redirects : array();
335
+
336
+ // Convert redirects list, so it can be merged with $permalink_manager_uris
337
+ foreach($permalink_manager_redirects as $element_id => $redirects) {
338
+ if(is_array($redirects)) {
339
+ foreach($redirects as $index => $uri) {
340
+ $all_uris["redirect-{$index}_{$element_id}"] = $uri;
341
+ }
342
+ }
343
+ }
344
+
345
+ // Count duplicates
346
+ $duplicates_removed = 0;
347
+ $duplicates_groups = array();
348
+ $duplicates_list = array_count_values($all_uris);
349
+ $duplicates_list = array_filter($duplicates_list, function ($x) { return $x >= 2; });
350
+
351
+ // Assign keys to duplicates (group them)
352
+ if(count($duplicates_list) > 0) {
353
+ foreach($duplicates_list as $duplicated_uri => $count) {
354
+ $duplicates_groups[$duplicated_uri] = array_keys($all_uris, $duplicated_uri);
355
+ }
356
+ }
357
+
358
+ return $duplicates_groups;
359
+ }
360
+
361
  }
includes/core/permalink-manager-third-parties.php CHANGED
@@ -54,7 +54,6 @@ class Permalink_Manager_Third_Parties extends Permalink_Manager_Class {
54
 
55
  // 6. WooCommerce
56
  if(class_exists('WooCommerce')) {
57
- add_filter('permalink-manager-endpoints', array($this, 'woocommerce_endpoints'), 0, 1);
58
  add_filter('request', array($this, 'woocommerce_detect'), 9, 1);
59
  add_filter('template_redirect', array($this, 'woocommerce_checkout_fix'), 9);
60
  }
@@ -88,7 +87,8 @@ class Permalink_Manager_Third_Parties extends Permalink_Manager_Class {
88
  if(!empty($sitepress_settings['active_languages'])) {
89
  $languages_list = implode("|", $sitepress_settings['active_languages']);
90
  //preg_match("/^(?:(\w{2})\/)?(.+?)(?:\/({$endpoints}))?(?:\/([\d+]))?\/?$/i", $request_url, $regex_parts);
91
- preg_match("/^(?:({$languages_list})\/)?(.+?)(?:\/({$endpoints}))?(?:\/([\d]+))?\/?$/i", $request_url, $regex_parts);
 
92
 
93
  $uri_parts['lang'] = (!empty($regex_parts[1])) ? $regex_parts[1] : "";
94
  $uri_parts['uri'] = (!empty($regex_parts[2])) ? $regex_parts[2] : "";
@@ -205,6 +205,8 @@ class Permalink_Manager_Third_Parties extends Permalink_Manager_Class {
205
  global $wpdb, $permalink_manager_uris;
206
 
207
  $uri = (!empty($uri_parts['uri'])) ? $uri_parts['uri'] : "";
 
 
208
 
209
  if(empty($item_id) && $uri) {
210
  $slug = basename($uri_parts['uri']);
@@ -212,11 +214,13 @@ class Permalink_Manager_Third_Parties extends Permalink_Manager_Class {
212
  // Check if slug is already used by any post or term
213
  $used_by_post = $wpdb->get_row($wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_status = %s AND post_name = %s", "publish", $slug ), ARRAY_A);
214
  $used_by_term = ($used_by_post) ? true : $wpdb->get_row($wpdb->prepare( "SELECT term_id FROM {$wpdb->terms} WHERE slug = %s", $slug ), ARRAY_A);
 
 
 
215
 
216
- if(empty($used_by_post) && empty($used_by_term)) {
217
- $attachment = $wpdb->get_row($wpdb->prepare( "SELECT ID, post_name FROM {$wpdb->posts} WHERE post_type = %s AND post_name = %s", "attachment", $slug ), ARRAY_A);
218
- $item_id = (!empty($attachment['ID'])) ? $attachment['ID'] : $item_id;
219
- }
220
  }
221
 
222
  return $item_id;
@@ -300,23 +304,6 @@ class Permalink_Manager_Third_Parties extends Permalink_Manager_Class {
300
  update_option('permalink-manager-uris', $permalink_manager_uris);
301
  }
302
 
303
- /**
304
- * WooCommerce
305
- */
306
- function woocommerce_endpoints($endpoints) {
307
- global $woocommerce;
308
-
309
- if(!empty($woocommerce->query->query_vars)) {
310
- $query_vars = $woocommerce->query->query_vars;
311
-
312
- foreach($query_vars as $key => $val) {
313
- $endpoints .= "|{$val}";
314
- }
315
- }
316
-
317
- return $endpoints;
318
- }
319
-
320
  function woocommerce_detect($query) {
321
  global $woocommerce, $pm_item_id;
322
 
54
 
55
  // 6. WooCommerce
56
  if(class_exists('WooCommerce')) {
 
57
  add_filter('request', array($this, 'woocommerce_detect'), 9, 1);
58
  add_filter('template_redirect', array($this, 'woocommerce_checkout_fix'), 9);
59
  }
87
  if(!empty($sitepress_settings['active_languages'])) {
88
  $languages_list = implode("|", $sitepress_settings['active_languages']);
89
  //preg_match("/^(?:(\w{2})\/)?(.+?)(?:\/({$endpoints}))?(?:\/([\d+]))?\/?$/i", $request_url, $regex_parts);
90
+
91
+ preg_match("/^(?:({$languages_list})\/)?(.+?)(?|\/({$endpoints})\/([^\/]+)|\/()([\d+]))?\/?$/i", $request_url, $regex_parts);
92
 
93
  $uri_parts['lang'] = (!empty($regex_parts[1])) ? $regex_parts[1] : "";
94
  $uri_parts['uri'] = (!empty($regex_parts[2])) ? $regex_parts[2] : "";
205
  global $wpdb, $permalink_manager_uris;
206
 
207
  $uri = (!empty($uri_parts['uri'])) ? $uri_parts['uri'] : "";
208
+ $endpoint = (!empty($uri_parts['endpoint'])) ? $uri_parts['endpoint'] : "";
209
+ $endpoint_value = (!empty($uri_parts['endpoint_value'])) ? $uri_parts['endpoint_value'] : "";
210
 
211
  if(empty($item_id) && $uri) {
212
  $slug = basename($uri_parts['uri']);
214
  // Check if slug is already used by any post or term
215
  $used_by_post = $wpdb->get_row($wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_status = %s AND post_name = %s", "publish", $slug ), ARRAY_A);
216
  $used_by_term = ($used_by_post) ? true : $wpdb->get_row($wpdb->prepare( "SELECT term_id FROM {$wpdb->terms} WHERE slug = %s", $slug ), ARRAY_A);
217
+ } else if($endpoint == 'attachment' && !empty($endpoint_value)) {
218
+ $slug = $endpoint_value;
219
+ }
220
 
221
+ if(!empty($slug)) {
222
+ $attachment = $wpdb->get_row($wpdb->prepare( "SELECT ID, post_name FROM {$wpdb->posts} WHERE post_type = %s AND post_name = %s", "attachment", $slug ), ARRAY_A);
223
+ $item_id = (!empty($attachment['ID'])) ? $attachment['ID'] : $item_id;
 
224
  }
225
 
226
  return $item_id;
304
  update_option('permalink-manager-uris', $permalink_manager_uris);
305
  }
306
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
307
  function woocommerce_detect($query) {
308
  global $woocommerce, $pm_item_id;
309
 
includes/core/permalink-manager-uri-functions-post.php CHANGED
@@ -23,7 +23,7 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
23
  add_action( 'save_post', array($this, 'update_post_uri'), 999, 1);
24
  add_action( 'edit_attachment', array($this, 'update_post_uri'), 999, 1 );
25
  add_action( 'wp_insert_post', array($this, 'new_post_uri'), 999, 1 );
26
- add_action( 'wp_trash_post', array($this, 'remove_post_uri'), 10, 1 );
27
 
28
  add_action( 'quick_edit_custom_box', array($this, 'quick_edit_column_form'), 999, 3);
29
  }
@@ -32,17 +32,17 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
32
  * Init
33
  */
34
  function admin_init() {
35
- $post_types = get_post_types(array('public' => true, '_builtin' => false), 'names', 'and');
36
 
37
  // Add "URI Editor" to "Quick Edit" for all post_types
38
  foreach($post_types as $post_type) {
 
 
 
 
39
  add_filter( "manage_{$post_type}_columns" , array($this, 'quick_edit_column') );
40
  add_filter( "manage_{$post_type}_custom_column" , array($this, 'quick_edit_column_content'), 10, 2 );
41
  }
42
- add_filter( "manage_posts_columns" , array($this, 'quick_edit_column') );
43
- add_filter( "manage_pages_columns" , array($this, 'quick_edit_column') );
44
- add_filter( "manage_posts_custom_column" , array($this, 'quick_edit_column_content'), 10, 2 );
45
- add_filter( "manage_pages_custom_column" , array($this, 'quick_edit_column_content'), 10, 2 );
46
  }
47
 
48
  /**
@@ -52,18 +52,20 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
52
  global $wp_rewrite, $permalink_manager_uris, $permalink_manager_options;
53
 
54
  $post = (is_integer($post)) ? get_post($post) : $post;
55
- $post_type = $post->post_type;
56
 
57
- // 1A. Do not change permalink of frontpage
 
 
 
58
  if(get_option('page_on_front') == $post->ID) {
59
  return $permalink;
60
  }
61
- // 1B. Do not change permalink for drafts and future posts (+ remove trailing slash from them)
62
  else if(in_array($post->post_status, array('draft', 'pending', 'auto-draft', 'future'))) {
63
  return trim($permalink, "/");
64
  }
65
 
66
- // 2. Filter only the posts with custom permalink assigned
67
  if(isset($permalink_manager_uris[$post->ID])) {
68
  // Apend the language code as a non-editable prefix (can be used also for another prefixes)
69
  $prefix = apply_filters('permalink-manager-post-permalink-prefix', '', $post);
@@ -80,7 +82,7 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
80
  $permalink = urldecode($permalink);
81
  }
82
 
83
- // 3. Additional filter
84
  $permalink = apply_filters('permalink_manager_filter_final_post_permalink', user_trailingslashit($permalink), $post);
85
 
86
  return $permalink;
@@ -135,18 +137,14 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
135
  } else {
136
  $permastruct = (isset($permalink_manager_permastructs['post_types'][$post_type])) ? $permalink_manager_permastructs['post_types'][$post_type] : $default_permastruct;
137
  }
138
-
139
  $default_base = (!empty($permastruct)) ? trim($permastruct, '/') : "";
140
 
141
- // Check if the slug should not be appended
142
- $dont_append_slug = (!$native_uri && !empty($permalink_manager_options['general']['disable_slug_appendix']) && in_array($post_type, $permalink_manager_options['general']['disable_slug_appendix'])) ? true : false;
143
-
144
  // 1A. Get the date
145
  $date = explode(" ", date('Y m d H i s', strtotime($post->post_date)));
146
 
147
  // 1B. Get the author (if needed)
148
  $author = '';
149
- if ( strpos($default_base, '%author%') !== false ) {
150
  $authordata = get_userdata($post->post_author);
151
  $author = $authordata->user_nicename;
152
  }
@@ -155,22 +153,33 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
155
  $full_slug = get_page_uri($post);
156
  $full_slug = (empty($full_slug)) ? $post_name : $full_slug;
157
 
 
158
  if(!$native_uri) {
159
- // 2C. Allow filter the default slug
160
  $full_slug = ($native_uri) ? $full_slug : Permalink_Manager_Helper_Functions::force_custom_slugs($full_slug, $post);
161
  $full_slug = apply_filters('permalink_manager_filter_default_post_slug', $full_slug, $post, $post_name);
162
  }
163
  $post_type_tag = Permalink_Manager_Helper_Functions::get_post_tag($post_type);
164
 
165
- // 3A. Do the replacement (post tag is removed now to enable support for hierarchical CPT)
166
- $tags = array('%year%', '%monthnum%', '%day%', '%hour%', '%minute%', '%second%', '%post_id%', '%author%', $post_type_tag, '%postname%', '%postname_flat%');
 
 
 
 
 
 
 
 
 
 
 
 
167
 
168
- if($dont_append_slug) {
169
- $replacements = array($date[0], $date[1], $date[2], $date[3], $date[4], $date[5], $post->ID, $author, $full_slug, $full_slug, $post_name);
170
- $default_uri = str_replace($tags, $replacements, "{$default_base}");
171
  } else {
172
- $replacements = array($date[0], $date[1], $date[2], $date[3], $date[4], $date[5], $post->ID, $author, '', '', '');
173
- $default_uri = str_replace($tags, $replacements, "{$default_base}/{$full_slug}");
174
  }
175
 
176
  // 3B. Replace taxonomies
@@ -182,7 +191,7 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
182
  $replacement = $terms = $replacement_term = "";
183
 
184
  // 2. Try to use Yoast SEO Primary Term
185
- $replacement_term = Permalink_Manager_Helper_Functions::get_primary_term($post->ID, $taxonomy, false);
186
 
187
  // 3. Get the first assigned term to this taxonomy
188
  if(empty($replacement_term)) {
@@ -190,6 +199,7 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
190
  $replacement_term = (!is_wp_error($terms) && !empty($terms) && is_object($terms[0])) ? $terms[0] : "";
191
  }
192
 
 
193
  if(!empty($replacement_term->term_id) && strpos($default_uri, "%{$taxonomy}_custom_uri%") !== false && !empty($permalink_manager_uris["tax-{$replacement_term->term_id}"])) {
194
  $replacement = $permalink_manager_uris["tax-{$replacement_term->term_id}"];
195
  }
@@ -209,7 +219,16 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
209
  $last_term_slug = ($native_uri) ? $replacement_term->slug : Permalink_Manager_Helper_Functions::force_custom_slugs($replacement_term->slug, $replacement_term);
210
  $replacement = "{$replacement}/{$last_term_slug}";
211
  }
212
- // 4C. Flat taxonomy base
 
 
 
 
 
 
 
 
 
213
  else if(!empty($replacement_term->slug)) {
214
  $replacement = ($native_uri) ? $replacement_term->slug : Permalink_Manager_Helper_Functions::force_custom_slugs($replacement_term->slug, $replacement_term);
215
  }
@@ -512,6 +531,9 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
512
  // Do not do anything if new slug is empty or page is front-page
513
  if(get_option('page_on_front') == $id) { return $html; }
514
 
 
 
 
515
  $html = preg_replace("/(<strong>(.*)<\/strong>)(.*)/is", "$1 ", $html);
516
  $default_uri = self::get_default_post_uri($id);
517
  $native_uri = self::get_default_post_uri($id, true);
@@ -590,8 +612,12 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
590
  // Fix for revisions
591
  $is_revision = wp_is_post_revision($post_id);
592
  $post_id = ($is_revision) ? $is_revision : $post_id;
 
593
  $post = get_post($post_id);
594
 
 
 
 
595
  // Continue only if no custom URI is already assigned
596
  if(!empty($permalink_manager_uris[$post_id])) { return $post_id; }
597
 
@@ -630,8 +656,11 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
630
  $post_id = ($is_revision) ? $is_revision : $post_id;
631
  $post = get_post($post_id);
632
 
 
 
 
633
  // Hotfix for menu items
634
- if($post->post_type == 'nav_menu_item') { return; }
635
 
636
  // Ignore auto-drafts & removed posts
637
  if(in_array($post->post_status, array('auto-draft', 'trash'))) { return; }
@@ -660,7 +689,7 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
660
  update_option('permalink-manager-uris', $permalink_manager_uris);
661
  }
662
 
663
- do_action('permalink-manager-updated-post-uri', $post_id, $new_uri, $old_uri, $native_uri, $default_uri);
664
  }
665
 
666
  /**
23
  add_action( 'save_post', array($this, 'update_post_uri'), 999, 1);
24
  add_action( 'edit_attachment', array($this, 'update_post_uri'), 999, 1 );
25
  add_action( 'wp_insert_post', array($this, 'new_post_uri'), 999, 1 );
26
+ //add_action( 'wp_trash_post', array($this, 'remove_post_uri'), 10, 1 );
27
 
28
  add_action( 'quick_edit_custom_box', array($this, 'quick_edit_column_form'), 999, 3);
29
  }
32
  * Init
33
  */
34
  function admin_init() {
35
+ $post_types = get_post_types(array('public' => true), 'names', 'and');
36
 
37
  // Add "URI Editor" to "Quick Edit" for all post_types
38
  foreach($post_types as $post_type) {
39
+ // Check if post type is allowed
40
+ if(Permalink_Manager_Helper_Functions::is_disabled($post_type, 'post_type')) { continue; }
41
+
42
+ $post_type = ($post_type == 'post' || $post_type == 'page') ? "{$post_type}s" : $post_type;
43
  add_filter( "manage_{$post_type}_columns" , array($this, 'quick_edit_column') );
44
  add_filter( "manage_{$post_type}_custom_column" , array($this, 'quick_edit_column_content'), 10, 2 );
45
  }
 
 
 
 
46
  }
47
 
48
  /**
52
  global $wp_rewrite, $permalink_manager_uris, $permalink_manager_options;
53
 
54
  $post = (is_integer($post)) ? get_post($post) : $post;
 
55
 
56
+ // 1. Check if post type is allowed
57
+ if(!empty($post->post_type) && Permalink_Manager_Helper_Functions::is_disabled($post->post_type, 'post_type')) { return $permalink; }
58
+
59
+ // 2A. Do not change permalink of frontpage
60
  if(get_option('page_on_front') == $post->ID) {
61
  return $permalink;
62
  }
63
+ // 2B. Do not change permalink for drafts and future posts (+ remove trailing slash from them)
64
  else if(in_array($post->post_status, array('draft', 'pending', 'auto-draft', 'future'))) {
65
  return trim($permalink, "/");
66
  }
67
 
68
+ // 3. Filter only the posts with custom permalink assigned
69
  if(isset($permalink_manager_uris[$post->ID])) {
70
  // Apend the language code as a non-editable prefix (can be used also for another prefixes)
71
  $prefix = apply_filters('permalink-manager-post-permalink-prefix', '', $post);
82
  $permalink = urldecode($permalink);
83
  }
84
 
85
+ // 4. Additional filter
86
  $permalink = apply_filters('permalink_manager_filter_final_post_permalink', user_trailingslashit($permalink), $post);
87
 
88
  return $permalink;
137
  } else {
138
  $permastruct = (isset($permalink_manager_permastructs['post_types'][$post_type])) ? $permalink_manager_permastructs['post_types'][$post_type] : $default_permastruct;
139
  }
 
140
  $default_base = (!empty($permastruct)) ? trim($permastruct, '/') : "";
141
 
 
 
 
142
  // 1A. Get the date
143
  $date = explode(" ", date('Y m d H i s', strtotime($post->post_date)));
144
 
145
  // 1B. Get the author (if needed)
146
  $author = '';
147
+ if(strpos($default_base, '%author%') !== false) {
148
  $authordata = get_userdata($post->post_author);
149
  $author = $authordata->user_nicename;
150
  }
153
  $full_slug = get_page_uri($post);
154
  $full_slug = (empty($full_slug)) ? $post_name : $full_slug;
155
 
156
+ // 2B. Allow filter the default slug
157
  if(!$native_uri) {
 
158
  $full_slug = ($native_uri) ? $full_slug : Permalink_Manager_Helper_Functions::force_custom_slugs($full_slug, $post);
159
  $full_slug = apply_filters('permalink_manager_filter_default_post_slug', $full_slug, $post, $post_name);
160
  }
161
  $post_type_tag = Permalink_Manager_Helper_Functions::get_post_tag($post_type);
162
 
163
+ // 3A. Get the standard tags and replace them with their values
164
+ $tags = array('%year%', '%monthnum%', '%day%', '%hour%', '%minute%', '%second%', '%post_id%', '%author%');
165
+ $tags_replacements = array($date[0], $date[1], $date[2], $date[3], $date[4], $date[5], $post->ID, $author);
166
+ $default_uri = str_replace($tags, $tags_replacements, $default_base);
167
+
168
+ // 3B. Check if any post tag is present in custom permastructure
169
+ $slug_tags = array($post_type_tag, '%postname%', '%postname_flat%');
170
+ $slug_tags_replacement = array($full_slug, $full_slug, $post_name);
171
+ foreach($slug_tags as $tag) {
172
+ if(strpos($default_uri, $tag) !== false) {
173
+ $do_not_append_slug = true;
174
+ break;
175
+ }
176
+ }
177
 
178
+ // 3C. Replace the post tags with slugs or rppend the slug if no post tag is defined
179
+ if(!empty($do_not_append_slug)) {
180
+ $default_uri = str_replace($slug_tags, $slug_tags_replacement, $default_uri);
181
  } else {
182
+ $default_uri .= "/{$full_slug}";
 
183
  }
184
 
185
  // 3B. Replace taxonomies
191
  $replacement = $terms = $replacement_term = "";
192
 
193
  // 2. Try to use Yoast SEO Primary Term
194
+ $replacement_term = $primary_term = Permalink_Manager_Helper_Functions::get_primary_term($post->ID, $taxonomy, false);
195
 
196
  // 3. Get the first assigned term to this taxonomy
197
  if(empty($replacement_term)) {
199
  $replacement_term = (!is_wp_error($terms) && !empty($terms) && is_object($terms[0])) ? $terms[0] : "";
200
  }
201
 
202
+ // 4A. Get permalink base from the term's custom URI
203
  if(!empty($replacement_term->term_id) && strpos($default_uri, "%{$taxonomy}_custom_uri%") !== false && !empty($permalink_manager_uris["tax-{$replacement_term->term_id}"])) {
204
  $replacement = $permalink_manager_uris["tax-{$replacement_term->term_id}"];
205
  }
219
  $last_term_slug = ($native_uri) ? $replacement_term->slug : Permalink_Manager_Helper_Functions::force_custom_slugs($replacement_term->slug, $replacement_term);
220
  $replacement = "{$replacement}/{$last_term_slug}";
221
  }
222
+ // 4C. Force flat taxonomy base - get highgest level term (if %taxonomy_flat% tag is used)
223
+ else if(!$native_uri && strpos($default_uri, "%{$taxonomy}_flat%") !== false && !empty($terms) && empty($primary_term->slug)) {
224
+ foreach ($terms as $single_term) {
225
+ if ($single_term->parent == 0) {
226
+ $replacement = Permalink_Manager_Helper_Functions::force_custom_slugs($single_term->slug, $single_term);
227
+ break;
228
+ }
229
+ }
230
+ }
231
+ // 4D. Flat/non-hierarchical taxonomy base - get primary term (if set) or first term
232
  else if(!empty($replacement_term->slug)) {
233
  $replacement = ($native_uri) ? $replacement_term->slug : Permalink_Manager_Helper_Functions::force_custom_slugs($replacement_term->slug, $replacement_term);
234
  }
531
  // Do not do anything if new slug is empty or page is front-page
532
  if(get_option('page_on_front') == $id) { return $html; }
533
 
534
+ // Check if post type is disabled
535
+ if(Permalink_Manager_Helper_Functions::is_disabled($post->post_type, 'post_type')) { return $html; }
536
+
537
  $html = preg_replace("/(<strong>(.*)<\/strong>)(.*)/is", "$1 ", $html);
538
  $default_uri = self::get_default_post_uri($id);
539
  $native_uri = self::get_default_post_uri($id, true);
612
  // Fix for revisions
613
  $is_revision = wp_is_post_revision($post_id);
614
  $post_id = ($is_revision) ? $is_revision : $post_id;
615
+
616
  $post = get_post($post_id);
617
 
618
+ // Check if post type is allowed
619
+ if(Permalink_Manager_Helper_Functions::is_disabled($post->post_type, 'post_type')) { return $post_id; };
620
+
621
  // Continue only if no custom URI is already assigned
622
  if(!empty($permalink_manager_uris[$post_id])) { return $post_id; }
623
 
656
  $post_id = ($is_revision) ? $is_revision : $post_id;
657
  $post = get_post($post_id);
658
 
659
+ // Check if post type is allowed
660
+ if(Permalink_Manager_Helper_Functions::is_disabled($post->post_type, 'post_type')) { return $post_id; };
661
+
662
  // Hotfix for menu items
663
+ if($post->post_type == 'nav_menu_item') { return $post_id; }
664
 
665
  // Ignore auto-drafts & removed posts
666
  if(in_array($post->post_status, array('auto-draft', 'trash'))) { return; }
689
  update_option('permalink-manager-uris', $permalink_manager_uris);
690
  }
691
 
692
+ do_action('permalink-manager-updated-post-uri', $post_id, $new_uri, $old_uri, $native_uri, $default_uri, $single_update = true);
693
  }
694
 
695
  /**
includes/views/permalink-manager-permastructs.php CHANGED
@@ -61,7 +61,7 @@ class Permalink_Manager_Permastructs extends Permalink_Manager_Class {
61
  // 3. Append fields for all post types
62
  foreach($all_post_types as $post_type) {
63
 
64
- $default_permastruct = Permalink_Manager_Helper_Functions::get_default_permastruct($post_type['name'], true);
65
  $current_permastruct = isset($permalink_manager_permastructs['post_types'][$post_type['name']]) ? $permalink_manager_permastructs['post_types'][$post_type['name']] : $default_permastruct;
66
 
67
  $fields["post_types"]["fields"][$post_type['name']] = array(
61
  // 3. Append fields for all post types
62
  foreach($all_post_types as $post_type) {
63
 
64
+ $default_permastruct = trim(Permalink_Manager_Helper_Functions::get_default_permastruct($post_type['name']), "/");
65
  $current_permastruct = isset($permalink_manager_permastructs['post_types'][$post_type['name']]) ? $permalink_manager_permastructs['post_types'][$post_type['name']] : $default_permastruct;
66
 
67
  $fields["post_types"]["fields"][$post_type['name']] = array(
includes/views/permalink-manager-settings.php CHANGED
@@ -24,9 +24,9 @@ class Permalink_Manager_Settings extends Permalink_Manager_Class {
24
  public function output() {
25
  // Get all registered post types array & statuses
26
  $all_post_statuses_array = get_post_statuses();
27
- $all_post_types = Permalink_Manager_Helper_Functions::get_post_types_array();
28
- $all_taxonomies = Permalink_Manager_Helper_Functions::get_taxonomies_array(false, false, true);
29
- $content_types = (defined('PERMALINK_MANAGER_PRO')) ? array_merge($all_post_types, $all_taxonomies) : $all_post_types;
30
 
31
  $sections_and_fields = apply_filters('permalink-manager-settings-fields', array(
32
  'general' => array(
@@ -36,15 +36,15 @@ class Permalink_Manager_Settings extends Permalink_Manager_Class {
36
  'fields' => array(
37
  'auto_update_uris' => array(
38
  'type' => 'single_checkbox',
39
- 'label' => __('Auto-update URIs', 'permalink-manager'),
40
  'input_class' => '',
41
- 'description' => __('If enabled, the custom URIs will be automatically updated every time the post is saved or updated.', 'permalink-manager')
42
  ),
43
  'case_insensitive_permalinks' => array(
44
  'type' => 'single_checkbox',
45
- 'label' => __('Case insensitive URIs', 'permalink-manager'),
46
  'input_class' => '',
47
- 'description' => __('Make the permalinks case-insensitive.', 'permalink-manager')
48
  )
49
  )
50
  ),
@@ -76,7 +76,7 @@ class Permalink_Manager_Settings extends Permalink_Manager_Class {
76
  'label' => __('Redirect', 'permalink-manager'),
77
  'input_class' => 'settings-select',
78
  'choices' => array(0 => __('Disable', 'permalink-manager'), "301" => __('Enable "301 redirect"', 'permalink-manager'), "302" => __('Enable "302 redirect"', 'permalink-manager')),
79
- 'description' => __('If enabled - the visitors will be redirected from native permalinks to your custom permalinks.<br /><strong>Only native permalinks & extra redirects will be redirected to new custom URIs</strong>.', 'permalink-manager')
80
  )
81
  )
82
  ),
@@ -87,31 +87,25 @@ class Permalink_Manager_Settings extends Permalink_Manager_Class {
87
  'fields' => array(
88
  'setup_redirects' => array(
89
  'type' => 'single_checkbox',
90
- 'label' => __('Add redirects for old URIs', 'permalink-manager'),
91
  'input_class' => '',
92
  'pro' => true,
93
  'disabled' => true,
94
- 'description' => __('If enabled, the redirects will be automatially created for old custom permalinks.', 'permalink-manager')
95
  ),
96
  'auto_remove_duplicates' => array(
97
  'type' => 'single_checkbox',
98
  'label' => __('Automatically remove duplicates', 'permalink-manager'),
99
  'input_class' => '',
100
- 'description' => __('If enabled, the duplicated redirects & custom URIs will be automatically removed.', 'permalink-manager')
101
  ),
102
  'force_custom_slugs' => array(
103
  'type' => 'single_checkbox',
104
  'label' => __('Force custom slugs', 'permalink-manager'),
105
  'input_class' => '',
106
- 'description' => __('If enabled, the native slugs in the defult URIs will be recreated from the post title.<br />This may cause URI duplicates when the post title is used more than once.', 'permalink-manager')
107
  ),
108
- 'disable_slug_appendix' => array(
109
- 'type' => 'checkbox',
110
- 'label' => __('Disable slug appendix', 'permalink-manager'),
111
- 'choices' => $content_types,
112
- 'description' => __('The slugs will not be automatically apended to the end of permastructure in the default permalinks for selected post types & taxonomies.<br />Works correctly only if <strong>"Force custom slugs" is disabled!</strong>', 'permalink-manager')
113
- ),
114
- 'deep_detect' => array(
115
  'type' => 'single_checkbox',
116
  'label' => __('Enable "Deep detect"', 'permalink-manager'),
117
  'description' => __('Please keep it enabled if your custom URIs end with numerals, e.g. <strong>example.com/projects/20171025</strong> or if $_GET parameters should be detected as endpoints e.g. <strong>?page=1</strong>.', 'permalink-manager')
@@ -121,14 +115,20 @@ class Permalink_Manager_Settings extends Permalink_Manager_Class {
121
  'label' => __('Decode URIs', 'permalink-manager'),
122
  'input_class' => '',
123
  'description' => __('If enabled, the permalinks with non-ASCII characters may not be recognized in older browsers versions (advanced users only).', 'permalink-manager')
124
- ),
125
  'trailing_slashes' => array(
126
  'type' => 'select',
127
  'label' => __('Trailing slashes', 'permalink-manager'),
128
  'input_class' => 'settings-select',
129
- 'choices' => array(0 => __('Use default settings', 'permalink-manager'), 1 => __('Always add trailing slashes', 'permalink-manager'), 2 => __('Always remove trailing slashes', 'permalink-manager')),
130
  'description' => __('This option can be used to alter the native settings and control if trailing slash should be added or removed from the end of posts & terms permalinks.', 'permalink-manager')
131
- )
 
 
 
 
 
 
132
  )
133
  )
134
  ));
24
  public function output() {
25
  // Get all registered post types array & statuses
26
  $all_post_statuses_array = get_post_statuses();
27
+ $all_post_types = Permalink_Manager_Helper_Functions::get_post_types_array(null, null, true);
28
+ $all_taxonomies = Permalink_Manager_Helper_Functions::get_taxonomies_array(false, false, false, true);
29
+ $content_types = (defined('PERMALINK_MANAGER_PRO')) ? array('post_types' => $all_post_types, 'taxonomies' => $all_taxonomies) : array('post_types' => $all_post_types);
30
 
31
  $sections_and_fields = apply_filters('permalink-manager-settings-fields', array(
32
  'general' => array(
36
  'fields' => array(
37
  'auto_update_uris' => array(
38
  'type' => 'single_checkbox',
39
+ 'label' => __('Auto-update permalinks', 'permalink-manager'),
40
  'input_class' => '',
41
+ 'description' => __('If enabled, the custom permalinks will be automatically updated every time the post is saved or updated.', 'permalink-manager')
42
  ),
43
  'case_insensitive_permalinks' => array(
44
  'type' => 'single_checkbox',
45
+ 'label' => __('Case insensitive permalinks', 'permalink-manager'),
46
  'input_class' => '',
47
+ 'description' => __('Make all the permalinks case-insensitive.', 'permalink-manager')
48
  )
49
  )
50
  ),
76
  'label' => __('Redirect', 'permalink-manager'),
77
  'input_class' => 'settings-select',
78
  'choices' => array(0 => __('Disable', 'permalink-manager'), "301" => __('Enable "301 redirect"', 'permalink-manager'), "302" => __('Enable "302 redirect"', 'permalink-manager')),
79
+ 'description' => __('If enabled - the visitors will be redirected from native permalinks to your custom permalinks.<br /><strong>Only native permalinks & extra redirects will be redirected to new custom permalinks</strong>.', 'permalink-manager')
80
  )
81
  )
82
  ),
87
  'fields' => array(
88
  'setup_redirects' => array(
89
  'type' => 'single_checkbox',
90
+ 'label' => __('Auto-create "Extra Redirects" for old permalinks', 'permalink-manager'),
91
  'input_class' => '',
92
  'pro' => true,
93
  'disabled' => true,
94
+ 'description' => __('If enabled, the redirects will be automatially created for old custom permalinks, after posts or terms are updated.', 'permalink-manager')
95
  ),
96
  'auto_remove_duplicates' => array(
97
  'type' => 'single_checkbox',
98
  'label' => __('Automatically remove duplicates', 'permalink-manager'),
99
  'input_class' => '',
100
+ 'description' => sprintf(__('If enabled, the duplicated redirects & custom permalinks will be automatically removed if they were previously assigned to removed posts or terms.<br />To manually remove the duplicates please go <a href="%s">to this page</a>.', 'permalink-manager'), admin_url('tools.php?page=permalink-manager&section=tools&subsection=duplicates'))
101
  ),
102
  'force_custom_slugs' => array(
103
  'type' => 'single_checkbox',
104
  'label' => __('Force custom slugs', 'permalink-manager'),
105
  'input_class' => '',
106
+ 'description' => __('If enabled, the slugs in the default custom permalinks will be recreated from the post titles.<br />This may cause permalinks duplicates when the post or term title is used more than once.', 'permalink-manager')
107
  ),
108
+ /*'deep_detect' => array(
 
 
 
 
 
 
109
  'type' => 'single_checkbox',
110
  'label' => __('Enable "Deep detect"', 'permalink-manager'),
111
  'description' => __('Please keep it enabled if your custom URIs end with numerals, e.g. <strong>example.com/projects/20171025</strong> or if $_GET parameters should be detected as endpoints e.g. <strong>?page=1</strong>.', 'permalink-manager')
115
  'label' => __('Decode URIs', 'permalink-manager'),
116
  'input_class' => '',
117
  'description' => __('If enabled, the permalinks with non-ASCII characters may not be recognized in older browsers versions (advanced users only).', 'permalink-manager')
118
+ ),*/
119
  'trailing_slashes' => array(
120
  'type' => 'select',
121
  'label' => __('Trailing slashes', 'permalink-manager'),
122
  'input_class' => 'settings-select',
123
+ 'choices' => array(0 => __('Use default settings', 'permalink-manager'), 1 => __('Add trailing slashes', 'permalink-manager'), 10 => __('Add trailing slashes (+ auto-redirect links without them)', 'permalink-manager'), 2 => __('Remove trailing slashes', 'permalink-manager'), 20 => __('Remove trailing slashes (+ auto-redirect links with them)', 'permalink-manager'),),
124
  'description' => __('This option can be used to alter the native settings and control if trailing slash should be added or removed from the end of posts & terms permalinks.', 'permalink-manager')
125
+ ),
126
+ 'partial_disable' => array(
127
+ 'type' => 'checkbox',
128
+ 'label' => __('Disable Permalink Manager functionalities', 'permalink-manager'),
129
+ 'choices' => $content_types,
130
+ 'description' => __('Select the post types & taxonomies where the functionalities of Permalink Manager should be completely disabled.', 'permalink-manager')
131
+ ),
132
  )
133
  )
134
  ));
includes/views/permalink-manager-tools.php CHANGED
@@ -48,10 +48,11 @@ class Permalink_Manager_Tools extends Permalink_Manager_Class {
48
  global $permalink_manager_uris, $permalink_manager_redirects;
49
 
50
  // Get the duplicates & another variables
51
- $all_duplicates = Permalink_Manager_Core_Functions::detect_duplicates();
52
  $home_url = trim(get_option('home'), "/");
53
 
54
  $html = sprintf("<h3>%s</h3>", __("List of duplicated permalinks", "permalink-manager"));
 
55
 
56
  if(!empty($all_duplicates)) {
57
  foreach($all_duplicates as $uri => $duplicates) {
@@ -73,21 +74,35 @@ class Permalink_Manager_Tools extends Permalink_Manager_Class {
73
  // Get term
74
  if($detected_term && !empty($detected_id)) {
75
  $term = get_term($detected_id);
76
- $title = $term->name;
77
- $edit_label = __("Edit term", "permalink-manager");
78
- $edit_link = get_edit_tag_link($term->term_id, $term->taxonomy);
79
- } else if(!empty($detected_id)) {
 
 
 
 
 
 
 
 
80
  $post = get_post($detected_id);
81
- $title = $post->post_title;
82
- $edit_label = __("Edit post", "permalink-manager");
83
- $edit_link = get_edit_post_link($post->ID);
 
 
 
 
 
 
84
  } else {
85
  continue;
86
  }
87
 
88
  $html .= sprintf(
89
  //'<td><a href="%1$s" target="_blank">%2$s</a>%3$s</td><td>%4$s</td><td class="actions"><a href="%1$s" target="_blank"><span class="dashicons dashicons-edit"></span> %5$s</a> | <a class="remove-duplicate-link" href="%6$s"><span class="dashicons dashicons-trash"></span> %7$s</a></td>',
90
- '<td><a href="%1$s" target="_blank">%2$s</a>%3$s</td><td>%4$s</td><td class="actions"><a href="%1$s" target="_blank"><span class="dashicons dashicons-edit"></span> %5$s</a></td>',
91
  $edit_link,
92
  $title,
93
  " <small>#{$detected_id}</small>",
48
  global $permalink_manager_uris, $permalink_manager_redirects;
49
 
50
  // Get the duplicates & another variables
51
+ $all_duplicates = Permalink_Manager_Helper_Functions::get_all_duplicates();
52
  $home_url = trim(get_option('home'), "/");
53
 
54
  $html = sprintf("<h3>%s</h3>", __("List of duplicated permalinks", "permalink-manager"));
55
+ $html .= wpautop(sprintf("<a class=\"button button-primary\" href=\"%s\">%s</a>", admin_url('tools.php?page=permalink-manager&section=tools&subsection=duplicates&clear-permalink-manager-uris=1'), __('Remove all broken URIs', 'permalink-manager')));
56
 
57
  if(!empty($all_duplicates)) {
58
  foreach($all_duplicates as $uri => $duplicates) {
74
  // Get term
75
  if($detected_term && !empty($detected_id)) {
76
  $term = get_term($detected_id);
77
+ if(!empty($term->name)) {
78
+ $title = $post->post_title;
79
+ $edit_label = "<span class=\"dashicons dashicons-edit\"></span>" . __("Edit term", "permalink-manager");
80
+ $edit_link = get_edit_tag_link($term->term_id, $term->taxonomy);
81
+ } else {
82
+ $title = __("(Removed term)", "permalink-manager");
83
+ $edit_label = "<span class=\"dashicons dashicons-trash\"></span>" . __("Remove broken URI", "permalink-manager");
84
+ $edit_link = admin_url("tools.php?page=permalink-manager&section=tools&subsection=duplicates&remove-uri=tax-{$detected_id}");
85
+ }
86
+ }
87
+ // Get post
88
+ else if(!empty($detected_id)) {
89
  $post = get_post($detected_id);
90
+ if(!empty($post->post_title)) {
91
+ $title = $post->post_title;
92
+ $edit_label = "<span class=\"dashicons dashicons-edit\"></span>" . __("Edit post", "permalink-manager");
93
+ $edit_link = get_edit_post_link($post->ID);
94
+ } else {
95
+ $title = __("(Removed post)", "permalink-manager");
96
+ $edit_label = "<span class=\"dashicons dashicons-trash\"></span>" . __("Remove broken URI", "permalink-manager");
97
+ $edit_link = admin_url("tools.php?page=permalink-manager&section=tools&subsection=duplicates&remove-uri={$detected_id}");
98
+ }
99
  } else {
100
  continue;
101
  }
102
 
103
  $html .= sprintf(
104
  //'<td><a href="%1$s" target="_blank">%2$s</a>%3$s</td><td>%4$s</td><td class="actions"><a href="%1$s" target="_blank"><span class="dashicons dashicons-edit"></span> %5$s</a> | <a class="remove-duplicate-link" href="%6$s"><span class="dashicons dashicons-trash"></span> %7$s</a></td>',
105
+ '<td><a href="%1$s" target="_blank">%2$s</a>%3$s</td><td>%4$s</td><td class="actions"><a href="%1$s" target="_blank">%5$s</a></td>',
106
  $edit_link,
107
  $title,
108
  " <small>#{$detected_id}</small>",
includes/views/permalink-manager-upgrade.php CHANGED
@@ -35,7 +35,7 @@ class Permalink_Manager_Upgrade extends Permalink_Manager_Class {
35
  $output .= "<div class=\"column-1_3\">";
36
  $output .= sprintf("<h5>%s</h5>", __("Full WooCommerce Support", "permalink-manager"));
37
  $output .= wpautop(__("Adjust your shop, product category, tags or single product permalinks and set your e-commerce URLs any way you want!", "permalink-manager"));
38
- $output .= wpautop(__("Remove <em>product-category</em>, <em>product-tag</em> and <em>product</em> or replace them with any permastructures. Furthermore, the plugin allows to set completely custom permalinks for each product &#038; product taxonomies individually.", "permalink-manager"));
39
  $output .= "</div>";
40
  $output .= "<div class=\"column-1_3\">";
41
  $output .= sprintf("<h5>%s</h5>", __("Custom fields inside permalinks", "permalink-manager"));
@@ -43,6 +43,10 @@ class Permalink_Manager_Upgrade extends Permalink_Manager_Class {
43
  $output .= wpautop(__("This functionality is compatible with meta keys set with Advanced Custom Fields plugin.", "permalink-manager"));
44
  $output .= "</div>";
45
  $output .= "<div class=\"column-1_3\">";
 
 
 
 
46
  $output .= sprintf("<h5>%s</h5>", __("Import permalinks from \"Custom Permalinks\"", "permalink-manager"));
47
  $output .= wpautop(__("Additionally, Permalink Manager Pro allows to import the custom URIs defined previously with \"Custom Permalinks\" plugin. ", "permalink-manager"));
48
  $output .= "</div>";
@@ -50,10 +54,6 @@ class Permalink_Manager_Upgrade extends Permalink_Manager_Class {
50
  $output .= sprintf("<h5>%s</h5>", __("Remove \"stop words\" from permalinks", "permalink-manager"));
51
  $output .= wpautop(__("Set your own list of stop words or use a predefined one available in 21 languages. If enabled, all the words will be automatically removed from the default permalinks.", "permalink-manager"));
52
  $output .= "</div>";
53
- $output .= "<div class=\"column-1_3\">";
54
- $output .= sprintf("<h5>%s</h5>", __("Extra Redirects", "permalink-manager"));
55
- $output .= wpautop(__("Set-up extra redirects and/or aliases for each post or term. Permalink Manager would also automatically create redirects for previously used custom permalinks.", "permalink-manager"));
56
- $output .= "</div>";
57
  $output .= "</div>";
58
 
59
  $output .= sprintf("<p><a class=\"button button-default margin-top\" href=\"%s\" target=\"_blank\">%s</a>&nbsp;&nbsp;<a class=\"button button-primary margin-top\" href=\"%s\" target=\"_blank\">%s</a></p>", PERMALINK_MANAGER_WEBSITE, __("More info about Permalink Manager Pro"), "https://gumroad.com/l/permalink-manager", __("Buy Permalink Manager Pro"));
35
  $output .= "<div class=\"column-1_3\">";
36
  $output .= sprintf("<h5>%s</h5>", __("Full WooCommerce Support", "permalink-manager"));
37
  $output .= wpautop(__("Adjust your shop, product category, tags or single product permalinks and set your e-commerce URLs any way you want!", "permalink-manager"));
38
+ $output .= wpautop(__("Remove <em>product-category</em>, <em>product-tag</em> and <em>product</em> or replace them with another permalink tags. Furthermore, the plugin allows to set completely custom permalinks for each product &#038; product taxonomies individually.", "permalink-manager"));
39
  $output .= "</div>";
40
  $output .= "<div class=\"column-1_3\">";
41
  $output .= sprintf("<h5>%s</h5>", __("Custom fields inside permalinks", "permalink-manager"));
43
  $output .= wpautop(__("This functionality is compatible with meta keys set with Advanced Custom Fields plugin.", "permalink-manager"));
44
  $output .= "</div>";
45
  $output .= "<div class=\"column-1_3\">";
46
+ $output .= sprintf("<h5>%s</h5>", __("Extra Redirects", "permalink-manager"));
47
+ $output .= wpautop(__("Set-up extra redirects and/or aliases for each post or term. Permalink Manager would also automatically create redirects for previously used custom permalinks.", "permalink-manager"));
48
+ $output .= "</div>";
49
+ $output .= "<div class=\"column-1_3\">";
50
  $output .= sprintf("<h5>%s</h5>", __("Import permalinks from \"Custom Permalinks\"", "permalink-manager"));
51
  $output .= wpautop(__("Additionally, Permalink Manager Pro allows to import the custom URIs defined previously with \"Custom Permalinks\" plugin. ", "permalink-manager"));
52
  $output .= "</div>";
54
  $output .= sprintf("<h5>%s</h5>", __("Remove \"stop words\" from permalinks", "permalink-manager"));
55
  $output .= wpautop(__("Set your own list of stop words or use a predefined one available in 21 languages. If enabled, all the words will be automatically removed from the default permalinks.", "permalink-manager"));
56
  $output .= "</div>";
 
 
 
 
57
  $output .= "</div>";
58
 
59
  $output .= sprintf("<p><a class=\"button button-default margin-top\" href=\"%s\" target=\"_blank\">%s</a>&nbsp;&nbsp;<a class=\"button button-primary margin-top\" href=\"%s\" target=\"_blank\">%s</a></p>", PERMALINK_MANAGER_WEBSITE, __("More info about Permalink Manager Pro"), "https://gumroad.com/l/permalink-manager", __("Buy Permalink Manager Pro"));
permalink-manager.php CHANGED
@@ -3,8 +3,8 @@
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: 2.0.4.3
8
  * Author: Maciej Bis
9
  * Author URI: http://maciejbis.net/
10
  * License: GPL-2.0+
@@ -21,7 +21,7 @@ if (!defined('WPINC')) {
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', '2.0.4.3' );
25
  define( 'PERMALINK_MANAGER_FILE', __FILE__ );
26
  define( 'PERMALINK_MANAGER_DIR', untrailingslashit( dirname( __FILE__ ) ) );
27
  define( 'PERMALINK_MANAGER_BASENAME', plugin_basename(__FILE__) );
@@ -150,15 +150,14 @@ class Permalink_Manager_Class {
150
  'force_custom_slugs' => 0,
151
  'auto_update_uris' => 0,
152
  'case_insensitive_permalinks' => 0,
153
- 'decode_uris' => 0,
154
  'yoast_primary_term' => 1,
155
- 'redirect' => '302',
156
  'yoast_attachment_redirect' => 1,
157
  'canonical_redirect' => 1,
158
  'trailing_slashes' => 0,
159
- 'setup_redirects' => 0,
160
  'auto_remove_duplicates' => 0,
161
- 'disable_slug_appendix' => array(),
162
  'deep_detect' => 1
163
  ),
164
  'licence' => array()
@@ -181,15 +180,15 @@ class Permalink_Manager_Class {
181
  */
182
  public function default_alerts($alerts) {
183
  $default_alerts = apply_filters('permalink-manager-default-alerts', array(
184
- 'october' => array(
185
  'txt' => sprintf(
186
- __("Get access to extra features: full taxonomy and WooCommerce support, possibility to use custom fields inside the permalinks and more!<br /><strong>Buy Permalink Manager Pro <a href=\"%s\" target=\"_blank\">here</a> and save 20&#37; using \"OCTOBER\" coupon code!</strong> Valid until 31.10!", "permalink-manager"),
187
  PERMALINK_MANAGER_WEBSITE
188
  ),
189
  'type' => 'notice-info',
190
  'show' => 'pro_hide',
191
  'plugin_only' => true,
192
- 'until' => '2017-10-31'
193
  )
194
  ));
195
 
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.0.5.1
8
  * Author: Maciej Bis
9
  * Author URI: http://maciejbis.net/
10
  * License: GPL-2.0+
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', '2.0.5.1' );
25
  define( 'PERMALINK_MANAGER_FILE', __FILE__ );
26
  define( 'PERMALINK_MANAGER_DIR', untrailingslashit( dirname( __FILE__ ) ) );
27
  define( 'PERMALINK_MANAGER_BASENAME', plugin_basename(__FILE__) );
150
  'force_custom_slugs' => 0,
151
  'auto_update_uris' => 0,
152
  'case_insensitive_permalinks' => 0,
 
153
  'yoast_primary_term' => 1,
154
+ 'redirect' => '301',
155
  'yoast_attachment_redirect' => 1,
156
  'canonical_redirect' => 1,
157
  'trailing_slashes' => 0,
158
+ 'setup_redirects' => 1,
159
  'auto_remove_duplicates' => 0,
160
+ 'partial_disable' => array(),
161
  'deep_detect' => 1
162
  ),
163
  'licence' => array()
180
  */
181
  public function default_alerts($alerts) {
182
  $default_alerts = apply_filters('permalink-manager-default-alerts', array(
183
+ 'november' => array(
184
  'txt' => sprintf(
185
+ __("Get access to extra features: full taxonomy and WooCommerce support, possibility to use custom fields inside the permalinks and more!<br /><strong>Buy Permalink Manager Pro <a href=\"%s\" target=\"_blank\">here</a> and save 20&#37; using \"NOVEMBER\" coupon code!</strong> Valid until 31.11!", "permalink-manager"),
186
  PERMALINK_MANAGER_WEBSITE
187
  ),
188
  'type' => 'notice-info',
189
  'show' => 'pro_hide',
190
  'plugin_only' => true,
191
+ 'until' => '2017-11-31'
192
  )
193
  ));
194