wp/wp-includes/blocks/navigation-link.php
changeset 21 48c4eec2b7e6
parent 19 3d72ae0968f4
child 22 8c2e4d02f4ef
equal deleted inserted replaced
20:7b1b88e27a20 21:48c4eec2b7e6
     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 	}
   230 	return $html;
   283 	return $html;
   231 }
   284 }
   232 
   285 
   233 /**
   286 /**
   234  * Returns a navigation link variation
   287  * Returns a navigation link variation
       
   288  *
       
   289  * @since 5.9.0
   235  *
   290  *
   236  * @param WP_Taxonomy|WP_Post_Type $entity post type or taxonomy entity.
   291  * @param WP_Taxonomy|WP_Post_Type $entity post type or taxonomy entity.
   237  * @param string                   $kind string of value 'taxonomy' or 'post-type'.
   292  * @param string                   $kind string of value 'taxonomy' or 'post-type'.
   238  *
   293  *
   239  * @return array
   294  * @return array
   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 );