syncing || 'product' !== get_post_type( $postId ) ) { return; } // Always sync from the original (source of truth), regardless of which language triggered the save. $originalId = apply_filters( 'wpml_original_element_id', null, $postId, 'post_product' ); if ( ! $originalId ) { $originalId = $postId; } $metaKeys = $this->getDynamicPricingMetaKeys( (int) $originalId ); if ( empty( $metaKeys ) ) { return; } // sync_to_translations() writes meta on the translations; guard against re-entering this handler. $this->syncing = true; foreach ( $metaKeys as $metaKey ) { // WPML resolves the translations of $originalId and copies the value to each of them. do_action( 'wpml_sync_custom_field', (int) $originalId, $metaKey ); } $this->syncing = false; } /** * Append the source product's dynamic pricing keys to Polylang's list of meta to copy. * * @param string[] $keys Meta keys Polylang will copy to the translation. * @param bool $sync Whether this is an ongoing sync (vs. an initial copy). * @param int $from Source (original) post ID. * @param int $to Target (translation) post ID. * * @return string[] */ public function addPolylangCopyKeys( $keys, $sync, $from, $to ) { if ( ! $from || 'product' !== get_post_type( $from ) ) { return $keys; } return array_values( array_unique( array_merge( (array) $keys, $this->getDynamicPricingMetaKeys( (int) $from ) ) ) ); } /** * All role-based / user-based tiered pricing meta keys actually present on a product. * * @param int $productId * * @return string[] */ protected function getDynamicPricingMetaKeys( int $productId ): array { $allKeys = array_keys( get_post_meta( $productId ) ); // _{role}_ (role may contain underscores, e.g. shop_manager) or _user_{id}_. $pattern = '/^_(?:user_\d+|[a-z0-9\-]+(?:_[a-z0-9\-]+)*)_(?:' . implode( '|', self::DYNAMIC_KEY_SUFFIXES ) . ')$/'; return array_values( array_filter( $allKeys, function ( $key ) use ( $pattern ) { return (bool) preg_match( $pattern, $key ); } ) ); } public function getTitle(): string { return 'WPML / Polylang Multilingual'; } public function getIconURL(): string { return $this->getContainer()->getFileManager()->locateAsset( 'admin/integrations/wpml-multicurrency-icon.png' ); } public function getAuthorURL(): string { return 'https://wpml.org/documentation/related-projects/woocommerce-multilingual/'; } public function getDescription(): string { return __( 'Copy role-based and user-based tiered pricing to product translations when using WPML or Polylang.', 'tier-pricing-table' ); } public function getSlug(): string { return 'wpml-multilingual'; } public function getIntegrationCategory(): string { return 'other'; } }