PluginProbe
Polylang / trunk
Polylang vtrunk
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 | src/modules/Blocks/Language_Switcher/Standard/Block.php +116 -18 3.8.3 → trunk View file →
@@ -4,9 +4,11 @@
4 4 */
5 5
6 6 namespace WP_Syntex\Polylang\Blocks\Language_Switcher\Standard;
7 7
8 -use PLL_Switcher;
8 +use WP_Syntex\Polylang\Switcher\Assets;
9 +use WP_Syntex\Polylang\Switcher\Switcher;
10 +use WP_Syntex\Polylang\Switcher\Settings\Settings;
9 11 use WP_Syntex\Polylang\Blocks\Language_Switcher\Abstract_Block;
10 12
11 13 /**
12 14 * Language switcher block.
@@ -15,10 +17,44 @@
15 17 * @since 3.2 Extends now the PLL_Abstract_Language_Switcher_Block abstract class.
16 18 * @since 3.8 Moved to Polylang Core and renamed to Language_Switcher\Standard\Block.
17 19 */
18 20 class Block extends Abstract_Block {
21 + /**
22 + * Adds the required hooks.
23 + *
24 + * @since 3.9
25 + *
26 + * @return self
27 + */
28 + public function init() {
29 + parent::init();
19 30
31 + add_action( 'init', array( $this, 'register_styles' ) );
32 + add_action( 'init', array( Assets::class, 'register_scripts' ) );
33 +
34 + return $this;
35 + }
36 +
20 37 /**
38 + * Registers the styles for the language switcher block.
39 + *
40 + * @since 3.9
41 + *
42 + * @return void
43 + */
44 + public function register_styles(): void {
45 + $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
46 +
47 + Assets::register_styles();
48 + wp_register_style(
49 + 'pll-language-switcher-editor', // Matches `block.json`'s `editorStyle` handle.
50 + plugins_url( "/css/build/language-switcher-editor{$suffix}.css", POLYLANG_ROOT_FILE ),
51 + array( ASSETS::FRONTEND_ASSET_HANDLE ),
52 + POLYLANG_VERSION
53 + );
54 + }
55 +
56 + /**
21 57 * Returns the language switcher block name with the Polylang's namespace.
22 58 *
23 59 * @since 3.2
24 60 *
@@ -43,33 +79,28 @@
43 79 public function render( $attributes, $content, $block ) { //phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
44 80 static $dropdown_id = 0;
45 81 ++$dropdown_id;
46 82
47 - // Sets a unique id for dropdown in PLL_Switcher::the_language().
48 - $attributes['dropdown'] = empty( $attributes['dropdown'] ) ? 0 : $dropdown_id;
83 + $attributes['unique_id'] = 'select' === $attributes['layout'] ? 'lang_choice_' . $dropdown_id : '';
84 + $attributes['show_wrapper'] = true; // Blocks always display a wrapper. Legacy `dropdown` attributes would otherwise set it to false.
49 85
50 - $attributes = $this->set_attributes_for_block( $attributes );
86 + if ( ! empty( $attributes['style']['typography']['textAlign'] ) ) {
87 + $attributes['alignment'] = $attributes['style']['typography']['textAlign'];
88 + }
51 89
52 - $attributes['raw'] = false;
53 - $switcher = new PLL_Switcher();
54 - $switcher_output = $switcher->the_languages( $this->links, $attributes );
90 + $settings = new Settings( $attributes );
91 + $switcher_output = ( new Switcher( $settings, $this->links ) )->get();
55 92
56 93 if ( empty( $switcher_output ) ) {
57 94 return '';
58 95 }
59 96
60 - $aria_label = __( 'Choose a language', 'polylang' );
61 - if ( $attributes['dropdown'] ) {
62 - $switcher_output = '<label class="screen-reader-text" for="' . esc_attr( 'lang_choice_' . $attributes['dropdown'] ) . '">' . esc_html( $aria_label ) . '</label>' . $switcher_output;
97 + $switcher_output = $this->apply_flag_styles_to_markup( $switcher_output, $attributes );
63 98
64 - $wrap_tag = '<div %1$s>%2$s</div>';
65 - } else {
66 - $wrap_tag = '<nav role="navigation" aria-label="' . esc_attr( $aria_label ) . '"><ul %1$s>%2$s</ul></nav>';
67 - }
68 -
69 - $wrap_attributes = get_block_wrapper_attributes();
70 -
71 - return sprintf( $wrap_tag, $wrap_attributes, $switcher_output );
99 + return $this->apply_block_wrapper_attributes(
100 + $switcher_output,
101 + get_block_wrapper_attributes()
102 + );
72 103 }
73 104
74 105 /**
75 106 * Returns the path to the block JSON file directory.
@@ -80,6 +111,73 @@
80 111 * @return string The path to the block.
81 112 */
82 113 protected function get_path(): string {
83 114 return __DIR__;
115 + }
116 +
117 + /**
118 + * Merges block wrapper attributes onto the switcher root element.
119 + *
120 + * Block supports (background, spacing, etc.) must apply to the switcher
121 + * wrapper itself — not to an extra full-width `<div>` around it.
122 + *
123 + * @since 3.9
124 + *
125 + * @param string $html Switcher HTML.
126 + * @param string $wrapper_attributes Attributes from `get_block_wrapper_attributes()`.
127 + * @return string
128 + */
129 + private function apply_block_wrapper_attributes( string $html, string $wrapper_attributes ): string {
130 + if ( '' === trim( $wrapper_attributes ) ) {
131 + return $html;
132 + }
133 +
134 + $processor = new \WP_HTML_Tag_Processor( $html );
135 +
136 + if ( ! $processor->next_tag() ) {
137 + return sprintf( '<div %1$s>%2$s</div>', $wrapper_attributes, $html );
138 + }
139 +
140 + foreach ( $this->parse_html_attributes( $wrapper_attributes ) as $name => $value ) {
141 + if ( 'class' === $name ) {
142 + $existing = $processor->get_attribute( 'class' ) ?? '';
143 + $value = trim( $existing . ' ' . $value );
144 + } elseif ( 'style' === $name ) {
145 + $existing = $processor->get_attribute( 'style' ) ?? '';
146 + /** @var string $existing `WP_HTML_Tag_Processor::get_attribute()` returns string|null for non-boolean attributes */
147 + $value = '' === $existing ? $value : rtrim( $existing, ';' ) . ';' . $value;
148 + }
149 +
150 + $processor->set_attribute( $name, $value );
151 + }
152 +
153 + return $processor->get_updated_html();
154 + }
155 +
156 + /**
157 + * Parses an HTML attributes string.
158 + *
159 + * @since 3.9
160 + *
161 + * @param string $attributes_string HTML attributes.
162 + * @return array<string, string>
163 + */
164 + private function parse_html_attributes( string $attributes_string ): array {
165 + $attributes = array();
166 + $processor = new \WP_HTML_Tag_Processor( '<div ' . $attributes_string . '></div>' );
167 +
168 + if ( ! $processor->next_tag() ) {
169 + return $attributes;
170 + }
171 +
172 + foreach ( array( 'class', 'style', 'id' ) as $name ) {
173 + /** @var string|null $value `WP_HTML_Tag_Processor::get_attribute()` returns string|null for non-boolean attributes */
174 + $value = $processor->get_attribute( $name );
175 +
176 + if ( null !== $value && '' !== $value ) {
177 + $attributes[ $name ] = $value;
178 + }
179 + }
180 +
181 + return $attributes;
84 182 }
85 183 }