screen_ids = [
'product',
'edit-product',
'woocommerce_page_wc-facebook',
'marketing_page_wc-facebook',
'edit-product_cat',
$order_screen_id,
];
// enqueue admin scripts
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
// handle dismiss action for WordPress.com update notice (runs before admin_notices)
add_action( 'admin_init', array( $this, 'handle_wpcom_update_notice_dismiss' ) );
// add admin notice about WordPress.com automatic updates ending (always check, regardless of connection status)
// Note: check is deferred to admin_notices time so the dismiss handler (admin_init) runs first
add_action( 'admin_notices', array( $this, 'maybe_show_wpcom_update_notice' ) );
$plugin = facebook_for_woocommerce();
// only alter the admin UI if the plugin is connected to Facebook and ready to sync products
if ( ! $plugin->get_connection_handler()->is_connected() || ! $plugin->get_integration()->get_product_catalog_id() ) {
return;
}
$this->product_categories = new Admin\Product_Categories();
// add a modal in admin product pages
add_action( 'admin_footer', array( $this, 'render_modal_template' ) );
add_action( 'admin_footer', array( $this, 'add_tab_switch_script' ) );
// add admin notice to inform that disabled products may need to be deleted manually
add_action( 'admin_notices', array( $this, 'maybe_show_product_disabled_sync_notice' ) );
// add admin notice if the user is enabling sync for virtual products using the bulk action
add_action( 'admin_notices', array( $this, 'maybe_add_enabling_virtual_products_sync_notice' ) );
add_filter( 'request', array( $this, 'filter_virtual_products_affected_enabling_sync' ) );
// add admin notice to inform sync mode has been automatically set to Sync and hide for virtual products and variations
add_action( 'admin_notices', array( $this, 'add_handled_virtual_products_variations_notice' ) );
// add columns for displaying Facebook sync enabled/disabled and catalog visibility status
add_filter( 'manage_product_posts_columns', array( $this, 'add_product_list_table_columns' ) );
add_action( 'manage_product_posts_custom_column', array( $this, 'add_product_list_table_columns_content' ) );
// add input to filter products by Facebook sync enabled
add_action( 'restrict_manage_posts', array( $this, 'add_products_by_sync_enabled_input_filter' ), 40 );
add_filter( 'request', array( $this, 'filter_products_by_sync_enabled' ) );
// add bulk actions to manage products sync
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' ) );
add_action( 'woocommerce_product_data_panels', array( $this, 'add_product_settings_tab_content' ) );
// add Variation edit fields
add_action( 'woocommerce_product_after_variable_attributes', array( $this, 'add_product_variation_edit_fields' ), 10, 3 );
add_action( 'woocommerce_save_product_variation', array( $this, 'save_product_variation_edit_fields' ), 10, 2 );
add_action( 'wp_ajax_get_facebook_product_data', array( $this, 'ajax_get_facebook_product_data' ) );
add_action( 'wp_ajax_sync_facebook_attributes', array( $this, 'ajax_sync_facebook_attributes' ) );
}
/**
* Enqueues admin scripts.
*
* @internal
*
* @since 1.10.0
*/
public function enqueue_scripts() {
global $current_screen;
if ( isset( $current_screen->id ) ) {
if ( in_array( $current_screen->id, $this->screen_ids, true ) || facebook_for_woocommerce()->is_plugin_settings() ) {
// enqueue modal functions
wp_enqueue_script(
'facebook-for-woocommerce-modal',
facebook_for_woocommerce()->get_asset_build_dir_url() . '/admin/modal.js',
array( 'jquery', 'wc-backbone-modal', 'jquery-blockui' ),
\WC_Facebookcommerce::PLUGIN_VERSION,
false
);
// enqueue google product category select
wp_enqueue_script(
'wc-facebook-google-product-category-fields',
facebook_for_woocommerce()->get_asset_build_dir_url() . '/admin/google-product-category-fields.js',
array( 'jquery' ),
\WC_Facebookcommerce::PLUGIN_VERSION,
false
);
wp_localize_script(
'wc-facebook-google-product-category-fields',
'facebook_for_woocommerce_google_product_category',
array(
'i18n' => array(
'top_level_dropdown_placeholder' => __( 'Search main categories...', 'facebook-for-woocommerce' ),
'second_level_empty_dropdown_placeholder' => __( 'Choose a main category first', 'facebook-for-woocommerce' ),
'general_dropdown_placeholder' => __( 'Choose a category', 'facebook-for-woocommerce' ),
),
)
);
}
if ( 'product' === $current_screen->id || 'edit-product' === $current_screen->id ) {
wp_enqueue_style(
'facebook-for-woocommerce-products-admin',
facebook_for_woocommerce()->get_plugin_url() . '/assets/css/admin/facebook-for-woocommerce-products-admin.css',
[],
\WC_Facebookcommerce::PLUGIN_VERSION
);
wp_enqueue_script(
'facebook-for-woocommerce-products-admin',
facebook_for_woocommerce()->get_asset_build_dir_url() . '/admin/products-admin.js',
[ 'jquery', 'wc-backbone-modal', 'jquery-blockui', 'facebook-for-woocommerce-modal' ],
\WC_Facebookcommerce::PLUGIN_VERSION,
false
);
wp_localize_script(
'facebook-for-woocommerce-products-admin',
'facebook_for_woocommerce_products_admin',
[
'ajax_url' => admin_url( 'admin-ajax.php' ),
'enhanced_attribute_optional_selector' => Enhanced_Catalog_Attribute_Fields::FIELD_ENHANCED_CATALOG_ATTRIBUTE_PREFIX . Enhanced_Catalog_Attribute_Fields::OPTIONAL_SELECTOR_KEY,
'enhanced_attribute_page_type_edit_category' => Enhanced_Catalog_Attribute_Fields::PAGE_TYPE_EDIT_CATEGORY,
'enhanced_attribute_page_type_add_category' => Enhanced_Catalog_Attribute_Fields::PAGE_TYPE_ADD_CATEGORY,
'enhanced_attribute_page_type_edit_product' => Enhanced_Catalog_Attribute_Fields::PAGE_TYPE_EDIT_PRODUCT,
'is_product_published' => $this->is_current_product_published(),
'is_sync_enabled_for_product' => $this->is_sync_enabled_for_current_product(),
'set_product_visibility_nonce' => wp_create_nonce( 'set-products-visibility' ),
'set_product_sync_prompt_nonce' => wp_create_nonce( 'set-product-sync-prompt' ),
'set_product_sync_bulk_action_prompt_nonce' => wp_create_nonce( 'set-product-sync-bulk-action-prompt' ),
'product_not_ready_modal_message' => $this->get_product_not_ready_modal_message(),
'product_not_ready_modal_buttons' => $this->get_product_not_ready_modal_buttons(),
'product_removed_from_sync_field_id' => '#' . \WC_Facebook_Product::FB_REMOVE_FROM_SYNC,
'i18n' => [
'missing_google_product_category_message' => __( 'Please enter a Google product category and at least one sub-category to sell this product on Instagram.', 'facebook-for-woocommerce' ),
],
]
);
}//end if
if ( facebook_for_woocommerce()->is_plugin_settings() ) {
wp_enqueue_style( 'woocommerce_admin_styles' );
wp_enqueue_script( 'wc-enhanced-select' );
}
}//end if
}
/**
* Determines whether sync is enabled for the current product.
*
* @since 2.0.5
*
* @return bool
*/
private function is_sync_enabled_for_current_product() {
global $post;
$product = wc_get_product( $post );
if ( ! $product instanceof \WC_Product ) {
return false;
}
return Products::is_sync_enabled_for_product( $product );
}
/**
* Determines whether the current product is published.
*
* @since 2.6.15
*
* @return bool
*/
private function is_current_product_published() {
global $post;
$product = wc_get_product( $post );
if ( ! $product instanceof \WC_Product ) {
return false;
}
return 'publish' === $product->get_status();
}
/**
* Gets the markup for the message used in the product not ready modal.
*
* @since 2.1.0
*
* @return string
*/
private function get_product_not_ready_modal_message() {
ob_start();
?>
opening HTML tag, %2$s - closing HTML tag */
__( 'Has %1$sManage Stock%2$s enabled on the %1$sInventory%2$s tab', 'facebook-for-woocommerce' ),
'',
''
)
);
?>
opening HTML tag, %2$s - closing HTML tag */
__( 'Has the %1$sFacebook Sync%2$s setting set to "Sync and show" or "Sync and hide"', 'facebook-for-woocommerce' ),
'',
''
)
);
?>
product_categories;
}
/**
* Adds Facebook-related columns in the products edit screen.
*
* @internal
*
* @since 1.10.0
*
* @param array $columns array of keys and labels
* @return array
*/
public function add_product_list_table_columns( $columns ) {
$columns['facebook_sync'] = __( 'Synced to Meta catalog', 'facebook-for-woocommerce' );
return $columns;
}
/**
* Outputs sync information for products in the edit screen.
*
* @internal
*
* @since 1.10.0
*
* @param string $column the current column in the posts table
*/
public function add_product_list_table_columns_content( $column ) {
global $post;
if ( 'facebook_sync' !== $column ) {
return;
}
$product = wc_get_product( $post );
$should_sync = false;
$no_sync_reason = '';
if ( $product instanceof \WC_Product ) {
try {
facebook_for_woocommerce()->get_product_sync_validator( $product )->validate();
$should_sync = true;
} catch ( \Exception $e ) {
$no_sync_reason = $e->getMessage();
}
}
if ( $should_sync ) {
esc_html_e( 'Synced', 'facebook-for-woocommerce' );
} else {
esc_html_e( 'Not synced', 'facebook-for-woocommerce' );
if ( ! empty( $no_sync_reason ) ) {
echo wc_help_tip( $no_sync_reason );
}
}
}
/**
* Adds a dropdown input to let shop managers filter products by sync setting.
*
* @internal
*
* @since 1.10.0
*/
public function add_products_by_sync_enabled_input_filter() {
global $typenow;
if ( 'product' !== $typenow ) {
return;
}
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$choice = isset( $_GET['fb_sync_enabled'] ) ? (string) sanitize_text_field( wp_unslash( $_GET['fb_sync_enabled'] ) ) : '';
?>
add_query_vars_to_find_products_with_sync_enabled( $query_vars );
$found_ids = get_posts( array_merge( $query_vars, array( 'fields' => 'ids' ) ) );
$found_products = empty( $found_ids ) ? [] : wc_get_products(
array(
'limit' => -1,
'include' => $found_ids,
)
);
/** @var \WC_Product[] $found_products */
foreach ( $found_products as $product ) {
try {
facebook_for_woocommerce()->get_product_sync_validator( $product )->validate();
} catch ( \Exception $e ) {
$exclude_products[] = $product->get_id();
}
}
if ( ! empty( $exclude_products ) ) {
if ( ! empty( $query_vars['post__not_in'] ) ) {
$query_vars['post__not_in'] = array_merge( $query_vars['post__not_in'], $exclude_products );
} else {
$query_vars['post__not_in'] = $exclude_products;
}
}
/**
* Showing only published products as private ones are not synced
*/
$query_vars['post_status'] = 'publish';
} else {
$query_vars = $this->add_query_vars_to_find_products_with_sync_disabled( $query_vars );
}
}
if ( isset( $query_vars['meta_query'] ) && empty( $query_vars['meta_query'] ) ) {
unset( $query_vars['meta_query'] );
}
return $query_vars;
}
/**
* Adds query vars to limit the results to products that have sync enabled.
*
* @since 1.10.0
*
* @param array $query_vars
* @return array
*/
private function add_query_vars_to_find_products_with_sync_enabled( array $query_vars ) {
$meta_query = array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
'relation' => 'OR',
array(
'key' => Products::get_product_sync_meta_key(),
'value' => 'yes',
),
array(
'key' => Products::get_product_sync_meta_key(),
'compare' => 'NOT EXISTS',
),
);
if ( empty( $query_vars['meta_query'] ) ) {
$query_vars['meta_query'] = $meta_query; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
} elseif ( is_array( $query_vars['meta_query'] ) ) {
$original_meta_query = $query_vars['meta_query'];
$query_vars['meta_query'] = array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
'relation' => 'AND',
$original_meta_query,
$meta_query,
);
}
// check whether the product belongs to an excluded product category or tag
$query_vars = $this->maybe_add_tax_query_for_excluded_taxonomies( $query_vars );
return $query_vars;
}
/**
* Adds query vars to limit the results to products that have sync disabled.
*
* @since 3.5.5
*
* @param array $query_vars
* @return array
*/
private function add_query_vars_to_find_products_with_sync_disabled( array $query_vars ) {
$meta_query = array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
array(
'key' => Products::get_product_sync_meta_key(),
'value' => 'no',
),
);
if ( empty( $query_vars['meta_query'] ) ) {
$query_vars['meta_query'] = $meta_query; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
} elseif ( is_array( $query_vars['meta_query'] ) ) {
$original_meta_query = $query_vars['meta_query'];
$query_vars['meta_query'] = array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
'relation' => 'AND',
$original_meta_query,
$meta_query,
);
}
return $query_vars;
}
/**
* Adds a tax query to filter in/out products in excluded product categories and product tags.
*
* @since 1.10.0
*
* @param array $query_vars product query vars for the edit screen
* @param bool $in whether we want to return products in excluded categories and tags or not
* @return array
*/
private function maybe_add_tax_query_for_excluded_taxonomies( $query_vars, $in = false ) {
$integration = facebook_for_woocommerce()->get_integration();
if ( $integration ) {
$tax_query = [];
$excluded_categories_ids = $integration->get_excluded_product_category_ids();
if ( $excluded_categories_ids ) {
$tax_query[] = array(
'taxonomy' => 'product_cat',
'terms' => $excluded_categories_ids,
'field' => 'term_id',
'operator' => $in ? 'IN' : 'NOT IN',
);
}
$excluded_tags_ids = $integration->get_excluded_product_tag_ids();
if ( $excluded_tags_ids ) {
$tax_query[] = array(
'taxonomy' => 'product_tag',
'terms' => $excluded_tags_ids,
'field' => 'term_id',
'operator' => $in ? 'IN' : 'NOT IN',
);
}
if ( count( $tax_query ) > 1 ) {
$tax_query['relation'] = $in ? 'OR' : 'AND';
}
if ( $tax_query && empty( $query_vars['tax_query'] ) ) {
$query_vars['tax_query'] = $tax_query; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
} elseif ( $tax_query && is_array( $query_vars ) ) {
$query_vars['tax_query'][] = $tax_query;
}
}//end if
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
*
* @internal
*
* @param string $product_edit the product metadata that is being edited.
*/
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 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 );
// 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 );
}
}
// set visibility for virtual variations
foreach ( $enabling_sync_virtual_variations as $variation ) {
Products::set_product_visibility( $variation, false );
}
}//end if
$products[] = $product;
if ( $this::BULK_EDIT_SYNC === $sync_mode ) {
Products::enable_sync_for_products( $products );
$this->resync_products( $products );
} elseif ( $this::BULK_EDIT_DELETE === $sync_mode ) {
Products::disable_sync_for_products( $products );
}
} //end if
}
/**
* Re-syncs the given products.
*
* @since 2.0.0
*
* @param \WC_Product[] $products Array of product objects to resync
*/
private function resync_products( array $products ) {
$integration = facebook_for_woocommerce()->get_integration();
// re-sync each product
foreach ( $products as $product ) {
if ( $product->is_type( 'variable' ) ) {
// create product group and schedule product variations to be synced in the background
$integration->on_product_publish( $product->get_id() );
} elseif ( $integration->product_should_be_synced( $product ) ) {
// 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() ) );
}
}
}
}
/**
* Adds a message for after a product or set of products get excluded from sync.
*
* @since 2.0.0
*/
public function maybe_show_product_disabled_sync_notice() {
$transient_name = 'wc_' . facebook_for_woocommerce()->get_id() . '_show_product_disabled_sync_notice_' . get_current_user_id();
$message_id = 'wc-' . facebook_for_woocommerce()->get_id_dasherized() . '-product-disabled-sync';
$count = get_transient( $transient_name );
if ( $count && ( Helper::is_current_screen( 'edit-product' ) || Helper::is_current_screen( 'product' ) ) ) {
$message = sprintf(
/* translators: Placeholders: %1$s - tag, %2$s - tag, %3$s - tag, %4$s - tag */
_n( '%1$sHeads up!%2$s If this product was previously visible in Facebook, you may need to delete it from the %3$sFacebook catalog%4$s to completely hide it from customer view.', '%1$sHeads up!%2$s If these products were previously visible in Facebook, you may need to delete them from the %3$sFacebook catalog%4$s to completely hide them from customer view.', $count, 'facebook-for-woocommerce' ),
'',
'',
'',
''
);
$message .= '' . esc_html__( "Don't show this notice again", 'facebook-for-woocommerce' ) . '';
facebook_for_woocommerce()->get_admin_notice_handler()->add_admin_notice(
$message,
$message_id,
array(
'dismissible' => false,
// we add our own dismiss button
'notice_class' => 'notice-info',
)
);
delete_transient( $transient_name );
}//end if
}
/**
* Prints a notice on products page to inform users that the virtual products selected for the Include bulk action will have sync enabled, but will be hidden.
*
* @internal
*
* @since 1.11.3-dev.2
*/
public function maybe_add_enabling_virtual_products_sync_notice() {
$show_notice_transient_name = 'wc_' . facebook_for_woocommerce()->get_id() . '_enabling_virtual_products_sync_show_notice_' . get_current_user_id();
$affected_products_transient_name = 'wc_' . facebook_for_woocommerce()->get_id() . '_enabling_virtual_products_sync_affected_products_' . get_current_user_id();
$affected_products = get_transient( $affected_products_transient_name );
if ( Helper::is_current_screen( 'edit-product' ) && get_transient( $show_notice_transient_name ) && $affected_products ) {
$message = sprintf(
esc_html(
/* translators: Placeholders: %1$s - number of affected products, %2$s opening HTML tag, %3$s - closing HTML tag, %4$s - opening HTML tag, %5$s - closing HTML tag */
_n(
'%2$s%1$s product%3$s or some of its variations could not be updated to show in the Facebook catalog — %4$sFacebook Commerce Policies%5$s prohibit selling some product types (like virtual products). You may still advertise Virtual products on Facebook.',
'%2$s%1$s products%3$s or some of their variations could not be updated to show in the Facebook catalog — %4$sFacebook Commerce Policies%5$s prohibit selling some product types (like virtual products). You may still advertise Virtual products on Facebook.',
count( $affected_products ),
'facebook-for-woocommerce'
)
),
count( $affected_products ),
'',
'',
'',
''
);
facebook_for_woocommerce()->get_admin_notice_handler()->add_admin_notice(
$message,
'wc-' . facebook_for_woocommerce()->get_id_dasherized() . '-enabling-virtual-products-sync',
array(
'dismissible' => false,
'notice_class' => 'notice-info',
)
);
delete_transient( $show_notice_transient_name );
}//end if
}
/**
* Tweaks the query to show a filtered view with the affected products.
*
* @internal
*
* @since 2.0.0
*
* @param array $query_vars product query vars for the edit screen
* @return array
*/
public function filter_virtual_products_affected_enabling_sync( $query_vars ) {
$transient_name = 'wc_' . facebook_for_woocommerce()->get_id() . '_enabling_virtual_products_sync_affected_products_' . get_current_user_id();
$affected_products = get_transient( $transient_name );
// phpcs:disable WordPress.Security.NonceVerification.Recommended
if ( isset( $_GET['facebook_show_affected_products'] ) && Helper::is_current_screen( 'edit-product' ) && $affected_products ) {
$query_vars['post__in'] = $affected_products;
}
// phpcs:enable WordPress.Security.NonceVerification.Recommended
return $query_vars;
}
/**
* Prints a notice to inform sync mode has been automatically set to Sync and hide for virtual products and variations.
*
* @internal
*
* @since 2.0.0
*/
public function add_handled_virtual_products_variations_notice() {
if ( 'yes' === get_option( 'wc_facebook_background_handle_virtual_products_variations_complete', 'no' ) &&
'yes' !== get_option( 'wc_facebook_background_handle_virtual_products_variations_skipped', 'no' ) ) {
facebook_for_woocommerce()->get_admin_notice_handler()->add_admin_notice(
sprintf(
/* translators: Placeholders: %1$s - opening HTML tag, %2$s - closing HTML tag, %3$s - opening HTML tag, %4$s - closing HTML tag */
esc_html__( '%1$sHeads up!%2$s Facebook\'s %3$sCommerce Policies%4$s do not support selling virtual products, so we have hidden your synced Virtual products in your Facebook catalog. You may still advertise Virtual products on Facebook.', 'facebook-for-woocommerce' ),
'',
'',
'',
''
),
'wc-' . facebook_for_woocommerce()->get_id_dasherized() . '-updated-virtual-products-sync',
array(
'notice_class' => 'notice-info',
'always_show_on_settings' => false,
)
);
}
}
/**
* Adds a new tab to the Product edit page.
*
* @internal
*
* @since 1.10.0
*
* @param array $tabs product tabs
* @return array
*/
public function add_product_settings_tab( $tabs ) {
$tabs['fb_commerce_tab'] = array(
'label' => __( 'Facebook', 'facebook-for-woocommerce' ),
'target' => 'facebook_options',
'class' => array( 'show_if_simple', 'show_if_variable', 'show_if_external' ),
);
return $tabs;
}
/**
* Outputs the form field for Facebook Product Videos with a description tip.
*
* @param array $video_urls Array of video URLs.
*/
private function render_facebook_product_video_field( $video_urls ) {
$attachment_ids = [];
// Output the form field for Facebook Product Videos with a description tip
?>
\WC_Facebook_Product::FB_PRODUCT_VIDEO,
'name' => \WC_Facebook_Product::FB_PRODUCT_VIDEO,
'value' => esc_attr( implode( ',', $attachment_ids ) ), // Store attachment IDs
]
);
}
/**
* Renders the Facebook Product Images field for variations.
*
* @param array $attachment_ids Array of attachment IDs.
* @param int $index The variation index.
* @param int $variation_id The variation ID.
*/
private function render_facebook_product_images_field( $attachment_ids, $index, $variation_id ) {
// Check if multiple images feature is enabled via rollout switch
$plugin = isset( $GLOBALS['wc_facebook_commerce'] ) ? $GLOBALS['wc_facebook_commerce'] : facebook_for_woocommerce();
if ( ! $plugin || ! $plugin->get_rollout_switches()->is_switch_enabled( RolloutSwitches::SWITCH_MULTIPLE_IMAGES_ENABLED ) ) {
return;
}
// attachment_ids is already an array of attachment IDs
// Output the form field for Facebook Product Images with a description tip
?>
'wc_facebook_sync_mode',
'label' => __( 'Facebook Sync', 'facebook-for-woocommerce' ),
'options' => array(
self::SYNC_MODE_SYNC_AND_SHOW => __( 'Sync and show in catalog', 'facebook-for-woocommerce' ),
self::SYNC_MODE_SYNC_AND_HIDE => __( 'Sync and hide in catalog', 'facebook-for-woocommerce' ),
self::SYNC_MODE_SYNC_DISABLED => __( 'Do not sync', 'facebook-for-woocommerce' ),
),
'value' => $sync_mode,
'desc_tip' => true,
'description' => __( 'Choose whether to sync this product to Facebook and, if synced, whether it should be visible in the catalog.', 'facebook-for-woocommerce' ),
)
);
?>