diff --git a/src/wp-includes/blocks/navigation.php b/src/wp-includes/blocks/navigation.php
new file mode 100644
index 0000000000000..13b6df425626a
--- /dev/null
+++ b/src/wp-includes/blocks/navigation.php
@@ -0,0 +1,195 @@
+ array(),
+ 'inline_styles' => '',
+ );
+
+ $has_named_text_color = array_key_exists( 'textColor', $attributes );
+ $has_custom_text_color = array_key_exists( 'customTextColor', $attributes );
+
+ // If has text color.
+ if ( $has_custom_text_color || $has_named_text_color ) {
+ // Add has-text-color class.
+ $colors['css_classes'][] = 'has-text-color';
+ }
+
+ if ( $has_named_text_color ) {
+ // Add the color class.
+ $colors['css_classes'][] = sprintf( 'has-%s-color', $attributes['textColor'] );
+ } elseif ( $has_custom_text_color ) {
+ // Add the custom color inline style.
+ $colors['inline_styles'] = sprintf( 'color: %s;', $attributes['customTextColor'] );
+ }
+
+ return $colors;
+}
+
+/**
+ * Build an array with CSS classes and inline styles defining the font sizes
+ * which will be applied to the navigation markup in the front-end.
+ *
+ * @param array $attributes Navigation block attributes.
+ * @return array Font size CSS classes and inline styles.
+ */
+function build_css_font_sizes( $attributes ) {
+ // CSS classes.
+ $font_sizes = array(
+ 'css_classes' => array(),
+ 'inline_styles' => '',
+ );
+
+ $has_named_font_size = array_key_exists( 'fontSize', $attributes );
+ $has_custom_font_size = array_key_exists( 'customFontSize', $attributes );
+
+ if ( $has_named_font_size ) {
+ // Add the font size class.
+ $font_sizes['css_classes'][] = sprintf( 'has-%s-font-size', $attributes['fontSize'] );
+ } elseif ( $has_custom_font_size ) {
+ // Add the custom font size inline style.
+ $font_sizes['inline_styles'] = sprintf( 'font-size: %spx;', $attributes['customFontSize'] );
+ }
+
+ return $font_sizes;
+}
+
+/**
+ * Renders the `core/navigation` block on server.
+ *
+ * @param array $attributes The block attributes.
+ * @param array $content The saved content.
+ * @param array $block The parsed block.
+ *
+ * @return string Returns the post content with the legacy widget added.
+ */
+function render_block_navigation( $attributes, $content, $block ) {
+ $colors = build_css_colors( $attributes );
+ $font_sizes = build_css_font_sizes( $attributes );
+ $classes = array_merge(
+ $colors['css_classes'],
+ $font_sizes['css_classes'],
+ array( 'wp-block-navigation' ),
+ isset( $attributes['className'] ) ? array( $attributes['className'] ) : array(),
+ isset( $attributes['itemsJustification'] ) ? array( 'items-justified-' . $attributes['itemsJustification'] ) : array(),
+ isset( $attributes['align'] ) ? array( 'align' . $attributes['align'] ) : array()
+ );
+ $class_attribute = sprintf( ' class="%s"', esc_attr( implode( ' ', $classes ) ) );
+ $style_attribute = ( $colors['inline_styles'] || $font_sizes['inline_styles'] )
+ ? sprintf( ' style="%s"', esc_attr( $colors['inline_styles'] ) . esc_attr( $font_sizes['inline_styles'] ) )
+ : '';
+
+ return sprintf(
+ '',
+ $class_attribute,
+ $style_attribute,
+ build_navigation_html( $block, $colors, $font_sizes )
+ );
+}
+
+/**
+ * Walks the inner block structure and returns an HTML list for it.
+ *
+ * @param array $block The block.
+ * @param array $colors Contains inline styles and CSS classes to apply to navigation item.
+ * @param array $font_sizes Contains inline styles and CSS classes to apply to navigation item.
+ *
+ * @return string Returns an HTML list from innerBlocks.
+ */
+function build_navigation_html( $block, $colors, $font_sizes ) {
+ $html = '';
+ $classes = array_merge(
+ $colors['css_classes'],
+ $font_sizes['css_classes']
+ );
+ $css_classes = implode( ' ', $classes );
+ $class_attribute = sprintf( ' class="wp-block-navigation-link__content %s"', esc_attr( trim( $css_classes ) ) );
+ $style_attribute = ( $colors['inline_styles'] || $font_sizes['inline_styles'] )
+ ? sprintf( ' style="%s"', esc_attr( $colors['inline_styles'] ) . esc_attr( $font_sizes['inline_styles'] ) )
+ : '';
+
+ foreach ( (array) $block['innerBlocks'] as $key => $block ) {
+
+ $html .= '
' .
+ ' 0 ) {
+ $html .= build_navigation_html( $block, $colors, $font_sizes );
+ }
+
+ $html .= '';
+ }
+ return '';
+}
+
+/**
+ * Register the navigation block.
+ *
+ * @uses render_block_navigation()
+ * @throws WP_Error An WP_Error exception parsing the block definition.
+ */
+function register_block_core_navigation() {
+
+ register_block_type(
+ 'core/navigation',
+ array(
+ 'attributes' => array(
+ 'className' => array(
+ 'type' => 'string',
+ ),
+ 'textColor' => array(
+ 'type' => 'string',
+ ),
+ 'customTextColor' => array(
+ 'type' => 'string',
+ ),
+ 'fontSize' => array(
+ 'type' => 'string',
+ ),
+ 'customFontSize' => array(
+ 'type' => 'number',
+ ),
+ 'itemsJustification' => array(
+ 'type' => 'string',
+ ),
+ ),
+
+ 'render_callback' => 'render_block_navigation',
+ )
+ );
+}
+add_action( 'init', 'register_block_core_navigation' );
diff --git a/src/wp-settings.php b/src/wp-settings.php
index 13f9bbb3a51e1..230b54010a6d5 100644
--- a/src/wp-settings.php
+++ b/src/wp-settings.php
@@ -263,6 +263,7 @@
require( ABSPATH . WPINC . '/blocks/categories.php' );
require( ABSPATH . WPINC . '/blocks/latest-comments.php' );
require( ABSPATH . WPINC . '/blocks/latest-posts.php' );
+require( ABSPATH . WPINC . '/blocks/navigation.php' );
require( ABSPATH . WPINC . '/blocks/rss.php' );
require( ABSPATH . WPINC . '/blocks/search.php' );
require( ABSPATH . WPINC . '/blocks/shortcode.php' );
diff --git a/tests/phpunit/includes/functions.php b/tests/phpunit/includes/functions.php
index 4fcb1601e303a..a69354d9b798c 100644
--- a/tests/phpunit/includes/functions.php
+++ b/tests/phpunit/includes/functions.php
@@ -301,6 +301,7 @@ function _unhook_block_registration() {
remove_action( 'init', 'register_block_core_categories' );
remove_action( 'init', 'register_block_core_latest_comments' );
remove_action( 'init', 'register_block_core_latest_posts' );
+ remove_action( 'init', 'register_block_core_navigation' );
remove_action( 'init', 'register_block_core_rss' );
remove_action( 'init', 'register_block_core_search' );
remove_action( 'init', 'register_block_core_shortcode' );
diff --git a/tests/phpunit/tests/rest-api/rest-schema-setup.php b/tests/phpunit/tests/rest-api/rest-schema-setup.php
index 0aeebb4352b83..1a207db546cf8 100644
--- a/tests/phpunit/tests/rest-api/rest-schema-setup.php
+++ b/tests/phpunit/tests/rest-api/rest-schema-setup.php
@@ -126,6 +126,7 @@ public function test_expected_routes_in_schema() {
'/wp/v2/block-renderer/(?Pcore/categories)',
'/wp/v2/block-renderer/(?Pcore/latest-comments)',
'/wp/v2/block-renderer/(?Pcore/latest-posts)',
+ '/wp/v2/block-renderer/(?Pcore/navigation)',
'/wp/v2/block-renderer/(?Pcore/rss)',
'/wp/v2/block-renderer/(?Pcore/search)',
'/wp/v2/block-renderer/(?Pcore/shortcode)',
diff --git a/tests/qunit/fixtures/wp-api-generated.js b/tests/qunit/fixtures/wp-api-generated.js
index 9c130539b789c..c709db9f6f5e5 100644
--- a/tests/qunit/fixtures/wp-api-generated.js
+++ b/tests/qunit/fixtures/wp-api-generated.js
@@ -4632,6 +4632,46 @@ mockedApiResponse.Schema = {
}
]
},
+ "/wp/v2/block-renderer/(?Pcore/navigation)": {
+ "namespace": "wp/v2",
+ "methods": [
+ "GET"
+ ],
+ "endpoints": [
+ {
+ "methods": [
+ "GET"
+ ],
+ "args": {
+ "name": {
+ "required": false,
+ "description": "Unique registered name for the block.",
+ "type": "string"
+ },
+ "context": {
+ "required": false,
+ "default": "view",
+ "enum": [
+ "edit"
+ ],
+ "description": "Scope under which the request is made; determines fields present in response.",
+ "type": "string"
+ },
+ "attributes": {
+ "required": false,
+ "default": [],
+ "description": "Attributes for core/navigation block",
+ "type": "object"
+ },
+ "post_id": {
+ "required": false,
+ "description": "ID of the post context.",
+ "type": "integer"
+ }
+ }
+ }
+ ]
+ },
"/wp/v2/block-renderer/(?Pcore/rss)": {
"namespace": "wp/v2",
"methods": [
diff --git a/tools/webpack/packages.js b/tools/webpack/packages.js
index ab9e2fdef1e51..a62245312645e 100644
--- a/tools/webpack/packages.js
+++ b/tools/webpack/packages.js
@@ -101,6 +101,7 @@ module.exports = function( env = { environment: 'production', watch: false, buil
'categories',
'latest-comments',
'latest-posts',
+ 'navigation',
'rss',
'search',
'shortcode',