PluginProbe
Polylang / 2.0.3
Polylang v2.0.3
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
← All changes | include/model.php +196 -205 3.0.12.0.3 View file →
@@ -1,8 +1,5 @@
1 1 <?php
2 -/**
3 - * @package Polylang
4 - */
5 2
6 3 /**
7 4 * Setups the language and translations model based on WordPress taxonomies
8 5 *
@@ -8,81 +5,57 @@
8 5 *
9 6 * @since 1.2
10 7 */
11 8 class PLL_Model {
12 - /**
13 - * Internal non persistent cache object.
14 - *
15 - * @var PLL_Cache
16 - */
17 - public $cache;
18 -
19 - /**
20 - * Stores the plugin options.
21 - *
22 - * @var array
23 - */
9 + public $cache; // our internal non persistent cache object
24 10 public $options;
11 + public $post, $term; // translated objects models
25 12
26 13 /**
27 - * Translated post model.
14 + * Constructor
15 + * setups translated objects sub models
16 + * setups filters and actions
28 17 *
29 - * @var PLL_Translated_Post
30 - */
31 - public $post;
32 -
33 - /**
34 - * Translated term model.
35 - *
36 - * @var PLL_Translated_Term
37 - */
38 - public $term;
39 -
40 - /**
41 - * Constructor.
42 - * Setups translated objects sub models.
43 - * Setups filters and actions.
44 - *
45 18 * @since 1.2
46 19 *
47 - * @param array $options Polylang options.
20 + * @param array $options Polylang options
48 21 */
49 22 public function __construct( &$options ) {
50 23 $this->options = &$options;
51 24
52 25 $this->cache = new PLL_Cache();
53 - $this->post = new PLL_Translated_Post( $this ); // Translated post sub model.
54 - $this->term = new PLL_Translated_Term( $this ); // Translated term sub model.
26 + $this->post = new PLL_Translated_Post( $this ); // translated post sub model
27 + $this->term = new PLL_Translated_Term( $this ); // translated term sub model
55 28
56 - // We need to clean languages cache when editing a language and when modifying the permalink structure.
29 + // we need to clean languages cache when editing a language and when modifying the permalink structure
57 30 add_action( 'edited_term_taxonomy', array( $this, 'clean_languages_cache' ), 10, 2 );
58 31 add_action( 'update_option_permalink_structure', array( $this, 'clean_languages_cache' ) );
59 32 add_action( 'update_option_siteurl', array( $this, 'clean_languages_cache' ) );
60 33 add_action( 'update_option_home', array( $this, 'clean_languages_cache' ) );
61 34
62 - add_filter( 'get_terms_args', array( $this, 'get_terms_args' ) );
63 -
64 - // Just in case someone would like to display the language description ;).
35 + // just in case someone would like to display the language description ;- )
65 36 add_filter( 'language_description', '__return_empty_string' );
66 37 }
67 38
68 39 /**
69 - * Returns the list of available languages.
70 - * - Stores the list in a db transient ( except flags ), unless PLL_CACHE_LANGUAGES is set to false.
71 - * - Caches the list ( with flags ) in a PLL_Cache object.
40 + * Returns the list of available languages
41 + * caches the list in a db transient ( except flags ), unless PLL_CACHE_LANGUAGES is set to false
42 + * caches the list ( with flags ) in the private property $languages
72 43 *
44 + * list of parameters accepted in $args:
45 + *
46 + * hide_empty => hides languages with no posts if set to true ( defaults to false )
47 + * fields => return only that field if set ( see PLL_Language for a list of fields )
48 + *
73 49 * @since 0.1
74 50 *
75 - * @param array $args {
76 - * @type bool $hide_empty Hides languages with no posts if set to true ( defaults to false ).
77 - * @type string $fields Returns only that field if set; {@see PLL_Language} for a list of fields.
78 - * }
79 - * @return array List of PLL_Language objects or PLL_Language object properties.
51 + * @param array $args
52 + * @return array|string|int list of PLL_Language objects or PLL_Language object properties
80 53 */
81 54 public function get_languages_list( $args = array() ) {
82 55 if ( false === $languages = $this->cache->get( 'languages' ) ) {
83 56
84 - // Create the languages from taxonomies.
57 + // create the languages from taxonomies
85 58 if ( ( defined( 'PLL_CACHE_LANGUAGES' ) && ! PLL_CACHE_LANGUAGES ) || false === ( $languages = get_transient( 'pll_languages_list' ) ) ) {
86 59 $languages = get_terms( 'language', array( 'hide_empty' => false, 'orderby' => 'term_group' ) );
87 60 $languages = empty( $languages ) || is_wp_error( $languages ) ? array() : $languages;
88 61
@@ -90,40 +63,38 @@
90 63 $term_languages = empty( $term_languages ) || is_wp_error( $term_languages ) ?
91 64 array() : array_combine( wp_list_pluck( $term_languages, 'slug' ), $term_languages );
92 65
93 66 if ( ! empty( $languages ) && ! empty( $term_languages ) ) {
94 - // Don't use array_map + create_function() to instantiate an autoloaded class as it breaks badly in old versions of PHP.
67 + // don't use array_map + create_function to instantiate an autoloaded class as it breaks badly in old versions of PHP
95 68 foreach ( $languages as $k => $v ) {
96 69 $languages[ $k ] = new PLL_Language( $v, $term_languages[ 'pll_' . $v->slug ] );
97 70 }
98 71
99 - // We will need the languages list to allow its access in the filter below.
72 + // we will need the languages list to allow its access in the filter below
100 73 $this->cache->set( 'languages', $languages );
101 74
102 75 /**
103 - * Filters the list of languages *before* it is stored in the persistent cache.
104 - * /!\ This filter is fired *before* the $polylang object is available.
76 + * Filter the list of languages *before* it is stored in the persistent cache
77 + * /!\ this filter is fired *before* the $polylang object is available
105 78 *
106 79 * @since 1.7.5
107 80 *
108 - * @param PLL_Language[] $languages The list of language objects.
109 - * @param PLL_Model $model PLL_Model object.
81 + * @param array $languages the list of language objects
82 + * @param object $model PLL_Model object
110 83 */
111 84 $languages = apply_filters( 'pll_languages_list', $languages, $this );
112 85
113 - /*
114 - * Don't store directly objects as it badly break with some hosts ( GoDaddy ) due to race conditions when using object cache.
115 - * Thanks to captin411 for catching this!
116 - * @see https://wordpress.org/support/topic/fatal-error-pll_model_languages_list?replies=8#post-6782255
117 - */
86 + // don't store directly objects as it badly break with some hosts ( GoDaddy ) due to race conditions when using object cache
87 + // thanks to captin411 for catching this!
88 + // see https://wordpress.org/support/topic/fatal-error-pll_model_languages_list?replies=8#post-6782255;
118 89 set_transient( 'pll_languages_list', array_map( 'get_object_vars', $languages ) );
119 90 }
120 91 else {
121 - $languages = array(); // In case something went wrong.
92 + $languages = array(); // in case something went wrong
122 93 }
123 94 }
124 95
125 - // Create the languages directly from arrays stored in transients.
96 + // create the languages directly from arrays stored in transients
126 97 else {
127 98 foreach ( $languages as $k => $v ) {
128 99 $languages[ $k ] = new PLL_Language( $v );
129 100 }
@@ -128,15 +99,22 @@
128 99 $languages[ $k ] = new PLL_Language( $v );
129 100 }
130 101 }
131 102
103 + // custom flags
104 + if ( ! PLL_ADMIN ) {
105 + foreach ( $languages as $language ) {
106 + $language->set_custom_flag();
107 + }
108 + }
109 +
132 110 /**
133 - * Filters the list of languages *after* it is stored in the persistent cache.
134 - * /!\ This filter is fired *before* the $polylang object is available.
111 + * Filter the list of languages *after* it is stored in the persistent cache
112 + * /!\ this filter is fired *before* the $polylang object is available
135 113 *
136 114 * @since 1.8
137 115 *
138 - * @param PLL_Language[] $languages The list of language objects.
116 + * @param array $languages the list of language objects
139 117 */
140 118 $languages = apply_filters( 'pll_after_languages_cache', $languages );
141 119 $this->cache->set( 'languages', $languages );
142 120 }
@@ -142,9 +120,9 @@
142 120 }
143 121
144 122 $args = wp_parse_args( $args, array( 'hide_empty' => false ) );
145 123
146 - // Remove empty languages if requested.
124 + // remove empty languages if requested
147 125 if ( $args['hide_empty'] ) {
148 126 $languages = wp_list_filter( $languages, array( 'count' => 0 ), 'NOT' );
149 127 }
150 128
@@ -159,11 +137,16 @@
159 137 * @since 1.2
160 138 *
161 139 * @param int $term not used
162 140 * @param string $taxonomy taxonomy name
163 - * @return void
164 141 */
165 142 public function clean_languages_cache( $term = 0, $taxonomy = null ) {
143 + // depending on WP version, the action is passed an object or a string
144 + // backward compatibility with WP < 4.2
145 + if ( ! empty( $taxonomy ) && is_object( $taxonomy ) ) {
146 + $taxonomy = $taxonomy->name;
147 + }
148 +
166 149 if ( empty( $taxonomy ) || 'language' == $taxonomy ) {
167 150 delete_transient( 'pll_languages_list' );
168 151 $this->cache->clean();
169 152 }
@@ -169,29 +152,14 @@
169 152 }
170 153 }
171 154
172 155 /**
173 - * Don't query term metas when only our taxonomies are queried
156 + * Returns the language by its term_id, tl_term_id, slug or locale
174 157 *
175 - * @since 2.3
176 - *
177 - * @param array $args WP_Term_Query arguments
178 - * @return array
179 - */
180 - public function get_terms_args( $args ) {
181 - if ( isset( $args['taxonomy'] ) && ! array_diff( (array) $args['taxonomy'], array( 'language', 'term_language', 'post_translations', 'term_translations' ) ) ) {
182 - $args['update_term_meta_cache'] = false;
183 - }
184 - return $args;
185 - }
186 -
187 - /**
188 - * Returns the language by its term_id, tl_term_id, slug or locale.
189 - *
190 158 * @since 0.1
191 159 *
192 - * @param mixed $value term_id, tl_term_id, slug or locale of the queried language.
193 - * @return PLL_Language|false Language object, false if no language found.
160 + * @param int|string term_id, tl_term_id, slug or locale of the queried language
161 + * @return object|bool PLL_Language object, false if no language found
194 162 */
195 163 public function get_language( $value ) {
196 164 if ( is_object( $value ) ) {
197 165 return $value instanceof PLL_Language ? $value : $this->get_language( $value->term_id ); // will force cast to PLL_Language
@@ -202,9 +170,8 @@
202 170 $this->cache->set( 'language:' . $lang->term_id, $lang );
203 171 $this->cache->set( 'language:' . $lang->tl_term_id, $lang );
204 172 $this->cache->set( 'language:' . $lang->slug, $lang );
205 173 $this->cache->set( 'language:' . $lang->locale, $lang );
206 - $this->cache->set( 'language:' . $lang->w3c, $lang );
207 174 }
208 175 $return = $this->cache->get( 'language:' . $value );
209 176 }
210 177
@@ -211,15 +178,15 @@
211 178 return $return;
212 179 }
213 180
214 181 /**
215 - * Adds terms clauses to the term query to filter them by languages.
182 + * Adds terms clauses to get_terms to filter them by languages - used in both frontend and admin
216 183 *
217 184 * @since 1.2
218 185 *
219 - * @param string[] $clauses The list of sql clauses in terms query.
220 - * @param PLL_Language $lang PLL_Language object.
221 - * @return string[] Modified list of clauses.
186 + * @param array $clauses the list of sql clauses in terms query
187 + * @param object $lang PLL_Language object
188 + * @return array modifed list of clauses
222 189 */
223 190 public function terms_clauses( $clauses, $lang ) {
224 191 if ( ! empty( $lang ) && false === strpos( $clauses['join'], 'pll_tr' ) ) {
225 192 $clauses['join'] .= $this->term->join_clause();
@@ -228,21 +195,20 @@
228 195 return $clauses;
229 196 }
230 197
231 198 /**
232 - * Returns post types that need to be translated.
233 - * The post types list is cached for better better performance.
234 - * The method waits for 'after_setup_theme' to apply the cache
235 - * to allow themes adding the filter in functions.php.
199 + * Returns post types that need to be translated
200 + * the post types list is cached for better better performance
201 + * wait for 'after_setup_theme' to apply the cache to allow themes adding the filter in functions.php
236 202 *
237 203 * @since 1.2
238 204 *
239 - * @param bool $filter True if we should return only valid registered post types.
240 - * @return string[] Post type names for which Polylang manages languages and translations.
205 + * @param bool $filter true if we should return only valid registered post types
206 + * @return array post type names for which Polylang manages languages and translations
241 207 */
242 208 public function get_translated_post_types( $filter = true ) {
243 209 if ( false === $post_types = $this->cache->get( 'post_types' ) ) {
244 - $post_types = array( 'post' => 'post', 'page' => 'page', 'wp_block' => 'wp_block' );
210 + $post_types = array( 'post' => 'post', 'page' => 'page' );
245 211
246 212 if ( ! empty( $this->options['media_support'] ) ) {
247 213 $post_types['attachment'] = 'attachment';
248 214 }
@@ -247,13 +213,13 @@
247 213 $post_types['attachment'] = 'attachment';
248 214 }
249 215
250 216 if ( ! empty( $this->options['post_types'] ) && is_array( $this->options['post_types'] ) ) {
251 - $post_types = array_merge( $post_types, array_combine( $this->options['post_types'], $this->options['post_types'] ) );
217 + $post_types = array_merge( $post_types, array_combine( $this->options['post_types'], $this->options['post_types'] ) );
252 218 }
253 219
254 220 /**
255 - * Filters the list of post types available for translation.
221 + * Filter the list of post types available for translation.
256 222 * The default are post types which have the parameter ‘public’ set to true.
257 223 * The filter must be added soon in the WordPress loading process:
258 224 * in a function hooked to ‘plugins_loaded’ or directly in functions.php for themes.
259 225 *
@@ -258,10 +224,10 @@
258 224 * in a function hooked to ‘plugins_loaded’ or directly in functions.php for themes.
259 225 *
260 226 * @since 0.8
261 227 *
262 - * @param string[] $post_types List of post type names.
263 - * @param bool $is_settings True when displaying the list of custom post types in Polylang settings.
228 + * @param array $post_types list of post type names
229 + * @param bool $is_settings true when displaying the list of custom post types in Polylang settings
264 230 */
265 231 $post_types = apply_filters( 'pll_get_post_types', $post_types, false );
266 232
267 233 if ( did_action( 'after_setup_theme' ) ) {
@@ -272,27 +238,27 @@
272 238 return $filter ? array_intersect( $post_types, get_post_types() ) : $post_types;
273 239 }
274 240
275 241 /**
276 - * Returns true if Polylang manages languages and translations for this post type.
242 + * Returns true if Polylang manages languages and translations for this post type
277 243 *
278 244 * @since 1.2
279 245 *
280 - * @param string|string[] $post_type Post type name or array of post type names.
246 + * @param string|array $post_type post type name or array of post type names
281 247 * @return bool
282 248 */
283 249 public function is_translated_post_type( $post_type ) {
284 250 $post_types = $this->get_translated_post_types( false );
285 - return ( is_array( $post_type ) && array_intersect( $post_type, $post_types ) || in_array( $post_type, $post_types ) || 'any' === $post_type && ! empty( $post_types ) );
251 + return ( is_array( $post_type ) && array_intersect( $post_type, $post_types ) || in_array( $post_type, $post_types ) );
286 252 }
287 253
288 254 /**
289 - * Returns taxonomies that need to be translated.
255 + * Return taxonomies that need to be translated
290 256 *
291 257 * @since 1.2
292 258 *
293 - * @param bool $filter True if we should return only valid registered taxonomies.
294 - * @return string[] Array of registered taxonomy names for which Polylang manages languages and translations.
259 + * @param bool $filter true if we should return only valid registered taxonmies
260 + * @return array array of registered taxonomy names for which Polylang manages languages and translations
295 261 */
296 262 public function get_translated_taxonomies( $filter = true ) {
297 263 if ( false === $taxonomies = $this->cache->get( 'taxonomies' ) ) {
298 264 $taxonomies = array( 'category' => 'category', 'post_tag' => 'post_tag' );
@@ -301,9 +267,9 @@
301 267 $taxonomies = array_merge( $taxonomies, array_combine( $this->options['taxonomies'], $this->options['taxonomies'] ) );
302 268 }
303 269
304 270 /**
305 - * Filters the list of taxonomies available for translation.
271 + * Filter the list of taxonomies available for translation.
306 272 * The default are taxonomies which have the parameter ‘public’ set to true.
307 273 * The filter must be added soon in the WordPress loading process:
308 274 * in a function hooked to ‘plugins_loaded’ or directly in functions.php for themes.
309 275 *
@@ -308,10 +274,10 @@
308 274 * in a function hooked to ‘plugins_loaded’ or directly in functions.php for themes.
309 275 *
310 276 * @since 0.8
311 277 *
312 - * @param string[] $taxonomies List of taxonomy names.
313 - * @param bool $is_settings True when displaying the list of custom taxonomies in Polylang settings.
278 + * @param array $taxonomies list of taxonomy names
279 + * @param bool $is_settings true when displaying the list of custom taxonomies in Polylang settings
314 280 */
315 281 $taxonomies = apply_filters( 'pll_get_taxonomies', $taxonomies, false );
316 282 if ( did_action( 'after_setup_theme' ) ) {
317 283 $this->cache->set( 'taxonomies', $taxonomies );
@@ -321,13 +287,13 @@
321 287 return $filter ? array_intersect( $taxonomies, get_taxonomies() ) : $taxonomies;
322 288 }
323 289
324 290 /**
325 - * Returns true if Polylang manages languages and translations for this taxonomy.
291 + * Returns true if Polylang manages languages and translations for this taxonomy
326 292 *
327 293 * @since 1.2
328 294 *
329 - * @param string|string[] $tax Taxonomy name or array of taxonomy names.
295 + * @param string|array $tax taxonomy name or array of taxonomy names
330 296 * @return bool
331 297 */
332 298 public function is_translated_taxonomy( $tax ) {
333 299 $taxonomies = $this->get_translated_taxonomies( false );
@@ -334,15 +300,40 @@
334 300 return ( is_array( $tax ) && array_intersect( $tax, $taxonomies ) || in_array( $tax, $taxonomies ) );
335 301 }
336 302
337 303 /**
338 - * Return staxonomies that need to be filtered ( post_format like ).
304 + * Check if translated taxonomy is queried
305 + * Compatible with nested queries introduced in WP 4.1
306 + * @see https://wordpress.org/support/topic/tax_query-bug
339 307 *
340 308 * @since 1.7
341 309 *
342 - * @param bool $filter True if we should return only valid registered taxonomies.
343 - * @return string[] Array of registered taxonomy names.
310 + * @param array $tax_queries
311 + * @return bool
344 312 */
313 + public function have_translated_taxonomy( $tax_queries ) {
314 + foreach ( $tax_queries as $tax_query ) {
315 + if ( isset( $tax_query['taxonomy'] ) && $this->is_translated_taxonomy( $tax_query['taxonomy'] ) && ! ( isset( $tax_query['operator'] ) && 'NOT IN' === $tax_query['operator'] ) ) {
316 + return true;
317 + }
318 +
319 + // Nested queries
320 + elseif ( is_array( $tax_query ) && $this->have_translated_taxonomy( $tax_query ) ) {
321 + return true;
322 + }
323 + }
324 +
325 + return false;
326 + }
327 +
328 + /**
329 + * Return taxonomies that need to be filtered ( post_format like )
330 + *
331 + * @since 1.7
332 + *
333 + * @param bool $filter true if we should return only valid registered taxonomies
334 + * @return array array of registered taxonomy names
335 + */
345 336 public function get_filtered_taxonomies( $filter = true ) {
346 337 if ( did_action( 'after_setup_theme' ) ) {
347 338 static $taxonomies = null;
348 339 }
@@ -350,9 +341,9 @@
350 341 if ( empty( $taxonomies ) ) {
351 342 $taxonomies = array( 'post_format' => 'post_format' );
352 343
353 344 /**
354 - * Filters the list of taxonomies not translatable but filtered by language.
345 + * Filter the list of taxonomies not translatable but filtered by language.
355 346 * Includes only the post format by default
356 347 * The filter must be added soon in the WordPress loading process:
357 348 * in a function hooked to ‘plugins_loaded’ or directly in functions.php for themes.
358 349 *
@@ -357,10 +348,10 @@
357 348 * in a function hooked to ‘plugins_loaded’ or directly in functions.php for themes.
358 349 *
359 350 * @since 1.7
360 351 *
361 - * @param string[] $taxonomies List of taxonomy names.
362 - * @param bool $is_settings True when displaying the list of custom taxonomies in Polylang settings.
352 + * @param array $taxonomies list of taxonomy names
353 + * @param bool $is_settings true when displaying the list of custom taxonomies in Polylang settings
363 354 */
364 355 $taxonomies = apply_filters( 'pll_filtered_taxonomies', $taxonomies, false );
365 356 }
366 357
@@ -367,13 +358,13 @@
367 358 return $filter ? array_intersect( $taxonomies, get_taxonomies() ) : $taxonomies;
368 359 }
369 360
370 361 /**
371 - * Returns true if Polylang filters this taxonomy per language.
362 + * Returns true if Polylang filters this taxonomy per language
372 363 *
373 364 * @since 1.7
374 365 *
375 - * @param string|string[] $tax Taxonomy name or array of taxonomy names.
366 + * @param string|array $tax taxonomy name or array of taxonomy names
376 367 * @return bool
377 368 */
378 369 public function is_filtered_taxonomy( $tax ) {
379 370 $taxonomies = $this->get_filtered_taxonomies( false );
@@ -380,9 +371,9 @@
380 371 return ( is_array( $tax ) && array_intersect( $tax, $taxonomies ) || in_array( $tax, $taxonomies ) );
381 372 }
382 373
383 374 /**
384 - * Returns the query vars of all filtered taxonomies.
375 + * Returns the query vars of all filtered taxonomies
385 376 *
386 377 * @since 1.7
387 378 *
388 379 * @return array
@@ -390,11 +381,9 @@
390 381 public function get_filtered_taxonomies_query_vars() {
391 382 $query_vars = array();
392 383 foreach ( $this->get_filtered_taxonomies() as $filtered_tax ) {
393 384 $tax = get_taxonomy( $filtered_tax );
394 - if ( ! empty( $tax ) ) {
395 - $query_vars[] = $tax->query_var;
396 - }
385 + $query_vars[] = $tax->query_var;
397 386 }
398 387 return $query_vars;
399 388 }
400 389
@@ -403,9 +392,8 @@
403 392 *
404 393 * @since 1.2
405 394 *
406 395 * @param object|string|int $lang language
407 - * @return void
408 396 */
409 397 public function create_default_category( $lang ) {
410 398 $lang = $this->get_language( $lang );
411 399
@@ -410,9 +398,9 @@
410 398 $lang = $this->get_language( $lang );
411 399
412 400 // create a new category
413 401 // FIXME this is translated in admin language when we would like it in $lang
414 - $cat_name = __( 'Uncategorized', 'polylang' );
402 + $cat_name = __( 'Uncategorized' );
415 403 $cat_slug = sanitize_title( $cat_name . '-' . $lang->slug );
416 404 $cat = wp_insert_term( $cat_name, 'category', array( 'slug' => $cat_slug ) );
417 405
418 406 // check that the category was not previously created ( in case the language was deleted and recreated )
@@ -437,24 +425,23 @@
437 425 }
438 426
439 427 /**
440 428 * It is possible to have several terms with the same name in the same taxonomy ( one per language )
441 - * but the native term_exists() will return true even if only one exists.
442 - * So here the function adds the language parameter.
429 + * but the native term_exists will return true even if only one exists
430 + * so here the function adds the language parameter
443 431 *
444 432 * @since 1.4
445 433 *
446 - * @param string $term_name The term name.
447 - * @param string $taxonomy Taxonomy name.
448 - * @param int $parent Parent term id.
449 - * @param string|PLL_Language $language The language slug or object.
450 - * @return null|int The term_id of the found term.
434 + * @param string $term_name the term name
435 + * @param string $taxonomy taxonomy name
436 + * @param int $parent parent term id
437 + * @param string|object $language the language slug or object
438 + * @return null|int the term_id of the found term
451 439 */
452 440 public function term_exists( $term_name, $taxonomy, $parent, $language ) {
453 441 global $wpdb;
454 442
455 443 $term_name = trim( wp_unslash( $term_name ) );
456 - $term_name = _wp_specialchars( $term_name );
457 444
458 445 $select = "SELECT t.term_id FROM $wpdb->terms AS t";
459 446 $join = " INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id";
460 447 $join .= $this->term->join_clause();
@@ -464,71 +451,24 @@
464 451 if ( $parent > 0 ) {
465 452 $where .= $wpdb->prepare( ' AND tt.parent = %d', $parent );
466 453 }
467 454
468 - // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
469 455 return $wpdb->get_var( $select . $join . $where );
470 456 }
471 457
472 458 /**
473 - * Checks if a term slug exists in a given language, taxonomy, hierarchy.
459 + * Gets the number of posts per language in a date, author or post type archive
474 460 *
475 - * @since 1.9
476 - * @since 2.8 Moved from PLL_Share_Term_Slug::term_exists() to PLL_Model::term_exists_by_slug().
477 - *
478 - * @param string $slug The term slug to test.
479 - * @param string|PLL_Language $language The language slug or object.
480 - * @param string $taxonomy Optional taxonomy name.
481 - * @param int $parent Optional parent term id.
482 - * @return null|int The term_id of the found term.
483 - */
484 - public function term_exists_by_slug( $slug, $language, $taxonomy = '', $parent = 0 ) {
485 - global $wpdb;
486 -
487 - $select = "SELECT t.term_id FROM {$wpdb->terms} AS t";
488 - $join = " INNER JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id";
489 - $join .= $this->term->join_clause();
490 - $where = $wpdb->prepare( ' WHERE t.slug = %s', $slug );
491 - $where .= $this->term->where_clause( $this->get_language( $language ) );
492 -
493 - if ( ! empty( $taxonomy ) ) {
494 - $where .= $wpdb->prepare( ' AND tt.taxonomy = %s', $taxonomy );
495 - }
496 -
497 - if ( $parent > 0 ) {
498 - $where .= $wpdb->prepare( ' AND tt.parent = %d', $parent );
499 - }
500 -
501 - // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
502 - return $wpdb->get_var( $select . $join . $where );
503 - }
504 -
505 -
506 - /**
507 - * Gets the number of posts per language in a date, author or post type archive.
508 - *
509 461 * @since 1.2
510 462 *
511 - * @param PLL_Language $lang PLL_Language instance.
512 - * @param array $q {
513 - * WP_Query arguments:
514 - *
515 - * @type string|string[] $post_type Post type or array of post types.
516 - * @type int $m Combination YearMonth. Accepts any four-digit year and month.
517 - * @type int $year Four-digit year.
518 - * @type int $monthnum Two-digit month.
519 - * @type int $day Day of the month.
520 - * @type int $author Author id.
521 - * @type string $author_name User 'user_nicename'.
522 - * @type string $post_format Post format.
523 - * @type string $post_status Post status.
524 - * }
463 + * @param object $lang
464 + * @param array $q WP_Query arguments ( accepted: post_type, m, year, monthnum, day, author, author_name, post_format )
525 465 * @return int
526 466 */
527 467 public function count_posts( $lang, $q = array() ) {
528 468 global $wpdb;
529 469
530 - $q = wp_parse_args( $q, array( 'post_type' => 'post', 'post_status' => 'publish' ) );
470 + $q = wp_parse_args( $q, array( 'post_type' => 'post' ) );
531 471
532 472 if ( ! is_array( $q['post_type'] ) ) {
533 473 $q['post_type'] = array( $q['post_type'] );
534 474 }
@@ -539,19 +479,19 @@
539 479 }
540 480 }
541 481
542 482 if ( empty( $q['post_type'] ) ) {
543 - $q['post_type'] = array( 'post' ); // We *need* a post type.
483 + $q['post_type'] = array( 'post' ); // we *need* a post type
544 484 }
545 485
546 - $cache_key = 'pll_count_posts_' . md5( maybe_serialize( $q ) );
547 - $counts = wp_cache_get( $cache_key, 'counts' );
486 + $cache_key = md5( serialize( $q ) );
487 + $counts = wp_cache_get( $cache_key, 'pll_count_posts' );
548 488
549 489 if ( false === $counts ) {
550 490 $select = "SELECT pll_tr.term_taxonomy_id, COUNT( * ) AS num_posts FROM {$wpdb->posts}";
551 491 $join = $this->post->join_clause();
552 - $where = sprintf( " WHERE post_status = '%s'", esc_sql( $q['post_status'] ) );
553 - $where .= sprintf( " AND {$wpdb->posts}.post_type IN ( '%s' )", implode( "', '", esc_sql( $q['post_type'] ) ) );
492 + $where = " WHERE post_status = 'publish'";
493 + $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_type IN ( '%s' )", join( "', '", $q['post_type'] ) );
554 494 $where .= $this->post->where_clause( $this->get_languages_list() );
555 495 $groupby = ' GROUP BY pll_tr.term_taxonomy_id';
556 496
557 497 if ( ! empty( $q['m'] ) ) {
@@ -577,9 +517,9 @@
577 517 $where .= $wpdb->prepare( " AND DAYOFMONTH( {$wpdb->posts}.post_date ) = %d", $q['day'] );
578 518 }
579 519
580 520 if ( ! empty( $q['author_name'] ) ) {
581 - $author = get_user_by( 'slug', sanitize_title_for_query( $q['author_name'] ) );
521 + $author = get_user_by( 'slug', sanitize_title_for_query( $q['author_name'] ) );
582 522 if ( $author ) {
583 523 $q['author'] = $author->ID;
584 524 }
585 525 }
@@ -587,9 +527,9 @@
587 527 if ( ! empty( $q['author'] ) ) {
588 528 $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_author = %d", $q['author'] );
589 529 }
590 530
591 - // Filtered taxonomies ( post_format ).
531 + // filtered taxonomies ( post_format )
592 532 foreach ( $this->get_filtered_taxonomies_query_vars() as $tax_qv ) {
593 533
594 534 if ( ! empty( $q[ $tax_qv ] ) ) {
595 535 $join .= " INNER JOIN {$wpdb->term_relationships} AS tr ON tr.object_id = {$wpdb->posts}.ID";
@@ -598,15 +538,14 @@
598 538 $where .= $wpdb->prepare( ' AND t.slug = %s', $q[ $tax_qv ] );
599 539 }
600 540 }
601 541
602 - // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
603 542 $res = $wpdb->get_results( $select . $join . $where . $groupby, ARRAY_A );
604 543 foreach ( (array) $res as $row ) {
605 544 $counts[ $row['term_taxonomy_id'] ] = $row['num_posts'];
606 545 }
607 546
608 - wp_cache_set( $cache_key, $counts, 'counts' );
547 + wp_cache_set( $cache_key, $counts, 'pll_count_posts' );
609 548 }
610 549
611 550 return empty( $counts[ $lang->term_taxonomy_id ] ) ? 0 : $counts[ $lang->term_taxonomy_id ];
612 551 }
@@ -611,27 +550,79 @@
611 550 return empty( $counts[ $lang->term_taxonomy_id ] ) ? 0 : $counts[ $lang->term_taxonomy_id ];
612 551 }
613 552
614 553 /**
615 - * Setup the links model based on options.
554 + * Setup the links model based on options
616 555 *
617 556 * @since 1.2
618 557 *
619 - * @return PLL_Links_Model
558 + * @return object implementing "links_model interface"
620 559 */
621 560 public function get_links_model() {
622 561 $c = array( 'Directory', 'Directory', 'Subdomain', 'Domain' );
623 562 $class = get_option( 'permalink_structure' ) ? 'PLL_Links_' . $c[ $this->options['force_lang'] ] : 'PLL_Links_Default';
563 + return new $class( $this );
564 + }
624 565
625 - /**
626 - * Filters the links model class to use.
627 - * /!\ this filter is fired *before* the $polylang object is available.
628 - *
629 - * @since 2.1.1
630 - *
631 - * @param string $class A class name: PLL_Links_Default, PLL_Links_Directory, PLL_Links_Subdomain, PLL_Links_Domain.
632 - */
633 - $class = apply_filters( 'pll_links_model', $class );
566 + /**
567 + * Some backward compatibility with Polylang < 1.8
568 + * allows for example to call $polylang->model->get_post_languages( $post_id ) instead of $polylang->model->post->get_language( $post_id )
569 + * this works but should be slower than the direct call, thus an error is triggered in debug mode
570 + *
571 + * @since 1.8
572 + *
573 + * @param string $func function name
574 + * @param array $args function arguments
575 + */
576 + public function __call( $func, $args ) {
577 + $f = $func;
634 578
635 - return new $class( $this );
579 + switch ( $func ) {
580 + case 'get_object_term':
581 + $o = false === strpos( $args[1], 'term' ) ? 'post' : 'term';
582 + break;
583 +
584 + case 'save_translations':
585 + case 'delete_translation':
586 + case 'get_translations':
587 + case 'get_translation':
588 + case 'join_clause':
589 + $o = ( 'post' == $args[0] || $this->is_translated_post_type( $args[0] ) ) ? 'post' : ( 'term' == $args[0] || $this->is_translated_taxonomy( $args[0] ) ? 'term' : false );
590 + unset( $args[0] );
591 + break;
592 +
593 + case 'set_post_language':
594 + case 'get_post_language':
595 + case 'set_term_language':
596 + case 'get_term_language':
597 + case 'delete_term_language':
598 + case 'get_post':
599 + case 'get_term':
600 + $str = explode( '_', $func );
601 + $f = empty( $str[2] ) ? $str[0] : $str[0] . '_' . $str[2];
602 + $o = $str[1];
603 + break;
604 +
605 + case 'where_clause':
606 + case 'get_objects_in_language':
607 + $o = $args[1];
608 + unset( $args[1] );
609 + break;
610 + }
611 +
612 + if ( ! empty( $o ) && is_object( $this->$o ) && method_exists( $this->$o, $f ) ) {
613 + if ( WP_DEBUG ) {
614 + $debug = debug_backtrace();
615 + $i = 1 + empty( $debug[1]['line'] ); // the file and line are in $debug[2] if the function was called using call_user_func
616 +
617 + trigger_error( sprintf(
618 + '%1$s was called incorrectly in %4$s on line %5$s: the call to $polylang->model->%1$s() has been deprecated in Polylang 1.8, use PLL()->model->%2$s->%3$s() instead.' . "\nError handler",
619 + $func, $o, $f, $debug[ $i ]['file'], $debug[ $i ]['line']
620 + ) );
621 + }
622 + return call_user_func_array( array( $this->$o, $f ), $args );
623 + }
624 +
625 + $debug = debug_backtrace();
626 + trigger_error( sprintf( 'Call to undefined function PLL()->model->%1$s() in %2$s on line %3$s' . "\nError handler", $func, $debug[0]['file'], $debug[0]['line'] ), E_USER_ERROR );
636 627 }
637 628 }