targets_translated_types( $args ) ) { return $args; } // Flag the query; the condition itself is added in filter_posts_where() // so it can be scoped to translated post types. $args['duolangue_restrict_lang'] = $lang; return $args; } /** * Skip fields that query no translated post type at all (e.g. a picker * limited to an untranslated CPT) — nothing to constrain there. */ private function targets_translated_types( $args ) { if ( empty( $args['post_type'] ) || 'any' === $args['post_type'] ) { return true; // Every public type: ours are in there. } return (bool) array_intersect( (array) $args['post_type'], duolangue_post_types() ); } /** * Restrict translated post types to one language, leaving every other * post type untouched. * * Duolangue works with a language pair, which keeps the condition * simple: "in the default language" is the exact * complement of "tagged as the secondary language", so a single NOT IN * subquery also covers content with no language meta at all. * * @param string $where SQL WHERE clause. * @param WP_Query $query Query being built. * @return string */ public function filter_posts_where( $where, $query ) { $lang = $query->get( 'duolangue_restrict_lang' ); if ( ! $lang || ! duolangue_get_language( $lang ) ) { return $where; } global $wpdb; $types = duolangue_post_types(); if ( ! $types ) { return $where; } $secondary = duolangue_secondary_lang()['code']; // Posts explicitly tagged with the secondary language: shown only when // browsing the secondary language (IN), hidden otherwise (NOT IN). if ( $lang === $secondary ) { $where .= $wpdb->prepare( " AND ( {$wpdb->posts}.post_type NOT IN ( " . implode( ', ', array_fill( 0, count( $types ), '%s' ) ) . ' )' . " OR {$wpdb->posts}.ID IN ( SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = '_duolangue_lang' AND meta_value = %s ) )", array_merge( $types, array( $secondary ) ) ); } else { $where .= $wpdb->prepare( " AND ( {$wpdb->posts}.post_type NOT IN ( " . implode( ', ', array_fill( 0, count( $types ), '%s' ) ) . ' )' . " OR {$wpdb->posts}.ID NOT IN ( SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = '_duolangue_lang' AND meta_value = %s ) )", array_merge( $types, array( $secondary ) ) ); } return $where; } /* ------------------------------------------------------------------ * Language resolution * ---------------------------------------------------------------- */ /** * Language of the object the field belongs to. * * @param int|string $post_id ACF container id ("123", "options", "options_fr"…). * @return string Language code. */ public static function editing_lang( $post_id ) { $codes = wp_list_pluck( duolangue_get_languages(), 'code' ); $default = duolangue_default_lang()['code']; // 1. A real post: its own language. if ( is_numeric( $post_id ) ) { return duolangue_get_post_lang( (int) $post_id ); } if ( is_string( $post_id ) && $post_id ) { // 2. A per-language options store ("options_fr"): the language // suffix is authoritative. foreach ( $codes as $code ) { if ( substr( $post_id, - ( strlen( $code ) + 1 ) ) === '_' . $code ) { return $code; } } } // 3. Options screens: the active language tab. On AJAX (the picker's // own search requests) the screen URL is only in the referer. $tab = self::request_lang_tab(); if ( $tab ) { return $tab; } return $default; } /** * The duolangue_lang tab from the current request or its referer. * * @return string Language code, or '' when absent/unknown. */ private static function request_lang_tab() { $arg = 'duolangue_lang'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only language hint. if ( ! empty( $_REQUEST[ $arg ] ) && is_string( $_REQUEST[ $arg ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $lang = sanitize_key( wp_unslash( $_REQUEST[ $arg ] ) ); if ( duolangue_get_language( $lang ) ) { return $lang; } } $referer = wp_get_referer(); if ( $referer ) { $query = (string) wp_parse_url( $referer, PHP_URL_QUERY ); if ( $query ) { $vars = array(); wp_parse_str( $query, $vars ); if ( ! empty( $vars[ $arg ] ) ) { $lang = sanitize_key( $vars[ $arg ] ); if ( duolangue_get_language( $lang ) ) { return $lang; } } } } return ''; } }