Custom Permalinks - Version 2.0.0

Version Description

  • Jul 30, 2021 =

  • Bugs

    • Bug with AMP plugin
    • Oembed links not working
    • Uncaught (in promise) TypeError: getHomeURL is null
    • Plugin stop saving uppercase slugs
    • template_redirect
    • conflict with WooCommerce Paid courses
    • Fix creating duplicated permalink while creating multiple Categories and/or Tags
  • Enhancements

    • Added Query caching to improve performance
    • Changed Permalink sanitization method (Similar way as WP does)
    • Added Nonce verification to make forms secure
    • Permalink Filter before saving
    • Show/Hide column and Pagination features added on Post Type Permalinks and Taxonomies Permalinks page
    • Removed deprecated functions
    • Applied WPCS Standards
Download this release

Release Info

Developer sasiddiqui
Plugin Icon Custom Permalinks
Version 2.0.0
Comparing to
See all releases

Code changes from version 1.7.1 to 2.0.0

Files changed (34) hide show
  1. admin/class-custom-permalinks-about.php +248 -264
  2. admin/class-custom-permalinks-admin.php +241 -169
  3. admin/class-custom-permalinks-pager.php +0 -109
  4. admin/class-custom-permalinks-post-types-table.php +511 -0
  5. admin/class-custom-permalinks-post-types.php +158 -0
  6. admin/class-custom-permalinks-posttypes.php +0 -342
  7. admin/class-custom-permalinks-taxonomies-table.php +501 -0
  8. admin/class-custom-permalinks-taxonomies.php +122 -308
  9. admin/class-custom-permalinks-updates.php +57 -55
  10. admin/css/about-plugins-1.7.1.min.css → assets/css/about-plugins-2.0.0.min.css +1 -1
  11. {admin → assets}/images/custom-permalinks.svg +0 -0
  12. {admin → assets}/images/http-auth.svg +0 -0
  13. {admin → assets}/images/json-structuring-markup.svg +0 -0
  14. {admin → assets}/images/make-paths-relative.svg +0 -0
  15. {admin → assets}/images/media-post-permalink.png +0 -0
  16. {admin → assets}/images/media-post-permalink.svg +0 -0
  17. {admin → assets}/images/permalinks-customizer.svg +0 -0
  18. {admin → assets}/images/prevent-xss-vulnerability.png +0 -0
  19. {admin → assets}/images/prevent-xss-vulnerability.svg +0 -0
  20. {admin → assets}/images/remove-links-and-scripts.svg +0 -0
  21. {admin → assets}/images/schema-for-article.svg +0 -0
  22. assets/js/script-form-2.0.0.min.js +1 -0
  23. changelog.txt +40 -0
  24. custom-permalinks.php +13 -161
  25. frontend/class-custom-permalinks-form.php +0 -732
  26. frontend/class-custom-permalinks-frontend.php +0 -792
  27. frontend/js/script-form-1.7.1.min.js +0 -1
  28. includes/class-custom-permalinks-form.php +862 -0
  29. includes/class-custom-permalinks-frontend.php +941 -0
  30. includes/class-custom-permalinks.php +188 -0
  31. {frontend → includes}/index.php +0 -0
  32. languages/index.php +1 -1
  33. readme.txt +82 -99
  34. uninstall.php +11 -11
admin/class-custom-permalinks-about.php CHANGED
@@ -1,271 +1,255 @@
1
  <?php
2
  /**
 
 
3
  * @package CustomPermalinks
4
  */
5
 
