PluginProbe ʕ •ᴥ•ʔ
Permalink Manager Lite / 2.4.4.3
Permalink Manager Lite v2.4.4.3
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 / integrations / permalink-manager-woocommerce.php
permalink-manager / includes / integrations Last commit date
permalink-manager-language-plugins.php 1 year ago permalink-manager-seo-plugins.php 1 year ago permalink-manager-third-parties.php 1 year ago permalink-manager-woocommerce.php 1 year ago
permalink-manager-woocommerce.php
375 lines
1 <?php
2
3 /**
4 * WooCommerce plugins integration
5 */
6 class Permalink_Manager_WooCommerce {
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 SEO plugins using their hooks
15 */
16 function init_hooks() {
17 if ( class_exists( 'WooCommerce' ) ) {
18 add_filter( 'permalink_manager_filter_query', array( $this, 'woocommerce_detect' ), 8, 5 );
19 add_filter( 'template_redirect', array( $this, 'woocommerce_checkout_fix' ), 9 );
20
21 if ( class_exists( 'Permalink_Manager_Pro_Functions' ) ) {
22 if ( empty( $permalink_manager_options['general']['partial_disable']['post_types'] ) || ! in_array( 'shop_coupon', $permalink_manager_options['general']['partial_disable']['post_types'] ) ) {
23 if ( is_admin() ) {
24 add_filter( 'woocommerce_coupon_data_tabs', 'Permalink_Manager_Pro_Functions::woocommerce_coupon_tabs' );
25 add_action( 'woocommerce_coupon_data_panels', 'Permalink_Manager_Pro_Functions::woocommerce_coupon_panel' );
26 add_action( 'woocommerce_coupon_options_save', 'Permalink_Manager_Pro_Functions::woocommerce_save_coupon_uri', 9, 2 );
27 }
28
29 add_filter( 'request', 'Permalink_Manager_Pro_Functions::woocommerce_detect_coupon_code', 1, 1 );
30 }
31 } else {
32 add_filter( 'permalink_manager_disabled_post_types', array( $this, 'woocommerce_coupon_uris' ), 9, 1 );
33 }
34
35 // WooCommerce Import/Export
36 add_filter( 'woocommerce_product_export_product_default_columns', array( $this, 'woocommerce_csv_custom_uri_column' ), 9 );
37 add_filter( 'woocommerce_product_export_product_column_custom_uri', array( $this, 'woocommerce_export_custom_uri_value' ), 9, 3 );
38
39 add_filter( 'woocommerce_csv_product_import_mapping_options', array( $this, 'woocommerce_csv_custom_uri_column' ), 9 );
40 add_filter( 'woocommerce_csv_product_import_mapping_default_columns', array( $this, 'woocommerce_csv_custom_uri_column' ), 9 );
41 add_action( 'woocommerce_product_import_inserted_product_object', array( $this, 'woocommerce_csv_import_custom_uri' ), 9, 2 );
42
43 add_action( 'woocommerce_product_duplicate', array( $this, 'woocommerce_generate_permalinks_after_duplicate' ), 9, 2 );
44 add_filter( 'permalink_manager_filter_default_post_uri', array( $this, 'woocommerce_product_attributes' ), 5, 5 );
45
46 if ( wp_doing_ajax() && class_exists( 'SitePress' ) ) {
47 add_filter( 'permalink_manager_filter_final_post_permalink', array( $this, 'woocommerce_translate_ajax_fragments_urls' ), 9999, 3 );
48 }
49 }
50
51 // WooCommerce Wishlist Plugin
52 if ( function_exists( 'tinv_get_option' ) ) {
53 add_filter( 'permalink_manager_detect_uri', array( $this, 'ti_woocommerce_wishlist_uris' ), 15, 3 );
54 }
55
56 // WooCommerce Subscriptions
57 if ( class_exists( 'WC_Subscriptions' ) ) {
58 add_filter( 'permalink_manager_filter_final_post_permalink', array( $this, 'wcs_fix_subscription_links' ), 10, 3 );
59 }
60 }
61
62 /**
63 * Some hooks must be called shortly after all the plugins are loaded
64 */
65 public function init_early_hooks() {
66 if ( class_exists( 'WooCommerce' ) ) {
67 add_filter( 'woocommerce_get_endpoint_url', array( 'Permalink_Manager_Core_Functions', 'control_trailing_slashes' ), 9 );
68 add_action( 'before_woocommerce_init', array( $this, 'woocommerce_declare_compatibility' ) );
69 }
70 }
71
72 /**
73 * Fix query on WooCommerce shop page & disable the canonical redirect if WooCommerce query variables are set
74 */
75 function woocommerce_detect( $query, $old_query, $uri_parts, $pm_query, $content_type ) {
76 global $woocommerce, $pm_query;
77
78 $shop_page_id = get_option( 'woocommerce_shop_page_id' );
79
80 // WPML - translate shop page id
81 $shop_page_id = apply_filters( 'wpml_object_id', $shop_page_id, 'page', true );
82
83 // Fix shop page
84 if ( get_theme_support( 'woocommerce' ) && ! empty( $pm_query['id'] ) && is_numeric( $pm_query['id'] ) && $shop_page_id == $pm_query['id'] ) {
85 $query['post_type'] = 'product';
86 unset( $query['pagename'] );
87 }
88
89 // Fix WooCommerce pages
90 if ( ! empty( $woocommerce->query->query_vars ) ) {
91 $query_vars = $woocommerce->query->query_vars;
92
93 foreach ( $query_vars as $key => $val ) {
94 if ( isset( $query[ $key ] ) ) {
95 $query['do_not_redirect'] = 1;
96 break;
97 }
98 }
99 }
100
101 return $query;
102 }
103
104 /**
105 * Redirects the user from the Shop archive to the Shop page if the user is not searching for anything
106 * Disable canonical redirect on "thank you" & another WooCommerce pages
107 */
108 function woocommerce_checkout_fix() {
109 global $wp_query, $pm_query, $permalink_manager_options;
110
111 // Redirect from Shop archive to selected page
112 if ( is_shop() && empty( $pm_query['id'] ) ) {
113 $redirect_mode = ( ! empty( $permalink_manager_options['general']['redirect'] ) ) ? $permalink_manager_options['general']['redirect'] : false;
114 $redirect_shop = apply_filters( 'permalink_manager_redirect_shop_archive', false );
115 $shop_page = get_option( 'woocommerce_shop_page_id' );
116
117 if ( $redirect_mode && $redirect_shop && $shop_page && empty( $wp_query->query_vars['s'] ) ) {
118 $shop_url = get_permalink( $shop_page );
119 wp_safe_redirect( $shop_url, $redirect_mode );
120 exit();
121 }
122 }
123
124 if ( is_checkout() || ( function_exists( 'is_wc_endpoint_url' ) && is_wc_endpoint_url() ) ) {
125 $wp_query->query_vars['do_not_redirect'] = 1;
126 }
127 }
128
129 /**
130 * Add "Coupons" to the list of excluded post types
131 *
132 * @param array $post_types
133 *
134 * @return array
135 */
136 public function woocommerce_coupon_uris( $post_types ) {
137 if ( is_array( $post_types ) ) {
138 $post_types[] = 'shop_coupon';
139 }
140
141 return $post_types;
142 }
143
144 /**
145 * Generate a new custom permalink for duplicated product
146 *
147 * @param WC_Product $new_product The new product object.
148 * @param WC_Product $old_product The product that was duplicated.
149 */
150 function woocommerce_generate_permalinks_after_duplicate( $new_product, $old_product ) {
151 if ( ! empty( $new_product ) ) {
152 $product_id = $new_product->get_id();
153
154 // Ignore variations
155 if ( $new_product->get_type() === 'variation' || Permalink_Manager_Helper_Functions::is_post_excluded( $product_id, true ) ) {
156 return;
157 }
158
159 $custom_uri = Permalink_Manager_URI_Functions_Post::get_default_post_uri( $product_id, false, true );
160 Permalink_Manager_URI_Functions::save_single_uri( $product_id, $custom_uri, false, true );
161 }
162 }
163
164 /**
165 * If the URI contains %pa_attribute_name% tag, replace it with the value of the attribute
166 *
167 * @param string $default_uri The default custom permalink that WordPress would use for the post.
168 * @param string $slug The post slug.
169 * @param WP_Post $post The post object.
170 * @param string $post_name The post slug.
171 * @param bool $native_uri true if the URI is a native URI, false if it's a custom URI
172 *
173 * @return string The default custom permalink
174 */
175 function woocommerce_product_attributes( $default_uri, $slug, $post, $post_name, $native_uri ) {
176 // Do not affect native URIs
177 if ( $native_uri ) {
178 return $default_uri;
179 }
180
181 // Use only for products
182 if ( empty( $post->post_type ) || $post->post_type !== 'product' ) {
183 return $default_uri;
184 }
185
186 preg_match_all( "/%pa_(.[^\%]+)%/", $default_uri, $custom_fields );
187
188 if ( ! empty( $custom_fields[1] ) ) {
189 $product = wc_get_product( $post->ID );
190
191 foreach ( $custom_fields[1] as $i => $custom_field ) {
192 $attribute_name = sanitize_title( $custom_field );
193 $attribute_value = $product->get_attribute( $attribute_name );
194
195 $default_uri = str_replace( $custom_fields[0][ $i ], Permalink_Manager_Helper_Functions::sanitize_title( $attribute_value ), $default_uri );
196 }
197 }
198
199 return $default_uri;
200 }
201
202 /**
203 * Check the current request is a WooCommerce AJAX request. If it is, check the translated page's URL should be returned
204 *
205 * @param string $permalink The full URL of the post
206 * @param WP_Post $post The post object
207 * @param string $old_permalink The original URL of the post.
208 *
209 * @return string The permalink is being returned.
210 */
211 function woocommerce_translate_ajax_fragments_urls( $permalink, $post, $old_permalink ) {
212 // Use it only if the permalinks are different
213 if ( $permalink == $old_permalink || $post->post_type !== 'page' ) {
214 return $permalink;
215 }
216
217 // A. Native WooCommerce AJAX events
218 if ( ! empty( $_REQUEST['wc-ajax'] ) ) {
219 $action = sanitize_title( $_REQUEST['wc-ajax'] );
220 } // B. Shoptimizer theme
221 else if ( ! empty( $_REQUEST['action'] ) ) {
222 $action = sanitize_title( $_REQUEST['action'] );
223 }
224
225 // Allowed action names
226 $allowed_actions = array( 'shoptimizer_pdp_ajax_atc', 'get_refreshed_fragments' );
227
228 if ( ! empty( $action ) && in_array( $action, $allowed_actions ) ) {
229 $translated_post_id = apply_filters( 'wpml_object_id', $post->ID, 'page' );
230 $permalink = ( $translated_post_id !== $post->ID ) ? get_permalink( $translated_post_id ) : $permalink;
231 }
232
233 return $permalink;
234 }
235
236 /**
237 * 4FA. Add a new column to the WooCommerce CSV Import/Export tool
238 *
239 * @param array $columns The array of columns to be displayed.
240 *
241 * @return array The $columns array.
242 */
243 function woocommerce_csv_custom_uri_column( $columns ) {
244 if ( ! is_array( $columns ) ) {
245 return $columns;
246 }
247
248 $label = __( 'Custom URI', 'permalink-manager' );
249 $key = 'custom_uri';
250
251 if ( current_filter() == 'woocommerce_csv_product_import_mapping_default_columns' ) {
252 $columns[ $label ] = $key;
253 } else {
254 $columns[ $key ] = $label;
255 }
256
257 return $columns;
258 }
259
260 /**
261 * 4FB. Return the custom permalink of the product if it exists, otherwise return the default URI
262 *
263 * @param string $value The value of the column.
264 * @param WC_Product $product The product object.
265 * @param mixed $column_id The column ID.
266 *
267 * @return string The custom permalink or default permalink
268 */
269 function woocommerce_export_custom_uri_value( $value, $product, $column_id ) {
270 if ( empty( $value ) && ! empty( $product ) ) {
271 $product_id = $product->get_id();
272
273 // Get custom permalink or default permalink
274 $value = Permalink_Manager_URI_Functions_Post::get_post_uri( $product_id );
275 }
276
277 return $value;
278 }
279
280 /**
281 * 4FC. Set the custom URI for the product using the value from CSV file, if not set use the default permalink
282 *
283 * @param WC_Product $product The product object.
284 * @param array $data The data array for the current row being imported.
285 */
286 function woocommerce_csv_import_custom_uri( $product, $data ) {
287 if ( ! empty( $product ) ) {
288 $product_id = $product->get_id();
289
290 // Ignore variations
291 if ( $product->get_type() == 'variation' ) {
292 return;
293 }
294
295 $current_uri = Permalink_Manager_URI_Functions::get_single_uri( $product_id, false, true );
296
297 // A. Use default permalink if "Custom URI" is not set and did not exist before
298 if ( empty( $current_uri ) && empty( $data['custom_uri'] ) ) {
299 $custom_uri = Permalink_Manager_URI_Functions_Post::get_default_post_uri( $product_id, false, true );
300 } else if ( ! empty( $data['custom_uri'] ) ) {
301 $custom_uri = Permalink_Manager_Helper_Functions::sanitize_title( $data['custom_uri'] );
302 } else {
303 return;
304 }
305
306 Permalink_Manager_URI_Functions::save_single_uri( $product_id, $custom_uri, false, true );
307 }
308 }
309
310 /**
311 * Declare support for 'High-Performance order storage (COT)' and other features in WooCommerce
312 */
313 function woocommerce_declare_compatibility() {
314 $features_util_class = '\Automattic\WooCommerce\Utilities\FeaturesUtil';
315
316 if ( class_exists( $features_util_class ) && method_exists( $features_util_class, 'declare_compatibility' ) ) {
317 $features = method_exists( $features_util_class, 'get_features' ) ? $features_util_class::get_features( true ) : array();
318
319 foreach ( array_keys( $features ) as $feature ) {
320 $features_util_class::declare_compatibility( $feature, PERMALINK_MANAGER_BASENAME );
321 }
322 }
323 }
324
325 /**
326 * Extract the Wishlist ID from the URI and add it to the $uri_parts array (WooCommerce Wishlist Plugin)
327 *
328 * @param array $uri_parts An array of the URI parts.
329 * @param string $request_url The URL that was requested.
330 * @param array $endpoints An array of all the endpoints that are currently registered.
331 *
332 * @return array The URI parts.
333 */
334 function ti_woocommerce_wishlist_uris( $uri_parts, $request_url, $endpoints ) {
335 $wishlist_pid = function_exists( 'tinv_get_option' ) ? tinv_get_option( 'general', 'page_wishlist' ) : '';
336
337 // Find the Wishlist page URI
338 if ( is_numeric( $wishlist_pid )) {
339 $current_uri = Permalink_Manager_URI_Functions::get_single_uri( $wishlist_pid, false, true );
340
341 if ( ! empty( $current_uri ) ) {
342 $wishlist_uri = preg_quote( $current_uri, '/' );
343
344 // Extract the Wishlist ID
345 preg_match( "/^({$wishlist_uri})\/([^\/]+)\/?$/", $uri_parts['uri'], $output_array );
346
347 if ( ! empty( $output_array[2] ) ) {
348 $uri_parts['uri'] = $output_array[1];
349 $uri_parts['endpoint'] = 'tinvwlID';
350 $uri_parts['endpoint_value'] = $output_array[2];
351 }
352 }
353 }
354
355 return $uri_parts;
356 }
357
358 /**
359 * Keep the query strings appended to the product permalinks by WooCommerce Subscriptions
360 *
361 * @param string $permalink
362 * @param WP_Post $post
363 * @param string $old_permalink
364 *
365 * @return string
366 */
367 function wcs_fix_subscription_links( $permalink, $post, $old_permalink ) {
368 if ( ! empty( $post->post_type ) && $post->post_type == 'product' && strpos( $old_permalink, 'switch-subscription=' ) !== false ) {
369 $query_arg = parse_url( $old_permalink, PHP_URL_QUERY );
370 $permalink = "{$permalink}?{$query_arg}";
371 }
372
373 return $permalink;
374 }
375 }