Files
2026-04-28 15:13:50 +02:00

372 lines
12 KiB
PHP

<?php
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*
* @package MetaCommerce
*/
namespace WooCommerce\Facebook\API\Plugin\Settings;
use WooCommerce\Facebook\API\Plugin\AbstractRESTEndpoint;
use WooCommerce\Facebook\API\Plugin\Settings\Update\Request as UpdateRequest;
use WooCommerce\Facebook\API\Plugin\Settings\Uninstall\Request as UninstallRequest;
use WooCommerce\Facebook\Framework\Logger;
defined( 'ABSPATH' ) || exit;
/**
* Settings REST API endpoint handler.
*
* @since 3.5.0
*/
class Handler extends AbstractRESTEndpoint {
/**
* Register routes for this endpoint.
*
* @since 3.5.0
*
* @return void
*/
public function register_routes() {
register_rest_route(
$this->get_namespace(),
'/settings/update',
[
'methods' => \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'handle_update' ],
'permission_callback' => [ $this, 'permission_callback' ],
]
);
register_rest_route(
$this->get_namespace(),
'/settings/uninstall',
[
'methods' => \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'handle_uninstall' ],
'permission_callback' => [ $this, 'permission_callback' ],
]
);
}
/**
* Handle the update settings request.
*
* @since 3.5.0
* @http_method POST
* @description Update Facebook settings
*
* @param \WP_REST_Request $wp_request The WordPress request object.
* @return \WP_REST_Response
*/
public function handle_update( \WP_REST_Request $wp_request ): \WP_REST_Response {
try {
$request = new UpdateRequest( $wp_request );
$request_data = $request->get_data();
$validation_result = $request->validate();
if ( is_wp_error( $validation_result ) ) {
return $this->error_response(
$validation_result->get_error_message(),
400
);
}
// Check if we should trigger product sync and/or metadata feed uploads for this update
// Only trigger products and sets sync if catalog id is being updated
$should_trigger_products_and_sets_sync = ! empty( $request_data['product_catalog_id'] ) && facebook_for_woocommerce()->get_integration()->get_product_catalog_id() !== $request_data['product_catalog_id'];
// Only trigger metadata feed uploads if CPI id is being updated
$should_trigger_metadata_feed_uploads = ! empty( $request_data['commerce_partner_integration_id'] ) && facebook_for_woocommerce()->get_connection_handler()->get_commerce_partner_integration_id() !== $request_data['commerce_partner_integration_id'];
// Map parameters to options and update settings
$options = $this->map_params_to_options( $request_data );
$this->update_settings( $options );
// Update connection status flags
$this->update_connection_status( $request_data );
// Maybe trigger products sync and/or metadata feed uploads
$this->maybe_trigger_feed_uploads( $should_trigger_products_and_sets_sync, $should_trigger_metadata_feed_uploads, $request_data );
return $this->success_response(
[
'message' => __( 'Facebook settings updated successfully', 'facebook-for-woocommerce' ),
]
);
} catch ( \Exception $e ) {
return $this->error_response(
$e->getMessage(),
500
);
}
}
/**
* Handle the uninstall request.
*
* @since 3.5.0
* @http_method POST
* @description Uninstall Facebook integration
*
* @param \WP_REST_Request $wp_request The WordPress request object.
* @return \WP_REST_Response
*/
public function handle_uninstall( \WP_REST_Request $wp_request ): \WP_REST_Response {
try {
$request = new UninstallRequest( $wp_request );
$validation_result = $request->validate();
if ( is_wp_error( $validation_result ) ) {
return $this->error_response(
$validation_result->get_error_message(),
400
);
}
// Clear integration options
$this->clear_integration_options();
return $this->success_response(
[
'message' => __( 'Facebook integration successfully uninstalled', 'facebook-for-woocommerce' ),
]
);
} catch ( \Exception $e ) {
return $this->error_response(
$e->getMessage(),
500
);
}
}
/**
* Maps request parameters to WooCommerce options.
*
* @since 3.5.0
*
* @param array $params Request parameters.
* @return array Mapped options.
*/
private function map_params_to_options( array $params ): array {
$options = [];
// Map access tokens
if ( ! empty( $params['access_token'] ) ) {
$options[ \WC_Facebookcommerce_Integration::OPTION_ACCESS_TOKEN ] = $params['access_token'];
}
if ( ! empty( $params['commerce_merchant_settings_id'] ) ) {
$options[ \WC_Facebookcommerce_Integration::OPTION_COMMERCE_MERCHANT_SETTINGS_ID ] = $params['commerce_merchant_settings_id'];
}
if ( ! empty( $params['commerce_partner_integration_id'] ) ) {
$options[ \WC_Facebookcommerce_Integration::OPTION_COMMERCE_PARTNER_INTEGRATION_ID ] = $params['commerce_partner_integration_id'];
}
if ( ! empty( $params['installed_features'] ) ) {
$options[ \WC_Facebookcommerce_Integration::OPTION_INSTALLED_FEATURES ] = $params['installed_features'];
}
if ( ! empty( $params['merchant_access_token'] ) ) {
$options[ \WC_Facebookcommerce_Integration::OPTION_MERCHANT_ACCESS_TOKEN ] = $params['merchant_access_token'];
}
if ( ! empty( $params['page_id'] ) ) {
update_option( \WC_Facebookcommerce_Integration::SETTING_FACEBOOK_PAGE_ID, $params['page_id'] );
}
if ( ! empty( $params['pixel_id'] ) ) {
$options[ \WC_Facebookcommerce_Integration::SETTING_FACEBOOK_PIXEL_ID ] = $params['pixel_id'];
update_option( \WC_Facebookcommerce_Integration::SETTING_FACEBOOK_PIXEL_ID, $params['pixel_id'] );
}
if ( ! empty( $params['product_catalog_id'] ) ) {
$options[ \WC_Facebookcommerce_Integration::OPTION_PRODUCT_CATALOG_ID ] = $params['product_catalog_id'];
}
if ( ! empty( $params['profiles'] ) ) {
$options[ \WC_Facebookcommerce_Integration::OPTION_PROFILES ] = $params['profiles'];
}
if ( ! empty( $params['business_manager_id'] ) ) {
$options[ \WC_Facebookcommerce_Integration::OPTION_BUSINESS_MANAGER_ID ] = $params['business_manager_id'];
}
return $options;
}
/**
* Updates Facebook settings options.
*
* @since 3.5.0
*
* @param array $settings Array of settings to update.
* @return void
*/
private function update_settings( array $settings ) {
foreach ( $settings as $key => $value ) {
if ( ! empty( $key ) ) {
update_option( $key, $value );
}
}
}
/**
* Updates connection status flags.
*
* @since 3.5.0
*
* @param array $params Request parameters.
* @return void
*/
private function update_connection_status( array $params ) {
// Set the connection is complete
update_option( 'wc_facebook_has_connected_fbe_2', 'yes' );
update_option( 'wc_facebook_has_authorized_pages_read_engagement', 'yes' );
// Set the Messenger chat visibility
if ( ! empty( $params['msger_chat'] ) ) {
update_option( 'wc_facebook_enable_messenger', wc_bool_to_string( 'yes' === $params['msger_chat'] ) );
}
}
/**
* Clears all integration options.
*
* @since 3.5.0
*
* @return void
*/
private function clear_integration_options() {
$options = [
\WC_Facebookcommerce_Integration::OPTION_ACCESS_TOKEN,
\WC_Facebookcommerce_Integration::OPTION_BUSINESS_MANAGER_ID,
\WC_Facebookcommerce_Integration::OPTION_AD_ACCOUNT_ID,
\WC_Facebookcommerce_Integration::OPTION_SYSTEM_USER_ID,
\WC_Facebookcommerce_Integration::OPTION_FEED_ID,
\WC_Facebookcommerce_Integration::OPTION_COMMERCE_MERCHANT_SETTINGS_ID,
\WC_Facebookcommerce_Integration::OPTION_COMMERCE_PARTNER_INTEGRATION_ID,
\WC_Facebookcommerce_Integration::OPTION_ENABLE_MESSENGER,
\WC_Facebookcommerce_Integration::OPTION_HAS_AUTHORIZED_PAGES_READ_ENGAGEMENT,
\WC_Facebookcommerce_Integration::OPTION_HAS_CONNECTED_FBE_2,
\WC_Facebookcommerce_Integration::OPTION_INSTALLED_FEATURES,
\WC_Facebookcommerce_Integration::OPTION_MERCHANT_ACCESS_TOKEN,
\WC_Facebookcommerce_Integration::OPTION_PRODUCT_CATALOG_ID,
\WC_Facebookcommerce_Integration::OPTION_PROFILES,
\WC_Facebookcommerce_Integration::SETTING_FACEBOOK_PAGE_ID,
\WC_Facebookcommerce_Integration::SETTING_FACEBOOK_PIXEL_ID,
];
foreach ( $options as $option ) {
delete_option( $option );
}
// Clear facebook_config option to stop pixel tracking and prevent stale data
if ( class_exists( 'WC_Facebookcommerce_Pixel' ) ) {
delete_option( \WC_Facebookcommerce_Pixel::SETTINGS_KEY );
}
}
/**
* Triggers products sync if catalog id is being set to a different value.
* Triggers metadata feed uploads if CPI id is being set to a different value.
*
* @since 3.5.0
*
* @param bool $should_trigger_products_and_sets_sync
* @param bool $should_trigger_metadata_feed_uploads
* @param array $params
* @return void
*/
private function maybe_trigger_feed_uploads( bool $should_trigger_products_and_sets_sync, bool $should_trigger_metadata_feed_uploads, array $params ) {
try {
if ( $should_trigger_products_and_sets_sync ) {
// Allow opt-out of full batch-API sync, for example if store has a large number of products.
if ( facebook_for_woocommerce()->get_integration()->allow_full_batch_api_sync() ) {
facebook_for_woocommerce()->get_products_sync_handler()->create_or_update_all_products();
} else {
Logger::log(
'Initial full product sync disabled by filter hook `facebook_for_woocommerce_allow_full_batch_api_sync`',
[
'flow_name' => 'product_sync',
'flow_step' => 'initial_sync',
],
array(
'should_send_log_to_meta' => true,
'should_save_log_in_woocommerce' => true,
'woocommerce_log_level' => \WC_Log_Levels::DEBUG,
)
);
}
}
} catch ( \Exception $exception ) {
Logger::log(
'Product feed upload failed.',
array(
'event' => 'product_sync',
'event_type' => 'sync_products_after_settings_update',
'extra_data' => [
'params' => wp_json_encode( $params ),
],
),
array(
'should_send_log_to_meta' => true,
'should_save_log_in_woocommerce' => false,
'woocommerce_log_level' => \WC_Log_Levels::DEBUG,
),
$exception,
);
}
try {
if ( $should_trigger_products_and_sets_sync ) {
facebook_for_woocommerce()->get_product_sets_sync_handler()->sync_all_product_sets();
}
} catch ( \Exception $exception ) {
Logger::log(
'Product sets sync failed.',
array(
'event' => 'product_sets_sync',
'event_type' => 'sync_product_sets_after_settings_update',
'extra_data' => [
'params' => wp_json_encode( $params ),
],
),
array(
'should_send_log_to_meta' => true,
'should_save_log_in_woocommerce' => false,
'woocommerce_log_level' => \WC_Log_Levels::DEBUG,
),
$exception,
);
}
try {
if ( $should_trigger_metadata_feed_uploads ) {
facebook_for_woocommerce()->feed_manager->run_all_feed_uploads();
}
} catch ( \Exception $exception ) {
Logger::log(
'Products metadata feed upload failed.',
array(
'event' => 'feed_upload',
'event_type' => 'trigger_feed_uploads_after_settings_update',
'extra_data' => [
'params' => wp_json_encode( $params ),
],
),
array(
'should_send_log_to_meta' => true,
'should_save_log_in_woocommerce' => false,
'woocommerce_log_level' => \WC_Log_Levels::DEBUG,
),
$exception,
);
}
}
}