original ) && isset( $translation->element_id ) ) { return (int) $translation->element_id; } } } return 0; } /** Language of the page, empty without a translation plugin that has languages. */ public static function current_language(): string { if ( function_exists( 'pll_current_language' ) ) { return (string) pll_current_language(); } if ( has_filter( 'wpml_current_language' ) ) { return (string) apply_filters( 'wpml_current_language', null ); } return ''; } /** * Runs a query in every language: Polylang reads 'lang' => '' in the query itself, WPML needs its language switched * to "all" for the time of the query. * * @param callable $query Function that runs the query. * @return mixed What the function returns. */ public static function all_languages( callable $query ) { $wpml = has_action( 'wpml_switch_language' ) && has_filter( 'wpml_current_language' ); $current = $wpml ? apply_filters( 'wpml_current_language', null ) : null; if ( $wpml ) { do_action( 'wpml_switch_language', 'all' ); } try { return $query(); } finally { if ( $wpml ) { // WPML 5 keeps its switches on a stack, closed by null; earlier versions put back the language given. do_action( 'wpml_switch_language', defined( 'ICL_SITEPRESS_VERSION' ) && version_compare( ICL_SITEPRESS_VERSION, '5', '<' ) ? $current : null ); } } } /** * Ids of a post and of all its translations. * * @param int $id Post id. * @param string $post_type Post type. * @return int[] */ public static function translation_ids( int $id, string $post_type ): array { $ids = array( $id ); if ( function_exists( 'pll_get_post_translations' ) ) { $ids = array_merge( $ids, array_values( (array) pll_get_post_translations( $id ) ) ); } elseif ( has_filter( 'wpml_element_trid' ) ) { $type = 'post_' . $post_type; $trid = apply_filters( 'wpml_element_trid', null, $id, $type ); // All statuses: for visitors, WPML leaves out the translations of post types that are not public (shared tabs). foreach ( (array) apply_filters( 'wpml_get_element_translations', null, $trid, $type, false, true ) as $translation ) { if ( isset( $translation->element_id ) ) { $ids[] = (int) $translation->element_id; } } } return array_values( array_unique( array_map( 'intval', $ids ) ) ); } /** * Product a translation follows: the original with WPML, the translation in the default language with Polylang. * * @param int $product_id Product id. * @return int 0 when the product is itself the source, or without translation plugin. */ public static function source_product( int $product_id ): int { if ( function_exists( 'pll_get_post_language' ) ) { $default = (string) pll_default_language(); if ( '' === $default || pll_get_post_language( $product_id ) === $default ) { return 0; } return (int) pll_get_post( $product_id, $default ); } $source_lang = self::wpml_source_language( $product_id ); return '' !== $source_lang ? (int) apply_filters( 'wpml_object_id', $product_id, 'product', false, $source_lang ) : 0; } /** * Whether the structure of a product's tabs comes from another product and cannot be changed on this one: a WPML * translation copies it from its original. With Polylang the structure is shared and can be changed in any language. * * @param int $product_id Product id. */ public static function structure_locked( int $product_id ): bool { return ! function_exists( 'pll_get_post_language' ) && '' !== self::wpml_source_language( $product_id ); } /** * Language a WPML translation was translated from. * * @param int $product_id Product id. * @return string Empty for an original or without WPML. */ private static function wpml_source_language( int $product_id ): string { if ( ! has_filter( 'wpml_element_language_details' ) ) { return ''; } $details = apply_filters( 'wpml_element_language_details', null, array( 'element_id' => $product_id, 'element_type' => 'post_product', ) ); return is_object( $details ) && ! empty( $details->source_language_code ) ? (string) $details->source_language_code : ''; } /** * Languages of the site. * * @return string[] Language codes, empty without WPML or Polylang. */ public static function languages(): array { if ( function_exists( 'pll_languages_list' ) ) { return array_map( 'strval', (array) pll_languages_list() ); } if ( has_filter( 'wpml_active_languages' ) ) { return array_map( 'strval', array_keys( (array) apply_filters( 'wpml_active_languages', null, array( 'skip_missing' => 0 ) ) ) ); } return array(); } /** Default language of the site, empty without a translation plugin that has languages. */ public static function default_language(): string { if ( function_exists( 'pll_default_language' ) ) { return (string) pll_default_language(); } if ( has_filter( 'wpml_default_language' ) ) { return (string) apply_filters( 'wpml_default_language', null ); } return ''; } /** * Language of a post. * * @param int $post_id Post id. * @return string Language code, empty when unknown. */ public static function post_language( int $post_id ): string { if ( function_exists( 'pll_get_post_language' ) ) { return (string) pll_get_post_language( $post_id ); } if ( has_filter( 'wpml_post_language_details' ) ) { $details = apply_filters( 'wpml_post_language_details', null, $post_id ); return is_array( $details ) && ! empty( $details['language_code'] ) ? (string) $details['language_code'] : ''; } return ''; } /** * Sets the language of a post. * * @param int $post_id Post id. * @param string $post_type Post type. * @param string $lang Language code. */ public static function set_language( int $post_id, string $post_type, string $lang ): void { if ( '' === $lang ) { return; } if ( function_exists( 'pll_set_post_language' ) ) { pll_set_post_language( $post_id, $lang ); return; } if ( has_action( 'wpml_set_element_language_details' ) ) { do_action( 'wpml_set_element_language_details', array( 'element_id' => $post_id, 'element_type' => 'post_' . $post_type, 'trid' => false, 'language_code' => $lang, ) ); } } /** * Links posts as translations of one another. * * @param int[] $by_lang Post id by language code; the first one is the original. * @param string $post_type Post type. */ public static function link_translations( array $by_lang, string $post_type ): void { if ( count( $by_lang ) < 2 ) { return; } if ( function_exists( 'pll_save_post_translations' ) ) { // Translations already linked are kept: saving a group replaces it, and would unlink the others. $merged = array(); foreach ( $by_lang as $post_id ) { $merged += array_map( 'intval', (array) pll_get_post_translations( (int) $post_id ) ); } foreach ( $by_lang as $lang => $post_id ) { if ( ! isset( $merged[ $lang ] ) ) { $merged[ $lang ] = (int) $post_id; } } pll_save_post_translations( $merged ); return; } if ( ! has_filter( 'wpml_element_trid' ) ) { return; } $element_type = 'post_' . $post_type; $source_lang = (string) array_key_first( $by_lang ); $trid = apply_filters( 'wpml_element_trid', null, (int) reset( $by_lang ), $element_type ); foreach ( $by_lang as $lang => $post_id ) { if ( (string) $lang === $source_lang ) { continue; } // A post already in another translation group is not moved. $own = apply_filters( 'wpml_element_trid', null, (int) $post_id, $element_type ); if ( $own && $own !== $trid && count( (array) apply_filters( 'wpml_get_element_translations', null, $own, $element_type, false, true ) ) > 1 ) { continue; } do_action( 'wpml_set_element_language_details', array( 'element_id' => (int) $post_id, 'element_type' => $element_type, 'trid' => $trid, 'language_code' => (string) $lang, 'source_language_code' => $source_lang, ) ); } } }