Permalink Manager Lite - Version 2.0.0

Version Description

  • Extra Redirects - possibility to define extra redirects for each post/term
  • New "Tools" section - "Permalink Duplicates"
  • UI improvements for taxonomies ("Custom URI" panel)
  • Fixes for reported bugs
Download this release

Release Info

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

Code changes from version 1.11.6.3 to 2.0.0

README.txt CHANGED
@@ -6,7 +6,7 @@ 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: 1.11.6
10
 
11
  Most advanced yet easy-to-use permalink plugin that helps to maintain & bulk change your URLs & slugs.
12
 
@@ -24,22 +24,15 @@ Currently, the plugin allows to perform four main actions:
24
  6. It allows to control trailing slash behavior (remove or append slash to the end of permalink).
25
 
26
  Additional features available in <a href="https://permalinkmanager.pro?utm_source=wordpress">Permalink Manager Pro</a> only.
27
- 1. Case insensitive permalinks.
28
- 2. Permalink editor for categories/tags/custom terms.
29
- 3. Possibility to remove /product-category and /product from WooCommerce permalinks.
30
- 4. "Stop-words" auto removal - custom words and/or words from predefined lists (19 languages available).
31
- 5. Custom fields inside the permalinks (works also with Advanced Custom Fields).
 
32
 
33
  To improve the user experience, each tool allows also to filter the permalinks by post types or post statuses.
34
 
35
- = "Find and replace" usage example =
36
-
37
- Word "krakow" should be replaced with "gdansk" in all your permalinks.
38
-
39
- `http://example.com/krakow/hotels-in-krakow === [changed] ===> http://example.com/gdansk/hotels-in-gdansk
40
- http://example.com/krakow/restaurants-in-krakow === [changed] ===> http://example.com/gdansk/restaurants-in-gdansk
41
- http://example.com/poland/cities/poznan === [not changed] ===> http://example.com/poland/cities/poznan`
42
-
43
  = All features =
44
 
45
  * "Permalink Editor" - list of your permalinks (groupped by post types).
@@ -53,7 +46,8 @@ http://example.com/poland/cities/poznan === [not changed] ===> http://example.co
53
  = Additional features available in Permalink Manager Pro =
54
 
55
  * Priority support
56
- * Full support for taxonomies (categories, tags & custom taxonomies)
 
57
  * Full support for WooCommerce (products, product tags, product categories)
58
  * "Stop-words" to keep your permalinks short & clean (pre-defined "stop-words" lists are available in 21 languages)
59
  * Add custom fields to the permalinks (Advanced Custom Fields compatible)
@@ -95,20 +89,30 @@ A. Currently there is no 100% guarantee that Permalink Manager will work correct
95
  1. "Permalink editor".
96
  2. "Find and replace" section.
97
  3. "Regenerate/Reset" section.
98
- 4. "Permastructures" section.
99
- 5. A list of updated posts.
100
- 6. Editable URI box in Post/Page/CPT edit pagees.
101
- 7. Settings section.
102
 
103
 
104
  == Changelog ==
105
 
 
 
 
 
 
 
 
 
 
 
106
  = 1.11.6 =
107
  * Hotfix for taxonomy tags
108
  * Hotfix for custom field tags
109
  * Hotfix for Jetpack
110
  * Suuport for WP All Import
111
- * Support for Custom Permalinks (Permalink Manager Pro only)
112
 
113
  = 1.11.5.1 =
114
  * Hotfix for "Custom URI" form
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.0
10
 
11
  Most advanced yet easy-to-use permalink plugin that helps to maintain & bulk change your URLs & slugs.
12
 
24
  6. It allows to control trailing slash behavior (remove or append slash to the end of permalink).
25
 
26
  Additional features available in <a href="https://permalinkmanager.pro?utm_source=wordpress">Permalink Manager Pro</a> only.
27
+
28
+ 1. Extra redirects that could be defined individually for each post and term.
29
+ 2. Possibility to remove /product-category and /product from WooCommerce permalinks.
30
+ 3. Custom fields inside the permalinks (works also with Advanced Custom Fields).
31
+ 4. Case insensitive permalinks.
32
+ 5. "Stop-words" auto removal - custom words and/or words from predefined lists (19 languages available).
33
 
34
  To improve the user experience, each tool allows also to filter the permalinks by post types or post statuses.
35
 
 
 
 
 
 
 
 
 
36
  = All features =
37
 
38
  * "Permalink Editor" - list of your permalinks (groupped by post types).
46
  = Additional features available in Permalink Manager Pro =
47
 
48
  * Priority support
49
+ * Full support for taxonomies (categories, tags & custom taxonomies)
50
+ * Extra redirects
51
  * Full support for WooCommerce (products, product tags, product categories)
52
  * "Stop-words" to keep your permalinks short & clean (pre-defined "stop-words" lists are available in 21 languages)
53
  * Add custom fields to the permalinks (Advanced Custom Fields compatible)
89
  1. "Permalink editor".
90
  2. "Find and replace" section.
91
  3. "Regenerate/Reset" section.
92
+ 4. "Permastructures" section.
93
+ 5. A list of updated posts.
94
+ 6. Editable URI box in Post/Page/CPT edit pagees.
95
+ 7. Settings section.
96
 
97
 
98
  == Changelog ==
99
 
100
+ = 2.0.0 =
101
+ * Extra Redirects - possibility to define extra redirects for each post/term
102
+ * New "Tools" section - "Permalink Duplicates"
103
+ * UI improvements for taxonomies ("Custom URI" panel)
104
+ * Fixes for reported bugs
105
+
106
+ = 1.11.6.3 =
107
+ * Slug appendix fix
108
+ * Hotfix for WooCommerce checkkout
109
+
110
  = 1.11.6 =
111
  * Hotfix for taxonomy tags
112
  * Hotfix for custom field tags
113
  * Hotfix for Jetpack
114
  * Suuport for WP All Import
115
+ * Support for Custom Permalinks
116
 
117
  = 1.11.5.1 =
118
  * Hotfix for "Custom URI" form
includes/core/permalink-manager-actions.php CHANGED
@@ -178,24 +178,12 @@ class Permalink_Manager_Actions extends Permalink_Manager_Class {
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
- // Remove duplicates
187
- /* $duplicates = array_count_values($permalink_manager_uris);
188
- foreach($duplicates as $uri => $count) {
189
- if($count > 1) {
190
- // Keep the last instance
191
- for($i = 1; $i < $count; $i++) {
192
- $duplicated_id = array_search($uri, $permalink_manager_uris);
193
- unset($permalink_manager_uris[$duplicated_id]);
194
- }
195
- }
196
- }*/
197
-
198
- update_option('permalink-manager-uris', $permalink_manager_uris);
199
  $permalink_manager_before_sections_html .= Permalink_Manager_Admin_Functions::get_alert_message(__( 'URI array is cleared!', 'permalink-manager' ), 'updated');
200
  }
201
 
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
 
includes/core/permalink-manager-admin-functions.php CHANGED
@@ -138,7 +138,7 @@ class Permalink_Manager_Admin_Functions extends Permalink_Manager_Class {
138
  $description = (isset($args['before_description'])) ? $args['before_description'] : "";
139
  $description .= (isset($args['description'])) ? "<p class=\"field-description description\">{$args['description']}</p>" : "";
140
  $description .= (isset($args['after_description'])) ? $args['after_description'] : "";
141
- $description .= (isset($args['pro'])) ? sprintf("<p class=\"field-description description\">%s</p>", strip_tags(Permalink_Manager_Admin_Functions::pro_text(true))) : "";
142
  $append_content = (isset($args['append_content'])) ? "{$args['append_content']}" : "";
143
 
144
  // Input attributes
@@ -528,6 +528,108 @@ class Permalink_Manager_Admin_Functions extends Permalink_Manager_Class {
528
  return $html;
529
  }
530
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
531
  /**
532
  * Display global notices (throughout wp-admin dashboard)
533
  */
138
  $description = (isset($args['before_description'])) ? $args['before_description'] : "";
139
  $description .= (isset($args['description'])) ? "<p class=\"field-description description\">{$args['description']}</p>" : "";
140
  $description .= (isset($args['after_description'])) ? $args['after_description'] : "";
141
+ $description .= (isset($args['pro'])) ? sprintf("<p class=\"field-description description alert info\">%s</p>", (Permalink_Manager_Admin_Functions::pro_text(true))) : "";
142
  $append_content = (isset($args['append_content'])) ? "{$args['append_content']}" : "";
143
 
144
  // Input attributes
528
  return $html;
529
  }
530
 
