Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion assets/js/admin/products-admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ jQuery( document ).ready( function( $ ) {
}
}


/**
* Disables and changes the checked status of the Sell on Instagram setting field.
*
Expand Down
32 changes: 23 additions & 9 deletions facebook-commerce.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use WooCommerce\Facebook\Products;
use WooCommerce\Facebook\Products\Feed;
use WooCommerce\Facebook\Framework\Logger;
use WooCommerce\Facebook\RolloutSwitches;

defined( 'ABSPATH' ) || exit;

Expand Down Expand Up @@ -2343,6 +2344,10 @@ public function get_facebook_pixel_id() {
* @since 1.10.0
*/
public function get_excluded_product_category_ids() {

if ( $this->is_woo_all_products_enabled() ) {
return (array) [];
}
/**
* Filters the configured excluded product category IDs.
*
Expand All @@ -2351,11 +2356,7 @@ public function get_excluded_product_category_ids() {
*
* @since 1.10.0
*/

// TODO: to Remove all existence of these function `get_excluded_product_category_ids` as we are no longer supporting these.
// Matter of fact it is used in multiple places including important places like Product sets tab.
// Hence providing empty array as excluded categories :)
return (array) [];
return (array) apply_filters( 'wc_facebook_excluded_product_category_ids', get_option( self::SETTING_EXCLUDED_PRODUCT_CATEGORY_IDS, [] ), $this );
}

/**
Expand All @@ -2365,6 +2366,9 @@ public function get_excluded_product_category_ids() {
* @since 1.10.0
*/
public function get_excluded_product_tag_ids() {
if ( $this->is_woo_all_products_enabled() ) {
return (array) [];
}
/**
* Filters the configured excluded product tag IDs.
*
Expand All @@ -2373,10 +2377,7 @@ public function get_excluded_product_tag_ids() {
*
* @since 1.10.0
*/
// TODO: to Remove all existence of these function `get_excluded_product_tag_ids` as we are no longer supporting these.
// Matter of fact it is used in multiple places including important places like Product sets tab.
// Hence providing empty array as excluded tags :)
return (array) [];
return (array) apply_filters( 'wc_facebook_excluded_product_tag_ids', get_option( self::SETTING_EXCLUDED_PRODUCT_TAG_IDS, [] ), $this );
}

/** Setter methods ************************************************************************************************/
Expand Down Expand Up @@ -2485,6 +2486,19 @@ public function is_configured() {
return $this->get_facebook_page_id() && $this->facebook_for_woocommerce->get_connection_handler()->is_connected();
}

/**
* Determines if viewing the plugin settings in the admin.
*
* @since 3.5.3
*
* @return bool
*/
public function is_woo_all_products_enabled() {
return $this->facebook_for_woocommerce->get_rollout_switches()->is_switch_enabled(
RolloutSwitches::SWITCH_WOO_ALL_PRODUCTS_SYNC_ENABLED
);
}

/**
* Determines whether advanced matching is enabled.
*
Expand Down
25 changes: 24 additions & 1 deletion includes/Admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,23 @@ private function maybe_add_tax_query_for_excluded_taxonomies( $query_vars, $in =
return $query_vars;
}

/**
* Adds bulk actions in the products edit screen.
*
* @internal
*
* @since 1.10.0
*
* @param array $bulk_actions array of bulk action keys and labels
* @return array
*/
public function add_products_sync_bulk_actions( $bulk_actions ) {
$bulk_actions['facebook_include'] = __( 'Include in Facebook sync', 'facebook-for-woocommerce' );
$bulk_actions['facebook_exclude'] = __( 'Exclude from Facebook sync', 'facebook-for-woocommerce' );
return $bulk_actions;
}