6
- class Custom_Permalinks_About
7
- {
8
- /*
9
- * Css file suffix (version number with with extension)
10
- */
11
- private $css_file_suffix = '-' . CUSTOM_PERMALINKS_PLUGIN_VERSION . '.min.css';
12
-
13
- /**
14
- * Class constructor.
15
- */
16
- public function __construct()
17
- {
18
- $this->more_plugins();
19
- }
20
-
21
- /**
22
- * Print HTML for Custom Permalinks About Page.
23
- *
24
- * @since 1.2.11
25
- * @access private
26
- */
27
- private function more_plugins()
28
- {
29
- $filename = 'about-plugins' . $this->css_file_suffix;
30
- $plugin_url = plugins_url( '/admin', CUSTOM_PERMALINKS_FILE );
31
- $img_src = $plugin_url . '/images';
32
- wp_enqueue_style( 'style', $plugin_url . '/css/' . $filename );
33
-
34
- $fivestar = '<span class="star">
35
- <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 53.867 53.867" width="15" height="15">
36
- <polygon points="26.934,1.318 35.256,18.182 53.867,20.887 40.4,34.013 43.579,52.549 26.934,43.798
37
- 10.288,52.549 13.467,34.013 0,20.887 18.611,18.182 "/>
38
- </svg>
39
- <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 53.867 53.867" width="15" height="15">
40
- <polygon points="26.934,1.318 35.256,18.182 53.867,20.887 40.4,34.013 43.579,52.549 26.934,43.798
41
- 10.288,52.549 13.467,34.013 0,20.887 18.611,18.182 "/>
42
- </svg>
43
- <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 53.867 53.867" width="15" height="15">
44
- <polygon points="26.934,1.318 35.256,18.182 53.867,20.887 40.4,34.013 43.579,52.549 26.934,43.798
45
- 10.288,52.549 13.467,34.013 0,20.887 18.611,18.182 "/>
46
- </svg>
47
- <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 53.867 53.867" width="15" height="15">
48
- <polygon points="26.934,1.318 35.256,18.182 53.867,20.887 40.4,34.013 43.579,52.549 26.934,43.798
49
- 10.288,52.549 13.467,34.013 0,20.887 18.611,18.182 "/>
50
- </svg>
51
- <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 53.867 53.867" width="15" height="15">
52
- <polygon points="26.934,1.318 35.256,18.182 53.867,20.887 40.4,34.013 43.579,52.549 26.934,43.798
53
- 10.288,52.549 13.467,34.013 0,20.887 18.611,18.182 "/>
54
- </svg>
55
- </span>';
56
- ?>
57
-
58
- <div class="wrap">
59
- <div class="float">
60
- <h1>
61
- <?php
62
- esc_html_e( 'Custom Permalinks v' . CUSTOM_PERMALINKS_PLUGIN_VERSION, 'custom-permalinks' );
63
- ?>
64
- </h1>
65
- <div class="tagline">
66
- <p>
67
- <?php
68
- esc_html_e(
69
- 'Thank you for choosing Custom Permalinks! We hope that your experience with our plugin for updating permalinks is quick and easy. We are trying to make it more feasible for you and provide capabilities in it.',
70
- 'custom-permalinks'
71
- );
72
- ?>
73
- </p>
74
- <p>
75
- <?php
76
- printf(
77
- __(
78
- 'To support future development and help to make it even better just leaving us a <a href="%s" title="Custom Permalinks Rating" target="_blank">%s</a> rating with a nice message to me :)',
79
- 'custom-permalinks'
80
- ),
81
- 'https://wordpress.org/support/plugin/custom-permalinks/reviews/?rate=5#new-post',
82
- $fivestar
83
- );
84
- ?>
85
- </p>
86
- </div>
87
- </div>
88
-
89
- <div class="float">
90
- <object type="image/svg+xml" data="<?php echo esc_url( $img_src . '/custom-permalinks.svg' );?>" width="128" height="128"></object>
91
- </div>
92
-
93
- <div class="product">
94
- <h2>
95
- <?php
96
- esc_html_e( 'More from Sami Ahmed Siddiqui', 'custom-permalinks' );
97
- ?>
98
- </h2>
99
- <span>
100
- <?php
101
- esc_html_e(
102
- 'Our List of Plugins provides the services which help you to prevent your site from XSS Attacks, Brute force attack, change absolute paths to relative, increase your site visitors by adding Structured JSON Markup and so on.',
103
- 'custom-permalinks'
104
- );
105
- ?>
106
- </span>
107
- <div class="box recommended">
108
- <div class="img">
109
- <img src="<?php echo esc_url( $img_src . '/prevent-xss-vulnerability.png' ); ?>" style="transform:scale(1.5)" />
110
- </div>
111
-
112
- <h3>
113
- <?php
114
- esc_html_e( 'Prevent XSS Vulnerability', 'custom-permalinks' );
115
- ?>
116
- </h3>
117
- <p>
118
- <?php
119
- esc_html_e(
120
- 'Secure your site from the XSS Attacks so, your users won\'t lose any kind of information or not redirected to any other site by visiting your site with the malicious code in the URL or so. In this way, users can open their site URLs without any hesitation.',
121
- 'custom-permalinks'
122
- );
123
- ?>
124
- </p>
125
- <a href="https://wordpress.org/plugins/prevent-xss-vulnerability/" class="checkout-button" target="_blank">
126
- <?php esc_html_e( 'Check it out', 'custom-permalinks' ); ?>
127
- </a>
128
- </div>
129
-
130
- <div class="box recommended">
131
- <div class="img">
132
- <img src="<?php echo esc_url( $img_src . '/http-auth.svg' ); ?>" />
133
- </div>
134
-
135
- <h3>
136
- <?php
137
- esc_html_e( 'HTTP Auth', 'custom-permalinks' );
138
- ?>
139
- </h3>
140
- <p>
141
- <?php
142
- esc_html_e(
143
- 'Allows you apply HTTP Auth on your site. You can apply Http Authentication all over the site or only the admin pages. It helps to stop crawling on your site while on development or persist the Brute Attacks by locking the Admin Pages.',
144
- 'custom-permalinks'
145
- );
146
- ?>
147
- </p>
148
- <a href="https://wordpress.org/plugins/http-auth/" class="checkout-button" target="_blank">
149
- <?php esc_html_e( 'Check it out', 'custom-permalinks' ); ?>
150
- </a>
151
- </div>
152
-
153
- <div class="box">
154
- <div class="img">
155
- <img src="<?php echo esc_url( $img_src . '/make-paths-relative.svg' ); ?>" />
156
- </div>
157
-
158
- <h3>
159
- <?php
160
- esc_html_e( 'Make Paths Relative', 'custom-permalinks' );
161
- ?>
162
- </h3>
163
- <p>
164
- <?php
165
- esc_html_e(
166
- 'Convert the paths(URLs) to relative instead of absolute. You can make Post, Category, Archive, Image URLs and Script and Style src as per your requirement. You can choose which you want to be relative from the settings Page.',
167
- 'custom-permalinks'
168
- );
169
- ?>
170
- </p>
171
- <a href="https://wordpress.org/plugins/make-paths-relative/" class="checkout-button" target="_blank">
172
- <?php esc_html_e( 'Check it out', 'custom-permalinks' ); ?>
173
- </a>
174
- </div>
175
-
176
- <div class="box">
177
- <div class="img">
178
- <img src="<?php echo esc_url( $img_src . '/schema-for-article.svg' ); ?>" />
179
- </div>
180
-
181
- <h3>
182
- <?php
183
- esc_html_e( 'SCHEMA for Article', 'custom-permalinks' );
184
- ?>
185
- </h3>
186
- <p>
187
- <?php
188
- esc_html_e(
189
- 'Simply the easiest solution to add valid schema.org as a JSON script in the head of blog posts or articles. You can choose the schema either to show with the type of Article or NewsArticle from the settings page.',
190
- 'custom-permalinks'
191
- );
192
- ?>
193
- </p>
194
- <a href="https://wordpress.org/plugins/schema-for-article/" class="checkout-button" target="_blank">
195
- <?php esc_html_e( 'Check it out', 'custom-permalinks' ); ?>
196
- </a>
197
- </div>
198
-
199
- <div class="box">
200
- <div class="img">
201
- <img src="<?php echo esc_url( $img_src . '/remove-links-and-scripts.svg' ); ?>" />
202
- </div>
203
-
204
- <h3>
205
- <?php
206
- esc_html_e( 'Remove Links and Scripts', 'custom-permalinks' );
207
- ?>
208
- </h3>
209
- <p>
210
- <?php
211
- esc_html_e(
212
- 'It removes some meta data from the wordpress header so, your header keeps clean of useless information like shortlink, rsd_link, wlwmanifest_link, emoji_scripts, wp_embed, wp_json, emoji_styles, generator and so on.',
213
- 'custom-permalinks'
214
- );
215
- ?>
216
- </p>
217
- <a href="https://wordpress.org/plugins/remove-links-and-scripts/" class="checkout-button" target="_blank">
218
- <?php esc_html_e( 'Check it out', 'custom-permalinks' ); ?>
219
- </a>
220
- </div>
221
-
222
- <div class="box">
223
- <div class="img">
224
- <img src="<?php echo esc_url( $img_src . '/media-post-permalink.png' ); ?>" style="transform:scale(1.5)" />
225
- </div>
226
-
227
- <h3>
228
- <?php
229
- esc_html_e( 'Media Post Permalink', 'custom-permalinks' );
230
- ?>
231
- </h3>
232
- <p>
233
- <?php
234
- esc_html_e(
235
- 'On uploading any image, let\'s say services.png, WordPress creates the attachment post with the permalink of /services/ and doesn\'t allow you to use that permalink to point your page. In this case, we come up with this great solution.',
236
- 'custom-permalinks'
237
- );
238
- ?>
239
- </p>
240
- <a href="https://wordpress.org/plugins/media-post-permalink/" class="checkout-button" target="_blank">
241
- <?php esc_html_e( 'Check it out', 'custom-permalinks' ); ?>
242
- </a>
243
- </div>
244
-
245
- <div class="box">
246
- <div class="img">
247
- <img src="<?php echo esc_url( $img_src . '/json-structuring-markup.svg' ); ?>" />
248
- </div>
249
 
250
- <h3>
251
- <?php
252
- esc_html_e( 'JSON Structuring Markup', 'custom-permalinks' );
253
- ?>
254
- </h3>
255
- <p>
256
- <?php
257
- esc_html_e(
258
- 'Simply the easiest solution to add valid schema.org as a JSON script in the head of posts and pages. It provides you multiple SCHEMA types like Article, News Article, Organization and Website Schema.',
259
- 'custom-permalinks'
260
- );
261
- ?>
262
- </p>
263
- <a href="https://wordpress.org/plugins/json-structuring-markup/" class="checkout-button" target="_blank">
264
- <?php esc_html_e( 'Check it out', 'custom-permalinks' ); ?>
265
- </a>
266
- </div>
267
- </div>
268
- </div>
269
- <?php
270
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
  }
1
  <?php
2
  /**
3
+ * Custom Permalinks About.
4
+ *
5
  * @package CustomPermalinks
6
  */
7
 
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
10
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
+ /**
13
+ * Generate about page HTML.
14
+ */
15
+ class Custom_Permalinks_About {
16
+ /**
17
+ * Class constructor.
18
+ */
19
+ public function __construct() {
20
+ $this->more_plugins();
21
+ }
22
+
23
+ /**
24
+ * Print HTML for Custom Permalinks About Page.
25
+ *
26
+ * @since 1.2.11
27
+ * @access private
28
+ *
29
+ * @return void
30
+ */
31
+ private function more_plugins() {
32
+ $img_src = plugins_url( '/assets/images', CUSTOM_PERMALINKS_FILE )
33
+ ?>
34
+
35
+ <div class="wrap">
36
+ <div class="float">
37
+ <h1>
38
+ <?php
39
+ esc_html_e(
40
+ // translators: After `v` there will be a Plugin version.
41
+ // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText
42
+ 'Custom Permalinks v' . CUSTOM_PERMALINKS_VERSION,
43
+ 'custom-permalinks'
44
+ );
45
+ ?>
46
+ </h1>
47
+ <div class="tagline">
48
+ <p>
49
+ <?php
50
+ esc_html_e(
51
+ 'Thank you for choosing Custom Permalinks! I hope that your experience with our plugin for updating permalinks is quick and easy. I am trying to make it more feasible for you and provide capabilities in it.',
52
+ 'custom-permalinks'
53
+ );
54
+ ?>
55
+ </p>
56
+ <p>
57
+ <?php
58
+ esc_html_e(
59
+ 'To support future development and to help make it even better please leave a',
60
+ 'custom-permalinks'
61
+ );
62
+ ?>
63
+ <a href="https://wordpress.org/support/plugin/custom-permalinks/reviews/?rate=5#new-post" title="Custom Permalinks Rating" target="_blank">
64
+ <?php
65
+ esc_html_e( '5-star', 'custom-permalinks' );
66
+ ?>
67
+ </a>
68
+ <?php
69
+ esc_html_e(
70
+ 'rating with a nice message to me :)',
71
+ 'custom-permalinks'
72
+ );
73
+ ?>
74
+ </p>
75
+ </div>
76
+ </div>
77
+
78
+ <div class="float">
79
+ <?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
80
+ <img src="<?php echo $img_src . '/custom-permalinks.svg'; ?>" alt="<?php esc_html_e( 'Custom Permalinks', 'custom-permalinks' ); ?>" title="<?php esc_html_e( 'Custom Permalinks', 'custom-permalinks' ); ?>" />
81
+ </div>
82
+
83
+ <div class="product">
84
+ <h2>
85
+ <?php esc_html_e( 'More from Sami Ahmed Siddiqui', 'custom-permalinks' ); ?>
86
+ </h2>
87
+ <span>
88
+ <?php
89
+ esc_html_e(
90
+ 'Our List of Plugins provides the services which help you to prevent your site from XSS Attacks, Brute force attack, change absolute paths to relative, increase your site visitors by adding Structured JSON Markup and so on.',
91
+ 'custom-permalinks'
92
+ );
93
+ ?>
94
+ </span>
95
+
96
+ <div class="box recommended">
97
+ <div class="img">
98
+ <?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
99
+ <img src="<?php echo $img_src . '/prevent-xss-vulnerability.png'; ?>" alt="<?php esc_html_e( 'Prevent XSS Vulnerability', 'custom-permalinks' ); ?>" title="<?php esc_html_e( 'Prevent XSS Vulnerability', 'custom-permalinks' ); ?>" style="transform:scale(1.5)" />
100
+ </div>
101
+
102
+ <h3>
103
+ <?php
104
+ esc_html_e( 'Prevent XSS Vulnerability', 'custom-permalinks' );
105
+ ?>
106
+ </h3>
107
+ <p>
108
+ <?php
109
+ esc_html_e(
110
+ 'Secure your site from the XSS Attacks so, your users won\'t lose any kind of information or not redirected to any other site by visiting your site with the malicious code in the URL or so. In this way, users can open their site URLs without any hesitation.',
111
+ 'custom-permalinks'
112
+ );
113
+ ?>
114
+ </p>
115
+ <a href="https://wordpress.org/plugins/prevent-xss-vulnerability/" class="checkout-button" title="<?php esc_html_e( 'Prevent XSS Vulnerability', 'custom-permalinks' ); ?>" target="_blank">
116
+ <?php esc_html_e( 'Check it out', 'custom-permalinks' ); ?>
117
+ </a>
118
+ </div>
119
+
120
+ <div class="box recommended">
121
+ <div class="img">
122
+ <?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
123
+ <img src="<?php echo $img_src . '/http-auth.svg'; ?>" alt="<?php esc_html_e( 'HTTP Auth', 'custom-permalinks' ); ?>" title="<?php esc_html_e( 'HTTP Auth', 'custom-permalinks' ); ?>" />
124
+ </div>
125
+
126
+ <h3>
127
+ <?php esc_html_e( 'HTTP Auth', 'custom-permalinks' ); ?>
128
+ </h3>
129
+ <p>
130
+ <?php
131
+ esc_html_e(
132
+ 'Allows you apply HTTP Auth on your site. You can apply Http Authentication all over the site or only the admin pages. It helps to stop crawling on your site while on development or persist the Brute Attacks by locking the Admin Pages.',
133
+ 'custom-permalinks'
134
+ );
135
+ ?>
136
+ </p>
137
+ <a href="https://wordpress.org/plugins/http-auth/" class="checkout-button" title="<?php esc_html_e( 'HTTP Auth', 'custom-permalinks' ); ?>" target="_blank">
138
+ <?php esc_html_e( 'Check it out', 'custom-permalinks' ); ?>
139
+ </a>
140
+ </div>
141
+
142
+ <div class="box">
143
+ <div class="img">
144
+ <?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
145
+ <img src="<?php echo $img_src . '/make-paths-relative.svg'; ?>" alt="<?php esc_html_e( 'Make Paths Relative', 'custom-permalinks' ); ?>" title="<?php esc_html_e( 'Make Paths Relative', 'custom-permalinks' ); ?>" />
146
+ </div>
147
+
148
+ <h3>
149
+ <?php esc_html_e( 'Make Paths Relative', 'custom-permalinks' ); ?>
150
+ </h3>
151
+ <p>
152
+ <?php
153
+ esc_html_e(
154
+ 'Convert the paths(URLs) to relative instead of absolute. You can make Post, Category, Archive, Image URLs and Script and Style src as per your requirement. You can choose which you want to be relative from the settings Page.',
155
+ 'custom-permalinks'
156
+ );
157
+ ?>
158
+ </p>
159
+ <a href="https://wordpress.org/plugins/make-paths-relative/" class="checkout-button" title="<?php esc_html_e( 'Make Paths Relative', 'custom-permalinks' ); ?>" target="_blank">
160
+ <?php esc_html_e( 'Check it out', 'custom-permalinks' ); ?>
161
+ </a>
162
+ </div>
163
+
164
+ <div class="box">
165
+ <div class="img">
166
+ <?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
167
+ <img src="<?php echo $img_src . '/schema-for-article.svg'; ?>" alt="<?php esc_html_e( 'SCHEMA for Article', 'custom-permalinks' ); ?>" title="<?php esc_html_e( 'SCHEMA for Article', 'custom-permalinks' ); ?>" />
168
+ </div>
169
+
170
+ <h3>
171
+ <?php esc_html_e( 'SCHEMA for Article', 'custom-permalinks' ); ?>
172
+ </h3>
173
+ <p>
174
+ <?php
175
+ esc_html_e(
176
+ 'Simply the easiest solution to add valid schema.org as a JSON script in the head of blog posts or articles. You can choose the schema either to show with the type of Article or NewsArticle from the settings page.',
177
+ 'custom-permalinks'
178
+ );
179
+ ?>
180
+ </p>
181
+ <a href="https://wordpress.org/plugins/schema-for-article/" class="checkout-button" title="<?php esc_html_e( 'SCHEMA for Article', 'custom-permalinks' ); ?>" target="_blank">
182
+ <?php esc_html_e( 'Check it out', 'custom-permalinks' ); ?>
183
+ </a>
184
+ </div>
185
+
186
+ <div class="box">
187
+ <div class="img">
188
+ <?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
189
+ <img src="<?php echo $img_src . '/remove-links-and-scripts.svg'; ?>" alt="<?php esc_html_e( 'Remove Links and Scripts', 'custom-permalinks' ); ?>" title="<?php esc_html_e( 'Remove Links and Scripts', 'custom-permalinks' ); ?>" />
190
+ </div>
191
+
192
+ <h3>
193
+ <?php esc_html_e( 'Remove Links and Scripts', 'custom-permalinks' ); ?>
194
+ </h3>
195
+ <p>
196
+ <?php
197
+ esc_html_e(
198
+ 'It removes some meta data from the WordPress header so, your header keeps clean of useless information like shortlink, rsd_link, wlwmanifest_link, emoji_scripts, wp_embed, wp_json, emoji_styles, generator and so on.',
199
+ 'custom-permalinks'
200
+ );
201
+ ?>
202
+ </p>
203
+ <a href="https://wordpress.org/plugins/remove-links-and-scripts/" class="checkout-button" title="<?php esc_html_e( 'Remove Links and Scripts', 'custom-permalinks' ); ?>" target="_blank">
204
+ <?php esc_html_e( 'Check it out', 'custom-permalinks' ); ?>
205
+ </a>
206
+ </div>
207
+
208
+ <div class="box">
209
+ <div class="img">
210
+ <?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
211
+ <img src="<?php echo $img_src . '/media-post-permalink.png'; ?>" style="transform:scale(1.5)" alt="<?php esc_html_e( 'Media Post Permalink', 'custom-permalinks' ); ?>" title="<?php esc_html_e( 'Media Post Permalink', 'custom-permalinks' ); ?>" />
212
+ </div>
213
+
214
+ <h3>
215
+ <?php esc_html_e( 'Media Post Permalink', 'custom-permalinks' ); ?>
216
+ </h3>
217
+ <p>
218
+ <?php
219
+ esc_html_e(
220
+ 'On uploading any image, let\'s say services.png, WordPress creates the attachment post with the permalink of /services/ and doesn\'t allow you to use that permalink to point your page. In this case, we come up with this great solution.',
221
+ 'custom-permalinks'
222
+ );
223
+ ?>
224
+ </p>
225
+ <a href="https://wordpress.org/plugins/media-post-permalink/" class="checkout-button" title="<?php esc_html_e( 'Media Post Permalink', 'custom-permalinks' ); ?>" target="_blank">
226
+ <?php esc_html_e( 'Check it out', 'custom-permalinks' ); ?>
227
+ </a>
228
+ </div>
229
+
230
+ <div class="box">
231
+ <div class="img">
232
+ <?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
233
+ <img src="<?php echo $img_src . '/json-structuring-markup.svg'; ?>" alt="<?php esc_html_e( 'JSON Structuring Markup', 'custom-permalinks' ); ?>" title="<?php esc_html_e( 'JSON Structuring Markup', 'custom-permalinks' ); ?>" />
234
+ </div>
235
+
236
+ <h3>
237
+ <?php esc_html_e( 'JSON Structuring Markup', 'custom-permalinks' ); ?>
238
+ </h3>
239
+ <p>
240
+ <?php
241
+ esc_html_e(
242
+ 'Simply the easiest solution to add valid schema.org as a JSON script in the head of posts and pages. It provides you multiple SCHEMA types like Article, News Article, Organization and Website Schema.',
243
+ 'custom-permalinks'
244
+ );
245
+ ?>
246
+ </p>
247
+ <a href="https://wordpress.org/plugins/json-structuring-markup/" class="checkout-button" title="<?php esc_html_e( 'JSON Structuring Markup', 'custom-permalinks' ); ?>" target="_blank">
248
+ <?php esc_html_e( 'Check it out', 'custom-permalinks' ); ?>
249
+ </a>
250
+ </div>
251
+ </div>
252
+ </div>
253
+ <?php
254
+ }
255
  }
admin/class-custom-permalinks-admin.php CHANGED
@@ -1,175 +1,247 @@
1
  <?php
2
  /**
 
 
3
  * @package CustomPermalinks
4
  */
5
 
6
- class Custom_Permalinks_Admin
7
- {
8
-
9
- /**
10
- * Initializes WordPress hooks.
11
- */
12
- function __construct()
13
- {
14
- add_action( 'admin_menu', array( $this, 'admin_menu' ) );
15
- add_filter( 'plugin_action_links_' . CUSTOM_PERMALINKS_BASENAME,
16
- array( $this, 'settings_link' )
17
- );
18
- add_action( 'admin_init', array( $this, 'privacy_policy' ) );
19
- }
20
-
21
- /**
22
- * Added Pages in Menu for Settings.
23
- *
24
- * @since 1.2.0
25
- * @access public
26
- */
27
- public function admin_menu()
28
- {
29
- add_menu_page( 'Custom Permalinks', 'Custom Permalinks',
30
- 'cp_view_post_permalinks', 'cp-post-permalinks',
31
- array( $this,'post_permalinks_page' ), 'dashicons-admin-links'
32
- );
33
- add_submenu_page( 'cp-post-permalinks', 'PostTypes Permalinks',
34
- 'PostTypes Permalinks', 'cp_view_post_permalinks',
35
- 'cp-post-permalinks', array( $this, 'post_permalinks_page' )
36
- );
37
- add_submenu_page( 'cp-post-permalinks', 'Taxonomies Permalinks',
38
- 'Taxonomies Permalinks', 'cp_view_category_permalinks',
39
- 'cp-category-permalinks', array( $this, 'taxonomy_permalinks_page' )
40
- );
41
- add_submenu_page( 'cp-post-permalinks', 'About Custom Permalinks', 'About',
42
- 'install_plugins', 'cp-about-plugins', array( $this, 'about_plugin' )
43
- );
44
- }
45
-
46
- /**
47
- * Calls another Function which shows the PostTypes Permalinks Page.
48
- *
49
- * @since 1.2.0
50
- * @access public
51
- */
52
- public function post_permalinks_page()
53
- {
54
- require_once CUSTOM_PERMALINKS_PATH . 'admin/class-custom-permalinks-posttypes.php';
55
- new Custom_Permalinks_PostTypes();
56
-
57
- add_filter( 'admin_footer_text', array( $this, 'admin_footer_text' ), 1 );
58
- }
59
-
60
- /**
61
- * Calls another Function which shows the Taxonomies Permalinks Page.
62
- *
63
- * @since 1.2.0
64
- * @access public
65
- */
66
- public function taxonomy_permalinks_page()
67
- {
68
- require_once CUSTOM_PERMALINKS_PATH . 'admin/class-custom-permalinks-taxonomies.php';
69
- new Custom_Permalinks_Taxonomies();
70
-
71
- add_filter( 'admin_footer_text', array( $this, 'admin_footer_text' ), 1 );
72
- }
73
-
74
- /**
75
- * Add About Plugins Page.
76
- *
77
- * @since 1.2.11
78
- * @access public
79
- */
80
- public function about_plugin()
81
- {
82
- require_once CUSTOM_PERMALINKS_PATH . 'admin/class-custom-permalinks-about.php';
83
- new Custom_Permalinks_About();
84
-
85
- add_filter( 'admin_footer_text', array( $this, 'admin_footer_text' ), 1 );
86
- }
87
-
88
- /**
89
- * Add Plugin Support and Follow Message in the footer of Admin Pages.
90
- *
91
- * @since 1.2.11
92
- * @access public
93
- *
94
- * @return string Shows version, website link and twitter.
95
- */
96
- public function admin_footer_text()
97
- {
98
- $footer_text = sprintf(
99
- __( 'Custom Permalinks version %s by <a href="%s" title="Sami Ahmed Siddiqui Company Website" target="_blank">Sami Ahmed Siddiqui</a> - <a href="%s" title="Support forums" target="_blank">Support forums</a> - Follow on Twitter: <a href="%s" title="Follow Sami Ahmed Siddiqui on Twitter" target="_blank">Sami Ahmed Siddiqui</a>',
100
- 'custom-permalinks'
101
- ),
102
- CUSTOM_PERMALINKS_PLUGIN_VERSION, 'https://www.yasglobal.com/',
103
- 'https://wordpress.org/support/plugin/custom-permalinks',
104
- 'https://twitter.com/samisiddiqui91'
105
- );
106
-
107
- return $footer_text;
108
- }
109
-
110
- /**
111
- * Add About and Premium Settings Page Link on the Plugin Page under the
112
- * Plugin Name.
113
- *
114
- * @since 1.2.11
115
- * @access public
116
- *
117
- * @param array $links Contains the Plugin Basic Link (Activate/Deactivate/Delete).
118
- *
119
- * @return array Plugin Basic Links and added some custome link for Settings,
120
- * Contact, and About.
121
- */
122
- public function settings_link( $links )
123
- {
124
- $about = sprintf( __(
125
- '<a href="%s" title="About">About</a>', 'custom-permalinks'
126
- ),
127
- 'admin.php?page=cp-about-plugins'
128
- );
129
- $premium_support = sprintf( __(
130
- '<a href="%s" title="Premium Support" target="_blank">Premium Support</a>',
131
- 'custom-permalinks'
132
- ),
133
- 'https://www.custompermalinks.com/#pricing-section'
134
- );
135
- $contact = sprintf( __(
136
- '<a href="%s" title="Contact" target="_blank">Contact</a>',
137
- 'custom-permalinks'
138
- ),
139
- 'https://www.custompermalinks.com/contact-us/'
140
- );
141
- array_unshift( $links, $contact );
142
- array_unshift( $links, $premium_support );
143
- array_unshift( $links, $about );
144
-
145
- return $links;
146
- }
147
-
148
- /**
149
- * Add Privacy Policy about the Plugin.
150
- *
151
- * @since 1.2.23
152
- * @access public
153
- */
154
- public function privacy_policy()
155
- {
156
- if ( ! function_exists( 'wp_add_privacy_policy_content' ) ) {
157
- return;
158
- }
159
-
160
- $content = sprintf(
161
- __(
162
- 'This plugin collect information about the site like URL, WordPress version etc.' .
163
- ' This plugin doesn\'t collect any user related information.' .
164
- ' To have any kind of further query please feel free to' .
165
- ' <a href="%s" target="_blank">contact us</a>.',
166
- 'custom-permalinks'
167
- ),
168
- 'https://www.custompermalinks.com/contact-us/'
169
- );
170
-
171
- wp_add_privacy_policy_content( 'Custom Permalinks',
172
- wp_kses_post( wpautop( $content, false ) )
173
- );
174
- }
175
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
2
  /**
3
+ * Custom Permalinks Admin.
4
+ *
5
  * @package CustomPermalinks
6
  */
7
 
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  }
11
+
12
+ /**
13
+ * Create admin menu, add privacy policy etc.
14
+ */
15
+ class Custom_Permalinks_Admin {
16
+ /**
17
+ * Css file suffix extension.
18
+ *
19
+ * @var string
20
+ */
21
+ private $css_file_suffix = '.min.css';
22
+
23
+ /**
24
+ * Initializes WordPress hooks.
25
+ */
26
+ public function __construct() {
27
+ /*
28
+ * Css file suffix (version number with extension).
29
+ */
30
+ $this->css_file_suffix = '-' . CUSTOM_PERMALINKS_VERSION . '.min.css';
31
+
32
+ add_action( 'admin_init', array( $this, 'privacy_policy' ) );
33
+ add_action( 'admin_menu', array( $this, 'admin_menu' ) );
34
+
35
+ add_filter(
36
+ 'plugin_action_links_' . CUSTOM_PERMALINKS_BASENAME,
37
+ array( $this, 'settings_link' )
38
+ );
39
+ }
40
+
41
+ /**
42
+ * Added Pages in Menu for Settings.
43
+ *
44
+ * @since 1.2.0
45
+ * @access public
46
+ *
47
+ * @return void
48
+ */
49
+ public function admin_menu() {
50
+ add_menu_page(
51
+ 'Custom Permalinks',
52
+ 'Custom Permalinks',
53
+ 'cp_view_post_permalinks',
54
+ 'cp-post-permalinks',
55
+ array( $this, 'post_permalinks_page' ),
56
+ 'dashicons-admin-links'
57
+ );
58
+ $post_permalinks_hook = add_submenu_page(
59
+ 'cp-post-permalinks',
60
+ 'Post Types Permalinks',
61
+ 'Post Types Permalinks',
62
+ 'cp_view_post_permalinks',
63
+ 'cp-post-permalinks',
64
+ array( $this, 'post_permalinks_page' )
65
+ );
66
+ $taxonomy_permalinks_hook = add_submenu_page(
67
+ 'cp-post-permalinks',
68
+ 'Taxonomies Permalinks',
69
+ 'Taxonomies Permalinks',
70
+ 'cp_view_category_permalinks',
71
+ 'cp-taxonomy-permalinks',
72
+ array( $this, 'taxonomy_permalinks_page' )
73
+ );
74
+ $about_page = add_submenu_page(
75
+ 'cp-post-permalinks',
76
+ 'About Custom Permalinks',
77
+ 'About',
78
+ 'install_plugins',
79
+ 'cp-about-plugins',
80
+ array( $this, 'about_plugin' )
81
+ );
82
+
83
+ add_action(
84
+ 'load-' . $post_permalinks_hook,
85
+ 'Custom_Permalinks_Post_Types_Table::instance'
86
+ );
87
+ add_action(
88
+ 'load-' . $taxonomy_permalinks_hook,
89
+ 'Custom_Permalinks_Taxonomies_Table::instance'
90
+ );
91
+ add_action(
92
+ 'admin_print_styles-' . $about_page . '',
93
+ array( $this, 'add_about_style' )
94
+ );
95
+ }
96
+
97
+ /**
98
+ * Add about page style.
99
+ *
100
+ * @since 2.0.0
101
+ * @access public
102
+ *
103
+ * @return void
104
+ */
105
+ public function add_about_style() {
106
+ wp_enqueue_style(
107
+ 'custom-permalinks-about-style',
108
+ plugins_url(
109
+ '/assets/css/about-plugins' . $this->css_file_suffix,
110
+ CUSTOM_PERMALINKS_FILE
111
+ ),
112
+ array(),
113
+ CUSTOM_PERMALINKS_VERSION
114
+ );
115
+ }
116
+
117
+ /**
118
+ * Calls another Function which shows the Post Types Permalinks Page.
119
+ *
120
+ * @since 1.2.0
121
+ * @access public
122
+ *
123
+ * @return void
124
+ */
125
+ public function post_permalinks_page() {
126
+ Custom_Permalinks_Post_Types_Table::output();
127
+
128
+ add_filter( 'admin_footer_text', array( $this, 'admin_footer_text' ), 1 );
129
+ }
130
+
131
+ /**
132
+ * Calls another Function which shows the Taxonomies Permalinks Page.
133
+ *
134
+ * @since 1.2.0
135
+ * @access public
136
+ *
137
+ * @return void
138
+ */
139
+ public function taxonomy_permalinks_page() {
140
+ Custom_Permalinks_Taxonomies_Table::output();
141
+
142
+ add_filter( 'admin_footer_text', array( $this, 'admin_footer_text' ), 1 );
143
+ }
144
+
145
+ /**
146
+ * Add About Plugins Page.
147
+ *
148
+ * @since 1.2.11
149
+ * @access public
150
+ *
151
+ * @return void
152
+ */
153
+ public function about_plugin() {
154
+ include_once CUSTOM_PERMALINKS_PATH . 'admin/class-custom-permalinks-about.php';
155
+ new Custom_Permalinks_About();
156
+
157
+ add_filter( 'admin_footer_text', array( $this, 'admin_footer_text' ), 1 );
158
+ }
159
+
160
+ /**
161
+ * Add Plugin Support and Follow Message in the footer of Admin Pages.
162
+ *
163
+ * @since 1.2.11
164
+ * @access public
165
+ *
166
+ * @return string Shows version, website link and twitter.
167
+ */
168
+ public function admin_footer_text() {
169
+ $cp_footer_text = __( 'Custom Permalinks version', 'custom-permalinks' ) .
170
+ ' ' . CUSTOM_PERMALINKS_VERSION . ' ' .
171
+ __( 'by', 'custom-permalinks' ) .
172
+ ' <a href="https://www.yasglobal.com/" target="_blank">' .
173
+ __( 'Sami Ahmed Siddiqui', 'custom-permalinks' ) .
174
+ '</a>' .
175
+ ' - ' .
176
+ '<a href="https://wordpress.org/support/plugin/custom-permalinks" target="_blank">' .
177
+ __( 'Support forums', 'custom-permalinks' ) .
178
+ '</a>' .
179
+ ' - ' .
180
+ 'Follow on Twitter:' .
181
+ ' <a href="https://twitter.com/samisiddiqui91" target="_blank">' .
182
+ __( 'Sami Ahmed Siddiqui', 'custom-permalinks' ) .
183
+ '</a>';
184
+
185
+ return $cp_footer_text;
186
+ }
187
+
188
+ /**
189
+ * Add About and Premium Settings Page Link on the Plugin Page under the
190
+ * Plugin Name.
191
+ *
192
+ * @since 1.2.11
193
+ * @access public
194
+ *
195
+ * @param array $links Contains the Plugin Basic Link (Activate/Deactivate/Delete).
196
+ *
197
+ * @return array Plugin Basic Links and added some custome link for Settings,
198
+ * Contact, and About.
199
+ */
200
+ public function settings_link( $links ) {
201
+ $about_link = '<a href="admin.php?page=cp-about-plugins" target="_blank">' .
202
+ __( 'About', 'custom-permalinks' ) .
203
+ '</a>';
204
+ $support_link = '<a href="https://www.custompermalinks.com/#pricing-section" target="_blank">' .
205
+ __( 'Premium Support', 'custom-permalinks' ) .
206
+ '</a>';
207
+ $contact_link = '<a href="https://www.custompermalinks.com/contact-us/" target="_blank">' .
208
+ __( 'Contact', 'custom-permalinks' ) .
209
+ '</a>';
210
+
211
+ array_unshift( $links, $contact_link );
212
+ array_unshift( $links, $support_link );
213
+ array_unshift( $links, $about_link );
214
+
215
+ return $links;
216
+ }
217
+
218
+ /**
219
+ * Add Privacy Policy about the Plugin.
220
+ *
221
+ * @since 1.2.23
222
+ * @access public
223
+ *
224
+ * @return void
225
+ */
226
+ public function privacy_policy() {
227
+ if ( ! function_exists( 'wp_add_privacy_policy_content' ) ) {
228
+ return;
229
+ }
230
+
231
+ $cp_privacy = esc_html__(
232
+ 'This plugin collect information about the site like URL, WordPress version etc. This plugin doesn\'t collect any user related information. To have any kind of further query please feel free to',
233
+ 'custom-permalinks'
234
+ );
235
+ $cp_privacy = $cp_privacy .
236
+ ' <a href="https://www.custompermalinks.com/contact-us/" target="_blank">' .
237
+ esc_html__( 'contact us', 'custom-permalinks' ) .
238
+ '</a>';
239
+
240
+ wp_add_privacy_policy_content(
241
+ 'Custom Permalinks',
242
+ wp_kses_post( wpautop( $cp_privacy, false ) )
243
+ );
244
+ }
245
+ }
246
+
247
+ new Custom_Permalinks_Admin();
admin/class-custom-permalinks-pager.php DELETED
@@ -1,109 +0,0 @@
1
- <?php
2
- /**
3
- * @package CustomPermalinks
4
- */
5
-
6
- class Custom_Permalinks_Pager
7
- {
8
-
9
- /**
10
- * Return the Pager HTML.
11
- *
12
- * @since 1.2.0
13
- * @access public
14
- *
15
- * @param int $total_permalinks No. of total results found.
16
- * @param int $current_pager_value Optional. Current Page. 1.
17
- * @param int $total_pager Optional. Total no. of pages. 0.
18
- *
19
- * @return string Pagination HTML if pager exist.
20
- */
21
- public function get_pagination( $total_permalinks, $current_pager_value = 1,
22
- $total_pager = 0
23
- ) {
24
- if ( 0 == $total_pager ) {
25
- return;
26
- }
27
-
28
- if ( 1 == $total_pager ) {
29
- $pagination_html = '<div class="tablenav-pages one-page">' .
30
- '<span class="displaying-num">' .
31
- $total_permalinks .
32
- __( 'items', 'custom-permalinks' ) .
33
- '</span>' .
34
- '</div>';
35
-
36
- return $pagination_html;
37
- }
38
-
39
- $remove_pager_uri = array();
40
- if ( isset( $_SERVER['REQUEST_URI'] ) ) {
41
- $remove_pager_uri = explode(
42
- '&paged=' . $current_pager_value . '', $_SERVER['REQUEST_URI']
43
- );
44
- }
45
- $pagination_html = '<div class="tablenav-pages">' .
46
- '<span class="displaying-num">' .
47
- $total_permalinks .
48
- __( 'items', 'custom-permalinks' ) .
49
- '</span>' .
50
- '<span class="pagination-links">';
51
-
52
- if ( 1 == $current_pager_value ) {
53
- $pagination_html .= '<span class="tablenav-pages-navspan" aria-hidden="true">&laquo; </span>' .
54
- '<span class="tablenav-pages-navspan" aria-hidden="true">&lsaquo; </span>';
55
- } else {
56
- $prev_page = $current_pager_value - 1;
57
- if ( 1 == $prev_page ) {
58
- $pagination_html .= '<span class="tablenav-pages-navspan" aria-hidden="true">&laquo;</span>';
59
- } else {
60
- $pagination_html .= ' <a href="' . $remove_pager_uri[0] . '&paged=1" title="' . __( "First page", "custom-permalinks" ) .'" class="first-page">' .
61
- '<span class="screen-reader-text">' .
62
- __( 'First page', 'custom-permalinks' ) .
63
- '</span>' .
64
- '<span aria-hidden="true">&laquo;</span>' .
65
- '</a> ';
66
- }
67
- $pagination_html .= ' <a href="' . $remove_pager_uri[0] . '&paged=' . $prev_page . '" title="' . __( "Previous page", "custom-permalinks" ) . '" class="prev-page">' .
68
- '<span class="screen-reader-text">' .
69
- __( 'Previous page', 'custom-permalinks' ) .
70
- '</span>' .
71
- '<span aria-hidden="true">&lsaquo;</span>' .
72
- '</a> ';
73
- }
74
-
75
- $pagination_html .= '<span class="paging-input">' .
76
- '<label for="current-page-selector" class="screen-reader-text">' .
77
- __( 'Current Page', 'custom-permalinks' ) .
78
- '</label>' .
79
- '<input class="current-page" id="current-page-selector" type="text" name="paged" value="' . $current_pager_value . '" size="1" aria-describedby="table-paging" />' .
80
- '<span class="tablenav-paging-text"> of <span class="total-pages">' . $total_pager . ' </span> </span>' .
81
- '</span>';
82
-
83
- if ( $current_pager_value == $total_pager ) {
84
- $pagination_html .= '<span class="tablenav-pages-navspan" aria-hidden="true">&rsaquo; </span>' .
85
- '<span class="tablenav-pages-navspan" aria-hidden="true">&raquo; </span>';
86
- } else {
87
- $next_page = $current_pager_value + 1;
88
- $pagination_html .= ' <a href="' . $remove_pager_uri[0] . '&paged=' . $next_page . '" title="' . __( "Next page", "custom-permalinks" ) . '" class="next-page">' .
89
- '<span class="screen-reader-text">' .
90
- __( 'Next page', 'custom-permalinks' ) .
91
- '</span>' .
92
- '<span aria-hidden="true">&rsaquo;</span>' .
93
- '</a> ';
94
- if ( $total_pager == $next_page ) {
95
- $pagination_html .= '<span class="tablenav-pages-navspan" aria-hidden="true">&raquo;</span>';
96
- } else {
97
- $pagination_html .= ' <a href="' . $remove_pager_uri[0] . '&paged=' . $total_pager . '" title="' . __( "Last page", "custom-permalinks" ) . '" class="last-page">' .
98
- '<span class="screen-reader-text">' .
99
- __( 'Last page', 'custom-permalinks' ) .
100
- '</span>' .
101
- '<span aria-hidden="true">&raquo;</span>' .
102
- '</a> ';
103
- }
104
- }
105
- $pagination_html .= '</span></div>';
106
-
107
- return $pagination_html;
108
- }
109
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/class-custom-permalinks-post-types-table.php ADDED
@@ -0,0 +1,511 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Custom Permalinks Post Types.
4
+ *
5
+ * @package CustomPermalinks
6
+ */
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
10
+ }
11
+
12
+ if ( ! class_exists( 'WP_List_Table' ) ) {
13
+ include_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
14
+ }
15
+
16
+ /**
17
+ * Post Types Permalinks table class.
18
+ */
19
+ final class Custom_Permalinks_Post_Types_Table extends WP_List_Table {
20
+ /**
21
+ * Singleton instance variable
22
+ *
23
+ * @var object
24
+ */
25
+ private static $instance;
26
+
27
+ /**
28
+ * Initialize the Post Types Permalinks table list.
29
+ *
30
+ * @since 2.0.0
31
+ * @access public
32
+ */
33
+ public function __construct() {
34
+ parent::__construct(
35
+ array(
36
+ 'singular' => __( 'Permalink', 'custom-permalinks' ),
37
+ 'plural' => __( 'Permalinks', 'custom-permalinks' ),
38
+ 'ajax' => false,
39
+ )
40
+ );
41
+
42
+ // Handle screen options.
43
+ $this->screen_options();
44
+ }
45
+
46
+ /**
47
+ * Singleton instance method.
48
+ *
49
+ * @since 2.0.0
50
+ * @access public
51
+ *
52
+ * @return Custom_Permalinks_Post_Types_Table The instance.
53
+ */
54
+ public static function instance() {
55
+ if ( ! isset( self::$instance ) ) {
56
+ self::$instance = new self();
57
+ }
58
+
59
+ return self::$instance;
60
+ }
61
+
62
+ /**
63
+ * Handle displaying and saving screen options.
64
+ *
65
+ * @since 2.0.0
66
+ * @access private
67
+ *
68
+ * @return void
69
+ */
70
+ private function screen_options() {
71
+ $per_page_option = "{$this->screen->id}_per_page";
72
+
73
+ // phpcs:disable WordPress.Security.NonceVerification.Missing
74
+ // Save screen options if the form has been submitted.
75
+ if ( isset( $_POST['screen-options-apply'] ) ) {
76
+ // Save posts per page option.
77
+ if ( isset( $_POST['wp_screen_options']['value'] ) ) {
78
+ update_user_option(
79
+ get_current_user_id(),
80
+ $per_page_option,
81
+ sanitize_text_field( $_POST['wp_screen_options']['value'] )
82
+ );
83
+ }
84
+ }
85
+ // phpcs:enable WordPress.Security.NonceVerification.Missing
86
+
87
+ // Add per page option to the screen options.
88
+ $this->screen->add_option(
89
+ 'per_page',
90
+ array(
91
+ 'option' => $per_page_option,
92
+ )
93
+ );
94
+ }
95
+
96
+ /**
97
+ * No items found text.
98
+ *
99
+ * @since 2.0.0
100
+ * @access public
101
+ *
102
+ * @return void
103
+ */
104
+ public function no_items() {
105
+ esc_html_e( 'No permalinks found.', 'custom-permalinks' );
106
+ }
107
+
108
+ /**
109
+ * Get list of columns in the form of array.
110
+ *
111
+ * @since 2.0.0
112
+ * @access public
113
+ *
114
+ * @return array Column list.
115
+ */
116
+ public function get_columns() {
117
+ $columns = array(
118
+ 'cb' => '<input type="checkbox" />',
119
+ 'title' => esc_html__( 'Title', 'custom-permalinks' ),
120
+ 'type' => esc_html__( 'Type', 'custom-permalinks' ),
121
+ 'permalink' => esc_html__( 'Permalink', 'custom-permalinks' ),
122
+ );
123
+
124
+ return $columns;
125
+ }
126
+
127
+ /**
128
+ * Returns the output of the page.
129
+ *
130
+ * @since 2.0.0
131
+ * @access public
132
+ */
133
+ public static function output() {
134
+ $user_id = get_current_user_id();
135
+ $permalink_deleted = filter_input( INPUT_GET, 'deleted' );
136
+ $search_permalink = filter_input( INPUT_GET, 's' );
137
+ $post_types_table = self::instance();
138
+ $post_types_table->prepare_items();
139
+ ?>
140
+
141
+ <div class="wrap">
142
+ <h1 class="wp-heading-inline">
143
+ <?php esc_html_e( 'Post Types Permalinks', 'custom-permalinks' ); ?>
144
+ </h1>
145
+
146
+ <?php if ( isset( $search_permalink ) && ! empty( $search_permalink ) ) : ?>
147
+ <span class="subtitle">
148
+ <?php
149
+ esc_html_e( 'Search results for: ', 'custom-permalinks' );
150
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
151
+ printf( '<strong>%s</strong>', $search_permalink );
152
+ ?>
153
+ </span>
154
+ <?php endif; ?>
155
+
156
+ <hr class="wp-header-end">
157
+
158
+ <?php if ( isset( $permalink_deleted ) && 0 < $permalink_deleted ) : ?>
159
+ <div id="message" class="updated notice is-dismissible">
160
+ <p>
161
+ <?php
162
+ printf(
163
+ // translators: Placeholder would bee replaced with the number.
164
+ _n( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
165
+ '%s permalink deleted.',
166
+ '%s permalinks deleted.',
167
+ $permalink_deleted,
168
+ 'custom-permalinks'
169
+ ),
170
+ esc_html( $permalink_deleted )
171
+ );
172
+ ?>
173
+ </p>
174
+ </div>
175
+ <?php endif; ?>
176
+ <form id="posts-filter" method="GET">
177
+ <input type="hidden" name="page" value="cp-post-permalinks" />
178
+ <?php
179
+ wp_nonce_field(
180
+ 'custom-permalinks-post_' . $user_id,
181
+ '_custom_permalinks_post_nonce'
182
+ );
183
+ $post_types_table->search_box(
184
+ esc_html__(
185
+ 'Search Permalinks',
186
+ 'custom-permalinks'
187
+ ),
188
+ 'search-submit'
189
+ );
190
+ $post_types_table->display();
191
+ ?>
192
+ </form>
193
+ </div>
194
+
195
+ <?php
196
+ }
197
+
198
+ /**
199
+ * Set up column headings for WP_List_Table.
200
+ *
201
+ * @since 2.0.0
202
+ * @access protected
203
+ *
204
+ * @return array
205
+ */
206
+ protected function get_hidden_columns() {
207
+ $columns = get_user_option( "manage{$this->screen->id}columnshidden" );
208
+
209
+ return apply_filters( 'custom_permalinks_post_types_table_hidden_columns', (array) $columns );
210
+ }
211
+
212
+ /**
213
+ * Render the checkbox for bulk action.
214
+ *
215
+ * @since 2.0.0
216
+ * @access protected
217
+ *
218
+ * @param array $item Single Item.
219
+ *
220
+ * @return string
221
+ */
222
+ protected function column_cb( $item ) {
223
+ return sprintf(
224
+ '<input type="checkbox" name="permalink[]" value="%s" />',
225
+ $item['ID']
226
+ );
227
+ }
228
+
229
+ /**
230
+ * Set up column contents for `Title`.
231
+ *
232
+ * @since 2.0.0
233
+ * @access public
234
+ *
235
+ * @param array $item Single Item.
236
+ *
237
+ * @return string Post Title.
238
+ */
239
+ protected function column_title( $item ) {
240
+ $post_title = 'NOT SET';
241
+
242
+ if ( $item['post_title'] ) {
243
+ $post_title = $item['post_title'];
244
+ }
245
+
246
+ $edit_link = get_edit_post_link( $item['ID'] );
247
+ $title_with_edit_link = $post_title;
248
+ if ( ! empty( $edit_link ) ) {
249
+ $title_with_edit_link = sprintf(
250
+ '<a href="%s" target="_blank" title="' . esc_html__( 'Edit ', 'custom-permalinks' ) . ' ' . $post_title . '">%s</a>',
251
+ $edit_link,
252
+ $post_title
253
+ );
254
+ }
255
+
256
+ return $title_with_edit_link;
257
+ }
258
+
259
+ /**
260
+ * Set up column contents for `Type`.
261
+ *
262
+ * @since 2.0.0
263
+ * @access protected
264
+ *
265
+ * @param array $item Single Item.
266
+ *
267
+ * @return string Post Type.
268
+ */
269
+ protected function column_type( $item ) {
270
+ $post_type_name = 'post';
271
+
272
+ if ( isset( $item['post_type'] ) ) {
273
+ $post_type_name = ucwords( $item['post_type'] );
274
+ }
275
+
276
+ return $post_type_name;
277
+ }
278
+
279
+ /**
280
+ * Set up column contents for `Permalink`.
281
+ *
282
+ * @since 2.0.0
283
+ * @access protected
284
+ *
285
+ * @param array $item Single Item.
286
+ *
287
+ * @return string Post Permalink.
288
+ */
289
+ protected function column_permalink( $item ) {
290
+ $permalink = '';
291
+
292
+ if ( $item['meta_value'] ) {
293
+ $cp_frontend = new Custom_Permalinks_Frontend();
294
+ $custom_permalink = '/' . $item['meta_value'];
295
+ $home_url = home_url();
296
+ $post_type = 'post';
297
+
298
+ if ( class_exists( 'SitePress' ) ) {
299
+ $wpml_lang_format = apply_filters(
300
+ 'wpml_setting',
301
+ 0,
302
+ 'language_negotiation_type'
303
+ );
304
+
305
+ if ( 1 === intval( $wpml_lang_format ) ) {
306
+ $home_url = $site_url;
307
+ }
308
+ }
309
+
310
+ if ( isset( $item['post_type'] ) ) {
311
+ $post_type = $item['post_type'];
312
+ }
313
+
314
+ $language_code = apply_filters(
315
+ 'wpml_element_language_code',
316
+ null,
317
+ array(
318
+ 'element_id' => $item['ID'],
319
+ 'element_type' => $post_type,
320
+ )
321
+ );
322
+
323
+ $permalink = $cp_frontend->wpml_permalink_filter(
324
+ $custom_permalink,
325
+ $language_code
326
+ );
327
+ $permalink = $cp_frontend->remove_double_slash( $permalink );
328
+ $perm_text = str_replace( $home_url, '', $permalink );
329
+
330
+ $permalink = sprintf(
331
+ '<a href="%s" target="_blank" title="' . esc_html__( 'Visit', 'custom-permalinks' ) . ' ' . $item['post_title'] . '">%s</a>',
332
+ $permalink,
333
+ $perm_text
334
+ );
335
+ }
336
+
337
+ return $permalink;
338
+ }
339
+
340
+ /**
341
+ * Get bulk actions.
342
+ *
343
+ * @since 2.0.0
344
+ * @access public
345
+ *
346
+ * @return array Available Actions.
347
+ */
348
+ public function get_bulk_actions() {
349
+ return array(
350
+ 'delete' => esc_html__( 'Delete Permalinks', 'custom-permalinks' ),
351
+ );
352
+ }
353
+
354
+ /**
355
+ * Process bulk actions.
356
+ *
357
+ * @since 2.0.0
358
+ * @access public
359
+ *
360
+ * @return void
361
+ */
362
+ public function process_bulk_action() {
363
+ if ( isset( $_REQUEST['_custom_permalinks_post_nonce'] ) ) {
364
+ $deleted = 0;
365
+ $user_id = get_current_user_id();
366
+
367
+ // Detect when a bulk action is being triggered.
368
+ if ( 'delete' === $this->current_action()
369
+ && wp_verify_nonce(
370
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
371
+ $_REQUEST['_custom_permalinks_post_nonce'],
372
+ 'custom-permalinks-post_' . $user_id
373
+ )
374
+ ) {
375
+ if ( isset( $_REQUEST['permalink'] ) ) {
376
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
377
+ $del_permalinks = $_REQUEST['permalink'];
378
+ }
379
+
380
+ if ( isset( $del_permalinks )
381
+ && ! empty( $del_permalinks )
382
+ && is_array( $del_permalinks )
383
+ && 0 < count( $del_permalinks )
384
+ ) {
385
+ $cp_form = new Custom_Permalinks_Form();
386
+ foreach ( $del_permalinks as $post_id ) {
387
+ if ( is_numeric( $post_id ) ) {
388
+ $cp_form->delete_permalink( $post_id );
389
+ ++$deleted;
390
+ }
391
+ }
392
+ }
393
+ }
394
+
395
+ $cp_order = filter_input( INPUT_GET, 'order' );
396
+ $cp_orderby = filter_input( INPUT_GET, 'orderby' );
397
+ $cp_page = filter_input( INPUT_GET, 'page' );
398
+ $cp_paged = filter_input( INPUT_GET, 'paged' );
399
+ $perm_search = filter_input( INPUT_GET, 's' );
400
+ $page_args = array();
401
+
402
+ if ( ! empty( $cp_page ) ) {
403
+ $page_args['page'] = $cp_page;
404
+ } else {
405
+ $page_args['page'] = 'cp-post-permalinks';
406
+ }
407
+
408
+ if ( ! empty( $perm_search ) ) {
409
+ $page_args['s'] = $perm_search;
410
+ }
411
+
412
+ if ( ! empty( $cp_orderby ) ) {
413
+ $page_args['orderby'] = $cp_orderby;
414
+ }
415
+
416
+ if ( ! empty( $cp_order ) ) {
417
+ $page_args['order'] = $cp_order;
418
+ }
419
+
420
+ if ( ! empty( $cp_paged ) && is_numeric( $cp_paged ) ) {
421
+ $page_args['paged'] = $cp_paged;
422
+ }
423
+
424
+ if ( 0 < $deleted ) {
425
+ $page_args['deleted'] = $deleted;
426
+ }
427
+
428
+ wp_safe_redirect( add_query_arg( $page_args, admin_url( 'admin.php' ) ) );
429
+ exit;
430
+ }
431
+ }
432
+
433
+ /**
434
+ * Generate the table navigation above or below the table.
435
+ *
436
+ * @since 2.0.0
437
+ * @access protected
438
+ *
439
+ * @param string $which Table Navigation position.
440
+ *
441
+ * @return void
442
+ */
443
+ protected function display_tablenav( $which ) {
444
+ ?>
445
+ <div class="tablenav <?php echo esc_attr( $which ); ?>">
446
+ <?php if ( $this->has_items() ) : ?>
447
+ <div class="alignleft actions bulkactions">
448
+ <?php $this->bulk_actions( $which ); ?>
449
+ </div>
450
+ <?php
451
+ endif;
452
+
453
+ $this->extra_tablenav( $which );
454
+ $this->pagination( $which );
455
+ ?>
456
+
457
+ <br class="clear" />
458
+ </div>
459
+ <?php
460
+ }
461
+
462
+ /**
463
+ * Prepare table list items.
464
+ *
465
+ * @since 2.0.0
466
+ * @access public
467
+ *
468
+ * @return void
469
+ */
470
+ public function prepare_items() {
471
+ $columns = $this->get_columns();
472
+ $hidden = $this->get_hidden_columns();
473
+ $sortable = $this->get_sortable_columns();
474
+
475
+ $this->_column_headers = array( $columns, $hidden, $sortable );
476
+
477
+ // Process bulk action.
478
+ $this->process_bulk_action();
479
+
480
+ $per_page = $this->get_items_per_page( "{$this->screen->id}_per_page" );
481
+ $current_page = $this->get_pagenum();
482
+ $total_items = Custom_Permalinks_Post_Types::total_permalinks();
483
+ $this->items = Custom_Permalinks_Post_Types::get_permalinks( $per_page, $current_page );
484
+
485
+ $this->set_pagination_args(
486
+ array(
487
+ 'total_items' => $total_items,
488
+ 'per_page' => $per_page,
489
+ 'total_pages' => ceil( $total_items / $per_page ),
490
+ )
491
+ );
492
+ }
493
+
494
+ /**
495
+ * Columns to make sortable.
496
+ *
497
+ * @since 2.0.0
498
+ * @access public
499
+ *
500
+ * @return array Sortable columns list.
501
+ */
502
+ public function get_sortable_columns() {
503
+ $sortable_columns = array(
504
+ 'title' => array( 'title', false ),
505
+ 'type' => array( 'type', false ),
506
+ 'permalink' => array( 'permalink', false ),
507
+ );
508
+
509
+ return $sortable_columns;
510
+ }
511
+ }
admin/class-custom-permalinks-post-types.php ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Custom Permalinks Post Types.
4
+ *
5
+ * @package CustomPermalinks
6
+ */
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
10
+ }
11
+
12
+ /**
13
+ * Post Types Permalinks table class.
14
+ */
15
+ final class Custom_Permalinks_Post_Types {
16
+ /**
17
+ * Returns the count of records in the database.
18
+ *
19
+ * @since 2.0.0
20
+ * @access public
21
+ *
22
+ * @return null|int
23
+ */
24
+ public static function total_permalinks() {
25
+ global $wpdb;
26
+
27
+ $total_posts = wp_cache_get( 'total_posts_result', 'custom_permalinks' );
28
+ if ( ! $total_posts ) {
29
+ $sql_query = "
30
+ SELECT COUNT(p.ID) FROM $wpdb->posts AS p
31
+ LEFT JOIN $wpdb->postmeta AS pm ON (p.ID = pm.post_id)
32
+ WHERE pm.meta_key = 'custom_permalink' AND pm.meta_value != ''
33
+ ";
34
+
35
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended
36
+ // Include search in total results.
37
+ if ( isset( $_REQUEST['s'] ) && ! empty( $_REQUEST['s'] ) ) {
38
+ $search_value = ltrim( sanitize_text_field( $_REQUEST['s'] ), '/' );
39
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
40
+ $total_posts = $wpdb->get_var(
41
+ $wpdb->prepare(
42
+ "SELECT COUNT(p.ID) FROM {$wpdb->posts} AS p
43
+ LEFT JOIN {$wpdb->postmeta} AS pm ON (p.ID = pm.post_id)
44
+ WHERE pm.meta_key = 'custom_permalink'
45
+ AND pm.meta_value != ''
46
+ AND pm.meta_value LIKE %s",
47
+ '%' . $wpdb->esc_like( $search_value ) . '%'
48
+ )
49
+ );
50
+ // phpcs:enable WordPress.Security.NonceVerification.Recommended
51
+ } else {
52
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
53
+ $total_posts = $wpdb->get_var(
54
+ "SELECT COUNT(p.ID) FROM {$wpdb->posts} AS p
55
+ LEFT JOIN {$wpdb->postmeta} AS pm ON (p.ID = pm.post_id)
56
+ WHERE pm.meta_key = 'custom_permalink' AND pm.meta_value != ''"
57
+ );
58
+ }
59
+
60
+ wp_cache_set( 'total_posts_result', $total_posts, 'custom_permalinks' );
61
+ }
62
+
63
+ return $total_posts;
64
+ }
65
+
66
+ /**
67
+ * Retrieve permalink's data from the database.
68
+ *
69
+ * @since 2.0.0
70
+ * @access public
71
+ *
72
+ * @param int $per_page Maximum Results needs to be shown on the page.
73
+ * @param int $page_number Current page.
74
+ *
75
+ * @return array Title, Post Type and Permalink set using this plugin.
76
+ */
77
+ public static function get_permalinks( $per_page = 20, $page_number = 1 ) {
78
+ global $wpdb;
79
+
80
+ $posts = wp_cache_get( 'post_type_results', 'custom_permalinks' );
81
+ if ( ! $posts ) {
82
+ $page_offset = ( $page_number - 1 ) * $per_page;
83
+ $order_by = 'p.ID';
84
+ $order = null;
85
+
86
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended
87
+ // Sort the items.
88
+ switch ( isset( $_REQUEST['orderby'] ) ? strtolower( sanitize_text_field( $_REQUEST['orderby'] ) ) : '' ) {
89
+ case 'title':
90
+ $order_by = 'p.post_title';
91
+ break;
92
+
93
+ case 'type':
94
+ $order_by = 'p.post_type';
95
+ break;
96
+
97
+ case 'permalink':
98
+ $order_by = 'pm.meta_value';
99
+ break;
100
+ }
101
+
102
+ switch ( isset( $_REQUEST['order'] ) ? strtolower( sanitize_text_field( $_REQUEST['order'] ) ) : '' ) {
103
+ case 'asc':
104
+ $order = 'ASC';
105
+ break;
106
+
107
+ case 'desc':
108
+ default:
109
+ $order = 'DESC';
110
+ break;
111
+ }
112
+
113
+ // Include search in total results.
114
+ if ( isset( $_REQUEST['s'] ) && ! empty( $_REQUEST['s'] ) ) {
115
+ $search_value = ltrim( sanitize_text_field( $_REQUEST['s'] ), '/' );
116
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
117
+ $posts = $wpdb->get_results(
118
+ $wpdb->prepare(
119
+ "SELECT p.ID, p.post_title, p.post_type, pm.meta_value
120
+ FROM {$wpdb->posts} AS p
121
+ LEFT JOIN {$wpdb->postmeta} AS pm ON (p.ID = pm.post_id)
122
+ WHERE pm.meta_key = 'custom_permalink'
123
+ AND pm.meta_value != ''
124
+ AND pm.meta_value LIKE %s
125
+ ORDER BY %s %s LIMIT %d, %d",
126
+ '%' . $wpdb->esc_like( $search_value ) . '%',
127
+ $order_by,
128
+ $order,
129
+ $page_offset,
130
+ $per_page
131
+ ),
132
+ ARRAY_A
133
+ );
134
+ } else {
135
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
136
+ $posts = $wpdb->get_results(
137
+ $wpdb->prepare(
138
+ "SELECT p.ID, p.post_title, p.post_type, pm.meta_value
139
+ FROM {$wpdb->posts} AS p
140
+ LEFT JOIN {$wpdb->postmeta} AS pm ON (p.ID = pm.post_id)
141
+ WHERE pm.meta_key = 'custom_permalink' AND pm.meta_value != ''
142
+ ORDER BY %s %s LIMIT %d, %d",
143
+ $order_by,
144
+ $order,
145
+ $page_offset,
146
+ $per_page
147
+ ),
148
+ ARRAY_A
149
+ );
150
+ }
151
+ // phpcs:enable WordPress.Security.NonceVerification.Recommended
152
+
153
+ wp_cache_set( 'post_type_results', $posts, 'custom_permalinks' );
154
+ }
155
+
156
+ return $posts;
157
+ }
158
+ }
admin/class-custom-permalinks-posttypes.php DELETED
@@ -1,342 +0,0 @@
1
- <?php
2
- /**
3
- * @package CustomPermalinks
4
- */
5
-
6
- class Custom_Permalinks_PostTypes
7
- {
8
-
9
- /**
10
- * Call Post Permalinks Function.
11
- */
12
- function __construct()
13
- {
14
- $this->post_permalinks();
15
- }
16
-
17
- /**
18
- * Return the Navigation row HTML same as Default Posts page for PostTypes.
19
- *
20
- * @since 1.2.0
21
- * @access private
22
- *
23
- * @param string $order_by_class Class either asc or desc.
24
- * @param string $order_by set orderby for sorting.
25
- * @param string $search_permalink Permalink which has been searched or an empty string.
26
- *
27
- * @return string table row according to the provided params.
28
- */
29
- private function post_nav( $order_by_class, $order_by, $search_permalink )
30
- {
31
- $admin_url = get_admin_url();
32
- $page_url = $admin_url . 'admin.php?page=cp-post-permalinks';
33
- $title_url = $page_url . '&amp;orderby=title&amp;order=' . $order_by;
34
- $user_id = get_current_user_id();
35
-
36
- if ( $search_permalink ) {
37
- $title_url = $title_url . $search_permalink;
38
- $title_url = wp_nonce_url( $title_url,
39
- 'custom-permalinks-post_' . $user_id,
40
- '_custom_permalinks_post_nonce'
41
- );
42
- }
43
-
44
- $post_nav = '<tr>' .
45
- '<td id="cb" class="manage-column column-cb check-column">' .
46
- '<label class="screen-reader-text" for="cb-select-all-1">' .
47
- __( 'Select All', 'custom-permalinks' ) .
48
- '</label>' .
49
- '<input id="cb-select-all-1" type="checkbox">' .
50
- '</td>' .
51
- '<th scope="col" id="title" class="manage-column column-title column-primary sortable ' . $order_by_class . '">' .
52
- '<a href="' . $title_url . '">' .
53
- '<span>' .
54
- __( 'Title', 'custom-permalinks' ) .
55
- '</span>' .
56
- '<span class="sorting-indicator"></span>' .
57
- '</a>' .
58
- '</th>' .
59
- '<th scope="col">' .
60
- __( 'Type', 'custom-permalinks' ) .
61
- '</th>' .
62
- '<th scope="col">' .
63
- __( 'Permalink', 'custom-permalinks' ) .
64
- '</th>' .
65
- '</tr>';
66
-
67
- return $post_nav;
68
- }
69
-
70
- /**
71
- * Shows all the Permalinks created by using this Plugin with Pager and Search
72
- * Functionality of Posts/Pages.
73
- *
74
- * @since 1.2.0
75
- * @access private
76
- */
77
- private function post_permalinks()
78
- {
79
- global $wpdb;
80
-
81
- $error = '';
82
- $filter_options = '';
83
- $filter_permalink = '';
84
- $home_url = home_url();
85
- $post_html = '';
86
- $post_action = filter_input( INPUT_POST, 'action' );
87
- $post_action2 = filter_input( INPUT_POST, 'action2' );
88
- $post_permalinks = filter_input( INPUT_POST, 'permalink', FILTER_DEFAULT,
89
- FILTER_REQUIRE_ARRAY
90
- );
91
- $request_uri = '';
92
- $search_permalink = '';
93
- $site_url = site_url();
94
- $user_id = get_current_user_id();
95
-
96
- if ( isset( $_SERVER['REQUEST_URI'] ) ) {
97
- $request_uri = $_SERVER['REQUEST_URI'];
98
- }
99
-
100
- // Handle Bulk Operations
101
- if ( ( 'delete' === $post_action || 'delete' === $post_action2 )
102
- && check_admin_referer( 'custom-permalinks-post_' . $user_id,
103
- '_custom_permalinks_post_nonce'
104
- )
105
- ) {
106
- if ( ! empty( $post_permalinks ) ) {
107
- $post_ids = $post_permalinks;
108
- if ( is_array( $post_ids ) && 0 < count( $post_ids ) ) {
109
- foreach ( $post_ids as $post_id ) {
110
- if ( is_numeric( $post_id ) ) {
111
- delete_metadata( 'post', $post_id, 'custom_permalink' );
112
- }
113
- }
114
- } else {
115
- $error = '<div id="message" class="error">' .
116
- '<p>' .
117
- __( 'Please select permalinks which you like to be deleted.',
118
- 'custom-permalinks'
119
- ) .
120
- '</p>' .
121
- '</div>';
122
- }
123
- } else {
124
- $error = '<div id="message" class="error">' .
125
- '<p>' .
126
- __( 'There is some error to proceed your request. Please retry with your request or contact to the plugin author.',
127
- 'custom-permalinks'
128
- ) .
129
- '</p>' .
130
- '</div>';
131
- }
132
- }
133
- $post_html .= '<div class="wrap">' .
134
- '<h1 class="wp-heading-inline">' .
135
- __( 'PostTypes Permalinks', 'custom-permalinks' ) .
136
- '</h1>' .
137
- $error;
138
-
139
- $get_paged = filter_input( INPUT_GET, 'paged' );
140
- $get_order = filter_input( INPUT_GET, 'order' );
141
- $get_order_by = filter_input( INPUT_GET, 'orderby' );
142
- $order_by = 'asc';
143
- $order_by_class = 'desc';
144
- $page_limit = 'LIMIT 0, 20';
145
- $search_input = filter_input( INPUT_GET, 's' );
146
- $search_value = '';
147
- $sorting_by = 'ORDER By p.ID DESC';
148
-
149
- if ( $search_input
150
- && check_admin_referer( 'custom-permalinks-post_' . $user_id,
151
- '_custom_permalinks_post_nonce'
152
- )
153
- ) {
154
- $filter_permalink = 'AND pm.meta_value LIKE "%' . $search_input . '%"';
155
- $search_permalink = '&s=' . $search_input . '';
156
- $search_value = ltrim( htmlspecialchars( $search_input ), '/' );
157
- $post_html .= '<span class="subtitle">Search results for "' . $search_value . '"</span>';
158
- }
159
-
160
- if ( is_numeric( $get_paged ) && 1 < $get_paged ) {
161
- $pager = 20 * ( $get_paged - 1 );
162
- $page_limit = 'LIMIT ' . $pager . ', 20';
163
- }
164
-
165
- if ( 'title' === $get_order_by ) {
166
- $filter_options .= '<input type="hidden" name="orderby" value="title" />';
167
- if ( 'desc' === $get_order ) {
168
- $sorting_by = 'ORDER By p.post_title DESC';
169
- $order_by = 'asc';
170
- $order_by_class = 'desc';
171
- $filter_options .= '<input type="hidden" name="order" value="desc" />';
172
- } else {
173
- $sorting_by = 'ORDER By p.post_title';
174
- $order_by = 'desc';
175
- $order_by_class = 'asc';
176
- $filter_options .= '<input type="hidden" name="order" value="asc" />';
177
- }
178
- }
179
-
180
- $count_query = "SELECT COUNT(p.ID) AS total_permalinks FROM $wpdb->posts AS p LEFT JOIN $wpdb->postmeta AS pm ON (p.ID = pm.post_id) WHERE pm.meta_key = 'custom_permalink' AND pm.meta_value != '' " . $filter_permalink . "";
181
- $count_posts = $wpdb->get_row( $count_query );
182
- $post_nonce = wp_nonce_field( 'custom-permalinks-post_' . $user_id,
183
- '_custom_permalinks_post_nonce', true, false
184
- );
185
-
186
- $post_html .= '<form action="' . $site_url . $request_uri . '" method="get">' .
187
- '<p class="search-box">' .
188
- '<input type="hidden" name="page" value="cp-post-permalinks" />' .
189
- $post_nonce .
190
- $filter_options .
191
- '<label class="screen-reader-text" for="custom-permalink-search-input">' .
192
- __( 'Search Custom Permalink:', 'custom-permalinks' ) .
193
- '</label>' .
194
- '<input type="search" id="custom-permalink-search-input" name="s" value="' . $search_value . '">' .
195
- '<input type="submit" id="search-submit" class="button" value="' . __( "Search Permalink", "custom-permalinks" ) . '"></p>' .
196
- '</form>' .
197
- '<form action="' . $site_url . $request_uri . '" method="post">' .
198
- '<div class="tablenav top">' .
199
- '<div class="alignleft actions bulkactions">' .
200
- '<label for="bulk-action-selector-top" class="screen-reader-text">' .
201
- __( 'Select bulk action', 'custom-permalinks' ) .
202
- '</label>' .
203
- $post_nonce .
204
- '<select name="action" id="bulk-action-selector-top">' .
205
- '<option value="-1">' .
206
- __( 'Bulk Actions', 'custom-permalinks' ) .
207
- '</option>' .
208
- '<option value="delete">' .
209
- __( 'Delete Permalinks', 'custom-permalinks' ) .
210
- '</option>' .
211
- '</select>' .
212
- '<input type="submit" id="doaction" class="button action" value="' . __( "Apply", "custom-permalinks" ) . '">' .
213
- '</div>';
214
-
215
- $posts = 0;
216
- $pagination_html = '';
217
- if ( isset( $count_posts->total_permalinks )
218
- && 0 < $count_posts->total_permalinks
219
- ) {
220
- include_once CUSTOM_PERMALINKS_PATH . 'admin/class-custom-permalinks-pager.php';
221
-
222
- $cp_pager = new Custom_Permalinks_Pager();
223
- $post_html .= '<h2 class="screen-reader-text">' .
224
- __( 'Custom Permalink navigation', 'custom-permalinks' ) .
225
- '</h2>';
226
-
227
- $query = "SELECT p.ID, p.post_title, p.post_type, pm.meta_value FROM $wpdb->posts AS p LEFT JOIN $wpdb->postmeta AS pm ON (p.ID = pm.post_id) WHERE pm.meta_key = 'custom_permalink' AND pm.meta_value != '' " . $filter_permalink . " " . $sorting_by . " " . $page_limit . "";
228
- $posts = $wpdb->get_results( $query );
229
-
230
- $total_pages = ceil( $count_posts->total_permalinks / 20 );
231
- if ( is_numeric( $get_paged ) && 0 < $get_paged ) {
232
- $pagination_html = $cp_pager->get_pagination(
233
- $count_posts->total_permalinks, $get_paged, $total_pages
234
- );
235
- if ( $get_paged > $total_pages ) {
236
- $redirect_uri = explode( '&paged=' . $get_paged . '',
237
- $request_uri
238
- );
239
-
240
- wp_safe_redirect( $redirect_uri[0], 301 );
241
- exit;
242
- }
243
- } elseif ( ! $get_paged ) {
244
- $pagination_html = $cp_pager->get_pagination(
245
- $count_posts->total_permalinks, 1, $total_pages
246
- );
247
- }
248
-
249
- $post_html .= $pagination_html;
250
- }
251
- $table_navigation = $this->post_nav( $order_by_class, $order_by,
252
- $search_permalink
253
- );
254
-
255
- $post_html .= '</div>';
256
- $post_html .= '<table class="wp-list-table widefat fixed striped posts">' .
257
- '<thead>' . $table_navigation . '</thead>' .
258
- '<tbody>';
259
- if ( 0 != $posts && ! empty( $posts ) ) {
260
- $cp_frontend = new Custom_Permalinks_Frontend();
261
- if ( class_exists( 'SitePress' ) ) {
262
- $wpml_lang_format = apply_filters( 'wpml_setting', 0,
263
- 'language_negotiation_type'
264
- );
265
-
266
- if ( 1 === intval( $wpml_lang_format ) ) {
267
- $home_url = $site_url;
268
- }
269
- }
270
-
271
- foreach ( $posts as $post ) {
272
- $custom_permalink = '/' . $post->meta_value;
273
- $post_type = 'post';
274
- if ( isset( $post->post_type ) ) {
275
- $post_type = $post->post_type;
276
- }
277
-
278
- $language_code = apply_filters( 'wpml_element_language_code', null,
279
- array(
280
- 'element_id' => $post->ID,
281
- 'element_type' => $post_type
282
- )
283
- );
284
-
285
- $permalink = $cp_frontend->wpml_permalink_filter( $custom_permalink,
286
- $language_code
287
- );
288
- $permalink = $cp_frontend->remove_double_slash( $permalink );
289
- $perm_text = str_replace( $home_url, '', $permalink );
290
-
291
- $post_html .= '<tr valign="top">' .
292
- '<th scope="row" class="check-column">' .
293
- '<input type="checkbox" name="permalink[]" value="' . $post->ID . '" />' .
294
- '</th>' .
295
- '<td>' .
296
- '<strong>' .
297
- '<a class="row-title" href="' . $site_url . '/wp-admin/post.php?action=edit&post=' . $post->ID . '">' .
298
- $post->post_title .
299
- '</a>' .
300
- '</strong>' .
301
- '</td>' .
302
- '<td>' . ucwords( $post->post_type ) . '</td>' .
303
- '<td>' .
304
- '<a href="' . $permalink . '" target="_blank" title="' . __( "Visit " . $post->post_title, "custom-permalinks" ) . '">' .
305
- $perm_text .
306
- '</a>' .
307
- '</td>' .
308
- '</tr>';
309
- }
310
- } else {
311
- $post_html .= '<tr class="no-items">' .
312
- '<td class="colspanchange" colspan="4">' .
313
- __( 'No permalinks found.', 'custom-permalinks' ) .
314
- '</td>' .
315
- '</tr>';
316
- }
317
- $post_html .= '</tbody>' .
318
- '<tfoot>' . $table_navigation . '</tfoot>' .
319
- '</table>';
320
-
321
- $post_html .= '<div class="tablenav bottom">' .
322
- '<div class="alignleft actions bulkactions">' .
323
- '<label for="bulk-action-selector-bottom" class="screen-reader-text">' .
324
- __( 'Select bulk action', 'custom-permalinks' ) .
325
- '</label>' .
326
- '<select name="action2" id="bulk-action-selector-bottom">' .
327
- '<option value="-1">' .
328
- __( 'Bulk Actions', 'custom-permalinks' ) .
329
- '</option>' .
330
- '<option value="delete">' .
331
- __( 'Delete Permalinks', 'custom-permalinks' ) .
332
- '</option>' .
333
- '</select>' .
334
- '<input type="submit" id="doaction2" class="button action" value="' . __( "Apply", "custom-permalinks" ) . '">' .
335
- '</div>' .
336
- $pagination_html .
337
- '</div>' .
338
- '</form></div>';
339
-
340
- echo $post_html;
341
- }
342
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/class-custom-permalinks-taxonomies-table.php ADDED
@@ -0,0 +1,501 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Custom Permalinks Post Types.
4
+ *
5
+ * @package CustomPermalinks
6
+ */
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
10
+ }
11
+
12
+ if ( ! class_exists( 'WP_List_Table' ) ) {
13
+ include_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
14
+ }
15
+
16
+ /**
17
+ * Taxonomies Permalinks table class.
18
+ */
19
+ final class Custom_Permalinks_Taxonomies_Table extends WP_List_Table {
20
+ /**
21
+ * Singleton instance variable
22
+ *
23
+ * @var object
24
+ */
25
+ private static $instance;
26
+
27
+ /**
28
+ * Initialize the Taxonomies Permalinks table list.
29
+ *
30
+ * @since 2.0.0
31
+ * @access public
32
+ */
33
+ public function __construct() {
34
+ parent::__construct(
35
+ array(
36
+ 'singular' => __( 'Permalink', 'custom-permalinks' ),
37
+ 'plural' => __( 'Permalinks', 'custom-permalinks' ),
38
+ 'ajax' => false,
39
+ )
40
+ );
41
+
42
+ // Handle screen options.
43
+ $this->screen_options();
44
+ }
45
+
46
+ /**
47
+ * Singleton instance method.
48
+ *
49
+ * @since 2.0.0
50
+ * @access public
51
+ *
52
+ * @return Custom_Permalinks_Taxonomies_Table The instance.
53
+ */
54
+ public static function instance() {
55
+ if ( ! isset( self::$instance ) ) {
56
+ self::$instance = new self();
57
+ }
58
+
59
+ return self::$instance;
60
+ }
61
+
62
+ /**
63
+ * Handle displaying and saving screen options.
64
+ *
65
+ * @since 2.0.0
66
+ * @access private
67
+ *
68
+ * @return void
69
+ */
70
+ private function screen_options() {
71
+ $per_page_option = "{$this->screen->id}_per_page";
72
+
73
+ // phpcs:disable WordPress.Security.NonceVerification.Missing
74
+ // Save screen options if the form has been submitted.
75
+ if ( isset( $_POST['screen-options-apply'] ) ) {
76
+ // Save posts per page option.
77
+ if ( isset( $_POST['wp_screen_options']['value'] ) ) {
78
+ update_user_option(
79
+ get_current_user_id(),
80
+ $per_page_option,
81
+ sanitize_text_field( $_POST['wp_screen_options']['value'] )
82
+ );
83
+ }
84
+ }
85
+ // phpcs:enable WordPress.Security.NonceVerification.Missing
86
+
87
+ // Add per page option to the screen options.
88
+ $this->screen->add_option(
89
+ 'per_page',
90
+ array(
91
+ 'option' => $per_page_option,
92
+ )
93
+ );
94
+ }
95
+
96
+ /**
97
+ * No items found text.
98
+ *
99
+ * @since 2.0.0
100
+ * @access public
101
+ *
102
+ * @return void
103
+ */
104
+ public function no_items() {
105
+ esc_html_e( 'No permalinks found.', 'custom-permalinks' );
106
+ }
107
+
108
+ /**
109
+ * Get list of columns in the form of array.
110
+ *
111
+ * @since 2.0.0
112
+ * @access public
113
+ *
114
+ * @return array Column list.
115
+ */
116
+ public function get_columns() {
117
+ $columns = array(
118
+ 'cb' => '<input type="checkbox" />',
119
+ 'title' => esc_html__( 'Title', 'custom-permalinks' ),
120
+ 'type' => esc_html__( 'Type', 'custom-permalinks' ),
121
+ 'permalink' => esc_html__( 'Permalink', 'custom-permalinks' ),
122
+ );
123
+
124
+ return $columns;
125
+ }
126
+
127
+ /**
128
+ * Returns the output of the page.
129
+ *
130
+ * @since 2.0.0
131
+ * @access public
132
+ */
133
+ public static function output() {
134
+ $user_id = get_current_user_id();
135
+ $permalink_deleted = filter_input( INPUT_GET, 'deleted' );
136
+ $search_permalink = filter_input( INPUT_GET, 's' );
137
+ $taxonomy_types_table = self::instance();
138
+ $taxonomy_types_table->prepare_items();
139
+ ?>
140
+
141
+ <div class="wrap">
142
+ <h1 class="wp-heading-inline">
143
+ <?php esc_html_e( 'Taxonomies Permalinks', 'custom-permalinks' ); ?>
144
+ </h1>
145
+
146
+ <?php if ( isset( $search_permalink ) && ! empty( $search_permalink ) ) : ?>
147
+ <span class="subtitle">
148
+ <?php
149
+ esc_html_e( 'Search results for: ', 'custom-permalinks' );
150
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
151
+ printf( '<strong>%s</strong>', $search_permalink );
152
+ ?>
153
+ </span>
154
+ <?php endif; ?>
155
+
156
+ <hr class="wp-header-end">
157
+
158
+ <?php if ( isset( $permalink_deleted ) && 0 < $permalink_deleted ) : ?>
159
+ <div id="message" class="updated notice is-dismissible">
160
+ <p>
161
+ <?php
162
+ printf(
163
+ // translators: Placeholder would bee replaced with the number.
164
+ _n( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
165
+ '%s permalink deleted.',
166
+ '%s permalinks deleted.',
167
+ $permalink_deleted,
168
+ 'custom-permalinks'
169
+ ),
170
+ esc_html( $permalink_deleted )
171
+ );
172
+ ?>
173
+ </p>
174
+ </div>
175
+ <?php endif; ?>
176
+ <form id="posts-filter" method="GET">
177
+ <input type="hidden" name="page" value="cp-taxonomy-permalinks" />
178
+ <?php
179
+ wp_nonce_field(
180
+ 'custom-permalinks-taxonomy_' . $user_id,
181
+ '_custom_permalinks_taxonomy_nonce'
182
+ );
183
+ $taxonomy_types_table->search_box(
184
+ esc_html__(
185
+ 'Search Permalinks',
186
+ 'custom-permalinks'
187
+ ),
188
+ 'search-submit'
189
+ );
190
+ $taxonomy_types_table->display();
191
+ ?>
192
+ </form>
193
+ </div>
194
+
195
+ <?php
196
+ }
197
+
198
+ /**
199
+ * Set up column headings for WP_List_Table.
200
+ *
201
+ * @since 2.0.0
202
+ * @access protected
203
+ *
204
+ * @return array
205
+ */
206
+ protected function get_hidden_columns() {
207
+ $columns = get_user_option( "manage{$this->screen->id}columnshidden" );
208
+
209
+ return apply_filters( 'custom_permalinks_taxonomy_table_hidden_columns', (array) $columns );
210
+ }
211
+
212
+ /**
213
+ * Render the checkbox for bulk action.
214
+ *
215
+ * @since 2.0.0
216
+ * @access protected
217
+ *
218
+ * @param array $item Single Item.
219
+ *
220
+ * @return string
221
+ */
222
+ protected function column_cb( $item ) {
223
+ return sprintf(
224
+ '<input type="checkbox" name="permalink[]" value="%s" />',
225
+ $item['ID']
226
+ );
227
+ }
228
+
229
+ /**
230
+ * Set up column contents for `Title`.
231
+ *
232
+ * @since 2.0.0
233
+ * @access public
234
+ *
235
+ * @param array $item Single Item.
236
+ *
237
+ * @return string Post Title.
238
+ */
239
+ protected function column_title( $item ) {
240
+ $edit_link = '';
241
+ $term_title = 'NOT SET';
242
+
243
+ if ( isset( $item['ID'] ) && isset( $item['type'] ) ) {
244
+ $taxonomy_type = 'category';
245
+ if ( 'tag' === $item['type'] ) {
246
+ $taxonomy_type = 'post_tag';
247
+ }
248
+
249
+ $edit_link = get_edit_term_link( $item['ID'], $taxonomy_type );
250
+ $term = get_term( $item['ID'], $taxonomy_type );
251
+
252
+ if ( isset( $term ) && isset( $term->name ) && ! empty( $term->name ) ) {
253
+ $term_title = $term->name;
254
+ }
255
+ }
256
+
257
+ $title_with_edit_link = $term_title;
258
+ if ( ! empty( $edit_link ) ) {
259
+ $title_with_edit_link = sprintf(
260
+ '<a href="%s" target="_blank" title="' . esc_html__( 'Edit ', 'custom-permalinks' ) . ' ' . $term_title . '">%s</a>',
261
+ $edit_link,
262
+ $term_title
263
+ );
264
+ }
265
+
266
+ return $title_with_edit_link;
267
+ }
268
+
269
+ /**
270
+ * Set up column contents for `Type`.
271
+ *
272
+ * @since 2.0.0
273
+ * @access protected
274
+ *
275
+ * @param array $item Single Item.
276
+ *
277
+ * @return string Taxonomy Name.
278
+ */
279
+ protected function column_type( $item ) {
280
+ $taxonomy_type = 'category';
281
+
282
+ if ( isset( $item['type'] ) ) {
283
+ $taxonomy_type = ucwords( $item['type'] );
284
+ }
285
+
286
+ return $taxonomy_type;
287
+ }
288
+
289
+ /**
290
+ * Set up column contents for `Permalink`.
291
+ *
292
+ * @since 2.0.0
293
+ * @access protected
294
+ *
295
+ * @param array $item Single Item.
296
+ *
297
+ * @return string Post Permalink.
298
+ */
299
+ protected function column_permalink( $item ) {
300
+ $permalink = '';
301
+
302
+ if ( $item['permalink'] ) {
303
+ $cp_frontend = new Custom_Permalinks_Frontend();
304
+ $custom_permalink = '/' . $item['permalink'];
305
+ $home_url = home_url();
306
+ $taxonomy_type = 'category';
307
+
308
+ if ( class_exists( 'SitePress' ) ) {
309
+ $wpml_lang_format = apply_filters(
310
+ 'wpml_setting',
311
+ 0,
312
+ 'language_negotiation_type'
313
+ );
314
+
315
+ if ( 1 === intval( $wpml_lang_format ) ) {
316
+ $home_url = $site_url;
317
+ }
318
+ }
319
+
320
+ if ( 'tag' === $item['type'] ) {
321
+ $taxonomy_type = 'post_tag';
322
+ }
323
+
324
+ $language_code = apply_filters(
325
+ 'wpml_element_language_code',
326
+ null,
327
+ array(
328
+ 'element_id' => $item['ID'],
329
+ 'element_type' => $taxonomy_type,
330
+ )
331
+ );
332
+
333
+ $permalink = $cp_frontend->wpml_permalink_filter(
334
+ $custom_permalink,
335
+ $language_code
336
+ );
337
+ $permalink = $cp_frontend->remove_double_slash( $permalink );
338
+ $perm_text = str_replace( $home_url, '', $permalink );
339
+
340
+ $term_title = '';
341
+ if ( isset( $item['ID'] ) && isset( $item['type'] ) ) {
342
+ $term = get_term( $item['ID'], $item['type'] );
343
+ if ( isset( $term ) && isset( $term->name ) && ! empty( $term->name ) ) {
344
+ $term_title = $term->name;
345
+ }
346
+ }
347
+
348
+ $permalink = sprintf(
349
+ '<a href="%s" target="_blank" title="' . esc_html__( 'Visit', 'custom-permalinks' ) . ' ' . $term_title . '">%s</a>',
350
+ $permalink,
351
+ $perm_text
352
+ );
353
+ }
354
+
355
+ return $permalink;
356
+ }
357
+
358
+ /**
359
+ * Get bulk actions.
360
+ *
361
+ * @since 2.0.0
362
+ * @access public
363
+ *
364
+ * @return array Available Actions.
365
+ */
366
+ public function get_bulk_actions() {
367
+ return array(
368
+ 'delete' => esc_html__( 'Delete Permalinks', 'custom-permalinks' ),
369
+ );
370
+ }
371
+
372
+ /**
373
+ * Process bulk actions.
374
+ *
375
+ * @since 2.0.0
376
+ * @access public
377
+ *
378
+ * @return void
379
+ */
380
+ public function process_bulk_action() {
381
+ if ( isset( $_REQUEST['_custom_permalinks_taxonomy_nonce'] ) ) {
382
+ $deleted = 0;
383
+ $user_id = get_current_user_id();
384
+
385
+ // Detect when a bulk action is being triggered.
386
+ if ( 'delete' === $this->current_action()
387
+ && wp_verify_nonce(
388
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
389
+ $_REQUEST['_custom_permalinks_taxonomy_nonce'],
390
+ 'custom-permalinks-taxonomy_' . $user_id
391
+ )
392
+ ) {
393
+ if ( isset( $_REQUEST['permalink'] ) ) {
394
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
395
+ $del_permalinks = $_REQUEST['permalink'];
396
+ }
397
+
398
+ if ( isset( $del_permalinks )
399
+ && ! empty( $del_permalinks )
400
+ && is_array( $del_permalinks )
401
+ && 0 < count( $del_permalinks )
402
+ ) {
403
+ $cp_form = new Custom_Permalinks_Form();
404
+ foreach ( $del_permalinks as $term_id ) {
405
+ if ( is_numeric( $term_id ) ) {
406
+ $cp_form->delete_term_permalink( $term_id );
407
+ ++$deleted;
408
+ }
409
+ }
410
+ }
411
+ }
412
+
413
+ $cp_page = filter_input( INPUT_GET, 'page' );
414
+ $cp_paged = filter_input( INPUT_GET, 'paged' );
415
+ $perm_search = filter_input( INPUT_GET, 's' );
416
+ $page_args = array();
417
+
418
+ if ( ! empty( $cp_page ) ) {
419
+ $page_args['page'] = $cp_page;
420
+ } else {
421
+ $page_args['page'] = 'cp-taxonomy-permalinks';
422
+ }
423
+
424
+ if ( ! empty( $perm_search ) ) {
425
+ $page_args['s'] = $perm_search;
426
+ }
427
+
428
+ if ( ! empty( $cp_paged ) && is_numeric( $cp_paged ) ) {
429
+ $page_args['paged'] = $cp_paged;
430
+ }
431
+
432
+ if ( 0 < $deleted ) {
433
+ $page_args['deleted'] = $deleted;
434
+ }
435
+
436
+ wp_safe_redirect( add_query_arg( $page_args, admin_url( 'admin.php' ) ) );
437
+ exit;
438
+ }
439
+ }
440
+
441
+ /**
442
+ * Generate the table navigation above or below the table.
443
+ *
444
+ * @since 2.0.0
445
+ * @access protected
446
+ *
447
+ * @param string $which Table Navigation position.
448
+ *
449
+ * @return void
450
+ */
451
+ protected function display_tablenav( $which ) {
452
+ ?>
453
+ <div class="tablenav <?php echo esc_attr( $which ); ?>">
454
+ <?php if ( $this->has_items() ) : ?>
455
+ <div class="alignleft actions bulkactions">
456
+ <?php $this->bulk_actions( $which ); ?>
457
+ </div>
458
+ <?php
459
+ endif;
460
+
461
+ $this->extra_tablenav( $which );
462
+ $this->pagination( $which );
463
+ ?>
464
+
465
+ <br class="clear" />
466
+ </div>
467
+ <?php
468
+ }
469
+
470
+ /**
471
+ * Prepare table list items.
472
+ *
473
+ * @since 2.0.0
474
+ * @access public
475
+ *
476
+ * @return void
477
+ */
478
+ public function prepare_items() {
479
+ $columns = $this->get_columns();
480
+ $hidden = $this->get_hidden_columns();
481
+ $sortable = array();
482
+
483
+ $this->_column_headers = array( $columns, $hidden, $sortable );
484
+
485
+ // Process bulk action.
486
+ $this->process_bulk_action();
487
+
488
+ $per_page = $this->get_items_per_page( "{$this->screen->id}_per_page" );
489
+ $current_page = $this->get_pagenum();
490
+ $total_items = Custom_Permalinks_Taxonomies::total_permalinks();
491
+ $this->items = Custom_Permalinks_Taxonomies::get_permalinks( $per_page, $current_page );
492
+
493
+ $this->set_pagination_args(
494
+ array(
495
+ 'total_items' => $total_items,
496
+ 'per_page' => $per_page,
497
+ 'total_pages' => ceil( $total_items / $per_page ),
498
+ )
499
+ );
500
+ }
501
+ }
admin/class-custom-permalinks-taxonomies.php CHANGED
@@ -1,315 +1,129 @@
1
  <?php