531
+ /**
532
+ * Display "Permalink Manager" box
533
+ */
534
+ public static function display_uri_box($element, $default_uri, $uri, $native_uri, $home_with_prefix) {
535
+ global $permalink_manager_options;
536
+
537
+ if(!empty($element->ID)) {
538
+ $id = $element->ID;
539
+
540
+ // Auto-update settings
541
+ $auto_update_val = get_post_meta($id, "auto_update_uri", true);
542
+ $auto_update_def_val = $permalink_manager_options["general"]["auto_update_uris"];
543
+ $auto_update_def_label = ($auto_update_def_val) ? __("Yes", "permalink-manager") : __("No", "permalink-manager");
544
+ $auto_update_choices = array(
545
+ 0 => array("label" => sprintf(__("Use global settings [%s]", "permalink-manager"), $auto_update_def_label), "atts" => "data-auto-update=\"{$auto_update_def_val}\""),
546
+ -1 => array("label" => __("No", "permalink-manager"), "atts" => "data-auto-update=\"0\""),
547
+ 1 => array("label" => __("Yes", "permalink-manager"), "atts" => "data-auto-update=\"1\"")
548
+ );
549
+ } else {
550
+ $id = $element->term_id;
551
+ }
552
+
553
+ // 1. Button
554
+ $html = sprintf("<span><button type=\"button\" class=\"button button-small hide-if-no-js\" id=\"permalink-manager-toggle\">%s</button></span>", __("Permalink Manager", "permalink-manager"));
555
+
556
+ $html .= "<div id=\"permalink-manager\" class=\"postbox permalink-manager-edit-uri-box\" style=\"display: none;\">";
557
+
558
+ // 2. The heading
559
+ $html .= "<a class=\"close-button\"><span class=\"screen-reader-text\">" . __("Close: ", "permalink-manager") . __("Permalink Manager", "permalink-manager") . "</span><span class=\"close-icon\" aria-hidden=\"false\"></span></a>";
560
+ $html .= sprintf("<h2><span>%s</span></h2>", __("Permalink Manager", "permalink-manager"));
561
+
562
+ // 3. The fields container [start]
563
+ $html .= "<div class=\"inside\">";
564
+
565
+ // 4. Custom URI
566
+ $html .= sprintf("<div><label for=\"custom_uri\" class=\"strong\">%s %s</label><span>%s</span></div>",
567
+ __("Current URI", "permalink-manager"),
568
+ ($element->ID) ? Permalink_Manager_Admin_Functions::help_tooltip(__("The custom URI can be edited only if 'Auto-update the URI' feature is not enabled.", "permalink-manager")) : "",
569
+ Permalink_Manager_Admin_Functions::generate_option_field("custom_uri", array("extra_atts" => "data-default=\"{$default_uri}\"", "input_class" => "widefat custom_uri", "value" => urldecode($uri)))
570
+ );
571
+
572
+ // 5. Custom URI
573
+ if(!empty($auto_update_choices)) {
574
+ $html .= sprintf("<div><label for=\"auto_auri\" class=\"strong\">%s %s</label><span>%s</span></div>",
575
+ __("Auto-update the URI", "permalink-manager"),
576
+ Permalink_Manager_Admin_Functions::help_tooltip(__("If enabled, the 'Current URI' field will be automatically changed to 'Default URI' (displayed below) after the post is saved or updated.", "permalink-manager")),
577
+ Permalink_Manager_Admin_Functions::generate_option_field("auto_update_uri", array("type" => "select", "input_class" => "widefat auto_update", "value" => $auto_update_val, "choices" => $auto_update_choices))
578
+ );
579
+ }
580
+
581
+ // 6. Default URI
582
+ $html .= sprintf(
583
+ "<div class=\"default-permalink-row columns-container\"><span class=\"column-3_4\"><strong>%s:</strong> %s</span><span class=\"column-1_4\"><a href=\"#\" class=\"restore-default\"><span class=\"dashicons dashicons-image-rotate\"></span> %s</a></span></div>",
584
+ __("Default URI", "permalink-manager"), urldecode(esc_html($default_uri)),
585
+ __("Restore to Default URI", "permalink-manager")
586
+ );
587
+
588
+ // 7. Native URI info
589
+ if(!empty($permalink_manager_options['general']['redirect']) && ((!empty($element->post_status) && in_array($element->post_status, array('auto-draft', 'trash', 'draft'))) == false)) {
590
+ $html .= sprintf(
591
+ "<div class=\"default-permalink-row columns-container\"><span><strong>%s</strong> <a href=\"%s\">%s</a></span></div>",
592
+ __("Automatic redirect for native URI enabled:", "permalink-manager"),
593
+ "{$home_with_prefix}{$native_uri}",
594
+ urldecode($native_uri)
595
+ );
596
+ }
597
+
598
+ // 8. Custom redirects
599
+ $html .= ($element->ID) ? self::display_redirect_panel($id) : self::display_redirect_panel("tax-{$id}");
600
+
601
+ $html .= "</div>";
602
+ $html .= "</div>";
603
+
604
+ return $html;
605
+ }
606
+
607
+ /**
608
+ * Display the redirect panel
609
+ */
610
+ public static function display_redirect_panel($element_id) {
611
+ global $permalink_manager_options, $permalink_manager_redirects;
612
+
613
+ // Heading
614
+ $html = sprintf(
615
+ "<div class=\"permalink-manager redirects-row redirects-panel columns-container\"><div class=\"heading\"><span class=\"dashicons dashicons-redo\"></span> <a href=\"#\" id=\"toggle-redirect-panel\">%s</a></span></div>",
616
+ __("Add Extra Redirects", "permalink-manager")
617
+ );
618
+
619
+ $html .= "<div id=\"redirect-panel-inside\">";
620
+
621
+ // Table
622
+ if(class_exists('Permalink_Manager_Pro_Addons')) {
623
+ $html .= Permalink_Manager_Pro_Addons::display_redirect_form($element_id);
624
+ } else {
625
+ $html .= self::pro_text(true);
626
+ }
627
+
628
+ $html .= "</div></div>";
629
+
630
+ return $html;
631
+ }
632
+
633
  /**
634
  * Display global notices (throughout wp-admin dashboard)
635
  */
