PluginProbe
Polylang / 3.7.1
Polylang v3.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
← All changes | include/language.php +575 -208 2.73.7.1 View file →
@@ -1,303 +1,670 @@
1 1 <?php
2 +/**
3 + * @package Polylang
4 + */
2 5
3 6 /**
4 - * A language object is made of two terms in 'language' and 'term_language' taxonomies
5 - * manipulating only one object per language instead of two terms should make things easier
7 + * A language object is made of two terms in 'language' and 'term_language' taxonomies.
8 + * Manipulating only one object per language instead of two terms should make things easier.
6 9 *
7 - * Properties:
8 - * term_id => id of term in 'language' taxonomy
9 - * name => language name. Ex: English
10 - * slug => language code used in url. Ex: en
11 - * term_group => order of the language when displayed in a list of languages
12 - * term_taxonomy_id => term taxonomy id in 'language' taxonomy
13 - * taxonomy => 'language'
14 - * description => language locale for backward compatibility
15 - * parent => 0 / not used
16 - * count => number of posts and pages in that language
17 - * tl_term_id => id of the term in 'term_language' taxonomy
18 - * tl_term_taxonomy_id => term taxonomy id in 'term_language' taxonomy
19 - * tl_count => number of terms in that language ( not used by Polylang )
20 - * locale => WordPress language locale. Ex: en_US
21 - * is_rtl => 1 if the language is rtl
22 - * w3c => W3C locale
23 - * flag_code => code of the flag
24 - * flag_url => url of the flag
25 - * flag => html img of the flag
26 - * custom_flag_url => url of the custom flag if exists, internal use only, moves to flag_url on frontend
27 - * custom_flag => html img of the custom flag if exists, internal use only, moves to flag on frontend
28 - * home_url => home url in this language
29 - * search_url => home url to use in search forms
30 - * host => host of this language
31 - * mo_id => id of the post storing strings translations
32 - * page_on_front => id of the page on front in this language ( set from pll_languages_list filter )
33 - * page_for_posts => id of the page for posts in this language ( set from pll_languages_list filter )
10 + * @since 1.2
11 + * @immutable
34 12 *
35 - * @since 1.2
13 + * @phpstan-type LanguagePropData array{
14 + * term_id: positive-int,
15 + * term_taxonomy_id: positive-int,
16 + * count: int<0, max>
17 + * }
18 + * @phpstan-type LanguageData array{
19 + * term_props: array{
20 + * language: LanguagePropData,
21 + * }&array<non-empty-string, LanguagePropData>,
22 + * name: non-empty-string,
23 + * slug: non-empty-string,
24 + * locale: non-empty-string,
25 + * w3c: non-empty-string,
26 + * flag_code: non-empty-string,
27 + * term_group: int,
28 + * is_rtl: int<0, 1>,
29 + * facebook?: string,
30 + * home_url: non-empty-string,
31 + * search_url: non-empty-string,
32 + * host: non-empty-string,
33 + * flag_url: non-empty-string,
34 + * flag: non-empty-string,
35 + * custom_flag_url?: string,
36 + * custom_flag?: string,
37 + * page_on_front: int<0, max>,
38 + * page_for_posts: int<0, max>,
39 + * active: bool,
40 + * fallbacks?: array<non-empty-string>,
41 + * is_default: bool
42 + * }
36 43 */
37 -class PLL_Language {
38 - public $term_id, $name, $slug, $term_group, $term_taxonomy_id, $taxonomy, $description, $parent, $count;
39 - public $tl_term_id, $tl_term_taxonomy_id, $tl_count;
40 - public $locale, $is_rtl;
41 - public $w3c, $facebook;
42 - public $flag_url, $flag;
43 - public $home_url, $search_url;
44 - public $host, $mo_id;
45 - public $page_on_front, $page_for_posts;
44 +class PLL_Language extends PLL_Language_Deprecated {
46 45
47 46 /**
48 - * Constructor: builds a language object given its two corresponding terms in language and term_language taxonomies
47 + * Language name. Ex: English.
49 48 *
49 + * @var string
50 + *
51 + * @phpstan-var non-empty-string
52 + */
53 + public $name;
54 +
55 + /**
56 + * Language code used in URL. Ex: en.
57 + *
58 + * @var string
59 + *
60 + * @phpstan-var non-empty-string
61 + */
62 + public $slug;
63 +
64 + /**
65 + * Order of the language when displayed in a list of languages.
66 + *
67 + * @var int
68 + */
69 + public $term_group;
70 +
71 + /**
72 + * ID of the term in 'language' taxonomy.
73 + * Duplicated from `$this->term_props['language']['term_id'],
74 + * but kept to facilitate the use of it.
75 + *
76 + * @var int
77 + *
78 + * @phpstan-var int<1, max>
79 + */
80 + public $term_id;
81 +
82 + /**
83 + * WordPress language locale. Ex: en_US.
84 + *
85 + * @var string
86 + *
87 + * @phpstan-var non-empty-string
88 + */
89 + public $locale;
90 +
91 + /**
92 + * 1 if the language is rtl, 0 otherwise.
93 + *
94 + * @var int
95 + *
96 + * @phpstan-var int<0, 1>
97 + */
98 + public $is_rtl;
99 +
100 + /**
101 + * W3C locale.
102 + *
103 + * @var string
104 + *
105 + * @phpstan-var non-empty-string
106 + */
107 + public $w3c;
108 +
109 + /**
110 + * Facebook locale.
111 + *
112 + * @var string
113 + */
114 + public $facebook = '';
115 +
116 + /**
117 + * Home URL in this language.
118 + *
119 + * @var string
120 + *
121 + * @phpstan-var non-empty-string
122 + */
123 + private $home_url;
124 +
125 + /**
126 + * Home URL to use in search forms.
127 + *
128 + * @var string
129 + *
130 + * @phpstan-var non-empty-string
131 + */
132 + private $search_url;
133 +
134 + /**
135 + * Host corresponding to this language.
136 + *
137 + * @var string
138 + *
139 + * @phpstan-var non-empty-string
140 + */
141 + public $host;
142 +
143 + /**
144 + * ID of the page on front in this language (set from pll_additional_language_data filter).
145 + *
146 + * @var int
147 + *
148 + * @phpstan-var int<0, max>
149 + */
150 + public $page_on_front = 0;
151 +
152 + /**
153 + * ID of the page for posts in this language (set from pll_additional_language_data filter).
154 + *
155 + * @var int
156 + *
157 + * @phpstan-var int<0, max>
158 + */
159 + public $page_for_posts = 0;
160 +
161 + /**
162 + * Code of the flag.
163 + *
164 + * @var string
165 + *
166 + * @phpstan-var non-empty-string
167 + */
168 + public $flag_code;
169 +
170 + /**
171 + * URL of the flag. Always set to the main domain.
172 + *
173 + * @var string
174 + *
175 + * @phpstan-var non-empty-string
176 + */
177 + public $flag_url;
178 +
179 + /**
180 + * HTML markup of the flag.
181 + *
182 + * @var string
183 + *
184 + * @phpstan-var non-empty-string
185 + */
186 + public $flag;
187 +
188 + /**
189 + * URL of the custom flag if it exists. Always set to the main domain.
190 + *
191 + * @var string
192 + */
193 + public $custom_flag_url = '';
194 +
195 + /**
196 + * HTML markup of the custom flag if it exists.
197 + *
198 + * @var string
199 + */
200 + public $custom_flag = '';
201 +
202 + /**
203 + * Whether or not the language is active. Default `true`.
204 + *
205 + * @var bool
206 + */
207 + public $active = true;
208 +
209 + /**
210 + * List of WordPress language locales. Ex: array( 'en_GB' ).
211 + *
212 + * @var string[]
213 + *
214 + * @phpstan-var list<non-empty-string>
215 + */
216 + public $fallbacks = array();
217 +
218 + /**
219 + * Whether the language is the default one.
220 + *
221 + * @var bool
222 + */
223 + public $is_default;
224 +
225 + /**
226 + * Stores language term properties (like term IDs and counts) for each language taxonomy (`language`,
227 + * `term_language`, etc).
228 + * This stores the values of the properties `$term_id` + `$term_taxonomy_id` + `$count` (`language`), `$tl_term_id`
229 + * + `$tl_term_taxonomy_id` + `$tl_count` (`term_language`), and the `term_id` + `term_taxonomy_id` + `count` for
230 + * other language taxonomies.
231 + *
232 + * @var array[] Array keys are language term names.
233 + *
234 + * @example array(
235 + * 'language' => array(
236 + * 'term_id' => 7,
237 + * 'term_taxonomy_id' => 8,
238 + * 'count' => 11,
239 + * ),
240 + * 'term_language' => array(
241 + * 'term_id' => 11,
242 + * 'term_taxonomy_id' => 12,
243 + * 'count' => 6,
244 + * ),
245 + * 'foo_language' => array(
246 + * 'term_id' => 33,
247 + * 'term_taxonomy_id' => 34,
248 + * 'count' => 0,
249 + * ),
250 + * )
251 + *
252 + * @phpstan-var array{
253 + * language: LanguagePropData,
254 + * }
255 + * &array<non-empty-string, LanguagePropData>
256 + */
257 + protected $term_props;
258 +
259 + /**
260 + * Constructor: builds a language object given the corresponding data.
261 + *
50 262 * @since 1.2
263 + * @since 3.4 Only accepts one argument.
51 264 *
52 - * @param object|array $language 'language' term or language object properties stored as an array
53 - * @param object $term_language Corresponding 'term_language' term
265 + * @param array $language_data {
266 + * Language object properties stored as an array.
267 + *
268 + * @type array[] $term_props An array of language term properties. Array keys are language taxonomy names
269 + * (`language` and `term_language` are mandatory), array values are arrays of
270 + * language term properties (`term_id`, `term_taxonomy_id`, and `count`).
271 + * @type string $name Language name. Ex: English.
272 + * @type string $slug Language code used in URL. Ex: en.
273 + * @type string $locale WordPress language locale. Ex: en_US.
274 + * @type string $w3c W3C locale.
275 + * @type string $flag_code Code of the flag.
276 + * @type int $term_group Order of the language when displayed in a list of languages.
277 + * @type int $is_rtl `1` if the language is rtl, `0` otherwise.
278 + * @type string $facebook Optional. Facebook locale.
279 + * @type string $home_url Home URL in this language.
280 + * @type string $search_url Home URL to use in search forms.
281 + * @type string $host Host corresponding to this language.
282 + * @type string $flag_url URL of the flag.
283 + * @type string $flag HTML markup of the flag.
284 + * @type string $custom_flag_url Optional. URL of the custom flag if it exists.
285 + * @type string $custom_flag Optional. HTML markup of the custom flag if it exists.
286 + * @type int $page_on_front Optional. ID of the page on front in this language.
287 + * @type int $page_for_posts Optional. ID of the page for posts in this language.
288 + * @type bool $active Whether or not the language is active. Default `true`.
289 + * @type string[] $fallbacks List of WordPress language locales. Ex: array( 'en_GB' ).
290 + * @type bool $is_default Whether or not the language is the default one.
291 + * }
292 + *
293 + * @phpstan-param LanguageData $language_data
54 294 */
55 - public function __construct( $language, $term_language = null ) {
56 - // Build the object from all properties stored as an array
57 - if ( empty( $term_language ) ) {
58 - foreach ( $language as $prop => $value ) {
59 - $this->$prop = $value;
60 - }
295 + public function __construct( array $language_data ) {
296 + foreach ( $language_data as $prop => $value ) {
297 + $this->$prop = $value;
61 298 }
62 299
63 - // Build the object from taxonomies
64 - else {
65 - foreach ( $language as $prop => $value ) {
66 - $this->$prop = in_array( $prop, array( 'term_id', 'term_taxonomy_id', 'count' ) ) ? (int) $language->$prop : $language->$prop;
67 - }
300 + $this->term_id = $this->term_props['language']['term_id'];
301 + }
68 302
69 - $this->tl_term_id = (int) $term_language->term_id;
70 - $this->tl_term_taxonomy_id = (int) $term_language->term_taxonomy_id;
71 - $this->tl_count = (int) $term_language->count;
303 + /**
304 + * Returns a language term property value (term ID, term taxonomy ID, or count).
305 + *
306 + * @since 3.4
307 + *
308 + * @param string $taxonomy_name Name of the taxonomy.
309 + * @param string $prop_name Name of the property: 'term_taxonomy_id', 'term_id', 'count'.
310 + * @return int
311 + *
312 + * @phpstan-param non-empty-string $taxonomy_name
313 + * @phpstan-param 'term_taxonomy_id'|'term_id'|'count' $prop_name
314 + * @phpstan-return int<0, max>
315 + */
316 + public function get_tax_prop( $taxonomy_name, $prop_name ) {
317 + return $this->term_props[ $taxonomy_name ][ $prop_name ] ?? 0;
318 + }
72 319
73 - // The description field can contain any property
74 - // Backward compatibility for is_rtl
75 - $description = maybe_unserialize( $language->description );
76 - foreach ( $description as $prop => $value ) {
77 - 'rtl' == $prop ? $this->is_rtl = $value : $this->$prop = $value;
78 - }
320 + /**
321 + * Returns the language term props for all content types.
322 + *
323 + * @since 3.4
324 + *
325 + * @param string $property Name of the field to return. An empty string to return them all.
326 + * @return (int[]|int)[] Array keys are taxonomy names, array values depend of `$property`.
327 + *
328 + * @phpstan-param 'term_taxonomy_id'|'term_id'|'count'|'' $property
329 + * @phpstan-return array<non-empty-string, (
330 + * $property is non-empty-string ?
331 + * (
332 + * $property is 'count' ?
333 + * int<0, max> :
334 + * positive-int
335 + * ) :
336 + * LanguagePropData
337 + * )>
338 + */
339 + public function get_tax_props( $property = '' ) {
340 + if ( empty( $property ) ) {
341 + return $this->term_props;
342 + }
79 343
80 - $this->description = &$this->locale; // Backward compatibility with Polylang < 1.2
344 + $term_props = array();
81 345
82 - $this->mo_id = PLL_MO::get_id( $this );
346 + foreach ( $this->term_props as $taxonomy_name => $props ) {
347 + $term_props[ $taxonomy_name ] = $props[ $property ];
348 + }
83 349
84 - $languages = include PLL_SETTINGS_INC . '/languages.php';
85 - $this->w3c = isset( $languages[ $this->locale ]['w3c'] ) ? $languages[ $this->locale ]['w3c'] : str_replace( '_', '-', $this->locale );
86 - if ( isset( $languages[ $this->locale ]['facebook'] ) ) {
87 - $this->facebook = $languages[ $this->locale ]['facebook'];
88 - }
89 - }
350 + return $term_props;
90 351 }
91 352
92 353 /**
93 - * Get the flag informations
94 - * 'url' => Flag url
95 - * 'src' => Optional, src attribute value if different of the url, for example if base64 encoded
96 - * 'width' => Optional, flag width in pixels
97 - * 'height' => Optional, flag height in pixels
354 + * Returns the flag information.
98 355 *
99 356 * @since 2.6
100 357 *
101 358 * @param string $code Flag code.
102 - * @return array Flag informations.
359 + * @return array {
360 + * Flag information.
361 + *
362 + * @type string $url Flag url.
363 + * @type string $src Optional, src attribute value if different of the url, for example if base64 encoded.
364 + * @type int $width Optional, flag width in pixels.
365 + * @type int $height Optional, flag height in pixels.
366 + * }
367 + *
368 + * @phpstan-return array{
369 + * url: string,
370 + * src: string,
371 + * width?: positive-int,
372 + * height?: positive-int
373 + * }
103 374 */
104 - public static function get_flag_informations( $code ) {
105 - $flag = array( 'url' => '' );
375 + public static function get_flag_information( $code ) {
376 + $default_flag = array(
377 + 'url' => '',
378 + 'src' => '',
379 + );
106 380
107 - // Polylang builtin flags
108 - if ( ! empty( $code ) && file_exists( POLYLANG_DIR . ( $file = '/flags/' . $code . '.png' ) ) ) {
109 - $flag['url'] = $_url = plugins_url( $file, POLYLANG_FILE );
381 + // Polylang builtin flags.
382 + if ( ! empty( $code ) && is_readable( POLYLANG_DIR . ( $file = '/flags/' . $code . '.png' ) ) ) {
383 + $default_flag['url'] = plugins_url( $file, POLYLANG_FILE );
384 +
385 + // If base64 encoded flags are preferred.
386 + if ( pll_get_constant( 'PLL_ENCODED_FLAGS', true ) ) {
387 + $imagesize = getimagesize( POLYLANG_DIR . $file );
388 + if ( is_array( $imagesize ) ) {
389 + list( $default_flag['width'], $default_flag['height'] ) = $imagesize;
390 + }
391 + $file_contents = file_get_contents( POLYLANG_DIR . $file ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
392 + $default_flag['src'] = 'data:image/png;base64,' . base64_encode( $file_contents ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
393 + }
110 394 }
111 395
112 396 /**
113 - * Filter flag informations
114 - * 'url' => Flag url
115 - * 'src' => Optional, src attribute value if different of the url, for example if base64 encoded
116 - * 'width' => Optional, flag width in pixels
117 - * 'height' => Optional, flag height in pixels
397 + * Filters flag information:
118 398 *
119 399 * @since 2.4
120 400 *
121 - * @param array $flag Information about the flag
122 - * @param string $code Flag code
401 + * @param array $flag {
402 + * Information about the flag.
403 + *
404 + * @type string $url Flag url.
405 + * @type string $src Optional, src attribute value if different of the url, for example if base64 encoded.
406 + * @type int $width Optional, flag width in pixels.
407 + * @type int $height Optional, flag height in pixels.
408 + * }
409 + * @param string $code Flag code.
123 410 */
124 - $flag = apply_filters( 'pll_flag', $flag, $code );
411 + $flag = apply_filters( 'pll_flag', $default_flag, $code );
125 412
126 - if ( empty( $flag['src'] ) ) {
127 - // If using predefined flags and base64 encoded flags are preferred
128 - if ( isset( $_url ) && $flag['url'] === $_url && ( ! defined( 'PLL_ENCODED_FLAGS' ) || PLL_ENCODED_FLAGS ) ) {
129 - list( $flag['width'], $flag['height'] ) = getimagesize( POLYLANG_DIR . $file );
130 - $file_contents = file_get_contents( POLYLANG_DIR . $file ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
131 - $flag['src'] = 'data:image/png;base64,' . base64_encode( $file_contents ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
132 - } else {
133 - $flag['src'] = esc_url( set_url_scheme( $flag['url'], 'relative' ) );
134 - }
413 + $flag['url'] = sanitize_url( $flag['url'] );
414 +
415 + if ( empty( $flag['src'] ) || ( $flag['src'] === $default_flag['src'] && $flag['url'] !== $default_flag['url'] ) ) {
416 + $flag['src'] = esc_url( set_url_scheme( $flag['url'], 'relative' ) );
135 417 }
136 418
137 - $flag['url'] = esc_url_raw( $flag['url'] );
138 -
139 419 return $flag;
140 420 }
141 421
142 422 /**
143 - * Sets flag_url and flag properties
423 + * Returns HTML code for flag.
144 424 *
145 - * @since 1.2
425 + * @since 2.7
426 + *
427 + * @param array $flag Flag properties: src, width and height.
428 + * @param string $title Optional title attribute.
429 + * @param string $alt Optional alt attribute.
430 + * @return string
431 + *
432 + * @phpstan-param array{
433 + * src: string,
434 + * width?: int|numeric-string,
435 + * height?: int|numeric-string
436 + * } $flag
146 437 */
147 - public function set_flag() {
148 - $flags = array( 'flag' => self::get_flag_informations( $this->flag_code ) );
438 + public static function get_flag_html( $flag, $title = '', $alt = '' ) {
439 + if ( empty( $flag['src'] ) ) {
440 + return '';
441 + }
149 442
150 - // Custom flags ?
151 - $directories = array(
152 - PLL_LOCAL_DIR,
153 - get_stylesheet_directory() . '/polylang',
154 - get_template_directory() . '/polylang',
155 - );
443 + $alt_attr = empty( $alt ) ? '' : sprintf( ' alt="%s"', esc_attr( $alt ) );
444 + $width_attr = empty( $flag['width'] ) ? '' : sprintf( ' width="%s"', (int) $flag['width'] );
445 + $height_attr = empty( $flag['height'] ) ? '' : sprintf( ' height="%s"', (int) $flag['height'] );
156 446
157 - foreach ( $directories as $dir ) {
158 - if ( file_exists( $file = "{$dir}/{$this->locale}.png" ) || file_exists( $file = "{$dir}/{$this->locale}.jpg" ) || file_exists( $file = "{$dir}/{$this->locale}.svg" ) ) {
159 - $flags['custom_flag']['url'] = content_url( '/' . str_replace( WP_CONTENT_DIR, '', $file ) );
160 - break;
161 - }
447 + $style = '';
448 + $sizes = array_intersect_key( $flag, array_flip( array( 'width', 'height' ) ) );
449 +
450 + if ( ! empty( $sizes ) ) {
451 + array_walk(
452 + $sizes,
453 + function ( &$value, $key ) {
454 + $value = sprintf( '%s: %dpx;', esc_attr( $key ), (int) $value );
455 + }
456 + );
457 + $style = sprintf( ' style="%s"', implode( ' ', $sizes ) );
162 458 }
163 459
164 - /**
165 - * Filter the custom flag informations
166 - * 'url' => Flag url
167 - * 'src' => Optional, src attribute value if different of the url, for example if base64 encoded
168 - * 'width' => Optional, flag width in pixels
169 - * 'height' => Optional, flag height in pixels
170 - *
171 - * @since 2.4
172 - *
173 - * @param array $flag Information about the custom flag
174 - * @param string $code Flag code
175 - */
176 - $flags['custom_flag'] = apply_filters( 'pll_custom_flag', empty( $flags['custom_flag'] ) ? null : $flags['custom_flag'], $this->flag_code );
460 + return sprintf(
461 + '<img src="%s"%s%s%s%s />',
462 + $flag['src'],
463 + $alt_attr,
464 + $width_attr,
465 + $height_attr,
466 + $style
467 + );
468 + }
177 469
178 - if ( ! empty( $flags['custom_flag']['url'] ) ) {
179 - if ( empty( $flags['custom_flag']['src'] ) ) {
180 - $flags['custom_flag']['src'] = esc_url( set_url_scheme( $flags['custom_flag']['url'], 'relative' ) );
181 - }
470 + /**
471 + * Returns the html of the custom flag if any, or the default flag otherwise.
472 + *
473 + * @since 2.8
474 + * @since 3.5.3 Added the `$alt` parameter.
475 + *
476 + * @param string $alt Whether or not the alternative text should be set. Accepts 'alt' and 'no-alt'.
477 + *
478 + * @return string
479 + *
480 + * @phpstan-param 'alt'|'no-alt' $alt
481 + */
482 + public function get_display_flag( $alt = 'alt' ) {
483 + $flag = empty( $this->custom_flag ) ? $this->flag : $this->custom_flag;
182 484
183 - $flags['custom_flag']['url'] = esc_url_raw( $flags['custom_flag']['url'] );
184 - } else {
185 - unset( $flags['custom_flag'] );
485 + if ( 'alt' === $alt ) {
486 + return $flag;
186 487 }
187 488
489 + return (string) preg_replace( '/(?<=\salt=\")([^"]+)(?=\")/', '', $flag );
490 + }
491 +
492 + /**
493 + * Returns the url of the custom flag if any, or the default flag otherwise.
494 + *
495 + * @since 2.8
496 + *
497 + * @return string
498 + */
499 + public function get_display_flag_url() {
500 + $flag_url = empty( $this->custom_flag_url ) ? $this->flag_url : $this->custom_flag_url;
501 +
188 502 /**
189 - * Filter the flag title attribute
190 - * Defaults to the language name
503 + * Filters `flag_url` property.
191 504 *
192 - * @since 0.7
505 + * @since 3.4.4
193 506 *
194 - * @param string $title the flag title attribute
195 - * @param string $slug the language code
196 - * @param string $locale the language locale
507 + * @param string $flag_url Flag URL.
508 + * @param PLL_Language $language Current `PLL_language` instance.
197 509 */
198 - $title = apply_filters( 'pll_flag_title', $this->name, $this->slug, $this->locale );
510 + return apply_filters( 'pll_language_flag_url', $flag_url, $this );
511 + }
199 512
200 - foreach ( $flags as $key => $flag ) {
201 - $this->{$key . '_url'} = empty( $flag['url'] ) ? '' : $flag['url'];
202 -
203 - /**
204 - * Filter the html markup of a flag
205 - *
206 - * @since 1.0.2
207 - *
208 - * @param string $flag html markup of the flag or empty string
209 - * @param string $slug language code
210 - */
211 - $this->{$key} = apply_filters(
212 - 'pll_get_flag',
213 - self::get_flag_html( $flag, $title, $this->name ),
214 - $this->slug
215 - );
513 + /**
514 + * Updates post and term count.
515 + *
516 + * @since 1.2
517 + *
518 + * @return void
519 + */
520 + public function update_count() {
521 + foreach ( $this->term_props as $taxonomy => $props ) {
522 + wp_update_term_count( $props['term_taxonomy_id'], $taxonomy );
216 523 }
217 524 }
218 525
219 526 /**
220 - * Get HTML code for flag
527 + * Returns the language locale.
528 + * Converts WP locales to W3C valid locales for display.
221 529 *
222 - * @since 2.7
530 + * @since 1.8
223 531 *
224 - * @param array $flag flag properties: src, width and height
225 - * @param string $title optional title attribute
226 - * @param string $alt optional alt attribute
532 + * @param string $filter Either 'display' or 'raw', defaults to raw.
533 + * @return string
534 + *
535 + * @phpstan-param 'display'|'raw' $filter
536 + * @phpstan-return non-empty-string
227 537 */
228 - public static function get_flag_html( $flag, $title = '', $alt = '' ) {
229 - return empty( $flag['src'] ) ? '' : sprintf(
230 - '<img src="%s"%s%s%s%s />',
231 - $flag['src'],
232 - empty( $title ) ? '' : sprintf( ' title="%s"', esc_attr( $title ) ),
233 - empty( $alt ) ? '' : sprintf( ' alt="%s"', esc_attr( $alt ) ),
234 - empty( $flag['width'] ) ? '' : sprintf( ' width="%s"', (int) $flag['width'] ),
235 - empty( $flag['height'] ) ? '' : sprintf( ' height="%s"', (int) $flag['height'] )
236 - );
538 + public function get_locale( $filter = 'raw' ) {
539 + return 'display' === $filter ? $this->w3c : $this->locale;
237 540 }
238 541
239 542 /**
240 - * Replace flag by custom flag
241 - * Takes care of url scheme
543 + * Returns the values of this instance's properties, which can be filtered if required.
242 544 *
243 - * @since 1.7
545 + * @since 3.4
546 + *
547 + * @param string $context Whether or not properties should be filtered. Accepts `db` or `display`.
548 + * Default to `display` which filters some properties.
549 + *
550 + * @return array Array of language object properties.
551 + *
552 + * @phpstan-return LanguageData
244 553 */
245 - public function set_custom_flag() {
246 - // Overwrite with custom flags on frontend only
247 - if ( ! empty( $this->custom_flag ) ) {
248 - $this->flag = $this->custom_flag;
249 - $this->flag_url = $this->custom_flag_url;
250 - unset( $this->custom_flag, $this->custom_flag_url ); // hide this
554 + public function to_array( $context = 'display' ) {
555 + $language = get_object_vars( $this );
556 +
557 + if ( 'db' !== $context ) {
558 + $language['home_url'] = $this->get_home_url();
559 + $language['search_url'] = $this->get_search_url();
251 560 }
252 561
253 - // Set url scheme, also for default flags
254 - $this->flag_url = set_url_scheme( $this->flag_url );
562 + /** @phpstan-var LanguageData $language */
563 + return $language;
255 564 }
256 565
257 566 /**
258 - * Updates post and term count
567 + * Converts current `PLL_language` into a `stdClass` object. Mostly used to allow dynamic properties.
259 568 *
260 - * @since 1.2
569 + * @since 3.4
570 + *
571 + * @return stdClass Converted `PLL_Language` object.
261 572 */
262 - public function update_count() {
263 - wp_update_term_count( $this->term_taxonomy_id, 'language' ); // posts count
264 - wp_update_term_count( $this->tl_term_taxonomy_id, 'term_language' ); // terms count
573 + public function to_std_class() {
574 + return (object) $this->to_array();
265 575 }
266 576
267 577 /**
268 - * Set home_url and search_url properties
578 + * Returns a predefined HTML flag.
269 579 *
270 - * @since 1.3
580 + * @since 3.4
271 581 *
272 - * @param string $search_url
273 - * @param string $home_url
582 + * @param string $flag_code Flag code to render.
583 + * @return string HTML code for the flag.
274 584 */
275 - public function set_home_url( $search_url, $home_url ) {
276 - $this->search_url = $search_url;
277 - $this->home_url = $home_url;
585 + public static function get_predefined_flag( $flag_code ) {
586 + $flag = self::get_flag_information( $flag_code );
587 +
588 + return self::get_flag_html( $flag );
278 589 }
279 590
280 591 /**
281 - * Set home_url scheme
282 - * this can't be cached across pages
592 + * Returns language's home URL. Takes care to render it dynamically if no cache is allowed.
283 593 *
284 - * @since 1.6.4
594 + * @since 3.4
595 + *
596 + * @return string Language home URL.
285 597 */
286 - public function set_home_url_scheme() {
287 - $this->home_url = set_url_scheme( $this->home_url );
288 - $this->search_url = set_url_scheme( $this->search_url );
598 + public function get_home_url() {
599 + if ( ! pll_get_constant( 'PLL_CACHE_LANGUAGES', true ) || ! pll_get_constant( 'PLL_CACHE_HOME_URL', true ) ) {
600 + /**
601 + * Filters current `PLL_Language` instance `home_url` property.
602 + *
603 + * @since 3.4.4
604 + *
605 + * @param string $home_url The `home_url` prop.
606 + * @param array $language Current Array of `PLL_Language` properties.
607 + */
608 + return apply_filters( 'pll_language_home_url', $this->home_url, $this->to_array( 'db' ) );
609 + }
610 +
611 + return $this->home_url;
289 612 }
290 613
291 614 /**
292 - * Returns the language locale
293 - * Converts WP locales to W3C valid locales for display
615 + * Returns language's search URL. Takes care to render it dynamically if no cache is allowed.
294 616 *
295 - * @since 1.8
617 + * @since 3.4
296 618 *
297 - * @param string $filter either 'display' or 'raw', defaults to raw
298 - * @return string
619 + * @return string Language search URL.
299 620 */
300 - public function get_locale( $filter = 'raw' ) {
301 - return 'display' === $filter ? $this->w3c : $this->locale;
621 + public function get_search_url() {
622 + if ( ! pll_get_constant( 'PLL_CACHE_LANGUAGES', true ) || ! pll_get_constant( 'PLL_CACHE_HOME_URL', true ) ) {
623 + /**
624 + * Filters current `PLL_Language` instance `search_url` property.
625 + *
626 + * @since 3.4.4
627 + *
628 + * @param string $search_url The `search_url` prop.
629 + * @param array $language Current Array of `PLL_Language` properties.
630 + */
631 + return apply_filters( 'pll_language_search_url', $this->search_url, $this->to_array( 'db' ) );
632 + }
633 +
634 + return $this->search_url;
635 + }
636 +
637 + /**
638 + * Returns the value of a language property.
639 + * This is handy to get a property's value without worrying about triggering a deprecation warning or anything.
640 + *
641 + * @since 3.4
642 + *
643 + * @param string $property A property name. A composite value can be used for language term property values, in the
644 + * form of `{language_taxonomy_name}:{property_name}` (see {@see PLL_Language::get_tax_prop()}
645 + * for the possible values). Ex: `term_language:term_taxonomy_id`.
646 + * @return string|int|bool|string[] The requested property for the language, `false` if the property doesn't exist.
647 + *
648 + * @phpstan-return (
649 + * $property is 'slug' ? non-empty-string : string|int|bool|list<non-empty-string>
650 + * )
651 + */
652 + public function get_prop( $property ) {
653 + // Deprecated property.
654 + if ( $this->is_deprecated_term_property( $property ) ) {
655 + return $this->get_deprecated_term_property( $property );
656 + }
657 +
658 + if ( $this->is_deprecated_url_property( $property ) ) {
659 + return $this->get_deprecated_url_property( $property );
660 + }
661 +
662 + // Composite property like 'term_language:term_taxonomy_id'.
663 + if ( preg_match( '/^(?<tax>.{1,32}):(?<field>term_id|term_taxonomy_id|count)$/', $property, $matches ) ) {
664 + /** @var array{tax:non-empty-string, field:'term_id'|'term_taxonomy_id'|'count'} $matches */
665 + return $this->get_tax_prop( $matches['tax'], $matches['field'] );
666 + }
667 +
668 + return $this->$property ?? false;
302 669 }
303 670 }