| @@ -22,9 +22,9 @@ | ||
| 22 | 22 | * name: non-empty-string, |
| 23 | 23 | * slug: non-empty-string, |
| 24 | 24 | * locale: non-empty-string, |
| 25 | 25 | * w3c: non-empty-string, |
| 26 | - * flag_code: non-empty-string, | |
| 26 | + * flag_code: string, | |
| 27 | 27 | * term_group: int, |
| 28 | 28 | * is_rtl: int<0, 1>, |
| 29 | 29 | * facebook?: string, |
| 30 | 30 | * home_url: non-empty-string, |
| @@ -29,17 +29,18 @@ | ||
| 29 | 29 | * facebook?: string, |
| 30 | 30 | * home_url: non-empty-string, |
| 31 | 31 | * search_url: non-empty-string, |
| 32 | 32 | * host: non-empty-string, |
| 33 | - * flag_url: non-empty-string, | |
| 34 | - * flag: non-empty-string, | |
| 33 | + * flag_url: string, | |
| 34 | + * flag: string, | |
| 35 | 35 | * custom_flag_url?: string, |
| 36 | 36 | * custom_flag?: string, |
| 37 | - * page_on_front: int<0, max>, | |
| 38 | - * page_for_posts: int<0, max>, | |
| 39 | - * active: bool, | |
| 37 | + * page_on_front?: int<0, max>, | |
| 38 | + * page_for_posts?: int<0, max>, | |
| 39 | + * active?: bool, | |
| 40 | 40 | * fallbacks?: array<non-empty-string>, |
| 41 | - * is_default: bool | |
| 41 | + * is_default: bool, | |
| 42 | + * admin_flag: array{'aria-hidden': non-empty-string, '': non-empty-string} | |
| 42 | 43 | * } |
| 43 | 44 | */ |
| 44 | 45 | class PLL_Language extends PLL_Language_Deprecated { |
| 45 | 46 | |
| @@ -110,9 +111,9 @@ | ||
| 110 | 111 | * Facebook locale. |
| 111 | 112 | * |
| 112 | 113 | * @var string |
| 113 | 114 | */ |
| 114 | - public $facebook = ''; | |
| 115 | + public $facebook; | |
| 115 | 116 | |
| 116 | 117 | /** |
| 117 | 118 | * Home URL in this language. |
| 118 | 119 | * |
| @@ -146,9 +147,9 @@ | ||
| 146 | 147 | * @var int |
| 147 | 148 | * |
| 148 | 149 | * @phpstan-var int<0, max> |
| 149 | 150 | */ |
| 150 | - public $page_on_front = 0; | |
| 151 | + public $page_on_front; | |
| 151 | 152 | |
| 152 | 153 | /** |
| 153 | 154 | * ID of the page for posts in this language (set from pll_additional_language_data filter). |
| 154 | 155 | * |
| @@ -155,16 +156,14 @@ | ||
| 155 | 156 | * @var int |
| 156 | 157 | * |
| 157 | 158 | * @phpstan-var int<0, max> |
| 158 | 159 | */ |
| 159 | - public $page_for_posts = 0; | |
| 160 | + public $page_for_posts; | |
| 160 | 161 | |
| 161 | 162 | /** |
| 162 | 163 | * Code of the flag. |
| 163 | 164 | * |
| 164 | 165 | * @var string |
| 165 | - * | |
| 166 | - * @phpstan-var non-empty-string | |
| 167 | 166 | */ |
| 168 | 167 | public $flag_code; |
| 169 | 168 | |
| 170 | 169 | /** |
| @@ -170,10 +169,8 @@ | ||
| 170 | 169 | /** |
| 171 | 170 | * URL of the flag. Always set to the main domain. |
| 172 | 171 | * |
| 173 | 172 | * @var string |
| 174 | - * | |
| 175 | - * @phpstan-var non-empty-string | |
| 176 | 173 | */ |
| 177 | 174 | public $flag_url; |
| 178 | 175 | |
| 179 | 176 | /** |
| @@ -179,10 +176,8 @@ | ||
| 179 | 176 | /** |
| 180 | 177 | * HTML markup of the flag. |
| 181 | 178 | * |
| 182 | 179 | * @var string |
| 183 | - * | |
| 184 | - * @phpstan-var non-empty-string | |
| 185 | 180 | */ |
| 186 | 181 | public $flag; |
| 187 | 182 | |
| 188 | 183 | /** |
| @@ -189,9 +184,9 @@ | ||
| 189 | 184 | * URL of the custom flag if it exists. Always set to the main domain. |
| 190 | 185 | * |
| 191 | 186 | * @var string |
| 192 | 187 | */ |
| 193 | - public $custom_flag_url = ''; | |
| 188 | + public $custom_flag_url; | |
| 194 | 189 | |
| 195 | 190 | /** |
| 196 | 191 | * HTML markup of the custom flag if it exists. |
| 197 | 192 | * |
| @@ -196,9 +191,9 @@ | ||
| 196 | 191 | * HTML markup of the custom flag if it exists. |
| 197 | 192 | * |
| 198 | 193 | * @var string |
| 199 | 194 | */ |
| 200 | - public $custom_flag = ''; | |
| 195 | + public $custom_flag; | |
| 201 | 196 | |
| 202 | 197 | /** |
| 203 | 198 | * Whether or not the language is active. Default `true`. |
| 204 | 199 | * |
| @@ -203,9 +198,9 @@ | ||
| 203 | 198 | * Whether or not the language is active. Default `true`. |
| 204 | 199 | * |
| 205 | 200 | * @var bool |
| 206 | 201 | */ |
| 207 | - public $active = true; | |
| 202 | + public $active; | |
| 208 | 203 | |
| 209 | 204 | /** |
| 210 | 205 | * List of WordPress language locales. Ex: array( 'en_GB' ). |
| 211 | 206 | * |
| @@ -212,9 +207,9 @@ | ||
| 212 | 207 | * @var string[] |
| 213 | 208 | * |
| 214 | 209 | * @phpstan-var list<non-empty-string> |
| 215 | 210 | */ |
| 216 | - public $fallbacks = array(); | |
| 211 | + public $fallbacks; | |
| 217 | 212 | |
| 218 | 213 | /** |
| 219 | 214 | * Whether the language is the default one. |
| 220 | 215 | * |
| @@ -256,8 +251,15 @@ | ||
| 256 | 251 | */ |
| 257 | 252 | protected $term_props; |
| 258 | 253 | |
| 259 | 254 | /** |
| 255 | + * @var array | |
| 256 | + * | |
| 257 | + * @phpstan-var array{'aria-hidden': non-empty-string, '': non-empty-string} | |
| 258 | + */ | |
| 259 | + private $admin_flag; | |
| 260 | + | |
| 261 | + /** | |
| 260 | 262 | * Constructor: builds a language object given the corresponding data. |
| 261 | 263 | * |
| 262 | 264 | * @since 1.2 |
| 263 | 265 | * @since 3.4 Only accepts one argument. |
| @@ -284,17 +286,30 @@ | ||
| 284 | 286 | * @type string $custom_flag_url Optional. URL of the custom flag if it exists. |
| 285 | 287 | * @type string $custom_flag Optional. HTML markup of the custom flag if it exists. |
| 286 | 288 | * @type int $page_on_front Optional. ID of the page on front in this language. |
| 287 | 289 | * @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 $active Optional. Whether or not the language is active. Default `true`. | |
| 291 | + * @type string[] $fallbacks Optional. List of WordPress language locales. Ex: array( 'en_GB' ). | |
| 290 | 292 | * @type bool $is_default Whether or not the language is the default one. |
| 293 | + * @type array $admin_flag An array containing the keys `''` (empty string) for the "normal" flag, and | |
| 294 | + * `'aria-hidden'` for the flag hidden to screen readers. | |
| 291 | 295 | * } |
| 292 | 296 | * |
| 293 | 297 | * @phpstan-param LanguageData $language_data |
| 294 | 298 | */ |
| 295 | 299 | public function __construct( array $language_data ) { |
| 296 | - foreach ( $language_data as $prop => $value ) { | |
| 300 | + // Default values for optional params. | |
| 301 | + $defaults = array( | |
| 302 | + 'facebook' => '', | |
| 303 | + 'page_on_front' => 0, | |
| 304 | + 'page_for_posts' => 0, | |
| 305 | + 'custom_flag_url' => '', | |
| 306 | + 'custom_flag' => '', | |
| 307 | + 'active' => true, | |
| 308 | + 'fallbacks' => array(), | |
| 309 | + ); | |
| 310 | + | |
| 311 | + foreach ( array_merge( $defaults, $language_data ) as $prop => $value ) { | |
| 297 | 312 | $this->$prop = $value; |
| 298 | 313 | } |
| 299 | 314 | |
| 300 | 315 | $this->term_id = $this->term_props['language']['term_id']; |
| @@ -350,8 +365,20 @@ | ||
| 350 | 365 | return $term_props; |
| 351 | 366 | } |
| 352 | 367 | |
| 353 | 368 | /** |
| 369 | + * Returns a predefined HTML flag. | |
| 370 | + * | |
| 371 | + * @since 3.4 | |
| 372 | + * | |
| 373 | + * @param string $flag_code Flag code to render. | |
| 374 | + * @return string HTML code for the flag. | |
| 375 | + */ | |
| 376 | + public static function get_predefined_flag( $flag_code ) { | |
| 377 | + return self::get_flag_html( self::get_flag_information( $flag_code ) ); | |
| 378 | + } | |
| 379 | + | |
| 380 | + /** | |
| 354 | 381 | * Returns the flag information. |
| 355 | 382 | * |
| 356 | 383 | * @since 2.6 |
| 357 | 384 | * |
| @@ -377,20 +404,29 @@ | ||
| 377 | 404 | 'url' => '', |
| 378 | 405 | 'src' => '', |
| 379 | 406 | ); |
| 380 | 407 | |
| 408 | + if ( empty( $code ) ) { | |
| 409 | + return $default_flag; | |
| 410 | + } | |
| 411 | + | |
| 381 | 412 | // Polylang builtin flags. |
| 382 | - if ( ! empty( $code ) && is_readable( POLYLANG_DIR . ( $file = '/flags/' . $code . '.png' ) ) ) { | |
| 383 | - $default_flag['url'] = plugins_url( $file, POLYLANG_FILE ); | |
| 413 | + $file = "/vendor/wpsyntex/flags/{$code}.svg"; | |
| 414 | + if ( is_readable( POLYLANG_ROOT_DIR . $file ) ) { | |
| 415 | + $default_flag = array( | |
| 416 | + 'url' => plugins_url( $file, POLYLANG_ROOT_FILE ), | |
| 417 | + 'src' => '', | |
| 418 | + 'width' => 18, | |
| 419 | + 'height' => 12, | |
| 420 | + ); | |
| 384 | 421 | |
| 385 | 422 | // If base64 encoded flags are preferred. |
| 386 | 423 | 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; | |
| 424 | + $content = file_get_contents( POLYLANG_ROOT_DIR . $file ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents | |
| 425 | + | |
| 426 | + if ( ! empty( $content ) ) { | |
| 427 | + $default_flag['src'] = 'data:image/svg+xml,' . self::encode_svg( $content ); | |
| 390 | 428 | } |
| 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 | 429 | } |
| 394 | 430 | } |
| 395 | 431 | |
| 396 | 432 | /** |
| @@ -415,8 +451,16 @@ | ||
| 415 | 451 | if ( empty( $flag['src'] ) || ( $flag['src'] === $default_flag['src'] && $flag['url'] !== $default_flag['url'] ) ) { |
| 416 | 452 | $flag['src'] = esc_url( set_url_scheme( $flag['url'], 'relative' ) ); |
| 417 | 453 | } |
| 418 | 454 | |
| 455 | + if ( isset( $flag['width'] ) ) { | |
| 456 | + $flag['width'] = absint( $flag['width'] ); | |
| 457 | + } | |
| 458 | + | |
| 459 | + if ( isset( $flag['height'] ) ) { | |
| 460 | + $flag['height'] = absint( $flag['height'] ); | |
| 461 | + } | |
| 462 | + | |
| 419 | 463 | return $flag; |
| 420 | 464 | } |
| 421 | 465 | |
| 422 | 466 | /** |
| @@ -422,11 +466,11 @@ | ||
| 422 | 466 | /** |
| 423 | 467 | * Returns HTML code for flag. |
| 424 | 468 | * |
| 425 | 469 | * @since 2.7 |
| 470 | + * @since 3.9 Removed param `$title` and pass `$alt` as second param. | |
| 426 | 471 | * |
| 427 | 472 | * @param array $flag Flag properties: src, width and height. |
| 428 | - * @param string $title Optional title attribute. | |
| 429 | 473 | * @param string $alt Optional alt attribute. |
| 430 | 474 | * @return string |
| 431 | 475 | * |
| 432 | 476 | * @phpstan-param array{ |
| @@ -434,13 +478,20 @@ | ||
| 434 | 478 | * width?: int|numeric-string, |
| 435 | 479 | * height?: int|numeric-string |
| 436 | 480 | * } $flag |
| 437 | 481 | */ |
| 438 | - public static function get_flag_html( $flag, $title = '', $alt = '' ) { | |
| 482 | + public static function get_flag_html( $flag, $alt = '' ) { | |
| 439 | 483 | if ( empty( $flag['src'] ) ) { |
| 440 | 484 | return ''; |
| 441 | 485 | } |
| 442 | 486 | |
| 487 | + // Backward compatibility. | |
| 488 | + if ( func_num_args() > 2 ) { | |
| 489 | + _deprecated_argument( __METHOD__ . '()', '3.9', 'The parameter `$title` has been removed and replaced by `$alt` in second position' ); | |
| 490 | + /** @var string */ | |
| 491 | + $alt = func_get_arg( 2 ); | |
| 492 | + } | |
| 493 | + | |
| 443 | 494 | $alt_attr = empty( $alt ) ? '' : sprintf( ' alt="%s"', esc_attr( $alt ) ); |
| 444 | 495 | $width_attr = empty( $flag['width'] ) ? '' : sprintf( ' width="%s"', (int) $flag['width'] ); |
| 445 | 496 | $height_attr = empty( $flag['height'] ) ? '' : sprintf( ' height="%s"', (int) $flag['height'] ); |
| 446 | 497 | |
| @@ -467,8 +518,26 @@ | ||
| 467 | 518 | ); |
| 468 | 519 | } |
| 469 | 520 | |
| 470 | 521 | /** |
| 522 | + * Returns the language flag or the language slug if there is no flag. | |
| 523 | + * | |
| 524 | + * @since 3.9 | |
| 525 | + * | |
| 526 | + * @param string $mode Optional. Allows to modify the markup depending on how the flag is used. Possible values are: | |
| 527 | + * - Empty string: the flag can be seen by screen readers, | |
| 528 | + * - `aria-hidden`: the flag is hidden from screen readers: it is preceded or followed by a | |
| 529 | + * text (language name for example) that would make the information redundant. | |
| 530 | + * Default is an empty string. | |
| 531 | + * @return string | |
| 532 | + * | |
| 533 | + * @phpstan-param ''|'aria-hidden' $mode | |
| 534 | + */ | |
| 535 | + public function get_admin_flag( string $mode = '' ): string { | |
| 536 | + return $this->admin_flag[ $mode ]; | |
| 537 | + } | |
| 538 | + | |
| 539 | + /** | |
| 471 | 540 | * Returns the html of the custom flag if any, or the default flag otherwise. |
| 472 | 541 | * |
| 473 | 542 | * @since 2.8 |
| 474 | 543 | * @since 3.5.3 Added the `$alt` parameter. |
| @@ -552,8 +621,9 @@ | ||
| 552 | 621 | * @phpstan-return LanguageData |
| 553 | 622 | */ |
| 554 | 623 | public function to_array( $context = 'display' ) { |
| 555 | 624 | $language = get_object_vars( $this ); |
| 625 | + unset( $language['admin_flag'] ); | |
| 556 | 626 | |
| 557 | 627 | if ( 'db' !== $context ) { |
| 558 | 628 | $language['home_url'] = $this->get_home_url(); |
| 559 | 629 | $language['search_url'] = $this->get_search_url(); |
| @@ -574,22 +644,8 @@ | ||
| 574 | 644 | return (object) $this->to_array(); |
| 575 | 645 | } |
| 576 | 646 | |
| 577 | 647 | /** |
| 578 | - * Returns a predefined HTML flag. | |
| 579 | - * | |
| 580 | - * @since 3.4 | |
| 581 | - * | |
| 582 | - * @param string $flag_code Flag code to render. | |
| 583 | - * @return string HTML code for the flag. | |
| 584 | - */ | |
| 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 ); | |
| 589 | - } | |
| 590 | - | |
| 591 | - /** | |
| 592 | 648 | * Returns language's home URL. Takes care to render it dynamically if no cache is allowed. |
| 593 | 649 | * |
| 594 | 650 | * @since 3.4 |
| 595 | 651 | * |
| @@ -665,6 +721,27 @@ | ||
| 665 | 721 | return $this->get_tax_prop( $matches['tax'], $matches['field'] ); |
| 666 | 722 | } |
| 667 | 723 | |
| 668 | 724 | return $this->$property ?? false; |
| 725 | + } | |
| 726 | + | |
| 727 | + /** | |
| 728 | + * Prepares a SVG image for use in data uri. | |
| 729 | + * | |
| 730 | + * @see https://codepen.io/tigt/post/optimizing-svgs-in-data-uris. | |
| 731 | + * @since 3.9 | |
| 732 | + * | |
| 733 | + * @param string $svg A string representing an SVG image. | |
| 734 | + * @return string Encode SVG. | |
| 735 | + */ | |
| 736 | + protected static function encode_svg( string $svg ): string { | |
| 737 | + $to_replace = array( | |
| 738 | + '"' => "'", | |
| 739 | + '<' => '%3C', | |
| 740 | + '>' => '%3E', | |
| 741 | + '#' => '%23', | |
| 742 | + "\n" => '', | |
| 743 | + "\r" => '', | |
| 744 | + ); | |
| 745 | + return str_replace( array_keys( $to_replace ), array_values( $to_replace ), $svg ); | |
| 669 | 746 | } |
| 670 | 747 | } |