PluginProbe
Polylang / 1.2.2
Polylang v1.2.2
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 / include / model.php

model.php in Polylang 1.2.2, at include/model.php

696 lines 23.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /*
4 * setups the language and translations model based on WordPress taxonomies
5 *
6 * @since 1.2
7 */
8 class PLL_Model {
9 public $options;
10 public $post_types = array(), $taxonomies = array(); // post types & taxonomies to filter by language
11 private $languages; // used to cache the list of languages
12
13 /*
14 * constructor: registers custom taxonomies and setups filters and actions
15 *
16 * @since 1.2
17 *
18 * @param array $options Polylang options
19 */
20 public function __construct(&$options) {
21 $this->options = &$options;
22
23 // register our taxonomies as soon as possible
24 // this is early registration, not ready for rewrite rules as wp_rewrite will be setup later
25 // FIXME should I supply an 'update_count_callback' for taxonomies other than 'language' (currently not needed by PLL)?
26 foreach (array('language', 'term_language', 'post_translations', 'term_translations') as $tax)
27 register_taxonomy($tax,
28 false !== strpos($tax, 'term_') ? 'term' : null ,
29 array('label' => false, 'public' => false, 'query_var' => false, 'rewrite' => false, '_pll' => true)
30 );
31
32 add_filter('get_terms', array(&$this, '_prime_terms_cache'), 10, 2);
33 add_filter('wp_get_object_terms', array(&$this, 'wp_get_object_terms'), 10, 3);
34
35 add_action('edited_term_taxonomy', array(&$this, 'clean_languages_cache'), 10, 2);
36
37 // registers completely the language taxonomy
38 add_action('setup_theme', array(&$this, 'register_taxonomy'), 1);
39
40 // setups post types and taxonomies to translate
41 add_action('registered_post_type', array(&$this, 'registered_post_type'));
42 add_action('registered_taxonomy', array(&$this, 'registered_taxonomy'));
43
44 // just in case someone would like to display the language description ;-)
45 add_filter('language_description', create_function('$v', "return '';"));
46 }
47
48 /*
49 * cache language and translations when terms are queried by get_terms
50 *
51 * @since 1.2
52 *
53 * @param array $terms queried terms
54 * @param array $taxonomies queried taxonomies
55 * @return array unmodified $terms
56 */
57 public function _prime_terms_cache($terms, $taxonomies) {
58 foreach ($terms as $term) {
59 if (is_object($term)) {
60 if (in_array($term->taxonomy, $this->taxonomies))
61 $term_ids[] = $term->term_id;
62 }
63 elseif (array_intersect($taxonomies, $this->taxonomies))
64 $term_ids[] = $term;
65 }
66
67 if (!empty($term_ids))
68 update_object_term_cache(array_unique($term_ids), 'term'); // adds language and translation of terms to cache
69 return $terms;
70 }
71
72 /*
73 * when terms are found for posts, add their language and translations to cache
74 *
75 * @since 1.2
76 *
77 * @param array $terms terms found
78 * @param array $object_ids not used
79 * @param array $taxonomies terms taxonomies
80 * @return array unmodified $terms
81 */
82 public function wp_get_object_terms($terms, $object_ids, $taxonomies) {
83 $taxonomies = explode("', '", trim($taxonomies, "'"));
84 if (!in_array('term_translations', $taxonomies))
85 $this->_prime_terms_cache($terms, $taxonomies);
86 return $terms;
87 }
88
89 /*
90 * wrap wp_get_object_terms to cache it and return only one object
91 * inspired by the function get_the_terms
92 *
93 * @since 1.2
94 *
95 * @param int $object_id post_id or term_id
96 * @param string $taxonomy Polylang taxonomy depending if we are looking for a post (or term) language (or translation)
97 * @return bool|object the term associated to the object in the requested taxonomy if exists, false otherwise
98 */
99 protected function get_object_term($object_id, $taxonomy) {
100 $term = get_object_term_cache($object_id, $taxonomy);
101
102 if ( false === $term ) {
103 // query language and translations at the same time
104 $taxonomies = (false !== strpos($taxonomy, 'term_')) ?
105 array('term_language', 'term_translations') :
106 array('language', 'post_translations');
107
108 foreach (wp_get_object_terms($object_id, $taxonomies) as $t) {
109 wp_cache_add($object_id, array($t), $t->taxonomy . '_relationships'); // store it the way WP wants it
110 if ($t->taxonomy == $taxonomy)
111 $term = $t;
112 }
113 }
114 else
115 $term = reset($term);
116
117 return empty($term) ? false : $term;
118 }
119
120 /*
121 * returns the list of available languages
122 * caches the list in a db transient (except flags)
123 * caches the list (with flags) in the private property $languages
124 *
125 * list of parameters accepted in $args:
126 *
127 * hide_empty => hides languages with no posts if set to true (defaults to false)
128 * fields => return only that field if set (see PLL_Language for a list of fields)
129 *
130 * @since 0.1
131 *
132 * @param array $args
133 * @return array|string|int list of PLL_Language objects or PLL_Language object properties
134 */
135 public function get_languages_list($args = array()) {
136 if (empty($this->languages)) {
137 if (false === ($languages = get_transient('pll_languages_list'))) {
138 $languages = get_terms('language', array('hide_empty' => false, 'orderby'=> 'term_group'));
139 $languages = empty($languages) || is_wp_error($languages) ? array() : $languages;
140
141 $term_languages = get_terms('term_language', array('hide_empty' => false));
142 $term_languages = empty($term_languages) || is_wp_error($term_languages) ?
143 array() : array_combine(wp_list_pluck($term_languages, 'name'), $term_languages);
144
145 if (!empty($languages) && !empty($term_languages)) {
146 array_walk($languages, create_function('&$v, $k, $term_languages', '$v = new PLL_Language($v, $term_languages[$v->name]);'), $term_languages);
147 set_transient('pll_languages_list', $languages);
148 }
149 else
150 $languages = array(); // in case something went wrong
151 }
152
153 // add flags (not in db cache as they may be different on frontend and admin)
154 foreach ($languages as $lang)
155 $lang->set_flag();
156
157 $this->languages = $languages;
158 }
159
160 $args = wp_parse_args($args, array('hide_empty' => false));
161 extract($args);
162
163 // remove empty languages if requested
164 $languages = array_filter($this->languages, create_function('$v', sprintf('return $v->count || !%d;', $hide_empty)));
165
166 return empty($fields) ? $languages : wp_list_pluck($languages, $fields);
167 }
168
169 /*
170 * cleans language cache
171 * can be called directly with no parameter
172 * called by the 'edited_term_taxonomy' filter with 2 parameters when count needs to be updated
173 *
174 * @since 1.2
175 *
176 * @param int $term not used
177 * @param string $taxonomy taxonomy name
178 */
179 public function clean_languages_cache($term = 0, $taxonomy = null) {
180 if (empty($taxonomy->name) || 'language' == $taxonomy->name) {
181 delete_transient('pll_languages_list');
182 $this->languages = array();
183 }
184 }
185
186 /*
187 * returns the language by its term_id, tl_term_id, slug or locale
188 *
189 * @since 0.1
190 *
191 * @param int|string term_id, tl_term_id, slug or locale of the queried language
192 * @return object|bool PLL_Language object, false if no language found
193 */
194 public function get_language($value) {
195 static $language;
196
197 if (is_object($value))
198 return $this->get_language($value->term_id); // will force cast to PLL_Language
199
200 if (empty($language[$value])) {
201 foreach ($this->get_languages_list() as $lang)
202 $language[$lang->term_id] = $language[$lang->tl_term_id] = $language[$lang->slug] = $language[$lang->locale] = $lang;
203 }
204
205 return empty($language[$value]) ? false : $language[$value];
206 }
207
208 /*
209 * saves translations for posts or terms
210 *
211 * @since 0.5
212
213 * @param string $type either 'post' or 'term'
214 * @param int $id post id or term id
215 * @param array $translations: an associative array of translations with language code as key and translation id as value
216 */
217 public function save_translations($type, $id, $translations) {
218 if (($lang = call_user_func(array(&$this, 'get_'.$type.'_language'), $id)) && isset($translations) && is_array($translations)) {
219 // first unlink this object
220 foreach ($this->get_translations($type, $id) as $object_id)
221 $this->delete_translation($type, $object_id);
222
223 $translations = array_merge(array($lang->slug => $id), $translations); // make sure this object is in tranlations
224 $translations = array_diff($translations, array(0)); // don't keep non translated languages
225
226 // don't create a translation group for untranslated posts as it is useless
227 // but we need one for terms to allow relationships remap when importing from a WXR file
228 if ('term' == $type || count($translations) > 1) {
229 $terms = wp_get_object_terms($translations, $type . '_translations');
230 $term = array_pop($terms);
231
232 // create a new term if necessary
233 empty($term) ?
234 wp_insert_term($group = uniqid('pll_'), $type . '_translations', array('description' => serialize($translations))) :
235 wp_update_term($group = (int) $term->term_id, $type . '_translations', array('description' => serialize($translations)));
236
237 // link all translations to the new term
238 foreach($translations as $p)
239 wp_set_object_terms($p, $group, $type . '_translations');
240 }
241 }
242 }
243
244 /*
245 * deletes a translation of a post or term
246 *
247 * @since 0.5
248 *
249 * @param string $type either 'post' or 'term'
250 * @param int $id post id or term id
251 */
252 public function delete_translation($type, $id) {
253 $term = $this->get_object_term($id, $type . '_translations');
254
255 if (!empty($term)) {
256 $translations = unserialize($term->description);
257
258 if (is_array($translations)) {
259 $slug = array_search($id, $translations);
260 unset($translations[$slug]);
261
262 empty($translations) || 1 == count($translations) ?
263 wp_delete_term((int) $term->term_id, $type . '_translations') :
264 wp_update_term((int) $term->term_id, $type . '_translations', array('description' => serialize($translations)));
265
266 wp_set_object_terms($id, null, $type . '_translations');
267 }
268 }
269 }
270
271 /*
272 * returns the id of the translation of a post or term
273 *
274 * @since 0.5
275 *
276 * @param string $type either 'post' or 'term'
277 * @param int $id post id or term id
278 * @param object|string $lang object or slug
279 * @return bool|int post id or term id of the translation, flase if there is none
280 */
281 public function get_translation($type, $id, $lang) {
282 $translations = $this->get_translations($type, $id);
283 $slug = $this->get_language($lang)->slug;
284 return isset($translations[$slug]) ? (int) $translations[$slug] : false;
285 }
286
287 /*
288 * returns an array of translations of a post or term
289 *
290 * @since 0.5
291 *
292 * @param string $type either 'post' or 'term'
293 * @param int $id post id or term id
294 * @return array an associative array of translations with language code as key and translation id as value
295 */
296 public function get_translations($type, $id) {
297 $type = ($type == 'post' || in_array($type, $this->post_types)) ? 'post' : (($type == 'term' || in_array($type, $this->taxonomies)) ? 'term' : false);
298 return $type && ($term = $this->get_object_term($id, $type . '_translations')) && !empty($term) ? unserialize($term->description) : array();
299 }
300
301 /*
302 * store the post language in the database
303 *
304 * @since 0.6
305 *
306 * @param int $post_id post id
307 * @param int|string|object language (term_id or slug or object)
308 */
309 public function set_post_language($post_id, $lang) {
310 wp_set_post_terms($post_id, $lang ? $this->get_language($lang)->slug : '', 'language' );
311 }
312
313 /*
314 * returns the language of a post
315 *
316 * @since 0.1
317 *
318 * @param int $post_id post id
319 * @return bool|object PLL_Language object, false if no language is associated to that post
320 */
321 public function get_post_language($post_id) {
322 $lang = $this->get_object_term($post_id, 'language' );
323 return ($lang) ? $this->get_language($lang) : false;
324 }
325
326 /*
327 * among the post and its translations, returns the id of the post which is in $lang
328 *
329 * @since 0.1
330 *
331 * @param int $post_id post id
332 * @param int|string|object language (term_id or slug or object)
333 * @return bool|int the translation post id if exists, otherwise the post id, false if the post has no language
334 */
335 public function get_post($post_id, $lang) {
336 $post_lang = $this->get_post_language($post_id); // FIXME is this necessary?
337 if (!$lang || !$post_lang)
338 return false;
339
340 $lang = $this->get_language($lang);
341 return $post_lang->term_id == $lang->term_id ? $post_id : $this->get_translation('post', $post_id, $lang);
342 }
343
344 /*
345 * stores the term language in the database
346 *
347 * @since 0.6
348 *
349 * @param int $term_id term id
350 * @param int|string|object language (term_id or slug or object)
351 */
352 public function set_term_language($term_id, $lang) {
353 wp_set_object_terms($term_id, $lang ? $this->get_language($lang)->tl_term_id : '', 'term_language');
354 }
355
356 /*
357 * removes the term language in database
358 *
359 * @since 0.5
360 *
361 * @param int $term_id term id
362 */
363 public function delete_term_language($term_id) {
364 wp_delete_object_term_relationships($term_id, 'term_language');
365 }
366
367 /*
368 * returns the language of a term
369 *
370 * @since 0.1
371 *
372 * @param int|string $value term id or term slug
373 * @param string $taxonomy optional taxonomy needed when the term slug is passed as first parameter
374 * @return bool|object PLL_Language object, false if no language is associated to that term
375 */
376 public function get_term_language($value, $taxonomy = '') {
377 if (is_numeric($value))
378 $term_id = $value;
379
380 // get_term_by still not cached in WP 3.5.1 but internally, the function is always called by term_id
381 elseif (is_string($value) && $taxonomy)
382 $term_id = get_term_by('slug', $value , $taxonomy)->term_id;
383
384 $lang = $this->get_object_term($term_id, 'term_language');
385
386 // switch to PLL_Language
387 return ($lang) ? $this->get_language($lang->term_id) : false;
388 }
389
390 /*
391 * among the term and its translations, returns the id of the term which is in $lang
392 *
393 * @since 0.1
394 *
395 * @param int $term_id term id
396 * @param int|string|object language (term_id or slug or object)
397 * @return bool|int the translation term id if exists, otherwise the term id, false if the term has no language
398 */
399 public function get_term($term_id, $lang) {
400 $lg = $this->get_term_language($term_id); // FIXME is this necessary?
401 if (!$lang || !$lg)
402 return false;
403
404 $lang = $this->get_language($lang);
405 return $lg->term_id == $lang->term_id ? $term_id : $this->get_translation('term', $term_id, $lang);
406 }
407
408 /*
409 * a join clause to add to sql queries when filtering by language is needed directly in query
410 *
411 * @since 1.2
412 *
413 * @param string $type either 'post' or 'term'
414 * @return string join clause
415 */
416 public function join_clause($type) {
417 global $wpdb;
418 return " INNER JOIN $wpdb->term_relationships AS pll_tr ON pll_tr.object_id = " . ('term' == $type ? "t.term_id" : "ID");
419 }
420
421 /*
422 * a where clause to add to sql queries when filtering by language is needed directly in query
423 *
424 * @since 1.2
425 *
426 * @param object|array|string $lang a PLL_Language object or a comma separated list of languag slug or an array of language slugs
427 * @param string $type either 'post' or 'term'
428 * @return string where clause
429 */
430 public function where_clause($lang, $type) {
431 global $wpdb;
432 $tt_id = 'term' == $type ? 'tl_term_taxonomy_id' : 'term_taxonomy_id';
433
434 // $lang is an object
435 // generally the case if the query is coming from Polylang
436 if (is_object($lang))
437 return $wpdb->prepare(" AND pll_tr.term_taxonomy_id = %d", $lang->$tt_id);
438
439 // $lang is a comma separated list of slugs (or an array of slugs)
440 // generally the case is the query is coming from outside with 'lang' parameter
441 $slugs = is_array($lang) ? $lang : explode(',', $lang);
442 foreach ($slugs as $slug)
443 $languages[] = (int) $this->get_language($slug)->$tt_id;
444
445 return " AND pll_tr.term_taxonomy_id IN (" . implode(',', $languages) . ")";
446 }
447
448 /*
449 * adds clauses to comments query to filter them by language - used in both frontend and admin
450 *
451 * @since 1.2
452 *
453 * @param array $clauses the list of sql clauses in comments query
454 * @param object $lang PLL_Language object
455 * @return array modifed list of clauses
456 */
457 public function comments_clauses($clauses, $lang) {
458 global $wpdb;
459 if (!empty($lang)) {
460 // if this clause is not already added by WP
461 if (!strpos($clauses['join'], '.ID'))
462 $clauses['join'] .= " JOIN $wpdb->posts ON $wpdb->posts.ID = $wpdb->comments.comment_post_ID";
463
464 $clauses['join'] .= $this->join_clause('post');
465 $clauses['where'] .= $this->where_clause($lang, 'post');
466 }
467 return $clauses;
468 }
469
470 /*
471 * adds terms clauses to get_terms to filter them by languages - used in both frontend and admin
472 *
473 * @since 1.2
474 *
475 * @param array $clauses the list of sql clauses in terms query
476 * @param object $lang PLL_Language object
477 * @return array modifed list of clauses
478 */
479 public function terms_clauses($clauses, $lang) {
480 if (!empty($lang)) {
481 $clauses['join'] .= $this->join_clause('term');
482 $clauses['where'] .= $this->where_clause($lang, 'term');
483 }
484 return $clauses;
485 }
486
487 /*
488 * register the language taxonomy
489 *
490 * @since 1.2
491 */
492 public function register_taxonomy() {
493 // registers the language taxonomy
494 // object types will be set later once all custom post types are registered
495 register_taxonomy('language', $this->post_types, array(
496 'labels' => array(
497 'name' => __('Languages', 'polylang'),
498 'singular_name' => __('Language', 'polylang'),
499 'all_items' => __('All languages', 'polylang'),
500 ),
501 'public' => false, // avoid displaying the 'like post tags text box' in the quick edit
502 'query_var' => 'lang',
503 'update_count_callback' => '_update_post_term_count',
504 '_pll' => true // polylang taxonomy
505 ));
506 }
507
508 /*
509 * post types that need to be translated
510 *
511 * @since 1.2
512 *
513 * @return array array of post types names for which Polylang manages languages and translations
514 */
515 protected function get_post_types() {
516 $post_types = array('post' => 'post', 'page' => 'page');
517 if (!empty($this->options['media_support']))
518 $post_types['attachement'] = 'attachment';
519
520 return apply_filters('pll_get_post_types', array_merge($post_types, $this->options['post_types']) , false);
521 }
522
523 /*
524 * returns valid registered post types that need to be translated
525 *
526 * @since 1.2
527 *
528 * @return array array of registered post type names for which Polylang manages languages and translations
529 */
530 public function get_translated_post_types() {
531 return $this->post_types = array_intersect($this->get_post_types(), get_post_types());
532 }
533
534 /*
535 * check if registered post type must be translated
536 *
537 * @since 1.2
538 *
539 * @param string $post_type post type name
540 */
541 public function registered_post_type($post_type) {
542 if (in_array($post_type, $this->get_post_types())) {
543 $this->post_types[$post_type] = $post_type;
544 register_taxonomy_for_object_type('language', $post_type);
545 register_taxonomy_for_object_type('post_translations', $post_type);
546 }
547 }
548
549 /*
550 * returns true if Polylang manages languages and translations for this post type
551 *
552 * @since 1.2
553 *
554 * @param string|array $post_type post type name or array of post type names
555 */
556 public function is_translated_post_type($post_type) {
557 return (is_array($post_type) && array_intersect($post_type, $this->post_types) || in_array($post_type, $this->post_types));
558 }
559
560 /*
561 * taxonomies that need to be translated
562 *
563 * @since 1.2
564 *
565 * @return array array of taxonomy names for which Polylang manages languages and translations
566 */
567 protected function get_taxonomies() {
568 $taxonomies = array('category' => 'category', 'post_tag' => 'post_tag', 'nav_menu' => 'nav_menu');
569 return apply_filters('pll_get_taxonomies', array_merge($taxonomies, $this->options['taxonomies']), false);
570 }
571
572 /*
573 * return valid registered taxonomies that need to be translated
574 *
575 * @since 1.2
576 *
577 * @return array array of registered taxonomy names for which Polylang manages languages and translations
578 */
579 public function get_translated_taxonomies() {
580 return $this->taxonomies = array_intersect($this->get_taxonomies(), get_taxonomies());
581 }
582
583 /*
584 * check if registered post type must be translated
585 *
586 * @since 1.2
587 *
588 * @param string $taxonomy taxonomy name
589 */
590 public function registered_taxonomy($taxonomy) {
591 if (in_array($taxonomy, $this->get_taxonomies()))
592 $this->taxonomies[$taxonomy] = $taxonomy;
593 }
594
595 /*
596 * returns true if Polylang manages languages and translations for this post type
597 *
598 * @since 1.2
599 *
600 * @param string|array $tax taxonomy name or array of taxonomy names
601 */
602 public function is_translated_taxonomy($tax) {
603 return (is_array($tax) && array_intersect($tax, $this->taxonomies) || in_array($tax, $this->taxonomies));
604 }
605
606 /*
607 * it is possible to have several terms with the same name in the same taxonomy (one per language)
608 * but the native get_term_by will return only one term
609 * so here the function adds the language parameter
610 *
611 * @since 1.2
612 *
613 * @param string $field currently the only possibility is 'name'
614 * @param string $value the term name
615 * @param string $taxonomy taxonomy name
616 * @param string|object $language the language slug or object
617 * @return null|int the term_id of the found term
618 */
619 public function get_term_by($field, $value, $taxonomy, $language) {
620 global $wpdb;
621
622 if ('name' != $field)
623 return NULL;
624
625 return $wpdb->get_row("SELECT t.*, tt.* FROM $wpdb->terms AS t"
626 . " INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id"
627 . $this->join_clause('term')
628 . $wpdb->prepare(" WHERE tt.taxonomy = %s AND t.name = %s", $taxonomy, $value)
629 . $this->where_clause($this->get_language($language), 'term')
630 );
631 }
632
633 /*
634 * gets the number of posts per language in a date, author or post type archive
635 *
636 * @since 1.2
637 *
638 * @param object lang
639 * @param array $args WP_Query arguments (accepted: post_type, m, year, monthnum, day, author, author_name)
640 * @return int
641 */
642 public function count_posts($lang, $args = array()) {
643 global $wpdb;
644
645 $q = wp_parse_args($args, array('post_type' => 'post'));
646
647 $cache_key = md5(serialize($q));
648 $counts = wp_cache_get($cache_key, 'pll_count_posts');
649
650 if (false === $counts) {
651 $where = " WHERE post_status = 'publish'";
652 $where .= $wpdb->prepare(" AND {$wpdb->posts}.post_type = %s", $q['post_type']);
653
654 if (!empty($q['m'])) {
655 $q['m'] = '' . preg_replace('|[^0-9]|', '', $q['m']);
656 $where .= $wpdb->prepare(" AND YEAR({$wpdb->posts}.post_date) = %d", substr($q['m'], 0, 4));
657 if ( strlen($q['m']) > 5 )
658 $where .= $wpdb->prepare(" AND MONTH({$wpdb->posts}.post_date) = %d", substr($q['m'], 4, 2));
659 if ( strlen($q['m']) > 7 )
660 $where .= $wpdb->prepare(" AND DAYOFMONTH({$wpdb->posts}.post_date) = %d", substr($q['m'], 6, 2));
661 }
662
663 if (!empty($q['year']))
664 $where .= $wpdb->prepare(" AND YEAR({$wpdb->posts}.post_date) = %d", $q['year']);
665
666 if (!empty($q['monthnum']))
667 $where .= $wpdb->prepare(" AND MONTH({$wpdb->posts}.post_date) = %d", $q['monthnum']);
668
669 if (!empty($q['day']))
670 $where .= $wpdb->prepare(" AND DAYOFMONTH({$wpdb->posts}.post_date) = %d", $q['day']);
671
672 if (!empty($q['author_name'])) {
673 $author = get_user_by('slug', sanitize_title_for_query($q['author_name']));
674 if ($author)
675 $q['author'] = $author->ID;
676 }
677
678 if (!empty($q['author']))
679 $where .= $wpdb->prepare(" AND {$wpdb->posts}.post_author = %d", $q['author']);
680
681 $select = "SELECT pll_tr.term_taxonomy_id, COUNT(*) AS num_posts FROM {$wpdb->posts}";
682 $join = $this->join_clause('post');
683 $where .= $this->where_clause($this->get_languages_list(), 'post');
684 $groupby = " GROUP BY pll_tr.term_taxonomy_id";
685
686 $res = $wpdb->get_results($select . $join . $where . $groupby, ARRAY_A);
687 foreach ((array) $res as $row)
688 $counts[$row['term_taxonomy_id']] = $row['num_posts'];
689
690 wp_cache_set($cache_key, $counts, 'pll_count_posts');
691 }
692
693 return empty($counts[$lang->term_taxonomy_id]) ? 0 : $counts[$lang->term_taxonomy_id];
694 }
695 }
696