/**
* Handles a Facebook product sync bulk action.
* Called every time for a product
Expand Down Expand Up @@ -842,7 +859,13 @@ private function resync_products( array $products ) {
$integration->on_product_publish( $product->get_id() );

} elseif ( $integration->product_should_be_synced( $product ) ) {
facebook_for_woocommerce()->get_products_sync_handler()->create_or_update_products( array( $product->get_id() ) );

// schedule simple products to be updated or deleted from the catalog in the background
if ( Products::product_should_be_deleted( $product ) ) {
facebook_for_woocommerce()->get_products_sync_handler()->delete_products( array( $product->get_id() ) );
} else {
facebook_for_woocommerce()->get_products_sync_handler()->create_or_update_products( array( $product->get_id() ) );
}
}
}
}
Expand Down
48 changes: 48 additions & 0 deletions includes/ProductSync/ProductValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ public function validate() {
$this->validate_product_sync_field();
$this->validate_product_status();
$this->validate_product_visibility();
$this->validate_product_terms();
}

/**
Expand All @@ -124,6 +125,7 @@ public function validate() {
public function validate_but_skip_status_check() {
$this->validate_product_sync_field();
$this->validate_product_visibility();
$this->validate_product_terms();
}

/**
Expand All @@ -134,6 +136,7 @@ public function validate_but_skip_status_check() {
*/
public function validate_but_skip_sync_field() {
$this->validate_product_visibility();
$this->validate_product_terms();
}

/**
Expand All @@ -153,6 +156,23 @@ public function passes_all_checks(): bool {
return true;
}

/**
* Check if the product's terms (categories and tags) allow it to sync.
*
* @return bool
*/
public function passes_product_terms_check(): bool {
try {
$this->validate_product_terms();
} catch ( ProductExcludedException $e ) {
return false;
} catch ( ProductInvalidException $e ) {
return false;
}

return true;
}

/**
* Check if the product's product sync meta field allows it to sync.
*
Expand Down Expand Up @@ -238,6 +258,34 @@ protected function validate_product_visibility() {
}
}

/**
* Check whether the product's categories or tags (terms) exclude it from sync.
*
* @throws ProductExcludedException If product should not be synced.
*/
protected function validate_product_terms() {

if ( $this->integration->is_woo_all_products_enabled() ) {
return;
}

$product = $this->product_parent ? $this->product_parent : $this->product;

$excluded_categories = $this->integration->get_excluded_product_category_ids();
if ( $excluded_categories ) {
if ( ! empty( array_intersect( $product->get_category_ids(), $excluded_categories ) ) ) {
throw new ProductExcludedException( __( 'Product excluded because of categories.', 'facebook-for-woocommerce' ) );
}
}

$excluded_tags = $this->integration->get_excluded_product_tag_ids();
if ( $excluded_tags ) {
if ( ! empty( array_intersect( $product->get_tag_ids(), $excluded_tags ) ) ) {
throw new ProductExcludedException( __( 'Product excluded because of tags.', 'facebook-for-woocommerce' ) );
}
}
}

/**
* Validate if the product is excluded from at the "product level" (product meta value).
*
Expand Down
33 changes: 33 additions & 0 deletions includes/Products.php
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,23 @@ public static function published_product_should_be_synced( \WC_Product $product
}
}


/**
* Determines whether the given product should be removed from the catalog.
*
* A product should be removed if it is no longer in stock and the user has opted-in to hide products that are out of stock,
* or belongs to an excluded category.
*
* @since 2.0.0
*
* @param \WC_Product $product
* @return bool
*/
public static function product_should_be_deleted( \WC_Product $product ) {
return ! facebook_for_woocommerce()->get_product_sync_validator( $product )->passes_product_terms_check();
}


/**
* Determines whether a product is enabled to be synced in Facebook.
*
Expand All @@ -243,6 +260,22 @@ public static function is_sync_enabled_for_product( \WC_Product $product ) {
return facebook_for_woocommerce()->get_product_sync_validator( $product )->passes_product_sync_field_check();
}


/**
* Determines whether the product's terms would make it excluded to be synced from Facebook.
*
* @since 1.10.0
*
* @deprecated use \WooCommerce\Facebook\ProductSync\ProductValidator::passes_product_terms_check() instead
*
* @param \WC_Product $product product object
* @return bool if true, product should be excluded from sync, if false, product can be included in sync (unless manually excluded by individual product meta)
*/
public static function is_sync_excluded_for_product_terms( \WC_Product $product ) {
return ! facebook_for_woocommerce()->get_product_sync_validator( $product )->passes_product_terms_check();
}


