[ Index ] |
PHP Cross Reference of WordPress |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Server-side rendering of the `core/navigation` block. 4 * 5 * @package WordPress 6 */ 7 8 // These functions are used for the __unstableLocation feature and only active 9 // when the gutenberg plugin is active. 10 if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) { 11 /** 12 * Returns the menu items for a WordPress menu location. 13 * 14 * @param string $location The menu location. 15 * @return array Menu items for the location. 16 */ 17 function block_core_navigation_get_menu_items_at_location( $location ) { 18 if ( empty( $location ) ) { 19 return; 20 } 21 22 // Build menu data. The following approximates the code in 23 // `wp_nav_menu()` and `gutenberg_output_block_nav_menu`. 24 25 // Find the location in the list of locations, returning early if the 26 // location can't be found. 27 $locations = get_nav_menu_locations(); 28 if ( ! isset( $locations[ $location ] ) ) { 29 return; 30 } 31 32 // Get the menu from the location, returning early if there is no 33 // menu or there was an error. 34 $menu = wp_get_nav_menu_object( $locations[ $location ] ); 35 if ( ! $menu || is_wp_error( $menu ) ) { 36 return; 37 } 38 39 $menu_items = wp_get_nav_menu_items( $menu->term_id, array( 'update_post_term_cache' => false ) ); 40 _wp_menu_item_classes_by_context( $menu_items ); 41 42 return $menu_items; 43 } 44 45 46 /** 47 * Sorts a standard array of menu items into a nested structure keyed by the 48 * id of the parent menu. 49 * 50 * @param array $menu_items Menu items to sort. 51 * @return array An array keyed by the id of the parent menu where each element 52 * is an array of menu items that belong to that parent. 53 */ 54 function block_core_navigation_sort_menu_items_by_parent_id( $menu_items ) { 55 $sorted_menu_items = array(); 56 foreach ( (array) $menu_items as $menu_item ) { 57 $sorted_menu_items[ $menu_item->menu_order ] = $menu_item; 58 } 59 unset( $menu_items, $menu_item ); 60 61 $menu_items_by_parent_id = array(); 62 foreach ( $sorted_menu_items as $menu_item ) { 63 $menu_items_by_parent_id[ $menu_item->menu_item_parent ][] = $menu_item; 64 } 65 66 return $menu_items_by_parent_id; 67 } 68 69 /** 70 * Turns menu item data into a nested array of parsed blocks 71 * 72 * @param array $menu_items An array of menu items that represent 73 * an individual level of a menu. 74 * @param array $menu_items_by_parent_id An array keyed by the id of the 75 * parent menu where each element is an 76 * array of menu items that belong to 77 * that parent. 78 * @return array An array of parsed block data. 79 */ 80 function block_core_navigation_parse_blocks_from_menu_items( $menu_items, $menu_items_by_parent_id ) { 81 if ( empty( $menu_items ) ) { 82 return array(); 83 } 84 85 $blocks = array(); 86 87 foreach ( $menu_items as $menu_item ) { 88 $class_name = ! empty( $menu_item->classes ) ? implode( ' ', (array) $menu_item->classes ) : null; 89 $id = ( null !== $menu_item->object_id && 'custom' !== $menu_item->object ) ? $menu_item->object_id : null; 90 $opens_in_new_tab = null !== $menu_item->target && '_blank' === $menu_item->target; 91 $rel = ( null !== $menu_item->xfn && '' !== $menu_item->xfn ) ? $menu_item->xfn : null; 92 $kind = null !== $menu_item->type ? str_replace( '_', '-', $menu_item->type ) : 'custom'; 93 94 $block = array( 95 'blockName' => isset( $menu_items_by_parent_id[ $menu_item->ID ] ) ? 'core/navigation-submenu' : 'core/navigation-link', 96 'attrs' => array( 97 'className' => $class_name, 98 'description' => $menu_item->description, 99 'id' => $id, 100 'kind' => $kind, 101 'label' => $menu_item->title, 102 'opensInNewTab' => $opens_in_new_tab, 103 'rel' => $rel, 104 'title' => $menu_item->attr_title, 105 'type' => $menu_item->object, 106 'url' => $menu_item->url, 107 ), 108 ); 109 110 $block['innerBlocks'] = isset( $menu_items_by_parent_id[ $menu_item->ID ] ) 111 ? block_core_navigation_parse_blocks_from_menu_items( $menu_items_by_parent_id[ $menu_item->ID ], $menu_items_by_parent_id ) 112 : array(); 113 $block['innerContent'] = array_map( 'serialize_block', $block['innerBlocks'] ); 114 115 $blocks[] = $block; 116 } 117 118 return $blocks; 119 } 120 } 121 122 /** 123 * Build an array with CSS classes and inline styles defining the colors 124 * which will be applied to the navigation markup in the front-end. 125 * 126 * @param array $attributes Navigation block attributes. 127 * 128 * @return array Colors CSS classes and inline styles. 129 */ 130 function block_core_navigation_build_css_colors( $attributes ) { 131 $colors = array( 132 'css_classes' => array(), 133 'inline_styles' => '', 134 'overlay_css_classes' => array(), 135 'overlay_inline_styles' => '', 136 ); 137 138 // Text color. 139 $has_named_text_color = array_key_exists( 'textColor', $attributes ); 140 $has_custom_text_color = array_key_exists( 'customTextColor', $attributes ); 141 142 // If has text color. 143 if ( $has_custom_text_color || $has_named_text_color ) { 144 // Add has-text-color class. 145 $colors['css_classes'][] = 'has-text-color'; 146 } 147 148 if ( $has_named_text_color ) { 149 // Add the color class. 150 $colors['css_classes'][] = sprintf( 'has-%s-color', $attributes['textColor'] ); 151 } elseif ( $has_custom_text_color ) { 152 // Add the custom color inline style. 153 $colors['inline_styles'] .= sprintf( 'color: %s;', $attributes['customTextColor'] ); 154 } 155 156 // Background color. 157 $has_named_background_color = array_key_exists( 'backgroundColor', $attributes ); 158 $has_custom_background_color = array_key_exists( 'customBackgroundColor', $attributes ); 159 160 // If has background color. 161 if ( $has_custom_background_color || $has_named_background_color ) { 162 // Add has-background class. 163 $colors['css_classes'][] = 'has-background'; 164 } 165 166 if ( $has_named_background_color ) { 167 // Add the background-color class. 168 $colors['css_classes'][] = sprintf( 'has-%s-background-color', $attributes['backgroundColor'] ); 169 } elseif ( $has_custom_background_color ) { 170 // Add the custom background-color inline style. 171 $colors['inline_styles'] .= sprintf( 'background-color: %s;', $attributes['customBackgroundColor'] ); 172 } 173 174 // Overlay text color. 175 $has_named_overlay_text_color = array_key_exists( 'overlayTextColor', $attributes ); 176 $has_custom_overlay_text_color = array_key_exists( 'customOverlayTextColor', $attributes ); 177 178 // If has overlay text color. 179 if ( $has_custom_overlay_text_color || $has_named_overlay_text_color ) { 180 // Add has-text-color class. 181 $colors['overlay_css_classes'][] = 'has-text-color'; 182 } 183 184 if ( $has_named_overlay_text_color ) { 185 // Add the overlay color class. 186 $colors['overlay_css_classes'][] = sprintf( 'has-%s-color', $attributes['overlayTextColor'] ); 187 } elseif ( $has_custom_overlay_text_color ) { 188 // Add the custom overlay color inline style. 189 $colors['overlay_inline_styles'] .= sprintf( 'color: %s;', $attributes['customOverlayTextColor'] ); 190 } 191 192 // Overlay background color. 193 $has_named_overlay_background_color = array_key_exists( 'overlayBackgroundColor', $attributes ); 194 $has_custom_overlay_background_color = array_key_exists( 'customOverlayBackgroundColor', $attributes ); 195 196 // If has overlay background color. 197 if ( $has_custom_overlay_background_color || $has_named_overlay_background_color ) { 198 // Add has-background class. 199 $colors['overlay_css_classes'][] = 'has-background'; 200 } 201 202 if ( $has_named_overlay_background_color ) { 203 // Add the overlay background-color class. 204 $colors['overlay_css_classes'][] = sprintf( 'has-%s-background-color', $attributes['overlayBackgroundColor'] ); 205 } elseif ( $has_custom_overlay_background_color ) { 206 // Add the custom overlay background-color inline style. 207 $colors['overlay_inline_styles'] .= sprintf( 'background-color: %s;', $attributes['customOverlayBackgroundColor'] ); 208 } 209 210 return $colors; 211 } 212 213 /** 214 * Build an array with CSS classes and inline styles defining the font sizes 215 * which will be applied to the navigation markup in the front-end. 216 * 217 * @param array $attributes Navigation block attributes. 218 * 219 * @return array Font size CSS classes and inline styles. 220 */ 221 function block_core_navigation_build_css_font_sizes( $attributes ) { 222 // CSS classes. 223 $font_sizes = array( 224 'css_classes' => array(), 225 'inline_styles' => '', 226 ); 227 228 $has_named_font_size = array_key_exists( 'fontSize', $attributes ); 229 $has_custom_font_size = array_key_exists( 'customFontSize', $attributes ); 230 231 if ( $has_named_font_size ) { 232 // Add the font size class. 233 $font_sizes['css_classes'][] = sprintf( 'has-%s-font-size', $attributes['fontSize'] ); 234 } elseif ( $has_custom_font_size ) { 235 // Add the custom font size inline style. 236 $font_sizes['inline_styles'] = sprintf( 'font-size: %spx;', $attributes['customFontSize'] ); 237 } 238 239 return $font_sizes; 240 } 241 242 /** 243 * Returns the top-level submenu SVG chevron icon. 244 * 245 * @return string 246 */ 247 function block_core_navigation_render_submenu_icon() { 248 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>'; 249 } 250 251 252 /** 253 * Finds the first non-empty `wp_navigation` Post. 254 * 255 * @return WP_Post|null the first non-empty Navigation or null. 256 */ 257 function block_core_navigation_get_first_non_empty_navigation() { 258 // Order and orderby args set to mirror those in `wp_get_nav_menus` 259 // see: 260 // - https://github.com/WordPress/wordpress-develop/blob/ba943e113d3b31b121f77a2d30aebe14b047c69d/src/wp-includes/nav-menu.php#L613-L619. 261 // - https://developer.wordpress.org/reference/classes/wp_query/#order-orderby-parameters. 262 $parsed_args = array( 263 'post_type' => 'wp_navigation', 264 'no_found_rows' => true, 265 'order' => 'ASC', 266 'orderby' => 'name', 267 'post_status' => 'publish', 268 'posts_per_page' => 20, // Try the first 20 posts. 269 ); 270 271 $navigation_posts = new WP_Query( $parsed_args ); 272 foreach ( $navigation_posts->posts as $navigation_post ) { 273 if ( has_blocks( $navigation_post ) ) { 274 return $navigation_post; 275 } 276 } 277 278 return null; 279 } 280 281 /** 282 * Filter out empty "null" blocks from the block list. 283 * 'parse_blocks' includes a null block with '\n\n' as the content when 284 * it encounters whitespace. This is not a bug but rather how the parser 285 * is designed. 286 * 287 * @param array $parsed_blocks the parsed blocks to be normalized. 288 * @return array the normalized parsed blocks. 289 */ 290 function block_core_navigation_filter_out_empty_blocks( $parsed_blocks ) { 291 $filtered = array_filter( 292 $parsed_blocks, 293 function( $block ) { 294 return isset( $block['blockName'] ); 295 } 296 ); 297 298 // Reset keys. 299 return array_values( $filtered ); 300 } 301 302 /** 303 * Retrieves the appropriate fallback to be used on the front of the 304 * site when there is no menu assigned to the Nav block. 305 * 306 * This aims to mirror how the fallback mechanic for wp_nav_menu works. 307 * See https://developer.wordpress.org/reference/functions/wp_nav_menu/#more-information. 308 * 309 * @return array the array of blocks to be used as a fallback. 310 */ 311 function block_core_navigation_get_fallback_blocks() { 312 $page_list_fallback = array( 313 array( 314 'blockName' => 'core/page-list', 315 'attrs' => array( 316 '__unstableMaxPages' => 4, 317 ), 318 ), 319 ); 320 321 $registry = WP_Block_Type_Registry::get_instance(); 322 323 // If `core/page-list` is not registered then return empty blocks. 324 $fallback_blocks = $registry->is_registered( 'core/page-list' ) ? $page_list_fallback : array(); 325 326 // Default to a list of Pages. 327 328 $navigation_post = block_core_navigation_get_first_non_empty_navigation(); 329 330 // Prefer using the first non-empty Navigation as fallback if available. 331 if ( $navigation_post ) { 332 $maybe_fallback = block_core_navigation_filter_out_empty_blocks( parse_blocks( $navigation_post->post_content ) ); 333 334 // Normalizing blocks may result in an empty array of blocks if they were all `null` blocks. 335 // In this case default to the (Page List) fallback. 336 $fallback_blocks = ! empty( $maybe_fallback ) ? $maybe_fallback : $fallback_blocks; 337 } 338 339 /** 340 * Filters the fallback experience for the Navigation block. 341 * 342 * Returning a falsey value will opt out of the fallback and cause the block not to render. 343 * To customise the blocks provided return an array of blocks - these should be valid 344 * children of the `core/navigation` block. 345 * 346 * @since 5.9.0 347 * 348 * @param array[] default fallback blocks provided by the default block mechanic. 349 */ 350 return apply_filters( 'block_core_navigation_render_fallback', $fallback_blocks ); 351 } 352 353 /** 354 * Renders the `core/navigation` block on server. 355 * 356 * @param array $attributes The block attributes. 357 * @param string $content The saved content. 358 * @param WP_Block $block The parsed block. 359 * 360 * @return string Returns the post content with the legacy widget added. 361 */ 362 function render_block_core_navigation( $attributes, $content, $block ) { 363 364 static $seen_menu_names = array(); 365 366 // Flag used to indicate whether the rendered output is considered to be 367 // a fallback (i.e. the block has no menu associated with it). 368 $is_fallback = false; 369 370 $nav_menu_name = ''; 371 372 /** 373 * Deprecated: 374 * The rgbTextColor and rgbBackgroundColor attributes 375 * have been deprecated in favor of 376 * customTextColor and customBackgroundColor ones. 377 * Move the values from old attrs to the new ones. 378 */ 379 if ( isset( $attributes['rgbTextColor'] ) && empty( $attributes['textColor'] ) ) { 380 $attributes['customTextColor'] = $attributes['rgbTextColor']; 381 } 382 383 if ( isset( $attributes['rgbBackgroundColor'] ) && empty( $attributes['backgroundColor'] ) ) { 384 $attributes['customBackgroundColor'] = $attributes['rgbBackgroundColor']; 385 } 386 387 unset( $attributes['rgbTextColor'], $attributes['rgbBackgroundColor'] ); 388 389 /** 390 * This is for backwards compatibility after `isResponsive` attribute has been removed. 391 */ 392 $has_old_responsive_attribute = ! empty( $attributes['isResponsive'] ) && $attributes['isResponsive']; 393 $is_responsive_menu = isset( $attributes['overlayMenu'] ) && 'never' !== $attributes['overlayMenu'] || $has_old_responsive_attribute; 394 $should_load_view_script = ! wp_script_is( 'wp-block-navigation-view' ) && ( $is_responsive_menu || $attributes['openSubmenusOnClick'] || $attributes['showSubmenuIcon'] ); 395 if ( $should_load_view_script ) { 396 wp_enqueue_script( 'wp-block-navigation-view' ); 397 } 398 399 $inner_blocks = $block->inner_blocks; 400 401 // Ensure that blocks saved with the legacy ref attribute name (navigationMenuId) continue to render. 402 if ( array_key_exists( 'navigationMenuId', $attributes ) ) { 403 $attributes['ref'] = $attributes['navigationMenuId']; 404 } 405 406 // If: 407 // - the gutenberg plugin is active 408 // - `__unstableLocation` is defined 409 // - we have menu items at the defined location 410 // - we don't have a relationship to a `wp_navigation` Post (via `ref`). 411 // ...then create inner blocks from the classic menu assigned to that location. 412 if ( 413 defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN && 414 array_key_exists( '__unstableLocation', $attributes ) && 415 ! array_key_exists( 'ref', $attributes ) && 416 ! empty( block_core_navigation_get_menu_items_at_location( $attributes['__unstableLocation'] ) ) 417 ) { 418 $menu_items = block_core_navigation_get_menu_items_at_location( $attributes['__unstableLocation'] ); 419 if ( empty( $menu_items ) ) { 420 return ''; 421 } 422 423 $menu_items_by_parent_id = block_core_navigation_sort_menu_items_by_parent_id( $menu_items ); 424 $parsed_blocks = block_core_navigation_parse_blocks_from_menu_items( $menu_items_by_parent_id[0], $menu_items_by_parent_id ); 425 $inner_blocks = new WP_Block_List( $parsed_blocks, $attributes ); 426 } 427 428 // Load inner blocks from the navigation post. 429 if ( array_key_exists( 'ref', $attributes ) ) { 430 $navigation_post = get_post( $attributes['ref'] ); 431 if ( ! isset( $navigation_post ) ) { 432 return ''; 433 } 434 435 $nav_menu_name = $navigation_post->post_title; 436 437 if ( isset( $seen_menu_names[ $nav_menu_name ] ) ) { 438 ++$seen_menu_names[ $nav_menu_name ]; 439 } else { 440 $seen_menu_names[ $nav_menu_name ] = 1; 441 } 442 443 $parsed_blocks = parse_blocks( $navigation_post->post_content ); 444 445 // 'parse_blocks' includes a null block with '\n\n' as the content when 446 // it encounters whitespace. This code strips it. 447 $compacted_blocks = block_core_navigation_filter_out_empty_blocks( $parsed_blocks ); 448 449 // TODO - this uses the full navigation block attributes for the 450 // context which could be refined. 451 $inner_blocks = new WP_Block_List( $compacted_blocks, $attributes ); 452 } 453 454 // If there are no inner blocks then fallback to rendering an appropriate fallback. 455 if ( empty( $inner_blocks ) ) { 456 $is_fallback = true; // indicate we are rendering the fallback. 457 458 $fallback_blocks = block_core_navigation_get_fallback_blocks(); 459 460 // Fallback my have been filtered so do basic test for validity. 461 if ( empty( $fallback_blocks ) || ! is_array( $fallback_blocks ) ) { 462 return ''; 463 } 464 465 $inner_blocks = new WP_Block_List( $fallback_blocks, $attributes ); 466 467 } 468 469 $layout_justification = array( 470 'left' => 'items-justified-left', 471 'right' => 'items-justified-right', 472 'center' => 'items-justified-center', 473 'space-between' => 'items-justified-space-between', 474 ); 475 476 // Restore legacy classnames for submenu positioning. 477 $layout_class = ''; 478 if ( isset( $attributes['layout']['justifyContent'] ) ) { 479 $layout_class .= $layout_justification[ $attributes['layout']['justifyContent'] ]; 480 } 481 if ( isset( $attributes['layout']['orientation'] ) && 'vertical' === $attributes['layout']['orientation'] ) { 482 $layout_class .= ' is-vertical'; 483 } 484 485 if ( isset( $attributes['layout']['flexWrap'] ) && 'nowrap' === $attributes['layout']['flexWrap'] ) { 486 $layout_class .= ' no-wrap'; 487 } 488 489 // Manually add block support text decoration as CSS class. 490 $text_decoration = _wp_array_get( $attributes, array( 'style', 'typography', 'textDecoration' ), null ); 491 $text_decoration_class = sprintf( 'has-text-decoration-%s', $text_decoration ); 492 493 $colors = block_core_navigation_build_css_colors( $attributes ); 494 $font_sizes = block_core_navigation_build_css_font_sizes( $attributes ); 495 $classes = array_merge( 496 $colors['css_classes'], 497 $font_sizes['css_classes'], 498 $is_responsive_menu ? array( 'is-responsive' ) : array(), 499 $layout_class ? array( $layout_class ) : array(), 500 $is_fallback ? array( 'is-fallback' ) : array(), 501 $text_decoration ? array( $text_decoration_class ) : array() 502 ); 503 504 $inner_blocks_html = ''; 505 $is_list_open = false; 506 foreach ( $inner_blocks as $inner_block ) { 507 if ( ( 'core/navigation-link' === $inner_block->name || 'core/home-link' === $inner_block->name || 'core/site-title' === $inner_block->name || 'core/site-logo' === $inner_block->name || 'core/navigation-submenu' === $inner_block->name ) && ! $is_list_open ) { 508 $is_list_open = true; 509 $inner_blocks_html .= '<ul class="wp-block-navigation__container">'; 510 } 511 if ( 'core/navigation-link' !== $inner_block->name && 'core/home-link' !== $inner_block->name && 'core/site-title' !== $inner_block->name && 'core/site-logo' !== $inner_block->name && 'core/navigation-submenu' !== $inner_block->name && $is_list_open ) { 512 $is_list_open = false; 513 $inner_blocks_html .= '</ul>'; 514 } 515 if ( 'core/site-title' === $inner_block->name || 'core/site-logo' === $inner_block->name ) { 516 $inner_blocks_html .= '<li class="wp-block-navigation-item">' . $inner_block->render() . '</li>'; 517 } else { 518 $inner_blocks_html .= $inner_block->render(); 519 } 520 } 521 522 if ( $is_list_open ) { 523 $inner_blocks_html .= '</ul>'; 524 } 525 526 $block_styles = isset( $attributes['styles'] ) ? $attributes['styles'] : ''; 527 528 // If the menu name has been used previously then append an ID 529 // to the name to ensure uniqueness across a given post. 530 if ( isset( $seen_menu_names[ $nav_menu_name ] ) && $seen_menu_names[ $nav_menu_name ] > 1 ) { 531 $count = $seen_menu_names[ $nav_menu_name ]; 532 $nav_menu_name = $nav_menu_name . ' ' . ( $count ); 533 } 534 535 $wrapper_attributes = get_block_wrapper_attributes( 536 array( 537 'class' => implode( ' ', $classes ), 538 'style' => $block_styles . $colors['inline_styles'] . $font_sizes['inline_styles'], 539 'aria-label' => $nav_menu_name, 540 ) 541 ); 542 543 $modal_unique_id = wp_unique_id( 'modal-' ); 544 545 // Determine whether or not navigation elements should be wrapped in the markup required to make it responsive, 546 // return early if they don't. 547 if ( ! $is_responsive_menu ) { 548 return sprintf( 549 '<nav %1$s>%2$s</nav>', 550 $wrapper_attributes, 551 $inner_blocks_html 552 ); 553 } 554 555 $is_hidden_by_default = isset( $attributes['overlayMenu'] ) && 'always' === $attributes['overlayMenu']; 556 557 $responsive_container_classes = array( 558 'wp-block-navigation__responsive-container', 559 $is_hidden_by_default ? 'hidden-by-default' : '', 560 implode( ' ', $colors['overlay_css_classes'] ), 561 ); 562 $open_button_classes = array( 563 'wp-block-navigation__responsive-container-open', 564 $is_hidden_by_default ? 'always-shown' : '', 565 ); 566 567 $toggle_button_icon = '<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><rect x="4" y="7.5" width="16" height="1.5" /><rect x="4" y="15" width="16" height="1.5" /></svg>'; 568 $should_display_icon_label = isset( $attributes['hasIcon'] ) && true === $attributes['hasIcon']; 569 $toggle_button_content = $should_display_icon_label ? $toggle_button_icon : 'Menu'; 570 571 $responsive_container_markup = sprintf( 572 '<button aria-haspopup="true" aria-label="%3$s" class="%6$s" data-micromodal-trigger="%1$s">%9$s</button> 573 <div class="%5$s" style="%7$s" id="%1$s"> 574 <div class="wp-block-navigation__responsive-close" tabindex="-1" data-micromodal-close> 575 <div class="wp-block-navigation__responsive-dialog" aria-label="%8$s"> 576 <button aria-label="%4$s" data-micromodal-close class="wp-block-navigation__responsive-container-close"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" focusable="false"><path d="M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z"></path></svg></button> 577 <div class="wp-block-navigation__responsive-container-content" id="%1$s-content"> 578 %2$s 579 </div> 580 </div> 581 </div> 582 </div>', 583 esc_attr( $modal_unique_id ), 584 $inner_blocks_html, 585 __( 'Open menu' ), // Open button label. 586 __( 'Close menu' ), // Close button label. 587 esc_attr( implode( ' ', $responsive_container_classes ) ), 588 esc_attr( implode( ' ', $open_button_classes ) ), 589 safecss_filter_attr( $colors['overlay_inline_styles'] ), 590 __( 'Menu' ), 591 $toggle_button_content 592 ); 593 594 return sprintf( 595 '<nav %1$s>%2$s</nav>', 596 $wrapper_attributes, 597 $responsive_container_markup 598 ); 599 } 600 601 /** 602 * Register the navigation block. 603 * 604 * @uses render_block_core_navigation() 605 * @throws WP_Error An WP_Error exception parsing the block definition. 606 */ 607 function register_block_core_navigation() { 608 register_block_type_from_metadata( 609 __DIR__ . '/navigation', 610 array( 611 'render_callback' => 'render_block_core_navigation', 612 ) 613 ); 614 } 615 616 add_action( 'init', 'register_block_core_navigation' ); 617 618 /** 619 * Filter that changes the parsed attribute values of navigation blocks contain typographic presets to contain the values directly. 620 * 621 * @param array $parsed_block The block being rendered. 622 * 623 * @return array The block being rendered without typographic presets. 624 */ 625 function block_core_navigation_typographic_presets_backcompatibility( $parsed_block ) { 626 if ( 'core/navigation' === $parsed_block['blockName'] ) { 627 $attribute_to_prefix_map = array( 628 'fontStyle' => 'var:preset|font-style|', 629 'fontWeight' => 'var:preset|font-weight|', 630 'textDecoration' => 'var:preset|text-decoration|', 631 'textTransform' => 'var:preset|text-transform|', 632 ); 633 foreach ( $attribute_to_prefix_map as $style_attribute => $prefix ) { 634 if ( ! empty( $parsed_block['attrs']['style']['typography'][ $style_attribute ] ) ) { 635 $prefix_len = strlen( $prefix ); 636 $attribute_value = &$parsed_block['attrs']['style']['typography'][ $style_attribute ]; 637 if ( 0 === strncmp( $attribute_value, $prefix, $prefix_len ) ) { 638 $attribute_value = substr( $attribute_value, $prefix_len ); 639 } 640 if ( 'textDecoration' === $style_attribute && 'strikethrough' === $attribute_value ) { 641 $attribute_value = 'line-through'; 642 } 643 } 644 } 645 } 646 647 return $parsed_block; 648 } 649 650 add_filter( 'render_block_data', 'block_core_navigation_typographic_presets_backcompatibility' );
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sat Dec 7 01:00:02 2024 | Cross-referenced by PHPXref 0.7.1 |