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

239 lines
7.4 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\Feed\Localization;
defined( 'ABSPATH' ) || exit;
use WooCommerce\Facebook\Framework\Logger;
/**
* Language Feed Management Trait
*
* Consolidates common functionality for language override feed management
* including API instance management, feed ID storage/retrieval, and upload status.
* This eliminates duplication across multiple language feed classes.
*
* @since 3.6.0
*/
trait LanguageFeedManagementTrait {
/** @var \WooCommerce\Facebook\API */
private $api;
/**
* Gets the API instance.
*
* @since 3.6.0
* @return \WooCommerce\Facebook\API
*/
private function get_api() {
if ( ! $this->api ) {
$this->api = facebook_for_woocommerce()->get_api();
}
return $this->api;
}
/**
* Store the Facebook feed ID for a language.
*
* @param string $language_code Language code
* @param string $feed_id Facebook feed ID
* @since 3.6.0
*/
private function store_language_feed_id( string $language_code, string $feed_id ): void {
$stored_feeds = get_option( 'wc_facebook_language_feed_ids', [] );
$stored_feeds[ $language_code ] = $feed_id;
update_option( 'wc_facebook_language_feed_ids', $stored_feeds );
}
/**
* Retrieves or creates a language override feed ID.
*
* @param string $language_code Language code
* @return string Feed ID
* @since 3.6.0
*/
public function retrieve_or_create_language_feed_id( string $language_code ): string {
// Attempt 1. Request feeds data from Meta and filter the right one
$feed_id = $this->request_and_filter_language_feed_id( $language_code );
if ( $feed_id ) {
$this->store_language_feed_id( $language_code, $feed_id );
return $feed_id;
}
// Attempt 2. Create a new feed
$feed_id = $this->create_language_feed_id( $language_code );
if ( $feed_id ) {
$this->store_language_feed_id( $language_code, $feed_id );
return $feed_id;
}
return '';
}
/**
* Queries existing feeds for the integration catalog and filters
* the language override feed ID for a specific language.
*
* @param string $language_code Language code
* @throws \Exception If catalog operations fail.
* @return string Feed ID
* @since 3.6.0
*/
private function request_and_filter_language_feed_id( string $language_code ): string {
try {
$catalog_id = facebook_for_woocommerce()->get_integration()->get_product_catalog_id();
if ( '' === $catalog_id ) {
throw new \Exception( 'No catalog ID' );
}
$feed_nodes = $this->get_api()->read_feeds( $catalog_id )->data;
} catch ( \Exception $e ) {
$message = sprintf( 'There was an error trying to get feed nodes for catalog: %s', $e->getMessage() );
Logger::log(
$message,
[],
array(
'should_send_log_to_meta' => false,
'should_save_log_in_woocommerce' => true,
'woocommerce_log_level' => \WC_Log_Levels::ERROR,
)
);
return '';
}
if ( empty( $feed_nodes ) ) {
return '';
}
$fb_language_code = \WooCommerce\Facebook\Locale::convert_to_facebook_language_code( $language_code );
$expected_feed_name = sprintf( 'WooCommerce Language Override Feed (%s)', strtoupper( $fb_language_code ) );
foreach ( $feed_nodes as $feed ) {
try {
$feed_metadata = $this->get_api()->read_feed( $feed['id'] );
} catch ( \Exception $e ) {
$message = sprintf( 'There was an error trying to get feed metadata: %s', $e->getMessage() );
Logger::log(
$message,
[],
array(
'should_send_log_to_meta' => false,
'should_save_log_in_woocommerce' => true,
'woocommerce_log_level' => \WC_Log_Levels::ERROR,
)
);
continue;
}
if ( $expected_feed_name === $feed_metadata['name'] ) {
return $feed['id'];
}
}
return '';
}
/**
* Creates a new language override feed on Facebook.
*
* @param string $language_code Language code
* @throws \Exception If feed creation fails.
* @return string Feed ID
* @since 3.6.0
*/
private function create_language_feed_id( string $language_code ): string {
try {
$catalog_id = facebook_for_woocommerce()->get_integration()->get_product_catalog_id();
if ( '' === $catalog_id ) {
throw new \Exception( 'No catalog ID' );
}
$fb_language_code = \WooCommerce\Facebook\Locale::convert_to_facebook_language_code( $language_code );
$override_value = \WooCommerce\Facebook\Locale::convert_to_facebook_override_value( $fb_language_code );
$feed_data = [
'name' => self::generate_language_feed_name( $language_code ),
'file_name' => self::generate_language_feed_filename( $language_code, true ), // For Facebook API
'override_type' => 'language',
'override_value' => $override_value,
];
$response = $this->get_api()->create_feed( $catalog_id, $feed_data );
if ( $response && isset( $response['id'] ) ) {
return $response['id'];
}
} catch ( \Exception $exception ) {
Logger::log(
'Could not create language override feed: ' . $exception->getMessage(),
array(
'language_code' => $language_code,
),
array(
'should_send_log_to_meta' => false,
'should_save_log_in_woocommerce' => true,
'woocommerce_log_level' => \WC_Log_Levels::ERROR,
)
);
}
return '';
}
/**
* Get the feed secret.
* Uses the same secret as the main product feed for consistency.
*
* @return string
* @since 3.6.0
*/
protected function get_feed_secret(): string {
return \WooCommerce\Facebook\Products\Feed::get_feed_secret();
}
/**
* Generate a consistent file name for language override feeds.
* This provides a single source of truth for file naming across all language feed operations.
* Uses the feed secret hash (like the main product feed) to ensure the same filename is reused.
*
* @param string $language_code Language code (e.g., 'es_ES', 'fr_FR')
* @param bool $for_facebook_api Whether this file name is for Facebook API feed creation
* @param bool $is_temp_file Whether this is for a temporary file
* @return string File name
* @since 3.6.0
*/
public static function generate_language_feed_filename( string $language_code, bool $for_facebook_api = false, bool $is_temp_file = false ): string {
$fb_language_code = \WooCommerce\Facebook\Locale::convert_to_facebook_language_code( $language_code );
$feed_secret = \WooCommerce\Facebook\Products\Feed::get_feed_secret();
// Use the same filename generation logic for both local and Facebook API
// This matches the main product feed behavior which reuses the same file
$prefix = $is_temp_file ? 'temp_' : '';
$hash_suffix = wp_hash( $feed_secret );
return "facebook_language_feed_{$prefix}{$fb_language_code}_{$hash_suffix}.csv";
}
/**
* Generate a consistent feed name for Facebook API feed creation.
* This provides a single source of truth for feed names in Facebook's catalog.
*
* @param string $language_code Language code (e.g., 'es_ES', 'fr_FR')
* @return string Feed name for Facebook API
* @since 3.6.0
*/
public static function generate_language_feed_name( string $language_code ): string {
$fb_language_code = \WooCommerce\Facebook\Locale::convert_to_facebook_language_code( $language_code );
return sprintf( 'WooCommerce Language Override Feed (%s)', strtoupper( $fb_language_code ) );
}
}