includes/core/permalink-manager-core-functions.php CHANGED
@@ -6,7 +6,7 @@
6
  class Permalink_Manager_Core_Functions extends Permalink_Manager_Class {
7
 
8
  public function __construct() {
9
- add_action('init', array($this, 'init_hooks'), 99);
10
  }
11
 
12
  function init_hooks() {
@@ -14,14 +14,14 @@ class Permalink_Manager_Core_Functions extends Permalink_Manager_Class {
14
  add_filter( 'request', array($this, 'detect_post'), 0, 1 );
15
 
16
  // Trailing slashes
17
- add_filter('permalink_manager_filter_final_term_permalink', array($this, 'control_trailing_slashes'), 9);
18
- add_filter('permalink_manager_filter_final_post_permalink', array($this, 'control_trailing_slashes'), 9);
19
- add_filter('permalink_manager_filter_post_sample_permalink', array($this, 'control_trailing_slashes'), 9);
20
- add_filter('redirect_canonical', array($this, 'canonical_redirect_trailing_slash'), 9, 2);
21
 
22
  // Redirects
 
23
  add_action( 'template_redirect', array($this, 'redirect_to_new_uri'), 999);
24
- add_action( 'parse_request', array($this, 'disable_canonical_redirect'), 0, 1 );
25
 
26
  // Case insensitive permalinks
27
  add_action( 'parse_request', array($this, 'case_insensitive_permalinks'), 0);
@@ -57,15 +57,18 @@ class Permalink_Manager_Core_Functions extends Permalink_Manager_Class {
57
  // Remove querystrings from URI
58
  $request_url = strtok($request_url, '?');
59
 
 
 
 
60
  // Use default REGEX to detect post
61
- preg_match("/^(.+?)(?:\/(page|feed|embed|attachment|track))?(?:\/([\d+]))?\/?$/i", $request_url, $regex_parts);
62
  $uri_parts['lang'] = false;
63
  $uri_parts['uri'] = (!empty($regex_parts[1])) ? $regex_parts[1] : "";
64
  $uri_parts['endpoint'] = (!empty($regex_parts[2])) ? $regex_parts[2] : "";
65
  $uri_parts['endpoint_value'] = (!empty($regex_parts[3])) ? $regex_parts[3] : "";
66
 
67
  // Allow to filter the results by third-parties
68
- $uri_parts = apply_filters('permalink-manager-detect-uri', $uri_parts, $request_url);
69
 
70
  // Stop the function if $uri_parts is empty
71
  if(empty($uri_parts)) return $query;
@@ -97,7 +100,7 @@ class Permalink_Manager_Core_Functions extends Permalink_Manager_Class {
97
  $item_id = (empty($item_id)) ? array_search("{$uri}.html", $permalink_manager_uris) : $item_id;
98
 
99
  // Check again in case someone used post/tax IDs instead of slugs
100
- $deep_detect_enabled = apply_filters('permalink-manager-deep-uri-detect', false);
101
  if($deep_detect_enabled && (empty($item_id)) && isset($old_query['page'])) {
102
  $item_id = array_search("{$uri}/{$endpoint_value}", $permalink_manager_uris);
103
  $endpoint_value = $endpoint = "";
@@ -124,7 +127,13 @@ class Permalink_Manager_Core_Functions extends Permalink_Manager_Class {
124
  if(empty($term->taxonomy)) { return $query; }
125
 
126
  // Get some term data
127
- $query_parameter = ($term->taxonomy == 'category') ? 'category_name' : $term->taxonomy;
 
 
 
 
 
 
128
  $term_ancestors = get_ancestors($item_id, $term->taxonomy);
129
  $final_uri = $term->slug;
130
 
@@ -231,26 +240,46 @@ class Permalink_Manager_Core_Functions extends Permalink_Manager_Class {
231
  return $permalink;
232
  }
233
 
234
- function canonical_redirect_trailing_slash($redirect_url, $requested_url) {
235
- global $permalink_manager_options;
236
-
237
- if(substr($redirect_url, 0, -1) != '/' && $permalink_manager_options['general']['trailing_slashes'] > 1) {
238
- $redirect_url = false;
239
- }
240
- return $redirect_url;
241
- }
242
-
243
  /**
244
  * Redirects
245
  */
246
  function redirect_to_new_uri() {
247
- global $wp_query, $permalink_manager_uris, $permalink_manager_options;
248
 
249
  // Sometimes $wp_query indicates the wrong object if requested directly
250
  $queried_object = get_queried_object();
251
 
252
- if(!empty($permalink_manager_options['general']['redirect']) && !empty($queried_object)) {
 
 
 
 
 
 
 
 
 
253
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
  // Affect only posts with custom URI and old URIs
255
  if(!empty($queried_object->ID) && isset($permalink_manager_uris[$queried_object->ID]) && empty($wp_query->query['do_not_redirect']) && empty($wp_query->query['preview'])) {
256
  // Ignore posts with specific statuses
@@ -267,9 +296,6 @@ class Permalink_Manager_Core_Functions extends Permalink_Manager_Class {
267
  $correct_permalink = get_term_link($queried_object->term_id, $queried_object->taxonomy);
268
  }
269
 
270
- // Get the redirection mode
271
- $redirect_mode = $permalink_manager_options['general']['redirect'];
272
-
273
  // Ignore default URIs (or do nothing if redirects are disabled)
274
  if(!empty($correct_permalink) && !empty($redirect_mode)) {
275
  wp_safe_redirect($correct_permalink, $redirect_mode);
@@ -278,9 +304,20 @@ class Permalink_Manager_Core_Functions extends Permalink_Manager_Class {
278
  }
279
  }
280
 
 
 
 
 
 
 
 
 
 
 
281
  function disable_canonical_redirect() {
282
- global $permalink_manager_options, $wp_filter;
283
- if(!($permalink_manager_options['general']['canonical_redirect'])) {
 
284
  remove_action('template_redirect', 'redirect_canonical');
285
  add_filter('wpml_is_redirected', '__return_false', 99, 2);
286
  }
@@ -298,5 +335,85 @@ class Permalink_Manager_Core_Functions extends Permalink_Manager_Class {
298
  }
299
  }
300
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
  }
302
  ?>
6
  class Permalink_Manager_Core_Functions extends Permalink_Manager_Class {
7
 
8
  public function __construct() {
9
+ add_action( 'init', array($this, 'init_hooks'), 99);
10
  }
11
 
12
  function init_hooks() {
14
  add_filter( 'request', array($this, 'detect_post'), 0, 1 );
15
 
16
  // Trailing slashes
17
+ add_filter( 'permalink_manager_filter_final_term_permalink', array($this, 'control_trailing_slashes'), 9);
18
+ add_filter( 'permalink_manager_filter_final_post_permalink', array($this, 'control_trailing_slashes'), 9);
19
+ add_filter( 'permalink_manager_filter_post_sample_permalink', array($this, 'control_trailing_slashes'), 9);
 
20
 
21
  // Redirects
22
+ add_filter( 'redirect_canonical', array($this, 'fix_canonical_redirect'), 9, 2);
23
  add_action( 'template_redirect', array($this, 'redirect_to_new_uri'), 999);
24
+ add_action( 'parse_request', array($this, 'disable_canonical_redirect'), 0, 1);
25
 
26
  // Case insensitive permalinks
27
  add_action( 'parse_request', array($this, 'case_insensitive_permalinks'), 0);
57
  // Remove querystrings from URI
58
  $request_url = strtok($request_url, '?');
59
 
60
+ // Filter endpoints
61
+ $endpoints = apply_filters("permalink-manager-endpoints", "page|feed|embed|attachment|track");
62
+
63
  // Use default REGEX to detect post
64
+ preg_match("/^(.+?)(?:\/($endpoints))?(?:\/([\d]+))?\/?$/i", $request_url, $regex_parts);
65
  $uri_parts['lang'] = false;
66
  $uri_parts['uri'] = (!empty($regex_parts[1])) ? $regex_parts[1] : "";
67
  $uri_parts['endpoint'] = (!empty($regex_parts[2])) ? $regex_parts[2] : "";
68
  $uri_parts['endpoint_value'] = (!empty($regex_parts[3])) ? $regex_parts[3] : "";
69
 
70
  // Allow to filter the results by third-parties
71
+ $uri_parts = apply_filters('permalink-manager-detect-uri', $uri_parts, $request_url, $endpoints);
72
 
73
  // Stop the function if $uri_parts is empty
74
  if(empty($uri_parts)) return $query;
100
  $item_id = (empty($item_id)) ? array_search("{$uri}.html", $permalink_manager_uris) : $item_id;
101
 
102
  // Check again in case someone used post/tax IDs instead of slugs
103
+ $deep_detect_enabled = apply_filters('permalink-manager-deep-uri-detect', true);
104
  if($deep_detect_enabled && (empty($item_id)) && isset($old_query['page'])) {
105
  $item_id = array_search("{$uri}/{$endpoint_value}", $permalink_manager_uris);
106
  $endpoint_value = $endpoint = "";
127
  if(empty($term->taxonomy)) { return $query; }
128
 
129
  // Get some term data
130
+ if($term->taxonomy == 'category') {
131
+ $query_parameter = 'category_name';
132
+ } else if($term->taxonomy == 'post_tag') {
133
+ $query_parameter = 'tag';
134
+ } else {
135
+ $query_parameter = $term->taxonomy;
136
+ }
137
  $term_ancestors = get_ancestors($item_id, $term->taxonomy);
138
  $final_uri = $term->slug;
139
 
240
  return $permalink;
241
  }
242
 
 
 
 
 
 
 
 
 
 
243
  /**
244
  * Redirects
245
  */
246
  function redirect_to_new_uri() {
247
+ global $wp_query, $permalink_manager_uris, $permalink_manager_redirects, $permalink_manager_options, $wp;
248
 
249
  // Sometimes $wp_query indicates the wrong object if requested directly
250
  $queried_object = get_queried_object();
251
 
252
+ // Get the redirection mode
253
+ $redirect_mode = (!empty($permalink_manager_options['general']['redirect'])) ? $permalink_manager_options['general']['redirect'] : false;
254
+
255
+ // A. Custom redirects
256
+ if(empty($wp_query->query['do_not_redirect']) && !empty($permalink_manager_redirects) && is_array($permalink_manager_redirects) && !empty($wp->request)) {
257
+ $uri = trim($wp->request, "/ ");
258
+
259
+ // Check if the URI is not assigned to any post/term's redirects
260
+ foreach($permalink_manager_redirects as $element => $redirects) {
261
+ if(is_array($redirects) && in_array($uri, $redirects)) {
262
 
263
+ // Post is detected
264
+ if(is_numeric($element)) {
265
+ $redirect_to = get_permalink($element);
266
+ }
267
+ // Term is detected
268
+ else {
269
+ $term_id = intval(preg_replace("/[^0-9]/", "", $element));
270
+ $redirect_to = get_term_link($term_id);
271
+ }
272
+
273
+ if(!empty($redirect_to)) {
274
+ wp_safe_redirect($redirect_to, $redirect_mode);
275
+ exit();
276
+ }
277
+ }
278
+ }
279
+ }
280
+
281
+ // B. Native redirect
282
+ if($redirect_mode && !empty($queried_object)) {
283
  // Affect only posts with custom URI and old URIs
284
  if(!empty($queried_object->ID) && isset($permalink_manager_uris[$queried_object->ID]) && empty($wp_query->query['do_not_redirect']) && empty($wp_query->query['preview'])) {
285
  // Ignore posts with specific statuses
296
  $correct_permalink = get_term_link($queried_object->term_id, $queried_object->taxonomy);
297
  }
298
 
 
 
 
299
  // Ignore default URIs (or do nothing if redirects are disabled)
300
  if(!empty($correct_permalink) && !empty($redirect_mode)) {
301
  wp_safe_redirect($correct_permalink, $redirect_mode);
304
  }
305
  }
306
 
307
+ function fix_canonical_redirect($redirect_url, $requested_url) {
308
+ global $permalink_manager_options;
309
+
310
+ // Trailing slash
311
+ if(substr($redirect_url, 0, -1) != '/' && $permalink_manager_options['general']['trailing_slashes'] > 1) {
312
+ $redirect_url = false;
313
+ }
314
+ return $redirect_url;
315
+ }
316
+
317
  function disable_canonical_redirect() {
318
+ global $permalink_manager_options, $wp_filter, $wp;
319
+
320
+ if(!($permalink_manager_options['general']['canonical_redirect']) || !empty($wp->query_vars['do_not_redirect'])) {
321
  remove_action('template_redirect', 'redirect_canonical');
322
  add_filter('wpml_is_redirected', '__return_false', 99, 2);
323
  }
335
  }
336
  }
337
 
338
+ /**
339
+ * Detect duplicates
340
+ */
341
+ public static function detect_duplicates() {
342
+ global $permalink_manager_uris, $permalink_manager_redirects, $permalink_manager_options, $wpdb;
343
+
344
+ // Make sure that both variables are arrays
345
+ $all_uris = (is_array($permalink_manager_uris)) ? $permalink_manager_uris : array();
346
+ $permalink_manager_redirects = (is_array($permalink_manager_redirects)) ? $permalink_manager_redirects : array();
347
+
348
+ // Convert redirects list, so it can be merged with $permalink_manager_uris
349
+ foreach($permalink_manager_redirects as $element_id => $redirects) {
350
+ if(is_array($redirects)) {
351
+ foreach($redirects as $index => $uri) {
352
+ $all_uris["redirect-{$index}_{$element_id}"] = $uri;
353
+ }
354
+ }
355
+ }
356
+
357
+ // Count duplicates
358
+ $duplicates_removed = 0;
359
+ $duplicates_groups = array();
360
+ $duplicates_list = array_count_values($all_uris);
361
+ $duplicates_list = array_filter($duplicates_list, function ($x) { return $x >= 2; });
362
+
363
+ // Assign keys to duplicates (group them)
364
+ if(count($duplicates_list) > 0) {
365
+ foreach($duplicates_list as $duplicated_uri => $count) {
366
+ $duplicates_array = array_keys($all_uris, $duplicated_uri);
367
+
368
+ // Remove the URIs for removed posts & terms
369
+ if(!empty($permalink_manager_options['general']['auto_remove_duplicates'])) {
370
+ foreach($duplicates_array as $index => $raw_item_id) {
371
+ $item_id = preg_replace("/(?:redirect-[\d]+_)?(.*)/", "$1", $raw_item_id);
372
+
373
+ if(strpos($item_id, 'tax-') !== false) {
374
+ $term_id = intval(preg_replace("/[^0-9]/", "", $item_id));
375
+ $element_exists = $wpdb->get_var( "SELECT * FROM {$wpdb->prefix}terms WHERE term_id = {$term_id}" );
376
+ } else {
377
+ $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'" );
378
+ }
379
+
380
+ if(empty($element_exists)) {
381
+ // Detect the type of URI
382
+ preg_match("/(redirect-([\d]+)_)?((?:tax-)?[\d]*)/", $raw_item_id, $parts);
383
+
384
+ $detected_redirect = $parts[1];
385
+ $detected_id = $parts[3];
386
+ $detected_index = $parts[2];
387
+
388
+ // A. Redirect
389
+ if($detected_redirect && $detected_index && $detected_id) {
390
+ unset($permalink_manager_redirects[$detected_id][$detected_index]);
391
+ }
392
+ // B. Custom URI
393
+ else if($detected_id) {
394
+ unset($permalink_manager_uris[$detected_id]);
395
+ }
396
+
397
+ if($detected_id) {
398
+ unset($duplicates_array[$index]);
399
+ $duplicates_removed++;
400
+ }
401
+ }
402
+ }
403
+ }
404
+
405
+ $duplicates_groups[$duplicated_uri] = $duplicates_array;
406
+ }
407
+
408
+ // Save cleared URIs & Redirects
409
+ if($duplicates_removed > 0 && !empty($permalink_manager_options['general']['auto_remove_duplicates'])) {
410
+ update_option('permalink-manager-uris', $permalink_manager_uris);
411
+ update_option('permalink-manager-redirects', $permalink_manager_redirects);
412
+ }
413
+ }
414
+
415
+ return $duplicates_groups;
416
+ }
417
+
418
  }
419
  ?>
includes/core/permalink-manager-helper-functions.php CHANGED
@@ -217,7 +217,7 @@ class Permalink_Manager_Helper_Functions extends Permalink_Manager_Class {
217
  $clean = remove_accents($clean);
218
 
219
  $clean = iconv('UTF-8', 'ASCII//TRANSLIT', $clean);
220
- $clean = preg_replace("/[^a-zA-Z0-9\/_|+ -]/", '', $clean);
221
  $clean = strtolower(trim($clean, '-'));
222
  $clean = preg_replace("/[_|+ -]+/", "-", $clean);
223
 
217
  $clean = remove_accents($clean);
218
 
219
  $clean = iconv('UTF-8', 'ASCII//TRANSLIT', $clean);
220
+ $clean = preg_replace("/[^a-zA-Z0-9\/_\.|+ -]/", '', $clean);
221
  $clean = strtolower(trim($clean, '-'));
222
  $clean = preg_replace("/[_|+ -]+/", "-", $clean);
223
 
includes/core/permalink-manager-third-parties.php CHANGED
@@ -23,9 +23,10 @@ class Permalink_Manager_Third_Parties extends Permalink_Manager_Class {
23
 
24
  // Split the current URL into subparts (check if WPML is active)
25
  if(isset($sitepress_settings['language_negotiation_type']) && $sitepress_settings['language_negotiation_type'] == 1) {
26
- add_filter('permalink-manager-detect-uri', array($this, 'wpml_detect_post'), 9, 2);
27
  add_filter('permalink-manager-post-permalink-prefix', array($this, 'wpml_element_lang_prefix'), 9, 3);
28
  add_filter('permalink-manager-term-permalink-prefix', array($this, 'wpml_element_lang_prefix'), 9, 3);
 
29
  } else if(isset($sitepress_settings['language_negotiation_type']) && $sitepress_settings['language_negotiation_type'] == 3) {
30
  add_filter('permalink-manager-detect-uri', array($this, 'wpml_ignore_lang_query_parameter'), 9);
31
  }
@@ -50,12 +51,20 @@ class Permalink_Manager_Third_Parties extends Permalink_Manager_Class {
50
 
51
  // 5. WP All Import
52
  add_action('pmxi_after_xml_import', array($this, 'pmxi_fix_permalinks'), 10);
 
 
 
 
 
 
53
  }
54
 
55
  /**
56
  * 1. WPML filters
57
  */
58
  function wpml_language_mismatch_fix($item_id, $uri_parts, $is_term = false) {
 
 
59
  if($is_term) {
60
  $current_term = get_term($item_id);
61
  $element_type = (!empty($current_term) && !is_wp_error($current_term)) ? $current_term->taxonomy : "";
@@ -72,8 +81,9 @@ class Permalink_Manager_Third_Parties extends Permalink_Manager_Class {
72
  return $item_id;
73
  }
74
 
75
- function wpml_detect_post($uri_parts, $request_url) {
76
- preg_match("/^(?:(\w{2})\/)?(.+?)\/?(page|feed|embed|attachment|track)?(?:\/([\d+]))?\/?$/i", $request_url, $regex_parts);
 
77
 
78
  $uri_parts['lang'] = (!empty($regex_parts[1])) ? $regex_parts[1] : "";
79
  $uri_parts['uri'] = (!empty($regex_parts[2])) ? $regex_parts[2] : "";
@@ -147,6 +157,14 @@ class Permalink_Manager_Third_Parties extends Permalink_Manager_Class {
147
  return $uri_parts;
148
  }
149
 
 
 
 
 
 
 
 
 
150
  /**
151
  * 2. AMP hooks
152
  */
@@ -178,13 +196,21 @@ class Permalink_Manager_Third_Parties extends Permalink_Manager_Class {
178
  * 3. Yoast SEO
179
  */
180
  function yoast_detect_attachment($item_id, $uri_parts, $request_url) {
181
- global $wpdb;
 
 
182
 
183
- if(empty($item_id) && !empty($uri_parts['uri'])) {
184
- $attachment_slug = basename($uri_parts['uri']);
185
- $attachment = $wpdb->get_row( $wpdb->prepare( "SELECT ID, post_name FROM {$wpdb->posts} WHERE post_type = %s AND post_name = %s", "attachment", $attachment_slug ), ARRAY_A );
186
 
187
- $item_id = (!empty($attachment['ID'])) ? $attachment['ID'] : $item_id;
 
 
 
 
 
 
 
188
  }
189
 
190
  return $item_id;
@@ -268,6 +294,41 @@ class Permalink_Manager_Third_Parties extends Permalink_Manager_Class {
268
  update_option('permalink-manager-uris', $permalink_manager_uris);
269
  }
270
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
 
272
  }
273
  ?>
23
 
24
  // Split the current URL into subparts (check if WPML is active)
25
  if(isset($sitepress_settings['language_negotiation_type']) && $sitepress_settings['language_negotiation_type'] == 1) {
26
+ add_filter('permalink-manager-detect-uri', array($this, 'wpml_detect_post'), 9, 3);
27
  add_filter('permalink-manager-post-permalink-prefix', array($this, 'wpml_element_lang_prefix'), 9, 3);
28
  add_filter('permalink-manager-term-permalink-prefix', array($this, 'wpml_element_lang_prefix'), 9, 3);
29
+ add_filter('template_redirect', array($this, 'wpml_redirect'), 0, 998 );
30
  } else if(isset($sitepress_settings['language_negotiation_type']) && $sitepress_settings['language_negotiation_type'] == 3) {
31
  add_filter('permalink-manager-detect-uri', array($this, 'wpml_ignore_lang_query_parameter'), 9);
32
  }
51
 
52
  // 5. WP All Import
53
  add_action('pmxi_after_xml_import', array($this, 'pmxi_fix_permalinks'), 10);
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_checkout_fix'), 9, 1);
59
+ }
60
  }
61
 
62
  /**
63
  * 1. WPML filters
64
  */
65
  function wpml_language_mismatch_fix($item_id, $uri_parts, $is_term = false) {
66
+ global $wp, $language_code;
67
+
68
  if($is_term) {
69
  $current_term = get_term($item_id);
70
  $element_type = (!empty($current_term) && !is_wp_error($current_term)) ? $current_term->taxonomy : "";
81
  return $item_id;
82
  }
83
 
84
+ function wpml_detect_post($uri_parts, $request_url, $endpoints) {
85
+ //preg_match("/^(?:(\w{2})\/)?(.+?)\/?({$endpoints})?(?:\/([\d+]))?\/?$/i", $request_url, $regex_parts);
86
+ preg_match("/^(?:(\w{2})\/)?(.+?)(?:\/({$endpoints}))?(?:\/([\d+]))?\/?$/i", $request_url, $regex_parts);
87
 
88
  $uri_parts['lang'] = (!empty($regex_parts[1])) ? $regex_parts[1] : "";
89
  $uri_parts['uri'] = (!empty($regex_parts[2])) ? $regex_parts[2] : "";
157
  return $uri_parts;
158
  }
159
 
160
+ function wpml_redirect() {
161
+ global $language_code, $wp_query;
162
+
163
+ if(!empty($language_code) && defined('ICL_LANGUAGE_CODE') && ICL_LANGUAGE_CODE != $language_code && !empty($wp_query->query['do_not_redirect'])) {
164
+ unset($wp_query->query['do_not_redirect']);
165
+ }
166
+ }
167
+
168
  /**
169
  * 2. AMP hooks
170
  */
196
  * 3. Yoast SEO
197
  */
198
  function yoast_detect_attachment($item_id, $uri_parts, $request_url) {
199
+ global $wpdb, $permalink_manager_uris;
200
+
201
+ $uri = (!empty($uri_parts['uri'])) ? $uri_parts['uri'] : "";
202
 
203
+ if(empty($item_id) && $uri) {
204
+ $slug = basename($uri_parts['uri']);
 
205
 
206
+ // Check if slug is already used by any post or term
207
+ $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);
208
+ $used_by_term = ($used_by_post) ? true : $wpdb->get_row($wpdb->prepare( "SELECT term_id FROM {$wpdb->terms} WHERE slug = %s", $slug ), ARRAY_A);
209
+
210
+ if(empty($used_by_post) && empty($used_by_term)) {
211
+ $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);
212
+ $item_id = (!empty($attachment['ID'])) ? $attachment['ID'] : $item_id;
213
+ }
214
  }
215
 
216
  return $item_id;
294
  update_option('permalink-manager-uris', $permalink_manager_uris);
295
  }
296
 
297
+ /**
298
+ * WooCommerce
299
+ */
300
+ function woocommerce_endpoints($endpoints) {
301
+ global $woocommerce;
302
+
303
+ if(!empty($woocommerce->query->query_vars)) {
304
+ $query_vars = $woocommerce->query->query_vars;
305
+
306
+ foreach($query_vars as $key => $val) {
307
+ $endpoints .= "|{$key}";
308
+ }
309
+ }
310
+
311
+ return $endpoints;
312
+ }
313
+
314
+ function woocommerce_checkout_fix($query) {
315
+ global $woocommerce;
316
+
317
+ if(!empty($woocommerce->query->query_vars)) {
318
+ $query_vars = $woocommerce->query->query_vars;
319
+
320
+ // Do not redirect "thank you" & another WooCommerce pages
321
+ foreach($query_vars as $key => $val) {
322
+ if(array_key_exists($key, $query)) {
323
+ $query['do_not_redirect'] = 1;
324
+ break;
325
+ }
326
+ }
327
+ }
328
+
329
+ return $query;
330
+ }
331
+
332
 
333
  }
334
  ?>
includes/core/permalink-manager-uri-functions-post.php CHANGED
@@ -17,7 +17,7 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
17
  add_filter( 'permalink-manager-uris', array($this, 'exclude_homepage'), 999, 2);
18
  add_action( 'save_post', array($this, 'update_post_uri'), 999, 1);
19
  add_action( 'edit_attachment', array($this, 'update_post_uri'), 999, 1 );
20
- add_action( 'wp_insert_post', array($this, 'update_post_uri'), 999, 1 );
21
  add_action( 'wp_trash_post', array($this, 'remove_post_uri'), 10, 1 );
22
  }
23
 
@@ -114,6 +114,9 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
114
 
115
  $default_base = (!empty($permastruct)) ? trim($permastruct, '/') : "";
116
 
 
 
 
117
  // 1A. Get the date
118
  $date = explode(" ", date('Y m d H i s', strtotime($post->post_date)));
119
 
@@ -129,22 +132,22 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
129
  $full_slug = (empty($full_slug)) ? $post_name : $full_slug;
130
 
131
  if(!$native_uri) {
132
- // 2B. Remove the post slug (the last occurence of post_name)
133
- if(!empty($permalink_manager_options['general']['disable_slug_appendix']) && in_array($post_type, $permalink_manager_options['general']['disable_slug_appendix'])) {
134
- $full_slug = (strpos($full_slug, '/') !== false) ? preg_replace("/(.*)\/(.*)$/", "$1", $full_slug) : "";
135
- }
136
-
137
  // 2C. Allow filter the default slug
138
- $full_slug = Permalink_Manager_Helper_Functions::force_custom_slugs($full_slug, $post);
139
  $full_slug = apply_filters('permalink_manager_filter_default_post_slug', $full_slug, $post, $post_name);
140
  }
141
  $post_type_tag = Permalink_Manager_Helper_Functions::get_post_tag($post_type);
142
 
143
  // 3A. Do the replacement (post tag is removed now to enable support for hierarchical CPT)
144
- $tags = array('%year%', '%monthnum%', '%day%', '%hour%', '%minute%', '%second%', '%post_id%', '%author%', $post_type_tag);
145
- $replacements = array($date[0], $date[1], $date[2], $date[3], $date[4], $date[5], $post->ID, $author, '');
146
 
147
- $default_uri = str_replace($tags, $replacements, "{$default_base}/{$full_slug}");
 
 
 
 
 
 
148
 
149
  // 3B. Replace taxonomies
150
  $taxonomies = get_taxonomies();
@@ -170,18 +173,18 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
170
 
171
  foreach((array) $ancestors as $ancestor) {
172
  $ancestor_term = get_term($ancestor, $taxonomy);
173
- $hierarchical_slugs[] = Permalink_Manager_Helper_Functions::force_custom_slugs($ancestor_term->slug, $ancestor_term);
174
  }
175
  $hierarchical_slugs = array_reverse($hierarchical_slugs);
176
  $replacement = implode('/', $hierarchical_slugs);
177
 
178
  // Append the term slug now
179
- $last_term_slug = Permalink_Manager_Helper_Functions::force_custom_slugs($replacement_term->slug, $replacement_term);
180
  $replacement = "{$replacement}/{$last_term_slug}";
181
  }
182
  // 4B. Flat taxonomy base
183
  else if(!empty($replacement_term->slug)) {
184
- $replacement = Permalink_Manager_Helper_Functions::force_custom_slugs($replacement_term->slug, $replacement_term);
185
  }
186
 
187
  // 4. Do the replacement
@@ -190,7 +193,7 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
190
  }
191
 
192
  // Clear the URI
193
- $default_uri = preg_replace("/(%(?:.+?)%\/)/i", "", $default_uri);
194
  $default_uri = preg_replace('/\s+/', '', $default_uri);
195
  $default_uri = str_replace('//', '/', $default_uri);
196
  $default_uri = trim($default_uri, "/");
@@ -296,6 +299,8 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
296
  $updated_array[] = array('item_title' => $row['post_title'], 'ID' => $row['ID'], 'old_uri' => $old_uri, 'new_uri' => $new_uri, 'old_slug' => $old_post_name, 'new_slug' => $new_post_name);
297
  $updated_slugs_count++;
298
  }
 
 
299
  }
300
 
301
  // Filter array before saving
@@ -394,6 +399,8 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
394
  $updated_array[] = array('item_title' => $row['post_title'], 'ID' => $row['ID'], 'old_uri' => $old_uri, 'new_uri' => $new_uri, 'old_slug' => $old_post_name, 'new_slug' => $new_post_name);
395
  $updated_slugs_count++;
396
  }
 
 
397
  }
398
 
399
  // Filter array before saving
@@ -450,6 +457,8 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
450
  $updated_array[] = array('item_title' => get_the_title($id), 'ID' => $id, 'old_uri' => $old_uri, 'new_uri' => $new_uri);
451
  $updated_slugs_count++;
452
  }
 
 
453
  }
454
 
455
  // Filter array before saving & append the global
@@ -482,7 +491,6 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
482
 
483
  // Make sure that home URL ends with slash
484
  $home_url = trim(get_option('home'), "/") . "/";
485
-
486
  $prefix = apply_filters('permalink-manager-post-permalink-prefix', '', $post, true);
487
 
488
  // Do not change anything if post is not saved yet (display sample permalink instead)
@@ -505,52 +513,7 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
505
  $html .= sprintf("<span class=\"sample-permalink-span\"><a href=\"%s\">%s</a></span>&nbsp;", strip_tags($sample_permalink), $sample_permalink);
506
 
507
  if(!empty($uri)) {
508
- // Auto-update settings
509
- $auto_update_val = get_post_meta($id, "auto_update_uri", true);
510
- $auto_update_def_val = $permalink_manager_options["general"]["auto_update_uris"];
511
- $auto_update_def_label = ($auto_update_def_val) ? __("Yes", "permalink-manager") : __("No", "permalink-manager");
512
- $auto_update_choices = array(
513
- 0 => array("label" => sprintf(__("Use global settings [%s]", "permalink-manager"), $auto_update_def_label), "atts" => "data-auto-update=\"{$auto_update_def_val}\""),
514
- -1 => array("label" => __("No", "permalink-manager"), "atts" => "data-auto-update=\"0\""),
515
- 1 => array("label" => __("Yes", "permalink-manager"), "atts" => "data-auto-update=\"1\"")
516
- );
517
-
518
- // Add the "edit buttons"
519
- $html .= sprintf("<span><button type=\"button\" class=\"button button-small hide-if-no-js\" id=\"permalink-manager-toggle\">%s</button></span>", __("Permalink Manager", "permalink-manager"));
520
- $html .= "<div id=\"permalink-manager\" class=\"postbox permalink-manager-edit-uri-box\" style=\"display: none;\">";
521
-
522
- // The heading
523
- $html .= "<a class=\"close-button\"><span class=\"screen-reader-text\">" . __("Close: ", "permalink-manager") . __("Permalink Manager", "permalink-manager") . "</span><span class=\"close-icon\" aria-hidden=\"false\"></span></a>";
524
- $html .= sprintf("<h2><span>%s</span></h2>", __("Permalink Manager", "permalink-manager"));
525
-
526
- // The fields
527
- $html .= "<div class=\"inside\">";
528
- $html .= sprintf("<p><label for=\"custom_uri\" class=\"strong\">%s %s</label><span>%s</span></p>",
529
- __("Current URI", "permalink-manager"),
530
- Permalink_Manager_Admin_Functions::help_tooltip(__("The custom URI can be edited only if 'Auto-update the URI' feature is not enabled.", "permalink-manager")),
531
- Permalink_Manager_Admin_Functions::generate_option_field("custom_uri", array("extra_atts" => "data-default=\"{$default_uri}\"", "input_class" => "widefat custom_uri", "value" => urldecode($uri)))
532
- );
533
- $html .= sprintf("<p><label for=\"auto_auri\" class=\"strong\">%s %s</label><span>%s</span></p>",
534
- __("Auto-update the URI", "permalink-manager"),
535
- Permalink_Manager_Admin_Functions::help_tooltip(__("If enabled, the 'Current URI' field will be automatically changed to 'Default URI' (displayed below) after the post is saved or updated.", "permalink-manager")),
536
- Permalink_Manager_Admin_Functions::generate_option_field("auto_update_uri", array("type" => "select", "input_class" => "widefat auto_update", "value" => $auto_update_val, "choices" => $auto_update_choices))
537
- );
538
- $html .= sprintf(
539
- "<p class=\"default-permalink-row columns-container\"><span class=\"column-3_4\"><strong>%s:</strong> %s</span><span class=\"column-1_4\"><a href=\"#\" class=\"restore-default\"><span class=\"dashicons dashicons-image-rotate\"></span> %s</a></span></p>",
540
- __("Default URI", "permalink-manager"), urldecode(esc_html($default_uri)),
541
- __("Restore to Default URI", "permalink-manager")
542
- );
543
- if(!empty($permalink_manager_options['general']['redirect'])) {
544
- $html .= sprintf(
545
- "<p class=\"default-permalink-row columns-container\"><span><strong>%s</strong> <a href=\"%s\">%s</a></span></p>",
546
- __("Automatic redirect for native URI enabled:", "permalink-manager"),
547
- "{$home_url}{$prefix}{$native_uri}",
548
- urldecode($native_uri)
549
- );
550
- }
551
- $html .= "</div>";
552
-
553
- $html .= "</div>";
554
  }
555
 
556
  // Append hidden field with native slug
@@ -573,6 +536,9 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
573
  $post_id = ($is_revision) ? $is_revision : $post_id;
574
  $post = get_post($post_id);
575
 
 
 
 
576
  $native_uri = self::get_default_post_uri($post_id, true);
577
  $new_uri = self::get_default_post_uri($post_id);;
578
  $permalink_manager_uris[$post->ID] = $new_uri;
@@ -596,6 +562,9 @@ class Permalink_Manager_URI_Functions_Post extends Permalink_Manager_Class {
596
  $post_id = ($is_revision) ? $is_revision : $post_id;
597
  $post = get_post($post_id);
598
 
 
 
 
599
  // Ignore auto-drafts & removed posts
600
  if(in_array($post->post_status, array('auto-draft', 'trash')) || (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || (!empty($_REQUEST['bulk_edit'])) || (!empty($_REQUEST['post_view']))) { return; }
601
 
17
  add_filter( 'permalink-manager-uris', array($this, 'exclude_homepage'), 999, 2);
18
  add_action( 'save_post', array($this, 'update_post_uri'), 999, 1);
19
  add_action( 'edit_attachment', array($this, 'update_post_uri'), 999, 1 );
20
+ add_action( 'wp_insert_post', array($this, 'new_post_uri'), 999, 1 );
21
  add_action( 'wp_trash_post', array($this, 'remove_post_uri'), 10, 1 );
22
  }
23
 
114
 
115
  $default_base = (!empty($permastruct)) ? trim($permastruct, '/') : "";
116
 
117
+ // Check if the slug should not be appended
118
+ $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;
119
+
120
  // 1A. Get the date
121
  $date = explode(" ", date('Y m d H i s', strtotime($post->post_date)));
122
 
132
  $full_slug = (empty($full_slug)) ? $post_name : $full_slug;
133
 
134
  if(!$native_uri) {
 
 
 
 
 
135
  // 2C. Allow filter the default slug
136
+ $full_slug = ($native_uri) ? $full_slug : Permalink_Manager_Helper_Functions::force_custom_slugs($full_slug, $post);
137
  $full_slug = apply_filters('permalink_manager_filter_default_post_slug', $full_slug, $post, $post_name);
138
  }
139
  $post_type_tag = Permalink_Manager_Helper_Functions::get_post_tag($post_type);
140
 
141
  // 3A. Do the replacement (post tag is removed now to enable support for hierarchical CPT)
142
+ $tags = array('%year%', '%monthnum%', '%day%', '%hour%', '%minute%', '%second%', '%post_id%', '%author%', $post_type_tag, '%postname%');
 
143
 
144
+ if($dont_append_slug) {
145
+ $replacements = array($date[0], $date[1], $date[2], $date[3], $date[4], $date[5], $post->ID, $author, $full_slug, $full_slug);
146
+ $default_uri = str_replace($tags, $replacements, "{$default_base}");
147
+ } else {
148
+ $replacements = array($date[0], $date[1], $date[2], $date[3], $date[4], $date[5], $post->ID, $author, '', '');
149
+ $default_uri = str_replace($tags, $replacements, "{$default_base}/{$full_slug}");
150
+ }
151
 
152
  // 3B. Replace taxonomies
153
  $taxonomies = get_taxonomies();
173
 
174
  foreach((array) $ancestors as $ancestor) {
175
  $ancestor_term = get_term($ancestor, $taxonomy);
176
+ $hierarchical_slugs[] = ($native_uri) ? $replacement_term->slug : Permalink_Manager_Helper_Functions::force_custom_slugs($ancestor_term->slug, $ancestor_term);
177
  }
178
  $hierarchical_slugs = array_reverse($hierarchical_slugs);
179
  $replacement = implode('/', $hierarchical_slugs);
180
 
181
  // Append the term slug now
182
+ $last_term_slug = ($native_uri) ? $replacement_term->slug : Permalink_Manager_Helper_Functions::force_custom_slugs($replacement_term->slug, $replacement_term);
183
  $replacement = "{$replacement}/{$last_term_slug}";
184
  }
185
  // 4B. Flat taxonomy base
186
  else if(!empty($replacement_term->slug)) {
187
+ $replacement = ($native_uri) ? $replacement_term->slug : Permalink_Manager_Helper_Functions::force_custom_slugs($replacement_term->slug, $replacement_term);
188
  }
189
 
190
  // 4. Do the replacement
193
  }
194
 
195
  // Clear the URI
196
+ $default_uri = preg_replace("/%(.+?)%/", "", $default_uri);
197
  $default_uri = preg_replace('/\s+/', '', $default_uri);
198
  $default_uri = str_replace('//', '/', $default_uri);
199
  $default_uri = trim($default_uri, "/");
299
  $updated_array[] = array('item_title' => $row['post_title'], 'ID' => $row['ID'], 'old_uri' => $old_uri, 'new_uri' => $new_uri, 'old_slug' => $old_post_name, 'new_slug' => $new_post_name);
300
  $updated_slugs_count++;
301
  }
302
+
303
+ do_action('permalink-manager-updated-post-uri', $row['ID'], $new_uri, $old_uri, $native_uri, $default_uri);
304
  }
