PluginProbe
Polylang / 3.8.8
Polylang v3.8.8
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 / src / model.php

model.php in Polylang 3.8.8, at src/model.php

617 lines 23.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package Polylang
4 */
5
6 use WP_Syntex\Polylang\Model;
7 use WP_Syntex\Polylang\Options\Options;
8
9 /**
10 * Setups the language and translations model based on WordPress taxonomies.
11 *
12 * @since 1.2
13 *
14 * @method bool has_languages() Checks if there are languages or not. See `Model\Languages::has()`.
15 * @method array get_languages_list(array $args = array()) Returns the list of available languages. See `Model\Languages::get_list()`.
16 * @method bool are_languages_ready() Tells if get_languages_list() can be used. See `Model\Languages::are_ready()`.
17 * @method void set_languages_ready() Sets the internal property `$languages_ready` to `true`, telling that get_languages_list() can be used. See `Model\Languages::set_ready()`.
18 * @method PLL_Language|false get_language(mixed $value) Returns the language by its term_id, tl_term_id, slug or locale. See `Model\Languages::get()`.
19 * @method PLL_Language|WP_Error add_language(array $args) Adds a new language and creates a default category for this language. See `Model\Languages::add()`.
20 * @method bool delete_language(int $lang_id) Deletes a language. See `Model\Languages::delete()`.
21 * @method PLL_Language|WP_Error update_language(array $args) Updates language properties. See `Model\Languages::update()`.
22 * @method PLL_Language|false get_default_language() Returns the default language. See `Model\Languages::get_default()`.
23 * @method void update_default_lang(string $slug) Updates the default language. See `Model\Languages::update_default()`.
24 * @method void maybe_create_language_terms() Maybe adds the missing language terms for 3rd party language taxonomies. See `Model\Languages::maybe_create_terms()`.
25 * @method string[] get_translated_post_types(bool $filter = true) Returns post types that need to be translated. See `Model\Post_Types::get_translated()`.
26 * @method bool is_translated_post_type(string|string[] $post_type) Returns true if Polylang manages languages and translations for this post type. See `Model\Post_Types::is_translated()`.
27 * @method string[] get_translated_taxonomies(bool $filter = true) Returns taxonomies that need to be translated. See `Model\Taxonomies::get_translated()`.
28 * @method bool is_translated_taxonomy(string|string[] $tax) Returns true if Polylang manages languages and translations for this taxonomy. See `Model\Taxonomies::is_translated()`.
29 * @method string[] get_filtered_taxonomies(bool $filter = true) Return taxonomies that need to be filtered (post_format like). See `Model\Taxonomies::get_filtered()`.
30 * @method bool is_filtered_taxonomy(string|string[] $tax) Returns true if Polylang filters this taxonomy per language. See `Model\Taxonomies::is_filtered()`.
31 * @method string[] get_filtered_taxonomies_query_vars() Returns the query vars of all filtered taxonomies. See `Model\Taxonomies::get_filtered_query_vars()`.
32 */
33 class PLL_Model {
34 /**
35 * Internal non persistent cache object.
36 *
37 * @var PLL_Cache<mixed>
38 */
39 public $cache;
40
41 /**
42 * Stores the plugin options.
43 *
44 * @var Options
45 */
46 public $options;
47
48 /**
49 * Translatable objects registry.
50 *
51 * @since 3.4
52 *
53 * @var PLL_Translatable_Objects
54 */
55 public $translatable_objects;
56
57 /**
58 * Translated post model.
59 *
60 * @var PLL_Translated_Post
61 */
62 public $post;
63
64 /**
65 * Translated term model.
66 *
67 * @var PLL_Translated_Term
68 */
69 public $term;
70
71 /**
72 * Model for the languages.
73 *
74 * @var Model\Languages
75 */
76 public $languages;
77
78 /**
79 * Model for taxonomies translated by Polylang.
80 *
81 * @var Model\Post_Types
82 */
83 public $post_types;
84
85 /**
86 * Model for taxonomies filtered/translated by Polylang.
87 *
88 * @var Model\Taxonomies
89 */
90 public $taxonomies;
91
92 /**
93 * Constructor.
94 * Setups translated objects sub models.
95 * Setups filters and actions.
96 *
97 * @since 1.2
98 * @since 3.7 Type of parameter `$options` changed from `array` to `Options`.
99 *
100 * @param Options $options Polylang options.
101 */
102 public function __construct( Options $options ) {
103 $this->options = $options;
104 $this->cache = new PLL_Cache();
105 $this->translatable_objects = new PLL_Translatable_Objects();
106 $this->languages = new Model\Languages( $this->options, $this->translatable_objects, $this->cache );
107
108 $this->languages->register_proxy( new Model\Hide_Empty() );
109 $this->languages->register_proxy( new Model\Hide_Default() );
110
111 $this->post = $this->translatable_objects->register( new PLL_Translated_Post( $this ) ); // Translated post sub model.
112 $this->term = $this->translatable_objects->register( new PLL_Translated_Term( $this ) ); // Translated term sub model.
113
114 $this->post_types = new Model\Post_Types( $this->post );
115 $this->taxonomies = new Model\Taxonomies( $this->term );
116
117 // We need to clean languages cache when editing a language and when modifying the permalink structure.
118 add_action( 'edited_term_taxonomy', array( $this, 'clean_languages_cache' ), 10, 2 );
119 add_action( 'update_option_permalink_structure', array( $this, 'clean_languages_cache' ) );
120 add_action( 'update_option_siteurl', array( $this, 'clean_languages_cache' ) );
121 add_action( 'update_option_home', array( $this, 'clean_languages_cache' ) );
122
123 add_filter( 'get_terms_args', array( $this, 'get_terms_args' ) );
124
125 // Just in case someone would like to display the language description ;).
126 add_filter( 'language_description', '__return_empty_string' );
127
128 add_action( 'delete_transient_' . Model\Languages::TRANSIENT_NAME, array( $this->languages, 'delete_transient_from_options_table' ) );
129 }
130
131 /**
132 * Backward compatibility for methods that have been moved to sub-models.
133 *
134 * @since 3.7
135 *
136 * @throws BadMethodCallException If the method is not found.
137 *
138 * @param string $name Name of the method being called.
139 * @param array $arguments Enumerated array containing the parameters passed to the $name'ed method.
140 * @return mixed
141 */
142 public function __call( string $name, array $arguments ) {
143 $methods = array(
144 // Languages.
145 'has_languages' => array( $this->languages, 'has' ),
146 'get_languages_list' => array( $this->languages, 'get_list' ),
147 'are_languages_ready' => array( $this->languages, 'are_ready' ),
148 'set_languages_ready' => array( $this->languages, 'set_ready' ),
149 'get_language' => array( $this->languages, 'get' ),
150 'add_language' => array( $this->languages, 'add' ),
151 'delete_language' => array( $this->languages, 'delete' ),
152 'update_language' => array( $this->languages, 'update' ),
153 'get_default_language' => array( $this->languages, 'get_default' ),
154 'update_default_lang' => array( $this->languages, 'update_default' ),
155 'maybe_create_language_terms' => array( $this->languages, 'maybe_create_terms' ),
156 // Post types.
157 'get_translated_post_types' => array( $this->post_types, 'get_translated' ),
158 'is_translated_post_type' => array( $this->post_types, 'is_translated' ),
159 // Taxonomies.
160 'get_translated_taxonomies' => array( $this->taxonomies, 'get_translated' ),
161 'is_translated_taxonomy' => array( $this->taxonomies, 'is_translated' ),
162 'get_filtered_taxonomies' => array( $this->taxonomies, 'get_filtered' ),
163 'is_filtered_taxonomy' => array( $this->taxonomies, 'is_filtered' ),
164 'get_filtered_taxonomies_query_vars' => array( $this->taxonomies, 'get_filtered_query_vars' ),
165 );
166
167 if ( isset( $methods[ $name ] ) ) {
168 return call_user_func_array( $methods[ $name ], $arguments );
169 }
170
171 $debug = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions
172 throw new BadMethodCallException(
173 sprintf(
174 'Call to undefined method PLL()->model->%1$s() in %2$s on line %3$s' . "\nError handler",
175 esc_html( $name ),
176 esc_html( $debug[0]['file'] ?? '' ),
177 absint( $debug[0]['line'] ?? 0 )
178 )
179 );
180 }
181
182 /**
183 * Cleans language cache
184 * can be called directly with no parameter
185 * called by the 'edited_term_taxonomy' filter with 2 parameters when count needs to be updated
186 *
187 * @since 1.2
188 *
189 * @param int $term not used
190 * @param string $taxonomy taxonomy name
191 * @return void
192 */
193 public function clean_languages_cache( $term = 0, $taxonomy = null ): void {
194 if ( empty( $taxonomy ) || 'language' === $taxonomy ) {
195 $this->languages->clean_cache();
196 }
197 }
198
199 /**
200 * Don't query term metas when only our taxonomies are queried
201 *
202 * @since 2.3
203 *
204 * @param array $args WP_Term_Query arguments
205 * @return array
206 */
207 public function get_terms_args( $args ) {
208 $taxonomies = $this->translatable_objects->get_taxonomy_names();
209
210 if ( isset( $args['taxonomy'] ) && ! array_diff( (array) $args['taxonomy'], $taxonomies ) ) {
211 $args['update_term_meta_cache'] = false;
212 }
213 return $args;
214 }
215
216 /**
217 * Adds terms clauses to the term query to filter them by languages.
218 *
219 * @since 1.2
220 * @since 3.8 Accepts an object or an array of objects for the second param.
221 *
222 * @param string[] $clauses The list of sql clauses in terms query.
223 * @param PLL_Language[]|PLL_Language $languages `PLL_Language` object or array of `PLL_Language` objects.
224 * @return string[] Modified list of clauses.
225 */
226 public function terms_clauses( $clauses, $languages ) {
227 if ( ! empty( $languages ) && false === strpos( $clauses['join'], 'pll_tr' ) ) {
228 $clauses['join'] .= $this->term->join_clause();
229 $clauses['where'] .= $this->term->where_clause( $languages );
230 }
231 return $clauses;
232 }
233
234 /**
235 * It is possible to have several terms with the same name in the same taxonomy ( one per language )
236 * but the native term_exists() will return true even if only one exists.
237 * So here the function adds the language parameter.
238 *
239 * @since 1.4
240 *
241 * @param string $term_name The term name.
242 * @param string $taxonomy Taxonomy name.
243 * @param int $parent Parent term id.
244 * @param string|PLL_Language $language The language slug or object.
245 * @return int The `term_id` of the found term. 0 otherwise.
246 *
247 * @phpstan-return int<0, max>
248 */
249 public function term_exists( $term_name, $taxonomy, $parent, $language ): int {
250 global $wpdb;
251
252 $language = $this->languages->get( $language );
253 if ( empty( $language ) ) {
254 return 0;
255 }
256
257 $term_name = trim( wp_unslash( $term_name ) );
258 $term_name = _wp_specialchars( $term_name );
259
260 $select = "SELECT t.term_id FROM $wpdb->terms AS t";
261 $join = " INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id";
262 $join .= $this->term->join_clause();
263 $where = $wpdb->prepare( ' WHERE tt.taxonomy = %s AND t.name = %s', $taxonomy, $term_name );
264 $where .= $this->term->where_clause( $language );
265
266 if ( $parent > 0 ) {
267 $where .= $wpdb->prepare( ' AND tt.parent = %d', $parent );
268 }
269
270 // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
271 $term_id = $wpdb->get_var( $select . $join . $where );
272 return max( 0, (int) $term_id );
273 }
274
275 /**
276 * Checks if a term slug exists in a given language, taxonomy, hierarchy.
277 *
278 * @since 1.9
279 * @since 2.8 Moved from PLL_Share_Term_Slug::term_exists() to PLL_Model::term_exists_by_slug().
280 * @since 3.8 Refactored to use `get_terms()` instead of direct SQL query.
281 *
282 * @param string $slug The term slug to test.
283 * @param string|PLL_Language $language The language slug or object.
284 * @param string $taxonomy Optional taxonomy name.
285 * @param int $parent Optional parent term id.
286 * @return int The `term_id` of the found term. 0 otherwise.
287 */
288 public function term_exists_by_slug( $slug, $language, $taxonomy = '', $parent = 0 ): int {
289 $language = $this->languages->get( $language );
290 if ( empty( $language ) ) {
291 return 0;
292 }
293
294 $args = array(
295 'slug' => $slug,
296 'hide_empty' => false,
297 'fields' => 'ids',
298 'lang' => $language->slug,
299 'update_term_meta_cache' => false,
300 );
301
302 if ( ! empty( $taxonomy ) ) {
303 $args['taxonomy'] = $taxonomy;
304 }
305
306 if ( $parent > 0 ) {
307 $args['parent'] = $parent;
308 }
309
310 $terms = get_terms( $args );
311
312 return ! empty( $terms ) && is_array( $terms ) ? (int) reset( $terms ) : 0;
313 }
314
315 /**
316 * Returns the number of posts per language in a date, author or post type archive.
317 *
318 * @since 1.2
319 *
320 * @param PLL_Language $lang PLL_Language instance.
321 * @param array $q {
322 * WP_Query arguments:
323 *
324 * @type string|string[] $post_type Post type or array of post types.
325 * @type int $m Combination YearMonth. Accepts any four-digit year and month.
326 * @type int $year Four-digit year.
327 * @type int $monthnum Two-digit month.
328 * @type int $day Day of the month.
329 * @type int $author Author id.
330 * @type string $author_name User 'user_nicename'.
331 * @type string $post_format Post format.
332 * @type string $post_status Post status.
333 * }
334 * @return int
335 *
336 * @phpstan-param array{
337 * post_type?: non-falsy-string|array<non-falsy-string>,
338 * post_status?: non-falsy-string,
339 * m?: numeric-string,
340 * year?: positive-int,
341 * monthnum?: int<1, 12>,
342 * day?: int<1, 31>,
343 * author?: int<1, max>,
344 * author_name?: non-falsy-string,
345 * post_format?: non-falsy-string
346 * } $q
347 * @phpstan-return int<0, max>
348 */
349 public function count_posts( $lang, $q = array() ): int {
350 global $wpdb;
351
352 $q = array_merge( array( 'post_type' => 'post', 'post_status' => 'publish' ), $q );
353
354 if ( ! is_array( $q['post_type'] ) ) {
355 $q['post_type'] = array( $q['post_type'] );
356 }
357
358 foreach ( $q['post_type'] as $key => $type ) {
359 if ( ! post_type_exists( $type ) ) {
360 unset( $q['post_type'][ $key ] );
361 }
362 }
363
364 if ( empty( $q['post_type'] ) ) {
365 $q['post_type'] = array( 'post' ); // We *need* a post type.
366 }
367
368 $cache_key = $this->cache->get_unique_key( 'pll_count_posts_', $q );
369 $counts = wp_cache_get( $cache_key, 'counts' );
370
371 if ( ! is_array( $counts ) ) {
372 $counts = array();
373 $select = "SELECT pll_tr.term_taxonomy_id, COUNT( * ) AS num_posts FROM {$wpdb->posts}";
374 $join = $this->post->join_clause();
375 $where = sprintf( " WHERE post_status = '%s'", esc_sql( $q['post_status'] ) );
376 $where .= sprintf( " AND {$wpdb->posts}.post_type IN ( '%s' )", implode( "', '", esc_sql( $q['post_type'] ) ) );
377 $where .= $this->post->where_clause( $this->languages->get_list() );
378 $groupby = ' GROUP BY pll_tr.term_taxonomy_id';
379
380 if ( ! empty( $q['m'] ) ) {
381 $q['m'] = '' . preg_replace( '|[^0-9]|', '', $q['m'] );
382 $where .= $wpdb->prepare( " AND YEAR( {$wpdb->posts}.post_date ) = %d", substr( $q['m'], 0, 4 ) );
383 if ( strlen( $q['m'] ) > 5 ) {
384 $where .= $wpdb->prepare( " AND MONTH( {$wpdb->posts}.post_date ) = %d", substr( $q['m'], 4, 2 ) );
385 }
386 if ( strlen( $q['m'] ) > 7 ) {
387 $where .= $wpdb->prepare( " AND DAYOFMONTH( {$wpdb->posts}.post_date ) = %d", substr( $q['m'], 6, 2 ) );
388 }
389 }
390
391 if ( ! empty( $q['year'] ) ) {
392 $where .= $wpdb->prepare( " AND YEAR( {$wpdb->posts}.post_date ) = %d", $q['year'] );
393 }
394
395 if ( ! empty( $q['monthnum'] ) ) {
396 $where .= $wpdb->prepare( " AND MONTH( {$wpdb->posts}.post_date ) = %d", $q['monthnum'] );
397 }
398
399 if ( ! empty( $q['day'] ) ) {
400 $where .= $wpdb->prepare( " AND DAYOFMONTH( {$wpdb->posts}.post_date ) = %d", $q['day'] );
401 }
402
403 if ( ! empty( $q['author_name'] ) ) {
404 $author = get_user_by( 'slug', sanitize_title_for_query( $q['author_name'] ) );
405 if ( $author ) {
406 $q['author'] = $author->ID;
407 }
408 }
409
410 if ( ! empty( $q['author'] ) ) {
411 $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_author = %d", $q['author'] );
412 }
413
414 // Filtered taxonomies ( post_format ).
415 foreach ( $this->taxonomies->get_filtered_query_vars() as $tax_qv ) {
416
417 if ( ! empty( $q[ $tax_qv ] ) ) {
418 $join .= " INNER JOIN {$wpdb->term_relationships} AS tr ON tr.object_id = {$wpdb->posts}.ID";
419 $join .= " INNER JOIN {$wpdb->term_taxonomy} AS tt ON tt.term_taxonomy_id = tr.term_taxonomy_id";
420 $join .= " INNER JOIN {$wpdb->terms} AS t ON t.term_id = tt.term_id";
421 $where .= $wpdb->prepare( ' AND t.slug = %s', $q[ $tax_qv ] );
422 }
423 }
424
425 // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
426 $res = $wpdb->get_results( $select . $join . $where . $groupby, ARRAY_A );
427 foreach ( (array) $res as $row ) {
428 $counts[ $row['term_taxonomy_id'] ] = $row['num_posts'];
429 }
430
431 wp_cache_set( $cache_key, $counts, 'counts' );
432 }
433
434 $term_taxonomy_id = $lang->get_tax_prop( 'language', 'term_taxonomy_id' );
435 return empty( $counts[ $term_taxonomy_id ] ) ? 0 : $counts[ $term_taxonomy_id ];
436 }
437
438 /**
439 * Setup the links model based on options.
440 *
441 * @since 1.2
442 *
443 * @return PLL_Links_Model
444 */
445 public function get_links_model(): PLL_Links_Model {
446 $c = array( 'Directory', 'Directory', 'Subdomain', 'Domain' );
447 $class = get_option( 'permalink_structure' ) ? 'PLL_Links_' . $c[ $this->options['force_lang'] ] : 'PLL_Links_Default';
448
449 /**
450 * Filters the links model class to use.
451 * /!\ this filter is fired *before* the $polylang object is available.
452 *
453 * @since 2.1.1
454 *
455 * @param string $class A class name: PLL_Links_Default, PLL_Links_Directory, PLL_Links_Subdomain, PLL_Links_Domain.
456 */
457 $class = apply_filters( 'pll_links_model', $class );
458
459 return new $class( $this );
460 }
461
462 /**
463 * Returns a list of object IDs without language (used in settings and wizard).
464 *
465 * @since 0.9
466 * @since 2.2.6 Added the `$limit` parameter.
467 * @since 3.4 Added the `$types` parameter.
468 *
469 * @param int $limit Optional. Max number of IDs to return. Defaults to -1 (no limit).
470 * @param string[] $types Optional. Types to handle (@see PLL_Translatable_Object::get_type()). Defaults to
471 * an empty array (all types).
472 * @return int[][]|false {
473 * IDs of objects without language.
474 *
475 * @type int[] $posts Array of post ids.
476 * @type int[] $terms Array of term ids.
477 * }
478 *
479 * @phpstan-param -1|positive-int $limit
480 */
481 public function get_objects_with_no_lang( $limit = -1, array $types = array() ) {
482 /**
483 * Filters the max number of IDs to return when searching objects with no language.
484 * This filter can be used to decrease the memory usage in case the number of objects
485 * without language is too big. Using a negative value is equivalent to have no limit.
486 *
487 * @since 2.2.6
488 * @since 3.4 Added the `$types` parameter.
489 *
490 * @param int $limit Max number of IDs to retrieve from the database.
491 * @param string[] $types Types to handle (@see PLL_Translatable_Object::get_type()). An empty array means all
492 * types.
493 */
494 $limit = apply_filters( 'get_objects_with_no_lang_limit', $limit, $types );
495 $limit = $limit < 1 ? -1 : max( (int) $limit, 1 );
496 $objects = array();
497
498 foreach ( $this->translatable_objects as $type => $object ) {
499 if ( ! empty( $types ) && ! in_array( $type, $types, true ) ) {
500 continue;
501 }
502
503 $ids = $object->get_objects_with_no_lang( $limit );
504
505 if ( empty( $ids ) ) {
506 continue;
507 }
508
509 // The trailing 's' in the array key is for backward compatibility.
510 $objects[ "{$type}s" ] = $ids;
511 }
512
513 $objects = ! empty( $objects ) ? $objects : false;
514
515 /**
516 * Filters the list of IDs of untranslated objects.
517 *
518 * @since 0.9
519 * @since 3.4 Added the `$limit` and `$types` parameters.
520 *
521 * @param int[][]|false $objects List of lists of object IDs, `false` if no IDs found.
522 * @param int $limit Max number of IDs to retrieve from the database.
523 * @param string[] $types Types to handle (@see PLL_Translatable_Object::get_type()). An empty array
524 * means all types.
525 */
526 return apply_filters( 'pll_get_objects_with_no_lang', $objects, $limit, $types );
527 }
528
529 /**
530 * Returns ids of post without language.
531 *
532 * @since 3.1
533 *
534 * @param string|string[] $post_types A translated post type or an array of translated post types.
535 * @param int $limit Max number of objects to return. `-1` to return all of them.
536 * @return int[]
537 *
538 * @phpstan-param -1|positive-int $limit
539 * @phpstan-return list<positive-int>
540 */
541 public function get_posts_with_no_lang( $post_types, $limit ): array {
542 return $this->translatable_objects->get( 'post' )->get_objects_with_no_lang( $limit, (array) $post_types );
543 }
544
545 /**
546 * Returns ids of terms without language.
547 *
548 * @since 3.1
549 *
550 * @param string|string[] $taxonomies A translated taxonomy or an array of taxonomies post types.
551 * @param int $limit Max number of objects to return. `-1` to return all of them.
552 * @return int[]
553 *
554 * @phpstan-param -1|positive-int $limit
555 * @phpstan-return list<positive-int>
556 */
557 public function get_terms_with_no_lang( $taxonomies, $limit ): array {
558 return $this->translatable_objects->get( 'term' )->get_objects_with_no_lang( $limit, (array) $taxonomies );
559 }
560
561 /**
562 * Assigns the default language to objects in mass.
563 *
564 * @since 1.2
565 * @since 3.4 Moved from PLL_Admin_Model class.
566 * Removed `$limit` parameter, added `$lang` and `$types` parameters.
567 *
568 * @param PLL_Language|null $lang Optional. The language to assign to objects. Defaults to `null` (default language).
569 * @param string[] $types Optional. Types to handle (@see PLL_Translatable_Object::get_type()). Defaults
570 * to an empty array (all types).
571 * @return void
572 */
573 public function set_language_in_mass( $lang = null, array $types = array() ): void {
574 if ( ! $lang instanceof PLL_Language ) {
575 $lang = $this->languages->get_default();
576
577 if ( empty( $lang ) ) {
578 return;
579 }
580 }
581
582 // 1000 is an arbitrary value that will be filtered by `get_objects_with_no_lang_limit`.
583 $nolang = $this->get_objects_with_no_lang( 1000, $types );
584
585 if ( empty( $nolang ) ) {
586 return;
587 }
588
589 /**
590 * Keep track of types where we set the language:
591 * those are types where we may have more items to process if we have more than 1000 items in total.
592 * This will prevent unnecessary SQL queries in the next recursion: if we have 0 items in this recursion for
593 * a type, we'll still have 0 in the next one, no need for a new query.
594 */
595 $types_with_objects = array();
596
597 foreach ( $this->translatable_objects as $type => $object ) {
598 if ( empty( $nolang[ "{$type}s" ] ) ) {
599 continue;
600 }
601
602 if ( ! empty( $types ) && ! in_array( $type, $types, true ) ) {
603 continue;
604 }
605
606 $object->set_language_in_mass( $nolang[ "{$type}s" ], $lang );
607 $types_with_objects[] = $type;
608 }
609
610 if ( empty( $types_with_objects ) ) {
611 return;
612 }
613
614 $this->set_language_in_mass( $lang, $types_with_objects );
615 }
616 }
617