1 <?php |
1 <?php |
2 /** |
2 /** |
3 * Server-side rendering of the `core/navigation-link` block. |
3 * Server-side registering and rendering of the `core/navigation-link` block. |
4 * |
4 * |
5 * @package WordPress |
5 * @package WordPress |
6 */ |
6 */ |
7 |
7 |
8 /** |
8 /** |
9 * Build an array with CSS classes and inline styles defining the colors |
9 * Build an array with CSS classes and inline styles defining the colors |
10 * which will be applied to the navigation markup in the front-end. |
10 * which will be applied to the navigation markup in the front-end. |
11 * |
11 * |
12 * @param array $context Navigation block context. |
12 * @since 5.9.0 |
13 * @param array $attributes Block attributes. |
13 * |
|
14 * @param array $context Navigation block context. |
|
15 * @param array $attributes Block attributes. |
|
16 * @param bool $is_sub_menu Whether the link is part of a sub-menu. |
14 * @return array Colors CSS classes and inline styles. |
17 * @return array Colors CSS classes and inline styles. |
15 */ |
18 */ |
16 function block_core_navigation_link_build_css_colors( $context, $attributes ) { |
19 function block_core_navigation_link_build_css_colors( $context, $attributes, $is_sub_menu = false ) { |
17 $colors = array( |
20 $colors = array( |
18 'css_classes' => array(), |
21 'css_classes' => array(), |
19 'inline_styles' => '', |
22 'inline_styles' => '', |
20 ); |
23 ); |
21 |
|
22 $is_sub_menu = isset( $attributes['isTopLevelLink'] ) ? ( ! $attributes['isTopLevelLink'] ) : false; |
|
23 |
24 |
24 // Text color. |
25 // Text color. |
25 $named_text_color = null; |
26 $named_text_color = null; |
26 $custom_text_color = null; |
27 $custom_text_color = null; |
27 |
28 |
78 |
79 |
79 /** |
80 /** |
80 * Build an array with CSS classes and inline styles defining the font sizes |
81 * Build an array with CSS classes and inline styles defining the font sizes |
81 * which will be applied to the navigation markup in the front-end. |
82 * which will be applied to the navigation markup in the front-end. |
82 * |
83 * |
|
84 * @since 5.9.0 |
|
85 * |
83 * @param array $context Navigation block context. |
86 * @param array $context Navigation block context. |
84 * @return array Font size CSS classes and inline styles. |
87 * @return array Font size CSS classes and inline styles. |
85 */ |
88 */ |
86 function block_core_navigation_link_build_css_font_sizes( $context ) { |
89 function block_core_navigation_link_build_css_font_sizes( $context ) { |
87 // CSS classes. |
90 // CSS classes. |
96 if ( $has_named_font_size ) { |
99 if ( $has_named_font_size ) { |
97 // Add the font size class. |
100 // Add the font size class. |
98 $font_sizes['css_classes'][] = sprintf( 'has-%s-font-size', $context['fontSize'] ); |
101 $font_sizes['css_classes'][] = sprintf( 'has-%s-font-size', $context['fontSize'] ); |
99 } elseif ( $has_custom_font_size ) { |
102 } elseif ( $has_custom_font_size ) { |
100 // Add the custom font size inline style. |
103 // Add the custom font size inline style. |
101 $font_sizes['inline_styles'] = sprintf( 'font-size: %s;', $context['style']['typography']['fontSize'] ); |
104 $font_sizes['inline_styles'] = sprintf( |
|
105 'font-size: %s;', |
|
106 wp_get_typography_font_size_value( |
|
107 array( |
|
108 'size' => $context['style']['typography']['fontSize'], |
|
109 ) |
|
110 ) |
|
111 ); |
102 } |
112 } |
103 |
113 |
104 return $font_sizes; |
114 return $font_sizes; |
105 } |
115 } |
106 |
116 |
107 /** |
117 /** |
108 * Returns the top-level submenu SVG chevron icon. |
118 * Returns the top-level submenu SVG chevron icon. |
|
119 * |
|
120 * @since 5.9.0 |
109 * |
121 * |
110 * @return string |
122 * @return string |
111 */ |
123 */ |
112 function block_core_navigation_link_render_submenu_icon() { |
124 function block_core_navigation_link_render_submenu_icon() { |
113 return '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none" aria-hidden="true" focusable="false"><path d="M1.50002 4L6.00002 8L10.5 4" stroke-width="1.5"></path></svg>'; |
125 return '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none" aria-hidden="true" focusable="false"><path d="M1.50002 4L6.00002 8L10.5 4" stroke-width="1.5"></path></svg>'; |
114 } |
126 } |
115 |
127 |
116 /** |
128 /** |
|
129 * Decodes a url if it's encoded, returning the same url if not. |
|
130 * |
|
131 * @since 6.2.0 |
|
132 * |
|
133 * @param string $url The url to decode. |
|
134 * |
|
135 * @return string $url Returns the decoded url. |
|
136 */ |
|
137 function block_core_navigation_link_maybe_urldecode( $url ) { |
|
138 $is_url_encoded = false; |
|
139 $query = parse_url( $url, PHP_URL_QUERY ); |
|
140 $query_params = wp_parse_args( $query ); |
|
141 |
|
142 foreach ( $query_params as $query_param ) { |
|
143 $can_query_param_be_encoded = is_string( $query_param ) && ! empty( $query_param ); |
|
144 if ( ! $can_query_param_be_encoded ) { |
|
145 continue; |
|
146 } |
|
147 if ( rawurldecode( $query_param ) !== $query_param ) { |
|
148 $is_url_encoded = true; |
|
149 break; |
|
150 } |
|
151 } |
|
152 |
|
153 if ( $is_url_encoded ) { |
|
154 return rawurldecode( $url ); |
|
155 } |
|
156 |
|
157 return $url; |
|
158 } |
|
159 |
|
160 |
|
161 /** |
117 * Renders the `core/navigation-link` block. |
162 * Renders the `core/navigation-link` block. |
|
163 * |
|
164 * @since 5.9.0 |
118 * |
165 * |
119 * @param array $attributes The block attributes. |
166 * @param array $attributes The block attributes. |
120 * @param string $content The saved content. |
167 * @param string $content The saved content. |
121 * @param WP_Block $block The parsed block. |
168 * @param WP_Block $block The parsed block. |
122 * |
169 * |
138 // Don't render the block's subtree if it has no label. |
185 // Don't render the block's subtree if it has no label. |
139 if ( empty( $attributes['label'] ) ) { |
186 if ( empty( $attributes['label'] ) ) { |
140 return ''; |
187 return ''; |
141 } |
188 } |
142 |
189 |
143 $colors = block_core_navigation_link_build_css_colors( $block->context, $attributes ); |
|
144 $font_sizes = block_core_navigation_link_build_css_font_sizes( $block->context ); |
190 $font_sizes = block_core_navigation_link_build_css_font_sizes( $block->context ); |
145 $classes = array_merge( |
191 $classes = array_merge( |
146 $colors['css_classes'], |
|
147 $font_sizes['css_classes'] |
192 $font_sizes['css_classes'] |
148 ); |
193 ); |
149 $style_attribute = ( $colors['inline_styles'] . $font_sizes['inline_styles'] ); |
194 $style_attribute = $font_sizes['inline_styles']; |
150 |
195 |
151 $css_classes = trim( implode( ' ', $classes ) ); |
196 $css_classes = trim( implode( ' ', $classes ) ); |
152 $has_submenu = count( $block->inner_blocks ) > 0; |
197 $has_submenu = count( $block->inner_blocks ) > 0; |
153 $is_active = ! empty( $attributes['id'] ) && ( get_the_ID() === $attributes['id'] ); |
198 $kind = empty( $attributes['kind'] ) ? 'post_type' : str_replace( '-', '_', $attributes['kind'] ); |
|
199 $is_active = ! empty( $attributes['id'] ) && get_queried_object_id() === (int) $attributes['id'] && ! empty( get_queried_object()->$kind ); |
|
200 |
|
201 if ( is_post_type_archive() ) { |
|
202 $queried_archive_link = get_post_type_archive_link( get_queried_object()->name ); |
|
203 if ( $attributes['url'] === $queried_archive_link ) { |
|
204 $is_active = true; |
|
205 } |
|
206 } |
154 |
207 |
155 $wrapper_attributes = get_block_wrapper_attributes( |
208 $wrapper_attributes = get_block_wrapper_attributes( |
156 array( |
209 array( |
157 'class' => $css_classes . ' wp-block-navigation-item' . ( $has_submenu ? ' has-child' : '' ) . |
210 'class' => $css_classes . ' wp-block-navigation-item' . ( $has_submenu ? ' has-child' : '' ) . |
158 ( $is_active ? ' current-menu-item' : '' ), |
211 ( $is_active ? ' current-menu-item' : '' ), |
162 $html = '<li ' . $wrapper_attributes . '>' . |
215 $html = '<li ' . $wrapper_attributes . '>' . |
163 '<a class="wp-block-navigation-item__content" '; |
216 '<a class="wp-block-navigation-item__content" '; |
164 |
217 |
165 // Start appending HTML attributes to anchor tag. |
218 // Start appending HTML attributes to anchor tag. |
166 if ( isset( $attributes['url'] ) ) { |
219 if ( isset( $attributes['url'] ) ) { |
167 $html .= ' href="' . esc_url( $attributes['url'] ) . '"'; |
220 $html .= ' href="' . esc_url( block_core_navigation_link_maybe_urldecode( $attributes['url'] ) ) . '"'; |
168 } |
221 } |
169 |
222 |
170 if ( $is_active ) { |
223 if ( $is_active ) { |
171 $html .= ' aria-current="page"'; |
224 $html .= ' aria-current="page"'; |
172 } |
225 } |
289 |
344 |
290 return $variation; |
345 return $variation; |
291 } |
346 } |
292 |
347 |
293 /** |
348 /** |
294 * Register the navigation link block. |
349 * Filters the registered variations for a block type. |
295 * |
350 * Returns the dynamically built variations for all post-types and taxonomies. |
296 * @uses render_block_core_navigation() |
351 * |
297 * @throws WP_Error An WP_Error exception parsing the block definition. |
352 * @since 6.5.0 |
298 */ |
353 * |
299 function register_block_core_navigation_link() { |
354 * @param array $variations Array of registered variations for a block type. |
|
355 * @param WP_Block_Type $block_type The full block type object. |
|
356 */ |
|
357 function block_core_navigation_link_filter_variations( $variations, $block_type ) { |
|
358 if ( 'core/navigation-link' !== $block_type->name ) { |
|
359 return $variations; |
|
360 } |
|
361 |
|
362 $generated_variations = block_core_navigation_link_build_variations(); |
|
363 return array_merge( $variations, $generated_variations ); |
|
364 } |
|
365 |
|
366 /** |
|
367 * Returns an array of variations for the navigation link block. |
|
368 * |
|
369 * @since 6.5.0 |
|
370 * |
|
371 * @return array |
|
372 */ |
|
373 function block_core_navigation_link_build_variations() { |
300 $post_types = get_post_types( array( 'show_in_nav_menus' => true ), 'objects' ); |
374 $post_types = get_post_types( array( 'show_in_nav_menus' => true ), 'objects' ); |
301 $taxonomies = get_taxonomies( array( 'show_in_nav_menus' => true ), 'objects' ); |
375 $taxonomies = get_taxonomies( array( 'show_in_nav_menus' => true ), 'objects' ); |
302 |
376 |
303 // Use two separate arrays as a way to order the variations in the UI. |
377 /* |
304 // Known variations (like Post Link and Page Link) are added to the |
378 * Use two separate arrays as a way to order the variations in the UI. |
305 // `built_ins` array. Variations for custom post types and taxonomies are |
379 * Known variations (like Post Link and Page Link) are added to the |
306 // added to the `variations` array and will always appear after `built-ins. |
380 * `built_ins` array. Variations for custom post types and taxonomies are |
|
381 * added to the `variations` array and will always appear after `built-ins. |
|
382 */ |
307 $built_ins = array(); |
383 $built_ins = array(); |
308 $variations = array(); |
384 $variations = array(); |
309 |
385 |
310 if ( $post_types ) { |
386 if ( $post_types ) { |
311 foreach ( $post_types as $post_type ) { |
387 foreach ( $post_types as $post_type ) { |
326 $variations[] = $variation; |
402 $variations[] = $variation; |
327 } |
403 } |
328 } |
404 } |
329 } |
405 } |
330 |
406 |
|
407 return array_merge( $built_ins, $variations ); |
|
408 } |
|
409 |
|
410 /** |
|
411 * Registers the navigation link block. |
|
412 * |
|
413 * @since 5.9.0 |
|
414 * |
|
415 * @uses render_block_core_navigation_link() |
|
416 * @throws WP_Error An WP_Error exception parsing the block definition. |
|
417 */ |
|
418 function register_block_core_navigation_link() { |
331 register_block_type_from_metadata( |
419 register_block_type_from_metadata( |
332 __DIR__ . '/navigation-link', |
420 __DIR__ . '/navigation-link', |
333 array( |
421 array( |
334 'render_callback' => 'render_block_core_navigation_link', |
422 'render_callback' => 'render_block_core_navigation_link', |
335 'variations' => array_merge( $built_ins, $variations ), |
|
336 ) |
423 ) |
337 ); |
424 ); |
338 } |
425 } |
339 add_action( 'init', 'register_block_core_navigation_link' ); |
426 add_action( 'init', 'register_block_core_navigation_link' ); |
|
427 /** |
|
428 * Creates all variations for post types / taxonomies dynamically (= each time when variations are requested). |
|
429 * Do not use variation_callback, to also account for unregistering post types/taxonomies later on. |
|
430 */ |
|
431 add_action( 'get_block_type_variations', 'block_core_navigation_link_filter_variations', 10, 2 ); |