305
 
306
  // Filter array before saving
399
  $updated_array[] = array('item_title' => $row['post_title'], 'ID' => $row['ID'], 'old_uri' => $old_uri, 'new_uri' => $new_uri, 'old_slug' => $old_post_name, 'new_slug' => $new_post_name);
400
  $updated_slugs_count++;
401
  }
402
+
403
+ do_action('permalink-manager-updated-post-uri', $row['ID'], $new_uri, $old_uri, $native_uri, $default_uri);
404
  }
405
 
406
  // Filter array before saving
457
  $updated_array[] = array('item_title' => get_the_title($id), 'ID' => $id, 'old_uri' => $old_uri, 'new_uri' => $new_uri);
458
  $updated_slugs_count++;
459
  }
460
+
461
+ do_action('permalink-manager-updated-post-uri', $id, $new_uri, $old_uri, $native_uri, $default_uri);
462
  }
463
 
464
  // Filter array before saving & append the global
491
 
492
  // Make sure that home URL ends with slash
493
  $home_url = trim(get_option('home'), "/") . "/";
 
494
  $prefix = apply_filters('permalink-manager-post-permalink-prefix', '', $post, true);
495
 
496
  // Do not change anything if post is not saved yet (display sample permalink instead)
513
  $html .= sprintf("<span class=\"sample-permalink-span\"><a href=\"%s\">%s</a></span>&nbsp;", strip_tags($sample_permalink), $sample_permalink);
