add_filters(); } else { add_action( 'pll_language_defined', array( $this, 'add_filters' ), 1 ); } // The language is not defined yet in REST. if ( Polylang::is_rest_request() ) { add_filter( 'locale', array( $this, 'get_locale' ) ); } } /** * Setups actions filters once the language is defined. * * @since 1.9.5 * * @return void */ public function add_filters() { add_action( 'wp_footer', array( $this, 'filter_dynamic_blocks' ), 0 ); // Use `render_block_data` to translate only attribute ids rather than content (which contains content such as post titles and links). add_filter( 'render_block_data', array( $this, 'filter_reviews_by_product_block_id' ) ); // Fix assets URLs when using one domain per language. if ( PLL()->options['force_lang'] > 1 ) { add_filter( 'transient_woocommerce_blocks_asset_api_script_data', array( $this, 'blocks_assets_links' ) ); add_filter( 'transient_woocommerce_blocks_asset_api_script_data_ssl', array( $this, 'blocks_assets_links' ) ); } } /** * Adds a script to allow filtering blocks relying on the WC REST API. * * @since 1.3 * * @return void */ public function filter_dynamic_blocks() { // Backward compatibility with WC < 6.4. $path = '/wc/store/products'; // Since WC 6.4. if ( version_compare( WC()->version, '6.4', '>=' ) ) { $path = '/wc/store/v1'; } $script = $this->get_filter_script( $path ); // Since WC 5.6. wp_add_inline_script( 'wc-reviews-block-frontend', $script, 'before' ); wp_add_inline_script( 'wc-all-products-block-frontend', $script, 'before' ); // Since WC 6.9. wp_add_inline_script( 'wc-checkout-block-frontend', $script, 'before' ); // Backward compatibility with WC < 7.1. wp_add_inline_script( 'wc-attribute-filter-block-frontend', $script, 'before' ); // Since WC 7.1. wp_add_inline_script( 'wc-filter-wrapper-block-frontend', $script, 'before' ); /** * WooCommerce `wc-cart-checkout-base` script which send REST requests to apply or remove coupon * is loaded before `wp-api-fetch` we're using to register our script to filter by language. * So we need to check `wc-cart-checkout-base` is enqueued to add our script after `wp-api-fetch` * only in this case. */ if ( wp_script_is( 'wc-cart-checkout-base' ) ) { wp_add_inline_script( 'wp-api-fetch', $script, 'after' ); } } /** * Get a script to allow filtering blocks relying on the WC REST API. * * @since 1.5.3 * * @param string $path The REST API path to filter. * @return string Inline js script to add. */ protected function get_filter_script( $path ) { /** @var string $current_language This cannot be false because the language is defined at this point */ $current_language = pll_current_language(); $path = esc_js( $path ); $lang = esc_js( $current_language ); return "wp.apiFetch.use( function( options, next ) { if ( 'undefined' !== options.path && options.path.indexOf( '{$path}' ) >= 0 ) { options.path = wp.url.addQueryArgs( options.path, { lang: '{$lang}' } ); } return next( options ); } );"; } /** * Translates the product ID for the widget block reviews by product. * * @since 1.9 * * @param array $parsed_block The block being rendered. * @return array */ public function filter_reviews_by_product_block_id( $parsed_block ) { if ( 'woocommerce/reviews-by-product' !== $parsed_block['blockName'] ) { return $parsed_block; } if ( empty( PLL()->curlang ) || empty( $parsed_block['attrs']['productId'] ) ) { return $parsed_block; } /** @var PLLWC_Product_Language_CPT */ $data_store = PLLWC_Data_Store::load( 'product_language' ); $product_language = $data_store->get_language( $parsed_block['attrs']['productId'] ); if ( PLL()->curlang->slug === $product_language ) { return $parsed_block; } $translated_product_id = $data_store->get( $parsed_block['attrs']['productId'] ); if ( ! $translated_product_id ) { return $parsed_block; } $parsed_block['attrs']['productId'] = $translated_product_id; return $parsed_block; } /** * Filters the locale when an account is created during checkout (REST request). * * @since 1.9.5 * * @param string $locale The locale ID. * @return string */ public function get_locale( $locale ) { $requested_url = pll_get_requested_url(); if ( ! is_string( $requested_url ) || ! strpos( $requested_url, '/wc/store/v1' ) ) { return $locale; } if ( empty( $_GET['lang'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification return $locale; } $lang = PLL()->model->get_language( sanitize_key( $_GET['lang'] ) ); // phpcs:ignore WordPress.Security.NonceVerification if ( empty( $lang ) ) { return $locale; } return $lang->locale; } /** * Replaces blocks assets URLs in WooCommerce transient depending on the current language * when using one domain per language. * * @since 2.1 * * @param string|false $value Current value of the WooCommerce transient (JSON encoded). * @return string|false WooCommerce transient with blocks assets URLs modified with the current language. */ public function blocks_assets_links( $value ) { $transient_value = (array) json_decode( (string) $value, true ); if ( json_last_error() !== JSON_ERROR_NONE || empty( $transient_value['script_data'] ) || ! is_array( $transient_value['script_data'] ) ) { return $value; } foreach ( $transient_value['script_data'] as $key => $script_data ) { if ( empty( $script_data['src'] ) ) { continue; } /** @var PLL_Language $language */ $language = PLL()->curlang; $transient_value['script_data'][ $key ]['src'] = PLL()->links_model->switch_language_in_link( $script_data['src'], $language ); } return wp_json_encode( $transient_value ); } }