diff --git a/facebook-commerce.php b/facebook-commerce.php index d7566a03b..75f23a91d 100644 --- a/facebook-commerce.php +++ b/facebook-commerce.php @@ -853,9 +853,6 @@ public function on_product_save( int $wp_id ) { $this->save_product_settings( $product ); } else { // if previously enabled, add a notice on the next page load - if ( Products::is_sync_enabled_for_product( $product ) ) { - Admin::add_product_disabled_sync_notice(); - } Products::disable_sync_for_products( [ $product ] ); if ( in_array( $wp_id, $products_to_delete_from_facebook, true ) ) { $this->delete_fb_product( $product ); diff --git a/includes/Admin.php b/includes/Admin.php index 11a0049bf..e9161a7d9 100644 --- a/includes/Admin.php +++ b/includes/Admin.php @@ -32,6 +32,12 @@ class Admin { /** @var string the "sync disabled" sync mode slug */ const SYNC_MODE_SYNC_DISABLED = 'sync_disabled'; + /** @var string the "include" sync mode for bulk edit */ + const BULK_EDIT_SYNC = 'bulk_edit_sync'; + + /** @var string the "exclude" sync mode for bulk edit */ + const BULK_EDIT_DELETE = 'bulk_edit_delete'; + /** @var Product_Categories the product category admin handler */ protected $product_categories; @@ -93,8 +99,8 @@ public function __construct() { add_filter( 'request', array( $this, 'filter_products_by_sync_enabled' ) ); // add bulk actions to manage products sync - add_filter( 'bulk_actions-edit-product', array( $this, 'add_products_sync_bulk_actions' ), 40 ); - add_action( 'handle_bulk_actions-edit-product', array( $this, 'handle_products_sync_bulk_actions' ) ); + add_action( 'woocommerce_product_bulk_edit_end', array( $this, 'add_facebook_sync_bulk_edit_dropdown_at_bottom' ) ); + add_action( 'woocommerce_product_bulk_edit_save', array( $this, 'handle_products_sync_bulk_actions' ), 10, 1 ); // add Product data tab add_filter( 'woocommerce_product_data_tabs', array( $this, 'add_product_settings_tab' ) ); @@ -440,7 +446,7 @@ public function get_product_categories_handler() { * @return array */ public function add_product_list_table_columns( $columns ) { - $columns['facebook_sync'] = __( 'Facebook sync', 'facebook-for-woocommerce' ); + $columns['facebook_sync'] = __( 'Synced to Meta catalog', 'facebook-for-woocommerce' ); return $columns; } @@ -474,13 +480,9 @@ public function add_product_list_table_columns_content( $column ) { } if ( $should_sync ) { - if ( Products::is_product_visible( $product ) ) { - esc_html_e( 'Sync and show', 'facebook-for-woocommerce' ); - } else { - esc_html_e( 'Sync and hide', 'facebook-for-woocommerce' ); - } + esc_html_e( 'Synced', 'facebook-for-woocommerce' ); } else { - esc_html_e( 'Do not sync', 'facebook-for-woocommerce' ); + esc_html_e( 'Not synced', 'facebook-for-woocommerce' ); if ( ! empty( $no_sync_reason ) ) { echo wc_help_tip( $no_sync_reason ); } @@ -513,6 +515,36 @@ public function add_products_by_sync_enabled_input_filter() { + + is_virtual() && ! Products::is_sync_enabled_for_product( $product ) ) { - $enabling_sync_virtual_products[ $product->get_id() ] = $product; - } elseif ( $product->is_type( 'variable' ) ) { - // collect the virtual variations - foreach ( $product->get_children() as $variation_id ) { - $variation = wc_get_product( $variation_id ); - if ( $variation && $variation->is_virtual() && ! Products::is_sync_enabled_for_product( $variation ) ) { - $enabling_sync_virtual_products[ $product->get_id() ] = $product; - $enabling_sync_virtual_variations[ $variation->get_id() ] = $variation; - } - } - }//end if - }//end if + public function handle_products_sync_bulk_actions( $product_edit ) { + + $sync_mode = isset( $_GET['facebook_bulk_sync_options'] ) ? (string) sanitize_text_field( wp_unslash( $_GET['facebook_bulk_sync_options'] ) ) : null; + + if ( $sync_mode ) { + /** @var \WC_Product[] $enabling_sync_virtual_products virtual products that are being included */ + $enabling_sync_virtual_products = []; + /** @var \WC_Product_Variation[] $enabling_sync_virtual_variations virtual variations that are being included */ + $enabling_sync_virtual_variations = []; + /** @var \WC_Product $product to store the product meta data */ + $product = wc_get_product( $product_edit ); + + if ( $product && $this::BULK_EDIT_SYNC === $sync_mode ) { + if ( $product->is_virtual() && ! Products::is_sync_enabled_for_product( $product ) ) { + $enabling_sync_virtual_products[ $product->get_id() ] = $product; + } elseif ( $product->is_type( 'variable' ) ) { + // collect the virtual variations + foreach ( $product->get_children() as $variation_id ) { + $variation = wc_get_product( $variation_id ); + if ( $variation && $variation->is_virtual() && ! Products::is_sync_enabled_for_product( $variation ) ) { + $enabling_sync_virtual_variations[ $variation->get_id() ] = $variation; + } + }//end foreach + if ( ! empty( $enabling_sync_virtual_variations ) ) { + $enabling_sync_virtual_products[ $product->get_id() ] = $product; }//end if - }//end foreach + }//end if + }//end if - if ( ! empty( $enabling_sync_virtual_products ) || ! empty( $enabling_sync_virtual_variations ) ) { - // display notice if enabling sync for virtual products or variations - set_transient( 'wc_' . facebook_for_woocommerce()->get_id() . '_enabling_virtual_products_sync_show_notice_' . get_current_user_id(), true, 15 * MINUTE_IN_SECONDS ); - set_transient( 'wc_' . facebook_for_woocommerce()->get_id() . '_enabling_virtual_products_sync_affected_products_' . get_current_user_id(), array_keys( $enabling_sync_virtual_products ), 15 * MINUTE_IN_SECONDS ); + if ( ! empty( $enabling_sync_virtual_products ) || ! empty( $enabling_sync_virtual_variations ) ) { + // display notice if enabling sync for virtual products or variations + set_transient( 'wc_' . facebook_for_woocommerce()->get_id() . '_enabling_virtual_products_sync_show_notice_' . get_current_user_id(), true, 15 * MINUTE_IN_SECONDS ); + set_transient( 'wc_' . facebook_for_woocommerce()->get_id() . '_enabling_virtual_products_sync_affected_products_' . get_current_user_id(), array_keys( $enabling_sync_virtual_products ), 15 * MINUTE_IN_SECONDS ); - // set visibility for virtual products - foreach ( $enabling_sync_virtual_products as $product ) { + // set visibility for virtual products + foreach ( $enabling_sync_virtual_products as $product ) { - // do not set visibility for variable products - if ( ! $product->is_type( 'variable' ) ) { - Products::set_product_visibility( $product, false ); - } + // do not set visibility for variable products + if ( ! $product->is_type( 'variable' ) ) { + Products::set_product_visibility( $product, false ); } + } - // set visibility for virtual variations - foreach ( $enabling_sync_virtual_variations as $variation ) { + // set visibility for virtual variations + foreach ( $enabling_sync_virtual_variations as $variation ) { - Products::set_product_visibility( $variation, false ); - } - }//end if + Products::set_product_visibility( $variation, false ); + } + }//end if - if ( 'facebook_include' === $action ) { + $products[] = $product; - Products::enable_sync_for_products( $products ); + if ( $this::BULK_EDIT_SYNC === $sync_mode ) { - $this->resync_products( $products ); + Products::enable_sync_for_products( $products ); - } elseif ( 'facebook_exclude' === $action ) { + $this->resync_products( $products ); - Products::disable_sync_for_products( $products ); + } elseif ( $this::BULK_EDIT_DELETE === $sync_mode ) { - self::add_product_disabled_sync_notice( count( $products ) ); - } - }//end if - }//end if + Products::disable_sync_for_products( $products ); - return $redirect; + } + } //end if } - /** * Re-syncs the given products. * @@ -994,22 +990,6 @@ private function resync_products( array $products ) { } } - - /** - * Adds a transient so an informational notice is displayed on the next page load. - * - * @since 2.0.0 - * - * @param int $count number of products - */ - public static function add_product_disabled_sync_notice( $count = 1 ) { - - if ( ! facebook_for_woocommerce()->get_admin_notice_handler()->is_notice_dismissed( 'wc-' . facebook_for_woocommerce()->get_id_dasherized() . '-product-disabled-sync' ) ) { - set_transient( 'wc_' . facebook_for_woocommerce()->get_id() . '_show_product_disabled_sync_notice_' . get_current_user_id(), $count, MINUTE_IN_SECONDS ); - } - } - - /** * Adds a message for after a product or set of products get excluded from sync. * diff --git a/includes/Products.php b/includes/Products.php index c578c913d..c10bfa027 100644 --- a/includes/Products.php +++ b/includes/Products.php @@ -91,7 +91,7 @@ private static function set_sync_for_products( array $products, $enabled ) { } // Remove excluded product from FB. - if ( "no" === $enabled && self::product_should_be_deleted( $product ) ) { + if ( "no" === $enabled ) { facebook_for_woocommerce()->get_integration()->delete_fb_product( $product ); } diff --git a/tests/Unit/WCFacebookCommerceIntegrationTest.php b/tests/Unit/WCFacebookCommerceIntegrationTest.php index 3a2c301cf..97a3451e8 100644 --- a/tests/Unit/WCFacebookCommerceIntegrationTest.php +++ b/tests/Unit/WCFacebookCommerceIntegrationTest.php @@ -573,11 +573,17 @@ public function test_on_product_save_existing_simple_product_sync_enabled_update */ public function test_on_product_save_existing_simple_product_sync_disabled_updates_the_product() { $product_to_update = WC_Helper_Product::create_simple_product(); - $product_to_delete = WC_Helper_Product::create_simple_product(); + + // The idea of the following mock is to overide the delete_product_item. + // The test is that the product item is being deleted as when it is marked for do not sync. + // The mock below is hit otherwise it would generate a random Mock_Response and throw error + $integration_mock = $this->createMock(WC_Facebookcommerce_Integration::class); + $integration_mock->method('delete_product_item'); + $this->integration = $integration_mock; $_POST['wc_facebook_sync_mode'] = Admin::SYNC_MODE_SYNC_DISABLED; - $_POST[ WC_Facebook_Product::FB_REMOVE_FROM_SYNC ] = $product_to_delete->get_id(); + $_POST[ WC_Facebook_Product::FB_REMOVE_FROM_SYNC ] = $product_to_update->get_id(); $product_to_update->set_stock_status( 'instock' ); @@ -586,11 +592,8 @@ public function test_on_product_save_existing_simple_product_sync_disabled_updat $this->integration->on_product_save( $product_to_update->get_id() ); - $this->assertEquals( null, get_post_meta( $product_to_delete->get_id(), WC_Facebookcommerce_Integration::FB_PRODUCT_ITEM_ID, true ) ); - $this->assertEquals( null, get_post_meta( $product_to_delete->get_id(), WC_Facebookcommerce_Integration::FB_PRODUCT_GROUP_ID, true ) ); - $this->assertEquals( 'no', get_post_meta( $product_to_update->get_id(), Products::SYNC_ENABLED_META_KEY, true ) ); - $this->assertEquals( 'no', get_post_meta( $product_to_update->get_id(), Products::VISIBILITY_META_KEY, true ) ); - + $this->assertEquals( 'facebook-product-item-id', get_post_meta( $product_to_update->get_id(), WC_Facebookcommerce_Integration::FB_PRODUCT_ITEM_ID, true ) ); + $this->assertEquals( null, get_post_meta( $product_to_update->get_id(), WC_Facebookcommerce_Integration::FB_PRODUCT_GROUP_ID, true ) ); } /**