2
  /**
 
 
3
  * @package CustomPermalinks
4
  */
5
 
6
- class Custom_Permalinks_Taxonomies
7
- {
8
-
9
- /**
10
- * Call Taxonomy Permalinks Function.
11
- */
12
- function __construct()
13
- {
14
- $this->taxonomies_permalinks();
15
- }
16
-
17
- /**
18
- * Return the Navigation row HTML same as Default Posts page for Category.
19
- *
20
- * @since 1.2.0
21
- * @access private
22
- *
23
- * @return string table row according to the provided params.
24
- */
25
- private function taxonomy_nav()
26
- {
27
- $navigation = '<tr>' .
28
- '<td id="cb" class="manage-column column-cb check-column">' .
29
- '<label class="screen-reader-text" for="cb-select-all-1">' .
30
- __( 'Select All', 'custom-permalinks' ) .
31
- '</label>' .
32
- '<input id="cb-select-all-1" type="checkbox">' .
33
- '</td>' .
34
- '<th scope="col" id="title" class="manage-column column-title column-primary">' .
35
- __( 'Title', 'custom-permalinks' ) .
36
- '</th>' .
37
- '<th scope="col">' .
38
- __( 'Type', 'custom-permalinks' ) .
39
- '</th>' .
40
- '<th scope="col">' .
41
- __( 'Permalink', 'custom-permalinks' ) .
42
- '</th>' .
43
- '</tr>';
44
-
45
- return $navigation;
46
- }
47
-
48
- /**
49
- * Sort the terms array in desc order using term id.
50
- *
51
- * @since 1.2.0
52
- * @access public
53
- *
54
- * @return int
55
- */
56
- public function sort_array( $comp1, $comp2 )
57
- {
58
- return $comp2['id'] - $comp1['id'];
59
- }
60
-
61
- /**
62
- * Shows all the Permalinks created by using this Plugin with Pager and
63
- * Search Functionality of Category/Tags.
64
- *
65
- * @since 1.2.0
66
- * @access private
67
- */
68
- private function taxonomies_permalinks()
69
- {
70
- $home_url = home_url();
71
- $page_html = '';
72
- $request_uri = '';
73
- $site_url = site_url();
74
- $term_action = filter_input( INPUT_POST, 'action' );
75
- $term_action2 = filter_input( INPUT_POST, 'action2' );
76
- $term_permalinks = filter_input( INPUT_POST, 'permalink',
77
- FILTER_DEFAULT, FILTER_REQUIRE_ARRAY
78
- );
79
- $user_id = get_current_user_id();
80
-
81
- if ( isset( $_SERVER['REQUEST_URI'] ) ) {
82
- $request_uri = $_SERVER['REQUEST_URI'];
83
- }
84
-
85
- // Handle Bulk Operations
86
- if ( ( 'delete' === $term_action || 'delete' === $term_action2 )
87
- && check_admin_referer( 'custom-permalinks-term_' . $user_id,
88
- '_custom_permalinks_term_nonce'
89
- )
90
- ) {
91
- if ( ! empty( $term_permalinks ) ) {
92
- $data = get_option( 'custom_permalink_table' );
93
- if ( isset( $data ) && is_array( $data ) ) {
94
- $loopCount = 0;
95
- foreach ( $data as $link => $info ) {
96
- if ( in_array( $info['id'], $term_permalinks ) ) {
97
- unset( $data[$link] );
98
- unset( $term_permalinks[$loopCount] );
99
- if ( ! is_array( $term_permalinks )
100
- || empty( $term_permalinks )
101
- ) {
102
- break;
103
- }
104
- }
105
- $loopCount += 1;
106
- }
107
- }
108
-
109
- update_option( 'custom_permalink_table', $data );
110
- }
111
- }
112
- $page_html .= '<div class="wrap">' .
113
- '<h1 class="wp-heading-inline">' .
114
- __( 'Taxonomies Permalinks', 'custom-permalinks' ) .
115
- '</h1>';
116
-
117
- $get_paged = filter_input( INPUT_GET, 'paged' );
118
- $page_limit = 20;
119
- $pager_offset = '0';
120
- $search_input = filter_input( INPUT_GET, 's' );
121
- $search_value = '';
122
- $term_nonce = wp_nonce_field( 'custom-permalinks-term_' . $user_id,
123
- '_custom_permalinks_term_nonce', true, false
124
- );
125
-
126
- if ( ! empty( $search_input )
127
- && check_admin_referer( 'custom-permalinks-term_' . $user_id,
128
- '_custom_permalinks_term_nonce'
129
- )
130
- ) {
131
- $search_value = ltrim( htmlspecialchars( $search_input ), '/' );
132
- $page_html .= '<span class="subtitle">Search results for "' . $search_value . '"</span>';
133
- }
134
-
135
- if ( is_numeric( $get_paged ) && 1 < $get_paged ) {
136
- $pager_offset = 20 * ( $get_paged - 1 );
137
- $page_limit = $pager_offset + 20;
138
- }
139
-
140
- $page_html .= '<form action="' . $site_url . $request_uri . '" method="get">' .
141
- '<p class="search-box">' .
142
- '<input type="hidden" name="page" value="cp-category-permalinks" />' .
143
- $term_nonce .
144
- '<label class="screen-reader-text" for="custom-permalink-search-input">' .
145
- __( 'Search Custom Permalink:', 'custom-permalinks' ) .
146
- '</label>' .
147
- '<input type="search" id="custom-permalink-search-input" name="s" value="' . $search_value . '">' .
148
- '<input type="submit" id="search-submit" class="button" value="' . __( "Search Permalink", "custom-permalinks" ) . '">' .
149
- '</p>' .
150
- '</form>' .
151
- '<form action="' . $site_url . $request_uri . '" method="post">' .
152
- '<div class="tablenav top">' .
153
- '<div class="alignleft actions bulkactions">' .
154
- '<label for="bulk-action-selector-top" class="screen-reader-text">' .
155
- __( 'Select bulk action', 'custom-permalinks' ) .
156
- '</label>' .
157
- $term_nonce .
158
- '<select name="action" id="bulk-action-selector-top">' .
159
- '<option value="-1">' .
160
- __( 'Bulk Actions', 'custom-permalinks' ) .
161
- '</option>' .
162
- '<option value="delete">' .
163
- __( 'Delete Permalinks', 'custom-permalinks' ) .
164
- '</option>' .
165
- '</select>' .
166
- '<input type="submit" id="doaction" class="button action" value="' . __( "Apply", "custom-permalinks" ) . '">' .
167
- '</div>';
168
-
169
- $table = get_option( 'custom_permalink_table' );
170
- $count_tags = 0;
171
- $pagination_html = '';
172
- if ( isset( $table ) && is_array( $table ) ) {
173
- $count_tags = count( $table );
174
- }
175
-
176
- if ( 0 < $count_tags ) {
177
- include_once CUSTOM_PERMALINKS_PATH . 'admin/class-custom-permalinks-pager.php';
178
-
179
- $cp_pager = new Custom_Permalinks_Pager();
180
- $filtered = array();
181
- if ( '' != $search_value ) {
182
- foreach ( $table as $key => $value ) {
183
- if ( preg_match( '/' . $search_value . '/', $key) ) {
184
- $filtered[$key] = $value;
185
- }
186
- }
187
- $table = $filtered;
188
- $count_tags = count( $table );
189
- }
190
-
191
- $page_html .= '<h2 class="screen-reader-text">' .
192
- __( 'Custom Permalink navigation', 'custom-permalinks' ) .
193
- '</h2>';
194
-
195
- $total_pages = ceil( $count_tags / 20 );
196
- if ( is_numeric( $get_paged ) && 0 < $get_paged ) {
197
- $pagination_html = $cp_pager->get_pagination(
198
- $count_tags, $get_paged, $total_pages
199
- );
200
- if ( $get_paged > $total_pages ) {
201
- $redirect_uri = explode( '&paged=' . $get_paged . '',
202
- $request_uri
203
- );
204
-
205
- wp_safe_redirect( $redirect_uri[0], 301 );
206
- exit;
207
- }
208
- } elseif ( ! isset( $get_paged ) ) {
209
- $pagination_html = $cp_pager->get_pagination( $count_tags, 1,
210
- $total_pages
211
- );
212
- }
213
-
214
- $page_html .= $pagination_html;
215
- }
216
- $table_navigation = $this->taxonomy_nav();
217
-
218
- $page_html .= '</div>' .
219
- '<table class="wp-list-table widefat fixed striped posts">' .
220
- '<thead>' . $table_navigation . '</thead>' .
221
- '<tbody>';
222
-
223
- if ( $table && is_array( $table ) && 0 < $count_tags ) {
224
- $cp_frontend = new Custom_Permalinks_Frontend();
225
- if ( class_exists( 'SitePress' ) ) {
226
- $wpml_lang_format = apply_filters( 'wpml_setting', 0,
227
- 'language_negotiation_type'
228
- );
229
-
230
- if ( 1 === intval( $wpml_lang_format ) ) {
231
- $home_url = $site_url;
232
- }
233
- }
234
-
235
- uasort( $table, array( $this, 'sort_array' ) );
236
- $loopCount = -1;
237
- foreach ( $table as $permalink => $info ) {
238
- $loopCount += 1;
239
- if ( $loopCount < $pager_offset ) {
240
- continue;
241
- }
242
-
243
- if ( $loopCount >= $page_limit ) {
244
- break;
245
- }
246
-
247
- $type = 'category';
248
- if ( 'tag' == $info['kind'] ) {
249
- $type = 'post_tag';
250
- }
251
-
252
- $language_code = apply_filters( 'wpml_element_language_code',
253
- null, array(
254
- 'element_id' => $info['id'],
255
- 'element_type' => $type
256
- )
257
- );
258
-
259
- $permalink = $cp_frontend->wpml_permalink_filter( $permalink,
260
- $language_code
261
- );
262
- $permalink = $cp_frontend->remove_double_slash( $permalink );
263
- $perm_text = str_replace( $home_url, '', $permalink );
264
-
265
- $term = get_term( $info['id'], $type );
266
- $page_html .= '<tr valign="top">' .
267
- '<th scope="row" class="check-column">' .
268
- '<input type="checkbox" name="permalink[]" value="' . $info['id'] . '" />' .
269
- '</th>' .
270
- '<td><strong>' .
271
- '<a class="row-title" href="' . $site_url . '/wp-admin/edit-tags.php?action=edit&taxonomy=' . $type . '&tag_ID=' . $info['id'] . ' ">' .
272
- $term->name .
273
- '</a>' .
274
- '</strong></td>' .
275
- '<td>' . ucwords( $info['kind'] ) . '</td>' .
276
- '<td>' .
277
- '<a href="' . $permalink . '" target="_blank" title="' . __( "Visit " . $term->name, "custom-permalinks" ) . '">' .
278
- $perm_text .
279
- '</a>' .
280
- '</td>' .
281
- '</tr>';
282
- }
283
- } else {
284
- $page_html .= '<tr class="no-items">' .
285
- '<td class="colspanchange" colspan="4">' .
286
- __( 'No permalinks found.', 'custom-permalinks' ) .
287
- '</td>' .
288
- '</tr>';
289
- }
290
- $page_html .= '</tbody>' .
291
- '<tfoot>' . $table_navigation . '</tfoot>' .
292
- '</table>';
293
-
294
- $page_html .= '<div class="tablenav bottom">' .
295
- '<div class="alignleft actions bulkactions">' .
296
- '<label for="bulk-action-selector-bottom" class="screen-reader-text">' .
297
- __( 'Select bulk action', 'custom-permalinks' ) .
298
- '</label>' .
299
- '<select name="action2" id="bulk-action-selector-bottom">' .
300
- '<option value="-1">' .
301
- __( 'Bulk Actions', 'custom-permalinks' ) .
302
- '</option>' .
303
- '<option value="delete">' .
304
- __( 'Delete Permalinks', 'custom-permalinks' ) .
305
- '</option>' .
306
- '</select>' .
307
- '<input type="submit" id="doaction2" class="button action" value="' . __( "Apply", "custom-permalinks" ) . '">' .
308
- '</div>' .
309
- $pagination_html .
310
- '</div>' .
311
- '</form></div>';
312
 
313
- echo $page_html;
314
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
315
  }
1
  <?php
2
  /**
3
+ * Custom Permalinks Taxonomies.
4
+ *
5
  * @package CustomPermalinks
6
  */
7
 
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
10
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
+ /**
13
+ * Taxonomies Permalinks table class.
14
+ */
15
+ final class Custom_Permalinks_Taxonomies {
16
+ /**
17
+ * Sort the terms array in desc order using term id.
18
+ *
19
+ * @since 1.2.0
20
+ * @access public
21
+ *
22
+ * @param int $comp1 Value 1.
23
+ * @param int $comp2 Value 2.
24
+ *
25
+ * @return int
26
+ */
27
+ public static function sort_array( $comp1, $comp2 ) {
28
+ return $comp2['id'] - $comp1['id'];
29
+ }
30
+
31
+ /**
32
+ * Returns the count of records in the database.
33
+ *
34
+ * @since 2.0.0
35
+ * @access public
36
+ *
37
+ * @return null|int
38
+ */
39
+ public static function total_permalinks() {
40
+ $total_taxonomies = wp_cache_get( 'total_taxonomies_result', 'custom_permalinks' );
41
+ if ( ! $total_taxonomies ) {
42
+ $taxonomy_table = get_option( 'custom_permalink_table' );
43
+ $search_taxonomy = array();
44
+
45
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended
46
+ // Include search in total results.
47
+ if ( isset( $_REQUEST['s'] ) && ! empty( $_REQUEST['s'] ) ) {
48
+ $search_value = ltrim( sanitize_text_field( $_REQUEST['s'] ), '/' );
49
+ $search_value = str_replace( '/', '\/', $search_value );
50
+ foreach ( $taxonomy_table as $key => $value ) {
51
+ if ( preg_match( '/' . $search_value . '/', $key ) ) {
52
+ $search_taxonomy[ $key ] = $value;
53
+ }
54
+ }
55
+
56
+ $taxonomy_table = $search_taxonomy;
57
+ }
58
+ // phpcs:enable WordPress.Security.NonceVerification.Recommended
59
+
60
+ $total_taxonomies = count( $taxonomy_table );
61
+
62
+ wp_cache_set( 'total_taxonomies_result', $total_taxonomies, 'custom_permalinks' );
63
+ }
64
+
65
+ return $total_taxonomies;
66
+ }
67
+
68
+ /**
69
+ * Retrieve permalink's data from the database.
70
+ *
71
+ * @since 2.0.0
72
+ * @access public
73
+ *
74
+ * @param int $per_page Maximum Results needs to be shown on the page.
75
+ * @param int $page_number Current page.
76
+ *
77
+ * @return array Title, Post Type and Permalink set using this plugin.
78
+ */
79
+ public static function get_permalinks( $per_page = 20, $page_number = 1 ) {
80
+ $taxonomies = wp_cache_get( 'taxonomies_results', 'custom_permalinks' );
81
+ if ( ! $taxonomies ) {
82
+ $page_offset = ( $page_number - 1 ) * $per_page;
83
+ $taxonomy_table = get_option( 'custom_permalink_table' );
84
+ $all_taxonomies = $taxonomy_table;
85
+ $search_taxonomy = array();
86
+
87
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended
88
+ // Include search in total results.
89
+ if ( isset( $_REQUEST['s'] ) && ! empty( $_REQUEST['s'] ) ) {
90
+ $search_value = ltrim( sanitize_text_field( $_REQUEST['s'] ), '/' );
91
+ $search_value = str_replace( '/', '\/', $search_value );
92
+ foreach ( $taxonomy_table as $key => $value ) {
93
+ if ( preg_match( '/' . $search_value . '/', $key ) ) {
94
+ $search_taxonomy[ $key ] = $value;
95
+ }
96
+ }
97
+
98
+ $all_taxonomies = $search_taxonomy;
99
+ }
100
+ // phpcs:enable WordPress.Security.NonceVerification.Recommended
101
+
102
+ uasort( $all_taxonomies, array( 'Custom_Permalinks_Taxonomies', 'sort_array' ) );
103
+ $pager_limit = -1;
104
+ $skip_count = -1;
105
+ $taxonomies = array();
106
+ foreach ( $all_taxonomies as $permalink => $info ) {
107
+ ++$skip_count;
108
+ if ( $skip_count < $page_offset ) {
109
+ continue;
110
+ }
111
+
112
+ ++$pager_limit;
113
+ if ( $pager_limit >= $per_page ) {
114
+ break;
115
+ }
116
+
117
+ $taxonomies[] = array(
118
+ 'ID' => $info['id'],
119
+ 'permalink' => $permalink,
120
+ 'type' => $info['kind'],
121
+ );
122
+ }
123
+
124
+ wp_cache_set( 'taxonomies_results', $taxonomies, 'custom_permalinks' );
125
+ }
126
+
127
+ return $taxonomies;
128
+ }
129
  }
admin/class-custom-permalinks-updates.php CHANGED
@@ -1,67 +1,69 @@
1
  <?php
2
  /**
 
 
3
  * @package CustomPermalinks
4
  */
5
 
6
- class Custom_Permalinks_Updates
7
- {
8
-
9
- /*
10
- * Check Whether Plugin gets activated or deactived.
11
- */
12
- private $method = 'install';
13
-
14
- /**
15
- * Initializes WordPress hooks.
16
- */
17
- function __construct( $action )
18
- {
19
- if ( $action && 'deactivate' === $action) {
20
- $this->method = 'uninstall';
21
- }
22
- $this->update_version_details();
23
- }
24
-
25
- /**
26
- * Fetch site details and sent it to CP.
27
- *
28
- * @since 1.6.0
29
- * @access private
30
- */
31
- private function update_version_details()
32
- {
33
- if ( true === function_exists( 'curl_init' ) ) {
34
- $admin_email = get_bloginfo( 'admin_email' );
35
- $curl_url = 'https://www.custompermalinks.com/plugin-update/';
36
- $site_name = get_bloginfo( 'name' );
37
- $site_url = get_bloginfo( 'wpurl' );
38
- $wp_version = get_bloginfo( 'version' );
39
 
40
- $updates = array(
41
- 'action' => $this->method,
42
- 'admin_email' => $admin_email,
43
- 'plugin_version' => CUSTOM_PERMALINKS_PLUGIN_VERSION,
44
- 'site_name' => $site_name,
45
- 'site_url' => $site_url,
46
- 'wp_version' => $wp_version,
47
- );
 
 
48
 
49
- // Create a connection
50
- $curl_conn = curl_init( $curl_url );
 
 
 
 
 
 
 
51
 
52
- // Generate URL-encoded query string
53
- $encoded_data = http_build_query( $updates, '', '&' );
54
 
55
- // Setting options
56
- curl_setopt( $curl_conn, CURLOPT_POST, 1 );
57
- curl_setopt( $curl_conn, CURLOPT_POSTFIELDS, $encoded_data );
58
- curl_setopt( $curl_conn, CURLOPT_RETURNTRANSFER, TRUE );
 
 
 
 
 
 
 
 
 
 
59
 
60
- // Execute the given cURL session
61
- curl_exec( $curl_conn );
 
 
 
 
 
 
62
 
63
- // Closes a cURL session and frees all resources
64
- curl_close( $curl_conn );
65
- }
66
- }
 
 
 
 
 
67
  }
1
  <?php
2
  /**
3
+ * Custom Permalinks Updates.
4
+ *
5
  * @package CustomPermalinks
6
  */
7
 
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
10
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
+ /**
13
+ * Send details(URL, CP version, WP Version etc) to Custom Permalinks.
14
+ */
15
+ class Custom_Permalinks_Updates {
16
+ /**
17
+ * Check Whether Plugin gets activated or deactivated.
18
+ *
19
+ * @var string
20
+ */
21
+ private $method = 'install';
22
 
23
+ /**
24
+ * Call function to send details.
25
+ *
26
+ * @param string $action Whether plugin activating or deactivating.
27
+ */
28
+ public function __construct( $action ) {
29
+ if ( $action && 'deactivate' === $action ) {
30
+ $this->method = 'uninstall';
31
+ }
32
 
33
+ $this->update_version_details();
34
+ }
35
 
36
+ /**
37
+ * Fetch site details and sent it to CP.
38
+ *
39
+ * @since 1.6.0
40
+ * @access private
41
+ *
42
+ * @return void
43
+ */
44
+ private function update_version_details() {
45
+ $admin_email = get_bloginfo( 'admin_email' );
46
+ $request_url = 'https://www.custompermalinks.com/plugin-update/';
47
+ $site_name = get_bloginfo( 'name' );
48
+ $site_url = get_bloginfo( 'wpurl' );
49
+ $wp_version = get_bloginfo( 'version' );
50
 
51
+ $updates = array(
52
+ 'action' => $this->method,
53
+ 'admin_email' => $admin_email,
54
+ 'plugin_version' => CUSTOM_PERMALINKS_VERSION,
55
+ 'site_name' => $site_name,
56
+ 'site_url' => $site_url,
57
+ 'wp_version' => $wp_version,
58
+ );
59
 
60
+ // Performs an HTTP request using the POST method.
61
+ wp_remote_post(
62
+ $request_url,
63
+ array(
64
+ 'method' => 'POST',
65
+ 'body' => $updates,
66
+ )
67
+ );
68
+ }
69
  }
admin/css/about-plugins-1.7.1.min.css → assets/css/about-plugins-2.0.0.min.css RENAMED
@@ -1 +1 @@
1
- .wrap{margin:2em auto 1em;max-width:1090px}.wrap .float{width:calc(100% - 188px);float:left;box-sizing:border-box}.wrap .float:nth-child(2){width:128px;margin:40px 0 70px 50px}.wrap h1{margin:40px auto 20px;font-size:2.5em}.tagline p{font-size:1.3em;margin:0 auto 1em}p a{text-decoration:none}.box>a{display:inline-block;float:right;color:#fff;background:linear-gradient(-35deg,rgba(216,225,231,.8) 12%,#b5c6d0 13%);text-decoration:none;font-size:20px;padding:8px 17px;border-radius:3px;transition:all 250ms ease}.box>a:hover{font-size:22px}#footer-left a{text-decoration:underline}a .star svg polygon{fill:#f9d539}a .star svg:hover polygon{fill:#ff7c00}.product{width:100%;display:inline-block;text-align:center}.product>span{font-size:1.3em;display:block;text-align:left;margin:0 auto 1em}.product h2{display:block;margin:1em auto;font-size:2.2em;text-align:left}.product .box{background-color:#fff;width:300px;min-height:200px;text-align:center;padding:20px;box-shadow:2px 2px 3px #d1d1d1;display:inline-block;margin:10px;vertical-align:top}.product .tagline{text-align:center}.product .img{background:#eee;border-radius:50%;width:150px;height:150px;margin:0 auto}.product .img img,.product .img svg{max-width:70%;margin-top:25px}.product .h3{margin-bottom:5px}.product p{color:#888;font-size:14px;line-height:26px;text-align:left;transition:max-height 450ms .1s ease;margin:1em 0 2em}@media (min-width:746px){.product p{min-height:185px;max-height:135px;overflow:hidden}.product .box:hover p{max-height:300px}}.box.recommended{position:relative;background:#e8ebee}.box.recommended *{position:relative;z-index:2}.box.recommended::before{content:"";position:absolute;width:100%;height:100%;transition:all 350ms ease;z-index:1;right:0;top:0;background:linear-gradient(35deg,#e8ebee 62%,rgba(181,198,208,1) 50%);transform-origin:top right}@keyframes blinking{0%,100%{opacity:.1}25%,75%{opacity:1}}.box.recommended::after{content:"RECOMMENDED";position:absolute;top:41px;right:-11px;color:#fff;font-size:18px;font-weight:700;transform:rotateZ(35deg);font-family:sans-serif;z-index:1;animation:blinking 2s infinite linear}.box.recommended:hover::before{height:175px;width:150px}.box.recommended:hover::after{animation:blinking 2s 1 linear}@media (max-width:991px){.wrap{max-width:725px}}@media (max-width:767px){.wrap{max-width:640px}.product .box{width:258px;min-height:410px}}@media (max-width:650px){.wrap{max-width:460px}.product .box{width:400px;max-width:90%;min-height:inherit;margin-left:0;margin-right:0;box-sizing:border-box}.wrap .float{width:100%}.wrap .float:nth-child(2){margin:40px 0 70px 50px;position:absolute;right:20px}.wrap h1{margin:70px 0 30px;width:300px;line-height:1.2em}}@media (max-width:450px){.wrap h1{margin:0 0 150px;font-size:2em;width:300px}.wrap .float:nth-child(2){right:inherit;margin:80px auto 0;text-align:center}}
1
+ .wrap{margin:2em auto 1em;max-width:1090px}.wrap .float{width:calc(100% - 188px);float:left;box-sizing:border-box}.wrap .float:nth-child(2){width:128px;margin:40px 0 70px 50px}.wrap h1{margin:40px auto 20px;font-size:2.5em}.tagline p{font-size:1.3em;margin:0 auto 1em}p a{text-decoration:none}.box>a{display:inline-block;float:right;color:#fff;background:linear-gradient(-35deg,rgba(216,225,231,.8) 12%,#b5c6d0 13%);text-decoration:none;font-size:20px;padding:8px 17px;border-radius:3px;transition:all 250ms ease}.box>a:hover{font-size:22px}#footer-left a{text-decoration:underline}a .star svg polygon{fill:#f9d539}a .star svg:hover polygon{fill:#ff7c00}.product{width:100%;display:inline-block;text-align:center}.product>span{font-size:1.3em;display:block;text-align:left;margin:0 auto 1em}.product h2{display:block;margin:1em auto;font-size:2.2em;text-align:left}.product .box{background-color:#fff;width:300px;min-height:200px;text-align:center;padding:20px;box-shadow:2px 2px 3px #d1d1d1;display:inline-block;margin:10px;vertical-align:top}.product .tagline{text-align:center}.product .img{background:#eee;border-radius:50%;width:150px;height:150px;margin:0 auto}.product .img img,.product .img svg{max-width:70%;margin-top:25px}.product .h3{margin-bottom:5px}.product p{color:#888;font-size:14px;line-height:26px;text-align:left;transition:max-height 450ms .1s ease;margin:1em 0 2em}@media (min-width:746px){.product p{min-height:185px;max-height:135px;overflow:hidden}.product .box:hover p{max-height:300px}}.box.recommended{position:relative;background:#e8ebee}.box.recommended *{position:relative;z-index:2}.box.recommended::before{content:"";position:absolute;width:100%;height:100%;transition:all 350ms ease;z-index:1;right:0;top:0;background:linear-gradient(35deg,#e8ebee 62%,#b5c6d0 50%);transform-origin:top right}@keyframes blinking{0%,100%{opacity:.1}25%,75%{opacity:1}}.box.recommended::after{content:"RECOMMENDED";position:absolute;top:41px;right:-11px;color:#fff;font-size:18px;font-weight:700;transform:rotateZ(35deg);font-family:sans-serif;z-index:1;animation:blinking 2s infinite linear}.box.recommended:hover::before{height:175px;width:150px}.box.recommended:hover::after{animation:blinking 2s 1 linear}@media (max-width:991px){.wrap{max-width:725px}}@media (max-width:767px){.wrap{max-width:640px}.product .box{width:258px;min-height:410px}}@media (max-width:650px){.wrap{max-width:460px}.product .box{width:400px;max-width:90%;min-height:inherit;margin-left:0;margin-right:0;box-sizing:border-box}.wrap .float{width:100%}.wrap .float:nth-child(2){margin:40px 0 70px 50px;position:absolute;right:20px}.wrap h1{margin:70px 0 30px;width:300px;line-height:1.2}}@media (max-width:450px){.wrap h1{margin:0 0 150px;font-size:2em;width:300px}.wrap .float:nth-child(2){right:inherit;margin:80px auto 0;text-align:center}}
{admin → assets}/images/custom-permalinks.svg RENAMED
File without changes
{admin → assets}/images/http-auth.svg RENAMED
File without changes
{admin → assets}/images/json-structuring-markup.svg RENAMED
File without changes
{admin → assets}/images/make-paths-relative.svg RENAMED
File without changes
{admin → assets}/images/media-post-permalink.png RENAMED
File without changes
{admin → assets}/images/media-post-permalink.svg RENAMED
File without changes
{admin → assets}/images/permalinks-customizer.svg RENAMED
File without changes
{admin → assets}/images/prevent-xss-vulnerability.png RENAMED
File without changes
{admin → assets}/images/prevent-xss-vulnerability.svg RENAMED
File without changes
{admin → assets}/images/remove-links-and-scripts.svg RENAMED
File without changes
{admin → assets}/images/schema-for-article.svg RENAMED
File without changes
assets/js/script-form-2.0.0.min.js ADDED
@@ -0,0 +1 @@
 
1
+ !function(){"use strict";var l="",a="",s=!1;function r(e){e.target&&(e.target.style.color="#000")}function i(e){var t=document.getElementById("original-permalink");e.target&&(document.getElementById("custom_permalink").value=e.target.value,""!==e.target.value&&e.target.value!==t.value||(e.target.value=t.value,e.target.style.color="#ddd"))}function d(){var e,t=document.getElementsByClassName("edit-post-post-link__preview-label"),n=document.getElementById("custom_permalinks_home_url"),o="";l&&wpApiSettings&&wpApiSettings.nonce&&(t&&t[0]&&t[0].parentNode.classList.add("cp-permalink-hidden"),(a=l.isSavingMetaBoxes())===s||a||(e=wp.data.select("core/editor").getEditedPostAttribute("id"),o=new XMLHttpRequest,s=a,o.onreadystatechange=function(){var e,t,n,a;4===o.readyState&&200===o.status&&(e=JSON.parse(o.responseText),t=document.getElementById("custom_permalinks_home_url"),n=document.getElementById("custom-permalinks-add"),a="",document.getElementById("custom_permalink").value=e.custom_permalink,""===e.custom_permalink&&(e.custom_permalink=e.original_permalink),a=e.preview_permalink?t.value+e.preview_permalink:t.value+e.custom_permalink,document.getElementById("custom-permalinks-post-slug").value=e.custom_permalink,document.getElementById("original-permalink").value=e.original_permalink,document.querySelector("#view-post-btn a")&&(document.querySelector("#view-post-btn a").href=a),document.querySelector("a.editor-post-preview")&&(document.querySelector("a.editor-post-preview").href=a),n&&"add"===n.value&&(document.getElementById("custom-permalinks-edit-box").style.display=""),document.querySelector(".components-notice__content a")&&(document.querySelector(".components-notice__content a").href="/"+e.custom_permalink))},o.open("GET",n.value+"wp-json/custom-permalinks/v1/get-permalink/"+e,!0),o.setRequestHeader("Cache-Control","private, max-age=0, no-cache"),o.setRequestHeader("X-WP-NONCE",wpApiSettings.nonce),o.send()),s=a)}function m(){var e=document.getElementsByClassName("edit-post-post-link__preview-label");e&&e[0]&&e[0].parentNode.classList.add("cp-permalink-hidden")}document.addEventListener("DOMContentLoaded",function(){var e=document.getElementsByClassName("edit-post-post-link__preview-label"),t=0,n=document.getElementById("custom-permalinks-edit-box"),a=document.getElementById("custom-permalinks-post-slug"),o="",s=0;if(a&&(a.addEventListener("focus",r),a.addEventListener("blur",i)),n&&""===document.querySelector("#custom-permalinks-edit-box .inside").innerHTML.trim()&&(n.style.display="none"),wp.data)for(a=document.getElementById("custom-permalinks-add"),(o=document.querySelectorAll(".edit-post-sidebar .components-panel__header"))&&o.length&&(s=o.length),a&&"add"===a.value&&(n.style.display="none"),l=wp.data.select("core/edit-post"),wp.data.subscribe(d),e&&e[0]&&e[0].parentNode.classList.add("cp-permalink-hidden"),n.classList.contains("closed")&&n.classList.remove("closed");t<s;)o[t].addEventListener("click",m),t+=1})}();
changelog.txt CHANGED
@@ -2,6 +2,46 @@
2
 
3
  This file contains only old changelog. See readme.txt for newer versions.
4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  = 1.5.1 - Jun 11, 2019 =
6
 
7
  * Bug
2
 
3
  This file contains only old changelog. See readme.txt for newer versions.
4
 
5
+ = 1.7.0 - Aug 20, 2020 =
6
+
7
+ * Bugs
8
+ * [Paged NextGen Galleries Broken with Custom Permalinks 1.62](https://github.com/samiahmedsiddiqui/custom-permalinks/issues/38)
9
+ * [custom permalink issue with weglot](https://wordpress.org/support/topic/custom-permalink-issue-with-weglot/)
10
+ * [Permalinks reverting back to old ones](https://wordpress.org/support/topic/permalinks-reverting-back-to-old-ones/)
11
+ * [A problem with wrongly deleted permalinks](https://wordpress.org/support/topic/a-problem-with-wrongly-deleted-permalinks/)
12
+ * Enhancements
13
+ * [Enhanced security through characters restriction](https://github.com/samiahmedsiddiqui/custom-permalinks#unsupported-characters)
14
+ * Introduce filter to disable specific redirect(s) or complete functionality
15
+ * Automatic replacement of upper case letters to lower case
16
+
17
+ = 1.6.2 - Aug 10, 2020 =
18
+
19
+ * Bugs
20
+ * Forgot to update the version in CSS and JS files in `v1.6.1`
21
+
22
+ = 1.6.1 - Aug 10, 2020 =
23
+
24
+ * Bugs
25
+ * Avoid caching issue by adding version as suffix in CSS and JS files
26
+
27
+ = 1.6.0 - Aug 08, 2020 =
28
+
29
+ * Bugs
30
+ * [Undefined index and undefined variable error](https://github.com/samiahmedsiddiqui/custom-permalinks/issues/28)
31
+ * [count(): Parameter must be an array or an object](https://github.com/samiahmedsiddiqui/custom-permalinks/issues/27)
32
+ * Fix double slash from the permalink form
33
+ * [use 'view_item' label for previewing custom post types](https://github.com/samiahmedsiddiqui/custom-permalinks/issues/31)
34
+ * [Fix PHP 7.4 issues](https://github.com/samiahmedsiddiqui/custom-permalinks/issues/32)
35
+ * Fix Yoast Canonical double slash issue
36
+ * [Replacing category_link with term_link](https://github.com/samiahmedsiddiqui/custom-permalinks/issues/34)
37
+ * [Bug with WPML and Use directory for default language](https://github.com/samiahmedsiddiqui/custom-permalinks/issues/36)
38
+ * Fix Static Homepage redirect issue
39
+ * Enhancements
40
+ * Improved Gutenberg Support
41
+ * Added compatibility for WPML language switcher
42
+ * Add filter to exclude Custom Permalinks for certain posts (based on Post IDs, template, etc)
43
+ * Optimized Code
44
+
45
  = 1.5.1 - Jun 11, 2019 =
46
 
47
  * Bug
custom-permalinks.php CHANGED
@@ -1,12 +1,15 @@
1
  <?php
2
  /**
3
  * Plugin Name: Custom Permalinks
4
- * Plugin URI: https://wordpress.org/plugins/custom-permalinks/
5
- * Description: Set custom permalinks on a per-post basis
6
- * Version: 1.7.1
 
 
7
  * Author: Sami Ahmed Siddiqui
8
- * Author URI: https://www.custompermalinks.com/
9
  * License: GPLv3
 
10
  *
11
  * Text Domain: custom-permalinks
12
  * Domain Path: /languages/
@@ -16,7 +19,7 @@
16
 
17
  /**
18
  * Custom Permalinks - Update Permalinks of Post/Pages and Categories
19
- * Copyright 2008-2020 Sami Ahmed Siddiqui <sami.siddiqui@yasglobal.com>
20
  *
21
  * This program is free software: you can redistribute it and/or modify
22
  * it under the terms of the GNU General Public License as published by
@@ -32,164 +35,13 @@
32
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
33
  */
34
 
35
- // Make sure we don't expose any info if called directly
36
  if ( ! defined( 'ABSPATH' ) ) {
37
- echo 'Hi there! I\'m just a plugin, not much I can do when called directly.';
38
- exit;
39
  }
40
 
41
- class Custom_Permalinks
42
- {
43
-
44
- /**
45
- * Class constructor.
46
- */
47
- public function __construct()
48
- {
49
- if ( ! defined( 'CUSTOM_PERMALINKS_FILE' ) ) {
50
- define( 'CUSTOM_PERMALINKS_FILE', __FILE__ );
51
- }
52
-
53
- if ( ! defined( 'CUSTOM_PERMALINKS_PLUGIN_VERSION' ) ) {
54
- define( 'CUSTOM_PERMALINKS_PLUGIN_VERSION', '1.7.1' );
55
- }
56
-
57
- if ( ! defined( 'CUSTOM_PERMALINKS_PATH' ) ) {
58
- define( 'CUSTOM_PERMALINKS_PATH', plugin_dir_path( __FILE__ ) );
59
- }
60
-
61
- if ( ! defined( 'CUSTOM_PERMALINKS_BASENAME' ) ) {
62
- define( 'CUSTOM_PERMALINKS_BASENAME', plugin_basename( __FILE__ ) );
63
- }
64
-
65
- $this->includes();
66
-
67
- add_action( 'plugins_loaded', array( $this, 'check_loaded_plugins' ) );
68
- }
69
-
70
- /**
71
- * Include required files.
72
- *
73
- * @since 1.2.18
74
- * @access private
75
- */
76
- private function includes()
77
- {
78
- $cp_files_path = array(
79
- 'admin' => CUSTOM_PERMALINKS_PATH . 'admin/class-custom-permalinks-admin.php',
80
- 'form' => CUSTOM_PERMALINKS_PATH . 'frontend/class-custom-permalinks-form.php',
81
- 'frontend' => CUSTOM_PERMALINKS_PATH . 'frontend/class-custom-permalinks-frontend.php',
82
- );
83
-
84
- require_once $cp_files_path['frontend'];
85
- require_once $cp_files_path['form'];
86
-
87
- $cp_frontend = new Custom_Permalinks_Frontend();
88
- $cp_frontend->init();
89
-
90
- $cp_form = new Custom_Permalinks_Form();
91
- $cp_form->init();
92
-
93
- if ( is_admin() ) {
94
- include_once $cp_files_path['admin'];
95
- new Custom_Permalinks_Admin();
96
-
97
- register_activation_hook( CUSTOM_PERMALINKS_FILE,
98
- array( 'Custom_Permalinks', 'add_roles' )
99
- );
100
-
101
- register_activation_hook( CUSTOM_PERMALINKS_FILE,
102
- array( 'Custom_Permalinks', 'activate_details' )
103
- );
104
-
105
- register_deactivation_hook( CUSTOM_PERMALINKS_FILE,
106
- array( 'Custom_Permalinks', 'deactivate_details' )
107
- );
108
- }
109
- }
110
-
111
- /**
112
- * Add role for the view post and category permalinks and by default assign
113
- * it to the administrator if administrator role exist.
114
- *
115
- * @since 1.2.22
116
- * @access public
117
- */
118
- public static function add_roles()
119
- {
120
- $admin_role = get_role( 'administrator' );
121
- $cp_role = get_role( 'custom_permalinks_manager' );
122
- $current_version = get_option( 'custom_permalinks_plugin_version', -1 );
123
-
124
- if ( ! empty( $admin_role ) ) {
125
- $admin_role->add_cap( 'cp_view_post_permalinks' );
126
- $admin_role->add_cap( 'cp_view_category_permalinks' );
127
- }
128
-
129
- if ( empty( $cp_role ) ) {
130
- add_role( 'custom_permalinks_manager', __( 'Custom Permalinks Manager' ),
131
- array(
132
- 'cp_view_post_permalinks' => true,
133
- 'cp_view_category_permalinks' => true
134
- )
135
- );
136
- }
137
- }
138
-
139
- /**
140
- * Sent details when plugin gets activated / updated ans set installed
141
- * version in options table.
142
- *
143
- * @since 1.6.1
144
- * @access public
145
- */
146
- public static function activate_details()
147
- {
148
- require_once CUSTOM_PERMALINKS_PATH . 'admin/class-custom-permalinks-updates.php';
149
- new Custom_Permalinks_Updates( 'activate' );
150
-
151
- update_option( 'custom_permalinks_plugin_version',
152
- CUSTOM_PERMALINKS_PLUGIN_VERSION
153
- );
154
- }
155
-
156
- /**
157
- * Sent details when plugin gets deactivated.
158
- *
159
- * @since 1.6.1
160
- * @access public
161
- */
162
- public function deactivate_details()
163
- {
164
- require_once CUSTOM_PERMALINKS_PATH . 'admin/class-custom-permalinks-updates.php';
165
- new Custom_Permalinks_Updates( 'deactivate' );
166
- }
167
-
168
- /**
169
- * Check if role not exist then call the function to add it. Update site
170
- * details if plugin gets updated. Also, loads the plugin language files to
171
- * support different languages.
172
- *
173
- * @since 1.2.18
174
- * @access public
175
- */
176
- public function check_loaded_plugins()
177
- {
178
- if ( is_admin() ) {
179
- $current_version = get_option( 'custom_permalinks_plugin_version', -1 );
180
-
181
- if ( -1 === $current_version
182
- || $current_version < CUSTOM_PERMALINKS_PLUGIN_VERSION
183
- ) {
184
- Custom_Permalinks::activate_details();
185
- Custom_Permalinks::add_roles();
186
- }
187
- }
188
-
189
- load_plugin_textdomain( 'custom-permalinks', FALSE,
190
- basename( dirname( CUSTOM_PERMALINKS_FILE ) ) . '/languages/'
191
- );
192
- }
193
  }
194
 
195
- new Custom_Permalinks();
 
1
  <?php
2
  /**
3
  * Plugin Name: Custom Permalinks
4
+ * Plugin URI: https://www.custompermalinks.com/
5
+ * Description: Set custom permalinks on a per-post basis.
6
+ * Version: 2.0.0
7
+ * Requires at least: 2.6
8
+ * Requires PHP: 5.4
9
  * Author: Sami Ahmed Siddiqui
10
+ * Author URI: https://www.linkedin.com/in/sami-ahmed-siddiqui/
11
  * License: GPLv3
12
+ * License URI: https://www.gnu.org/licenses/gpl-3.0.html
13
  *
14
  * Text Domain: custom-permalinks
15
  * Domain Path: /languages/
19
 
20
  /**
21
  * Custom Permalinks - Update Permalinks of Post/Pages and Categories
22
+ * Copyright 2008-2021 Sami Ahmed Siddiqui <sami.siddiqui@yasglobal.com>
23
  *
24
  * This program is free software: you can redistribute it and/or modify
25
  * it under the terms of the GNU General Public License as published by
35
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
36
  */
37
 
 
38
  if ( ! defined( 'ABSPATH' ) ) {
39
+ exit;
 
40
  }
41
 
42
+ if ( ! defined( 'CUSTOM_PERMALINKS_FILE' ) ) {
43
+ define( 'CUSTOM_PERMALINKS_FILE', __FILE__ );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  }
45
 
46
+ // Include the main Custom Permalinks class.
47
+ require_once plugin_dir_path( CUSTOM_PERMALINKS_FILE ) . 'includes/class-custom-permalinks.php';
frontend/class-custom-permalinks-form.php DELETED
@@ -1,732 +0,0 @@
1
- <?php
2
- /**
3
- * @package CustomPermalinks
4
- */
5
-
6
- class Custom_Permalinks_Form
7
- {
8
-
9
- /*
10
- * JS file suffix (version number with with extension)
11
- */
12
- private $js_file_suffix = '-' . CUSTOM_PERMALINKS_PLUGIN_VERSION . '.min.js';
13
-
14
- /*
15
- * Decide whether to show metabox or override WordPress default Permalink box.
16
- */
17
- private $permalink_metabox = 0;
18
-
19
- /**
20
- * Initialize WordPress Hooks.
21
- *
22
- * @since 1.2.0
23
- * @access public
24
- */
25
- public function init()
26
- {
27
- add_action( 'add_meta_boxes', array( $this, 'permalink_edit_box' ) );
28
- add_action( 'save_post', array( $this, 'save_post' ), 10, 3 );
29
- add_action( 'delete_post', array( $this, 'delete_permalink' ), 10 );
30
- add_action( 'category_add_form', array( $this, 'term_options' ) );
31
- add_action( 'category_edit_form', array( $this, 'term_options' ) );
32
- add_action( 'post_tag_add_form', array( $this, 'term_options' ) );
33
- add_action( 'post_tag_edit_form', array( $this, 'term_options' ) );
34
- add_action( 'created_term', array( $this, 'save_term' ), 10, 3 );
35
- add_action( 'edited_term', array( $this, 'save_term' ), 10, 3 );
36
- add_action( 'delete_term', array( $this, 'delete_term_permalink' ), 10, 3 );
37
- add_action( 'rest_api_init', array( $this, 'rest_edit_form' ) );
38
- add_action( 'update_option_page_on_front',
39
- array( $this, 'static_homepage' ), 10, 2
40
- );
41
-
42
- add_filter( 'get_sample_permalink_html',
43
- array( $this, 'sample_permalink_html' ), 10, 2
44
- );
45
- add_filter( 'is_protected_meta', array( $this, 'protect_meta' ), 10, 2 );
46
- }
47
-
48
- /**
49
- * Initialize WordPress Hooks.
50
- *
51
- * @since 1.6.0
52
- * @access private
53
- *
54
- * @param object $post WP Post Object.
55
- *
56
- * return bool false Whether to show Custom Permalink form or not.
57
- */
58
- private function exclude_custom_permalinks( $post )
59
- {
60
- $args = array(
61
- 'public' => true,
62
- );
63
- $exclude_post_types = apply_filters( 'custom_permalinks_exclude_post_type',
64
- $post->post_type
65
- );
66
- /*
67
- * Exclude custom permalink `form` from any post(s) if filter returns `true`.
68
- *
69
- * @since 1.6.0
70
- */
71
- $exclude_posts = apply_filters( 'custom_permalinks_exclude_posts',
72
- $post
73
- );
74
- $public_post_types = get_post_types( $args, 'objects' );
75
-
76
- if ( isset( $this->permalink_metabox ) && 1 === $this->permalink_metabox ) {
77
- $check_availability = true;
78
- } elseif ( 'attachment' === $post->post_type ) {
79
- $check_availability = true;
80
- } elseif ( $post->ID == get_option( 'page_on_front' ) ) {
81
- $check_availability = true;
82
- } elseif ( ! isset( $public_post_types[$post->post_type] ) ) {
83
- $check_availability = true;
84
- } elseif ( '__true' === $exclude_post_types ) {
85
- $check_availability = true;
86
- } elseif ( is_bool( $exclude_posts ) && $exclude_posts ) {
87
- $check_availability = true;
88
- } else {
89
- $check_availability = false;
90
- }
91
-
92
- return $check_availability;
93
- }
94
-
95
- /**
96
- * Register meta box(es).
97
- *
98
- * @since 1.4.0
99
- * @access public
100
- */
101
- public function permalink_edit_box()
102
- {
103
- add_meta_box( 'custom-permalinks-edit-box',
104
- __( 'Custom Permalinks', 'custom-permalinks' ),
105
- array( $this, 'meta_edit_form' ), null, 'normal', 'high',
106
- array(
107
- '__back_compat_meta_box' => false,
108
- )
109
- );
110
- }
111
-
112
- /**
113
- * Set the meta_keys to protected which is created by the plugin.
114
- *
115
- * @since 1.4.0
116
- * @access public
117
- *
118
- * @param bool $protected Whether the key is protected or not.
119
- * @param string $meta_key Meta key.
120
- *
121
- * @return bool `true` for the custom_permalink key.
122
- */
123
- public function protect_meta( $protected, $meta_key )
124
- {
125
- if ( 'custom_permalink' === $meta_key ) {
126
- $protected = true;
127
- }
128
-
129
- return $protected;
130
- }
131
-
132
- /**
133
- * Save per-post options.
134
- *
135
- * @access public
136
- *
137
- * @param int $post_id Post ID.
138
- */
139
- public function save_post( $post_id )
140
- {
141
- if ( ! isset( $_REQUEST['custom_permalinks_edit'] ) ) {
142
- return;
143
- }
144
-
145
- $cp_frontend = new Custom_Permalinks_Frontend();
146
- $original_link = $cp_frontend->original_post_link( $post_id );
147
-
148
- if ( isset( $_REQUEST['custom_permalink'] )
149
- && $_REQUEST['custom_permalink'] != $original_link
150
- ) {
151
- $reserved_chars = array(
152
- '(',
153
- ')',
154
- '[',
155
- ']',
156
- );
157
-
158
- $unsafe_chars = array(
159
- '<',
160
- '>',
161
- '{',
162
- '}',
163
- '|',
164
- '`',
165
- '^',
166
- '\\',
167
- );
168
-
169
- $permalink = $_REQUEST['custom_permalink'];
170
- $permalink = ltrim( $permalink, '/' );
171
- $permalink = strtolower( $permalink );
172
- $permalink = str_replace( $reserved_chars, '', $permalink );
173
- $permalink = str_replace( $unsafe_chars, '', $permalink );
174
- $permalink = urlencode( $permalink );
175
- // Replace encoded slash input with slash
176
- $permalink = str_replace( '%2F', '/', $permalink );
177
-
178
- $replace_hyphen = array( '%20', '%2B', '+' );
179
- $split_path = explode( '%3F', $permalink );
180
- if ( 1 < count( $split_path ) ) {
181
- // Replace encoded space and plus input with hyphen
182
- $replaced_path = str_replace( $replace_hyphen, '-', $split_path[0] );
183
- $replaced_path = preg_replace( '/(\-+)/', '-', $replaced_path );
184
- $permalink = str_replace( $split_path[0], $replaced_path,
185
- $permalink
186
- );
187
- } else {
188
- // Replace encoded space and plus input with hyphen
189
- $permalink = str_replace( $replace_hyphen, '-', $permalink );
190
- $permalink = preg_replace( '/(\-+)/', '-', $permalink );
191
- }
192
-
193
- update_post_meta( $post_id, 'custom_permalink', $permalink );
194
- }
195
- }
196
-
197
- /**
198
- * Delete Post Permalink.
199
- *
200
- * @access public
201
- *
202
- * @param int $post_id Post ID.
203
- */
204
- public function delete_permalink( $post_id )
205
- {
206
- delete_metadata( 'post', $post_id, 'custom_permalink' );
207
- }
208
-
209
- /**
210
- * Result Permalink HTML Form for classic editor and Gutenberg.
211
- *
212
- * @since 1.6.0
213
- * @access private
214
- *
215
- * @param object $post WP Post Object.
216
- * @param bool $meta_box Show whether calls from clasic WordPress or Gutenberg.
217
- *
218
- * @return string Permalink Form HTML.
219
- */
220
- private function get_permalink_html( $post, $meta_box = false )
221
- {
222
- $post_id = $post->ID;
223
- $permalink = get_post_meta( $post_id, 'custom_permalink', true );
224
-
225
- ob_start();
226
-
227
- $cp_frontend = new Custom_Permalinks_Frontend();
228
- if ( 'page' === $post->post_type ) {
229
- $original_permalink = $cp_frontend->original_page_link( $post_id );
230
- $view_post = __( 'View Page', 'custom-permalinks' );
231
- } else {
232
- $post_type_name = '';
233
- $post_type_object = get_post_type_object( $post->post_type );
234
- if ( is_object($post_type_object) && isset( $post_type_object->labels )
235
- && isset( $post_type_object->labels->singular_name )
236
- ) {
237
- $post_type_name = ' ' . $post_type_object->labels->singular_name;
238
- } elseif ( is_object($post_type_object)
239
- && isset( $post_type_object->label )
240
- ) {
241
- $post_type_name = ' ' . $post_type_object->label;
242
- }
243
-
244
- $original_permalink = $cp_frontend->original_post_link( $post_id );
245
- $view_post = __( 'View', 'custom-permalinks' ) . $post_type_name;
246
- }
247
- $this->get_permalink_form( $permalink, $original_permalink, false,
248
- $post->post_name
249
- );
250
-
251
- $content = ob_get_contents();
252
- ob_end_clean();
253
-
254
- if ( 'trash' !== $post->post_status ) {
255
- wp_enqueue_script( 'custom-permalinks-form',
256
- plugins_url( '/js/script-form' . $this->js_file_suffix, __FILE__ ),
257
- array(), false, true
258
- );
259
-
260
- $home_url = trailingslashit( home_url() );
261
- if ( isset( $permalink ) && ! empty( $permalink ) ) {
262
- $view_post_link = $home_url . $permalink;
263
- } else {
264
- if ( 'draft' === $post->post_status ) {
265
- $view_post = 'Preview';
266
- $view_post_link = $home_url . '?';
267
- if ( 'page' === $post->post_type ) {
268
- $view_post_link .= 'page_id';
269
- } elseif ( 'post' === $post->post_type ) {
270
- $view_post_link .= 'p';
271
- } else {
272
- $view_post_link .= 'post_type=' . $post->post_type . '&p';
273
- }
274
- $view_post_link .= '=' . $post_id . '&preview=true';
275
- } else {
276
- $view_post_link = $home_url . $original_permalink;
277
- }
278
- }
279
-
280
- $content .= ' <span id="view-post-btn">' .
281
- '<a href="' . $view_post_link . '" class="button button-medium" target="_blank">' . $view_post .'</a>' .
282
- '</span><br>';
283
- if ( true === $meta_box ) {
284
- $content .= '<style>.editor-post-permalink,.cp-permalink-hidden{display:none;}</style>';
285
- }
286
- }
287
-
288
- return '<strong>' . __( 'Permalink:', 'custom-permalinks' ) . '</strong> ' . $content;
289
- }
290
-
291
- /**
292
- * Per-post/page options (Wordpress > 2.9).
293
- *
294
- * @access public
295
- *
296
- * @param string $html WP Post Permalink HTML.
297
- * @param int $post_id Post ID.
298
- *
299
- * @return string Edit Form string.
300
- */
301
- public function sample_permalink_html( $html, $post_id )
302
- {
303
- $post = get_post( $post_id );
304
-
305
- $disable_cp = $this->exclude_custom_permalinks( $post );
306
- $this->permalink_metabox = 1;
307
- if ( $disable_cp ) {
308
- return $html;
309
- }
310
-
311
- $output_content = $this->get_permalink_html( $post );
312
-
313
- return $output_content;
314
- }
315
-
316
- /**
317
- * Adds the Permalink Edit Meta box for the user with validating the
318
- * PostTypes to make compatibility with Gutenberg.
319
- *
320
- * @access public
321
- *
322
- * @param object $post WP Post Object.
323
- */
324
- public function meta_edit_form( $post )
325
- {
326
- $disable_cp = $this->exclude_custom_permalinks( $post );
327
- if ( $disable_cp ) {
328
- wp_enqueue_script( 'custom-permalinks-form',
329
- plugins_url( '/js/script-form' . $this->js_file_suffix, __FILE__ ),
330
- array(), false, true
331
- );
332
-
333
- return;
334
- }
335
-
336
- $screen = get_current_screen();
337
- if ( 'add' === $screen->action ) {
338
- echo '<input value="add" type="hidden" name="custom-permalinks-add" id="custom-permalinks-add" />';
339
- }
340
-
341
- $output_content = $this->get_permalink_html( $post, true );
342
-
343
- echo $output_content;
344
- }
345
-
346
- /**
347
- * Per-post options (Wordpress < 2.9).
348
- *
349
- * @access public
350
- */
351
- public function post_options()
352
- {
353
- global $post;
354
-
355
- if ( is_object( $post ) ) {
356
- $post_id = $post->ID;
357
- } else {
358
- $post_id = $post;
359
- }
360
-
361
- $permalink = get_post_meta( $post_id, 'custom_permalink', true );
362
- ?>
363
- <div class="postbox closed">
364
- <h3>
365
- <?php
366
- esc_html_e( 'Custom Permalink', 'custom-permalinks' );
367
- ?>
368
- </h3>
369
-
370
- <div class="inside">
371
- <?php
372
- $cp_frontend = new Custom_Permalinks_Frontend();
373
- $this->get_permalink_form( $permalink,
374
- $cp_frontend->original_post_link( $post_id )
375
- );
376
- ?>
377
- </div>
378
- </div>
379
- <?php
380
- }
381
-
382
- /**
383
- * Per-page options (Wordpress < 2.9).
384
- *
385
- * @access public
386
- */
387
- public function page_options()
388
- {
389
- global $post;
390
-
391
- if ( is_object( $post ) ) {
392
- $post_id = $post->ID;
393
- } else {
394
- $post_id = $post;
395
- }
396
-
397
- $permalink = get_post_meta( $post_id, 'custom_permalink', true );
398
- ?>
399
- <div class="postbox closed">
400
- <h3>
401
- <?php
402
- esc_html_e( 'Custom Permalink', 'custom-permalinks' );
403
- ?>
404
- </h3>
405
- <div class="inside">
406
- <?php
407
- $cp_frontend = new Custom_Permalinks_Frontend();
408
- $page_permalink = $cp_frontend->original_page_link( $post_id );
409
- $this->get_permalink_form( $permalink, $page_permalink );
410
- ?>
411
- </div>
412
- </div>
413
- <?php
414
- }
415
-
416
- /**
417
- * Per-category/tag options.
418
- *
419
- * @access public
420
- *
421
- * @param object $object Term Object.
422
- */
423
- public function term_options( $object )
424
- {
425
- $permalink = '';
426
- $original_permalink = '';
427
- if ( is_object( $object ) && isset( $object->term_id ) ) {
428
- $cp_frontend = new Custom_Permalinks_Frontend();
429
- if ( $object->term_id ) {
430
- $permalink = $cp_frontend->term_permalink( $object->term_id );
431
- $original_permalink = $cp_frontend->original_term_link(
432
- $object->term_id
433
- );
434
- }
435
- }
436
-
437
- $this->get_permalink_form( $permalink, $original_permalink );
438
-
439
- // Move the save button to above this form
440
- wp_enqueue_script( 'jquery' );
441
- ?>
442
- <script type="text/javascript">
443
- jQuery(document).ready(function() {
444
- var button = jQuery('#custom_permalink_form').parent().find('.submit');
445
- button.remove().insertAfter(jQuery('#custom_permalink_form'));
446
- });
447
- </script>
448
- <?php
449
- }
450
-
451
- /**
452
- * Helper function to render form.
453
- *
454
- * @access private
455
- *
456
- * @param string $permalink Permalink which is created by the plugin.
457
- * @param string $original Permalink which set by WordPress.
458
- * @param bool $render_containers Shows Post/Term Edit.
459
- * @param string $postname Post Name.
460
- */
461
- private function get_permalink_form( $permalink, $original = '',
462
- $render_containers = true, $postname = ''
463
- ) {
464
- $encoded_permalink = htmlspecialchars( urldecode( $permalink ) );
465
- $home_url = trailingslashit( home_url() );
466
-
467
- echo '<input value="true" type="hidden" name="custom_permalinks_edit" />' .
468
- '<input value="' . $home_url . '" type="hidden" name="custom_permalinks_home_url" id="custom_permalinks_home_url" />' .
469
- '<input value="' . $encoded_permalink . '" type="hidden" name="custom_permalink" id="custom_permalink" />';
470
-
471
- if ( $render_containers ) {
472
- echo '<table class="form-table" id="custom_permalink_form">' .
473
- '<tr>' .
474
- '<th scope="row">' . __( 'Custom Permalink', 'custom-permalinks' ) . '</th>' .
475
- '<td>';
476
- }
477
- if ( '' === $permalink ) {
478
- $original = $this->check_conflicts( $original );
479
- }
480
-
481
- if ( $permalink ) {
482
- $post_slug = htmlspecialchars( urldecode( $permalink ) );
483
- $original_encoded_url = htmlspecialchars( urldecode( $original ) );
484
- } else {
485
- $post_slug = htmlspecialchars( urldecode( $original ) );
486
- $original_encoded_url = $post_slug;
487
- }
488
-
489
- wp_enqueue_script( 'custom-permalinks-form',
490
- plugins_url( '/js/script-form' . $this->js_file_suffix, __FILE__ ),
491
- array(), false, true
492
- );
493
- $postname_html = '';
494
- if ( isset( $postname ) && '' !== $postname ) {
495
- $postname_html = '<input type="hidden" id="new-post-slug" class="text" value="' . $postname . '" />';
496
- }
497
-
498
- $field_style = 'width: 250px;';
499
- if ( !$permalink ) {
500
- $field_style .= ' color: #ddd;';
501
- }
502
-
503
- echo $home_url .
504
- '<span id="editable-post-name" title="Click to edit this part of the permalink">' .
505
- $postname_html .
506
- '<input type="hidden" id="original-permalink" value="' . $original_encoded_url . '" />' .
507
- '<input type="text" id="custom-permalinks-post-slug" class="text" value="' . $post_slug . '" style="' . $field_style . '" />' .
508
- '</span>';
509
-
510
- if ( $render_containers ) {
511
- echo '<br />' .
512
- '<small>' .
513
- __( 'Leave blank to disable', 'custom-permalinks' ) .
514
- '</small>' .
515
- '</td>' .
516
- '</tr>' .
517
- '</table>';
518
- }
519
- }
520
-
521
- /**
522
- * Save term (common to tags and categories).
523
- *
524
- * @since 1.6.0
525
- * @access public
526
- *
527
- * @param string $term_id Term ID.
528
- */
529
- public function save_term( $term_id )
530
- {
531
- $term = get_term( $term_id );
532
- if ( isset( $_REQUEST['custom_permalink'] ) && isset( $term )
533
- && isset( $term->taxonomy )
534
- ) {
535
- $taxonomy_name = $term->taxonomy;
536
- if ( 'category' === $taxonomy_name
537
- || 'post_tag' === $taxonomy_name
538
- ) {
539
- if ( 'post_tag' === $taxonomy_name ) {
540
- $taxonomy_name = 'tag';
541
- }
542
-
543
- $new_permalink = ltrim(
544
- stripcslashes( $_REQUEST['custom_permalink'] ), '/'
545
- );
546
- if ( empty( $new_permalink ) || '' === $new_permalink ) {
547
- return;
548
- }
549
-
550
- $cp_frontend = new Custom_Permalinks_Frontend();
551
- $old_permalink = $cp_frontend->original_term_link( $term_id );
552
- if ( $new_permalink === $old_permalink ) {
553
- return;
554
- }
555
-
556
- $this->delete_term_permalink( $term_id );
557
-
558
- $permalink = str_replace( '%2F', '/', urlencode( $new_permalink ) );
559
- $table = get_option( 'custom_permalink_table' );
560
-
561
- if ( $permalink ) {
562
- $table[$permalink] = array(
563
- 'id' => $term_id,
564
- 'kind' => $taxonomy_name,
565
- 'slug' => $term->slug,
566
- );
567
- }
568
-
569
- update_option( 'custom_permalink_table', $table );
570
- }
571
- }
572
- }
573
-
574
- /**
575
- * Delete term.
576
- *
577
- * @access public
578
- *
579
- * @param int $term_id Term ID.
580
- */
581
- public function delete_term_permalink( $term_id )
582
- {
583
- $table = get_option( 'custom_permalink_table' );
584
- if ( $table ) {
585
- foreach ( $table as $link => $info ) {
586
- if ( $info['id'] === $term_id ) {
587
- unset( $table[$link] );
588
- break;
589
- }
590
- }
591
- }
592
-
593
- update_option( 'custom_permalink_table', $table );
594
- }
595
-
596
- /**
597
- * Check Conflicts and resolve it (e.g: Polylang) UPDATED for Polylang
598
- * hide_default setting.
599
- *
600
- * @since 1.2.0
601
- * @access public
602
- *
603
- * @return string requested URL by removing the language/ from it if exist.
604
- */
605
- public function check_conflicts( $requested_url = '' )
606
- {
607
- if ( '' === $requested_url ) {
608
- return;
609
- }
610
-
611
- // Check if the Polylang Plugin is installed so, make changes in the URL
612
- if ( defined( 'POLYLANG_VERSION' ) ) {
613
- $polylang_config = get_option( 'polylang' );
614
- if ( 1 === $polylang_config['force_lang'] ) {
615
- if ( false !== strpos( $requested_url, 'language/' ) ) {
616
- $requested_url = str_replace( 'language/', '', $requested_url );
617
- }
618
-
619
- /*
620
- * Check if `hide_default` is `true` and the current language is not
621
- * the default. Otherwise remove the lang code from the url.
622
- */
623
- if ( 1 === $polylang_config['hide_default'] ) {
624
- $current_language = '';
625
- if ( function_exists( 'pll_current_language' ) ) {
626
- // get current language
627
- $current_language = pll_current_language();
628
- }
629
-
630
- // get default language
631
- $default_language = $polylang_config['default_lang'];
632
- if ( $current_language !== $default_language ) {
633
- $remove_lang = ltrim( strstr( $requested_url, '/' ), '/' );
634
- if ( '' != $remove_lang ) {
635
- return $remove_lang;
636
- }
637
- }
638
- } else {
639
- $remove_lang = ltrim( strstr( $requested_url, '/' ), '/' );
640
- if ( '' != $remove_lang ) {
641
- return $remove_lang;
642
- }
643
- }
644
- }
645
- }
646
-
647
- return $requested_url;
648
- }
649
-
650
- /**
651
- * Refresh Permalink using AJAX Call.
652
- *
653
- * @since 1.6.0
654
- * @access public
655
- *
656
- * @param object $data Contains post id with some default REST Values.
657
- */
658
- public function refresh_meta_form( $data )
659
- {
660
- if ( isset( $data['id'] ) && is_numeric( $data['id'] ) ) {
661
- $post = get_post( $data['id'] );
662
- $all_permalinks = array();
663
- $all_permalinks['custom_permalink'] = get_post_meta( $data['id'],
664
- 'custom_permalink', true
665
- );
666
-
667
- if ( ! $all_permalinks['custom_permalink'] ) {
668
- if ( 'draft' === $post->post_status ) {
669
- $view_post_link = '?';
670
- if ( 'page' === $post->post_type ) {
671
- $view_post_link .= 'page_id';
672
- } elseif ( 'post' === $post->post_type ) {
673
- $view_post_link .= 'p';
674
- } else {
675
- $view_post_link .= 'post_type=' . $post->post_type . '&p';
676
- }
677
- $view_post_link .= '=' . $data['id'] . '&preview=true';
678
-
679
- $all_permalinks['preview_permalink'] = $view_post_link;
680
- }
681
- }
682
-
683
- $cp_frontend = new Custom_Permalinks_Frontend;
684
- if ( 'page' === $post->post_type ) {
685
- $all_permalinks['original_permalink'] = $cp_frontend->original_page_link(
686
- $data['id']
687
- );
688
- } else {
689
- $all_permalinks['original_permalink'] = $cp_frontend->original_post_link(
690
- $data['id']
691
- );
692
- }
693
-
694
- echo json_encode( $all_permalinks );
695
- exit;
696
- }
697
- }
698
-
699
- /**
700
- * Added Custom Endpoints for refreshing the permalink.
701
- *
702
- * @since 1.6.0
703
- * @access public
704
- */
705
- public function rest_edit_form()
706
- {
707
- register_rest_route( 'custom-permalinks/v1', '/get-permalink/(?P<id>\d+)',
708
- array(
709
- 'methods' => 'GET',
710
- 'callback' => array( $this, 'refresh_meta_form' ),
711
- 'permission_callback' => function() {
712
- return current_user_can( 'edit_posts' );
713
- },
714
- )
715
- );
716
- }
717
-
718
- /**
719
- * Delete the Permalink for the Page selected as the Static Homepage.
720
- *
721
- * @since 1.6.0
722
- * @access public
723
- *
724
- * @param int $prev_homepage_id Page ID of previously set Front Page.
725
- * @param int $new_homepage_id Page ID of current Front Page.
726
- */
727
- public function static_homepage( $prev_homepage_id, $new_homepage_id ) {
728
- if ( $prev_homepage_id !== $new_homepage_id ) {
729
- $this->delete_permalink( $new_homepage_id );
730
- }
731
- }
732
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
frontend/class-custom-permalinks-frontend.php DELETED
@@ -1,792 +0,0 @@
1
- <?php
2
- /**
3
- * @package CustomPermalinks
4
- */
5
-
6
- class Custom_Permalinks_Frontend
7
- {
8
-
9
- /*
10
- * The query string, if any, via which the page is accessed otherwise empty.
11
- */
12
- private $query_string_uri = '';
13
-
14
- /*
15
- * The URI which is given in order to access this page. Default empty.
16
- */
17
- private $request_uri = '';
18
-
19
- /**
20
- * Initialize WordPress Hooks.
21
- *
22
- * @since 1.2.0
23
- * @access public
24
- */
25
- public function init()
26
- {
27
- if ( isset( $_SERVER['QUERY_STRING'] ) ) {
28
- $this->query_string_uri = $_SERVER['QUERY_STRING'];
29
- }
30
-
31
- if ( isset( $_SERVER['REQUEST_URI'] ) ) {
32
- $this->request_uri = $_SERVER['REQUEST_URI'];
33
- }
34
-
35
- add_action( 'template_redirect', array( $this, 'make_redirect' ), 5 );
36
-
37
- add_filter( 'request', array( $this, 'parse_request' ) );
38
- add_filter( 'post_link', array( $this, 'custom_post_link' ), 10, 2 );
39
- add_filter( 'post_type_link', array( $this, 'custom_post_link' ), 10, 2 );
40
- add_filter( 'page_link', array( $this, 'custom_page_link' ), 10, 2 );
41
- add_filter( 'term_link', array( $this, 'custom_term_link' ), 10, 2 );
42
- add_filter( 'user_trailingslashit', array( $this, 'custom_trailingslash' ) );
43
-
44
- // WPSEO Filters
45
- add_filter( 'wpseo_canonical',
46
- array( $this, 'fix_canonical_double_slash' ), 20, 1
47
- );
48
- }
49
-
50
- /**
51
- * Replace double slash `//` with single slash `/`.
52
- *
53
- * @since 1.6.0
54
- * @access public
55
- *
56
- * @param string $permalink URL in which `//` needs to be replaced with `/`.
57
- *
58
- * @return string URL with single slash.
59
- */
60
- public function remove_double_slash( $permalink = '' )
61
- {
62
- $protocol = '';
63
- if ( 0 === strpos( $permalink, 'http://' )
64
- || 0 === strpos( $permalink, 'https://' )
65
- ) {
66
- $split_protocol = explode( '://', $permalink );
67
- if ( 1 < count( $split_protocol ) ) {
68
- $protocol = $split_protocol[0] . '://';
69
- $permalink = str_replace( $protocol, '', $permalink );
70
- }
71
- }
72
-
73
- $permalink = str_replace( '//', '/', $permalink );
74
- $permalink = $protocol . $permalink;
75
-
76
- return $permalink;
77
- }
78
-
79
- /**
80
- * Use `wpml_permalink` to add language information to permalinks and
81
- * resolve language switcher issue if found.
82
- *
83
- * @since 1.6.0
84
- * @access public
85
- *
86
- * @param string $permalink Custom Permalink.
87
- * @param string $language_code The language to convert the url into.
88
- *
89
- * @return string permalink with language information.
90
- */
91
- public function wpml_permalink_filter( $permalink = '', $language_code )
92
- {
93
- $custom_permalink = $permalink;
94
- $trailing_permalink = trailingslashit( home_url() ) . $custom_permalink;
95
- if ( $language_code ) {
96
- $permalink = apply_filters( 'wpml_permalink', $trailing_permalink,
97
- $language_code
98
- );
99
- $site_url = site_url();
100
- $wpml_href = str_replace( $site_url, '', $permalink );
101
- if ( 0 === strpos( $wpml_href, '//' ) ) {
102
- if ( 0 !== strpos( $wpml_href, '//' . $language_code . '/' ) ) {
103
- $permalink = $site_url . '/' . $language_code . '/' . $custom_permalink;
104
- }
105
- }
106
- } else {
107
- $permalink = apply_filters( 'wpml_permalink', $trailing_permalink );
108
- }
109
-
110
- return $permalink;
111
- }
112
-
113
- /**
114
- * Filter to rewrite the query if we have a matching post.
115
- *
116
- * @since 0.1.0
117
- * @access public
118
- *
119
- * @param string $query Requested URL.
120
- *
121
- * @return string the URL which has to be parsed.
122
- */
123
- public function parse_request( $query )
124
- {
125
- global $wpdb;
126
- global $_CPRegisteredURL;
127
-
128
- if ( isset( $_SERVER['REQUEST_URI'] )
129
- && $_SERVER['REQUEST_URI'] !== $this->request_uri
130
- ) {
131
- $this->request_uri = $_SERVER['REQUEST_URI'];
132
- }
133
-
134
- /*
135
- * First, search for a matching custom permalink, and if found
136
- * generate the corresponding original URL
137
- */
138
- $original_url = NULL;
139
-
140
- // Get request URI, strip parameters and /'s
141
- $url = parse_url( get_bloginfo( 'url' ) );
142
- $url = isset( $url['path'] ) ? $url['path'] : '';
143
- $request = ltrim( substr( $this->request_uri, strlen( $url ) ), '/' );
144
- $pos = strpos( $request, '?' );
145
- if ( $pos ) {
146
- $request = substr( $request, 0, $pos );
147
- }
148
-
149
- if ( ! $request ) {
150
- return $query;
151
- }
152
-
153
- $ignore = apply_filters( 'custom_permalinks_request_ignore', $request );
154
-
155
- if ( '__true' === $ignore ) {
156
- return $query;
157
- }
158
-
159
- if ( defined( 'POLYLANG_VERSION' ) ) {
160
- $cp_file_path = CUSTOM_PERMALINKS_PATH;
161
- $cp_file_path .= 'frontend/class-custom-permalinks-form.php';
162
- include_once $cp_file_path;
163
-
164
- $cp_form = new Custom_Permalinks_Form();
165
- $request = $cp_form->check_conflicts( $request );
166
- }
167
- $request_no_slash = preg_replace( '@/+@','/', trim( $request, '/' ) );
168
-
169
- $sql = $wpdb->prepare( "SELECT p.ID, pm.meta_value, p.post_type, p.post_status " .
170
- " FROM $wpdb->posts AS p INNER JOIN $wpdb->postmeta AS pm ON (pm.post_id = p.ID) " .
171
- " WHERE pm.meta_key = 'custom_permalink' " .
172
- " AND (pm.meta_value = '%s' OR pm.meta_value = '%s') " .
173
- " AND p.post_status != 'trash' AND p.post_type != 'nav_menu_item' " .
174
- " ORDER BY FIELD(post_status,'publish','private','pending','draft','auto-draft','inherit')," .
175
- " FIELD(post_type,'post','page') LIMIT 1", $request_no_slash, $request_no_slash . "/" );
176
-
177
- $posts = $wpdb->get_results( $sql );
178
-
179
- $remove_like_query = apply_filters( 'cp_remove_like_query', '__true' );
180
- if ( ! $posts && '__true' === $remove_like_query ) {
181
- $sql = $wpdb->prepare( "SELECT p.ID, pm.meta_value, p.post_type, p.post_status FROM $wpdb->posts AS p " .
182
- " LEFT JOIN $wpdb->postmeta AS pm ON (p.ID = pm.post_id) WHERE " .
183
- " meta_key = 'custom_permalink' AND meta_value != '' AND " .
184
- " ( LOWER(meta_value) = LEFT(LOWER('%s'), LENGTH(meta_value)) OR " .
185
- " LOWER(meta_value) = LEFT(LOWER('%s'), LENGTH(meta_value)) ) " .
186
- " AND post_status != 'trash' AND post_type != 'nav_menu_item'" .
187
- " ORDER BY LENGTH(meta_value) DESC, " .
188
- " FIELD(post_status,'publish','private','pending','draft','auto-draft','inherit')," .
189
- " FIELD(post_type,'post','page'), p.ID ASC LIMIT 1",
190
- $request_no_slash, $request_no_slash . "/" );
191
-
192
- $posts = $wpdb->get_results( $sql );
193
- }
194
-
195
- if ( $posts ) {
196
- /*
197
- * A post matches our request. Preserve this url for later
198
- * if it's the same as the permalink (no extra stuff).
199
- */
200
- if ( $request_no_slash == trim( $posts[0]->meta_value, '/' ) ) {
201
- $_CPRegisteredURL = $request;
202
- }
203
-
204
- if ( 'draft' === $posts[0]->post_status ) {
205
- if ( 'page' === $posts[0]->post_type ) {
206
- $original_url = '?page_id=' . $posts[0]->ID;
207
- } else {
208
- $original_url = '?post_type=' . $posts[0]->post_type . '&p=' . $posts[0]->ID;
209
- }
210
- } else {
211
- $post_meta = trim( strtolower( $posts[0]->meta_value ), '/' );
212
- if ( 'page' === $posts[0]->post_type ) {
213
- $get_original_url = $this->original_page_link( $posts[0]->ID );
214
- $original_url = preg_replace( '@/+@', '/',
215
- str_replace( $post_meta, $get_original_url,
216
- strtolower( $request_no_slash )
217
- )
218
- );
219
- } else {
220
- $get_original_url = $this->original_post_link( $posts[0]->ID );
221
- $original_url = preg_replace( '@/+@', '/',
222
- str_replace( $post_meta, $get_original_url,
223
- strtolower( $request_no_slash )
224
- )
225
- );
226
- }
227
- }
228
- }
229
-
230
- if ( NULL === $original_url ) {
231
- // See if any terms have a matching permalink
232
- $table = get_option( 'custom_permalink_table' );
233
- if ( ! $table ) {
234
- return $query;
235
- }
236
-
237
- foreach ( array_keys( $table ) as $permalink ) {
238
- if ( $permalink === substr( $request_no_slash, 0, strlen( $permalink ) )
239
- || $permalink === substr( $request_no_slash . '/', 0, strlen( $permalink ) )
240
- ) {
241
- $term = $table[$permalink];
242
-
243
- /*
244
- * Preserve this url for later if it's the same as the
245
- * permalink (no extra stuff)
246
- */
247
- if ( $request_no_slash === trim( $permalink, '/' ) ) {
248
- $_CPRegisteredURL = $request;
249
- }
250
-
251
- $term_link = $this->original_term_link( $term['id'] );
252
- $original_url = str_replace( trim( $permalink, '/' ),
253
- $term_link, trim( $request, '/' )
254
- );
255
- }
256
- }
257
- }
258
-
259
- if ( NULL !== $original_url ) {
260
- $original_url = str_replace( '//', '/', $original_url );
261
-
262
- $pos = strpos( $this->request_uri, '?' );
263
- if ( false !== $pos ) {
264
- $query_vars = substr( $this->request_uri, $pos + 1 );
265
- $original_url .= ( strpos( $original_url, '?' ) === false ? '?' : '&' ) . $query_vars;
266
- }
267
-
268
- /*
269
- * Now we have the original URL, run this back through WP->parse_request,
270
- * in order to parse parameters properly.
271
- * We set $_SERVER variables to fool the function.
272
- */
273
- $_SERVER['REQUEST_URI'] = '/' . ltrim( $original_url, '/' );
274
- $path_info = apply_filters( 'custom_permalinks_path_info', '__false' );
275
- if ( '__false' !== $path_info ) {
276
- $_SERVER['PATH_INFO'] = '/' . ltrim( $original_url, '/' );
277
- }
278
-
279
- $_SERVER['QUERY_STRING'] = '';
280
- $pos = strpos( $original_url, '?' );
281
- if ( false !== $pos ) {
282
- $_SERVER['QUERY_STRING'] = substr( $original_url, $pos + 1 );
283
- }
284
-
285
- parse_str( $_SERVER['QUERY_STRING'], $query_array );
286
- $old_values = array();
287
- if ( is_array( $query_array ) ) {
288
- foreach ( $query_array as $key => $value ) {
289
- $old_values[$key] = '';
290
- if ( isset( $_REQUEST[$key] ) ) {
291
- $old_values[$key] = $_REQUEST[$key];
292
- }
293
- $_REQUEST[$key] = $_GET[$key] = $value;
294
- }
295
- }
296
-
297
- // Re-run the filter, now with original environment in place
298
- remove_filter( 'request', array( $this, 'parse_request' ) );
299
- global $wp;
300
- if ( isset( $wp->matched_rule ) ) {
301
- $wp->matched_rule = NULL;
302
- }
303
- $wp->parse_request();
304
- $query = $wp->query_vars;
305
- add_filter( 'request', array( $this, 'parse_request' ) );
306
-
307
- // Restore values
308
- $_SERVER['REQUEST_URI'] = $this->request_uri;
309
- $_SERVER['QUERY_STRING'] = $this->query_string_uri;
310
- foreach ( $old_values as $key => $value ) {
311
- $_REQUEST[$key] = $value;
312
- }
313
- }
314
-
315
- return $query;
316
- }
317
-
318
- /**
319
- * Action to redirect to the custom permalink.
320
- *
321
- * @since 0.1.0
322
- * @access public
323
- */
324
- public function make_redirect()
325
- {
326
- global $wpdb;
327
-
328
- if ( isset( $_SERVER['REQUEST_URI'] )
329
- && $_SERVER['REQUEST_URI'] !== $this->request_uri
330
- ) {
331
- $this->request_uri = $_SERVER['REQUEST_URI'];
332
- }
333
-
334
- $custom_permalink = '';
335
- $original_permalink = '';
336
-
337
- // Get request URI, strip parameters
338
- $url = parse_url( get_bloginfo( 'url' ) );
339
- $url = isset( $url['path'] ) ? $url['path'] : '';
340
- $request = ltrim( substr( $this->request_uri, strlen( $url ) ), '/' );
341
- $pos = strpos( $request, '?' );
342
- if ( $pos ) {
343
- $request = substr( $request, 0, $pos );
344
- }
345
-
346
- /*
347
- * Disable redirects to be processed if filter returns `true`.
348
- *
349
- * @since 1.7.0
350
- */
351
- $avoid_redirect = apply_filters( 'custom_permalinks_avoid_redirect',
352
- $request
353
- );
354
-
355
- if ( is_bool( $avoid_redirect ) && $avoid_redirect ) {
356
- return;
357
- }
358
-
359
- if ( defined( 'POLYLANG_VERSION' ) ) {
360
- $cp_file_path = CUSTOM_PERMALINKS_PATH;
361
- $cp_file_path .= 'frontend/class-custom-permalinks-form.php';
362
- include_once $cp_file_path;
363
-
364
- $cp_form = new Custom_Permalinks_Form();
365
- $request = $cp_form->check_conflicts( $request );
366
- }
367
- $request_no_slash = preg_replace( '@/+@','/', trim( $request, '/' ) );
368
-
369
- $sql = $wpdb->prepare( "SELECT p.ID, pm.meta_value, p.post_type, p.post_status " .
370
- " FROM $wpdb->posts AS p INNER JOIN $wpdb->postmeta AS pm ON (pm.post_id = p.ID) " .
371
- " WHERE pm.meta_key = 'custom_permalink' " .
372
- " AND (pm.meta_value = '%s' OR pm.meta_value = '%s') " .
373
- " AND p.post_status != 'trash' AND p.post_type != 'nav_menu_item' " .
374
- " ORDER BY FIELD(post_status,'publish','private','draft','auto-draft','inherit')," .
375
- " FIELD(post_type,'post','page') LIMIT 1", $request_no_slash, $request_no_slash . "/" );
376
-
377
- $posts = $wpdb->get_results( $sql );
378
-
379
- $remove_like_query = apply_filters( 'cp_remove_like_query', '__true' );
380
- if ( ! $posts && '__false' !== $remove_like_query ) {
381
- $sql = $wpdb->prepare( "SELECT p.ID, pm.meta_value, p.post_type, p.post_status FROM $wpdb->posts AS p " .
382
- " LEFT JOIN $wpdb->postmeta AS pm ON (p.ID = pm.post_id) WHERE " .
383
- " meta_key = 'custom_permalink' AND meta_value != '' AND " .
384
- " ( LOWER(meta_value) = LEFT(LOWER('%s'), LENGTH(meta_value)) OR " .
385
- " LOWER(meta_value) = LEFT(LOWER('%s'), LENGTH(meta_value)) ) " .
386
- " AND post_status != 'trash' AND post_type != 'nav_menu_item'" .
387
- " ORDER BY LENGTH(meta_value) DESC, " .
388
- " FIELD(post_status,'publish','private','draft','auto-draft','inherit')," .
389
- " FIELD(post_type,'post','page'), p.ID ASC LIMIT 1",
390
- $request_no_slash, $request_no_slash . "/" );
391
-
392
- $posts = $wpdb->get_results( $sql );
393
- }
394
-
395
- if ( ! isset( $posts[0]->ID ) || ! isset( $posts[0]->meta_value )
396
- || empty( $posts[0]->meta_value )
397
- ) {
398
- global $wp_query;
399
-
400
- /*
401
- * If the post/tag/category we're on has a custom permalink, get it
402
- * and check against the request.
403
- */
404
- if ( ( is_single() || is_page() ) && ! empty( $wp_query->post ) ) {
405
- $post = $wp_query->post;
406
- $custom_permalink = get_post_meta( $post->ID,
407
- 'custom_permalink', true
408
- );
409
- if ( 'page' === $post->post_type ) {
410
- $original_permalink = $this->original_page_link( $post->ID );
411
- } else {
412
- $original_permalink = $this->original_post_link( $post->ID );
413
- }
414
- } elseif ( is_tag() || is_category() ) {
415
- $the_term = $wp_query->get_queried_object();
416
- $custom_permalink = $this->term_permalink( $the_term->term_id );
417
- $original_permalink = $this->original_term_link( $the_term->term_id );
418
- }
419
- } else {
420
- $custom_permalink = $posts[0]->meta_value;
421
- if ( 'page' === $posts[0]->post_type ) {
422
- $original_permalink = $this->original_page_link( $posts[0]->ID );
423
- } else {
424
- $original_permalink = $this->original_post_link( $posts[0]->ID );
425
- }
426
- }
427
-
428
- if ( $custom_permalink
429
- && (
430
- substr( $request, 0, strlen( $custom_permalink ) ) != $custom_permalink
431
- || $request == $custom_permalink . '/'
432
- )
433
- ) {
434
- // Request doesn't match permalink - redirect
435
- $url = $custom_permalink;
436
-
437
- if ( substr( $request, 0, strlen( $original_permalink ) ) == $original_permalink
438
- && trim( $request, '/' ) != trim( $original_permalink, '/' )
439
- ) {
440
- // This is the original link; we can use this url to derive the new one
441
- $url = preg_replace( '@//*@', '/', str_replace(
442
- trim( $original_permalink, '/' ),
443
- trim( $custom_permalink, '/' ), $request
444
- ) );
445
- $url = preg_replace( '@([^?]*)&@', '\1?', $url );
446
- }
447
-
448
- // Append any query compenent
449
- $url .= strstr( $this->request_uri, '?' );
450
-
451
- wp_safe_redirect( home_url() . '/' . $url, 301 );
452
- exit(0);
453
- }
454
- }
455
-
456
- /**
457
- * Filter to replace the post permalink with the custom one.
458
- *
459
- * @access public
460
- *
461
- * @param string $permalink Default WordPress Permalink of Post.
462
- * @param object $post Post Details.
463
- *
464
- * @return string customized Post Permalink.
465
- */
466
- public function custom_post_link( $permalink, $post )
467
- {
468
- $custom_permalink = get_post_meta( $post->ID, 'custom_permalink', true );
469
- if ( $custom_permalink ) {
470
- $post_type = 'post';
471
- if ( isset( $post->post_type ) ) {
472
- $post_type = $post->post_type;
473
- }
474
-
475
- $language_code = apply_filters( 'wpml_element_language_code', null,
476
- array(
477
- 'element_id' => $post->ID,
478
- 'element_type' => $post_type
479
- )
480
- );
481
-
482
- $permalink = $this->wpml_permalink_filter( $custom_permalink,
483
- $language_code
484
- );
485
- } else {
486
- if ( class_exists( 'SitePress' ) ) {
487
- $wpml_lang_format = apply_filters( 'wpml_setting', 0,
488
- 'language_negotiation_type'
489
- );
490
-
491
- if ( 1 === intval( $wpml_lang_format ) ) {
492
- $get_original_url = $this->original_post_link( $post->ID );
493
- $permalink = $this->remove_double_slash( $permalink );
494
- if ( strlen( $get_original_url ) === strlen( $permalink ) ) {
495
- $permalink = $get_original_url;
496
- }
497
- }
498
- }
499
- }
500
-
501
- $permalink = $this->remove_double_slash( $permalink );
502
-
503
- return $permalink;
504
- }
505
-
506
- /**
507
- * Filter to replace the page permalink with the custom one.
508
- *
509
- * @access public
510
- *
511
- * @param string $permalink Default WordPress Permalink of Page.
512
- * @param int $page Page ID.
513
- *
514
- * @return string customized Page Permalink.
515
- */
516
- public function custom_page_link( $permalink, $page )
517
- {
518
- $custom_permalink = get_post_meta( $page, 'custom_permalink', true );
519
- if ( $custom_permalink ) {
520
- $language_code = apply_filters( 'wpml_element_language_code', null,
521
- array(
522
- 'element_id' => $page,
523
- 'element_type' => 'page'
524
- )
525
- );
526
-
527
- $permalink = $this->wpml_permalink_filter( $custom_permalink,
528
- $language_code
529
- );
530
- } else {
531
- if ( class_exists( 'SitePress' ) ) {
532
- $wpml_lang_format = apply_filters( 'wpml_setting', 0,
533
- 'language_negotiation_type'
534
- );
535
-
536
- if ( 1 === intval( $wpml_lang_format ) ) {
537
- $get_original_url = $this->original_page_link( $page );
538
- $permalink = $this->remove_double_slash( $permalink );
539
- if ( strlen( $get_original_url ) === strlen( $permalink ) ) {
540
- $permalink = $get_original_url;
541
- }
542
- }
543
- }
544
- }
545
-
546
- $permalink = $this->remove_double_slash( $permalink );
547
-
548
- return $permalink;
549
- }
550
-
551
- /**
552
- * Filter to replace the term permalink with the custom one.
553
- *
554
- * @access public
555
- *
556
- * @param string $permalink Term link URL.
557
- * @param object $term Term object.
558
- *
559
- * @return string customized Term Permalink.
560
- */
561
- public function custom_term_link( $permalink, $term )
562
- {
563
- if ( isset( $term ) ) {
564
- if ( isset( $term->term_id ) ) {
565
- $custom_permalink = $this->term_permalink( $term->term_id );
566
- }
567
-
568
- if ( $custom_permalink ) {
569
- $language_code = NULL;
570
- if ( isset( $term->term_taxonomy_id ) ) {
571
- $term_type = 'category';
572
- if ( isset( $term->taxonomy ) ) {
573
- $term_type = $term->taxonomy;
574
- }
575
-
576
- $language_code = apply_filters( 'wpml_element_language_code',
577
- null, array(
578
- 'element_id' => $term->term_taxonomy_id,
579
- 'element_type' => $term_type
580
- )
581
- );
582
- }
583
-
584
- $permalink = $this->wpml_permalink_filter( $custom_permalink,
585
- $language_code
586
- );
587
- } elseif ( isset( $term->term_id ) ) {
588
- if ( class_exists( 'SitePress' ) ) {
589
- $wpml_lang_format = apply_filters( 'wpml_setting', 0,
590
- 'language_negotiation_type'
591
- );
592
-
593
- if ( 1 === intval( $wpml_lang_format ) ) {
594
- $get_original_url = $this->original_term_link(
595
- $term->term_id
596
- );
597
- $permalink = $this->remove_double_slash( $permalink );
598
- if ( strlen( $get_original_url ) === strlen( $permalink ) ) {
599
- $permalink = $get_original_url;
600
- }
601
- }
602
- }
603
- }
604
- }
605
-
606
- $permalink = $this->remove_double_slash( $permalink );
607
-
608
- return $permalink;
609
- }
610
-
611
- /**
612
- * Remove the post_link and user_trailingslashit filter to get the original
613
- * permalink of the default and custom post type and apply right after that.
614
- *
615
- * @access public
616
- *
617
- * @param int $post_id Post ID.
618
- *
619
- * @return string Original Permalink for Posts.
620
- */
621
- public function original_post_link( $post_id )
622
- {
623
- remove_filter( 'post_link', array( $this, 'custom_post_link' ) );
624
- remove_filter( 'post_type_link', array( $this, 'custom_post_link' ) );
625
-
626
- $post_file_path = ABSPATH . '/wp-admin/includes/post.php';
627
- require_once $post_file_path;
628
-
629
- list( $permalink, $post_name ) = get_sample_permalink( $post_id );
630
- $permalink = str_replace( array( '%pagename%','%postname%' ), $post_name,
631
- $permalink
632
- );
633
- $permalink = ltrim( str_replace( home_url(), '', $permalink ), '/' );
634
-
635
- add_filter( 'post_link', array( $this, 'custom_post_link' ), 10, 3 );
636
- add_filter( 'post_type_link', array( $this, 'custom_post_link' ), 10, 2 );
637
-
638
- return $permalink;
639
- }
640
-
641
- /**
642
- * Remove the page_link and user_trailingslashit filter to get the original
643
- * permalink of the page and apply right after that.
644
- *
645
- * @access public
646
- *
647
- * @param int $post_id Page ID.
648
- *
649
- * @return string Original Permalink for the Page.
650
- */
651
- public function original_page_link( $post_id )
652
- {
653
- remove_filter( 'page_link', array( $this, 'custom_page_link' ) );
654
- remove_filter( 'user_trailingslashit',
655
- array( $this, 'custom_trailingslash' )
656
- );
657
-
658
- $post_file_path = ABSPATH . '/wp-admin/includes/post.php';
659
- require_once $post_file_path;
660
-
661
- list( $permalink, $post_name ) = get_sample_permalink( $post_id );
662
- $permalink = str_replace( array( '%pagename%','%postname%' ), $post_name,
663
- $permalink
664
- );
665
- $permalink = ltrim( str_replace( home_url(), '', $permalink ), '/' );
666
-
667
- add_filter( 'user_trailingslashit', array( $this, 'custom_trailingslash' ) );
668
- add_filter( 'page_link', array( $this, 'custom_page_link' ), 10, 2 );
669
-
670
- return $permalink;
671
- }
672
-
673
- /**
674
- * Remove the term_link and user_trailingslashit filter to get the original
675
- * permalink of the Term and apply right after that.
676
- *
677
- * @since 1.6.0
678
- * @access public
679
- *
680
- * @param int $term_id Term ID.
681
- *
682
- * @return string Original Permalink for Posts.
683
- */
684
- public function original_term_link( $term_id )
685
- {
686
- remove_filter( 'term_link', array( $this, 'custom_term_link' ) );
687
- remove_filter( 'user_trailingslashit',
688
- array( $this, 'custom_trailingslash' )
689
- );
690
-
691
- $term = get_term( $term_id );
692
- $term_link = get_term_link( $term );
693
-
694
- add_filter( 'user_trailingslashit', array( $this, 'custom_trailingslash' ) );
695
- add_filter( 'term_link', array( $this, 'custom_term_link' ), 10, 2 );
696
-
697
- if ( is_wp_error( $term_link ) ) {
698
- return '';
699
- }
700
-
701
- $original_permalink = ltrim( str_replace( home_url(), '', $term_link ), '/' );
702
-
703
- return $original_permalink;
704
- }
705
-
706
- /**
707
- * Filter to handle trailing slashes correctly.
708
- *
709
- * @access public
710
- *
711
- * @param string $url_string URL with or without a trailing slash.
712
- *
713
- * @return string Adds/removes a trailing slash based on the permalink structure.
714
- */
715
- public function custom_trailingslash( $url_string )
716
- {
717
- global $_CPRegisteredURL;
718
-
719
- remove_filter( 'user_trailingslashit',
720
- array( $this, 'custom_trailingslash' )
721
- );
722
-
723
- $trailingslash_string = $url_string;
724
- $url = parse_url( get_bloginfo( 'url' ) );
725
-
726
- if ( isset( $url['path'] ) ) {
727
- $request = substr( $url_string, strlen( $url['path'] ) );
728
- } else {
729
- $request = $url_string;
730
- }
731
-
732
- $request = ltrim( $request, '/' );
733
-
734
- add_filter( 'user_trailingslashit', array( $this, 'custom_trailingslash' ) );
735
-
736
- if ( trim( $request ) ) {
737
- if ( trim( $_CPRegisteredURL, '/' ) == trim( $request, '/' ) ) {
738
- if ( '/' === $url_string[0] ) {
739
- $trailingslash_string = '/';
740
- } else {
741
- $trailingslash_string = '';
742
- }
743
-
744
- if ( isset( $url['path'] ) ) {
745
- $trailingslash_string .= trailingslashit( $url['path'] );
746
- }
747
-
748
- $trailingslash_string .= $_CPRegisteredURL;
749
- }
750
- }
751
-
752
- return $trailingslash_string;
753
- }
754
-
755
- /**
756
- * Get permalink for term.
757
- *
758
- * @access public
759
- *
760
- * @return bool Term link.
761
- */
762
- public function term_permalink( $term_id )
763
- {
764
- $table = get_option( 'custom_permalink_table' );
765
- if ( $table ) {
766
- foreach ( $table as $link => $info ) {
767
- if ( $info['id'] == $term_id ) {
768
- return $link;
769
- }
770
- }
771
- }
772
-
773
- return false;
774
- }
775
-
776
- /**
777
- * Fix double slash issue with canonical of Yoast SEO specially with WPML.
778
- *
779
- * @since 1.6.0
780
- * @access public
781
- *
782
- * @param string $canonical The canonical.
783
- *
784
- * @return string the canonical after removing double slash if exist.
785
- */
786
- public function fix_canonical_double_slash( $canonical )
787
- {
788
- $canonical = $this->remove_double_slash( $canonical );
789
-
790
- return $canonical;
791
- }
792
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
frontend/js/script-form-1.7.1.min.js DELETED
@@ -1 +0,0 @@
1
- var getHomeURL=document.getElementById("custom_permalinks_home_url"),getPermalink=document.getElementById("custom_permalink"),editPost="",isSaving="",lastIsSaving=!1;function focusPermalinkField(){"use strict";var e=document.getElementById("custom-permalinks-post-slug");e&&(e.style.color="#000")}function blurPermalinkField(){"use strict";var e=document.getElementById("custom-permalinks-post-slug"),t=document.getElementById("original-permalink");e&&(getPermalink.value=e.value,""!==e.value&&e.value!==t.value||(e.value=t.value,e.style.color="#ddd"))}function updateMetaBox(){"use strict";var e,t,a;editPost&&((e=document.getElementsByClassName("edit-post-post-link__preview-label"))&&e[0]&&e[0].parentNode.classList.add("cp-permalink-hidden"),(isSaving=editPost.isSavingMetaBoxes())===lastIsSaving||isSaving||(t=wp.data.select("core/editor").getEditedPostAttribute("id"),a=new XMLHttpRequest,lastIsSaving=isSaving,a.onreadystatechange=function(){var e,t,n;4===a.readyState&&200===a.status&&(e=JSON.parse(a.responseText),t=document.getElementById("custom-permalinks-add"),getPermalink.value=e.custom_permalink,""===e.custom_permalink&&(e.custom_permalink=e.original_permalink),n=e.preview_permalink?getHomeURL.value+e.preview_permalink:getHomeURL.value+e.custom_permalink,document.getElementById("custom-permalinks-post-slug").value=e.custom_permalink,document.getElementById("original-permalink").value=e.original_permalink,document.querySelector("#view-post-btn a")&&(document.querySelector("#view-post-btn a").href=n),document.querySelector("a.editor-post-preview")&&(document.querySelector("a.editor-post-preview").href=n),t&&"add"===t.value&&(document.getElementById("custom-permalinks-edit-box").style.display=""),document.querySelector(".components-notice__content a")&&(document.querySelector(".components-notice__content a").href="/"+e.custom_permalink))},a.open("GET",getHomeURL.value+"/wp-json/custom-permalinks/v1/get-permalink/"+t,!0),a.setRequestHeader("Cache-Control","private, max-age=0, no-cache"),a.send()),lastIsSaving=isSaving)}function hideDefaultPermalink(){"use strict";var e=document.getElementsByClassName("edit-post-post-link__preview-label");e&&e[0]&&e[0].parentNode.classList.add("cp-permalink-hidden")}function permalinkContentLoaded(){"use strict";var e=document.getElementsByClassName("edit-post-post-link__preview-label"),t=document.getElementById("custom-permalinks-edit-box"),n=document.getElementById("custom-permalinks-post-slug");if(n&&(n.addEventListener("focus",focusPermalinkField),n.addEventListener("blur",blurPermalinkField)),""===document.querySelector("#custom-permalinks-edit-box .inside").innerHTML.trim()&&(t.style.display="none"),wp.data){var a=document.getElementById("custom-permalinks-add"),s=document.querySelectorAll(".edit-post-sidebar .components-panel__header"),i=0,o=s.length;if(a&&"add"===a.value&&(t.style.display="none"),editPost=wp.data.select("core/edit-post"),wp.data.subscribe(updateMetaBox),e&&e[0]&&e[0].parentNode.classList.add("cp-permalink-hidden"),t.classList.contains("closed")&&t.classList.remove("closed"),s&&0<o)for(;i<o;)s[i].addEventListener("click",hideDefaultPermalink),i+=1}}document.addEventListener("DOMContentLoaded",permalinkContentLoaded);
 
includes/class-custom-permalinks-form.php ADDED
@@ -0,0 +1,862 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Custom Permalinks Form.
4
+ *
5
+ * @package CustomPermalinks
6
+ */
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
10
+ }
11
+
12
+ /**
13
+ * Class that shows permalink form on edit post/category and saves it.
14
+ */
15
+ class Custom_Permalinks_Form {
16
+ /**
17
+ * JS file suffix extension.
18
+ *
19
+ * @var string
20
+ */
21
+ private $js_file_suffix = '.min.js';
22
+
23
+ /**
24
+ * Decide whether to show metabox or override WordPress default Permalink box.
25
+ *
26
+ * @var int
27
+ */
28
+ private $permalink_metabox = 0;
29
+
30
+ /**
31
+ * Initialize WordPress Hooks.
32
+ *
33
+ * @since 1.2.0
34
+ * @access public
35
+ *
36
+ * @return void
37
+ */
38
+ public function init() {
39
+ /*
40
+ * JS file suffix (version number with extension).
41
+ */
42
+ $this->js_file_suffix = '-' . CUSTOM_PERMALINKS_VERSION . '.min.js';
43
+
44
+ add_action( 'add_meta_boxes', array( $this, 'permalink_edit_box' ) );
45
+ add_action( 'save_post', array( $this, 'save_post' ), 10, 3 );
46
+ add_action( 'delete_post', array( $this, 'delete_permalink' ), 10 );
47
+ add_action( 'category_add_form', array( $this, 'term_options' ) );
48
+ add_action( 'category_edit_form', array( $this, 'term_options' ) );
49
+ add_action( 'post_tag_add_form', array( $this, 'term_options' ) );
50
+ add_action( 'post_tag_edit_form', array( $this, 'term_options' ) );
51
+ add_action( 'created_term', array( $this, 'save_term' ), 10, 3 );
52
+ add_action( 'edited_term', array( $this, 'save_term' ), 10, 3 );
53
+ add_action( 'delete_term', array( $this, 'delete_term_permalink' ), 10, 3 );
54
+ add_action( 'rest_api_init', array( $this, 'rest_edit_form' ) );
55
+ add_action(
56
+ 'update_option_page_on_front',
57
+ array( $this, 'static_homepage' ),
58
+ 10,
59
+ 2
60
+ );
61
+
62
+ add_filter(
63
+ 'get_sample_permalink_html',
64
+ array( $this, 'sample_permalink_html' ),
65
+ 10,
66
+ 2
67
+ );
68
+ add_filter( 'is_protected_meta', array( $this, 'protect_meta' ), 10, 2 );
69
+ }
70
+
71
+ /**
72
+ * Initialize WordPress Hooks.
73
+ *
74
+ * @since 1.6.0
75
+ * @access private
76
+ *
77
+ * @param object $post WP Post Object.
78
+ *
79
+ * return bool false Whether to show Custom Permalink form or not.
80
+ */
81
+ private function exclude_custom_permalinks( $post ) {
82
+ $args = array(
83
+ 'public' => true,
84
+ );
85
+ $exclude_post_types = apply_filters(
86
+ 'custom_permalinks_exclude_post_type',
87
+ $post->post_type
88
+ );
89
+
90
+ /*
91
+ * Exclude custom permalink `form` from any post(s) if filter returns `true`.
92
+ *
93
+ * @since 1.6.0
94
+ */
95
+ $exclude_posts = apply_filters(
96
+ 'custom_permalinks_exclude_posts',
97
+ $post
98
+ );
99
+ $public_post_types = get_post_types( $args, 'objects' );
100
+
101
+ if ( isset( $this->permalink_metabox ) && 1 === $this->permalink_metabox ) {
102
+ $check_availability = true;
103
+ } elseif ( 'attachment' === $post->post_type ) {
104
+ $check_availability = true;
105
+ } elseif ( intval( get_option( 'page_on_front' ) ) === $post->ID ) {
106
+ $check_availability = true;
107
+ } elseif ( ! isset( $public_post_types[ $post->post_type ] ) ) {
108
+ $check_availability = true;
109
+ } elseif ( '__true' === $exclude_post_types ) {
110
+ $check_availability = true;
111
+ } elseif ( is_bool( $exclude_posts ) && $exclude_posts ) {
112
+ $check_availability = true;
113
+ } else {
114
+ $check_availability = false;
115
+ }
116
+
117
+ return $check_availability;
118
+ }
119
+
120
+ /**
121
+ * Register meta box(es).
122
+ *
123
+ * @since 1.4.0
124
+ * @access public
125
+ *
126
+ * @return void
127
+ */
128
+ public function permalink_edit_box() {
129
+ add_meta_box(
130
+ 'custom-permalinks-edit-box',
131
+ __( 'Custom Permalinks', 'custom-permalinks' ),
132
+ array( $this, 'meta_edit_form' ),
133
+ null,
134
+ 'normal',
135
+ 'high',
136
+ array(
137
+ '__back_compat_meta_box' => false,
138
+ )
139
+ );
140
+ }
141
+
142
+ /**
143
+ * Set the meta_keys to protected which is created by the plugin.
144
+ *
145
+ * @since 1.4.0
146
+ * @access public
147
+ *
148
+ * @param bool $protected Whether the key is protected or not.
149
+ * @param string $meta_key Meta key.
150
+ *
151
+ * @return bool `true` for the custom_permalink key.
152
+ */
153
+ public function protect_meta( $protected, $meta_key ) {
154
+ if ( 'custom_permalink' === $meta_key ) {
155
+ $protected = true;
156
+ }
157
+
158
+ return $protected;
159
+ }
160
+
161
+ /**
162
+ * Sanitize given string to make it standard URL. It's a copy of default
163
+ * `sanitize_title_with_dashes` function with few changes.
164
+ *
165
+ * @since 2.0.0
166
+ * @access private
167
+ *
168
+ * @param string $permalink String that needs to be sanitized.
169
+ *
170
+ * @return string Sanitized permalink.
171
+ */
172
+ private function sanitize_permalink( $permalink ) {
173
+ $permalink = remove_accents( $permalink );
174
+ $permalink = wp_strip_all_tags( $permalink );
175
+ // Preserve escaped octets.
176
+ $permalink = preg_replace( '|%([a-fA-F0-9][a-fA-F0-9])|', '---$1---', $permalink );
177
+ // Remove percent signs that are not part of an octet.
178
+ $permalink = str_replace( '%', '', $permalink );
179
+ // Restore octets.
180
+ $permalink = preg_replace( '|---([a-fA-F0-9][a-fA-F0-9])---|', '%$1', $permalink );
181
+
182
+ /*
183
+ * Add Capability to allow Capital letter (if required). By default, It is
184
+ * disabled.
185
+ */
186
+ $allow_caps = apply_filters( 'custom_permalinks_allow_caps', false );
187
+ if ( ! is_bool( $allow_caps ) && ! $allow_caps ) {
188
+ if ( seems_utf8( $permalink ) ) {
189
+ if ( function_exists( 'mb_strtolower' ) ) {
190
+ $permalink = mb_strtolower( $permalink, 'UTF-8' );
191
+ }
192
+ $permalink = utf8_uri_encode( $permalink );
193
+ }
194
+ $permalink = strtolower( $permalink );
195
+ }
196
+
197
+ // Convert &nbsp, &ndash, and &mdash to hyphens.
198
+ $permalink = str_replace( array( '%c2%a0', '%e2%80%93', '%e2%80%94' ), '-', $permalink );
199
+ // Convert &nbsp, &ndash, and &mdash HTML entities to hyphens.
200
+ $permalink = str_replace( array( '&nbsp;', '&#160;', '&ndash;', '&#8211;', '&mdash;', '&#8212;' ), '-', $permalink );
201
+
202
+ // Strip these characters entirely.
203
+ $permalink = str_replace(
204
+ array(
205
+ // Soft hyphens.
206
+ '%c2%ad',
207
+ // &iexcl and &iquest.
208
+ '%c2%a1',
209
+ '%c2%bf',
210
+ // Angle quotes.
211
+ '%c2%ab',
212
+ '%c2%bb',
213
+ '%e2%80%b9',
214
+ '%e2%80%ba',
215
+ // Curly quotes.
216
+ '%e2%80%98',
217
+ '%e2%80%99',
218
+ '%e2%80%9c',
219
+ '%e2%80%9d',
220
+ '%e2%80%9a',
221
+ '%e2%80%9b',
222
+ '%e2%80%9e',
223
+ '%e2%80%9f',
224
+ // Bullet.
225
+ '%e2%80%a2',
226
+ // Copy, &reg, &deg, HORIZONTAL ELLIPSIS, and &trade.
227
+ '%c2%a9',
228
+ '%c2%ae',
229
+ '%c2%b0',
230
+ '%e2%80%a6',
231
+ '%e2%84%a2',
232
+ // Acute accents.
233
+ '%c2%b4',
234
+ '%cb%8a',
235
+ '%cc%81',
236
+ '%cd%81',
237
+ // Grave accent, macron, caron.
238
+ '%cc%80',
239
+ '%cc%84',
240
+ '%cc%8c',
241
+ ),
242
+ '',
243
+ $permalink
244
+ );
245
+
246
+ // Convert &times to 'x'.
247
+ $permalink = str_replace( '%c3%97', 'x', $permalink );
248
+
249
+ // Kill entities.
250
+ $permalink = preg_replace( '/&.+?;/', '', $permalink );
251
+
252
+ // Allow Alphanumeric and few symbols only.
253
+ if ( ! is_bool( $allow_caps ) && ! $allow_caps ) {
254
+ $permalink = preg_replace( '/[^%a-z0-9 \.\/_-]/', '', $permalink );
255
+ } else {
256
+ // Allow Capital letters.
257
+ $permalink = preg_replace( '/[^%a-zA-Z0-9 \.\/_-]/', '', $permalink );
258
+ }
259
+
260
+ // Allow only dot that are coming before any alphabet.
261
+ $allow_dot = explode( '.', $permalink );
262
+ if ( 0 < count( $allow_dot ) ) {
263
+ $new_perm = $allow_dot[0];
264
+ $dot_length = count( $allow_dot );
265
+ for ( $i = 1; $i < $dot_length; ++$i ) {
266
+ preg_match( '/^[a-z]/', $allow_dot[ $i ], $check_perm );
267
+ if ( isset( $check_perm ) && ! empty( $check_perm ) ) {
268
+ $new_perm .= '.';
269
+ }
270
+ $new_perm .= $allow_dot[ $i ];
271
+ }
272
+
273
+ $permalink = $new_perm;
274
+ }
275
+
276
+ $permalink = preg_replace( '/\s+/', '-', $permalink );
277
+ $permalink = preg_replace( '|-+|', '-', $permalink );
278
+ $permalink = str_replace( '-/', '/', $permalink );
279
+ $permalink = str_replace( '/-', '/', $permalink );
280
+ $permalink = trim( $permalink, '-' );
281
+
282
+ return $permalink;
283
+ }
284
+
285
+ /**
286
+ * Save per-post options.
287
+ *
288
+ * @access public
289
+ *
290
+ * @param int $post_id Post ID.
291
+ *
292
+ * @return void
293
+ */
294
+ public function save_post( $post_id ) {
295
+ if ( ! isset( $_REQUEST['_custom_permalinks_post_nonce'] )
296
+ && ! isset( $_REQUEST['custom_permalink'] )
297
+ ) {
298
+ return;
299
+ }
300
+
301
+ $action = 'custom-permalinks_' . $post_id;
302
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
303
+ if ( ! wp_verify_nonce( $_REQUEST['_custom_permalinks_post_nonce'], $action ) ) {
304
+ return;
305
+ }
306
+
307
+ $cp_frontend = new Custom_Permalinks_Frontend();
308
+ $original_link = $cp_frontend->original_post_link( $post_id );
309
+
310
+ if ( ! empty( $_REQUEST['custom_permalink'] )
311
+ && $_REQUEST['custom_permalink'] !== $original_link
312
+ ) {
313
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
314
+ $permalink = $this->sanitize_permalink( $_REQUEST['custom_permalink'] );
315
+ $permalink = apply_filters(
316
+ 'custom_permalink_before_saving',
317
+ $permalink,
318
+ $post_id
319
+ );
320
+
321
+ update_post_meta( $post_id, 'custom_permalink', $permalink );
322
+ }
323
+ }
324
+
325
+ /**
326
+ * Delete Post Permalink.
327
+ *
328
+ * @access public
329
+ *
330
+ * @param int $post_id Post ID.
331
+ *
332
+ * @return void
333
+ */
334
+ public function delete_permalink( $post_id ) {
335
+ delete_metadata( 'post', $post_id, 'custom_permalink' );
336
+ }
337
+
338
+ /**
339
+ * Result Permalink HTML Form for classic editor and Gutenberg.
340
+ *
341
+ * @since 1.6.0
342
+ * @access private
343
+ *
344
+ * @param object $post WP Post Object.
345
+ * @param bool $meta_box Show whether calls from classic WordPress or Gutenberg.
346
+ *
347
+ * @return string Permalink Form HTML.
348
+ */
349
+ private function get_permalink_html( $post, $meta_box = false ) {
350
+ $post_id = $post->ID;
351
+ $permalink = get_post_meta( $post_id, 'custom_permalink', true );
352
+
353
+ ob_start();
354
+
355
+ $cp_frontend = new Custom_Permalinks_Frontend();
356
+ if ( 'page' === $post->post_type ) {
357
+ $original_permalink = $cp_frontend->original_page_link( $post_id );
358
+ $view_post = __( 'View Page', 'custom-permalinks' );
359
+ } else {
360
+ $post_type_name = '';
361
+ $post_type_object = get_post_type_object( $post->post_type );
362
+ if ( is_object( $post_type_object ) && isset( $post_type_object->labels )
363
+ && isset( $post_type_object->labels->singular_name )
364
+ ) {
365
+ $post_type_name = ' ' . $post_type_object->labels->singular_name;
366
+ } elseif ( is_object( $post_type_object )
367
+ && isset( $post_type_object->label )
368
+ ) {
369
+ $post_type_name = ' ' . $post_type_object->label;
370
+ }
371
+
372
+ $original_permalink = $cp_frontend->original_post_link( $post_id );
373
+ $view_post = __( 'View', 'custom-permalinks' ) . $post_type_name;
374
+ }
375
+ $this->get_permalink_form(
376
+ $permalink,
377
+ $original_permalink,
378
+ $post_id,
379
+ false,
380
+ $post->post_name
381
+ );
382
+
383
+ $content = ob_get_contents();
384
+ ob_end_clean();
385
+
386
+ if ( 'trash' !== $post->post_status ) {
387
+ $home_url = trailingslashit( home_url() );
388
+ if ( isset( $permalink ) && ! empty( $permalink ) ) {
389
+ $view_post_link = $home_url . $permalink;
390
+ } else {
391
+ if ( 'draft' === $post->post_status ) {
392
+ $view_post = 'Preview';
393
+ $view_post_link = $home_url . '?';
394
+ if ( 'page' === $post->post_type ) {
395
+ $view_post_link .= 'page_id';
396
+ } elseif ( 'post' === $post->post_type ) {
397
+ $view_post_link .= 'p';
398
+ } else {
399
+ $view_post_link .= 'post_type=' . $post->post_type . '&p';
400
+ }
401
+ $view_post_link .= '=' . $post_id . '&preview=true';
402
+ } else {
403
+ $view_post_link = $home_url . $original_permalink;
404
+ }
405
+ }
406
+
407
+ $content .= ' <span id="view-post-btn">' .
408
+ '<a href="' . $view_post_link . '" class="button button-medium" target="_blank">' . $view_post . '</a>' .
409
+ '</span><br>';
410
+ if ( true === $meta_box ) {
411
+ $content .= '<style>.editor-post-permalink,.cp-permalink-hidden{display:none;}</style>';
412
+ }
413
+ }
414
+
415
+ return '<strong>' . __( 'Permalink:', 'custom-permalinks' ) . '</strong> ' . $content;
416
+ }
417
+
418
+ /**
419
+ * Per-post/page options (WordPress > 2.9).
420
+ *
421
+ * @access public
422
+ *
423
+ * @param string $html WP Post Permalink HTML.
424
+ * @param int $post_id Post ID.
425
+ *
426
+ * @return string Edit Form string.
427
+ */
428
+ public function sample_permalink_html( $html, $post_id ) {
429
+ $post = get_post( $post_id );
430
+
431
+ $disable_cp = $this->exclude_custom_permalinks( $post );
432
+ $this->permalink_metabox = 1;
433
+ if ( $disable_cp ) {
434
+ return $html;
435
+ }
436
+
437
+ $output_content = $this->get_permalink_html( $post );
438
+
439
+ return $output_content;
440
+ }
441
+
442
+ /**
443
+ * Adds the Permalink Edit Meta box for the user with validating the
444
+ * PostTypes to make compatibility with Gutenberg.
445
+ *
446
+ * @access public
447
+ *
448
+ * @param object $post WP Post Object.
449
+ *
450
+ * @return void
451
+ */
452
+ public function meta_edit_form( $post ) {
453
+ $disable_cp = $this->exclude_custom_permalinks( $post );
454
+ if ( $disable_cp ) {
455
+ wp_enqueue_script(
456
+ 'custom-permalinks-form',
457
+ plugins_url(
458
+ '/assets/js/script-form' . $this->js_file_suffix,
459
+ CUSTOM_PERMALINKS_FILE
460
+ ),
461
+ array(),
462
+ CUSTOM_PERMALINKS_VERSION,
463
+ true
464
+ );
465
+
466
+ return;
467
+ }
468
+
469
+ $screen = get_current_screen();
470
+ if ( 'add' === $screen->action ) {
471
+ echo '<input value="add" type="hidden" name="custom-permalinks-add" id="custom-permalinks-add" />';
472
+ }
473
+
474
+ $output_content = $this->get_permalink_html( $post, true );
475
+
476
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
477
+ echo $output_content;
478
+ }
479
+
480
+ /**
481
+ * Per-category/tag options.
482
+ *
483
+ * @access public
484
+ *
485
+ * @param object|string $tag Current taxonomy term object for Edit form
486
+ * otherwise the taxonomy slug.
487
+ *
488
+ * @return void
489
+ */
490
+ public function term_options( $tag ) {
491
+ $permalink = '';
492
+ $original_permalink = '';
493
+
494
+ if ( is_object( $tag ) && isset( $tag->term_id ) ) {
495
+ $cp_frontend = new Custom_Permalinks_Frontend();
496
+ if ( $tag->term_id ) {
497
+ $permalink = $cp_frontend->term_permalink( $tag->term_id );
498
+ $original_permalink = $cp_frontend->original_term_link(
499
+ $tag->term_id
500
+ );
501
+ }
502
+
503
+ $this->get_permalink_form( $permalink, $original_permalink, $tag->term_id );
504
+ } else {
505
+ $this->get_permalink_form( $permalink, $original_permalink, $tag );
506
+ }
507
+
508
+ // Move the save button to above this form.
509
+ wp_enqueue_script( 'jquery' );
510
+ ?>
511
+ <script type="text/javascript">
512
+ jQuery(document).ready(function() {
513
+ var button = jQuery('#custom_permalink_form').parent().find('.submit');
514
+ button.remove().insertAfter(jQuery('#custom_permalink_form'));
515
+ });
516
+ </script>
517
+ <?php
518
+ }
519
+
520
+ /**
521
+ * Helper function to render form.
522
+ *
523
+ * @access private
524
+ *
525
+ * @param string $permalink Permalink which is created by the plugin.
526
+ * @param string $original Permalink which set by WordPress.
527
+ * @param int|string $id Post ID for Posts, Pages and custom post
528
+ * types, Term ID for Taxonomy Edit form and
529
+ * taxonomy slug in case of term add.
530
+ * @param bool $render_containers Shows Post/Term Edit.
531
+ * @param string $postname Post Name.
532
+ *
533
+ * @return void
534
+ */
535
+ private function get_permalink_form( $permalink, $original = '', $id,
536
+ $render_containers = true, $postname = ''
537
+ ) {
538
+ $encoded_permalink = htmlspecialchars( urldecode( $permalink ) );
539
+ $home_url = trailingslashit( home_url() );
540
+
541
+ if ( $render_containers ) {
542
+ wp_nonce_field(
543
+ 'custom-permalinks_' . $id,
544
+ '_custom_permalinks_term_nonce',
545
+ false,
546
+ true
547
+ );
548
+ } else {
549
+ wp_nonce_field(
550
+ 'custom-permalinks_' . $id,
551
+ '_custom_permalinks_post_nonce',
552
+ false,
553
+ true
554
+ );
555
+ }
556
+
557
+ // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
558
+ echo '<input value="' . $home_url . '" type="hidden" name="custom_permalinks_home_url" id="custom_permalinks_home_url" />' .
559
+ '<input value="' . $encoded_permalink . '" type="hidden" name="custom_permalink" id="custom_permalink" />';
560
+ // phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped
561
+
562
+ if ( $render_containers ) {
563
+ echo '<table class="form-table" id="custom_permalink_form">' .
564
+ '<tr>' .
565
+ '<th scope="row">' . esc_html__( 'Custom Permalink', 'custom-permalinks' ) . '</th>' .
566
+ '<td>';
567
+ }
568
+ if ( '' === $permalink ) {
569
+ $original = $this->check_conflicts( $original );
570
+ }
571
+
572
+ if ( $permalink ) {
573
+ $post_slug = htmlspecialchars( urldecode( $permalink ) );
574
+ $original_encoded_url = htmlspecialchars( urldecode( $original ) );
575
+ } else {
576
+ $post_slug = htmlspecialchars( urldecode( $original ) );
577
+ $original_encoded_url = $post_slug;
578
+ }
579
+
580
+ wp_enqueue_script(
581
+ 'custom-permalinks-form',
582
+ plugins_url(
583
+ '/assets/js/script-form' . $this->js_file_suffix,
584
+ CUSTOM_PERMALINKS_FILE
585
+ ),
586
+ array(),
587
+ CUSTOM_PERMALINKS_VERSION,
588
+ true
589
+ );
590
+ $postname_html = '';
591
+ if ( isset( $postname ) && '' !== $postname ) {
592
+ $postname_html = '<input type="hidden" id="new-post-slug" class="text" value="' . $postname . '" />';
593
+ }
594
+
595
+ $field_style = 'width: 250px;';
596
+ if ( ! $permalink ) {
597
+ $field_style .= ' color: #ddd;';
598
+ }
599
+
600
+ // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
601
+ echo $home_url .
602
+ '<span id="editable-post-name" title="Click to edit this part of the permalink">' .
603
+ $postname_html .
604
+ '<input type="hidden" id="original-permalink" value="' . $original_encoded_url . '" />' .
605
+ '<input type="text" id="custom-permalinks-post-slug" class="text" value="' . $post_slug . '" style="' . $field_style . '" />' .
606
+ '</span>';
607
+ // phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped
608
+
609
+ if ( $render_containers ) {
610
+ echo '<br />' .
611
+ '<small>' .
612
+ esc_html__( 'Leave blank to disable', 'custom-permalinks' ) .
613
+ '</small>' .
614
+ '</td>' .
615
+ '</tr>' .
616
+ '</table>';
617
+ }
618
+ }
619
+
620
+ /**
621
+ * Save term (common to tags and categories).
622
+ *
623
+ * @since 1.6.0
624
+ * @access public
625
+ *
626
+ * @param string $term_id Term ID.
627
+ *
628
+ * @return void
629
+ */
630
+ public function save_term( $term_id ) {
631
+ $term = get_term( $term_id );
632
+
633
+ if ( ! isset( $_REQUEST['_custom_permalinks_term_nonce'] )
634
+ && ! isset( $_REQUEST['custom_permalink'] )
635
+ ) {
636
+ return;
637
+ }
638
+
639
+ $action1 = 'custom-permalinks_' . $term_id;
640
+ $action2 = 'custom-permalinks_' . $term->taxonomy;
641
+ // phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
642
+ if ( ! wp_verify_nonce( $_REQUEST['_custom_permalinks_term_nonce'], $action1 )
643
+ && ! wp_verify_nonce( $_REQUEST['_custom_permalinks_term_nonce'], $action2 )
644
+ ) {
645
+ return;
646
+ }
647
+ // phpcs:enable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
648
+
649
+ if ( isset( $term ) && isset( $term->taxonomy ) ) {
650
+ $taxonomy_name = $term->taxonomy;
651
+ if ( 'category' === $taxonomy_name || 'post_tag' === $taxonomy_name ) {
652
+ if ( 'post_tag' === $taxonomy_name ) {
653
+ $taxonomy_name = 'tag';
654
+ }
655
+
656
+ $new_permalink = ltrim(
657
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
658
+ stripcslashes( $_REQUEST['custom_permalink'] ),
659
+ '/'
660
+ );
661
+ if ( empty( $new_permalink ) || '' === $new_permalink ) {
662
+ return;
663
+ }
664
+
665
+ $cp_frontend = new Custom_Permalinks_Frontend();
666
+ $old_permalink = $cp_frontend->original_term_link( $term_id );
667
+ if ( $new_permalink === $old_permalink ) {
668
+ return;
669
+ }
670
+
671
+ $this->delete_term_permalink( $term_id );
672
+
673
+ $permalink = $this->sanitize_permalink( $new_permalink );
674
+ $table = get_option( 'custom_permalink_table' );
675
+
676
+ if ( $permalink && ! array_key_exists( $permalink, $table ) ) {
677
+ $table[ $permalink ] = array(
678
+ 'id' => $term_id,
679
+ 'kind' => $taxonomy_name,
680
+ 'slug' => $term->slug,
681
+ );
682
+ }
683
+
684
+ update_option( 'custom_permalink_table', $table );
685
+ }
686
+ }
687
+ }
688
+
689
+ /**
690
+ * Delete term.
691
+ *
692
+ * @access public
693
+ *
694
+ * @param int $term_id Term ID.
695
+ *
696
+ * @return void
697
+ */
698
+ public function delete_term_permalink( $term_id ) {
699
+ $table = get_option( 'custom_permalink_table' );
700
+ if ( $table ) {
701
+ foreach ( $table as $link => $info ) {
702
+ if ( $info['id'] === (int) $term_id ) {
703
+ unset( $table[ $link ] );
704
+ break;
705
+ }
706
+ }
707
+ }
708
+
709
+ update_option( 'custom_permalink_table', $table );
710
+ }
711
+
712
+ /**
713
+ * Check Conflicts and resolve it (e.g: Polylang) UPDATED for Polylang
714
+ * hide_default setting.
715
+ *
716
+ * @since 1.2.0
717
+ * @access public
718
+ *
719
+ * @param string $requested_url Original permalink.
720
+ *
721
+ * @return string requested URL by removing the language/ from it if exist.
722
+ */
723
+ public function check_conflicts( $requested_url = '' ) {
724
+ if ( '' === $requested_url ) {
725
+ return;
726
+ }
727
+
728
+ // Check if the Polylang Plugin is installed so, make changes in the URL.
729
+ if ( defined( 'POLYLANG_VERSION' ) ) {
730
+ $polylang_config = get_option( 'polylang' );
731
+ if ( 1 === $polylang_config['force_lang'] ) {
732
+ if ( false !== strpos( $requested_url, 'language/' ) ) {
733
+ $requested_url = str_replace( 'language/', '', $requested_url );
734
+ }
735
+
736
+ /*
737
+ * Check if `hide_default` is `true` and the current language is not
738
+ * the default. Otherwise remove the lang code from the url.
739
+ */
740
+ if ( 1 === $polylang_config['hide_default'] ) {
741
+ $current_language = '';
742
+ if ( function_exists( 'pll_current_language' ) ) {
743
+ // get current language.
744
+ $current_language = pll_current_language();
745
+ }
746
+
747
+ // get default language.
748
+ $default_language = $polylang_config['default_lang'];
749
+ if ( $current_language !== $default_language ) {
750
+ $remove_lang = ltrim( strstr( $requested_url, '/' ), '/' );
751
+ if ( '' !== $remove_lang ) {
752
+ return $remove_lang;
753
+ }
754
+ }
755
+ } else {
756
+ $remove_lang = ltrim( strstr( $requested_url, '/' ), '/' );
757
+ if ( '' !== $remove_lang ) {
758
+ return $remove_lang;
759
+ }
760
+ }
761
+ }
762
+ }
763
+
764
+ return $requested_url;
765
+ }
766
+
767
+ /**
768
+ * Refresh Permalink using AJAX Call.
769
+ *
770
+ * @since 1.6.0
771
+ * @access public
772
+ *
773
+ * @param object $data Contains post id with some default REST Values.
774
+ *
775
+ * @return void
776
+ */
777
+ public function refresh_meta_form( $data ) {
778
+ if ( isset( $data['id'] ) && is_numeric( $data['id'] ) ) {
779
+ $post = get_post( $data['id'] );
780
+ $all_permalinks = array();
781
+ $all_permalinks['custom_permalink'] = get_post_meta(
782
+ $data['id'],
783
+ 'custom_permalink',
784
+ true
785
+ );
786
+
787
+ if ( ! $all_permalinks['custom_permalink'] ) {
788
+ if ( 'draft' === $post->post_status ) {
789
+ $view_post_link = '?';
790
+ if ( 'page' === $post->post_type ) {
791
+ $view_post_link .= 'page_id';
792
+ } elseif ( 'post' === $post->post_type ) {
793
+ $view_post_link .= 'p';
794
+ } else {
795
+ $view_post_link .= 'post_type=' . $post->post_type . '&p';
796
+ }
797
+ $view_post_link .= '=' . $data['id'] . '&preview=true';
798
+
799
+ $all_permalinks['preview_permalink'] = $view_post_link;
800
+ }
801
+ }
802
+
803
+ $cp_frontend = new Custom_Permalinks_Frontend();
804
+ if ( 'page' === $post->post_type ) {
805
+ $all_permalinks['original_permalink'] = $cp_frontend->original_page_link(
806
+ $data['id']
807
+ );
808
+ } else {
809
+ $all_permalinks['original_permalink'] = $cp_frontend->original_post_link(
810
+ $data['id']
811
+ );
812
+ }
813
+
814
+ echo wp_json_encode( $all_permalinks );
815
+ exit;
816
+ }
817
+ }
818
+
819
+ /**
820
+ * Added Custom Endpoints for refreshing the permalink.
821
+ *
822
+ * @since 1.6.0
823
+ * @access public
824
+ *
825
+ * @return void
826
+ */
827
+ public function rest_edit_form() {
828
+ register_rest_route(
829
+ 'custom-permalinks/v1',
830
+ '/get-permalink/(?P<id>\d+)',
831
+ array(
832
+ 'methods' => 'GET',
833
+ 'callback' => array( $this, 'refresh_meta_form' ),
834
+ 'args' => array(
835
+ 'id' => array(
836
+ 'validate_callback' => 'is_numeric',
837
+ ),
838
+ ),
839
+ 'permission_callback' => function () {
840
+ return current_user_can( 'edit_posts' );
841
+ },
842
+ )
843
+ );
844
+ }
845
+
846
+ /**
847
+ * Delete the permalink for the page selected as the static Homepage.
848
+ *
849
+ * @since 1.6.0
850
+ * @access public
851
+ *
852
+ * @param int $prev_homepage_id Page ID of previously set Front Page.
853
+ * @param int $new_homepage_id Page ID of current Front Page.
854
+ *
855
+ * @return void
856
+ */
857
+ public function static_homepage( $prev_homepage_id, $new_homepage_id ) {
858
+ if ( $prev_homepage_id !== $new_homepage_id ) {
859
+ $this->delete_permalink( $new_homepage_id );
860
+ }
861
+ }
862
+ }
includes/class-custom-permalinks-frontend.php ADDED
@@ -0,0 +1,941 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Custom Permalinks Frontend.
4
+ *
5
+ * @package CustomPermalinks
6
+ */
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
10
+ }
11
+
12
+ /**
13
+ * Class that passes custom link, parse the requested url and redirect.
14
+ */
15
+ class Custom_Permalinks_Frontend {
16
+ /**
17
+ * Make it `true` when `parse_request()` succeeded to make performance better.
18
+ *
19
+ * @var bool
20
+ */
21
+ private $parse_request_status = false;
22
+
23
+ /**
24
+ * The query string, if any, via which the page is accessed otherwise empty.
25
+ *
26
+ * @var string
27
+ */
28
+ private $query_string_uri = '';
29
+
30
+ /**
31
+ * Preserve the url for later use in parse_request.
32
+ *
33
+ * @var string
34
+ */
35
+ private $registered_url = '';
36
+
37
+ /**
38
+ * The URI which is given in order to access this page. Default empty.
39
+ *
40
+ * @var string
41
+ */
42
+ private $request_uri = '';
43
+
44
+ /**
45
+ * Initialize WordPress Hooks.
46
+ *
47
+ * @since 1.2.0
48
+ * @access public
49
+ *
50
+ * @return void
51
+ */
52
+ public function init() {
53
+ if ( isset( $_SERVER['QUERY_STRING'] ) ) {
54
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
55
+ $this->query_string_uri = $_SERVER['QUERY_STRING'];
56
+ }
57
+
58
+ if ( isset( $_SERVER['REQUEST_URI'] ) ) {
59
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
60
+ $this->request_uri = $_SERVER['REQUEST_URI'];
61
+ }
62
+
63
+ add_action( 'template_redirect', array( $this, 'make_redirect' ), 5 );
64
+
65
+ add_filter( 'request', array( $this, 'parse_request' ) );
66
+ add_filter( 'oembed_request_post_id', array( $this, 'oembed_request' ), 10, 2 );
67
+ add_filter( 'post_link', array( $this, 'custom_post_link' ), 10, 2 );
68
+ add_filter( 'post_type_link', array( $this, 'custom_post_link' ), 10, 2 );
69
+ add_filter( 'page_link', array( $this, 'custom_page_link' ), 10, 2 );
70
+ add_filter( 'term_link', array( $this, 'custom_term_link' ), 10, 2 );
71
+ add_filter( 'user_trailingslashit', array( $this, 'custom_trailingslash' ) );
72
+
73
+ // WPSEO Filters.
74
+ add_filter(
75
+ 'wpseo_canonical',
76
+ array( $this, 'fix_canonical_double_slash' ),
77
+ 20,
78
+ 1
79
+ );
80
+ }
81
+
82
+ /**
83
+ * Replace double slash `//` with single slash `/`.
84
+ *
85
+ * @since 1.6.0
86
+ * @access public
87
+ *
88
+ * @param string $permalink URL in which `//` needs to be replaced with `/`.
89
+ *
90
+ * @return string URL with single slash.
91
+ */
92
+ public function remove_double_slash( $permalink = '' ) {
93
+ $protocol = '';
94
+ if ( 0 === strpos( $permalink, 'http://' )
95
+ || 0 === strpos( $permalink, 'https://' )
96
+ ) {
97
+ $split_protocol = explode( '://', $permalink );
98
+ if ( 1 < count( $split_protocol ) ) {
99
+ $protocol = $split_protocol[0] . '://';
100
+ $permalink = str_replace( $protocol, '', $permalink );
101
+ }
102
+ }
103
+
104
+ $permalink = str_replace( '//', '/', $permalink );
105
+ $permalink = $protocol . $permalink;
106
+
107
+ return $permalink;
108
+ }
109
+
110
+ /**
111
+ * Use `wpml_permalink` to add language information to permalinks and
112
+ * resolve language switcher issue if found.
113
+ *
114
+ * @since 1.6.0
115
+ * @access public
116
+ *
117
+ * @param string $permalink Custom Permalink.
118
+ * @param string $language_code The language to convert the url into.
119
+ *
120
+ * @return string permalink with language information.
121
+ */
122
+ public function wpml_permalink_filter( $permalink = '', $language_code ) {
123
+ $custom_permalink = $permalink;
124
+ $trailing_permalink = trailingslashit( home_url() ) . $custom_permalink;
125
+ if ( $language_code ) {
126
+ $permalink = apply_filters(
127
+ 'wpml_permalink',
128
+ $trailing_permalink,
129
+ $language_code
130
+ );
131
+ $site_url = site_url();
132
+ $wpml_href = str_replace( $site_url, '', $permalink );
133
+ if ( 0 === strpos( $wpml_href, '//' ) ) {
134
+ if ( 0 !== strpos( $wpml_href, '//' . $language_code . '/' ) ) {
135
+ $permalink = $site_url . '/' . $language_code . '/' . $custom_permalink;
136
+ }
137
+ }
138
+ } else {
139
+ $permalink = apply_filters( 'wpml_permalink', $trailing_permalink );
140
+ }
141
+
142
+ return $permalink;
143
+ }
144
+
145
+ /**
146
+ * Search a permalink in the posts table and return its result.
147
+ *
148
+ * @since 2.0.0
149
+ * @access private
150
+ *
151
+ * @param string $requested_url Requested URL.
152
+ *
153
+ * @return object|null Containing Post ID, Permalink, Post Type, and Post status
154
+ * if URL matched otherwise returns null.
155
+ */
156
+ private function query_post( $requested_url ) {
157
+ global $wpdb;
158
+
159
+ $cache_name = 'cp$_' . str_replace( '/', '-', $requested_url ) . '_#cp';
160
+ $posts = wp_cache_get( $cache_name, 'custom_permalinks' );
161
+
162
+ if ( ! $posts ) {
163
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
164
+ $posts = $wpdb->get_results(
165
+ $wpdb->prepare(
166
+ 'SELECT p.ID, pm.meta_value, p.post_type, p.post_status ' .
167
+ " FROM $wpdb->posts AS p INNER JOIN $wpdb->postmeta AS pm ON (pm.post_id = p.ID) " .
168
+ " WHERE pm.meta_key = 'custom_permalink' " .
169
+ ' AND (pm.meta_value = %s OR pm.meta_value = %s) ' .
170
+ " AND p.post_status != 'trash' AND p.post_type != 'nav_menu_item' " .
171
+ " ORDER BY FIELD(post_status,'publish','private','pending','draft','auto-draft','inherit')," .
172
+ " FIELD(post_type,'post','page') LIMIT 1",
173
+ $requested_url,
174
+ $requested_url . '/'
175
+ )
176
+ );
177
+
178
+ $remove_like_query = apply_filters( 'cp_remove_like_query', '__true' );
179
+ if ( ! $posts && '__true' === $remove_like_query ) {
180
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
181
+ $posts = $wpdb->get_results(
182
+ $wpdb->prepare(
183
+ "SELECT p.ID, pm.meta_value, p.post_type, p.post_status FROM $wpdb->posts AS p " .
184
+ " LEFT JOIN $wpdb->postmeta AS pm ON (p.ID = pm.post_id) WHERE " .
185
+ " meta_key = 'custom_permalink' AND meta_value != '' AND " .
186
+ ' ( LOWER(meta_value) = LEFT(LOWER(%s), LENGTH(meta_value)) OR ' .
187
+ ' LOWER(meta_value) = LEFT(LOWER(%s), LENGTH(meta_value)) ) ' .
188
+ " AND post_status != 'trash' AND post_type != 'nav_menu_item'" .
189
+ ' ORDER BY LENGTH(meta_value) DESC, ' .
190
+ " FIELD(post_status,'publish','private','pending','draft','auto-draft','inherit')," .
191
+ " FIELD(post_type,'post','page'), p.ID ASC LIMIT 1",
192
+ $requested_url,
193
+ $requested_url . '/'
194
+ )
195
+ );
196
+ }
197
+
198
+ wp_cache_set( $cache_name, $posts, 'custom_permalinks' );
199
+ }
200
+
201
+ return $posts;
202
+ }
203
+
204
+ /**
205
+ * Filter to rewrite the query if we have a matching post.
206
+ *
207
+ * @since 0.1.0
208
+ * @access public
209
+ *
210
+ * @param string $query Requested URL.
211
+ *
212
+ * @return string the URL which has to be parsed.
213
+ */
214
+ public function parse_request( $query ) {
215
+ global $wpdb;
216
+
217
+ if ( isset( $_SERVER['REQUEST_URI'] )
218
+ && $_SERVER['REQUEST_URI'] !== $this->request_uri
219
+ ) {
220
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
221
+ $this->request_uri = $_SERVER['REQUEST_URI'];
222
+ }
223
+
224
+ /*
225
+ * First, search for a matching custom permalink, and if found
226
+ * generate the corresponding original URL.
227
+ */
228
+ $original_url = null;
229
+
230
+ // Get request URI, strip parameters and /'s.
231
+ $url = wp_parse_url( get_bloginfo( 'url' ) );
232
+ $url = isset( $url['path'] ) ? $url['path'] : '';
233
+ $request = ltrim( substr( $this->request_uri, strlen( $url ) ), '/' );
234
+ $pos = strpos( $request, '?' );
235
+ if ( $pos ) {
236
+ $request = substr( $request, 0, $pos );
237
+ }
238
+
239
+ if ( ! $request ) {
240
+ return $query;
241
+ }
242
+
243
+ $ignore = apply_filters( 'custom_permalinks_request_ignore', $request );
244
+
245
+ if ( '__true' === $ignore ) {
246
+ return $query;
247
+ }
248
+
249
+ if ( defined( 'POLYLANG_VERSION' ) ) {
250
+ $cp_form = new Custom_Permalinks_Form();
251
+ $request = $cp_form->check_conflicts( $request );
252
+ }
253
+ $request_no_slash = preg_replace( '@/+@', '/', trim( $request, '/' ) );
254
+ $posts = $this->query_post( $request_no_slash );
255
+
256
+ if ( $posts ) {
257
+ /*
258
+ * A post matches our request. Preserve this url for later
259
+ * if it's the same as the permalink (no extra stuff).
260
+ */
261
+ if ( trim( $posts[0]->meta_value, '/' ) === $request_no_slash ) {
262
+ $this->registered_url = $request;
263
+ }
264
+
265
+ if ( 'draft' === $posts[0]->post_status ) {
266
+ if ( 'page' === $posts[0]->post_type ) {
267
+ $original_url = '?page_id=' . $posts[0]->ID;
268
+ } else {
269
+ $original_url = '?post_type=' . $posts[0]->post_type . '&p=' . $posts[0]->ID;
270
+ }
271
+ } else {
272
+ $post_meta = trim( strtolower( $posts[0]->meta_value ), '/' );
273
+ if ( 'page' === $posts[0]->post_type ) {
274
+ $get_original_url = $this->original_page_link( $posts[0]->ID );
275
+ $original_url = preg_replace(
276
+ '@/+@',
277
+ '/',
278
+ str_replace(
279
+ $post_meta,
280
+ $get_original_url,
281
+ strtolower( $request_no_slash )
282
+ )
283
+ );
284
+ } else {
285
+ $get_original_url = $this->original_post_link( $posts[0]->ID );
286
+ $original_url = preg_replace(
287
+ '@/+@',
288
+ '/',
289
+ str_replace(
290
+ $post_meta,
291
+ $get_original_url,
292
+ strtolower( $request_no_slash )
293
+ )
294
+ );
295
+ }
296
+ }
297
+ }
298
+
299
+ if ( null === $original_url ) {
300
+ // See if any terms have a matching permalink.
301
+ $table = get_option( 'custom_permalink_table' );
302
+ if ( ! $table ) {
303
+ return $query;
304
+ }
305
+
306
+ foreach ( array_keys( $table ) as $permalink ) {
307
+ $perm_length = strlen( $permalink );
308
+ if ( substr( $request_no_slash, 0, $perm_length ) === $permalink
309
+ || substr( $request_no_slash . '/', 0, $perm_length ) === $permalink
310
+ ) {
311
+ $term = $table[ $permalink ];
312
+
313
+ /*
314
+ * Preserve this url for later if it's the same as the
315
+ * permalink (no extra stuff)
316
+ */
317
+ if ( trim( $permalink, '/' ) === $request_no_slash ) {
318
+ $this->registered_url = $request;
319
+ }
320
+
321
+ $term_link = $this->original_term_link( $term['id'] );
322
+ $original_url = str_replace(
323
+ trim( $permalink, '/' ),
324
+ $term_link,
325
+ trim( $request, '/' )
326
+ );
327
+ }
328
+ }
329
+ }
330
+
331
+ $this->parse_request_status = false;
332
+ if ( null !== $original_url ) {
333
+ $this->parse_request_status = true;
334
+
335
+ $original_url = str_replace( '//', '/', $original_url );
336
+ $pos = strpos( $this->request_uri, '?' );
337
+ if ( false !== $pos ) {
338
+ $query_vars = substr( $this->request_uri, $pos + 1 );
339
+ if ( false === strpos( $original_url, '?' ) ) {
340
+ $original_url .= '?' . $query_vars;
341
+ } else {
342
+ $original_url .= '&' . $query_vars;
343
+ }
344
+ }
345
+
346
+ /*
347
+ * Now we have the original URL, run this back through WP->parse_request,
348
+ * in order to parse parameters properly.
349
+ * We set $_SERVER variables to fool the function.
350
+ */
351
+ $_SERVER['REQUEST_URI'] = '/' . ltrim( $original_url, '/' );
352
+ $path_info = apply_filters(
353
+ 'custom_permalinks_path_info',
354
+ '__false'
355
+ );
356
+ if ( '__false' !== $path_info ) {
357
+ $_SERVER['PATH_INFO'] = '/' . ltrim( $original_url, '/' );
358
+ }
359
+
360
+ $_SERVER['QUERY_STRING'] = '';
361
+ $pos = strpos( $original_url, '?' );
362
+ if ( false !== $pos ) {
363
+ $_SERVER['QUERY_STRING'] = substr( $original_url, $pos + 1 );
364
+ }
365
+
366
+ $old_values = array();
367
+ $query_array = array();
368
+ if ( isset( $_SERVER['QUERY_STRING'] ) ) {
369
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
370
+ parse_str( $_SERVER['QUERY_STRING'], $query_array );
371
+ }
372
+
373
+ if ( is_array( $query_array ) && count( $query_array ) > 0 ) {
374
+ foreach ( $query_array as $key => $value ) {
375
+ $old_values[ $key ] = '';
376
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended
377
+ if ( isset( $_REQUEST[ $key ] ) ) {
378
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
379
+ $old_values[ $key ] = $_REQUEST[ $key ];
380
+ }
381
+ // phpcs:enable WordPress.Security.NonceVerification.Recommended
382
+
383
+ $_GET[ $key ] = $value;
384
+ $_REQUEST[ $key ] = $value;
385
+ }
386
+ }
387
+
388
+ // Re-run the filter, now with original environment in place.
389
+ remove_filter( 'request', array( $this, 'parse_request' ) );
390
+ global $wp;
391
+ if ( isset( $wp->matched_rule ) ) {
392
+ $wp->matched_rule = null;
393
+ }
394
+ $wp->parse_request();
395
+ $query = $wp->query_vars;
396
+ add_filter( 'request', array( $this, 'parse_request' ) );
397
+
398
+ // Restore values.
399
+ $_SERVER['REQUEST_URI'] = $this->request_uri;
400
+ $_SERVER['QUERY_STRING'] = $this->query_string_uri;
401
+ foreach ( $old_values as $key => $value ) {
402
+ $_REQUEST[ $key ] = $value;
403
+ }
404
+ }
405
+
406
+ return $query;
407
+ }
408
+
409
+ /**
410
+ * Filters the determined post ID and change it if we have a matching URL in CP.
411
+ *
412
+ * @since 2.0.0
413
+ * @access public
414
+ *
415
+ * @param int $post_id Post ID or 0.
416
+ * @param string $oembed_url The requested URL.
417
+ *
418
+ * @return int Post ID or 0.
419
+ */
420
+ public function oembed_request( $post_id, $oembed_url ) {
421
+ global $wpdb;
422
+
423
+ /*
424
+ * First, search for a matching custom permalink, and if found
425
+ * generate the corresponding original URL.
426
+ */
427
+ $original_url = null;
428
+ $oembed_url = str_replace( home_url(), '', $oembed_url );
429
+
430
+ // Get request URI, strip parameters and /'s.
431
+ $url = wp_parse_url( get_bloginfo( 'url' ) );
432
+ $url = isset( $url['path'] ) ? $url['path'] : '';
433
+ $request = ltrim( substr( $oembed_url, strlen( $url ) ), '/' );
434
+ $pos = strpos( $request, '?' );
435
+ if ( $pos ) {
436
+ $request = substr( $request, 0, $pos );
437
+ }
438
+
439
+ if ( ! $request ) {
440
+ return $post_id;
441
+ }
442
+
443
+ $ignore = apply_filters( 'custom_permalinks_request_ignore', $request );
444
+
445
+ if ( '__true' === $ignore ) {
446
+ return $post_id;
447
+ }
448
+
449
+ if ( defined( 'POLYLANG_VERSION' ) ) {
450
+ $cp_form = new Custom_Permalinks_Form();
451
+ $request = $cp_form->check_conflicts( $request );
452
+ }
453
+ $request_no_slash = preg_replace( '@/+@', '/', trim( $request, '/' ) );
454
+ $posts = $this->query_post( $request_no_slash );
455
+
456
+ if ( $posts && $posts[0]->ID && $posts[0]->ID > 0 ) {
457
+ $post_id = $posts[0]->ID;
458
+ }
459
+
460
+ return $post_id;
461
+ }
462
+
463
+ /**
464
+ * Action to redirect to the custom permalink.
465
+ *
466
+ * @since 0.1.0
467
+ * @access public
468
+ *
469
+ * @return void
470
+ */
471
+ public function make_redirect() {
472
+ global $wpdb;
473
+
474
+ /*
475
+ * If `parse_request()` succeeded then early return to make performance
476
+ * better.
477
+ */
478
+ if ( $this->parse_request_status ) {
479
+ return;
480
+ }
481
+
482
+ if ( isset( $_SERVER['REQUEST_URI'] )
483
+ && $_SERVER['REQUEST_URI'] !== $this->request_uri
484
+ ) {
485
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
486
+ $this->request_uri = $_SERVER['REQUEST_URI'];
487
+ }
488
+
489
+ $custom_permalink = '';
490
+ $original_permalink = '';
491
+
492
+ // Get request URI, strip parameters.
493
+ $url = wp_parse_url( get_bloginfo( 'url' ) );
494
+ $url = isset( $url['path'] ) ? $url['path'] : '';
495
+ $request = ltrim( substr( $this->request_uri, strlen( $url ) ), '/' );
496
+ $pos = strpos( $request, '?' );
497
+ if ( $pos ) {
498
+ $request = substr( $request, 0, $pos );
499
+ }
500
+
501
+ /*
502
+ * Disable redirects to be processed if filter returns `true`.
503
+ *
504
+ * @since 1.7.0
505
+ */
506
+ $avoid_redirect = apply_filters(
507
+ 'custom_permalinks_avoid_redirect',
508
+ $request
509
+ );
510
+
511
+ if ( is_bool( $avoid_redirect ) && $avoid_redirect ) {
512
+ return;
513
+ }
514
+
515
+ if ( defined( 'POLYLANG_VERSION' ) ) {
516
+ $cp_form = new Custom_Permalinks_Form();
517
+ $request = $cp_form->check_conflicts( $request );
518
+ }
519
+ $request_no_slash = preg_replace( '@/+@', '/', trim( $request, '/' ) );
520
+ $posts = $this->query_post( $request_no_slash );
521
+
522
+ if ( ! isset( $posts[0]->ID ) || ! isset( $posts[0]->meta_value )
523
+ || empty( $posts[0]->meta_value )
524
+ ) {
525
+ global $wp_query;
526
+
527
+ /*
528
+ * If the post/tag/category we're on has a custom permalink, get it
529
+ * and check against the request.
530
+ */
531
+ if ( ( is_single() || is_page() ) && ! empty( $wp_query->post ) ) {
532
+ $post = $wp_query->post;
533
+ $custom_permalink = get_post_meta(
534
+ $post->ID,
535
+ 'custom_permalink',
536
+ true
537
+ );
538
+ if ( 'page' === $post->post_type ) {
539
+ $original_permalink = $this->original_page_link( $post->ID );
540
+ } else {
541
+ $original_permalink = $this->original_post_link( $post->ID );
542
+ }
543
+ } elseif ( is_tag() || is_category() ) {
544
+ $the_term = $wp_query->get_queried_object();
545
+ $custom_permalink = $this->term_permalink( $the_term->term_id );
546
+ $original_permalink = $this->original_term_link( $the_term->term_id );
547
+ }
548
+ } else {
549
+ $custom_permalink = $posts[0]->meta_value;
550
+ if ( 'page' === $posts[0]->post_type ) {
551
+ $original_permalink = $this->original_page_link( $posts[0]->ID );
552
+ } else {
553
+ $original_permalink = $this->original_post_link( $posts[0]->ID );
554
+ }
555
+ }
556
+
557
+ $custom_length = strlen( $custom_permalink );
558
+ if ( $custom_permalink
559
+ && (
560
+ substr( $request, 0, $custom_length ) !== $custom_permalink
561
+ || $request === $custom_permalink . '/'
562
+ )
563
+ ) {
564
+ // Request doesn't match permalink - redirect.
565
+ $url = $custom_permalink;
566
+ $original_length = strlen( $original_permalink );
567
+
568
+ if ( substr( $request, 0, $original_length ) === $original_permalink
569
+ && trim( $request, '/' ) !== trim( $original_permalink, '/' )
570
+ ) {
571
+ // This is the original link; we can use this url to derive the new one.
572
+ $url = preg_replace(
573
+ '@//*@',
574
+ '/',
575
+ str_replace(
576
+ trim( $original_permalink, '/' ),
577
+ trim( $custom_permalink, '/' ),
578
+ $request
579
+ )
580
+ );
581
+ $url = preg_replace( '@([^?]*)&@', '\1?', $url );
582
+ }
583
+
584
+ // Append any query compenent.
585
+ $url .= strstr( $this->request_uri, '?' );
586
+
587
+ wp_safe_redirect( home_url() . '/' . $url, 301 );
588
+ exit( 0 );
589
+ }
590
+ }
591
+
592
+ /**
593
+ * Filter to replace the post permalink with the custom one.
594
+ *
595
+ * @access public
596
+ *
597
+ * @param string $permalink Default WordPress Permalink of Post.
598
+ * @param object $post Post Details.
599
+ *
600
+ * @return string customized Post Permalink.
601
+ */
602
+ public function custom_post_link( $permalink, $post ) {
603
+ $custom_permalink = get_post_meta( $post->ID, 'custom_permalink', true );
604
+ if ( $custom_permalink ) {
605
+ $post_type = 'post';
606
+ if ( isset( $post->post_type ) ) {
607
+ $post_type = $post->post_type;
608
+ }
609
+
610
+ $language_code = apply_filters(
611
+ 'wpml_element_language_code',
612
+ null,
613
+ array(
614
+ 'element_id' => $post->ID,
615
+ 'element_type' => $post_type,
616
+ )
617
+ );
618
+
619
+ $permalink = $this->wpml_permalink_filter(
620
+ $custom_permalink,
621
+ $language_code
622
+ );
623
+ } else {
624
+ if ( class_exists( 'SitePress' ) ) {
625
+ $wpml_lang_format = apply_filters(
626
+ 'wpml_setting',
627
+ 0,
628
+ 'language_negotiation_type'
629
+ );
630
+
631
+ if ( 1 === intval( $wpml_lang_format ) ) {
632
+ $get_original_url = $this->original_post_link( $post->ID );
633
+ $permalink = $this->remove_double_slash( $permalink );
634
+ if ( strlen( $get_original_url ) === strlen( $permalink ) ) {
635
+ $permalink = $get_original_url;
636
+ }
637
+ }
638
+ }
639
+ }
640
+
641
+ $permalink = $this->remove_double_slash( $permalink );
642
+
643
+ return $permalink;
644
+ }
645
+
646
+ /**
647
+ * Filter to replace the page permalink with the custom one.
648
+ *
649
+ * @access public
650
+ *
651
+ * @param string $permalink Default WordPress Permalink of Page.
652
+ * @param int $page Page ID.
653
+ *
654
+ * @return string customized Page Permalink.
655
+ */
656
+ public function custom_page_link( $permalink, $page ) {
657
+ $custom_permalink = get_post_meta( $page, 'custom_permalink', true );
658
+ if ( $custom_permalink ) {
659
+ $language_code = apply_filters(
660
+ 'wpml_element_language_code',
661
+ null,
662
+ array(
663
+ 'element_id' => $page,
664
+ 'element_type' => 'page',
665
+ )
666
+ );
667
+
668
+ $permalink = $this->wpml_permalink_filter(
669
+ $custom_permalink,
670
+ $language_code
671
+ );
672
+ } else {
673
+ if ( class_exists( 'SitePress' ) ) {
674
+ $wpml_lang_format = apply_filters(
675
+ 'wpml_setting',
676
+ 0,
677
+ 'language_negotiation_type'
678
+ );
679
+
680
+ if ( 1 === intval( $wpml_lang_format ) ) {
681
+ $get_original_url = $this->original_page_link( $page );
682
+ $permalink = $this->remove_double_slash( $permalink );
683
+ if ( strlen( $get_original_url ) === strlen( $permalink ) ) {
684
+ $permalink = $get_original_url;
685
+ }
686
+ }
687
+ }
688
+ }
689
+
690
+ $permalink = $this->remove_double_slash( $permalink );
691
+
692
+ return $permalink;
693
+ }
694
+
695
+ /**
696
+ * Filter to replace the term permalink with the custom one.
697
+ *
698
+ * @access public
699
+ *
700
+ * @param string $permalink Term link URL.
701
+ * @param object $term Term object.
702
+ *
703
+ * @return string customized Term Permalink.
704
+ */
705
+ public function custom_term_link( $permalink, $term ) {
706
+ if ( isset( $term ) ) {
707
+ if ( isset( $term->term_id ) ) {
708
+ $custom_permalink = $this->term_permalink( $term->term_id );
709
+ }
710
+
711
+ if ( $custom_permalink ) {
712
+ $language_code = null;
713
+ if ( isset( $term->term_taxonomy_id ) ) {
714
+ $term_type = 'category';
715
+ if ( isset( $term->taxonomy ) ) {
716
+ $term_type = $term->taxonomy;
717
+ }
718
+
719
+ $language_code = apply_filters(
720
+ 'wpml_element_language_code',
721
+ null,
722
+ array(
723
+ 'element_id' => $term->term_taxonomy_id,
724
+ 'element_type' => $term_type,
725
+ )
726
+ );
727
+ }
728
+
729
+ $permalink = $this->wpml_permalink_filter(
730
+ $custom_permalink,
731
+ $language_code
732
+ );
733
+ } elseif ( isset( $term->term_id ) ) {
734
+ if ( class_exists( 'SitePress' ) ) {
735
+ $wpml_lang_format = apply_filters(
736
+ 'wpml_setting',
737
+ 0,
738
+ 'language_negotiation_type'
739
+ );
740
+
741
+ if ( 1 === intval( $wpml_lang_format ) ) {
742
+ $get_original_url = $this->original_term_link(
743
+ $term->term_id
744
+ );
745
+ $permalink = $this->remove_double_slash( $permalink );
746
+ if ( strlen( $get_original_url ) === strlen( $permalink ) ) {
747
+ $permalink = $get_original_url;
748
+ }
749
+ }
750
+ }
751
+ }
752
+ }
753
+
754
+ $permalink = $this->remove_double_slash( $permalink );
755
+
756
+ return $permalink;
757
+ }
758
+
759
+ /**
760
+ * Remove the post_link and user_trailingslashit filter to get the original
761
+ * permalink of the default and custom post type and apply right after that.
762
+ *
763
+ * @access public
764
+ *
765
+ * @param int $post_id Post ID.
766
+ *
767
+ * @return string Original Permalink for Posts.
768
+ */
769
+ public function original_post_link( $post_id ) {
770
+ remove_filter( 'post_link', array( $this, 'custom_post_link' ) );
771
+ remove_filter( 'post_type_link', array( $this, 'custom_post_link' ) );
772
+
773
+ $post_file_path = ABSPATH . '/wp-admin/includes/post.php';
774
+ include_once $post_file_path;
775
+
776
+ list( $permalink, $post_name ) = get_sample_permalink( $post_id );
777
+ $permalink = str_replace(
778
+ array( '%pagename%', '%postname%' ),
779
+ $post_name,
780
+ $permalink
781
+ );
782
+ $permalink = ltrim( str_replace( home_url(), '', $permalink ), '/' );
783
+
784
+ add_filter( 'post_link', array( $this, 'custom_post_link' ), 10, 3 );
785
+ add_filter( 'post_type_link', array( $this, 'custom_post_link' ), 10, 2 );
786
+
787
+ return $permalink;
788
+ }
789
+
790
+ /**
791
+ * Remove the page_link and user_trailingslashit filter to get the original
792
+ * permalink of the page and apply right after that.
793
+ *
794
+ * @access public
795
+ *
796
+ * @param int $post_id Page ID.
797
+ *
798
+ * @return string Original Permalink for the Page.
799
+ */
800
+ public function original_page_link( $post_id ) {
801
+ remove_filter( 'page_link', array( $this, 'custom_page_link' ) );
802
+ remove_filter(
803
+ 'user_trailingslashit',
804
+ array( $this, 'custom_trailingslash' )
805
+ );
806
+
807
+ $post_file_path = ABSPATH . '/wp-admin/includes/post.php';
808
+ include_once $post_file_path;
809
+
810
+ list( $permalink, $post_name ) = get_sample_permalink( $post_id );
811
+ $permalink = str_replace(
812
+ array( '%pagename%', '%postname%' ),
813
+ $post_name,
814
+ $permalink
815
+ );
816
+ $permalink = ltrim( str_replace( home_url(), '', $permalink ), '/' );
817
+
818
+ add_filter( 'user_trailingslashit', array( $this, 'custom_trailingslash' ) );
819
+ add_filter( 'page_link', array( $this, 'custom_page_link' ), 10, 2 );
820
+
821
+ return $permalink;
822
+ }
823
+
824
+ /**
825
+ * Remove the term_link and user_trailingslashit filter to get the original
826
+ * permalink of the Term and apply right after that.
827
+ *
828
+ * @since 1.6.0
829
+ * @access public
830
+ *
831
+ * @param int $term_id Term ID.
832
+ *
833
+ * @return string Original Permalink for Posts.
834
+ */
835
+ public function original_term_link( $term_id ) {
836
+ remove_filter( 'term_link', array( $this, 'custom_term_link' ) );
837
+ remove_filter(
838
+ 'user_trailingslashit',
839
+ array( $this, 'custom_trailingslash' )
840
+ );
841
+
842
+ $term = get_term( $term_id );
843
+ $term_link = get_term_link( $term );
844
+
845
+ add_filter( 'user_trailingslashit', array( $this, 'custom_trailingslash' ) );
846
+ add_filter( 'term_link', array( $this, 'custom_term_link' ), 10, 2 );
847
+
848
+ if ( is_wp_error( $term_link ) ) {
849
+ return '';
850
+ }
851
+
852
+ $original_permalink = ltrim( str_replace( home_url(), '', $term_link ), '/' );
853
+
854
+ return $original_permalink;
855
+ }
856
+
857
+ /**
858
+ * Filter to handle trailing slashes correctly.
859
+ *
860
+ * @access public
861
+ *
862
+ * @param string $url_string URL with or without a trailing slash.
863
+ *
864
+ * @return string Adds/removes a trailing slash based on the permalink structure.
865
+ */
866
+ public function custom_trailingslash( $url_string ) {
867
+ remove_filter(
868
+ 'user_trailingslashit',
869
+ array( $this, 'custom_trailingslash' )
870
+ );
871
+
872
+ $trailingslash_string = $url_string;
873
+ $url = wp_parse_url( get_bloginfo( 'url' ) );
874
+
875
+ if ( isset( $url['path'] ) ) {
876
+ $request = substr( $url_string, strlen( $url['path'] ) );
877
+ } else {
878
+ $request = $url_string;
879
+ }
880
+
881
+ $request = ltrim( $request, '/' );
882
+
883
+ add_filter( 'user_trailingslashit', array( $this, 'custom_trailingslash' ) );
884
+
885
+ if ( trim( $request ) ) {
886
+ if ( trim( $this->registered_url, '/' ) === trim( $request, '/' ) ) {
887
+ if ( '/' === $url_string[0] ) {
888
+ $trailingslash_string = '/';
889
+ } else {
890
+ $trailingslash_string = '';
891
+ }
892
+
893
+ if ( isset( $url['path'] ) ) {
894
+ $trailingslash_string .= trailingslashit( $url['path'] );
895
+ }
896
+
897
+ $trailingslash_string .= $this->registered_url;
898
+ }
899
+ }
900
+
901
+ return $trailingslash_string;
902
+ }
903
+
904
+ /**
905
+ * Get permalink for term.
906
+ *
907
+ * @access public
908
+ *
909
+ * @param int $term_id Term id.
910
+ *
911
+ * @return bool Term link.
912
+ */
913
+ public function term_permalink( $term_id ) {
914
+ $table = get_option( 'custom_permalink_table' );
915
+ if ( $table ) {
916
+ foreach ( $table as $link => $info ) {
917
+ if ( $info['id'] === $term_id ) {
918
+ return $link;
919
+ }
920
+ }
921
+ }
922
+
923
+ return false;
924
+ }
925
+
926
+ /**
927
+ * Fix double slash issue with canonical of Yoast SEO specially with WPML.
928
+ *
929
+ * @since 1.6.0
930
+ * @access public
931
+ *
932
+ * @param string $canonical The canonical.
933
+ *
934
+ * @return string the canonical after removing double slash if exist.
935
+ */
936
+ public function fix_canonical_double_slash( $canonical ) {
937
+ $canonical = $this->remove_double_slash( $canonical );
938
+
939
+ return $canonical;
940
+ }
941
+ }
includes/class-custom-permalinks.php ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Custom Permalinks setup.
4
+ *
5
+ * @package CustomPermalinks
6
+ */
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
10
+ }
11
+
12
+ /**
13
+ * Main Custom Permalinks class.
14
+ */
15
+ class Custom_Permalinks {
16
+ /**
17
+ * Custom Permalinks version.
18
+ *
19
+ * @var string
20
+ */
21
+ public $version = '2.0.0';
22
+
23
+ /**
24
+ * Class constructor.
25
+ */
26
+ public function __construct() {
27
+ $this->define_constants();
28
+ $this->includes();
29
+ $this->init_hooks();
30
+ }
31
+
32
+ /**
33
+ * Define Custom Permalinks Constants.
34
+ *
35
+ * @since 2.0.0
36
+ * @access private
37
+ */
38
+ private function define_constants() {
39
+ $this->define( 'CUSTOM_PERMALINKS_BASENAME', plugin_basename( CUSTOM_PERMALINKS_FILE ) );
40
+ $this->define( 'CUSTOM_PERMALINKS_PATH', plugin_dir_path( CUSTOM_PERMALINKS_FILE ) );
41
+ $this->define( 'CUSTOM_PERMALINKS_VERSION', $this->version );
42
+ }
43
+
44
+ /**
45
+ * Define constant if not set already.
46
+ *
47
+ * @since 2.0.0
48
+ * @access private
49
+ *
50
+ * @param string $name Constant name.
51
+ * @param string|bool $value Constant value.
52
+ */
53
+ private function define( $name, $value ) {
54
+ if ( ! defined( $name ) ) {
55
+ define( $name, $value );
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Include required core files used in admin and on the frontend.
61
+ *
62
+ * @since 1.2.18
63
+ * @access private
64
+ */
65
+ private function includes() {
66
+ include_once CUSTOM_PERMALINKS_PATH . 'includes/class-custom-permalinks-form.php';
67
+ include_once CUSTOM_PERMALINKS_PATH . 'includes/class-custom-permalinks-frontend.php';
68
+ include_once CUSTOM_PERMALINKS_PATH . 'admin/class-custom-permalinks-admin.php';
69
+ include_once CUSTOM_PERMALINKS_PATH . 'admin/class-custom-permalinks-post-types.php';
70
+ include_once CUSTOM_PERMALINKS_PATH . 'admin/class-custom-permalinks-post-types-table.php';
71
+ include_once CUSTOM_PERMALINKS_PATH . 'admin/class-custom-permalinks-taxonomies.php';
72
+ include_once CUSTOM_PERMALINKS_PATH . 'admin/class-custom-permalinks-taxonomies-table.php';
73
+
74
+ $cp_form = new Custom_Permalinks_Form();
75
+ $cp_form->init();
76
+
77
+ $cp_frontend = new Custom_Permalinks_Frontend();
78
+ $cp_frontend->init();
79
+ }
80
+
81
+ /**
82
+ * Hook into actions and filters.
83
+ *
84
+ * @since 2.0.0
85
+ * @access private
86
+ */
87
+ private function init_hooks() {
88
+ register_activation_hook(
89
+ CUSTOM_PERMALINKS_FILE,
90
+ array( 'Custom_Permalinks', 'add_roles' )
91
+ );
92
+
93
+ register_activation_hook(
94
+ CUSTOM_PERMALINKS_FILE,
95
+ array( 'Custom_Permalinks', 'activate_details' )
96
+ );
97
+
98
+ register_deactivation_hook(
99
+ CUSTOM_PERMALINKS_FILE,
100
+ array( 'Custom_Permalinks', 'deactivate_details' )
101
+ );
102
+
103
+ add_action( 'plugins_loaded', array( $this, 'check_loaded_plugins' ) );
104
+ }
105
+
106
+ /**
107
+ * Add role for the view post and category permalinks and by default assign
108
+ * it to the administrator if administrator role exist.
109
+ *
110
+ * @since 1.2.22
111
+ * @access public
112
+ */
113
+ public static function add_roles() {
114
+ $admin_role = get_role( 'administrator' );
115
+ $cp_role = get_role( 'custom_permalinks_manager' );
116
+ $current_version = get_option( 'custom_permalinks_plugin_version', -1 );
117
+
118
+ if ( ! empty( $admin_role ) ) {
119
+ $admin_role->add_cap( 'cp_view_post_permalinks' );
120
+ $admin_role->add_cap( 'cp_view_category_permalinks' );
121
+ }
122
+
123
+ if ( empty( $cp_role ) ) {
124
+ add_role(
125
+ 'custom_permalinks_manager',
126
+ __( 'Custom Permalinks Manager' ),
127
+ array(
128
+ 'cp_view_post_permalinks' => true,
129
+ 'cp_view_category_permalinks' => true,
130
+ )
131
+ );
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Sent details when plugin gets activated / updated ans set installed
137
+ * version in options table.
138
+ *
139
+ * @since 1.6.1
140
+ * @access public
141
+ */
142
+ public static function activate_details() {
143
+ include_once CUSTOM_PERMALINKS_PATH . 'admin/class-custom-permalinks-updates.php';
144
+ new Custom_Permalinks_Updates( 'activate' );
145
+
146
+ update_option( 'custom_permalinks_plugin_version', CUSTOM_PERMALINKS_VERSION );
147
+ }
148
+
149
+ /**
150
+ * Sent details when plugin gets deactivated.
151
+ *
152
+ * @since 1.6.1
153
+ * @access public
154
+ */
155
+ public function deactivate_details() {
156
+ include_once CUSTOM_PERMALINKS_PATH . 'admin/class-custom-permalinks-updates.php';
157
+ new Custom_Permalinks_Updates( 'deactivate' );
158
+ }
159
+
160
+ /**
161
+ * Check if role not exist then call the function to add it. Update site
162
+ * details if plugin gets updated. Also, loads the plugin language files to
163
+ * support different languages.
164
+ *
165
+ * @since 1.2.18
166
+ * @access public
167
+ */
168
+ public function check_loaded_plugins() {
169
+ if ( is_admin() ) {
170
+ $current_version = get_option( 'custom_permalinks_plugin_version', -1 );
171
+
172
+ if ( -1 === $current_version
173
+ || $current_version < CUSTOM_PERMALINKS_VERSION
174
+ ) {
175
+ self::activate_details();
176
+ self::add_roles();
177
+ }
178
+ }
179
+
180
+ load_plugin_textdomain(
181
+ 'custom-permalinks',
182
+ false,
183
+ basename( dirname( CUSTOM_PERMALINKS_FILE ) ) . '/languages/'
184
+ );
185
+ }
186
+ }
187
+
188
+ new Custom_Permalinks();
{frontend → includes}/index.php RENAMED
File without changes
languages/index.php CHANGED
@@ -1,4 +1,4 @@
1
  <?php
2
  /**
3
  * Silence is golden
4
- */
1
  <?php
2
  /**
3
  * Silence is golden
4
+ */
readme.txt CHANGED
@@ -1,16 +1,17 @@
1
  === Custom Permalinks ===
2
  Contributors: sasiddiqui, michaeltyson
3
  Tags: permalink, url, link, address, custom, redirect, custom post type, GDPR, GDPR Compliant
4
- Requires at least: 2.6
5
- Tested up to: 5.5
6
- Stable tag: 1.7.1
7
  License: GPLv3
8
- License URI: https://www.gnu.org/licenses/gpl.html
9
 
10
  Set custom permalinks on a per-post, per-tag or per-category basis.
11
 
12
  == Description ==
13
 
 
 
14
  Lay out your site the way *you* want it. Set the URL of any post, page, tag or category to anything you want. Old permalinks will redirect properly to the new address. Custom Permalinks give you ultimate control over your site structure.
15
 
16
  > Be warned: *This plugin is not a replacement for WordPress's built-in permalink system*. Check your WordPress administration's "Permalinks" settings page first, to make sure that this doesn't already meet your needs.
@@ -19,25 +20,6 @@ This plugin is only useful for assigning custom permalinks for *individual* post
19
 
20
  > If anyone wants the different Structure Tags for their Post types or use symbols in the URLs So, use the [Permalinks Customizer](https://wordpress.org/plugins/permalinks-customizer/) which is a fork of this plugin and contains the enhancement of this plugin.
21
 
22
- === Unsupported Characters ===
23
-
24
- Following characters are no longer allowed in the permalinks.
25
-
26
- * `<`
27
- * `>`
28
- * `{`
29
- * `}`
30
- * `|`
31
- * <code>`</code>
32
- * `^`
33
- * `\`
34
- * `(`
35
- * `)`
36
- * `[`
37
- * `]`
38
-
39
- > Permalinks created previously using any of these characters will not be affected in anyway. However, new permalinks will not support the use of these characters as they are not considered to be safe.
40
-
41
  == Privacy Policy ==
42
 
43
  This plugin only collects the following information.
@@ -60,47 +42,44 @@ To have any kind of query please feel free to [contact us](https://www.customper
60
  add_filter( 'custom_permalinks_path_info', '__return_true' );
61
  `
62
 
63
- === Disable redirects ===
64
 
65
  To disable complete redirects functionality provided by this plugin, add the filter that looks like this:
66
 
67
  `
68
- function yasglobal_avoid_redirect( $permalink )
69
- {
70
- return true;
71
  }
72
  add_filter( 'custom_permalinks_avoid_redirect', 'yasglobal_avoid_redirect' );
73
  `
74
 
75
- === Disable specific redirects ===
76
 
77
  To disable any specific redirect to be processed by this plugin, add the filter that looks like this:
78
 
79
  `
80
- function yasglobal_avoid_redirect( $permalink )
81
- {
82
- // Replace 'testing-hello-world/' with the permalink you want to avoid
83
- if ( 'testing-hello-world/' === $permalink ) {
84
- return true;
85
- }
86
 
87
- return false;
88
  }
89
  add_filter( 'custom_permalinks_avoid_redirect', 'yasglobal_avoid_redirect' );
90
  `
91
 
92
- === Exclude permalink to be processed ===
93
 
94
  To exclude any Permalink to be processed by the plugin, add the filter that looks like this:
95
 
96
  `
97
- function yasglobal_xml_sitemap_url( $permalink )
98
- {
99
- if ( false !== strpos( $permalink, 'sitemap.xml' ) ) {
100
- return '__true';
101
- }
102
 
103
- return;
104
  }
105
  add_filter( 'custom_permalinks_request_ignore', 'yasglobal_xml_sitemap_url' );
106
  `
@@ -110,35 +89,61 @@ add_filter( 'custom_permalinks_request_ignore', 'yasglobal_xml_sitemap_url' );
110
  To remove custom permalink **form** from any post type, add the filter that looks like this:
111
 
112
  `
113
- function yasglobal_exclude_post_types( $post_type )
114
- {
115
- // Replace 'custompost' with your post type name
116
- if ( 'custompost' === $post_type ) {
117
- return '__true';
118
- }
119
 
120
- return '__false';
121
  }
122
  add_filter( 'custom_permalinks_exclude_post_type', 'yasglobal_exclude_post_types' );
123
  `
124
 
125
  === Exclude Posts ===
126
 
127
- To exclude custom permalink **form** from any posts (based on ID, Template, etc), add the filter that looks like this:
128
 
129
  `
130
- function yasglobal_exclude_posts( $post )
131
- {
132
- if ( 1557 === $post->ID ) {
133
- return true;
134
- }
135
 
136
- return false;
137
  }
138
  add_filter( 'custom_permalinks_exclude_posts', 'yasglobal_exclude_posts' );
139
  `
140
 
141
- === Remove `like` query ===
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
 
143
  To remove `like` query to being work, add below-mentioned line in your theme `functions.php`:
144
  `
@@ -149,8 +154,7 @@ Note: Use `custom_permalinks_like_query` filter if the URLs doesn't works for yo
149
 
150
  === Thanks for the Support ===
151
 
152
- I do not always provide active support for the Custom Permalinks plugin on the WordPress.org forums, as I have prioritized the email support.
153
- One-on-one email support is available to people who bought [Custom Permalinks Premium](https://www.custompermalinks.com/#pricing-section) only.
154
 
155
  === Bug reports ===
156
 
@@ -173,51 +177,30 @@ This process defines you the steps to follow either you are installing through W
173
 
174
  == Changelog ==
175
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
  = 1.7.1 - Aug 30, 2020 =
177
 
178
  * Bugs
179
  * Fix PHP notice (start reporting with WordPress 5.5)
180
 
181
- = 1.7.0 - Aug 20, 2020 =
182
-
183
- * Bugs
184
- * [Paged NextGen Galleries Broken with Custom Permalinks 1.62](https://github.com/samiahmedsiddiqui/custom-permalinks/issues/38)
185
- * [custom permalink issue with weglot](https://wordpress.org/support/topic/custom-permalink-issue-with-weglot/)
186
- * [Permalinks reverting back to old ones](https://wordpress.org/support/topic/permalinks-reverting-back-to-old-ones/)
187
- * [A problem with wrongly deleted permalinks](https://wordpress.org/support/topic/a-problem-with-wrongly-deleted-permalinks/)
188
- * Enhancements
189
- * [Enhanced security through characters restriction](https://github.com/samiahmedsiddiqui/custom-permalinks#unsupported-characters)
190
- * Introduce filter to disable specific redirect(s) or complete functionality
191
- * Automatic replacement of upper case letters to lower case
192
-
193
- = 1.6.2 - Aug 10, 2020 =
194
-
195
- * Bugs
196
- * Forgot to update the version in CSS and JS files in `v1.6.1`
197
-
198
- = 1.6.1 - Aug 10, 2020 =
199
-
200
- * Bugs
201
- * Avoid caching issue by adding version as suffix in CSS and JS files
202
-
203
- = 1.6.0 - Aug 08, 2020 =
204
-
205
- * Bugs
206
- * [Undefined index and undefined variable error](https://github.com/samiahmedsiddiqui/custom-permalinks/issues/28)
207
- * [count(): Parameter must be an array or an object](https://github.com/samiahmedsiddiqui/custom-permalinks/issues/27)
208
- * Fix double slash from the permalink form
209
- * [use 'view_item' label for previewing custom post types](https://github.com/samiahmedsiddiqui/custom-permalinks/issues/31)
210
- * [Fix PHP 7.4 issues](https://github.com/samiahmedsiddiqui/custom-permalinks/issues/32)
211
- * Fix Yoast Canonical double slash issue
212
- * [Replacing category_link with term_link](https://github.com/samiahmedsiddiqui/custom-permalinks/issues/34)
213
- * [Bug with WPML and Use directory for default language](https://github.com/samiahmedsiddiqui/custom-permalinks/issues/36)
214
- * Fix Static Homepage redirect issue
215
- * Enhancements
216
- * Improved Gutenberg Support
217
- * Added compatibility for WPML language switcher
218
- * Add filter to exclude Custom Permalinks for certain posts (based on Post IDs, template, etc)
219
- * Optimized Code
220
-
221
  = Earlier versions =
222
 
223
  * For the changelog of earlier versions, please refer to the separate changelog.txt file.
1
  === Custom Permalinks ===
2
  Contributors: sasiddiqui, michaeltyson
3
  Tags: permalink, url, link, address, custom, redirect, custom post type, GDPR, GDPR Compliant
4
+ Tested up to: 5.8
5
+ Stable tag: 2.0.0
 
6
  License: GPLv3
7
+ License URI: https://www.gnu.org/licenses/gpl-3.0.html
8
 
9
  Set custom permalinks on a per-post, per-tag or per-category basis.
10
 
11
  == Description ==
12
 
13
+ > Incase of found any site breaking issue after upgrading to the latest version then please report the issue on [WordPress Forum](https://wordpress.org/support/plugin/custom-permalinks/) OR [GitHub](https://github.com/samiahmedsiddiqui/custom-permalinks) with complete information to reproduce the issue and move back to the old version. You can download any of the old version from here: https://wordpress.org/plugins/custom-permalinks/advanced/
14
+
15
  Lay out your site the way *you* want it. Set the URL of any post, page, tag or category to anything you want. Old permalinks will redirect properly to the new address. Custom Permalinks give you ultimate control over your site structure.
16
 
17
  > Be warned: *This plugin is not a replacement for WordPress's built-in permalink system*. Check your WordPress administration's "Permalinks" settings page first, to make sure that this doesn't already meet your needs.
20
 
21
  > If anyone wants the different Structure Tags for their Post types or use symbols in the URLs So, use the [Permalinks Customizer](https://wordpress.org/plugins/permalinks-customizer/) which is a fork of this plugin and contains the enhancement of this plugin.
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  == Privacy Policy ==
24
 
25
  This plugin only collects the following information.
42
  add_filter( 'custom_permalinks_path_info', '__return_true' );
43
  `
44
 
45
+ === Disable Redirects ===
46
 
47
  To disable complete redirects functionality provided by this plugin, add the filter that looks like this:
48
 
49
  `
50
+ function yasglobal_avoid_redirect( $permalink ) {
51
+ return true;
 
52
  }
53
  add_filter( 'custom_permalinks_avoid_redirect', 'yasglobal_avoid_redirect' );
54
  `
55
 
56
+ === Disable Particular Redirects ===
57
 
58
  To disable any specific redirect to be processed by this plugin, add the filter that looks like this:
59
 
60
  `
61
+ function yasglobal_avoid_redirect( $permalink ) {
62
+ // Replace 'testing-hello-world/' with the permalink you want to avoid
63
+ if ( 'testing-hello-world/' === $permalink ) {
64
+ return true;
65
+ }
 
66
 
67
+ return false;
68
  }
69
  add_filter( 'custom_permalinks_avoid_redirect', 'yasglobal_avoid_redirect' );
70
  `
71
 
72
+ === Exclude Permalink to be processed ===
73
 
74
  To exclude any Permalink to be processed by the plugin, add the filter that looks like this:
75
 
76
  `
77
+ function yasglobal_xml_sitemap_url( $permalink ) {
78
+ if ( false !== strpos( $permalink, 'sitemap.xml' ) ) {
79
+ return '__true';
80
+ }
 
81
 
82
+ return;
83
  }
84
  add_filter( 'custom_permalinks_request_ignore', 'yasglobal_xml_sitemap_url' );
85
  `
89
  To remove custom permalink **form** from any post type, add the filter that looks like this:
90
 
91
  `
92
+ function yasglobal_exclude_post_types( $post_type ) {
93
+ // Replace 'custompost' with your post type name
94
+ if ( 'custompost' === $post_type ) {
95
+ return '__true';
96
+ }
 
97
 
98
+ return '__false';
99
  }
100
  add_filter( 'custom_permalinks_exclude_post_type', 'yasglobal_exclude_post_types' );
101
  `
102
 
103
  === Exclude Posts ===
104
 
105
+ To exclude custom permalink **form** from any posts (based on ID, Template, etc), add the filter that looks like this:
106
 
107
  `
108
+ function yasglobal_exclude_posts( $post ) {
109
+ if ( 1557 === $post->ID ) {
110
+ return true;
111
+ }
 
112
 
113
+ return false;
114
  }
115
  add_filter( 'custom_permalinks_exclude_posts', 'yasglobal_exclude_posts' );
116
  `
117
 
118
+ === Allow Uppercase Letters ===
119
+
120
+ To allow uppercase letters/words, please add below-mentioned line in your theme `functions.php`:
121
+
122
+ `
123
+ function yasglobal_allow_uppercaps() {
124
+ return true;
125
+ }
126
+ add_filter( 'custom_permalinks_allow_caps', 'yasglobal_allow_uppercaps' );
127
+ `
128
+
129
+ === Manipulate Permalink Before Saving ===
130
+
131
+ To make changes in permalink before saving, please use `custom_permalink_before_saving` filter. Here is an example to see how it works.
132
+
133
+ `
134
+ function yasglobal_permalink_before_saving( $permalink, $post_id ) {
135
+ // Check trialing slash in the permalink.
136
+ if ( substr( $permalink, -1 ) !== '/' ) {
137
+ // If permalink doesn't contain trialing slash then add one.
138
+ $permalink .= '/';
139
+ }
140
+
141
+ return $permalink;
142
+ }
143
+ add_filter( 'custom_permalink_before_saving', 'yasglobal_permalink_before_saving', 10, 2 );
144
+ `
145
+
146
+ === Remove `like` Query ===
147
 
148
  To remove `like` query to being work, add below-mentioned line in your theme `functions.php`:
149
  `
154
 
155
  === Thanks for the Support ===
156
 
157
+ I do not always provide active support for the Custom Permalinks plugin on the WordPress.org forums, as I have prioritized the email support. One-on-one email support is available to people who bought [Custom Permalinks Premium](https://www.custompermalinks.com/#pricing-section) only.
 
158
 
159
  === Bug reports ===
160
 
177
 
178
  == Changelog ==
179
 
180
+ = 2.0.0 - Jul 30, 2021 =
181
+
182
+ * Bugs
183
+ * [Bug with AMP plugin](https://wordpress.org/support/topic/bug-with-amp-plugin/)
184
+ * [Oembed links not working](https://wordpress.org/support/topic/oembed-links-not-working/)
185
+ * [Uncaught (in promise) TypeError: getHomeURL is null](https://wordpress.org/support/topic/uncaught-in-promise-typeerror-gethomeurl-is-null/)
186
+ * [Plugin stop saving uppercase slugs](https://wordpress.org/support/topic/plugin-stop-saving-upppercase-slugs/)
187
+ * [template_redirect](https://wordpress.org/support/topic/make-redirect/)
188
+ * conflict with WooCommerce Paid courses
189
+ * Fix creating duplicated permalink while creating multiple `Categories` and/or `Tags`
190
+ * Enhancements
191
+ * Added Query caching to improve performance
192
+ * Changed Permalink sanitization method (Similar way as WP does)
193
+ * Added Nonce verification to make forms secure
194
+ * [Permalink Filter before saving](https://wordpress.org/support/topic/permalink-filter/)
195
+ * Show/Hide column and Pagination features added on Post Type Permalinks and Taxonomies Permalinks page
196
+ * Removed deprecated functions
197
+ * Applied WPCS Standards
198
+
199
  = 1.7.1 - Aug 30, 2020 =
200
 
201
  * Bugs
202
  * Fix PHP notice (start reporting with WordPress 5.5)
203
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
204
  = Earlier versions =
205
 
206
  * For the changelog of earlier versions, please refer to the separate changelog.txt file.
uninstall.php CHANGED
@@ -9,25 +9,25 @@
9
  */
10
 
11
  if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
12
- exit;
13
  }
14
 
15
  delete_post_meta_by_key( 'custom_permalink' );
16
  delete_option( 'custom_permalink_table' );
17
 
18
- $role = get_role( 'administrator' );
19
- if ( ! empty( $role ) ) {
20
- $role->remove_cap( 'cp_view_post_permalinks' );
21
- $role->remove_cap( 'cp_view_category_permalinks' );
22
  }
23
 
24
- $role = get_role( 'custom_permalinks_manager' );
25
- if ( ! empty( $role ) ) {
26
- $role->remove_cap( 'cp_view_post_permalinks' );
27
- $role->remove_cap( 'cp_view_category_permalinks' );
28
 
29
- remove_role( 'custom_permalinks_manager' );
30
  }
31
 
32
- // Clear any cached data that has been removed
33
  wp_cache_flush();
9
  */
10
 
11
  if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
12
+ exit;
13
  }
14
 
15
  delete_post_meta_by_key( 'custom_permalink' );
16
  delete_option( 'custom_permalink_table' );
17
 
18
+ $wp_role = get_role( 'administrator' );
19
+ if ( ! empty( $wp_role ) ) {
20
+ $wp_role->remove_cap( 'cp_view_post_permalinks' );
21
+ $wp_role->remove_cap( 'cp_view_category_permalinks' );
22
  }
23
 
24
+ $wp_role = get_role( 'custom_permalinks_manager' );
25
+ if ( ! empty( $wp_role ) ) {
26
+ $wp_role->remove_cap( 'cp_view_post_permalinks' );
27
+ $wp_role->remove_cap( 'cp_view_category_permalinks' );
28
 
29
+ remove_role( 'custom_permalinks_manager' );
30
  }
31
 
32
+ // Clear any cached data that has been removed.
33
  wp_cache_flush();