PluginProbe
Polylang / 1.2.4
Polylang v1.2.4
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.4, at include/model.php

706 lines 23.3 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 if (!$lang = $this->get_language($lang))
283 return false;
284
285 $translations = $this->get_translations($type, $id);
286
287 return isset($translations[$lang->slug]) ? (int) $translations[$lang->slug] : false;
288 }
289
290 /*
291 * returns an array of translations of a post or term
292 *
293 * @since 0.5
294 *
295 * @param string $type either 'post' or 'term'
296 * @param int $id post id or term id
297 * @return array an associative array of translations with language code as key and translation id as value
298 */
299 public function get_translations($type, $id) {
300 $type = ($type == 'post' || in_array($type, $this->post_types)) ? 'post' : (($type == 'term' || in_array($type, $this->taxonomies)) ? 'term' : false);
301 return $type && ($term = $this->get_object_term($id, $type . '_translations')) && !empty($term) ? unserialize($term->description) : array();
302 }
303
304 /*
305 * store the post language in the database
306 *
307 * @since 0.6
308 *
309 * @param int $post_id post id
310 * @param int|string|object language (term_id or slug or object)
311 */
312 public function set_post_language($post_id, $lang) {
313 wp_set_post_terms($post_id, $lang ? $this->get_language($lang)->slug : '', 'language' );
314 }
315
316 /*
317 * returns the language of a post
318 *
319 * @since 0.1
320 *
321 * @param int $post_id post id
322 * @return bool|object PLL_Language object, false if no language is associated to that post
323 */
324 public function get_post_language($post_id) {
325 $lang = $this->get_object_term($post_id, 'language' );
326 return ($lang) ? $this->get_language($lang) : false;
327 }
328
329 /*
330 * among the post and its translations, returns the id of the post which is in $lang
331 *
332 * @since 0.1
333 *
334 * @param int $post_id post id
335 * @param int|string|object language (term_id or slug or object)
336 * @return bool|int the translation post id if exists, otherwise the post id, false if the post has no language
337 */
338 public function get_post($post_id, $lang) {
339 $post_lang = $this->get_post_language($post_id); // FIXME is this necessary?
340 if (!$lang || !$post_lang)
341 return false;
342
343 $lang = $this->get_language($lang);
344 return $post_lang->term_id == $lang->term_id ? $post_id : $this->get_translation('post', $post_id, $lang);
345 }
346
347 /*
348 * stores the term language in the database
349 *
350 * @since 0.6
351 *
352 * @param int $term_id term id
353 * @param int|string|object language (term_id or slug or object)
354 */
355 public function set_term_language($term_id, $lang) {
356 wp_set_object_terms($term_id, $lang ? $this->get_language($lang)->tl_term_id : '', 'term_language');
357 }
358
359 /*
360 * removes the term language in database
361 *
362 * @since 0.5
363 *
364 * @param int $term_id term id
365 */
366 public function delete_term_language($term_id) {
367 wp_delete_object_term_relationships($term_id, 'term_language');
368 }
369
370 /*
371 * returns the language of a term
372 *
373 * @since 0.1
374 *
375 * @param int|string $value term id or term slug
376 * @param string $taxonomy optional taxonomy needed when the term slug is passed as first parameter
377 * @return bool|object PLL_Language object, false if no language is associated to that term
378 */
379 public function get_term_language($value, $taxonomy = '') {
380 if (is_numeric($value))
381 $term_id = $value;
382
383 // get_term_by still not cached in WP 3.5.1 but internally, the function is always called by term_id
384 elseif (is_string($value) && $taxonomy)
385 $term_id = get_term_by('slug', $value , $taxonomy)->term_id;
386
387 $lang = $this->get_object_term($term_id, 'term_language');
388
389 // switch to PLL_Language
390 return ($lang) ? $this->get_language($lang->term_id) : false;
391 }
392
393 /*
394 * among the term and its translations, returns the id of the term which is in $lang
395 *
396 * @since 0.1
397 *
398 * @param int $term_id term id
399 * @param int|string|object language (term_id or slug or object)
400 * @return bool|int the translation term id if exists, otherwise the term id, false if the term has no language
401 */
402 public function get_term($term_id, $lang) {
403 $lg = $this->get_term_language($term_id); // FIXME is this necessary?
404 if (!$lang || !$lg)
405 return false;
406
407 $lang = $this->get_language($lang);
408 return $lg->term_id == $lang->term_id ? $term_id : $this->get_translation('term', $term_id, $lang);
409 }
410
411 /*
412 * a join clause to add to sql queries when filtering by language is needed directly in query
413 *
414 * @since 1.2
415 *
416 * @param string $type either 'post' or 'term'
417 * @return string join clause
418 */
419 public function join_clause($type) {
420 global $wpdb;
421 return " INNER JOIN $wpdb->term_relationships AS pll_tr ON pll_tr.object_id = " . ('term' == $type ? "t.term_id" : "ID");
422 }
423
424 /*
425 * a where clause to add to sql queries when filtering by language is needed directly in query
426 *
427 * @since 1.2
428 *
429 * @param object|array|string $lang a PLL_Language object or a comma separated list of languag slug or an array of language slugs
430 * @param string $type either 'post' or 'term'
431 * @return string where clause
432 */
433 public function where_clause($lang, $type) {
434 global $wpdb;
435 $tt_id = 'term' == $type ? 'tl_term_taxonomy_id' : 'term_taxonomy_id';
436
437 // $lang is an object
438 // generally the case if the query is coming from Polylang
439 if (is_object($lang))
440 return $wpdb->prepare(" AND pll_tr.term_taxonomy_id = %d", $lang->$tt_id);
441
442 // $lang is a comma separated list of slugs (or an array of slugs)
443 // generally the case is the query is coming from outside with 'lang' parameter
444 $slugs = is_array($lang) ? $lang : explode(',', $lang);
445 foreach ($slugs as $slug)
446 $languages[] = (int) $this->get_language($slug)->$tt_id;
447
448 return " AND pll_tr.term_taxonomy_id IN (" . implode(',', $languages) . ")";
449 }
450
451 /*
452 * adds clauses to comments query to filter them by language - used in both frontend and admin
453 *
454 * @since 1.2
455 *
456 * @param array $clauses the list of sql clauses in comments query
457 * @param object $lang PLL_Language object
458 * @return array modifed list of clauses
459 */
460 public function comments_clauses($clauses, $lang) {
461 global $wpdb;
462 if (!empty($lang)) {
463 // if this clause is not already added by WP
464 if (!strpos($clauses['join'], '.ID'))
465 $clauses['join'] .= " JOIN $wpdb->posts ON $wpdb->posts.ID = $wpdb->comments.comment_post_ID";
466
467 $clauses['join'] .= $this->join_clause('post');
468 $clauses['where'] .= $this->where_clause($lang, 'post');
469 }
470 return $clauses;
471 }
472
473 /*
474 * adds terms clauses to get_terms to filter them by languages - used in both frontend and admin
475 *
476 * @since 1.2
477 *
478 * @param array $clauses the list of sql clauses in terms query
479 * @param object $lang PLL_Language object
480 * @return array modifed list of clauses
481 */
482 public function terms_clauses($clauses, $lang) {
483 if (!empty($lang)) {
484 $clauses['join'] .= $this->join_clause('term');
485 $clauses['where'] .= $this->where_clause($lang, 'term');
486 }
487 return $clauses;
488 }
489
490 /*
491 * register the language taxonomy
492 *
493 * @since 1.2
494 */
495 public function register_taxonomy() {
496 // registers the language taxonomy
497 // object types will be set later once all custom post types are registered
498 register_taxonomy('language', $this->post_types, array(
499 'labels' => array(
500 'name' => __('Languages', 'polylang'),
501 'singular_name' => __('Language', 'polylang'),
502 'all_items' => __('All languages', 'polylang'),
503 ),
504 'public' => false, // avoid displaying the 'like post tags text box' in the quick edit
505 'query_var' => 'lang',
506 'update_count_callback' => '_update_post_term_count',
507 '_pll' => true // polylang taxonomy
508 ));
509 }
510
511 /*
512 * post types that need to be translated
513 *
514 * @since 1.2
515 *
516 * @return array array of post types names for which Polylang manages languages and translations
517 */
518 protected function get_post_types() {
519 $post_types = array('post' => 'post', 'page' => 'page');
520 if (!empty($this->options['media_support']))
521 $post_types['attachement'] = 'attachment';
522
523 if (is_array($this->options['post_types']))
524 $post_types = array_merge($post_types, $this->options['post_types']);
525
526 return apply_filters('pll_get_post_types', $post_types , false);
527 }
528
529 /*
530 * returns valid registered post types that need to be translated
531 *
532 * @since 1.2
533 *
534 * @return array array of registered post type names for which Polylang manages languages and translations
535 */
536 public function get_translated_post_types() {
537 return $this->post_types = array_intersect($this->get_post_types(), get_post_types());
538 }
539
540 /*
541 * check if registered post type must be translated
542 *
543 * @since 1.2
544 *
545 * @param string $post_type post type name
546 */
547 public function registered_post_type($post_type) {
548 if (in_array($post_type, $this->get_post_types())) {
549 $this->post_types[$post_type] = $post_type;
550 register_taxonomy_for_object_type('language', $post_type);
551 register_taxonomy_for_object_type('post_translations', $post_type);
552 }
553 }
554
555 /*
556 * returns true if Polylang manages languages and translations for this post type
557 *
558 * @since 1.2
559 *
560 * @param string|array $post_type post type name or array of post type names
561 */
562 public function is_translated_post_type($post_type) {
563 return (is_array($post_type) && array_intersect($post_type, $this->post_types) || in_array($post_type, $this->post_types));
564 }
565
566 /*
567 * taxonomies that need to be translated
568 *
569 * @since 1.2
570 *
571 * @return array array of taxonomy names for which Polylang manages languages and translations
572 */
573 protected function get_taxonomies() {
574 $taxonomies = array('category' => 'category', 'post_tag' => 'post_tag');
575
576 if (is_array($this->options['taxonomies']))
577 $taxonomies = array_merge($taxonomies, $this->options['taxonomies']);
578
579 return apply_filters('pll_get_taxonomies', $taxonomies, false);
580 }
581
582 /*
583 * return valid registered taxonomies that need to be translated
584 *
585 * @since 1.2
586 *
587 * @return array array of registered taxonomy names for which Polylang manages languages and translations
588 */
589 public function get_translated_taxonomies() {
590 return $this->taxonomies = array_intersect($this->get_taxonomies(), get_taxonomies());
591 }
592
593 /*
594 * check if registered post type must be translated
595 *
596 * @since 1.2
597 *
598 * @param string $taxonomy taxonomy name
599 */
600 public function registered_taxonomy($taxonomy) {
601 if (in_array($taxonomy, $this->get_taxonomies()))
602 $this->taxonomies[$taxonomy] = $taxonomy;
603 }
604
605 /*
606 * returns true if Polylang manages languages and translations for this post type
607 *
608 * @since 1.2
609 *
610 * @param string|array $tax taxonomy name or array of taxonomy names
611 */
612 public function is_translated_taxonomy($tax) {
613 return (is_array($tax) && array_intersect($tax, $this->taxonomies) || in_array($tax, $this->taxonomies));
614 }
615
616 /*
617 * it is possible to have several terms with the same name in the same taxonomy (one per language)
618 * but the native get_term_by will return only one term
619 * so here the function adds the language parameter
620 *
621 * @since 1.2
622 *
623 * @param string $field currently the only possibility is 'name'
624 * @param string $value the term name
625 * @param string $taxonomy taxonomy name
626 * @param string|object $language the language slug or object
627 * @return null|int the term_id of the found term
628 */
629 public function get_term_by($field, $value, $taxonomy, $language) {
630 global $wpdb;
631
632 if ('name' != $field)
633 return NULL;
634
635 return $wpdb->get_row("SELECT t.*, tt.* FROM $wpdb->terms AS t"
636 . " INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id"
637 . $this->join_clause('term')
638 . $wpdb->prepare(" WHERE tt.taxonomy = %s AND t.name = %s", $taxonomy, $value)
639 . $this->where_clause($this->get_language($language), 'term')
640 );
641 }
642
643 /*
644 * gets the number of posts per language in a date, author or post type archive
645 *
646 * @since 1.2
647 *
648 * @param object lang
649 * @param array $args WP_Query arguments (accepted: post_type, m, year, monthnum, day, author, author_name)
650 * @return int
651 */
652 public function count_posts($lang, $args = array()) {
653 global $wpdb;
654
655 $q = wp_parse_args($args, array('post_type' => 'post'));
656
657 $cache_key = md5(serialize($q));
658 $counts = wp_cache_get($cache_key, 'pll_count_posts');
659
660 if (false === $counts) {
661 $where = " WHERE post_status = 'publish'";
662 $where .= $wpdb->prepare(" AND {$wpdb->posts}.post_type = %s", $q['post_type']);
663
664 if (!empty($q['m'])) {
665 $q['m'] = '' . preg_replace('|[^0-9]|', '', $q['m']);
666 $where .= $wpdb->prepare(" AND YEAR({$wpdb->posts}.post_date) = %d", substr($q['m'], 0, 4));
667 if ( strlen($q['m']) > 5 )
668 $where .= $wpdb->prepare(" AND MONTH({$wpdb->posts}.post_date) = %d", substr($q['m'], 4, 2));
669 if ( strlen($q['m']) > 7 )
670 $where .= $wpdb->prepare(" AND DAYOFMONTH({$wpdb->posts}.post_date) = %d", substr($q['m'], 6, 2));
671 }
672
673 if (!empty($q['year']))
674 $where .= $wpdb->prepare(" AND YEAR({$wpdb->posts}.post_date) = %d", $q['year']);
675
676 if (!empty($q['monthnum']))
677 $where .= $wpdb->prepare(" AND MONTH({$wpdb->posts}.post_date) = %d", $q['monthnum']);
678
679 if (!empty($q['day']))
680 $where .= $wpdb->prepare(" AND DAYOFMONTH({$wpdb->posts}.post_date) = %d", $q['day']);
681
682 if (!empty($q['author_name'])) {
683 $author = get_user_by('slug', sanitize_title_for_query($q['author_name']));
684 if ($author)
685 $q['author'] = $author->ID;
686 }
687
688 if (!empty($q['author']))
689 $where .= $wpdb->prepare(" AND {$wpdb->posts}.post_author = %d", $q['author']);
690
691 $select = "SELECT pll_tr.term_taxonomy_id, COUNT(*) AS num_posts FROM {$wpdb->posts}";
692 $join = $this->join_clause('post');
693 $where .= $this->where_clause($this->get_languages_list(), 'post');
694 $groupby = " GROUP BY pll_tr.term_taxonomy_id";
695
696 $res = $wpdb->get_results($select . $join . $where . $groupby, ARRAY_A);
697 foreach ((array) $res as $row)
698 $counts[$row['term_taxonomy_id']] = $row['num_posts'];
699
700 wp_cache_set($cache_key, $counts, 'pll_count_posts');
701 }
702
703 return empty($counts[$lang->term_taxonomy_id]) ? 0 : $counts[$lang->term_taxonomy_id];
704 }
705 }
706