/**
* Sets a product's visibility in the Facebook shop.
*
Expand Down
8 changes: 7 additions & 1 deletion includes/Products/Stock.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,19 @@ function ( $item ) {


/**
* Schedules a product sync to update the product's stock status
* Schedules a product sync to update the product's stock status.
*
* The product is removed from Facebook if it is out of stock and the plugin is configured to remove out of stock products from the catalog.
*
* @since 2.0.5
*
* @param \WC_Product $product a product object
*/
private function maybe_sync_product_stock_status( \WC_Product $product ) {
if ( Products::product_should_be_deleted( $product ) ) {
facebook_for_woocommerce()->get_integration()->delete_fb_product( $product );
return;
}
facebook_for_woocommerce()->get_products_sync_handler()->create_or_update_products( array( $product->get_id() ) );
}
}
2 changes: 1 addition & 1 deletion includes/Products/Sync/Background.php
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ private function process_item_update( $prefixed_product_id ) {
}

$request = null;
if ( Products::product_should_be_synced( $product ) ) {
if ( ! Products::product_should_be_deleted( $product ) && Products::product_should_be_synced( $product ) ) {

if ( $product->is_type( 'variation' ) ) {
$product_data = \WC_Facebookcommerce_Utils::prepare_product_variation_data_items_batch( $product );
Expand Down
18 changes: 10 additions & 8 deletions includes/RolloutSwitches.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,17 @@ class RolloutSwitches {
/** @var \WC_Facebookcommerce commerce handler */
private \WC_Facebookcommerce $plugin;

public const SWITCH_ROLLOUT_FEATURES = 'rollout_enabled';
public const WHATSAPP_UTILITY_MESSAGING = 'whatsapp_utility_messages_enabled';
public const SWITCH_PRODUCT_SETS_SYNC_ENABLED = 'product_sets_sync_enabled';
private const SETTINGS_KEY = 'wc_facebook_for_woocommerce_rollout_switches';
public const SWITCH_ROLLOUT_FEATURES = 'rollout_enabled';
public const WHATSAPP_UTILITY_MESSAGING = 'whatsapp_utility_messages_enabled';
public const SWITCH_PRODUCT_SETS_SYNC_ENABLED = 'product_sets_sync_enabled';
public const SWITCH_WOO_ALL_PRODUCTS_SYNC_ENABLED = 'woo_all_products_sync_enabled';
private const SETTINGS_KEY = 'wc_facebook_for_woocommerce_rollout_switches';

private const ACTIVE_SWITCHES = array(
self::SWITCH_ROLLOUT_FEATURES,
self::WHATSAPP_UTILITY_MESSAGING,
self::SWITCH_PRODUCT_SETS_SYNC_ENABLED,
self::SWITCH_WOO_ALL_PRODUCTS_SYNC_ENABLED,
);

public function __construct( \WC_Facebookcommerce $plugin ) {
Expand Down Expand Up @@ -82,13 +84,13 @@ public function init() {
Logger::log(
$e->getMessage(),
array(
'flow_name' => 'rollout_switches',
'flow_step' => 'init',
'flow_name' => 'rollout_switches',
'flow_step' => 'init',
),
array(
'should_send_log_to_meta' => true,
'should_send_log_to_meta' => true,
'should_save_log_in_woocommerce' => true,
'woocommerce_log_level' => \WC_Log_Levels::ERROR,
'woocommerce_log_level' => \WC_Log_Levels::ERROR,
)
);
}
Expand Down
7 changes: 6 additions & 1 deletion includes/fbproductfeed.php
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,12 @@ private function prepare_product_for_feed( $woo_product, &$attribute_variants )

$product_data['default_product'] = '';
}


// when dealing with the feed file, only set out-of-stock products as hidden
if ( Products::product_should_be_deleted( $woo_product->woo_product ) ) {
$product_data['visibility'] = \WC_Facebookcommerce_Integration::FB_SHOP_PRODUCT_HIDDEN;
}

// Sale price, only format if we have a sale price set for the product, else leave as empty ('').
$sale_price = static::get_value_from_product_data( $product_data, 'sale_price', '' );
$sale_price_effective_date = '';
Expand Down
Loading