514
 
515
  if(!empty($uri)) {
516
+ $html .= Permalink_Manager_Admin_Functions::display_uri_box($post, $default_uri, $uri, $native_uri, "{$home_url}{$prefix}");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
517
  }
518
 
519
  // Append hidden field with native slug
536
  $post_id = ($is_revision) ? $is_revision : $post_id;
537
  $post = get_post($post_id);
538
 
539
+ // Hotfix for menu items
540
+ if($post->post_type == 'nav_menu_item') { return; }
541
+
542
  $native_uri = self::get_default_post_uri($post_id, true);
543
  $new_uri = self::get_default_post_uri($post_id);;
544
  $permalink_manager_uris[$post->ID] = $new_uri;
562
  $post_id = ($is_revision) ? $is_revision : $post_id;
563
  $post = get_post($post_id);
564
 
565
+ // Hotfix for menu items
566
+ if($post->post_type == 'nav_menu_item') { return; }
567
+
568
  // Ignore auto-drafts & removed posts
569
  if(in_array($post->post_status, array('auto-draft', 'trash')) || (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || (!empty($_REQUEST['bulk_edit'])) || (!empty($_REQUEST['post_view']))) { return; }
570
 
includes/views/permalink-manager-debug.php CHANGED
@@ -19,12 +19,7 @@ class Permalink_Manager_Debug extends Permalink_Manager_Class {
19
  }
20
 
21
  public function output() {
22
- global $permalink_manager_options, $permalink_manager_uris, $permalink_manager_permastructs, $wp_filter;
23
-
24
- // Get permalink hooks
25
- foreach(array('_get_page_link', 'post_link', 'page_link', 'post_type_link') as $hook) {
26
- $permalink_hooks[$hook] = json_encode($wp_filter[$hook]);
27
- }
28
 
29
  $sections_and_fields = apply_filters('permalink-manager-debug-fields', array(
30
  'debug-data' => array(
@@ -37,6 +32,13 @@ class Permalink_Manager_Debug extends Permalink_Manager_Class {
37
  'input_class' => 'short-textarea widefat',
38
  'value' => ($permalink_manager_uris) ? print_r($permalink_manager_uris, true) : ''
39
  ),
 
 
 
 
 
 
 
40
  'permastructs' => array(
41
  'type' => 'textarea',
42
  'description' => __('List of the permastructures.', 'permalink-manager'),
@@ -50,13 +52,6 @@ class Permalink_Manager_Debug extends Permalink_Manager_Class {
50
  'label' => __('Array with settings used in this plugin.', 'permalink-manager'),
51
  'input_class' => 'short-textarea widefat',
52
  'value' => print_r($permalink_manager_options, true)
53
- ),
54
- 'hooks' => array(
55
- 'type' => 'textarea',
56
- 'description' => __('Permalink hooks.', 'permalink-manager'),
57
- 'label' => __('Array with list of permalink hooks used on this website.', 'permalink-manager'),
58
- 'input_class' => 'short-textarea widefat',
59
- 'value' => print_r($permalink_hooks, true)
60
  )
61
  )
62
  )
19
  }
20
 
21
  public function output() {
22
+ global $permalink_manager_options, $permalink_manager_uris, $permalink_manager_permastructs, $permalink_manager_redirects, $wp_filter;
 
 
 
 
 
23
 
24
  $sections_and_fields = apply_filters('permalink-manager-debug-fields', array(
25
  'debug-data' => array(
32
  'input_class' => 'short-textarea widefat',
33
  'value' => ($permalink_manager_uris) ? print_r($permalink_manager_uris, true) : ''
34
  ),
35
+ 'custom-redirects' => array(
36
+ 'type' => 'textarea',
37
+ 'description' => __('List of custom redirects set-up by this plugin.', 'permalink-manager'),
38
+ 'label' => __('Array with redirects', 'permalink-manager'),
39
+ 'input_class' => 'short-textarea widefat',
40
+ 'value' => ($permalink_manager_redirects) ? print_r($permalink_manager_redirects, true) : ''
41
+ ),
42
  'permastructs' => array(
43
  'type' => 'textarea',
44
  'description' => __('List of the permastructures.', 'permalink-manager'),
52
  'label' => __('Array with settings used in this plugin.', 'permalink-manager'),
53
  'input_class' => 'short-textarea widefat',
54
  'value' => print_r($permalink_manager_options, true)
 
 
 
 
 
 
 
55
  )
56
  )
57
  )
includes/views/permalink-manager-settings.php CHANGED
@@ -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 (used when the plugin is disabled) will be redirected to new custom URIs</strong>.', 'permalink-manager')
80
  )
81
  )
82
  ),
@@ -85,11 +85,19 @@ class Permalink_Manager_Settings extends Permalink_Manager_Class {
85
  'container' => 'row',
86
  'name' => 'general',
87
  'fields' => array(
88
- 'decode_uris' => array(
89
  'type' => 'single_checkbox',
90
- 'label' => __('Decode URIs', 'permalink-manager'),
91
  'input_class' => '',
92
- 'description' => __('If enabled, the permalinks with non-ASCII characters may not be recognized in older browsers versions (advanced users only).', 'permalink-manager')
 
 
 
 
 
 
 
 
93
  ),
94
  'force_custom_slugs' => array(
95
  'type' => 'single_checkbox',
@@ -97,28 +105,25 @@ class Permalink_Manager_Settings extends Permalink_Manager_Class {
97
  'input_class' => '',
98
  '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')
99
  ),
100
- 'trailing_slashes' => array(
101
- 'type' => 'select',
102
- 'label' => __('Trailing slashes', 'permalink-manager'),
103
- 'input_class' => 'settings-select',
104
- 'choices' => array(0 => __('Use default settings', 'permalink-manager'), 1 => __('Always add trailing slashes', 'permalink-manager'), 2 => __('Always remove trailing slashes', 'permalink-manager')),
105
- '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')
106
- ),
107
  'disable_slug_appendix' => array(
108
  'type' => 'checkbox',
109
  'label' => __('Disable slug appendix', 'permalink-manager'),
110
  'choices' => $content_types,
111
  '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')
112
  ),
113
- /*'extension_suffix' => array(
 
 
 
 
 
 
114
  'type' => 'select',
115
- 'label' => __('Extension suffix', 'permalink-manager'),
116
  'input_class' => 'settings-select',
117
- 'pro' => true,
118
- 'disabled' => true,
119
- 'choices' => array(0 => __('Do not add', 'permalink-manager'), 'html' => __('Append .html', 'permalink-manager'), 'htm' => __('Append .htm', 'permalink-manager'), 'php' => __('Append .php', 'permalink-manager')),
120
- 'description' => __('Allows to add .html, .htm or .php extension to the end of permalink.', 'permalink-manager')
121
- )*/
122
  )
