PluginProbe
Polylang / 2.7.1
Polylang v2.7.1
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 2.7.1, at include/model.php

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