PluginProbe
Polylang / 2.3.6
Polylang v2.3.6
3.8.9 3.8.8 3.8.7 3.8.6 3.8.5 3.8.4 3.8.3 2.7 2.7.0.1 2.7.1 2.7.2 2.7.3 2.7.4 2.8 2.8.1 2.8.2 2.8.3 2.8.4 2.9 2.9.1 2.9.2 3.0 3.0.1 3.0.2 3.0.3 All 233 releases
polylang / frontend / frontend-auto-translate.php

frontend-auto-translate.php in Polylang 2.3.6, at frontend/frontend-auto-translate.php

286 lines 8.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Auto translates the posts and terms ids
5 * Useful for example for themes querying a specific cat
6 *
7 * @since 1.1
8 */
9 class PLL_Frontend_Auto_Translate {
10 public $model, $curlang;
11
12 /**
13 * Constructor
14 *
15 * @since 1.1
16 *
17 * @param object $polylang
18 */
19 public function __construct( &$polylang ) {
20 $this->model = &$polylang->model;
21 $this->curlang = &$polylang->curlang;
22
23 add_action( 'pre_get_posts', array( $this, 'pre_get_posts' ) ); // after main Polylang filter
24 add_filter( 'get_terms_args', array( $this, 'get_terms_args' ), 20, 2 );
25 }
26
27 /**
28 * Helper function to get the translated post in the current language
29 *
30 * @since 1.8
31 *
32 * @param int $post_id
33 * @return int
34 */
35 protected function get_post( $post_id ) {
36 return $this->model->post->get( $post_id, $this->curlang );
37 }
38
39 /**
40 * Helper function to get the translated term in the current language
41 *
42 * @since 1.8
43 *
44 * @param int $term_id
45 * @return int
46 */
47 protected function get_term( $term_id ) {
48 return $this->model->term->get( $term_id, $this->curlang );
49 }
50
51 /**
52 * Filters posts query to automatically translate included ids
53 *
54 * @since 1.1
55 *
56 * @param object $query WP_Query object
57 */
58 public function pre_get_posts( $query ) {
59 global $wpdb;
60 $qv = &$query->query_vars;
61
62 if ( $query->is_main_query() || isset( $qv['lang'] ) || ( ! empty( $qv['post_type'] ) && ! $this->model->is_translated_post_type( $qv['post_type'] ) ) ) {
63 return;
64 }
65
66 // /!\ always keep untranslated as is
67
68 // Term ids separated by a comma
69 $arr = array();
70 if ( ! empty( $qv['cat'] ) ) {
71 foreach ( explode( ',', $qv['cat'] ) as $cat ) {
72 $tr = $this->get_term( abs( $cat ) );
73 $arr[] = $cat < 0 ? -$tr : $tr;
74 }
75
76 $qv['cat'] = implode( ',', $arr );
77 }
78
79 // Category_name
80 $arr = array();
81 if ( ! empty( $qv['category_name'] ) ) {
82 foreach ( explode( ',', $qv['category_name'] ) as $slug ) {
83 $arr[] = $this->get_translated_term_by( 'slug', $slug, 'category' );
84 }
85
86 $qv['category_name'] = implode( ',', $arr );
87 }
88
89 // Array of term ids
90 foreach ( array( 'category__and', 'category__in', 'category__not_in', 'tag__and', 'tag__in', 'tag__not_in' ) as $key ) {
91 $arr = array();
92 if ( ! empty( $qv[ $key ] ) ) {
93 foreach ( $qv[ $key ] as $cat ) {
94 $arr[] = ( $tr = $this->get_term( $cat ) ) ? $tr : $cat;
95 }
96 $qv[ $key ] = $arr;
97 }
98 }
99
100 // Tag
101 $arr = array();
102 if ( ! empty( $qv['tag'] ) ) {
103 $sep = strpos( $qv['tag'], ',' ) !== false ? ',' : '+'; // Two possible separators for tag slugs
104 foreach ( explode( $sep, $qv['tag'] ) as $slug ) {
105 $arr[] = $this->get_translated_term_by( 'slug', $slug, 'post_tag' );
106 }
107
108 $qv['tag'] = implode( $sep, $arr );
109 }
110
111 // tag_id can only take one id
112 if ( ! empty( $qv['tag_id'] ) && $tr_id = $this->get_term( $qv['tag_id'] ) ) {
113 $qv['tag_id'] = $tr_id;
114 }
115
116 // Array of tag slugs
117 foreach ( array( 'tag_slug__and', 'tag_slug__in' ) as $key ) {
118 $arr = array();
119 if ( ! empty( $qv[ $key ] ) ) {
120 foreach ( $qv[ $key ] as $slug ) {
121 $arr[] = $this->get_translated_term_by( 'slug', $slug, 'post_tag' );
122 }
123
124 $qv[ $key ] = $arr;
125 }
126 }
127
128 // Custom taxonomies
129 // According to the codex, this type of query is deprecated as of WP 3.1 but it does not appear in WP 3.5 source code
130 foreach ( array_intersect( $this->model->get_translated_taxonomies(), get_taxonomies( array( '_builtin' => false ) ) ) as $taxonomy ) {
131 $tax = get_taxonomy( $taxonomy );
132 $arr = array();
133 if ( ! empty( $qv[ $tax->query_var ] ) ) {
134 $sep = strpos( $qv[ $tax->query_var ], ',' ) !== false ? ',' : '+'; // Two possible separators
135 foreach ( explode( $sep, $qv[ $tax->query_var ] ) as $slug ) {
136 $arr[] = $this->get_translated_term_by( 'slug', $slug, $taxonomy );
137 }
138
139 $qv[ $tax->query_var ] = implode( $sep, $arr );
140 }
141 }
142
143 // Tax_query since WP 3.1
144 if ( ! empty( $qv['tax_query'] ) && is_array( $qv['tax_query'] ) ) {
145 $qv['tax_query'] = $this->translate_tax_query_recursive( $qv['tax_query'] );
146 }
147
148 // p, page_id, post_parent can only take one id
149 foreach ( array( 'p', 'page_id', 'post_parent' ) as $key ) {
150 if ( ! empty( $qv[ $key ] ) && $tr_id = $this->get_post( $qv[ $key ] ) ) {
151 $qv[ $key ] = $tr_id;
152 }
153 }
154
155 // name, can only take one slug
156 if ( ! empty( $qv['name'] ) ) {
157 if ( empty( $qv['post_type'] ) ) {
158 $post_types = array( 'post' );
159 } elseif ( 'any' === $qv['post_type'] ) {
160 $post_types = get_post_types( array( 'exclude_from_search' => false ) ); // May return a empty array
161 } else {
162 $post_types = (array) $qv['post_type'];
163 }
164
165 if ( ! empty( $post_types ) ) {
166 // No function to get post by name except get_posts itself
167 $id = $wpdb->get_var( sprintf( "
168 SELECT ID from {$wpdb->posts}
169 WHERE {$wpdb->posts}.post_type IN ( '%s' )
170 AND post_name='%s'",
171 implode( "', '", esc_sql( $post_types ) ),
172 esc_sql( $qv['name'] )
173 ) );
174 $qv['name'] = ( $id && ( $tr_id = $this->get_post( $id ) ) && $tr = get_post( $tr_id ) ) ? $tr->post_name : $qv['name'];
175 }
176 }
177
178 // pagename, the page id is already available in queried_object_id
179 if ( ! empty( $qv['pagename'] ) && ! empty( $query->queried_object_id ) && $tr_id = $this->get_post( $query->queried_object_id ) ) {
180 $query->queried_object_id = $tr_id;
181 $qv['pagename'] = get_page_uri( $tr_id );
182 }
183
184 // Array of post ids
185 // post_parent__in & post_parent__not_in since WP 3.6
186 foreach ( array( 'post__in', 'post__not_in', 'post_parent__in', 'post_parent__not_in' ) as $key ) {
187 $arr = array();
188 if ( ! empty( $qv[ $key ] ) ) {
189 // post__in used by the 2 functions below
190 // Useless to filter them as output is already in the right language and would result in performance loss
191 foreach ( debug_backtrace() as $trace ) {
192 if ( in_array( $trace['function'], array( 'wp_nav_menu', 'gallery_shortcode' ) ) ) {
193 return;
194 }
195 }
196
197 foreach ( $qv[ $key ] as $p ) {
198 $arr[] = ( $tr = $this->get_post( $p ) ) ? $tr : $p;
199 }
200
201 $qv[ $key ] = $arr;
202 }
203 }
204 }
205
206 /**
207 * Filters terms query to automatically translate included ids
208 *
209 * @since 1.1.1
210 *
211 * @param array $args
212 * @param array $taxonomies
213 * @return array modified $args
214 */
215 public function get_terms_args( $args, $taxonomies ) {
216 if ( ! isset( $args['lang'] ) && ! empty( $args['include'] ) && ( empty( $taxonomies ) || $this->model->is_translated_taxonomy( $taxonomies ) ) ) {
217 foreach ( wp_parse_id_list( $args['include'] ) as $id ) {
218 $arr[] = ( $tr = $this->get_term( $id ) ) ? $tr : $id;
219 }
220
221 $args['include'] = $arr;
222 }
223 return $args;
224 }
225
226 /**
227 * Translates tax queries
228 * Compatible with nested tax queries introduced in WP 4.1
229 *
230 * @since 1.7
231 *
232 * @param array $tax_queries
233 * @return array translated tax queries
234 */
235 protected function translate_tax_query_recursive( $tax_queries ) {
236 foreach ( $tax_queries as $key => $q ) {
237 if ( isset( $q['taxonomy'], $q['terms'] ) && $this->model->is_translated_taxonomy( $q['taxonomy'] ) ) {
238 $arr = array();
239 $field = isset( $q['field'] ) && in_array( $q['field'], array( 'slug', 'name' ) ) ? $q['field'] : 'term_id';
240 foreach ( (array) $q['terms'] as $t ) {
241 $arr[] = $this->get_translated_term_by( $field, $t, $q['taxonomy'] );
242 }
243
244 $tax_queries[ $key ]['terms'] = $arr;
245 }
246
247 // Nested queries
248 elseif ( is_array( $q ) ) {
249 $tax_queries[ $key ] = $this->translate_tax_query_recursive( $q );
250 }
251 }
252
253 return $tax_queries;
254 }
255
256 /**
257 * Translates a term given one field.
258 *
259 * @since 2.3.3
260 *
261 * @param string $field Either 'slug', 'name', 'term_id', or 'term_taxonomy_id'
262 * @param string|int $term Search for this term value
263 * @param string $taxonomy Taxonomy name.
264 * @return string|int Translated term slug, name, term_id or term_taxonomy_id
265 */
266 protected function get_translated_term_by( $field, $term, $taxonomy ) {
267 if ( 'term_id' === $field ) {
268 if ( $tr_id = $this->get_term( $term ) ) {
269 return $tr_id;
270 }
271 } else {
272 $terms = get_terms( $taxonomy, array( $field => $term, 'lang' => '' ) );
273
274 if ( ! empty( $terms ) && ! is_wp_error( $terms ) ) {
275 $t = reset( $terms );
276 $tr_id = $this->get_term( $t->term_id );
277
278 if ( ! is_wp_error( $tr = get_term( $tr_id, $taxonomy ) ) ) {
279 return $tr->$field;
280 }
281 }
282 }
283 return $term;
284 }
285 }
286