123
  )
124
  ));
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
  ),
85
  'container' => 'row',
86
  'name' => 'general',
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',
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
+ 'decode_uris' => array(
115
+ 'type' => 'single_checkbox',
116
+ 'label' => __('Decode URIs', 'permalink-manager'),
117
+ 'input_class' => '',
118
+ 'description' => __('If enabled, the permalinks with non-ASCII characters may not be recognized in older browsers versions (advanced users only).', 'permalink-manager')
119
+ ),
120
+ 'trailing_slashes' => array(
121
  'type' => 'select',
122
+ 'label' => __('Trailing slashes', 'permalink-manager'),
123
  'input_class' => 'settings-select',
124
+ 'choices' => array(0 => __('Use default settings', 'permalink-manager'), 1 => __('Always add trailing slashes', 'permalink-manager'), 2 => __('Always remove trailing slashes', 'permalink-manager')),
125
+ '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')
126
+ )
 
 
127
  )
128
  )
129
  ));
includes/views/permalink-manager-tools.php CHANGED
@@ -14,8 +14,12 @@ class Permalink_Manager_Tools extends Permalink_Manager_Class {
14
  $admin_sections['tools'] = array(
15
  'name' => __('Tools', 'permalink-manager'),
16
  'subsections' => array(
 
 
 
 
17
  'find_and_replace' => array(
18
- 'name' => __('Find and replace', 'permalink-manager'),
19
  'function' => array('class' => 'Permalink_Manager_Tools', 'method' => 'find_and_replace_output')
20
  ),
21
  'regenerate_slugs' => array(
@@ -23,7 +27,7 @@ class Permalink_Manager_Tools extends Permalink_Manager_Class {
23
  'function' => array('class' => 'Permalink_Manager_Tools', 'method' => 'regenerate_slugs_output')
24
  ),
25
  'stop_words' => array(
26
- 'name' => __('Stop words', 'permalink-manager'),
27
  'function' => array('class' => 'Permalink_Manager_Admin_Functions', 'method' => 'pro_text')
28
  ),
29
  'import' => array(
@@ -40,6 +44,68 @@ class Permalink_Manager_Tools extends Permalink_Manager_Class {
40
  return wpautop(__('<strong>A MySQL backup is highly recommended before using "<em>Native slugs</em>" mode!</strong>', 'permalink-manager'));
41
  }
42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  public function find_and_replace_output() {
44
  // Get all registered post types array & statuses
45
  $all_post_statuses_array = get_post_statuses();
14
  $admin_sections['tools'] = array(
15
  'name' => __('Tools', 'permalink-manager'),
16
  'subsections' => array(
17
+ 'duplicates' => array(
18
+ 'name' => __('Permalink Duplicates', 'permalink-manager'),
19
+ 'function' => array('class' => 'Permalink_Manager_Tools', 'method' => 'duplicates_output')
20
+ ),
21
  'find_and_replace' => array(
22
+ 'name' => __('Find & Replace', 'permalink-manager'),
23
  'function' => array('class' => 'Permalink_Manager_Tools', 'method' => 'find_and_replace_output')
24
  ),
25
  'regenerate_slugs' => array(
27
  'function' => array('class' => 'Permalink_Manager_Tools', 'method' => 'regenerate_slugs_output')
28
  ),
29
  'stop_words' => array(
30
+ 'name' => __('Stop Words', 'permalink-manager'),
31
  'function' => array('class' => 'Permalink_Manager_Admin_Functions', 'method' => 'pro_text')
32
  ),
33
  'import' => array(
44
  return wpautop(__('<strong>A MySQL backup is highly recommended before using "<em>Native slugs</em>" mode!</strong>', 'permalink-manager'));
45
  }
46
 
47
+ public function duplicates_output() {
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) {
58
+ $html .= "<div class=\"permalink-manager postbox permalink-manager-duplicate-box\">";
59
+ $html .= "<h4 class=\"heading\"><a href=\"{$home_url}/{$uri}\" target=\"_blank\">{$home_url}/{$uri} <span class=\"dashicons dashicons-external\"></span></a></h4>";
60
+ $html .= "<table>";
61
+
62
+ foreach($duplicates as $item_id) {
63
+ $html .= "<tr>";
64
+
65
+ // Detect duplicate type
66
+ preg_match("/(redirect-([\d]+)_)?(?:(tax-)?([\d]*))/", $item_id, $parts);
67
+
68
+ $redirect_type = (!empty($parts[1])) ? __('Extra Redirect', 'permalink-manager') : __('Custom URI', 'permalink-manager');
69
+ $detected_id = $parts[4];
70
+ $detected_index = $parts[2];
71
+ $detected_term = (!empty($parts[3])) ? true : false;
72
+
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>",
94
+ $redirect_type,
95
+ $edit_label
96
+ );
97
+ $html .= "</tr>";
98
+ }
99
+ $html .= "</table>";
100
+ $html .= "</div>";
101
+ }
102
+ } else {
103
+ $html .= sprintf("<p class=\"alert notice-success notice\">%s</p>", __('Congratulations! No duplicated URIs or Redirects found!', 'permalink-manager'));
104
+ }
105
+
106
+ return $html;
107
+ }
108
+
109
  public function find_and_replace_output() {
110
  // Get all registered post types array & statuses
111
  $all_post_statuses_array = get_post_statuses();
includes/views/permalink-manager-upgrade.php CHANGED
@@ -51,8 +51,8 @@ class Permalink_Manager_Upgrade extends Permalink_Manager_Class {
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>", __("First priority support", "permalink-manager"));
55
- $output .= wpautop(__("All Permalink Manager Pro users have early to plugin updates and first priority for support tickets.", "permalink-manager"));
56
  $output .= "</div>";
57
  $output .= "</div>";
58
 
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
 
out/permalink-manager-admin.css CHANGED
@@ -2,7 +2,6 @@
2
  * Permalink Manager CSS
3
  */
4
  #permalink-manager #plugin-name-heading .author-link{color:#959595;font-size:60%;text-decoration:none}
5
- #permalink-manager #permalink-manager-tab-nav > a:first-child{margin-left:0}
6
  #permalink-manager #permalink-manager-tab-nav .section_upgrade,#permalink-manager #permalink-manager-tab-nav .section_support{background:#555;border-color:#555;color:#fff}
7
  #permalink-manager h4{font-size:18px;margin-bottom:10px}
8
  #permalink-manager h5{font-size:15px;margin-bottom:10px}
@@ -18,7 +17,7 @@
18
  #permalink-manager .woocommerce-cart:before{content:"\e01d"}
19
  #permalink-manager .woocommerce-logo:before{content:"\e03d"}
20
 
21
- #permalink-manager .subsubsub{display:block;width:100%;overflow:hidden;margin-bottom:8px}
22
  #permalink-manager .subsubsub li:before{content:" | "}
23
  #permalink-manager .subsubsub li:first-child:before{content:"";color:#aaa}
24
  #permalink-manager .subsubsub li .dashicons,#permalink-manager .subsubsub li .woocommerce-logo{font-size:100%;line-height:200%;height:auto;width:auto}
@@ -88,22 +87,50 @@
88
  #slugdiv #post_name{width:100%}
89
 
90
  /**
91
- * Edit URI box
92
  */
93
  #permalink-manager.permalink-manager-edit-uri-box{margin:10px -10px}
94
  #permalink-manager.permalink-manager-edit-uri-box h2{border-bottom:1px solid #eee}
95
- #permalink-manager.permalink-manager-edit-uri-box .inside{padding:0 10px 10px 10px}
 
 
96
  #permalink-manager.permalink-manager-edit-uri-box .strong{display:block;font-weight:bold;margin-bottom:5px}
97
  #permalink-manager.permalink-manager-edit-uri-box .toggle-indicator:before{content:"\f142";display:inline-block;font:400 20px/1 dashicons}
98
- #permalink-manager.permalink-manager-edit-uri-box .columns-container{margin-left:-10px;margin-right:-10px}
99
- #permalink-manager.permalink-manager-edit-uri-box .columns-container > *{padding-left:10px;padding-right:10px}
100
  #permalink-manager.permalink-manager-edit-uri-box .close-button{float:right;width:36px;height:36px;padding:0;cursor:pointer;display:block}
101
  #permalink-manager.permalink-manager-edit-uri-box .close-icon{margin-top:4px;-webkit-border-radius:50%;border-radius:50%;text-indent:-1px;color:#72777c;line-height:36px;display:block;text-align:center}
102
  #permalink-manager.permalink-manager-edit-uri-box .close-icon:before{content:"\f158";display:inline-block;font:400 20px/1 dashicons;speak:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-decoration:none!important}
103
- #permalink-manager .default-permalink-row{border-top:1px solid #eee;padding-top:10px}
104
- #permalink-manager .default-permalink-row,#permalink-manager .default-permastruct-row{color:#aaa;font-size:90%}
105
  #permalink-manager .restore-default{display:inline-block;text-align:right;width:100%;border-radius:0;color:#959595;text-decoration:none}
106
- #permalink-manager .widefat{width:100% !important}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
 
108
  /**
109
  * Tippy.js custom theme
@@ -135,4 +162,5 @@
135
  }
136
  @media only screen and (max-width :782px) {
137
  #permalink-manager .columns-container .column-1_2,#permalink-manager .columns-container .column-1_3,#permalink-manager .columns-container .column-2_3{width:100%}
 
138
  }
2
  * Permalink Manager CSS
3
  */
4
  #permalink-manager #plugin-name-heading .author-link{color:#959595;font-size:60%;text-decoration:none}
 
5
  #permalink-manager #permalink-manager-tab-nav .section_upgrade,#permalink-manager #permalink-manager-tab-nav .section_support{background:#555;border-color:#555;color:#fff}
6
  #permalink-manager h4{font-size:18px;margin-bottom:10px}
7
  #permalink-manager h5{font-size:15px;margin-bottom:10px}
17
  #permalink-manager .woocommerce-cart:before{content:"\e01d"}
18
  #permalink-manager .woocommerce-logo:before{content:"\e03d"}
19
 
20
+ #permalink-manager .subsubsub{display:block;width:100%;overflow:hidden;margin-bottom:25px}
21
  #permalink-manager .subsubsub li:before{content:" | "}
22
  #permalink-manager .subsubsub li:first-child:before{content:"";color:#aaa}
23
  #permalink-manager .subsubsub li .dashicons,#permalink-manager .subsubsub li .woocommerce-logo{font-size:100%;line-height:200%;height:auto;width:auto}
87
  #slugdiv #post_name{width:100%}
88
 
89
  /**
90
+ * Edit URI & Duplicate box
91
  */
92
  #permalink-manager.permalink-manager-edit-uri-box{margin:10px -10px}
93
  #permalink-manager.permalink-manager-edit-uri-box h2{border-bottom:1px solid #eee}
94
+ #permalink-manager.permalink-manager-edit-uri-box .inside{padding:0 10px 10px 10px;margin-bottom:0}
95
+ #permalink-manager.permalink-manager-edit-uri-box .inside > div{font-size:13px;line-height:1.5;margin:1em 0}
96
+ #permalink-manager.permalink-manager-edit-uri-box .inside > div:last-child,#permalink-manager.permalink-manager-edit-uri-box .inside p:last-child{margin-bottom:0}
97
  #permalink-manager.permalink-manager-edit-uri-box .strong{display:block;font-weight:bold;margin-bottom:5px}
98
  #permalink-manager.permalink-manager-edit-uri-box .toggle-indicator:before{content:"\f142";display:inline-block;font:400 20px/1 dashicons}
99
+ #permalink-manager.permalink-manager-edit-uri-box .columns-container{margin-left:-10px!important;margin-right:-10px!important}
100
+ #permalink-manager.permalink-manager-edit-uri-box .columns-container > *{padding-left:10px!important;padding-right:10px!important}
101
  #permalink-manager.permalink-manager-edit-uri-box .close-button{float:right;width:36px;height:36px;padding:0;cursor:pointer;display:block}
102
  #permalink-manager.permalink-manager-edit-uri-box .close-icon{margin-top:4px;-webkit-border-radius:50%;border-radius:50%;text-indent:-1px;color:#72777c;line-height:36px;display:block;text-align:center}
103
  #permalink-manager.permalink-manager-edit-uri-box .close-icon:before{content:"\f158";display:inline-block;font:400 20px/1 dashicons;speak:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-decoration:none!important}
104
+ #permalink-manager .default-permalink-row,#permalink-manager .redirects-row{border-top:1px solid #eee;padding-top:10px}
105
+ #permalink-manager .default-permalink-row,#permalink-manager .default-permastruct-row,#permalink-manager .redirects-row{color:#aaa;font-size:90%}
106
  #permalink-manager .restore-default{display:inline-block;text-align:right;width:100%;border-radius:0;color:#959595;text-decoration:none}
107
+ #permalink-manager .widefat,#permalink-manager #redirect-panel-inside,#permalink-manager #redirect-panel-inside table{width:100%!important}
108
+ #permalink-manager .heading,#permalink-manager .heading a{margin:0;line-height:1.4;font-weight:600;text-decoration:none}
109
+ #permalink-manager.permalink-manager-edit-term .permalink-manager-edit-uri-box{display:block!important;margin:0}
110
+ #permalink-manager.permalink-manager-edit-term .permalink-manager-edit-uri-box h2,.permalink-manager.postbox .heading{font-size:14px!important;padding:8px 12px;margin:0;line-height:1.4}
111
+ #permalink-manager.permalink-manager-edit-term .permalink-manager-edit-uri-box .close-button,#permalink-manager.permalink-manager-edit-term #permalink-manager-toggle{display:none}
112
+ #permalink-manager .permalink-manager-duplicate-box table{width:100%;color:#aaa}
113
+ #permalink-manager .permalink-manager-duplicate-box table tr td{border-top:1px solid #eee}
114
+ #permalink-manager .permalink-manager-duplicate-box table tr:first-child td{border-top:0}
115
+ #permalink-manager .permalink-manager-duplicate-box table td{font-size:12px;line-height:1.5em;padding:8px 12px}
116
+ #permalink-manager .permalink-manager-duplicate-box table tr td:first-child{width:60%}
117
+ #permalink-manager .permalink-manager-duplicate-box table tr td:last-child{text-align:right}
118
+ #permalink-manager .permalink-manager-duplicate-box .actions a{text-decoration:none}
119
+ #permalink-manager .permalink-manager-duplicate-box .remove-duplicate-link{color:#a00}
120
+ .permalink-manager.postbox .heading{border-bottom:3px double #eee}
121
+ .permalink-manager.postbox a{color:#444;text-decoration:none;white-space:nowrap}
122
+
123
+ /**
124
+ * Redirect panel
125
+ */
126
+ .permalink-manager #redirect-panel-inside{display:none}
127
+ .permalink-manager #redirect-panel-inside,#permalink-manager #redirect-panel-inside p{margin-top:10px}
128
+ .permalink-manager #redirect-panel-inside table{margin-bottom:10px}
129
+ .permalink-manager #redirect-panel-inside table td{padding:5px 0;width:100%}
130
+ .permalink-manager #redirect-panel-inside table td a{text-decoration:none;text-align:right}
131
+ .permalink-manager .sample-row{display:none}
132
+ .permalink-manager .redirects-panel-description{margin-bottom:10px}
133
+ .permalink-manager .redirects-panel-description *{font-size:12px}
134
 
135
  /**
136
  * Tippy.js custom theme
162
  }
163
  @media only screen and (max-width :782px) {
164
  #permalink-manager .columns-container .column-1_2,#permalink-manager .columns-container .column-1_3,#permalink-manager .columns-container .column-2_3{width:100%}
165
+ #permalink-manager .permalink-manager-duplicate-box table tr td:first-child{width:40%}
166
  }
out/permalink-manager-admin.js CHANGED
@@ -57,7 +57,38 @@ jQuery(document).ready(function() {
57
  jQuery('.permalink-manager-edit-uri-box').slideToggle();
58
 
59
  return false;
60
- }).trigger('keyup');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
  /**
63
  * Synchronize "Edit URI" input field with the sample permalink
57
  jQuery('.permalink-manager-edit-uri-box').slideToggle();
58
 
59
  return false;
60
+ });
61
+
62
+ /**
63
+ * Toggle "Edit Redirects" box
64
+ */
65
+ jQuery('#toggle-redirect-panel').on('click', function() {
66
+ jQuery('#redirect-panel-inside').slideToggle();
67
+
68
+ return false;
69
+ });
70
+
71
+ jQuery('.permalink-manager.redirects-panel #permalink-manager-new-redirect').on('click', function() {
72
+ // Find the table
73
+ var table = jQuery(this).parents('.redirects-panel').find('table');
74
+
75
+ // Copy the row from the sample
76
+ var new_row = jQuery(this).parents('.redirects-panel').find('.sample-row').clone().removeClass('sample-row');
77
+
78
+ // Adjust the array key
79
+ var last_key = jQuery(table).find("tr:last-of-type input[data-index]").data("index") + 1;
80
+ jQuery("input[data-index]", new_row).attr("data-index", last_key).attr("name", function(){ return jQuery(this).attr("name") + "[" + last_key + "]" });
81
+
82
+ // Append the new row
83
+ jQuery(table).append(new_row);
84
+
85
+ return false;
86
+ });
87
+
88
+ jQuery('.permalink-manager.redirects-panel').on('click', '.remove-redirect', function() {
89
+ var table = jQuery(this).closest('tr').remove();
90
+ return false;
91
+ });
92
 
93
  /**
94
  * Synchronize "Edit URI" input field with the sample permalink
permalink-manager.php CHANGED
@@ -4,7 +4,7 @@
4
  * Plugin Name: Permalink Manager Lite
5
  * Plugin URI: https://permalinkmanager.pro?utm_source=plugin
6
  * Description: Most advanced Permalink utility for Wordpress. It allows to bulk edit the permalinks & permastructures and regenerate/reset all the URIs in your Wordpress instance.
7
- * Version: 1.11.6
8
  * Author: Maciej Bis
9
  * Author URI: http://maciejbis.net/
10
  * License: GPL-2.0+
@@ -21,7 +21,8 @@ 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', '1.11.6' );
 
25
  define( 'PERMALINK_MANAGER_DIR', untrailingslashit( dirname( __FILE__ ) ) );
26
  define( 'PERMALINK_MANAGER_BASENAME', plugin_basename(__FILE__) );
27
  define( 'PERMALINK_MANAGER_URL', untrailingslashit( plugins_url( '', __FILE__ ) ) );
@@ -103,9 +104,6 @@ class Permalink_Manager_Class {
103
  // Default settings & alerts
104
  add_filter( 'permalink-manager-options', array($this, 'default_settings'), 1 );
105
  add_filter( 'permalink-manager-alerts', array($this, 'default_alerts'), 1 );
106
-
107
- // Check for updates
108
- add_action( 'init', array($this, 'check_for_updates'), 999 );
109
  }
110
 
111
  /**
@@ -120,11 +118,12 @@ class Permalink_Manager_Class {
120
  */
121
  public function get_options_and_globals() {
122
  // 1. Globals with data stored in DB
123
- global $permalink_manager_options, $permalink_manager_uris, $permalink_manager_permastructs;
124
 
125
  $this->permalink_manager_options = $permalink_manager_options = apply_filters('permalink-manager-options', get_option('permalink-manager', array()));
126
  $this->permalink_manager_uris = $permalink_manager_uris = apply_filters('permalink-manager-uris', get_option('permalink-manager-uris', array()));
127
  $this->permalink_manager_permastructs = $permalink_manager_permastructs = apply_filters('permalink-manager-permastructs', get_option('permalink-manager-permastructs', array()));
 
128
 
129
  // 2. Globals used to display additional content (eg. alerts)
130
  global $permalink_manager_alerts, $permalink_manager_before_sections_html, $permalink_manager_after_sections_html;
@@ -157,6 +156,8 @@ class Permalink_Manager_Class {
157
  'yoast_attachment_redirect' => 1,
158
  'canonical_redirect' => 1,
159
  'trailing_slashes' => 0,
 
 
160
  'disable_slug_appendix' => array()
161
  ),
162
  'licence' => array()
@@ -179,15 +180,15 @@ class Permalink_Manager_Class {
179
  */
180
  public function default_alerts($alerts) {
181
  $default_alerts = apply_filters('permalink-manager-default-alerts', array(
182
- 'september' => array(
183
  'txt' => sprintf(
184
- __("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 \"SUMMER\" coupon code!</strong>", "permalink-manager"),
185
  PERMALINK_MANAGER_WEBSITE
186
  ),
187
  'type' => 'notice-info',
188
  'show' => 'pro_hide',
189
  'plugin_only' => true,
190
- 'until' => '2017-09-10'
191
  )
192
  ));
193
 
@@ -232,32 +233,6 @@ class Permalink_Manager_Class {
232
  }
233
  }
234
 
235
- /**
236
- * Update check
237
- */
238
- public function check_for_updates() {
239
- global $permalink_manager_options;
240
-
241
- if(defined('PERMALINK_MANAGER_PRO')) {
242
- // Get the licence key
243
- $license_key = (!empty($permalink_manager_options['licence']['licence_key'])) ? $permalink_manager_options['licence']['licence_key'] : "";
244
-
245
- // Get expiration date
246
- // add_filter('puc_request_info_result-permalink-manager-pro', array($this, 'update_pro_info'), 99, 2);
247
-
248
- // Load Plugin Update Checker by YahnisElsts
249
- require_once PERMALINK_MANAGER_DIR . '/includes/ext/plugin-update-checker/plugin-update-checker.php';
250
-
251
- $UpdateChecker = Puc_v4_Factory::buildUpdateChecker(
252
- "https://updates.permalinkmanager.pro/?action=get_metadata&slug=permalink-manager-pro&license_key={$license_key}",
253
- __FILE__,
254
- "permalink-manager-pro"
255
- );
256
-
257
- $file = PERMALINK_MANAGER_BASENAME;
258
- }
259
- }
260
-
261
  }
262
 
263
  /**
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.0
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.0' );
25
+ define( 'PERMALINK_MANAGER_FILE', __FILE__ );
26
  define( 'PERMALINK_MANAGER_DIR', untrailingslashit( dirname( __FILE__ ) ) );
27
  define( 'PERMALINK_MANAGER_BASENAME', plugin_basename(__FILE__) );
28
  define( 'PERMALINK_MANAGER_URL', untrailingslashit( plugins_url( '', __FILE__ ) ) );
104
  // Default settings & alerts
105
  add_filter( 'permalink-manager-options', array($this, 'default_settings'), 1 );
106
  add_filter( 'permalink-manager-alerts', array($this, 'default_alerts'), 1 );
 
 
 
107
  }
108
 
109
  /**
118
  */
119
  public function get_options_and_globals() {
120
  // 1. Globals with data stored in DB
121
+ global $permalink_manager_options, $permalink_manager_uris, $permalink_manager_permastructs, $permalink_manager_redirects;
122
 
123
  $this->permalink_manager_options = $permalink_manager_options = apply_filters('permalink-manager-options', get_option('permalink-manager', array()));
124
  $this->permalink_manager_uris = $permalink_manager_uris = apply_filters('permalink-manager-uris', get_option('permalink-manager-uris', array()));
125
  $this->permalink_manager_permastructs = $permalink_manager_permastructs = apply_filters('permalink-manager-permastructs', get_option('permalink-manager-permastructs', array()));
126
+ $this->permalink_manager_redirects = $permalink_manager_redirects = apply_filters('permalink-manager-redirects', get_option('permalink-manager-redirects', array()));
127
 
128
  // 2. Globals used to display additional content (eg. alerts)
129
  global $permalink_manager_alerts, $permalink_manager_before_sections_html, $permalink_manager_after_sections_html;
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
  ),
163
  'licence' => array()
180
  */
181
  public function default_alerts($alerts) {
182
  $default_alerts = apply_filters('permalink-manager-default-alerts', array(
183
+ 'sept' => 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 25&#37; using \"SEPTEMBER\" coupon code (valid until 30th September)!</strong>", "permalink-manager"),
186
  PERMALINK_MANAGER_WEBSITE
187
  ),
188
  'type' => 'notice-info',
189
  'show' => 'pro_hide',
190
  'plugin_only' => true,
191
+ 'until' => '2017-10-01'
192
  )
193
  ));
194
 
233
  }
234
  }
235
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
  }
237
 
238
  /**