PluginProbe ʕ •ᴥ•ʔ
Meta for WooCommerce / 1.11.3
Meta for WooCommerce v1.11.3
3.7.1 trunk 1.10.0 1.10.1 1.10.2 1.11.0 1.11.1 1.11.2 1.11.3 1.11.4 1.9.11 1.9.12 1.9.13 1.9.14 1.9.15 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.2.0 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.3.5 2.4.0 2.4.1 2.5.0 2.5.1 2.6.0 2.6.1 2.6.10 2.6.11 2.6.12 2.6.13 2.6.14 2.6.15 2.6.16 2.6.17 2.6.18 2.6.19 2.6.2 2.6.20 2.6.21 2.6.22 2.6.23 2.6.24 2.6.25 2.6.26 2.6.27 2.6.28 2.6.29 2.6.3 2.6.30 2.6.4 2.6.5 2.6.6 2.6.7 2.6.8 2.6.9 3.0.0 3.0.1 3.0.10 3.0.11 3.0.12 3.0.13 3.0.14 3.0.15 3.0.16 3.0.17 3.0.18 3.0.19 3.0.2 3.0.20 3.0.21 3.0.22 3.0.23 3.0.24 3.0.25 3.0.26 3.0.27 3.0.28 3.0.29 3.0.3 3.0.30 3.0.31 3.0.32 3.0.33 3.0.34 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.10 3.1.11 3.1.12 3.1.13 3.1.14 3.1.15 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.1 3.2.10 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.4.0 3.4.1 3.4.10 3.4.2 3.4.3 3.4.4 3.4.5 3.4.6 3.4.7 3.4.8 3.4.9 3.5.10 3.5.11 3.5.12 3.5.13 3.5.14 3.5.15 3.5.16 3.5.17 3.5.18 3.5.2 3.5.3 3.5.4 3.5.5 3.5.6 3.5.7 3.5.8 3.5.9 3.6.0 3.6.1 3.6.2 3.6.3 3.7.0
facebook-for-woocommerce / includes / Admin.php
facebook-for-woocommerce / includes Last commit date
Integrations 6 years ago Products 6 years ago Utilities 6 years ago test 6 years ago AJAX.php 6 years ago Admin.php 6 years ago Lifecycle.php 6 years ago Products.php 6 years ago fbasync.php 6 years ago fbbackground.php 6 years ago fbgraph.php 6 years ago fbinfobanner.php 6 years ago fbproduct.php 6 years ago fbproductfeed.php 6 years ago fbutils.php 6 years ago fbwpml.php 6 years ago
Admin.php
1122 lines
1 <?php
2 /**
3 * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
4 *
5 * This source code is licensed under the license found in the
6 * LICENSE file in the root directory of this source tree.
7 *
8 * @package FacebookCommerce
9 */
10
11 namespace SkyVerge\WooCommerce\Facebook;
12
13 use SkyVerge\WooCommerce\PluginFramework\v5_5_4\SV_WC_Helper;
14
15 defined( 'ABSPATH' ) or exit;
16
17 /**
18 * Admin handler.
19 *
20 * @since 1.10.0
21 */
22 class Admin {
23
24
25 /**
26 * Admin constructor.
27 *
28 * @since 1.10.0
29 */
30 public function __construct() {
31
32 // enqueue admin scripts
33 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
34
35 $integration = facebook_for_woocommerce()->get_integration();
36
37 // only alter the admin UI if the plugin is connected to Facebook and ready to sync products
38 if ( ! $integration->get_product_catalog_id() ) {
39 return;
40 }
41
42 // add a modal in admin product pages
43 add_action( 'admin_footer', [ $this, 'render_modal_template' ] );
44 // may trigger the modal to open to warn the merchant about a conflict with the current product terms
45 add_action( 'admin_footer', [ $this, 'validate_product_excluded_terms' ] );
46
47 // add admin notification in case of site URL change
48 add_action( 'admin_notices', [ $this, 'validate_cart_url' ] );
49
50 // add admin notice to inform that product sync has changed
51 add_action( 'admin_notices', [ $this, 'add_product_sync_delay_notice' ] );
52 // add admin notice to inform that the catalog visibility setting was removed
53 add_action( 'admin_notices', [ $this, 'add_catalog_visibility_settings_removed_notice' ] );
54 // add admin notice if the user attempted to enable sync for virtual products using the bulk action
55 add_action( 'admin_notices', [ $this, 'add_enabling_virtual_products_sync_notice' ] );
56 // add admin notice to inform sync has been automatically disabled for virtual products
57 add_action( 'admin_notices', [ $this, 'add_disabled_virtual_products_sync_notice' ] );
58
59 // handle dismissal of special notices
60 add_action( 'wc_' . facebook_for_woocommerce()->get_id(). '_dismiss_notice', [ $this, 'handle_dismiss_notice' ], 10, 2 );
61
62 // add columns for displaying Facebook sync enabled/disabled and catalog visibility status
63 add_filter( 'manage_product_posts_columns', [ $this, 'add_product_list_table_columns' ] );
64 add_action( 'manage_product_posts_custom_column', [ $this, 'add_product_list_table_columns_content' ] );
65
66 // add input to filter products by Facebook sync enabled
67 add_action( 'restrict_manage_posts', [ $this, 'add_products_by_sync_enabled_input_filter' ], 40 );
68 add_filter( 'request', [ $this, 'filter_products_by_sync_enabled' ] );
69
70 // add bulk actions to manage products sync
71 add_filter( 'bulk_actions-edit-product', [ $this, 'add_products_sync_bulk_actions' ], 40 );
72 add_action( 'handle_bulk_actions-edit-product', [ $this, 'handle_products_sync_bulk_actions' ] );
73
74 // add Product data tab
75 add_filter( 'woocommerce_product_data_tabs', [ $this, 'add_product_settings_tab' ] );
76 add_action( 'woocommerce_product_data_panels', [ $this, 'add_product_settings_tab_content' ] );
77
78 // add Variation edit fields
79 add_action( 'woocommerce_product_after_variable_attributes', [ $this, 'add_product_variation_edit_fields' ], 10, 3 );
80 add_action( 'woocommerce_save_product_variation', [ $this, 'save_product_variation_edit_fields' ], 10, 2 );
81 }
82
83
84 /**
85 * Enqueues admin scripts.
86 *
87 * @internal
88 *
89 * @since 1.10.0
90 */
91 public function enqueue_scripts() {
92 global $current_screen;
93
94 $modal_screens = [
95 'product',
96 'edit-product',
97 ];
98
99 if ( isset( $current_screen->id ) ) {
100
101 if ( in_array( $current_screen->id, $modal_screens, true ) || facebook_for_woocommerce()->is_plugin_settings() ) {
102
103 // enqueue modal functions
104 wp_enqueue_script( 'facebook-for-woocommerce-modal', plugins_url( '/facebook-for-woocommerce/assets/js/facebook-for-woocommerce-modal.min.js' ), [ 'jquery', 'wc-backbone-modal', 'jquery-blockui' ], \WC_Facebookcommerce::PLUGIN_VERSION );
105 }
106
107 if ( 'product' === $current_screen->id || 'edit-product' === $current_screen->id ) {
108
109 wp_enqueue_style( 'facebook-for-woocommerce-products-admin', plugins_url( '/facebook-for-woocommerce/assets/css/admin/facebook-for-woocommerce-products-admin.css' ), [], \WC_Facebookcommerce::PLUGIN_VERSION );
110
111 wp_enqueue_script( 'facebook-for-woocommerce-products-admin', plugins_url( '/facebook-for-woocommerce/assets/js/admin/facebook-for-woocommerce-products-admin.min.js' ), [ 'jquery', 'wc-backbone-modal', 'jquery-blockui', 'facebook-for-woocommerce-modal' ], \WC_Facebookcommerce::PLUGIN_VERSION );
112
113 wp_localize_script( 'facebook-for-woocommerce-products-admin', 'facebook_for_woocommerce_products_admin', [
114 'ajax_url' => admin_url( 'admin-ajax.php' ),
115 'set_product_visibility_nonce' => wp_create_nonce( 'set-products-visibility' ),
116 'set_product_sync_prompt_nonce' => wp_create_nonce( 'set-product-sync-prompt' ),
117 'set_product_sync_bulk_action_prompt_nonce' => wp_create_nonce( 'set-product-sync-bulk-action-prompt' ),
118 ] );
119 }
120
121 if ( facebook_for_woocommerce()->is_plugin_settings() ) {
122
123 wp_enqueue_script( 'facebook-for-woocommerce-settings-sync', plugins_url( '/facebook-for-woocommerce/assets/js/admin/facebook-for-woocommerce-settings-sync.min.js' ), [ 'jquery', 'wc-backbone-modal', 'jquery-blockui', 'facebook-for-woocommerce-modal' ], \WC_Facebookcommerce::PLUGIN_VERSION );
124
125 /* translators: Placeholders %1$s - opening <strong> html tag, %2$s closing </strong> html tag, {count} number of remaining items */
126 $sync_remaining_items_string = _n_noop( '%1$sProgress:%2$s {count} item remaining.', '%1$sProgress:%2$s {count} items remaining.', 'facebook-for-woocommerce' );
127
128 wp_localize_script( 'facebook-for-woocommerce-settings-sync', 'facebook_for_woocommerce_settings_sync', [
129 'ajax_url' => admin_url( 'admin-ajax.php' ),
130 'set_excluded_terms_prompt_nonce' => wp_create_nonce( 'set-excluded-terms-prompt' ),
131 'set_product_visibility_nonce' => wp_create_nonce( 'set-products-visibility' ),
132 'i18n' => [
133 /* translators: Placeholders %s - html code for a spinner icon */
134 'confirm_resync' => esc_html__( 'Your products will now be resynced to Facebook, this may take some time.', 'facebook-for-woocommerce' ),
135 'confirm_sync_test' => esc_html__( 'Launch Test?', 'facebook-for-woocommerce' ),
136 'confirm_sync' => esc_html__( "Facebook for WooCommerce automatically syncs your products on create/update. Are you sure you want to force product resync?\n\nThis will query all published products and may take some time. You only need to do this if your products are out of sync or some of your products did not sync.", 'facebook-for-woocommerce' ),
137 'sync_in_progress' => sprintf( esc_html__( 'Syncing... Keep this browser open until sync is complete. %s', 'facebook-for-woocommerce' ), '<span class="spinner is-active"></span>' ),
138 'sync_remaining_items_singular' => sprintf( esc_html( translate_nooped_plural( $sync_remaining_items_string, 1 ) ), '<strong>', '</strong>', '<span class="spinner is-active"></span>' ),
139 'sync_remaining_items_plural' => sprintf( esc_html( translate_nooped_plural( $sync_remaining_items_string, 2 ) ), '<strong>', '</strong>', '<span class="spinner is-active"></span>' ),
140 /* translators: Placeholders %1$s - opening <strong> html tag, %2$s closing </strong> html tag */
141 'integration_test_sucessful' => sprintf( esc_html__( '%1$sStatus:%2$s Test Pass.', 'facebook-for-woocommerce' ), '<strong>', '</strong>' ),
142 /* translators: Placeholders %1$s - opening <strong> html tag, %2$s closing </strong> html tag */
143 'integration_test_in_progress' => sprintf( esc_html__( '%1$sStatus:%2$s Integration test in progress...', 'facebook-for-woocommerce' ), '<strong>', '</strong>' ),
144 /* translators: Placeholders %1$s - opening <strong> html tag, %2$s closing </strong> html tag */
145 'integration_test_failed' => sprintf( esc_html__( '%1$sStatus:%2$s Test Fail.', 'facebook-for-woocommerce' ), '<strong>', '</strong>' ),
146 'general_error' => esc_html__( 'There was an error trying to sync the products to Facebook.', 'facebook-for-woocommerce' ),
147 'feed_upload_error' => esc_html__( 'Something went wrong while uploading the product information, please try again.', 'facebook-for-woocommerce' ),
148 ],
149 ] );
150 }
151 }
152 }
153
154
155 /**
156 * Adds Facebook-related columns in the products edit screen.
157 *
158 * @internal
159 *
160 * @since 1.10.0
161 *
162 * @param array $columns array of keys and labels
163 * @return array
164 */
165 public function add_product_list_table_columns( $columns ) {
166
167 $columns['facebook_sync_enabled'] = __( 'FB Sync Enabled', 'facebook-for-woocommerce' );
168 // $columns['facebook_catalog_visibility'] = __( 'FB Catalog Visibility', 'facebook-for-woocommerce' );
169
170 return $columns;
171 }
172
173
174 /**
175 * Outputs sync information for products in the edit screen.
176 *
177 * @internal
178 *
179 * @since 1.10.0
180 *
181 * @param string $column the current column in the posts table
182 */
183 public function add_product_list_table_columns_content( $column ) {
184 global $post;
185
186 if ( 'facebook_sync_enabled' === $column ) :
187
188 $product = wc_get_product( $post );
189
190 if ( $product && Products::product_should_be_synced( $product ) ) :
191 esc_html_e( 'Enabled', 'facebook-for-woocommerce' );
192 else :
193 esc_html_e( 'Disabled', 'facebook-for-woocommerce' );
194 endif;
195
196 elseif ( 'facebook_catalog_visibility' === $column ) :
197
198 $integration = facebook_for_woocommerce()->get_integration();
199 $product = wc_get_product( $post );
200 $fb_product = new \WC_Facebook_Product( $post );
201 $fb_product_group_id = $integration && $product && $integration->get_product_fbid( \WC_Facebookcommerce_Integration::FB_PRODUCT_GROUP_ID, $post->ID, $fb_product );
202
203 if ( ! $fb_product_group_id ) :
204
205 ?>
206 <span
207 class="facebook-for-woocommerce-product-visibility-toggle"
208 style="cursor:default;"
209 title="<?php
210 /* translators: Points to a product that was never synced with Facebook */
211 esc_attr_e( 'Never synced with Facebook.', 'facebook-for-woocommerce' ); ?>"
212 >&ndash;</span>
213 <?php
214
215 else :
216
217 $is_sync_enabled = Products::product_should_be_synced( $product );
218 $is_visible = Products::is_product_visible( $product );
219 $is_hidden = ! $is_visible;
220
221 if ( $is_sync_enabled ) {
222 /* translators: Action to hide a product (currently synced with Facebook) from the Facebook catalog */
223 $visible_tooltip_text = __( 'Hide from Facebook catalog. Currently synced with Facebook.', 'facebook-for-woocommerce' );
224 /* translators: Action to publish a product (currently synced with Facebook) in the Facebook catalog */
225 $hidden_tooltip_text = __( 'Publish in Facebook catalog. Currently synced with Facebook.', 'facebook-for-woocommerce' );
226 } else {
227 /* translators: Action to hide a product (currently not synced with Facebook) from the Facebook catalog */
228 $visible_tooltip_text = __( 'Hide from Facebook catalog. Not synced with Facebook.', 'facebook-for-woocommerce' );
229 /* translators: Action to publish a product (currently not synced with Facebook) in the Facebook catalog */
230 $hidden_tooltip_text = __( 'Publish in Facebook catalog. Not synced with Facebook.', 'facebook-for-woocommerce' );
231 }
232
233 ?>
234 <button
235 id="facebook-for-woocommerce-product-visibility-show-<?php echo esc_attr( $post->ID ); ?>"
236 class="button button-primary button-large facebook-for-woocommerce-product-visibility-toggle facebook-for-woocommerce-product-visibility-show"
237 style="<?php echo $is_hidden ? 'display:block;' : 'display:none;'; ?>"
238 data-action="show"
239 data-product-id="<?php echo esc_attr( $post->ID ); ?>"
240 title="<?php echo esc_attr( $hidden_tooltip_text ); ?>"
241 ><?php esc_html_e( 'Show', 'facebook-for-woocommerce' ); ?></button>
242 <button
243 id="facebook-for-woocommerce-product-visibility-hide-<?php echo esc_attr( $post->ID ); ?>"
244 class="button button-large facebook-for-woocommerce-product-visibility-toggle facebook-for-woocommerce-product-visibility-hide"
245 style="<?php echo $is_visible ? 'display:block;' : 'display:none;'; ?>"
246 data-action="hide"
247 data-product-id="<?php echo esc_attr( $post->ID ); ?>"
248 title="<?php echo esc_attr( $visible_tooltip_text ); ?>"
249 ><?php esc_html_e( 'Hide', 'facebook-for-woocommerce' ); ?></button>
250 <?php
251
252 endif;
253
254 endif;
255 }
256
257
258 /**
259 * Adds a dropdown input to let shop managers filter products by sync setting.
260 *
261 * @internal
262 *
263 * @since 1.10.0
264 */
265 public function add_products_by_sync_enabled_input_filter() {
266 global $typenow;
267
268 if ( 'product' !== $typenow ) {
269 return;
270 }
271
272 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
273 $choice = isset( $_GET['fb_sync_enabled'] ) ? (string) sanitize_text_field( wp_unslash( $_GET['fb_sync_enabled'] ) ) : '';
274
275 ?>
276 <select name="fb_sync_enabled">
277 <option value="" <?php selected( $choice, '' ); ?>><?php esc_html_e( 'Filter by Facebook sync setting', 'facebook-for-woocommerce' ); ?></option>
278 <option value="yes" <?php selected( $choice, 'yes' ); ?>><?php esc_html_e( 'Facebook sync enabled', 'facebook-for-woocommerce' ); ?></option>
279 <option value="no" <?php selected( $choice, 'no' ); ?>><?php esc_html_e( 'Facebook sync disabled', 'facebook-for-woocommerce' ); ?></option>
280 </select>
281 <?php
282 }
283
284
285 /**
286 * Filters products by Facebook sync setting.
287 *
288 * @internal
289 *
290 * @since 1.10.0
291 *
292 * @param array $query_vars product query vars for the edit screen
293 * @return array
294 */
295 public function filter_products_by_sync_enabled( $query_vars ) {
296
297 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
298 if ( isset( $_REQUEST['fb_sync_enabled'] ) && in_array( $_REQUEST['fb_sync_enabled'], [ 'yes', 'no' ], true ) ) {
299
300 // by default use an "AND" clause if multiple conditions exist for a meta query
301 if ( ! empty( $query_vars['meta_query'] ) ) {
302 $query_vars['meta_query']['relation'] = 'AND';
303 } else {
304 $query_vars['meta_query'] = [];
305 }
306
307 // when checking for products with sync enabled we need to check both "yes" and meta not set, this requires adding an "OR" clause
308 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
309 if ( 'yes' === $_REQUEST['fb_sync_enabled'] ) {
310
311 $query_vars = $this->add_query_vars_to_find_products_with_sync_enabled( $query_vars );
312
313 // since we record enabled status on child variations, we may need to query variable products found for their children to exclude them from query results
314 $exclude_products = [];
315 $found_ids = get_posts( array_merge( $query_vars, [ 'fields' => 'ids' ] ) );
316 $found_products = empty( $found_ids ) ? [] : wc_get_products( [
317 'limit' => -1,
318 'type' => 'variable',
319 'include' => $found_ids,
320 ] );
321
322 /** @var \WC_Product[] $found_products */
323 foreach ( $found_products as $product ) {
324
325 if ( ! Products::is_sync_enabled_for_product( $product ) ) {
326 $exclude_products[] = $product->get_id();
327 }
328 }
329
330 if ( ! empty( $exclude_products ) ) {
331 if ( ! empty( $query_vars['post__not_in'] ) ) {
332 $query_vars['post__not_in'] = array_merge( $query_vars['post__not_in'], $exclude_products );
333 } else {
334 $query_vars['post__not_in'] = $exclude_products;
335 }
336 }
337
338 } else {
339
340 $integration = facebook_for_woocommerce()->get_integration();
341 $excluded_categories_ids = $integration ? $integration->get_excluded_product_category_ids() : [];
342 $excluded_tags_ids = $integration ? $integration->get_excluded_product_tag_ids() : [];
343
344 if ( $excluded_categories_ids || $excluded_tags_ids ) {
345
346 // find the IDs of products that have sync enabled
347 $products_query_vars = [
348 'post_type' => 'product',
349 'post_status' => ! empty( $query_vars['post_status'] ) ? $query_vars['post_status'] : 'any',
350 'no_found_rows' => true,
351 'update_post_meta_cache' => false,
352 'update_post_term_cache' => false,
353 'fields' => 'ids',
354 'nopaging' => true,
355 ];
356
357 $products_query_vars = $this->add_query_vars_to_find_products_with_sync_enabled( $products_query_vars );
358
359 // exclude products that have sync enabled from the current query
360 $query_vars['post__not_in'] = get_posts( $products_query_vars );
361
362 } else {
363
364 $query_vars['meta_query'][] = [
365 'key' => Products::SYNC_ENABLED_META_KEY,
366 'value' => 'no',
367 ];
368 }
369 }
370 }
371
372 return $query_vars;
373 }
374
375
376 /**
377 * Adds query vars to limit the results to products that have sync enabled.
378 *
379 * @since 1.10.0
380 *
381 * @param array $query_vars
382 * @return array
383 */
384 private function add_query_vars_to_find_products_with_sync_enabled( array $query_vars ) {
385
386 $query_vars['meta_query']['relation'] = 'OR';
387 $query_vars['meta_query'][] = [
388 'key' => Products::SYNC_ENABLED_META_KEY,
389 'value' => 'yes',
390 ];
391 $query_vars['meta_query'][] = [
392 'key' => Products::SYNC_ENABLED_META_KEY,
393 'compare' => 'NOT EXISTS',
394 ];
395
396 // check whether the product belongs to an excluded product category or tag
397 $query_vars = $this->maybe_add_tax_query_for_excluded_taxonomies( $query_vars );
398
399 return $query_vars;
400 }
401
402
403 /**
404 * Adds a tax query to filter out products in excluded product categories and product tags.
405 *
406 * @since 1.10.0
407 *
408 * @param array $query_vars product query vars for the edit screen
409 * @return array
410 */
411 private function maybe_add_tax_query_for_excluded_taxonomies( $query_vars ) {
412
413 $integration = facebook_for_woocommerce()->get_integration();
414
415 if ( $integration ) {
416
417 $tax_query = [];
418 $excluded_categories_ids = $integration->get_excluded_product_category_ids();
419
420 if ( $excluded_categories_ids ) {
421 $tax_query[] = [
422 'taxonomy' => 'product_cat',
423 'terms' => $excluded_categories_ids,
424 'field' => 'term_id',
425 'operator' => 'NOT IN',
426 ];
427 }
428
429 $excluded_tags_ids = $integration->get_excluded_product_tag_ids();
430
431 if ( $excluded_tags_ids ) {
432 $tax_query[] = [
433 'taxonomy' => 'product_tag',
434 'terms' => $excluded_tags_ids,
435 'field' => 'term_id',
436 'operator' => 'NOT IN',
437 ];
438 }
439
440 if ( $tax_query && empty( $query_vars['tax_query'] ) ) {
441 $query_vars['tax_query'] = $tax_query;
442 } elseif ( $tax_query && is_array( $query_vars ) ) {
443 $query_vars['tax_query'][] = $tax_query;
444 }
445 }
446
447 return $query_vars;
448 }
449
450
451 /**
452 * Adds bulk actions in the products edit screen.
453 *
454 * @internal
455 *
456 * @since 1.10.0
457 *
458 * @param array $bulk_actions array of bulk action keys and labels
459 * @return array
460 */
461 public function add_products_sync_bulk_actions( $bulk_actions ) {
462
463 $bulk_actions['facebook_include'] = __( 'Include in Facebook sync', 'facebook-for-woocommerce' );
464 $bulk_actions['facebook_exclude'] = __( 'Exclude from Facebook sync', 'facebook-for-woocommerce' );
465
466 return $bulk_actions;
467 }
468
469
470 /**
471 * Handles a Facebook product sync bulk action.
472 *
473 * @internal
474 *
475 * @since 1.10.0
476 *
477 * @param string $redirect admin URL used by WordPress to redirect after performing the bulk action
478 * @return string
479 */
480 public function handle_products_sync_bulk_actions( $redirect ) {
481
482 // primary dropdown at the top of the list table
483 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
484 $action = isset( $_REQUEST['action'] ) && -1 !== (int) $_REQUEST['action'] ? sanitize_text_field( wp_unslash( $_REQUEST['action'] ) ) : null;
485
486 // secondary dropdown at the bottom of the list table
487 if ( ! $action ) {
488 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
489 $action = isset( $_REQUEST['action2'] ) && -1 !== (int) $_REQUEST['action2'] ? sanitize_text_field( wp_unslash( $_REQUEST['action2'] ) ) : null;
490 }
491
492 if ( $action && in_array( $action, [ 'facebook_include', 'facebook_exclude' ], true ) ) {
493
494 $products = [];
495
496 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
497 $product_ids = isset( $_REQUEST['post'] ) && is_array( $_REQUEST['post'] ) ? array_map( 'absint', $_REQUEST['post'] ) : [];
498
499 if ( ! empty( $product_ids ) ) {
500
501 $is_enabling_sync_virtual_products = false;
502 $is_enabling_sync_virtual_variations = false;
503
504 foreach ( $product_ids as $product_id ) {
505
506 if ( $product = wc_get_product( $product_id ) ) {
507
508 if ( 'facebook_include' === $action ) {
509
510 if ( $product->is_virtual() ) {
511
512 $is_enabling_sync_virtual_products = true;
513
514 } else {
515
516 // products with virtual variations are also added to the list,
517 // because they may have non-virtual variations as well
518 $products[] = $product;
519
520 if ( $product->is_type( 'variable' ) ) {
521
522 // check if the product has virtual variations, to display notice
523 foreach ( $product->get_children() as $variation_id ) {
524
525 $variation = wc_get_product( $variation_id );
526
527 if ( $variation && $variation->is_virtual() ) {
528
529 $is_enabling_sync_virtual_variations = true;
530 break;
531 }
532 }
533 }
534 }
535 } else {
536
537 // add the product to the list of products to disable sync from
538 $products[] = $product;
539 }
540 }
541 }
542
543 // display notice if enabling sync for virtual products or variations
544 if ( $is_enabling_sync_virtual_products || $is_enabling_sync_virtual_variations ) {
545
546 $redirect = add_query_arg( [ 'enabling_virtual_products_sync' => 1 ], $redirect );
547 }
548
549 if ( 'facebook_include' === $action ) {
550
551 Products::enable_sync_for_products( $products );
552
553 // re-sync each product
554 foreach ( $products as $product ) {
555 facebook_for_woocommerce()->get_integration()->on_product_publish( $product->get_id() );
556 }
557
558 } elseif ( 'facebook_exclude' === $action ) {
559
560 Products::disable_sync_for_products( $products );
561 }
562 }
563 }
564
565 return $redirect;
566 }
567
568
569 /**
570 * Prints a notice on products page in case the current cart URL is not the original sync URL.
571 *
572 * @internal
573 *
574 * TODO: update this method to use the notice handler once we framework the plugin {CW 2020-01-09}
575 *
576 * @since 1.10.0
577 */
578 public function validate_cart_url() {
579 global $current_screen;
580
581 if ( isset( $current_screen->id ) && in_array( $current_screen->id, [ 'edit-product', 'product' ], true ) ) :
582
583 $cart_url = get_option( \WC_Facebookcommerce_Integration::FB_CART_URL, '' );
584
585 if ( ! empty( $cart_url ) && $cart_url !== wc_get_cart_url() ) :
586
587 ?>
588 <div class="notice notice-warning">
589 <?php printf(
590 /* translators: Placeholders: %1$s - Facebook for Woocommerce, %2$s - opening HTML <a> link tag, %3$s - closing HTML </a> link tag */
591 '<p>' . esc_html__( '%1$s: One or more of your products is using a checkout URL that may be different than your shop checkout URL. %2$sRe-sync your products to update checkout URLs on Facebook%3$s.', 'facebook-for-woocommerce' ) . '</p>',
592 '<strong>' . esc_html__( 'Facebook for WooCommerce', 'facebook-for-woocommerce' ) . '</strong>',
593 '<a href="' . esc_url( WOOCOMMERCE_FACEBOOK_PLUGIN_SETTINGS_URL ) . '">',
594 '</a>'
595 ); ?>
596 </div>
597 <?php
598
599 endif;
600
601 endif;
602 }
603
604
605 /**
606 * Prints a notice on products page to inform users about changes in product sync.
607 *
608 * @internal
609 *
610 * @since 1.11.0
611 */
612 public function add_product_sync_delay_notice() {
613 global $current_screen;
614
615 $transient_name = 'wc_' . facebook_for_woocommerce()->get_id() . '_show_product_sync_delay_notice_' . get_current_user_id();
616
617 if ( isset( $current_screen->id ) && in_array( $current_screen->id, [ 'edit-product', 'product' ], true ) && get_transient( $transient_name ) ) {
618
619 if ( isset( $_GET['message'] ) || isset( $_GET['trashed'] ) || isset( $_GET['deleted'] ) ) {
620
621 facebook_for_woocommerce()->get_admin_notice_handler()->add_admin_notice(
622 sprintf(
623 /* translators: Placeholders: %1$s - opening HTML <strong> tag, %2$s - closing HTML </strong> tag, %3$s - opening HTML <a> tag, %4$s - closing HTML </a> tag */
624 esc_html__( '%1$sHeads up!%2$s Product sync is temporarily changed as we migrate to a more secure experience. An automated sync from Facebook will run every hour to update the catalog with any changes you\'ve made. %3$sLearn more%4$s', 'facebook-for-woocommerce' ),
625 '<strong>',
626 '</strong>',
627 '<a href="https://docs.woocommerce.com/document/facebook-for-woocommerce/#faq-security" target="_blank">',
628 '</a>'
629 )
630 . '</p><p>' // close notice paragraph and open a new one for the button
631 . '<button class="button notice-dismiss-permanently" type="button">' . esc_html__( "Don't show this notice again", 'facebook-for-woocommerce' ) . '</button>',
632 'wc-' . facebook_for_woocommerce()->get_id_dasherized() . '-product-sync-delay',
633 [ 'notice_class' => 'notice-info' ]
634 );
635 }
636
637 delete_transient( $transient_name );
638 }
639 }
640
641
642 /**
643 * Handles dismissed notices.
644 *
645 * @internal
646 *
647 * @since 1.11.0
648 *
649 * @param string $message_id the dismissed notice ID
650 * @param int $user_id the ID of the user the noticed was dismissed for
651 */
652 public function handle_dismiss_notice( $message_id, $user_id = null ) {
653
654 // undismiss product sync delay notice unless 'permanently' is included in the request
655 if ( ! SV_WC_Helper::get_requested_value( 'permanently' ) && 'wc-' . facebook_for_woocommerce()->get_id_dasherized() . '-product-sync-delay' === $message_id ) {
656
657 facebook_for_woocommerce()->get_admin_notice_handler()->undismiss_notice( $message_id, $user_id );
658 }
659 }
660
661
662 /**
663 * Prints a notice on products page to inform users that catalog visibility settings were removed.
664 *
665 * @internal
666 *
667 * @since 1.11.0
668 */
669 public function add_catalog_visibility_settings_removed_notice() {
670 global $current_screen;
671
672 if ( isset( $current_screen->id ) && in_array( $current_screen->id, [ 'edit-product', 'product' ], true ) ) {
673
674 facebook_for_woocommerce()->get_admin_notice_handler()->add_admin_notice(
675 sprintf(
676 /* translators: Placeholders: %1$s - opening HTML <strong> tag, %2$s - closing HTML </strong> tag, %3$s - opening HTML <a> tag, %4$s - closing HTML </a> tag */
677 esc_html__( '%1$sHeads up!%2$s Catalog visibility settings have been temporarily removed as we migrate to a more secure experience. To remove products from your Facebook catalog, please disable syncing to Facebook for the product. %3$sLearn more%4$s', 'facebook-for-woocommerce' ),
678 '<strong>',
679 '</strong>',
680 '<a href="https://docs.woocommerce.com/document/facebook-for-woocommerce/#section-10" target="_blank">', // TODO: add link to FAQ entry {WV 2020-03-30}
681 '</a>'
682 ),
683 'wc-' . facebook_for_woocommerce()->get_id_dasherized() . '-catalog-visibility-settings-removed',
684 [ 'notice_class' => 'notice-info' ]
685 );
686 }
687 }
688
689
690 /**
691 * Prints a notice on products page to inform users that the virtual products selected for the Include bulk action will NOT have sync enabled.
692 *
693 * @internal
694 *
695 * @since 1.11.3-dev.2
696 */
697 public function add_enabling_virtual_products_sync_notice() {
698 global $current_screen;
699
700 if ( isset( $_GET['enabling_virtual_products_sync'] ) && isset( $current_screen->id ) && 'edit-product' === $current_screen->id ) {
701
702 facebook_for_woocommerce()->get_admin_notice_handler()->add_admin_notice(
703 sprintf(
704 /* translators: Placeholders: %1$s - opening HTML <strong> tag, %2$s - closing HTML </strong> tag, %3$s - opening HTML <a> tag, %4$s - closing HTML </a> tag */
705 esc_html__( '%1$sHeads up!%2$s Facebook does not support selling virtual products, so we can\'t include virtual products in your catalog sync. %3$sClick here to read more about Facebook\'s policy%4$s.', 'facebook-for-woocommerce' ),
706 '<strong>',
707 '</strong>',
708 '<a href="https://www.facebook.com/help/130910837313345" target="_blank">',
709 '</a>'
710 ),
711 'wc-' . facebook_for_woocommerce()->get_id_dasherized() . '-enabling-virtual-products-sync',
712 [ 'notice_class' => 'notice-info' ]
713 );
714 }
715 }
716
717
718 /**
719 * Prints a notice to inform sync has been automatically disabled for virtual products.
720 *
721 * @internal
722 *
723 * @since 1.11.3-dev.2
724 */
725 public function add_disabled_virtual_products_sync_notice() {
726
727 if ( 'yes' === get_option( 'wc_facebook_sync_virtual_products_disabled', 'no' ) &&
728 'yes' !== get_option( 'wc_facebook_sync_virtual_products_disabled_skipped', 'no' ) ) {
729
730 facebook_for_woocommerce()->get_admin_notice_handler()->add_admin_notice(
731 sprintf(
732 /* translators: Placeholders: %1$s - opening HTML <strong> tag, %2$s - closing HTML </strong> tag, %3$s - opening HTML <a> tag, %4$s - closing HTML </a> tag */
733 esc_html__( '%1$sHeads up!%2$s Facebook does not support selling virtual products, so we have removed any previously synced virtual products from the catalog sync going forward. %3$sClick here to read more about Facebook\'s policy%4$s.', 'facebook-for-woocommerce' ),
734 '<strong>',
735 '</strong>',
736 '<a href="https://www.facebook.com/help/130910837313345" target="_blank">',
737 '</a>'
738 ),
739 'wc-' . facebook_for_woocommerce()->get_id_dasherized() . '-disabled-virtual-products-sync',
740 [ 'notice_class' => 'notice-info' ]
741 );
742 }
743 }
744
745
746 /**
747 * Adds a new tab to the Product edit page.
748 *
749 * @internal
750 *
751 * @since 1.10.0
752 *
753 * @param array $tabs product tabs
754 * @return array
755 */
756 public function add_product_settings_tab( $tabs ) {
757
758 $tabs['fb_commerce_tab'] = [
759 'label' => __( 'Facebook', 'facebook-for-woocommerce' ),
760 'target' => 'facebook_options',
761 'class' => [ 'show_if_simple', 'hide_if_virtual' ],
762 ];
763
764 return $tabs;
765 }
766
767
768 /**
769 * Adds content to the new Facebook tab on the Product edit page.
770 *
771 * @internal
772 *
773 * @since 1.10.0
774 */
775 public function add_product_settings_tab_content() {
776 global $post;
777
778 // all products have sync enabled unless explicitly disabled
779 $sync_enabled = 'no' !== get_post_meta( $post->ID, Products::SYNC_ENABLED_META_KEY, true );
780 $description = get_post_meta( $post->ID, \WC_Facebookcommerce_Integration::FB_PRODUCT_DESCRIPTION, true );
781 $price = get_post_meta( $post->ID, \WC_Facebook_Product::FB_PRODUCT_PRICE, true );
782 $image_source = get_post_meta( $post->ID, Products::PRODUCT_IMAGE_SOURCE_META_KEY, true );
783 $image = get_post_meta( $post->ID, \WC_Facebook_Product::FB_PRODUCT_IMAGE, true );
784
785 // 'id' attribute needs to match the 'target' parameter set above
786 ?>
787 <div id='facebook_options' class='panel woocommerce_options_panel'>
788 <div class='options_group'>
789 <?php
790
791 woocommerce_wp_checkbox( [
792 'id' => 'fb_sync_enabled',
793 'label' => __( 'Include in Facebook sync', 'facebook-for-woocommerce' ),
794 'value' => wc_bool_to_string( (bool) $sync_enabled ),
795 ] );
796
797 woocommerce_wp_textarea_input( [
798 'id' => \WC_Facebookcommerce_Integration::FB_PRODUCT_DESCRIPTION,
799 'label' => __( 'Facebook Description', 'facebook-for-woocommerce' ),
800 'desc_tip' => true,
801 'description' => __( 'Custom (plain-text only) description for product on Facebook. If blank, product description will be used. If product description is blank, shortname will be used.', 'facebook-for-woocommerce' ),
802 'cols' => 40,
803 'rows' => 20,
804 'value' => $description,
805 'class' => 'enable-if-sync-enabled',
806 ] );
807
808 woocommerce_wp_radio( [
809 'id' => 'fb_product_image_source',
810 'label' => __( 'Facebook Product Image', 'facebook-for-woocommerce' ),
811 'desc_tip' => true,
812 'description' => __( 'Choose the product image that should be synced to the Facebook catalog for this product. If using a custom image, please enter an absolute URL (e.g. https://domain.com/image.jpg).', 'facebook-for-woocommerce' ),
813 'options' => [
814 Products::PRODUCT_IMAGE_SOURCE_PRODUCT => __( 'Use WooCommerce image', 'facebook-for-woocommerce' ),
815 Products::PRODUCT_IMAGE_SOURCE_CUSTOM => __( 'Use custom image', 'facebook-for-woocommerce' ),
816 ],
817 'value' => $image_source ?: Products::PRODUCT_IMAGE_SOURCE_PRODUCT,
818 'class' => 'short enable-if-sync-enabled js-fb-product-image-source',
819 'wrapper_class' => 'fb-product-image-source-field',
820 ] );
821
822 woocommerce_wp_text_input( [
823 'id' => \WC_Facebook_Product::FB_PRODUCT_IMAGE,
824 'label' => __( 'Custom Image URL', 'facebook-for-woocommerce' ),
825 'value' => $image,
826 'class' => sprintf( 'enable-if-sync-enabled product-image-source-field show-if-product-image-source-%s', Products::PRODUCT_IMAGE_SOURCE_CUSTOM ),
827 ] );
828
829 woocommerce_wp_text_input( [
830 'id' => \WC_Facebook_Product::FB_PRODUCT_PRICE,
831 'label' => sprintf(
832 /* translators: Placeholders %1$s - WC currency symbol */
833 __( 'Facebook Price (%1$s)', 'facebook-for-woocommerce' ),
834 get_woocommerce_currency_symbol()
835 ),
836 'desc_tip' => true,
837 'description' => __( 'Custom price for product on Facebook. Please enter in monetary decimal (.) format without thousand separators and currency symbols. If blank, product price will be used.', 'facebook-for-woocommerce' ),
838 'cols' => 40,
839 'rows' => 60,
840 'value' => $price,
841 'class' => 'enable-if-sync-enabled',
842 ] );
843
844 ?>
845 </div>
846 </div>
847 <?php
848 }
849
850
851 /**
852 * Outputs the Facebook settings fields for a single variation.
853 *
854 * @internal
855 *
856 * @since 1.10.0
857 *
858 * @param int $index the index of the current variation
859 * @param array $variation_data unused
860 * @param \WC_Post $post the post type for the current variation
861 */
862 public function add_product_variation_edit_fields( $index, $variation_data, $post ) {
863
864 $variation = wc_get_product( $post );
865
866 if ( ! $variation instanceof \WC_Product_Variation ) {
867 return;
868 }
869
870 $parent = wc_get_product( $variation->get_parent_id() );
871
872 if ( ! $parent instanceof \WC_Product ) {
873 return;
874 }
875
876 $sync_enabled = $this->get_product_variation_meta( $variation, Products::SYNC_ENABLED_META_KEY, $parent );
877 $description = $this->get_product_variation_meta( $variation, \WC_Facebookcommerce_Integration::FB_PRODUCT_DESCRIPTION, $parent );
878 $price = $this->get_product_variation_meta( $variation, \WC_Facebook_Product::FB_PRODUCT_PRICE, $parent );
879 $image_url = $this->get_product_variation_meta( $variation, \WC_Facebook_Product::FB_PRODUCT_IMAGE, $parent );
880 $image_source = $variation->get_meta( Products::PRODUCT_IMAGE_SOURCE_META_KEY );
881
882 woocommerce_wp_checkbox( [
883 'id' => "variable_fb_sync_enabled$index",
884 'name' => "variable_fb_sync_enabled[$index]",
885 'label' => __( 'Include in Facebook sync', 'facebook-for-woocommerce' ),
886 'value' => wc_bool_to_string( 'no' !== $sync_enabled ),
887 'class' => 'checkbox js-variable-fb-sync-toggle',
888 'wrapper_class' => 'fb-sync-enabled-field hide_if_variation_virtual',
889 ] );
890
891 woocommerce_wp_textarea_input( [
892 'id' => sprintf( 'variable_%s%s', \WC_Facebookcommerce_Integration::FB_PRODUCT_DESCRIPTION, $index ),
893 'name' => sprintf( "variable_%s[$index]", \WC_Facebookcommerce_Integration::FB_PRODUCT_DESCRIPTION ),
894 'label' => __( 'Facebook Description', 'facebook-for-woocommerce' ),
895 'desc_tip' => true,
896 'description' => __( 'Custom (plain-text only) description for product on Facebook. If blank, product description will be used. If product description is blank, shortname will be used.', 'facebook-for-woocommerce' ),
897 'cols' => 40,
898 'rows' => 5,
899 'value' => $description,
900 'class' => 'enable-if-sync-enabled',
901 'wrapper_class' => 'form-row form-row-full hide_if_variation_virtual',
902 ] );
903
904 woocommerce_wp_radio( [
905 'id' => "variable_fb_product_image_source$index",
906 'name' => "variable_fb_product_image_source[$index]",
907 'label' => __( 'Facebook Product Image', 'facebook-for-woocommerce' ),
908 'desc_tip' => true,
909 'description' => __( 'Choose the product image that should be synced to the Facebook catalog for this product. If using a custom image, please enter an absolute URL (e.g. https://domain.com/image.jpg).', 'facebook-for-woocommerce' ),
910 'options' => [
911 Products::PRODUCT_IMAGE_SOURCE_PRODUCT => __( 'Use variation image', 'facebook-for-woocommerce' ),
912 Products::PRODUCT_IMAGE_SOURCE_PARENT_PRODUCT => __( 'Use parent image', 'facebook-for-woocommerce' ),
913 Products::PRODUCT_IMAGE_SOURCE_CUSTOM => __( 'Use custom image', 'facebook-for-woocommerce' ),
914 ],
915 'value' => $image_source ?: Products::PRODUCT_IMAGE_SOURCE_PRODUCT,
916 'class' => 'enable-if-sync-enabled js-fb-product-image-source',
917 'wrapper_class' => 'fb-product-image-source-field hide_if_variation_virtual',
918 ] );
919
920 woocommerce_wp_text_input( [
921 'id' => sprintf( 'variable_%s%s', \WC_Facebook_Product::FB_PRODUCT_IMAGE, $index ),
922 'name' => sprintf( "variable_%s[$index]", \WC_Facebook_Product::FB_PRODUCT_IMAGE ),
923 'label' => __( 'Custom Image URL', 'facebook-for-woocommerce' ),
924 'value' => $image_url,
925 'class' => sprintf( 'enable-if-sync-enabled product-image-source-field show-if-product-image-source-%s', Products::PRODUCT_IMAGE_SOURCE_CUSTOM ),
926 'wrapper_class' => 'form-row form-row-full hide_if_variation_virtual',
927 ] );
928
929 woocommerce_wp_text_input( [
930 'id' => sprintf( 'variable_%s%s', \WC_Facebook_Product::FB_PRODUCT_PRICE, $index ),
931 'name' => sprintf( "variable_%s[$index]", \WC_Facebook_Product::FB_PRODUCT_PRICE ),
932 'label' => sprintf(
933 /* translators: Placeholders %1$s - WC currency symbol */
934 __( 'Facebook Price (%1$s)', 'facebook-for-woocommerce' ),
935 get_woocommerce_currency_symbol()
936 ),
937 'desc_tip' => true,
938 'description' => __( 'Custom price for product on Facebook. Please enter in monetary decimal (.) format without thousand separators and currency symbols. If blank, product price will be used.', 'facebook-for-woocommerce' ),
939 'value' => wc_format_decimal( $price ),
940 'class' => 'enable-if-sync-enabled',
941 'wrapper_class' => 'form-row form-full hide_if_variation_virtual',
942 ] );
943 }
944
945
946 /**
947 * Gets the stored value for the given meta of a product variation.
948 *
949 * If no value is found, we try to use the value stored in the parent product.
950 *
951 * @since 1.10.0
952 *
953 * @param \WC_Product_Variation $variation the product variation
954 * @param string $key the name of the meta to retrieve
955 * @param \WC_Product $parent the parent product
956 * @return mixed
957 */
958 private function get_product_variation_meta( $variation, $key, $parent ) {
959
960 $value = $variation->get_meta( $key );
961
962 if ( '' === $value && $parent instanceof \WC_Product ) {
963 $value = $parent->get_meta( $key );
964 }
965
966 return $value;
967 }
968
969
970 /**
971 * Saves the submitted Facebook settings for each variation.
972 *
973 * @internal
974 *
975 * @since 1.10.0
976 *
977 * @param int $variation_id the ID of the product variation being edited
978 * @param int $index the index of the current variation
979 */
980 public function save_product_variation_edit_fields( $variation_id, $index ) {
981
982 $variation = wc_get_product( $variation_id );
983
984 if ( ! $variation instanceof \WC_Product_Variation ) {
985 return;
986 }
987
988 // phpcs:disable WordPress.Security.NonceVerification.Missing
989 if ( ! $variation->is_virtual() && isset( $_POST['variable_fb_sync_enabled'][ $index ] ) && 'yes' === $_POST['variable_fb_sync_enabled'][ $index ] ) {
990
991 Products::enable_sync_for_products( [ $variation ] );
992
993 $posted_param = 'variable_' . \WC_Facebookcommerce_Integration::FB_PRODUCT_DESCRIPTION;
994 $description = isset( $_POST[ $posted_param ][ $index ] ) ? sanitize_text_field( wp_unslash( $_POST[ $posted_param ][ $index ] ) ) : null;
995
996 $posted_param = 'variable_fb_product_image_source';
997 $image_source = isset( $_POST[ $posted_param ][ $index ] ) ? sanitize_key( wp_unslash( $_POST[ $posted_param ][ $index ] ) ) : '';
998
999 $posted_param = 'variable_' . \WC_Facebook_Product::FB_PRODUCT_IMAGE;
1000 $image_url = isset( $_POST[ $posted_param ][ $index ] ) ? esc_url_raw( wp_unslash( $_POST[ $posted_param ][ $index ] ) ) : null;
1001
1002 $posted_param = 'variable_' . \WC_Facebook_Product::FB_PRODUCT_PRICE;
1003 $price = isset( $_POST[ $posted_param ][ $index ] ) ? wc_format_decimal( $_POST[ $posted_param ][ $index ] ) : '';
1004
1005 $variation->update_meta_data( \WC_Facebookcommerce_Integration::FB_PRODUCT_DESCRIPTION, $description );
1006 $variation->update_meta_data( Products::PRODUCT_IMAGE_SOURCE_META_KEY, $image_source );
1007 $variation->update_meta_data( \WC_Facebook_Product::FB_PRODUCT_IMAGE, $image_url );
1008 $variation->update_meta_data( \WC_Facebook_Product::FB_PRODUCT_PRICE, $price );
1009 $variation->save_meta_data();
1010
1011 } else {
1012
1013 Products::disable_sync_for_products( [ $variation ] );
1014
1015 }
1016 // phpcs:enable WordPress.Security.NonceVerification.Missing
1017 }
1018
1019
1020 /**
1021 * Outputs a modal template in admin product pages.
1022 *
1023 * @internal
1024 *
1025 * @since 1.10.0
1026 */
1027 public function render_modal_template() {
1028 global $current_screen;
1029
1030 // bail if not on the products, product edit, or settings screen
1031 if ( ! $current_screen || ! in_array( $current_screen->id, [ 'edit-product', 'product', 'woocommerce_page_wc-settings' ], true ) ) {
1032 return;
1033 }
1034
1035 ?>
1036 <script type="text/template" id="tmpl-facebook-for-woocommerce-modal">
1037 <div class="wc-backbone-modal facebook-for-woocommerce-modal">
1038 <div class="wc-backbone-modal-content">
1039 <section class="wc-backbone-modal-main" role="main">
1040 <header class="wc-backbone-modal-header">
1041 <h1><?php esc_html_e( 'Facebook for WooCommerce', 'facebook-for-woocommerce' ); ?></h1>
1042 <button class="modal-close modal-close-link dashicons dashicons-no-alt">
1043 <span class="screen-reader-text"><?php esc_html_e( 'Close modal panel', 'facebook-for-woocommerce' ); ?></span>
1044 </button>
1045 </header>
1046 <article>{{{data.message}}}</article>
1047 <footer>
1048 <div class="inner">{{{data.buttons}}}</div>
1049 </footer>
1050 </section>
1051 </div>
1052 </div>
1053 <div class="wc-backbone-modal-backdrop modal-close"></div>
1054 </script>
1055 <?php
1056 }
1057
1058
1059 /**
1060 * Maybe triggers the modal to open on the product edit screen on page load.
1061 *
1062 * If the product is set to be synced in Facebook, but belongs to a term that is set to be excluded, the modal prompts the merchant for action.
1063 *
1064 * @internal
1065 *
1066 * @since 1.10.0
1067 */
1068 public function validate_product_excluded_terms() {
1069 global $current_screen, $post;
1070
1071 if ( $post && $current_screen && $current_screen->id === 'product' ) :
1072
1073 $product = wc_get_product( $post );
1074
1075 if ( $product instanceof \WC_Product
1076 && Products::is_sync_enabled_for_product( $product )
1077 && Products::is_sync_excluded_for_product_terms( $product )
1078 ) :
1079
1080 ?>
1081 <script type="text/javascript">
1082 jQuery( document ).ready( function( $ ) {
1083
1084 var productID = parseInt( $( 'input#post_ID' ).val(), 10 ),
1085 productTag = $( 'textarea[name=\"tax_input[product_tag]\"]' ).val().split( ',' ),
1086 productCat = [];
1087
1088 $( '#taxonomy-product_cat input[name=\"tax_input[product_cat][]\"]:checked' ).each( function() {
1089 productCat.push( parseInt( $( this ).val(), 10 ) );
1090 } );
1091
1092 $.post( facebook_for_woocommerce_products_admin.ajax_url, {
1093 action: 'facebook_for_woocommerce_set_product_sync_prompt',
1094 security: facebook_for_woocommerce_products_admin.set_product_sync_prompt_nonce,
1095 sync_enabled: 'enabled',
1096 product: productID,
1097 categories: productCat,
1098 tags: productTag
1099 }, function( response ) {
1100
1101 if ( response && ! response.success ) {
1102
1103 $( '#wc-backbone-modal-dialog .modal-close' ).trigger( 'click' );
1104
1105 new $.WCBackboneModal.View( {
1106 target: 'facebook-for-woocommerce-modal',
1107 string: response.data
1108 } );
1109 }
1110 } );
1111 } );
1112 </script>
1113 <?php
1114
1115 endif;
1116
1117 endif;
1118 }
1119
1120
1121 }
1122