PluginProbe ʕ •ᴥ•ʔ
Permalink Manager Lite / 2.4.0
Permalink Manager Lite v2.4.0
2.6.0 2.5.5 2.5.4 2.5.3.4 2.2.18 2.2.19.2 2.2.19.3 2.2.19.3.1 2.2.2 2.2.20 2.2.20.1 2.2.20.3 2.2.4 2.2.5 2.2.6 2.2.7.2 2.2.7.3 2.2.7.5 2.2.7.6 2.2.8.4 2.2.8.5 2.2.8.6 2.2.8.7 2.2.8.9 2.2.9.1 2.2.9.2 2.2.9.2.1 2.2.9.3 2.2.9.4 2.2.9.6 2.2.9.7 2.2.9.9 2.3.0 2.3.1.1 2.4.0 2.4.1 2.4.1.2 2.4.1.3 2.4.1.4 2.4.1.5 2.4.1.6 2.4.2 2.4.2.1 2.4.3 2.4.3.1 2.4.3.2 2.4.3.3 2.4.3.4 2.4.4 2.4.4.1 2.4.4.2 2.4.4.3 2.5.0 2.5.1 2.5.1.1 2.5.1.2 2.5.1.3 2.5.1.4 2.5.2 2.5.2.1 2.5.2.2 2.5.2.3 2.5.2.4 2.5.3 2.5.3.1 2.5.3.2 2.5.3.3 trunk 0.2 0.3 0.3.1 0.3.2 0.3.3 0.3.4 0.4 0.4.1 0.4.2 0.4.3 0.4.4 0.4.6 0.4.7 0.4.8 0.4.9 0.5.3 0.5.4 1.0.0 1.0.1 1.0.4 1.1.0 1.1.1 1.1.2 1.11.6.3 2.0.0 2.0.3 2.0.4 2.0.4.3 2.0.5.1 2.0.5.2 2.0.5.3 2.0.5.3.1 2.0.5.4 2.0.5.4a 2.0.5.5 2.0.5.6 2.0.5.6.1 2.0.5.7 2.0.5.9a 2.0.6.2.1 2.0.6.2a 2.0.6.3 2.1.0 2.1.1 2.1.2.4 2.2.0 2.2.1.1 2.2.1.2 2.2.11 2.2.12 2.2.13.1 2.2.14 2.2.15.1 2.2.16 2.2.17
permalink-manager / includes / core / permalink-manager-third-parties.php
permalink-manager / includes / core Last commit date
permalink-manager-actions.php 3 years ago permalink-manager-admin-functions.php 3 years ago permalink-manager-core-functions.php 3 years ago permalink-manager-debug.php 3 years ago permalink-manager-gutenberg.php 3 years ago permalink-manager-helper-functions.php 3 years ago permalink-manager-language-plugins.php 3 years ago permalink-manager-third-parties.php 3 years ago permalink-manager-uri-functions-post.php 3 years ago permalink-manager-uri-functions.php 3 years ago
permalink-manager-third-parties.php
1765 lines
1 <?php
2
3 /**
4 * Third parties integration
5 */
6 class Permalink_Manager_Third_Parties {
7
8 public function __construct() {
9 add_action( 'init', array( $this, 'init_hooks' ), 99 );
10 add_action( 'plugins_loaded', array( $this, 'init_early_hooks' ), 99 );
11 }
12
13 /**
14 * Add support for 3rd party plugins using their hooks
15 */
16 function init_hooks() {
17 global $permalink_manager_options;
18
19 // 0. Stop redirect
20 add_action( 'wp', array( $this, 'stop_redirect' ), 0 );
21
22 // 1. AMP
23 if ( defined( 'AMP_QUERY_VAR' ) ) {
24 add_filter( 'permalink_manager_detect_uri', array( $this, 'detect_amp' ), 10, 2 );
25 add_filter( 'request', array( $this, 'enable_amp' ), 10, 1 );
26 }
27
28 // 2. AMP for WP
29 if ( defined( 'AMPFORWP_AMP_QUERY_VAR' ) ) {
30 add_filter( 'permalink_manager_filter_query', array( $this, 'detect_amp_for_wp' ), 5 );
31 }
32
33 // 4. WooCommerce
34 if ( class_exists( 'WooCommerce' ) ) {
35 add_filter( 'permalink_manager_filter_query', array( $this, 'woocommerce_detect' ), 9, 5 );
36 add_filter( 'template_redirect', array( $this, 'woocommerce_checkout_fix' ), 9 );
37
38 if ( class_exists( 'Permalink_Manager_Pro_Functions' ) ) {
39 if ( empty( $permalink_manager_options['general']['partial_disable']['post_types'] ) || ! in_array( 'shop_coupon', $permalink_manager_options['general']['partial_disable']['post_types'] ) ) {
40 if ( is_admin() ) {
41 add_filter( 'woocommerce_coupon_data_tabs', 'Permalink_Manager_Pro_Functions::woocommerce_coupon_tabs' );
42 add_action( 'woocommerce_coupon_data_panels', 'Permalink_Manager_Pro_Functions::woocommerce_coupon_panel' );
43 add_action( 'woocommerce_coupon_options_save', 'Permalink_Manager_Pro_Functions::woocommerce_save_coupon_uri', 9, 2 );
44 }
45
46 add_filter( 'request', 'Permalink_Manager_Pro_Functions::woocommerce_detect_coupon_code', 1, 1 );
47 add_filter( 'permalink_manager_disabled_post_types', 'Permalink_Manager_Pro_Functions::woocommerce_coupon_uris', 9, 1 );
48 }
49 }
50
51 // WooCommerce Import/Export
52 add_filter( 'woocommerce_product_export_product_default_columns', array( $this, 'woocommerce_csv_custom_uri_column' ), 9 );
53 add_filter( 'woocommerce_product_export_product_column_custom_uri', array( $this, 'woocommerce_export_custom_uri_value' ), 9, 3 );
54
55 add_filter( 'woocommerce_csv_product_import_mapping_options', array( $this, 'woocommerce_csv_custom_uri_column' ), 9 );
56 add_filter( 'woocommerce_csv_product_import_mapping_default_columns', array( $this, 'woocommerce_csv_custom_uri_column' ), 9 );
57 add_action( 'woocommerce_product_import_inserted_product_object', array( $this, 'woocommerce_csv_import_custom_uri' ), 9, 2 );
58
59 add_action( 'woocommerce_product_duplicate', array( $this, 'woocommerce_generate_permalinks_after_duplicate' ), 9, 2 );
60 add_filter( 'permalink_manager_filter_default_post_uri', array( $this, 'woocommerce_product_attributes' ), 5, 5 );
61
62 if ( wp_doing_ajax() && class_exists( 'SitePress' ) ) {
63 add_filter( 'permalink_manager_filter_final_post_permalink', array( $this, 'woocommerce_translate_ajax_fragments_urls' ), 9999, 3 );
64 }
65 }
66
67 // 5. Theme My Login
68 if ( class_exists( 'Theme_My_Login' ) ) {
69 add_action( 'wp', array( $this, 'tml_ignore_custom_permalinks' ), 10 );
70 }
71
72 // 6. Yoast SEO
73 add_filter( 'wpseo_xml_sitemap_post_url', array( $this, 'yoast_fix_sitemap_urls' ), 9 );
74 if ( defined( 'WPSEO_VERSION' ) && version_compare( WPSEO_VERSION, '14.0', '>=' ) ) {
75 add_action( 'permalink_manager_updated_post_uri', array( $this, 'yoast_update_indexable_permalink' ), 10, 3 );
76 add_action( 'permalink_manager_updated_term_uri', array( $this, 'yoast_update_indexable_permalink' ), 10, 3 );
77 add_filter( 'wpseo_canonical', array( $this, 'yoast_fix_canonical' ), 10 );
78 add_filter( 'wpseo_opengraph_url', array( $this, 'yoast_fix_canonical' ), 10 );
79 }
80
81 // 7. Breadcrumbs
82 add_filter( 'wpseo_breadcrumb_links', array( $this, 'filter_breadcrumbs' ), 9 );
83 add_filter( 'rank_math/frontend/breadcrumb/items', array( $this, 'filter_breadcrumbs' ), 9 );
84 add_filter( 'seopress_pro_breadcrumbs_crumbs', array( $this, 'filter_breadcrumbs' ), 9 );
85 add_filter( 'woocommerce_get_breadcrumb', array( $this, 'filter_breadcrumbs' ), 9 );
86 add_filter( 'slim_seo_breadcrumbs_links', array( $this, 'filter_breadcrumbs' ), 9 );
87 // add_filter( 'aioseo_breadcrumbs_trail', array( $this, 'filter_breadcrumbs' ), 9 );
88 add_filter( 'avia_breadcrumbs_trail', array( $this, 'filter_breadcrumbs' ), 100 );
89
90 // 8. WooCommerce Wishlist Plugin
91 if ( function_exists( 'tinv_get_option' ) ) {
92 add_filter( 'permalink_manager_detect_uri', array( $this, 'ti_woocommerce_wishlist_uris' ), 15, 3 );
93 }
94
95 // 9. Revisionize
96 if ( defined( 'REVISIONIZE_ROOT' ) ) {
97 add_action( 'revisionize_after_create_revision', array( $this, 'revisionize_keep_post_uri' ), 9, 2 );
98 add_action( 'revisionize_before_publish', array( $this, 'revisionize_clone_uri' ), 9, 2 );
99 }
100
101 // 10. WP All Import
102 if ( class_exists( 'PMXI_Plugin' ) && ( ! empty( $permalink_manager_options['general']['pmxi_support'] ) ) ) {
103 add_action( 'pmxi_extend_options_featured', array( $this, 'wpaiextra_uri_display' ), 9, 2 );
104 add_filter( 'pmxi_options_options', array( $this, 'wpai_api_options' ) );
105 add_filter( 'pmxi_addons', array( $this, 'wpai_api_register' ) );
106 add_filter( 'wp_all_import_addon_parse', array( $this, 'wpai_api_parse' ) );
107 add_filter( 'wp_all_import_addon_import', array( $this, 'wpai_api_import' ) );
108
109 add_action( 'pmxi_saved_post', array( $this, 'wpai_save_redirects' ) );
110
111 add_action( 'pmxi_after_xml_import', array( $this, 'wpai_schedule_regenerate_uris_after_xml_import' ), 10, 1 );
112 add_action( 'wpai_regenerate_uris_after_import_event', array( $this, 'wpai_regenerate_uris_after_import' ), 10, 1 );
113 }
114
115 // 11. WP All Export
116 if ( class_exists( 'PMXE_Plugin' ) && ( ! empty( $permalink_manager_options['general']['pmxi_support'] ) ) ) {
117 add_filter( 'wp_all_export_available_sections', array( $this, 'wpae_custom_uri_section' ), 9 );
118 add_filter( 'wp_all_export_available_data', array( $this, 'wpae_custom_uri_section_fields' ), 9 );
119 add_filter( 'wp_all_export_csv_rows', array( $this, 'wpae_export_custom_uri' ), 10, 2 );
120 }
121
122 // 12. Duplicate Post
123 if ( defined( 'DUPLICATE_POST_CURRENT_VERSION' ) ) {
124 add_action( 'dp_duplicate_post', array( $this, 'duplicate_custom_uri' ), 100, 2 );
125 add_action( 'dp_duplicate_page', array( $this, 'duplicate_custom_uri' ), 100, 2 );
126 }
127
128 // 13. My Listing by 27collective
129 if ( class_exists( '\MyListing\Post_Types' ) ) {
130 add_filter( 'permalink_manager_filter_default_post_uri', array( $this, 'ml_listing_custom_fields' ), 5, 5 );
131 add_action( 'mylisting/submission/save-listing-data', array( $this, 'ml_set_listing_uri' ), 100 );
132 add_filter( 'permalink_manager_filter_query', array( $this, 'ml_detect_archives' ), 1, 2 );
133 }
134
135 // 14. bbPress
136 if ( class_exists( 'bbPress' ) && function_exists( 'bbp_get_edit_slug' ) ) {
137 add_filter( 'permalink_manager_endpoints', array( $this, 'bbpress_endpoints' ), 9 );
138 add_action( 'wp', array( $this, 'bbpress_detect_endpoints' ), 0 );
139 }
140
141 // 15. Dokan
142 if ( class_exists( 'WeDevs_Dokan' ) ) {
143 add_action( 'wp', array( $this, 'dokan_detect_endpoints' ), 999 );
144 add_filter( 'permalink_manager_endpoints', array( $this, 'dokan_endpoints' ) );
145 }
146
147 // 16. GeoDirectory
148 if ( class_exists( 'GeoDirectory' ) ) {
149 add_filter( 'permalink_manager_filter_default_post_uri', array( $this, 'geodir_custom_fields' ), 5, 5 );
150 }
151
152 // 17. BasePress
153 if ( class_exists( 'Basepress' ) ) {
154 add_filter( 'permalink_manager_filter_query', array( $this, 'kb_adjust_query' ), 5, 5 );
155 }
156
157 // 18. Ultimate Member
158 if ( class_exists( 'UM' ) && ! ( empty( $permalink_manager_options['general']['um_support'] ) ) ) {
159 add_filter( 'permalink_manager_detect_uri', array( $this, 'um_detect_extra_pages' ), 20 );
160 }
161
162 // 19. WooCommerce Subscriptions
163 if ( class_exists( 'WC_Subscriptions' ) ) {
164 add_filter( 'permalink_manager_filter_final_post_permalink', array( $this, 'wcs_fix_subscription_links' ), 10, 3 );
165 }
166
167 // 20. LearnPress
168 if ( class_exists( 'LearnPress' ) ) {
169 add_filter( 'permalink_manager_excluded_post_ids', array( $this, 'learnpress_exclude_pages' ) );
170 }
171 }
172
173 /**
174 * Some hooks must be called shortly after all the plugins are loaded
175 */
176 public function init_early_hooks() {
177 // WP Store Locator
178 if ( class_exists( 'WPSL_CSV' ) ) {
179 add_action( 'added_post_meta', array( $this, 'wpsl_regenerate_after_import' ), 10, 4 );
180 add_action( 'updated_post_meta', array( $this, 'wpsl_regenerate_after_import' ), 10, 4 );
181 }
182 // Woocommerce
183 if ( class_exists( 'WooCommerce' ) ) {
184 add_filter( 'woocommerce_get_endpoint_url', array( 'Permalink_Manager_Core_Functions', 'control_trailing_slashes' ), 9 );
185 }
186 }
187
188 /**
189 * 0. Stop canonical redirect if specific query variables are set
190 */
191 public static function stop_redirect() {
192 global $wp_query, $post;
193
194 if ( ! empty( $wp_query->query ) ) {
195 $query_vars = $wp_query->query;
196
197 // WordPress Photo Seller Plugin
198 if ( ! empty( $query_vars['image_id'] ) && ! empty( $query_vars['gallery_id'] ) ) {
199 $wp_query->query_vars['do_not_redirect'] = 1;
200 } // Ultimate Member
201 else if ( ! empty( $query_vars['um_user'] ) || ! empty( $query_vars['um_tab'] ) || ( ! empty( $query_vars['provider'] ) && ! empty( $query_vars['state'] ) ) ) {
202 $wp_query->query_vars['do_not_redirect'] = 1;
203 } // Mailster
204 else if ( ! empty( $query_vars['_mailster_page'] ) ) {
205 $wp_query->query_vars['do_not_redirect'] = 1;
206 } // WP Route
207 else if ( ! empty( $query_vars['WP_Route'] ) ) {
208 $wp_query->query_vars['do_not_redirect'] = 1;
209 } // WooCommerce Wishlist
210 else if ( ! empty( $query_vars['wishlist-action'] ) ) {
211 $wp_query->query_vars['do_not_redirect'] = 1;
212 } // UserPro
213 else if ( ! empty( $query_vars['up_username'] ) ) {
214 $wp_query->query_vars['do_not_redirect'] = 1;
215 } // The Events Calendar
216 else if ( ! empty( $query_vars['eventDisplay'] ) ) {
217 $wp_query->query_vars['do_not_redirect'] = 1;
218 } // Groundhogg
219 else if ( class_exists( '\Groundhogg\Plugin' ) && ! empty( $query_vars['subpage'] ) ) {
220 $wp_query->query_vars['do_not_redirect'] = 1;
221 } // MyListing theme
222 else if ( ! empty( $query_vars['explore_tab'] ) || ! empty( $query_vars['explore_region'] ) || ! empty( $_POST['submit_job'] ) ) {
223 $wp_query->query_vars['do_not_redirect'] = 1;
224 } // GeoDirectory
225 else if ( function_exists( 'geodir_location_page_id' ) && ! empty( $post->ID ) && geodir_location_page_id() == $post->ID ) {
226 $wp_query->query_vars['do_not_redirect'] = 1;
227 } // RankMath Pro
228 else if ( isset( $query_vars['schema-preview'] ) ) {
229 $wp_query->query_vars['do_not_redirect'] = 1;
230 } // Theme.co - Pro Theme
231 else if ( ! empty( $_POST['_cs_nonce'] ) ) {
232 $wp_query->query_vars['do_not_redirect'] = 1;
233 } // Tutor LMS
234 else if ( ! empty( $query_vars['tutor_dashboard_page'] ) ) {
235 $wp_query->query_vars['do_not_redirect'] = 1;
236 } // AMP
237 else if ( function_exists( 'amp_get_slug' ) && array_key_exists( amp_get_slug(), $query_vars ) ) {
238 $wp_query->query_vars['do_not_redirect'] = 1;
239 } // LearnPress
240 if ( ! empty( $query_vars['view'] ) && ! empty( $query_vars['page_id'] ) ) {
241 $wp_query->query_vars['do_not_redirect'] = 1;
242 }
243 }
244
245 // WPForo
246 if ( defined( 'WPFORO_VERSION' ) ) {
247 $forum_page_id = get_option( 'wpforo_pageid' );
248
249 if ( ! empty( $forum_page_id ) && ! empty( $post->ID ) && $forum_page_id == $post->ID ) {
250 $wp_query->query_vars['do_not_redirect'] = 1;
251 }
252 }
253 }
254
255 /**
256 * 1A. AMP hooks (support for older versions)
257 *
258 * @param array $uri_parts
259 * @param string $request_url
260 *
261 * @return array
262 */
263 function detect_amp( $uri_parts, $request_url ) {
264 global $amp_enabled;
265
266 if ( defined( 'AMP_QUERY_VAR' ) ) {
267 $amp_query_var = AMP_QUERY_VAR;
268
269 // Check if AMP should be triggered
270 preg_match( "/^(.+?)\/({$amp_query_var})?\/?$/i", $uri_parts['uri'], $regex_parts );
271 if ( ! empty( $regex_parts[2] ) ) {
272 $uri_parts['uri'] = $regex_parts[1];
273 $amp_enabled = true;
274 }
275 }
276
277 return $uri_parts;
278 }
279
280 /**
281 * 1B. AMP hooks
282 *
283 * @param array $query
284 *
285 * @return array
286 */
287 function enable_amp( $query ) {
288 global $amp_enabled;
289
290 if ( ! empty( $amp_enabled ) && defined( 'AMP_QUERY_VAR' ) ) {
291 $query[ AMP_QUERY_VAR ] = 1;
292 }
293
294 return $query;
295 }
296
297 /**
298 * 2. AMP for WP hooks (support for older versions)
299 *
300 * @param array $query
301 *
302 * @return array
303 */
304 function detect_amp_for_wp( $query ) {
305 global $wp_rewrite, $pm_query;
306
307 if ( defined( 'AMPFORWP_AMP_QUERY_VAR' ) ) {
308 $amp_endpoint = AMPFORWP_AMP_QUERY_VAR;
309 $paged_endpoint = $wp_rewrite->pagination_base;
310
311 if ( ! empty( $pm_query['endpoint'] ) && strpos( $pm_query['endpoint_value'], "{$paged_endpoint}/" ) !== false ) {
312 $paged_val = preg_replace( "/({$paged_endpoint}\/)([\d]+)/", '$2', $pm_query['endpoint_value'] );
313
314 if ( ! empty( $paged_val ) ) {
315 $query[ $amp_endpoint ] = 1;
316 $query['paged'] = $paged_val;
317 }
318 }
319 }
320
321 return $query;
322 }
323
324 /**
325 * 3A. Parse Custom Permalinks import
326 */
327 public static function custom_permalinks_uris() {
328 global $wpdb;
329
330 $custom_permalinks_uris = array();
331
332 // 1. List tags/categories
333 $table = get_option( 'custom_permalink_table' );
334 if ( $table && is_array( $table ) ) {
335 foreach ( $table as $permalink => $info ) {
336 $custom_permalinks_uris[] = array(
337 'id' => "tax-" . $info['id'],
338 'uri' => trim( $permalink, "/" )
339 );
340 }
341 }
342
343 // 2. List posts/pages
344 $query = "SELECT p.ID, m.meta_value FROM $wpdb->posts AS p LEFT JOIN $wpdb->postmeta AS m ON (p.ID = m.post_id) WHERE m.meta_key = 'custom_permalink' AND m.meta_value != '';";
345 $posts = $wpdb->get_results( $query );
346 foreach ( $posts as $post ) {
347 $custom_permalinks_uris[] = array(
348 'id' => $post->ID,
349 'uri' => trim( $post->meta_value, "/" ),
350 );
351 }
352
353 return $custom_permalinks_uris;
354 }
355
356 /**
357 * 3B. Import the URIs from the Custom Permalinks plugin.
358 */
359 static public function import_custom_permalinks_uris() {
360 global $permalink_manager_uris, $permalink_manager_before_sections_html;
361
362 $custom_permalinks_plugin = 'custom-permalinks/custom-permalinks.php';
363
364 if ( is_plugin_active( $custom_permalinks_plugin ) && ! empty( $_POST['disable_custom_permalinks'] ) ) {
365 deactivate_plugins( $custom_permalinks_plugin );
366 }
367
368 // Get a list of imported URIs
369 $custom_permalinks_uris = self::custom_permalinks_uris();
370
371 if ( ! empty( $custom_permalinks_uris ) && count( $custom_permalinks_uris ) > 0 ) {
372 foreach ( $custom_permalinks_uris as $item ) {
373 $item_uri = $item['uri'];
374
375 // Decode custom permalink if contains percent-encoded characters
376 if ( preg_match( '/%[0-9A-F]{2}/i', $item_uri ) ) {
377 $item_uri = urldecode( $item_uri );
378 }
379
380 $permalink_manager_uris[ $item['id'] ] = Permalink_Manager_Helper_Functions::sanitize_title( $item_uri );
381 }
382
383 $permalink_manager_before_sections_html .= Permalink_Manager_Admin_Functions::get_alert_message( __( '"Custom Permalinks" URIs were imported!', 'permalink-manager' ), 'updated' );
384 update_option( 'permalink-manager-uris', $permalink_manager_uris );
385 } else {
386 $permalink_manager_before_sections_html .= Permalink_Manager_Admin_Functions::get_alert_message( __( 'No "Custom Permalinks" URIs were imported!', 'permalink-manager' ), 'error' );
387 }
388 }
389
390 /**
391 * 4A. Fix query on WooCommerce shop page & disable the canonical redirect if WooCommerce query variables are set
392 */
393 function woocommerce_detect( $query, $old_query, $uri_parts, $pm_query, $content_type ) {
394 global $woocommerce, $pm_query;
395
396 $shop_page_id = get_option( 'woocommerce_shop_page_id' );
397
398 // WPML - translate shop page id
399 $shop_page_id = apply_filters( 'wpml_object_id', $shop_page_id, 'page', true );
400
401 // Fix shop page
402 if ( get_theme_support( 'woocommerce' ) && ! empty( $pm_query['id'] ) && is_numeric( $pm_query['id'] ) && $shop_page_id == $pm_query['id'] ) {
403 $query['post_type'] = 'product';
404 unset( $query['pagename'] );
405 }
406
407 // Fix WooCommerce pages
408 if ( ! empty( $woocommerce->query->query_vars ) ) {
409 $query_vars = $woocommerce->query->query_vars;
410
411 foreach ( $query_vars as $key => $val ) {
412 if ( isset( $query[ $key ] ) ) {
413 $query['do_not_redirect'] = 1;
414 break;
415 }
416 }
417 }
418
419 return $query;
420 }
421
422 /**
423 * 4B. Redirects the user from the Shop archive to the Shop page if the user is not searching for anything
424 * Disable canonical redirect on "thank you" & another WooCommerce pages
425 */
426 function woocommerce_checkout_fix() {
427 global $wp_query, $pm_query, $permalink_manager_options;
428
429 // Redirect from Shop archive to selected page
430 if ( is_shop() && empty( $pm_query['id'] ) ) {
431 $redirect_mode = ( ! empty( $permalink_manager_options['general']['redirect'] ) ) ? $permalink_manager_options['general']['redirect'] : false;
432 $redirect_shop = apply_filters( 'permalink_manager_redirect_shop_archive', false );
433 $shop_page = get_option( 'woocommerce_shop_page_id' );
434
435 if ( $redirect_mode && $redirect_shop && $shop_page && empty( $wp_query->query_vars['s'] ) ) {
436 $shop_url = get_permalink( $shop_page );
437 wp_safe_redirect( $shop_url, $redirect_mode );
438 exit();
439 }
440 }
441
442 if ( is_checkout() || ( function_exists( 'is_wc_endpoint_url' ) && is_wc_endpoint_url() ) ) {
443 $wp_query->query_vars['do_not_redirect'] = 1;
444 }
445 }
446
447 /**
448 * 4C. Generate a new custom permalink for duplicated product
449 *
450 * @param WC_Product $new_product The new product object.
451 * @param WC_Product $old_product The product that was duplicated.
452 */
453 function woocommerce_generate_permalinks_after_duplicate( $new_product, $old_product ) {
454 if ( ! empty( $new_product ) ) {
455 $product_id = $new_product->get_id();
456
457 // Ignore variations
458 if ( $new_product->get_type() !== 'variation' ) {
459 $custom_uri = Permalink_Manager_URI_Functions_Post::get_default_post_uri( $product_id, false, true );
460
461 Permalink_Manager_URI_Functions::save_single_uri( $product_id, $custom_uri, false, true );
462 }
463 }
464 }
465
466 /**
467 * 4D. If the URI contains %pa_attribute_name% tag, replace it with the value of the attribute
468 *
469 * @param string $default_uri The default custom permalink that WordPress would use for the post.
470 * @param string $slug The post slug.
471 * @param WP_Post $post The post object.
472 * @param string $post_name The post slug.
473 * @param bool $native_uri true if the URI is a native URI, false if it's a custom URI
474 *
475 * @return string The default custom permalink
476 */
477 function woocommerce_product_attributes( $default_uri, $slug, $post, $post_name, $native_uri ) {
478 // Do not affect native URIs
479 if ( $native_uri ) {
480 return $default_uri;
481 }
482
483 // Use only for products
484 if ( empty( $post->post_type ) || $post->post_type !== 'product' ) {
485 return $default_uri;
486 }
487
488 preg_match_all( "/%pa_(.[^\%]+)%/", $default_uri, $custom_fields );
489
490 if ( ! empty( $custom_fields[1] ) ) {
491 $product = wc_get_product( $post->ID );
492
493 foreach ( $custom_fields[1] as $i => $custom_field ) {
494 $attribute_name = sanitize_title( $custom_field );
495 $attribute_value = $product->get_attribute( $attribute_name );
496
497 $default_uri = str_replace( $custom_fields[0][ $i ], Permalink_Manager_Helper_Functions::sanitize_title( $attribute_value ), $default_uri );
498 }
499 }
500
501 return $default_uri;
502 }
503
504 /**
505 * 4E. Check the current request is a WooCommerce AJAX request. If it is, check the translated page's URL should be returned
506 *
507 * @param string $permalink The full URL of the post
508 * @param WP_Post $post The post object
509 * @param string $old_permalink The original URL of the post.
510 *
511 * @return string The permalink is being returned.
512 */
513 function woocommerce_translate_ajax_fragments_urls( $permalink, $post, $old_permalink ) {
514 // Use it only if the permalinks are different
515 if ( $permalink == $old_permalink || $post->post_type !== 'page' ) {
516 return $permalink;
517 }
518
519 // A. Native WooCommerce AJAX events
520 if ( ! empty( $_REQUEST['wc-ajax'] ) ) {
521 $action = sanitize_title( $_REQUEST['wc-ajax'] );
522 } // B. Shoptimizer theme
523 else if ( ! empty( $_REQUEST['action'] ) ) {
524 $action = sanitize_title( $_REQUEST['action'] );
525 }
526
527 // Allowed action names
528 $allowed_actions = array( 'shoptimizer_pdp_ajax_atc', 'get_refreshed_fragments' );
529
530 if ( ! empty( $action ) && in_array( $action, $allowed_actions ) ) {
531 $translated_post_id = apply_filters( 'wpml_object_id', $post->ID, 'page' );
532 $permalink = ( $translated_post_id !== $post->ID ) ? get_permalink( $translated_post_id ) : $permalink;
533 }
534
535 return $permalink;
536 }
537
538 /**
539 * 4FA. Add a new column to the WooCommerce CSV Import/Export tool
540 *
541 * @param array $columns The array of columns to be displayed.
542 *
543 * @return array The $columns array.
544 */
545 function woocommerce_csv_custom_uri_column( $columns ) {
546 if ( ! is_array( $columns ) ) {
547 return $columns;
548 }
549
550 $label = __( 'Custom URI', 'permalink-manager' );
551 $key = 'custom_uri';
552
553 if ( current_filter() == 'woocommerce_csv_product_import_mapping_default_columns' ) {
554 $columns[ $label ] = $key;
555 } else {
556 $columns[ $key ] = $label;
557 }
558
559 return $columns;
560 }
561
562 /**
563 * 4FB. Return the custom permalink of the product if it exists, otherwise return the default URI
564 *
565 * @param string $value The value of the column.
566 * @param WC_Product $product The product object.
567 * @param mixed $column_id The column ID.
568 *
569 * @return string The custom permalink or default permalink
570 */
571 function woocommerce_export_custom_uri_value( $value, $product, $column_id ) {
572 if ( empty( $value ) && ! empty( $product ) ) {
573 $product_id = $product->get_id();
574
575 // Get custom permalink or default permalink
576 $value = Permalink_Manager_URI_Functions_Post::get_post_uri( $product_id );
577 }
578
579 return $value;
580 }
581
582 /**
583 * 4FC. Set the custom URI for the product using the value from CSV file, if not set use the default permalink
584 *
585 * @param WC_Product $product The product object.
586 * @param array $data The data array for the current row being imported.
587 */
588 function woocommerce_csv_import_custom_uri( $product, $data ) {
589 global $permalink_manager_uris;
590
591 if ( ! empty( $product ) ) {
592 $product_id = $product->get_id();
593
594 // Ignore variations
595 if ( $product->get_type() == 'variation' ) {
596 return;
597 }
598
599 // A. Use default permalink if "Custom URI" is not set and did not exist before
600 if ( empty( $permalink_manager_uris[ $product_id ] ) && empty( $data['custom_uri'] ) ) {
601 $custom_uri = Permalink_Manager_URI_Functions_Post::get_default_post_uri( $product_id, false, true );
602 } else if ( ! empty( $data['custom_uri'] ) ) {
603 $custom_uri = Permalink_Manager_Helper_Functions::sanitize_title( $data['custom_uri'] );
604 } else {
605 return;
606 }
607
608 Permalink_Manager_URI_Functions::save_single_uri( $product_id, $custom_uri, false, true );
609 }
610 }
611
612 /**
613 * 5. Do not use custom permalinks if any action is triggered inside Theme My Login plugin
614 */
615 function tml_ignore_custom_permalinks() {
616 global $wp, $permalink_manager_ignore_permalink_filters;
617
618 if ( isset( $wp->query_vars['action'] ) || ! empty( $_GET['redirect_to'] ) ) {
619 $permalink_manager_ignore_permalink_filters = true;
620
621 // Allow the canonical redirect (if blocked earlier by Permalink Manager)
622 if ( ! empty( $wp_query->query_vars['do_not_redirect'] ) ) {
623 $wp_query->query_vars['do_not_redirect'] = 0;
624 }
625 }
626 }
627
628 /**
629 * 6A. Get the HTTP protocol of the home URL and use it in Yoast SEO sitemap permalinks
630 *
631 * @param string $permalink The permalink in the sitemap
632 *
633 * @return string The sitemap's permalink
634 */
635 function yoast_fix_sitemap_urls( $permalink ) {
636 if ( class_exists( 'WPSEO_Utils' ) ) {
637 $home_url = WPSEO_Utils::home_url();
638 $home_protocol = parse_url( $home_url, PHP_URL_SCHEME );
639
640 $permalink = preg_replace( "/^http(s)?/", $home_protocol, $permalink );
641 }
642
643 return $permalink;
644 }
645
646 /**
647 * 6B. Update the permalink in the Yoast SEO indexable table when the permalink is changed
648 *
649 * @param int $element_id The ID of the post/term element that was updated.
650 * @param string $new_uri The new URI of the element.
651 * @param string $old_uri The old URI of the element.
652 */
653 function yoast_update_indexable_permalink( $element_id, $new_uri, $old_uri ) {
654 global $wpdb;
655
656 if ( ! empty( $new_uri ) && ! empty( $old_uri ) && $new_uri !== $old_uri ) {
657 if ( current_filter() == 'permalink_manager_updated_term_uri' ) {
658 $permalink = get_term_link( (int) $element_id );
659 $object_type = 'term';
660 } else {
661 $permalink = get_permalink( $element_id );
662 $object_type = 'post';
663 }
664
665 if ( ! empty( $permalink ) ) {
666 $permalink_hash = strlen( $permalink ) . ':' . md5( $permalink );
667 $wpdb->update( "{$wpdb->prefix}yoast_indexable", array( 'permalink' => $permalink, 'permalink_hash' => $permalink_hash ), array( 'object_id' => $element_id, 'object_type' => $object_type ), array( '%s', '%s' ), array( '%d', '%s' ) );
668 }
669 }
670 }
671
672 /**
673 * 6C. Filter the canonical permalink used by SEO using 'wpseo_canonical' & 'wpseo_opengraph_url' hooks
674 *
675 * @param string $url The canonical URL that Yoast SEO has generated.
676 *
677 * @return string the URL.
678 */
679 function yoast_fix_canonical( $url ) {
680 global $pm_query, $wp_rewrite;
681
682 if ( ! empty( $pm_query['id'] ) ) {
683 $element = get_queried_object();
684
685 if ( ! empty( $element->ID ) && ! empty( $element->post_type ) ) {
686 $new_url = get_permalink( $element->ID );
687
688 // Do not filter if custom canonical URL is set
689 $yoast_canonical_url = get_post_meta( $element->ID, '_yoast_wpseo_canonical', true );
690 if ( ! empty( $yoast_canonical_url ) ) {
691 return $url;
692 }
693
694 if ( is_home() ) {
695 $paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
696 $new_url = ( $paged > 1 ) ? sprintf( '%s/%s/%d', trim( $new_url, '/' ), $wp_rewrite->pagination_base, $paged ) : $new_url;
697 } else {
698 $paged = ( get_query_var( 'page' ) ) ? get_query_var( 'page' ) : 1;
699 $new_url = ( $paged > 1 ) ? sprintf( '%s/%d', trim( $new_url, '/' ), $paged ) : $new_url;
700 }
701 } else if ( ! empty( $element->taxonomy ) && ! empty( $element->term_id ) ) {
702 $new_url = get_term_link( $element, $element->taxonomy );
703
704 // Do not filter if custom canonical URL is set
705 if ( class_exists( 'WPSEO_Taxonomy_Meta' ) ) {
706 $yoast_canonical_url = WPSEO_Taxonomy_Meta::get_term_meta( $element, $element->taxonomy, 'canonical' );
707 if ( ! empty( $yoast_canonical_url ) ) {
708 return $url;
709 }
710 }
711
712 $paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
713 if ( $paged > 1 ) {
714 $new_url = sprintf( '%s/%s/%d', trim( $new_url, '/' ), $wp_rewrite->pagination_base, $paged );
715 }
716 }
717
718 $url = ( ! empty( $new_url ) ) ? $new_url : $url;
719 $url = Permalink_Manager_Core_Functions::control_trailing_slashes( $url );
720 }
721
722 return $url;
723 }
724
725 /**
726 * 7. Filter the breadcrumbs array to match the structure of currently requested URL
727 *
728 * @param array $links The current breadcrumb links.
729 *
730 * @return array The $links array.
731 */
732 function filter_breadcrumbs( $links ) {
733 // Get post type permastructure settings
734 global $permalink_manager_uris, $permalink_manager_options, $post, $wpdb, $wp, $wp_current_filter;
735
736 // Check if the filter should be activated
737 if ( empty( $permalink_manager_options['general']['yoast_breadcrumbs'] ) || empty( $permalink_manager_uris ) ) {
738 return $links;
739 }
740
741 // Get current post/page/term (if available)
742 $queried_element = get_queried_object();
743 if ( ! empty( $queried_element->ID ) ) {
744 $element_id = $queried_element->ID;
745 } else if ( ! empty( $queried_element->term_id ) ) {
746 $element_id = "tax-{$queried_element->term_id}";
747 } else if ( defined( 'REST_REQUEST' ) && ! empty( $post->ID ) ) {
748 $element_id = $post->ID;
749 }
750
751 // Get the custom permalink (if available) or the current request URL (if unavailable)
752 if ( ! empty( $element_id ) && ! empty( $permalink_manager_uris[ $element_id ] ) ) {
753 $custom_uri = preg_replace( "/([^\/]+)$/", '', $permalink_manager_uris[ $element_id ] );
754 } else {
755 $custom_uri = trim( preg_replace( "/([^\/]+)$/", '', $wp->request ), "/" );
756 }
757
758 $all_uris = array_flip( $permalink_manager_uris );
759 $custom_uri_parts = explode( '/', trim( $custom_uri ) );
760 $breadcrumbs = array();
761 $snowball = '';
762 $available_taxonomies = Permalink_Manager_Helper_Functions::get_taxonomies_array( null, null, true );
763 $available_post_types = Permalink_Manager_Helper_Functions::get_post_types_array( null, null, true );
764 $available_post_types_archive = Permalink_Manager_Helper_Functions::get_post_types_array( 'archive_slug', null, true );
765 $current_filter = end( $wp_current_filter );
766
767 // Get Yoast Meta (the breadcrumbs titles can be changed in Yoast metabox)
768 $yoast_meta_terms = get_option( 'wpseo_taxonomy_meta' );
769
770 // Check what array keys should be used for breadcrumbs ("All In One SEO" uses a more complicated schema)
771 if ( $current_filter == 'aioseo_breadcrumbs_trail' ) {
772 $breadcrumb_key_text = 'label';
773 $breadcrumb_key_url = 'link';
774 $is_aioseo = true;
775 } else if ( in_array( $current_filter, array( 'wpseo_breadcrumb_links', 'slim_seo_breadcrumbs_links' ) ) ) {
776 $breadcrumb_key_text = 'text';
777 $breadcrumb_key_url = 'url';
778 $is_aioseo = false;
779 } else {
780 $breadcrumb_key_text = 0;
781 $breadcrumb_key_url = 1;
782 $is_aioseo = false;
783 }
784
785 // Get internal breadcrumb elements
786 foreach ( $custom_uri_parts as $slug ) {
787 if ( empty( $slug ) ) {
788 continue;
789 }
790
791 $snowball = ( empty( $snowball ) ) ? $slug : "{$snowball}/{$slug}";
792
793 // 1A. Try to match any custom URI
794 $uri = trim( $snowball, "/" );
795 $element = ( ! empty( $all_uris[ $uri ] ) ) ? $all_uris[ $uri ] : false;
796
797 if ( ! empty( $element ) && strpos( $element, 'tax-' ) !== false ) {
798 $element_id = intval( preg_replace( "/[^0-9]/", "", $element ) );
799 $element = get_term( $element_id );
800 } else if ( is_numeric( $element ) ) {
801 $element = get_post( $element );
802 }
803
804 // 1B. Try to get term
805 if ( empty( $element ) && ! empty( $available_taxonomies ) ) {
806 $sql = sprintf( "SELECT t.term_id, t.name, tt.taxonomy FROM {$wpdb->terms} AS t LEFT JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE slug = '%s' AND tt.taxonomy IN ('%s') LIMIT 1", esc_sql( $slug ), implode( "','", array_keys( $available_taxonomies ) ) );
807
808 $element = $wpdb->get_row( $sql );
809 }
810
811 // 1C. Try to get page/post
812 if ( empty( $element ) && ! empty( $available_post_types ) ) {
813 $sql = sprintf( "SELECT ID, post_title, post_type FROM {$wpdb->posts} WHERE post_name = '%s' AND post_status = 'publish' AND post_type IN ('%s') AND post_type != 'attachment' LIMIT 1", esc_sql( $slug ), implode( "','", array_keys( $available_post_types ) ) );
814
815 $element = $wpdb->get_row( $sql );
816 }
817
818 // 1D. Try to get post type archive
819 if ( empty( $element ) && ! empty( $available_post_types_archive ) && in_array( $snowball, $available_post_types_archive ) ) {
820 $post_type_slug = array_search( $snowball, $available_post_types_archive );
821 $element = get_post_type_object( $post_type_slug );
822 }
823
824 // 2A. When the term is found, we can add it to the breadcrumbs
825 if ( ! empty( $element->term_id ) ) {
826 $term_id = apply_filters( 'wpml_object_id', $element->term_id, $element->taxonomy, true );
827 $term = ( ( $element->term_id !== $term_id ) || $is_aioseo ) ? get_term( $term_id ) : $element;
828
829 // Alternative title
830 if ( $current_filter == 'wpseo_breadcrumb_links' ) {
831 $alt_title = ( ! empty( $yoast_meta_terms[ $term->taxonomy ][ $term->term_id ]['wpseo_bctitle'] ) ) ? $yoast_meta_terms[ $term->taxonomy ][ $term->term_id ]['wpseo_bctitle'] : '';
832 } else if ( $current_filter == 'seopress_pro_breadcrumbs_crumbs' ) {
833 $alt_title = get_term_meta( $term->term_id, '_seopress_robots_breadcrumbs', true );
834 } else if ( $current_filter == 'rank_math/frontend/breadcrumb/items' ) {
835 $alt_title = get_term_meta( $term->term_id, 'rank_math_breadcrumb_title', true );
836 }
837
838 $title = ( ! empty( $alt_title ) ) ? $alt_title : $term->name;
839
840 if ( $is_aioseo ) {
841 $breadcrumbs[] = array(
842 $breadcrumb_key_text => wp_strip_all_tags( $title ),
843 $breadcrumb_key_url => get_term_link( (int) $term->term_id, $term->taxonomy ),
844 'type' => 'taxonomy',
845 'subType' => 'parent',
846 'reference' => $term,
847 );
848 } else {
849 $breadcrumbs[] = array(
850 $breadcrumb_key_text => wp_strip_all_tags( $title ),
851 $breadcrumb_key_url => get_term_link( (int) $term->term_id, $term->taxonomy )
852 );
853 }
854 } // 2B. When the post/page is found, we can add it to the breadcrumbs
855 else if ( ! empty( $element->ID ) ) {
856 $page_id = apply_filters( 'wpml_object_id', $element->ID, $element->post_type, true );
857 $page = ( ( $element->ID !== $page_id ) || $is_aioseo ) ? get_post( $page_id ) : $element;
858
859 // Alternative title
860 if ( $current_filter == 'wpseo_breadcrumb_links' ) {
861 $alt_title = get_post_meta( $page->ID, '_yoast_wpseo_bctitle', true );
862 } else if ( $current_filter == 'seopress_pro_breadcrumbs_crumbs' ) {
863 $alt_title = get_post_meta( $page->ID, '_seopress_robots_breadcrumbs', true );
864 } else if ( $current_filter == 'rank_math/frontend/breadcrumb/items' ) {
865 $alt_title = get_post_meta( $page->ID, 'rank_math_breadcrumb_title', true );
866 }
867
868 $title = ( ! empty( $alt_title ) ) ? $alt_title : $page->post_title;
869
870 if ( $is_aioseo ) {
871 $breadcrumbs[] = array(
872 $breadcrumb_key_text => wp_strip_all_tags( $title ),
873 $breadcrumb_key_url => get_permalink( $page->ID ),
874 'type' => 'single',
875 'subType' => '',
876 'reference' => $page
877 );
878 } else {
879 $breadcrumbs[] = array(
880 $breadcrumb_key_text => wp_strip_all_tags( $title ),
881 $breadcrumb_key_url => get_permalink( $page->ID )
882 );
883 }
884 } // 2C. When the post archive is found, we can add it to the breadcrumbs
885 else if ( ! empty( $element->rewrite ) && ( ! empty( $element->labels->name ) ) ) {
886 if ( $is_aioseo ) {
887 $breadcrumbs[] = array(
888 $breadcrumb_key_text => apply_filters( 'post_type_archive_title', $element->labels->name, $element->name ),
889 $breadcrumb_key_url => get_post_type_archive_link( $element->name ),
890 'type' => 'postTypeArchive',
891 'subType' => '',
892 'reference' => $element
893 );
894 } else {
895 $breadcrumbs[] = array(
896 $breadcrumb_key_text => apply_filters( 'post_type_archive_title', $element->labels->name, $element->name ),
897 $breadcrumb_key_url => get_post_type_archive_link( $element->name )
898 );
899 }
900 }
901 }
902
903 // Add new links to current breadcrumbs array
904 if ( ! empty( $links ) && is_array( $links ) ) {
905 $first_element = reset( $links );
906 $last_element = end( $links );
907 $b_last_element = prev( $links );
908 $breadcrumbs = ( ! empty( $breadcrumbs ) ) ? $breadcrumbs : array();
909
910 // Support RankMath/SEOPress/WooCommerce/Slim SEO/AIOSEO breadcrumbs
911 if ( in_array( $current_filter, array( 'wpseo_breadcrumb_links', 'rank_math/frontend/breadcrumb/items', 'seopress_pro_breadcrumbs_crumbs', 'woocommerce_get_breadcrumb', 'slim_seo_breadcrumbs_links', 'aioseo_breadcrumbs_trail' ) ) ) {
912 if ( $current_filter == 'slim_seo_breadcrumbs_links' ) {
913 $links = array_merge( array( $first_element ), $breadcrumbs );
914 } // Append the element before the last element if the last breadcrumb does not have a URL set (e.g. if the /page/ endpoint is used)
915 else if ( ! in_array( $current_filter, array( 'aioseo_breadcrumbs_trail', 'slim_seo_breadcrumbs_links' ) ) && ! empty( $wp->query_vars['paged'] ) && $wp->query_vars['paged'] > 1 && ! empty( $b_last_element[ $breadcrumb_key_url ] ) ) {
916 $links = array_merge( array( $first_element ), $breadcrumbs, array( $b_last_element ), array( $last_element ) );
917 } else {
918 $links = array_merge( array( $first_element ), $breadcrumbs, array( $last_element ) );
919 }
920 } // Support Avia/Enfold breadcrumbs
921 else if ( $current_filter == 'avia_breadcrumbs_trail' ) {
922 foreach ( $breadcrumbs as &$breadcrumb ) {
923 if ( isset( $breadcrumb[ $breadcrumb_key_text ] ) ) {
924 $breadcrumb = sprintf( '<a href="%s" title="%2$s">%2$s</a>', esc_attr( $breadcrumb[ $breadcrumb_key_url ] ), esc_attr( $breadcrumb[ $breadcrumb_key_text ] ) );
925 }
926 }
927
928 $links = array_merge( array( $first_element ), $breadcrumbs, array( 'trail_end' => $last_element ) );
929 }
930 }
931
932 return array_filter( $links );
933 }
934
935 /**
936 * 8. Extracts the Wishlist ID from the URI and add it to the $uri_parts array (WooCommerce Wishlist Plugin)
937 *
938 * @param array $uri_parts An array of the URI parts.
939 * @param string $request_url The URL that was requested.
940 * @param array $endpoints An array of all the endpoints that are currently registered.
941 *
942 * @return array The URI parts.
943 */
944 function ti_woocommerce_wishlist_uris( $uri_parts, $request_url, $endpoints ) {
945 global $permalink_manager_uris;
946
947 $wishlist_pid = tinv_get_option( 'general', 'page_wishlist' );
948
949 // Find the Wishlist page URI
950 if ( is_numeric( $wishlist_pid ) && ! empty( $permalink_manager_uris[ $wishlist_pid ] ) ) {
951 $wishlist_uri = preg_quote( $permalink_manager_uris[ $wishlist_pid ], '/' );
952
953 // Extract the Wishlist ID
954 preg_match( "/^({$wishlist_uri})\/([^\/]+)\/?$/", $uri_parts['uri'], $output_array );
955
956 if ( ! empty( $output_array[2] ) ) {
957 $uri_parts['uri'] = $output_array[1];
958 $uri_parts['endpoint'] = 'tinvwlID';
959 $uri_parts['endpoint_value'] = $output_array[2];
960 }
961 }
962
963 return $uri_parts;
964 }
965
966 /**
967 * 9A. Copy the custom URI from original post and apply it to the new temp. revision post (Revisionize)
968 *
969 * @param int $old_id
970 * @param int $new_id
971 */
972 function revisionize_keep_post_uri( $old_id, $new_id ) {
973 global $permalink_manager_uris;
974
975 if ( ! empty( $permalink_manager_uris[ $old_id ] ) ) {
976 $permalink_manager_uris[ $new_id ] = $permalink_manager_uris[ $old_id ];
977
978 update_option( 'permalink-manager-uris', $permalink_manager_uris );
979 }
980 }
981
982 /**
983 * 9B. Copy the custom URI from revision post and apply it to the original post
984 *
985 * @param int $old_id
986 * @param int $new_id
987 */
988 function revisionize_clone_uri( $old_id, $new_id ) {
989 global $permalink_manager_uris;
990
991 if ( ! empty( $permalink_manager_uris[ $new_id ] ) ) {
992 $permalink_manager_uris[ $old_id ] = $permalink_manager_uris[ $new_id ];
993 unset( $permalink_manager_uris[ $new_id ] );
994
995 update_option( 'permalink-manager-uris', $permalink_manager_uris );
996 }
997 }
998
999 /**
1000 * 10A. Add a new section to the WP All Import interface
1001 *
1002 * @param string $content_type The type of content being imported
1003 * @param array $current_values An array of the current values for the post
1004 */
1005 function wpaiextra_uri_display( $content_type, $current_values ) {
1006 // Check if post type is supported
1007 if ( $content_type !== 'taxonomies' && Permalink_Manager_Helper_Functions::is_post_type_disabled( $content_type ) ) {
1008 return;
1009 }
1010
1011 // Get custom URI format
1012 $custom_uri = ( ! empty( $current_values['custom_uri'] ) ) ? sanitize_text_field( $current_values['custom_uri'] ) : "";
1013
1014 $html = '<div class="wpallimport-collapsed closed wpallimport-section">';
1015 $html .= '<div class="wpallimport-content-section">';
1016 $html .= sprintf( '<div class="wpallimport-collapsed-header"><h3>%s</h3></div>', __( 'Permalink Manager', 'permalink-manager' ) );
1017 $html .= '<div class="wpallimport-collapsed-content">';
1018
1019 $html .= '<div class="template_input">';
1020 $html .= Permalink_Manager_Admin_Functions::generate_option_field( 'custom_uri', array( 'extra_atts' => 'style="width:100%; line-height: 25px;"', 'placeholder' => __( 'Custom URI', 'permalink-manager' ), 'value' => $custom_uri ) );
1021 $html .= wpautop( sprintf( __( 'If empty, a default permalink based on your current <a href="%s" target="_blank">permastructure settings</a> will be used.', 'permalink-manager' ), Permalink_Manager_Admin_Functions::get_admin_url( '&section=permastructs' ) ) );
1022 $html .= '</div>';
1023
1024 $html .= '</div>';
1025 $html .= '</div>';
1026 $html .= '</div>';
1027
1028 echo $html;
1029 }
1030
1031 /**
1032 * 10BA. Add a new field to the list of WP All Import options
1033 *
1034 * @param array $all_options The array of all options that are currently set
1035 *
1036 * @return array The array of all options plus the custom_uri option
1037 */
1038 function wpai_api_options( $all_options ) {
1039 return $all_options + array( 'custom_uri' => null );
1040 }
1041
1042 /**
1043 * 10BB. Add Permalink Manager plugin to the WP All Import API
1044 *
1045 * @param array $addons
1046 *
1047 * @return array
1048 */
1049 function wpai_api_register( $addons ) {
1050 if ( empty( $addons[ PERMALINK_MANAGER_PLUGIN_SLUG ] ) ) {
1051 $addons[ PERMALINK_MANAGER_PLUGIN_SLUG ] = 1;
1052 }
1053
1054 return $addons;
1055 }
1056
1057 /**
1058 * 10BC. Register function that parses Permalink Manager plugin data in WP All Import API data feed
1059 *
1060 * @param array $functions
1061 *
1062 * @return array
1063 */
1064 function wpai_api_parse( $functions ) {
1065 $functions[ PERMALINK_MANAGER_PLUGIN_SLUG ] = array( $this, 'wpai_api_parse_function' );
1066
1067 return $functions;
1068 }
1069
1070 /**
1071 * 10BD. Register function that saves Permalink Manager plugin data extracted from WP All Import API data feed
1072 *
1073 * @param array $functions
1074 *
1075 * @return array
1076 */
1077 function wpai_api_import( $functions ) {
1078 $functions[ PERMALINK_MANAGER_PLUGIN_SLUG ] = array( $this, 'wpai_api_import_function' );
1079
1080 return $functions;
1081 }
1082
1083 /**
1084 * 10C. Parse Permalink Manager plugin data in WP All Import API data feed
1085 *
1086 * @param array $data
1087 *
1088 * @return array
1089 */
1090 function wpai_api_parse_function( $data ) {
1091 extract( $data );
1092
1093 $data = array(); // parsed data
1094 $option_name = 'custom_uri';
1095
1096 if ( ! empty( $import->options[ $option_name ] ) && class_exists( 'XmlImportParser' ) ) {
1097 $cxpath = $xpath_prefix . $import->xpath;
1098 $tmp_files = array();
1099
1100 if ( isset( $import->options[ $option_name ] ) && $import->options[ $option_name ] != '' ) {
1101 if ( $import->options[ $option_name ] == "xpath" ) {
1102 $data[ $option_name ] = XmlImportParser::factory( $xml, $cxpath, (string) $import->options['xpaths'][ $option_name ], $file )->parse();
1103 } else {
1104 $data[ $option_name ] = XmlImportParser::factory( $xml, $cxpath, (string) $import->options[ $option_name ], $file )->parse();
1105 }
1106
1107 $tmp_files[] = $file;
1108 } else {
1109 $data[ $option_name ] = array_fill( 0, $count, "" );
1110 }
1111
1112 foreach ( $tmp_files as $file ) {
1113 unlink( $file );
1114 }
1115 }
1116
1117 return $data;
1118 }
1119
1120 /**
1121 * 10D. Save the Permalink Manager plugin data extracted from WP All Import API data feed
1122 *
1123 * @param array $importData
1124 * @param array $parsedData
1125 */
1126 function wpai_api_import_function( $importData, $parsedData ) {
1127 // Check if the array with $parsedData is not empty
1128 if ( empty( $parsedData ) || empty( $importData['post_type'] ) ) {
1129 return;
1130 }
1131
1132 // Check if the imported elements are terms
1133 if ( $importData['post_type'] == 'taxonomies' ) {
1134 $is_term = true;
1135 } else if ( Permalink_Manager_Helper_Functions::is_post_type_disabled( $importData['post_type'] ) ) {
1136 return;
1137 }
1138
1139 // Get the parsed custom URI
1140 $index = ( isset( $importData['i'] ) ) ? $importData['i'] : false;
1141 $pid = ( ! empty( $importData['pid'] ) ) ? (int) $importData['pid'] : false;
1142
1143 if ( isset( $index ) && ! empty( $pid ) && ! empty( $parsedData['custom_uri'][ $index ] ) ) {
1144 $new_uri = Permalink_Manager_Helper_Functions::sanitize_title( $parsedData['custom_uri'][ $index ] );
1145
1146 if ( ! empty( $new_uri ) ) {
1147 if ( ! empty( $is_term ) ) {
1148 $default_uri = Permalink_Manager_URI_Functions_Tax::get_default_term_uri( $pid );
1149 $native_uri = Permalink_Manager_URI_Functions_Tax::get_default_term_uri( $pid, true );
1150 $custom_uri = Permalink_Manager_URI_Functions_Tax::get_term_uri( $pid, false, true );
1151 $old_uri = ( ! empty( $custom_uri ) ) ? $custom_uri : $native_uri;
1152
1153 if ( $new_uri !== $old_uri ) {
1154 Permalink_Manager_URI_Functions::save_single_uri( $pid, $new_uri, true, true );
1155 do_action( 'permalink_manager_updated_term_uri', $pid, $new_uri, $old_uri, $native_uri, $default_uri, $single_update = true, $uri_saved = true );
1156 }
1157 } else {
1158 $default_uri = Permalink_Manager_URI_Functions_Post::get_default_post_uri( $pid );
1159 $native_uri = Permalink_Manager_URI_Functions_Post::get_default_post_uri( $pid, true );
1160 $custom_uri = Permalink_Manager_URI_Functions_Post::get_post_uri( $pid, false, true );
1161 $old_uri = ( ! empty( $custom_uri ) ) ? $custom_uri : $native_uri;
1162
1163 if ( $new_uri !== $old_uri ) {
1164 Permalink_Manager_URI_Functions::save_single_uri( $pid, $new_uri, false, true );
1165 do_action( 'permalink_manager_updated_post_uri', $pid, $new_uri, $old_uri, $native_uri, $default_uri, $single_update = true, $uri_saved = true );
1166 }
1167 }
1168 }
1169 }
1170 }
1171
1172 /**
1173 * 10E. Copy the external redirect from the "external_redirect" custom field to the data model used by Permalink Manager Pro
1174 *
1175 * @param int $pid The post ID of the post being imported.
1176 */
1177 function wpai_save_redirects( $pid ) {
1178 $external_url = get_post_meta( $pid, '_external_redirect', true );
1179 $external_url = ( empty( $external_url ) ) ? get_post_meta( $pid, 'external_redirect', true ) : $external_url;
1180
1181 if ( $external_url && class_exists( 'Permalink_Manager_Pro_Functions' ) ) {
1182 Permalink_Manager_Pro_Functions::save_external_redirect( $external_url, $pid );
1183 }
1184 }
1185
1186 /**
1187 * 10FA. Use the import ID to extract all the post IDs that were imported, then splits them into chunks and schedule a single regenerate permalink event for each chunk
1188 *
1189 * @param int $import_id The ID of the import.
1190 */
1191 function wpai_schedule_regenerate_uris_after_xml_import( $import_id ) {
1192 global $wpdb;
1193
1194 $post_ids = $wpdb->get_col( "SELECT post_id FROM {$wpdb->prefix}pmxi_posts WHERE import_id = {$import_id}" );
1195 $chunks = array_chunk( $post_ids, 200 );
1196
1197 // Schedule URI regenerate and split into bulks
1198 foreach ( $chunks as $i => $chunk ) {
1199 wp_schedule_single_event( time() + ( $i * 30 ), 'wpai_regenerate_uris_after_import_event', array( $chunk ) );
1200 }
1201 }
1202
1203 /**
1204 * 10FB. Regenerate the custom permalinks for all imported posts
1205 *
1206 * @param array $post_ids An array of post IDs that were just imported.
1207 */
1208 function wpai_regenerate_uris_after_import( $post_ids ) {
1209 global $permalink_manager_uris;
1210
1211 if ( ! is_array( $post_ids ) ) {
1212 return;
1213 }
1214
1215 foreach ( $post_ids as $id ) {
1216 if ( ! empty( $permalink_manager_uris[ $id ] ) ) {
1217 continue;
1218 }
1219
1220 $post_object = get_post( $id );
1221
1222 // Check if post is allowed
1223 if ( empty( $post_object->post_type ) || Permalink_Manager_Helper_Functions::is_post_excluded( $post_object, true ) ) {
1224 continue;
1225 }
1226
1227 $default_uri = Permalink_Manager_URI_Functions_Post::get_default_post_uri( $id );
1228 Permalink_Manager_URI_Functions::save_single_uri( $id, $default_uri );
1229 }
1230
1231 Permalink_Manager_URI_Functions::save_all_uris();
1232 }
1233
1234 /**
1235 * 11A. Add a new section to the WP All Export interface
1236 *
1237 * @param array $sections
1238 *
1239 * @return array
1240 */
1241 function wpae_custom_uri_section( $sections ) {
1242 if ( is_array( $sections ) ) {
1243 $sections['permalink_manager'] = array(
1244 'title' => __( 'Permalink Manager', 'permalink-manager' ),
1245 'content' => 'permalink_manager_fields'
1246 );
1247 }
1248
1249 return $sections;
1250 }
1251
1252 /**
1253 * 11B. Add a new field to the "Permalink Manager" section of the WP All Export interface
1254 *
1255 * @param array $fields The fields to be displayed in the section.
1256 *
1257 * @return array
1258 */
1259 function wpae_custom_uri_section_fields( $fields ) {
1260 if ( is_array( $fields ) ) {
1261 $fields['permalink_manager_fields'] = array(
1262 array(
1263 'label' => 'custom_uri',
1264 'name' => 'Custom URI',
1265 'type' => 'custom_uri'
1266 )
1267 );
1268 }
1269
1270 return $fields;
1271 }
1272
1273 /**
1274 * 11C. Add a new column to the export file with the custom permalink for each post/term
1275 *
1276 * @param array $articles The array of articles to be exported.
1277 * @param array $options an array of options for the export.
1278 *
1279 * @return array
1280 */
1281 function wpae_export_custom_uri( $articles, $options ) {
1282 if ( ( ! empty( $options['selected_post_type'] ) && $options['selected_post_type'] == 'taxonomies' ) || ! empty( $options['is_taxonomy_export'] ) ) {
1283 $is_term = true;
1284 } else {
1285 $is_term = false;
1286 }
1287
1288 foreach ( $articles as &$article ) {
1289 if ( ! empty( $article['id'] ) ) {
1290 $item_id = $article['id'];
1291 } else if ( ! empty( $article['ID'] ) ) {
1292 $item_id = $article['ID'];
1293 } else if ( ! empty( $article['Term ID'] ) ) {
1294 $item_id = $article['Term ID'];
1295 } else {
1296 continue;
1297 }
1298
1299 if ( ! empty( $is_term ) ) {
1300 $article['Custom URI'] = Permalink_Manager_URI_Functions_Tax::get_term_uri( $item_id );
1301 } else {
1302 $article['Custom URI'] = Permalink_Manager_URI_Functions_Post::get_post_uri( $item_id );
1303 }
1304 }
1305
1306 return $articles;
1307 }
1308
1309 /**
1310 * 12. Check if the "custom_uri" is not blacklisted in the "duplicate_post_blacklist" option and if it's not, clone the custom permalink of the original post to the new one
1311 *
1312 * @param int $new_post_id The ID of the newly created post.
1313 * @param WP_Post $old_post The post object of the original post.
1314 */
1315 function duplicate_custom_uri( $new_post_id, $old_post ) {
1316 global $permalink_manager_uris;
1317
1318 $duplicate_post_blacklist = get_option( 'duplicate_post_blacklist', false );
1319 $duplicate_custom_uri_bool = ( ! empty( $duplicate_post_blacklist ) && strpos( $duplicate_post_blacklist, 'custom_uri' ) !== false ) ? false : true;
1320
1321 if ( ! empty( $old_post->ID ) && $duplicate_custom_uri_bool ) {
1322 $old_post_id = $old_post->ID;
1323
1324 // Clone custom permalink (if set for cloned post/page)
1325 if ( ! empty( $permalink_manager_uris[ $old_post_id ] ) ) {
1326 $old_post_uri = $permalink_manager_uris[ $old_post_id ];
1327 $new_post_uri = preg_replace( '/(.+?)(\.[^\.]+$|$)/', '$1-2$2', $old_post_uri );
1328
1329 $permalink_manager_uris[ $new_post_id ] = $new_post_uri;
1330 update_option( 'permalink-manager-uris', $permalink_manager_uris );
1331 }
1332 }
1333 }
1334
1335 /**
1336 * 13A. Replace in the default permalink format the unique permastructure tags available for My Listing theme
1337 *
1338 * @param string $default_uri The default permalink for the element.
1339 * @param string $native_slug The native slug of the post type.
1340 * @param WP_Post $element The post object.
1341 * @param string $slug The slug of the post type.
1342 * @param bool $native_uri
1343 *
1344 * @return string
1345 */
1346 public function ml_listing_custom_fields( $default_uri, $native_slug, $element, $slug, $native_uri ) {
1347 // Use only for "listing" post type & custom permalink
1348 if ( empty( $element->post_type ) || $element->post_type !== 'job_listing' ) {
1349 return $default_uri;
1350 }
1351
1352 // A1. Listing type
1353 if ( strpos( $default_uri, '%listing-type%' ) !== false || strpos( $default_uri, '%listing_type%' ) !== false ) {
1354 if ( class_exists( 'MyListing\Src\Listing' ) ) {
1355 $listing_type_post = MyListing\Src\Listing::get( $element );
1356 $listing_type = ( is_object( $listing_type_post ) && ! empty( $listing_type_post->type ) ) ? $listing_type_post->type->get_permalink_name() : '';
1357 } else {
1358 $listing_type_slug = get_post_meta( $element->ID, '_case27_listing_type', true );
1359 $listing_type_post = get_page_by_path( $listing_type_slug, OBJECT, 'case27_listing_type' );
1360
1361 if ( ! empty( $listing_type_post ) ) {
1362 $listing_type_post_settings = get_post_meta( $listing_type_post->ID, 'case27_listing_type_settings_page', true );
1363 $listing_type_post_settings = ( is_serialized( $listing_type_post_settings ) ) ? unserialize( $listing_type_post_settings ) : array();
1364
1365 $listing_type = ( ! empty( $listing_type_post_settings['permalink'] ) ) ? $listing_type_post_settings['permalink'] : $listing_type_post->post_name;
1366 }
1367 }
1368
1369 if ( ! empty( $listing_type ) ) {
1370 $default_uri = str_replace( array( '%listing-type%', '%listing_type%' ), Permalink_Manager_Helper_Functions::sanitize_title( $listing_type, true ), $default_uri );
1371 }
1372 }
1373
1374 // A2. Listing type (slug)
1375 if ( strpos( $default_uri, '%listing-type-slug%' ) !== false || strpos( $default_uri, '%listing_type_slug%' ) !== false || strpos( $default_uri, '%case27_listing_type%' ) !== false ) {
1376 $listing_type = get_post_meta( $element->ID, '_case27_listing_type', true );
1377
1378 if ( ! empty( $listing_type ) ) {
1379 $listing_type = Permalink_Manager_Helper_Functions::sanitize_title( $listing_type, true );
1380 $default_uri = str_replace( array( '%listing-type-slug%', '%listing_type_slug%', '%case27_listing_type%' ), $listing_type, $default_uri );
1381 }
1382 }
1383
1384 // B. Listing location
1385 if ( strpos( $default_uri, '%listing-location%' ) !== false || strpos( $default_uri, '%listing_location%' ) !== false ) {
1386 $listing_location = get_post_meta( $element->ID, '_job_location', true );
1387
1388 if ( ! empty( $listing_location ) ) {
1389 $listing_location = Permalink_Manager_Helper_Functions::sanitize_title( $listing_location, true );
1390 $default_uri = str_replace( array( '%listing-location%', '%listing_location%' ), $listing_location, $default_uri );
1391 }
1392 }
1393
1394 // C. Listing region
1395 if ( strpos( $default_uri, '%listing-region%' ) !== false || strpos( $default_uri, '%listing_region%' ) !== false ) {
1396 $listing_region_terms = wp_get_object_terms( $element->ID, 'region' );
1397 $listing_region_term = ( ! is_wp_error( $listing_region_terms ) && ! empty( $listing_region_terms ) && is_object( $listing_region_terms[0] ) ) ? Permalink_Manager_Helper_Functions::get_lowest_element( $listing_region_terms[0], $listing_region_terms ) : "";
1398
1399 if ( ! empty( $listing_region_term ) ) {
1400 $listing_region = Permalink_Manager_Helper_Functions::get_term_full_slug( $listing_region_term, $listing_region_terms, 2 );
1401 $listing_region = Permalink_Manager_Helper_Functions::sanitize_title( $listing_region, true );
1402
1403 $default_uri = str_replace( array( '%listing-region%', '%listing_region%' ), $listing_region, $default_uri );
1404 }
1405 }
1406
1407 // D. Listing category
1408 if ( strpos( $default_uri, '%listing-category%' ) !== false || strpos( $default_uri, '%listing_category%' ) !== false ) {
1409 $listing_category_terms = wp_get_object_terms( $element->ID, 'job_listing_category' );
1410 $listing_category_term = ( ! is_wp_error( $listing_category_terms ) && ! empty( $listing_category_terms ) && is_object( $listing_category_terms[0] ) ) ? Permalink_Manager_Helper_Functions::get_lowest_element( $listing_category_terms[0], $listing_category_terms ) : "";
1411
1412 if ( ! empty( $listing_category_term ) ) {
1413 $listing_category = Permalink_Manager_Helper_Functions::get_term_full_slug( $listing_category_term, $listing_category_terms, 2 );
1414 $listing_category = Permalink_Manager_Helper_Functions::sanitize_title( $listing_category, true );
1415
1416 $default_uri = str_replace( array( '%listing-category%', '%listing_category%' ), $listing_category, $default_uri );
1417 }
1418 }
1419
1420 return $default_uri;
1421 }
1422
1423 /**
1424 * 13B. Set the default custom permalink for the listing item when it is created
1425 *
1426 * @param int $post_id
1427 */
1428 function ml_set_listing_uri( $post_id ) {
1429 global $permalink_manager_uris;
1430
1431 if ( ! empty( $permalink_manager_uris ) ) {
1432 $default_uri = Permalink_Manager_URI_Functions_Post::get_default_post_uri( $post_id );
1433
1434 if ( $default_uri ) {
1435 $permalink_manager_uris[ $post_id ] = $default_uri;
1436 update_option( 'permalink-manager-uris', $permalink_manager_uris );
1437 }
1438 }
1439 }
1440
1441 /**
1442 * 13C. If the user is on a MyListing archive page submitting a job, redirect the user to the Explore Listings page
1443 *
1444 * @param array $query The query object.
1445 * @param array $old_query The original query array.
1446 *
1447 * @return array The new query array is being returned if the explore_tab property is present. Otherwise, the original query is returned.
1448 */
1449 function ml_detect_archives( $query, $old_query ) {
1450 if ( function_exists( 'mylisting_custom_taxonomies' ) && empty( $_POST['submit_job'] ) ) {
1451 $explore_page_id = get_option( 'options_general_explore_listings_page', false );
1452 if ( empty( $explore_page_id ) ) {
1453 return $query;
1454 }
1455
1456 // 1. Set-up new query array variable
1457 $new_query = array(
1458 "page_id" => $explore_page_id
1459 );
1460
1461 // 2A. Check if any custom MyListing taxonomy was detected
1462 $ml_taxonomies = mylisting_custom_taxonomies();
1463
1464 if ( ! empty( $ml_taxonomies ) && is_array( $ml_taxonomies ) ) {
1465 $ml_taxonomies = array_keys( $ml_taxonomies );
1466
1467 foreach ( $ml_taxonomies as $taxonomy ) {
1468 if ( ! empty( $query[ $taxonomy ] ) && empty( $_GET[ $taxonomy ] ) ) {
1469 $new_query["explore_tab"] = $taxonomy;
1470 $new_query["explore_{$taxonomy}"] = $query['term'];
1471 }
1472 }
1473 }
1474
1475 // 2b. Check if any MyListing query var was detected
1476 $ml_query_vars = array(
1477 'explore_tag' => 'tags',
1478 'explore_region' => 'regions',
1479 'explore_category' => 'categories'
1480 );
1481
1482 foreach ( $ml_query_vars as $query_var => $explore_tab ) {
1483 if ( ! empty( $old_query[ $query_var ] ) && empty( $_GET[ $query_var ] ) ) {
1484 $new_query[ $query_var ] = $old_query[ $query_var ];
1485 $new_query["explore_tab"] = $explore_tab;
1486 }
1487 }
1488 }
1489
1490 return ( ! empty( $new_query["explore_tab"] ) ) ? $new_query : $query;
1491 }
1492
1493 /**
1494 * 14A. Add the bbPress endpoints to the list of endpoints that are supported by the plugin
1495 *
1496 * @param string $endpoints
1497 * @param bool $all Whether to return all endpoints or just the bbPress ones
1498 *
1499 * @return string|array
1500 */
1501 function bbpress_endpoints( $endpoints, $all = true ) {
1502 $bbpress_endpoints = array();
1503 $bbpress_endpoints[] = bbp_get_edit_slug();
1504
1505 return ( $all ) ? $endpoints . "|" . implode( "|", $bbpress_endpoints ) : $bbpress_endpoints;
1506 }
1507
1508 /**
1509 * 14B. If the query contains the edit endpoint, then set the appropriate bbPress query variable
1510 */
1511 function bbpress_detect_endpoints() {
1512 global $wp_query;
1513
1514 if ( ! empty( $wp_query->query ) ) {
1515 $edit_endpoint = bbp_get_edit_slug();
1516
1517 if ( isset( $wp_query->query[ $edit_endpoint ] ) ) {
1518 if ( isset( $wp_query->query['forum'] ) ) {
1519 $wp_query->bbp_is_forum_edit = true;
1520 } else if ( isset( $wp_query->query['topic'] ) ) {
1521 $wp_query->bbp_is_topic_edit = true;
1522 } else if ( isset( $wp_query->query['reply'] ) ) {
1523 $wp_query->bbp_is_reply_edit = true;
1524 }
1525 }
1526 }
1527 }
1528
1529 /**
1530 * 15A. Add the endpoint "edit" used by Dokan to the endpoints array supported by Permalink Manager
1531 *
1532 * @param string $endpoints
1533 *
1534 * @return string
1535 */
1536 function dokan_endpoints( $endpoints ) {
1537 return "{$endpoints}|edit|edit-account";
1538 }
1539
1540 /**
1541 * 15B. Check if the current page is a Dokan page, and if so, adjust the query variables to disable the canonical redirect
1542 */
1543 function dokan_detect_endpoints() {
1544 global $post, $wp_query, $wp, $pm_query;
1545
1546 // Check if Dokan is activated
1547 if ( ! function_exists( 'dokan_get_option' ) || is_admin() || empty( $pm_query['id'] ) ) {
1548 return;
1549 }
1550
1551 // Get Dokan dashboard page id
1552 $dashboard_page = dokan_get_option( 'dashboard', 'dokan_pages' );
1553
1554 // Stop the redirect
1555 if ( ! empty( $dashboard_page ) && ! empty( $post->ID ) && ( $post->ID == $dashboard_page ) ) {
1556 $wp->query_vars['do_not_redirect'] = 1;
1557
1558 // Detect Dokan shortcode
1559 if ( empty( $pm_query['endpoint'] ) ) {
1560 $wp->query_vars['page'] = 1;
1561 } else if ( isset( $wp->query_vars['page'] ) ) {
1562 unset( $wp->query_vars['page'] );
1563 }
1564 }
1565
1566 // 2. Support "Edit Product" pages
1567 if ( isset( $wp_query->query_vars['edit'] ) ) {
1568 $wp_query->query_vars['edit'] = 1;
1569 $wp_query->query_vars['do_not_redirect'] = 1;
1570 }
1571 }
1572
1573 /**
1574 * 16. Replace in the default permalink format the unique permastructure tags available for GeoDirectory plugin
1575 *
1576 * @param string $default_uri The default permalink for the element.
1577 * @param string $native_slug The native slug of the post type.
1578 * @param WP_Post $element The post object.
1579 * @param string $slug The slug of the post type.
1580 * @param bool $native_uri
1581 *
1582 * @return string
1583 */
1584 public function geodir_custom_fields( $default_uri, $native_slug, $element, $slug, $native_uri ) {
1585 // Use only for GeoDirectory post types & custom permalinks
1586 if ( empty( $element->post_type ) || ( strpos( $element->post_type, 'gd_' ) === false ) || $native_uri || ! function_exists( 'geodir_get_post_info' ) ) {
1587 return $default_uri;
1588 }
1589
1590 // Get place info
1591 $place_data = geodir_get_post_info( $element->ID );
1592
1593 // A. Category
1594 if ( strpos( $default_uri, '%category%' ) !== false ) {
1595 $place_category_terms = wp_get_object_terms( $element->ID, 'gd_placecategory' );
1596 $place_category_term = ( ! is_wp_error( $place_category_terms ) && ! empty( $place_category_terms ) && is_object( $place_category_terms[0] ) ) ? Permalink_Manager_Helper_Functions::get_lowest_element( $place_category_terms[0], $place_category_terms ) : "";
1597
1598 if ( ! empty( $place_category_term ) && is_a( $place_category_term, 'WP_Term' ) ) {
1599 $place_category = Permalink_Manager_Helper_Functions::get_term_full_slug( $place_category_term, '', 2 );
1600 $place_category = Permalink_Manager_Helper_Functions::sanitize_title( $place_category, true );
1601
1602 $default_uri = str_replace( '%category%', $place_category, $default_uri );
1603 }
1604 }
1605
1606 // B. Country
1607 if ( strpos( $default_uri, '%country%' ) !== false && ! empty( $place_data->country ) ) {
1608 $place_country = Permalink_Manager_Helper_Functions::sanitize_title( $place_data->country, true );
1609 $default_uri = str_replace( '%country%', $place_country, $default_uri );
1610 }
1611
1612 // C. Region
1613 if ( strpos( $default_uri, '%region%' ) !== false && ! empty( $place_data->region ) ) {
1614 $place_region = Permalink_Manager_Helper_Functions::sanitize_title( $place_data->region, true );
1615 $default_uri = str_replace( '%region%', $place_region, $default_uri );
1616 }
1617
1618 // D. City
1619 if ( strpos( $default_uri, '%city%' ) !== false && ! empty( $place_data->city ) ) {
1620 $place_city = Permalink_Manager_Helper_Functions::sanitize_title( $place_data->city, true );
1621 $default_uri = str_replace( '%city%', $place_city, $default_uri );
1622 }
1623
1624 return $default_uri;
1625 }
1626
1627 /**
1628 * 17. Adjust the query if BasePress page is detected
1629 *
1630 * @param array $query The query object.
1631 * @param array $old_query The original query array.
1632 * @param array $uri_parts An array of the URI parts.
1633 * @param array $pm_query
1634 * @param string $content_type
1635 *
1636 * @return array
1637 */
1638 function kb_adjust_query( $query, $old_query, $uri_parts, $pm_query, $content_type ) {
1639 $knowledgebase_options = get_option( 'basepress_settings' );
1640 $knowledgebase_page = ( ! empty( $knowledgebase_options['entry_page'] ) ) ? $knowledgebase_options['entry_page'] : '';
1641
1642 // A. Knowledgebase category
1643 if ( isset( $query['knowledgebase_cat'] ) && ! empty( $pm_query['id'] ) ) {
1644 $kb_category = $query['knowledgebase_cat'];
1645
1646 $query = array(
1647 'post_type' => 'knowledgebase',
1648 'knowledgebase_items' => $kb_category
1649 );
1650
1651 // Disable the canonical redirect function included in BasePress
1652 add_filter( 'basepress_canonical_redirect', '__return_false' );
1653 } // B. Knowledgebase main page
1654 else if ( ! empty( $knowledgebase_page ) && ! empty( $pm_query['id'] ) && $pm_query['id'] == $knowledgebase_page ) {
1655 $query = array(
1656 'page_id' => $knowledgebase_page
1657 );
1658 }
1659
1660 return $query;
1661 }
1662
1663 /**
1664 * 18. Detect the extra pages created by Ultimate Member plugin
1665 *
1666 * @param array $uri_parts
1667 *
1668 * @return array
1669 */
1670 public function um_detect_extra_pages( $uri_parts ) {
1671 global $permalink_manager_uris;
1672
1673 $request_url = trim( "{$uri_parts['uri']}/{$uri_parts['endpoint_value']}", "/" );
1674 $um_pages = array(
1675 'user' => 'um_user',
1676 'account' => 'um_tab',
1677 );
1678
1679 // Detect UM permalinks
1680 foreach ( $um_pages as $um_page => $query_var ) {
1681 $um_page_id = UM()->config()->permalinks[ $um_page ];
1682 // Support for WPML/Polylang
1683 $um_page_id = ( ! empty( $uri_parts['lang'] ) ) ? apply_filters( 'wpml_object_id', $um_page_id, 'page', true, $uri_parts['lang'] ) : $um_page_id;
1684
1685 if ( ! empty( $um_page_id ) && ! empty( $permalink_manager_uris[ $um_page_id ] ) ) {
1686 $user_page_uri = preg_quote( $permalink_manager_uris[ $um_page_id ], '/' );
1687 preg_match( "/^({$user_page_uri})\/([^\/]+)?$/", $request_url, $parts );
1688
1689 if ( ! empty( $parts[2] ) ) {
1690 $uri_parts['uri'] = $parts[1];
1691 $uri_parts['endpoint'] = $query_var;
1692 $uri_parts['endpoint_value'] = Permalink_Manager_Helper_Functions::sanitize_title( $parts[2], null, null, false );
1693 }
1694 }
1695 }
1696
1697 return $uri_parts;
1698 }
1699
1700 /**
1701 * 19. Keep the query strings appended to the product permalinks by WooCommerce Subscriptions
1702 *
1703 * @param string $permalink
1704 * @param WP_Post $post
1705 * @param string $old_permalink
1706 *
1707 * @return string
1708 */
1709 function wcs_fix_subscription_links( $permalink, $post, $old_permalink ) {
1710 if ( ! empty( $post->post_type ) && $post->post_type == 'product' && strpos( $old_permalink, 'switch-subscription=' ) !== false ) {
1711 $query_arg = parse_url( $old_permalink, PHP_URL_QUERY );
1712 $permalink = "{$permalink}?{$query_arg}";
1713 }
1714
1715 return $permalink;
1716 }
1717
1718 /**
1719 * 20. Excluding the LearnPress pages from Permalink Manager
1720 *
1721 * @param array $excluded_ids
1722 *
1723 * @return array
1724 */
1725 function learnpress_exclude_pages( $excluded_ids ) {
1726 if ( is_array( $excluded_ids ) && function_exists( 'learn_press_get_page_id' ) ) {
1727 $learnpress_pages = array( 'profile', 'courses', 'checkout', 'become_a_teacher' );
1728
1729 foreach ( $learnpress_pages as $page ) {
1730 $learnpress_page_id = learn_press_get_page_id( $page );
1731
1732 if ( empty( $learnpress_page_id ) || in_array( $learnpress_page_id, $excluded_ids ) ) {
1733 continue;
1734 }
1735
1736 $excluded_ids[] = $learnpress_page_id;
1737 }
1738 }
1739
1740 return $excluded_ids;
1741 }
1742
1743 /**
1744 * 21. Regenerate the default permalink for the post after the custom permalink is imported by Store Locator - CSV Manager
1745 *
1746 * @param int $meta_id The ID of the metadata entry.
1747 * @param int $post_id The ID of the post that the metadata is for.
1748 * @param string $meta_key The meta key of the metadata being updated.
1749 * @param mixed $meta_value The value of the meta key.
1750 */
1751 public function wpsl_regenerate_after_import( $meta_id, $post_id, $meta_key, $meta_value ) {
1752 global $permalink_manager_uris;
1753
1754 if ( strpos( $meta_key, 'wpsl_' ) !== false && isset( $_POST['wpsl_csv_import_nonce'] ) ) {
1755 $default_uri = Permalink_Manager_URI_Functions_Post::get_default_post_uri( $post_id );
1756
1757 if ( $default_uri ) {
1758 $permalink_manager_uris[ $post_id ] = $default_uri;
1759 update_option( 'permalink-manager-uris', $permalink_manager_uris );
1760 }
1761 }
1762 }
1763
1764 }
1765