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/Navigation/Block.php +134 -114 3.8.8 → trunk View file →
@@ -5,10 +5,15 @@
5 5
6 6 namespace WP_Syntex\Polylang\Blocks\Language_Switcher\Navigation;
7 7
8 8 use WP_Block;
9 -use PLL_Switcher;
9 +use PLL_Language;
10 +use SplObjectStorage;
10 11 use WP_HTML_Tag_Processor;
12 +use WP_Syntex\Polylang\Switcher\Switcher;
13 +use WP_Syntex\Polylang\Switcher\Element\Abstract_Element;
14 +use WP_Syntex\Polylang\Switcher\Element\Nav as Element;
15 +use WP_Syntex\Polylang\Switcher\Settings\Menu as Settings;
11 16 use WP_Syntex\Polylang\Blocks\Language_Switcher\Abstract_Block;
12 17
13 18 /**
14 19 * Language switcher block for navigation.
@@ -24,8 +29,29 @@
24 29 */
25 30 const PLACEHOLDER = '%pll%';
26 31
27 32 /**
33 + * Trusted locale and label, keyed by the inner navigation blocks created by this switcher.
34 + * Blocks parsed from saved content are never the same instances, so they can't be found here.
35 + *
36 + * @var SplObjectStorage<WP_Block, array{locale: string, label: string}>
37 + */
38 + private SplObjectStorage $internal_blocks;
39 +
40 + /**
41 + * Constructor.
42 + *
43 + * @since 3.9
44 + *
45 + * @param \PLL_Base $polylang Polylang object.
46 + */
47 + public function __construct( &$polylang ) {
48 + parent::__construct( $polylang );
49 +
50 + $this->internal_blocks = new SplObjectStorage();
51 + }
52 +
53 + /**
28 54 * Adds the required hooks specific to the navigation language switcher.
29 55 *
30 56 * @since 3.2
31 57 *
@@ -34,33 +60,40 @@
34 60 public function init() {
35 61 parent::init();
36 62
37 63 add_action( 'rest_api_init', array( $this, 'register_switcher_menu_item_options_meta_rest_field' ) );
38 - add_filter( 'block_type_metadata', array( $this, 'register_custom_attributes' ) );
39 64 add_filter( 'render_block_core/navigation-link', array( $this, 'render_custom_attributes' ), 10, 3 );
40 65 add_filter( 'render_block_core/navigation-submenu', array( $this, 'render_custom_attributes' ), 10, 3 );
41 - add_action( 'init', array( $this, 'register_editor_style' ) );
66 + add_action( 'init', array( $this, 'register_styles' ) );
42 67
43 68 return $this;
44 69 }
45 70
46 71 /**
47 - * Registers the editor style for the navigation language switcher block.
72 + * Registers the styles for the navigation language switcher block.
48 73 *
49 74 * @since 3.8
50 75 *
51 76 * @return void
52 77 */
53 - public function register_editor_style(): void {
78 + public function register_styles(): void {
54 79 $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
55 80
56 81 wp_register_style(
57 - 'pll-navigation-language-switcher-editor-style',
58 - plugins_url( 'css/build/navigation-language-switcher-editor-style' . $suffix . '.css', POLYLANG_ROOT_FILE ),
82 + 'pll-navigation-language-switcher',
83 + plugins_url( 'css/build/navigation-language-switcher' . $suffix . '.css', POLYLANG_ROOT_FILE ),
59 84 array(),
60 85 POLYLANG_VERSION
61 86 );
87 +
88 + wp_register_style(
89 + 'pll-navigation-language-switcher-editor',
90 + plugins_url( 'css/build/navigation-language-switcher-editor' . $suffix . '.css', POLYLANG_ROOT_FILE ),
91 + array(),
92 + POLYLANG_VERSION
93 + );
62 94 }
95 +
63 96 /**
64 97 * Returns the navigation language switcher block name with the Polylang's namespace.
65 98 *
66 99 * @since 3.2
@@ -82,55 +115,38 @@
82 115 * @param WP_Block $block The parsed block.
83 116 * @return string The HTML string output to serve.
84 117 */
85 118 public function render( $attributes, $content, $block ) {
86 - $attributes = $this->set_attributes_for_block( $attributes );
87 - $switcher = new PLL_Switcher();
88 - $switcher_elements = (array) $switcher->the_languages( $this->links, array_merge( $attributes, array( 'raw' => true ) ) );
119 + $settings = new Settings( $attributes );
120 + $elements = ( new Switcher( $settings, $this->links ) )->get_elements();
89 121
90 - if ( empty( $switcher_elements ) ) {
122 + if ( empty( $elements ) ) {
91 123 return '';
92 124 }
93 125
94 - if ( $attributes['dropdown'] ) {
95 - $inner_nav_link_blocks = array();
96 - $top_level_lang = reset( $switcher_elements );
97 - foreach ( $switcher_elements as $switcher_element ) {
98 - $nav_link_block_args = array(
99 - 'blockName' => 'core/navigation-link',
100 - 'attrs' => $this->get_core_block_attributes( $attributes, $switcher_element ),
101 - );
126 + $attributes['className'] .= ' ' . wp_apply_generated_classname_support( $block->block_type )['class'];
102 127
103 - $inner_nav_link_blocks[] = new WP_Block( $nav_link_block_args, $block->context );
128 + if ( 'dropdown' === $settings->layout ) {
129 + $top_level_element = $this->get_top_level_element( $settings );
104 130
105 - if ( $switcher_element['current_lang'] && ! $attributes['hide_current'] ) {
106 - $top_level_lang = $switcher_element;
107 - }
131 + if ( empty( $top_level_element ) ) {
132 + return '';
108 133 }
109 134
110 - $attributes = $this->get_core_block_attributes( $attributes, $top_level_lang );
111 - $attributes['className'] .= ' ' . wp_apply_generated_classname_support( $block->block_type )['class'];
112 - $submenu_block_args = array(
113 - 'blockName' => 'core/navigation-submenu',
114 - 'attrs' => $attributes,
115 - 'innerBlocks' => $inner_nav_link_blocks,
116 - );
135 + $inner_nav_link_blocks = array();
136 + $attributes_wo_classname = array_diff_key( $attributes, array( 'className' => '' ) );
117 137
118 - $submenu_block = new WP_Block( $submenu_block_args, $block->context );
138 + foreach ( $elements as $element ) {
139 + $inner_nav_link_blocks[] = $this->create_inner_block( 'core/navigation-link', $attributes_wo_classname, $element, $block->context );
140 + }
141 +
142 + $submenu_block = $this->create_inner_block( 'core/navigation-submenu', $attributes, $top_level_element, $block->context, $inner_nav_link_blocks );
119 143 $output = $submenu_block->render();
120 144 } else {
121 145 $output = '';
122 146
123 - foreach ( $switcher_elements as $switcher_element ) {
124 - $link_attributes = $this->get_core_block_attributes( $attributes, $switcher_element );
125 - $link_attributes['className'] .= ' ' . wp_apply_generated_classname_support( $block->block_type )['class'];
126 - $nav_link_block_args = array(
127 - 'blockName' => 'core/navigation-link',
128 - 'attrs' => $link_attributes,
129 - );
130 -
131 - $link_block = new WP_Block( $nav_link_block_args, $block->context );
132 - $output .= $link_block->render();
147 + foreach ( $elements as $element ) {
148 + $output .= $this->create_inner_block( 'core/navigation-link', $attributes, $element, $block->context )->render();
133 149 }
134 150 }
135 151
136 152 return $output;
@@ -163,45 +179,8 @@
163 179 );
164 180 }
165 181
166 182 /**
167 - * Filters core/navigation-link and core/navigation-submenu attributes during registration to add our own.
168 - *
169 - * @since 3.6
170 - *
171 - * @param array $metadata Metadata for registering a block type.
172 - *
173 - * @return array The filtered metadata if about a core/navigation-link.
174 - */
175 - public function register_custom_attributes( $metadata ) {
176 - if ( 'core/navigation-link' === $metadata['name'] || 'core/navigation-submenu' === $metadata['name'] ) {
177 - $pll_attributes = array(
178 - 'hreflang' => array(
179 - 'type' => 'string',
180 - ),
181 - 'lang' => array(
182 - 'type' => 'string',
183 - ),
184 - 'pll_show_flags' => array(
185 - 'type' => 'boolean',
186 - ),
187 - 'pll_show_names' => array(
188 - 'type' => 'boolean',
189 - ),
190 - 'pll_flag' => array(
191 - 'type' => 'string',
192 - ),
193 - 'pll_name' => array(
194 - 'type' => 'string',
195 - ),
196 - );
197 - $metadata['attributes'] = array_merge( $metadata['attributes'], $pll_attributes );
198 - }
199 -
200 - return $metadata;
201 - }
202 -
203 - /**
204 183 * Renders a core/naviagation-link or core/naviagation-submenu block by adding hreflang and lang attributes to the <a> tag
205 184 * and also the language flag if required.
206 185 *
207 186 * @since 3.6
@@ -212,27 +191,22 @@
212 191 *
213 192 * @return string A formatted HTML string representing the core/navigation-link or core/navigation-submenu block.
214 193 */
215 194 public function render_custom_attributes( $block_content, $block, $instance ) {
216 - if ( ! isset(
217 - $instance->attributes['pll_show_flags'],
218 - $instance->attributes['pll_show_names'],
219 - $instance->attributes['pll_flag'],
220 - $instance->attributes['pll_name'],
221 - $instance->attributes['lang'],
222 - $instance->attributes['hreflang']
223 - )
224 - ) {
195 + if ( ! $this->internal_blocks->offsetExists( $instance ) ) {
225 196 return $block_content;
226 197 }
227 198
199 + $snapshot = $this->internal_blocks->offsetGet( $instance );
200 + $this->internal_blocks->offsetUnset( $instance );
201 +
228 202 $content_tags = new WP_HTML_Tag_Processor( $block_content );
229 203
230 204 if ( 'core/navigation-submenu' === $instance->name ) {
231 205 // If `openSubmenusOnClick`, the submenu is rendered as a button, so there are no `<a>` to process.
232 206 if ( empty( $instance->context['openSubmenusOnClick'] ) && $content_tags->next_tag( array( 'tag_name' => 'a' ) ) ) {
233 - $content_tags->set_attribute( 'hreflang', $instance->attributes['hreflang'] );
234 - $content_tags->set_attribute( 'lang', $instance->attributes['lang'] );
207 + $content_tags->set_attribute( 'hreflang', $snapshot['locale'] );
208 + $content_tags->set_attribute( 'lang', $snapshot['locale'] );
235 209 }
236 210 if ( $content_tags->next_tag( array( 'tag_name' => 'button' ) ) ) {
237 211 $content_tags->set_attribute(
238 212 'aria-label',
@@ -243,27 +217,17 @@
243 217 )
244 218 );
245 219 }
246 220 } elseif ( $content_tags->next_tag( array( 'tag_name' => 'a' ) ) ) {
247 - $content_tags->set_attribute( 'hreflang', $instance->attributes['hreflang'] );
248 - $content_tags->set_attribute( 'lang', $instance->attributes['lang'] );
221 + $content_tags->set_attribute( 'hreflang', $snapshot['locale'] );
222 + $content_tags->set_attribute( 'lang', $snapshot['locale'] );
249 223 }
250 224
251 225 $overridden_block_content = $content_tags->get_updated_html();
252 226
253 - $link_label = '';
254 -
255 - if ( $instance->attributes['pll_show_flags'] ) {
256 - $link_label .= $instance->attributes['pll_flag'];
257 - }
258 -
259 - if ( $instance->attributes['pll_show_names'] ) {
260 - $link_label .= $instance->attributes['pll_show_flags'] ? ' ' . $instance->attributes['pll_name'] : $instance->attributes['pll_name'];
261 - }
262 -
263 227 return str_replace(
264 228 static::PLACEHOLDER,
265 - $link_label,
229 + $snapshot['label'],
266 230 $overridden_block_content
267 231 );
268 232 }
269 233
@@ -279,26 +243,82 @@
279 243 return __DIR__;
280 244 }
281 245
282 246 /**
247 + * Creates an inner navigation block and stores the locale and label to render for it.
248 + *
249 + * @since 3.9
250 + *
251 + * @param string $block_name Core block name.
252 + * @param array $attributes Array of polylang/navigation-language-switcher attributes.
253 + * @param Abstract_Element $element Switcher element.
254 + * @param array $context Block context.
255 + * @param WP_Block[] $inner_blocks Optional inner blocks.
256 + * @return WP_Block
257 + */
258 + private function create_inner_block( string $block_name, array $attributes, Abstract_Element $element, array $context, array $inner_blocks = array() ): WP_Block {
259 + $block = new WP_Block(
260 + array(
261 + 'blockName' => $block_name,
262 + 'attrs' => $this->get_core_block_attributes( $attributes, $element ),
263 + 'innerBlocks' => $inner_blocks,
264 + ),
265 + $context
266 + );
267 +
268 + $this->internal_blocks->offsetSet(
269 + $block,
270 + array(
271 + 'locale' => $element->locale,
272 + 'label' => $this->apply_flag_styles_to_markup( $element->get_label(), $attributes ),
273 + )
274 + );
275 +
276 + return $block;
277 + }
278 +
279 + /**
280 + * Returns the top-level language element for a dropdown layout.
281 + *
282 + * @since 3.9
283 + *
284 + * @param Settings $settings Switcher settings.
285 + * @return Element|null
286 + */
287 + private function get_top_level_element( Settings $settings ): ?Element {
288 + $curlang = $this->links->curlang ?? $this->model->get_default_language();
289 +
290 + if ( ! $curlang instanceof PLL_Language ) {
291 + return null;
292 + }
293 +
294 + return new Element( $curlang, $settings, $this->links );
295 + }
296 +
297 + /**
283 298 * Returns attributes that fit for core/navigation-link or core/navigation-submenu and specific to polylang/navigation-language-switcher.
284 299 *
285 300 * @since 3.6
286 301 *
287 - * @param array $attributes Array of polylang/navigation-language-switcher attributes.
288 - * @param array $switcher_item Array of a switcher item data.
302 + * @param array $attributes Array of polylang/navigation-language-switcher attributes.
303 + * @param Abstract_Element $element Switcher element.
289 304 * @return array Attributes to be rendered by core.
290 305 */
291 - private function get_core_block_attributes( $attributes, $switcher_item ) {
306 + private function get_core_block_attributes( array $attributes, Abstract_Element $element ): array {
307 + $class_name = trim( implode( ' ', $element->item_classes ) );
308 +
309 + if ( ! empty( $attributes['show_flags'] ) ) {
310 + $aspect_ratio = $attributes['flag_aspect_ratio'] ?? '3:2';
311 + $class_name .= ' pll-aspect-ratio-' . str_replace( ':', '', $aspect_ratio );
312 + }
313 +
314 + if ( ! empty( $attributes['className'] ) ) {
315 + $class_name .= ' ' . $attributes['className'];
316 + }
317 +
292 318 return array(
293 - 'label' => static::PLACEHOLDER,
294 - 'url' => $switcher_item['url'],
295 - 'pll_show_flags' => $attributes['show_flags'],
296 - 'pll_show_names' => $attributes['show_names'],
297 - 'lang' => $switcher_item['locale'],
298 - 'hreflang' => $switcher_item['locale'],
299 - 'pll_flag' => $switcher_item['flag'],
300 - 'pll_name' => $switcher_item['name'],
301 - 'className' => trim( implode( ' ', (array) $switcher_item['classes'] ) ),
319 + 'label' => static::PLACEHOLDER,
320 + 'url' => $element->url,
321 + 'className' => $class_name,
302 322 );
303 323 }
304 324 }