diff --git a/lib/blocks.php b/lib/blocks.php
index aff9e254edf1c6..1ba9e37e1b84be 100644
--- a/lib/blocks.php
+++ b/lib/blocks.php
@@ -26,6 +26,7 @@ function gutenberg_reregister_core_block_types() {
'group',
'heading',
'html',
+ 'home-link',
'image',
'list',
'media-text',
@@ -59,6 +60,7 @@ function gutenberg_reregister_core_block_types() {
'loginout.php' => 'core/loginout',
'navigation.php' => 'core/navigation',
'navigation-link.php' => 'core/navigation-link',
+ 'home-link.php' => 'core/home-link',
'rss.php' => 'core/rss',
'search.php' => 'core/search',
'shortcode.php' => 'core/shortcode',
diff --git a/packages/block-library/src/home-link/block.json b/packages/block-library/src/home-link/block.json
new file mode 100644
index 00000000000000..42cea69c7aaf7f
--- /dev/null
+++ b/packages/block-library/src/home-link/block.json
@@ -0,0 +1,29 @@
+{
+ "apiVersion": 2,
+ "name": "core/home-link",
+ "category": "design",
+ "parent": [ "core/navigation" ],
+ "title": "Home Link",
+ "description": "Create a link that always points to the homepage of the site. Usually not necessary if there is already a site title link present in the header.",
+ "textdomain": "default",
+ "attributes": {
+ "label": {
+ "type": "string"
+ }
+ },
+ "usesContext": [
+ "textColor",
+ "customTextColor",
+ "backgroundColor",
+ "customBackgroundColor",
+ "fontSize",
+ "customFontSize",
+ "style"
+ ],
+ "supports": {
+ "reusable": false,
+ "html": false
+ },
+ "editorStyle": "wp-block-home-link-editor",
+ "style": "wp-block-home-link"
+}
diff --git a/packages/block-library/src/home-link/edit.js b/packages/block-library/src/home-link/edit.js
new file mode 100644
index 00000000000000..85571c518c8621
--- /dev/null
+++ b/packages/block-library/src/home-link/edit.js
@@ -0,0 +1,86 @@
+/**
+ * External dependencies
+ */
+import classnames from 'classnames';
+
+/**
+ * WordPress dependencies
+ */
+import { RichText, useBlockProps } from '@wordpress/block-editor';
+import { __ } from '@wordpress/i18n';
+import { useSelect } from '@wordpress/data';
+import { store as coreStore } from '@wordpress/core-data';
+import { useEffect } from '@wordpress/element';
+
+const preventDefault = ( event ) => event.preventDefault();
+
+export default function HomeEdit( {
+ attributes,
+ setAttributes,
+ context,
+ clientId,
+} ) {
+ const { homeUrl } = useSelect(
+ ( select ) => {
+ const {
+ getUnstableBase, //site index
+ } = select( coreStore );
+ return {
+ homeUrl: getUnstableBase()?.home,
+ };
+ },
+ [ clientId ]
+ );
+
+ const { textColor, backgroundColor, style } = context;
+ const blockProps = useBlockProps( {
+ className: classnames( {
+ 'has-text-color': !! textColor || !! style?.color?.text,
+ [ `has-${ textColor }-color` ]: !! textColor,
+ 'has-background': !! backgroundColor || !! style?.color?.background,
+ [ `has-${ backgroundColor }-background-color` ]: !! backgroundColor,
+ } ),
+ style: {
+ color: style?.color?.text,
+ backgroundColor: style?.color?.background,
+ },
+ } );
+
+ const { label } = attributes;
+
+ useEffect( () => {
+ if ( label === undefined ) {
+ setAttributes( { label: __( 'Home' ) } );
+ }
+ }, [ clientId, label ] );
+
+ return (
+ <>
+
+
+ {
+ setAttributes( { label: labelValue } );
+ } }
+ aria-label={ __( 'Home link text' ) }
+ placeholder={ __( 'Add home link' ) }
+ withoutInteractiveFormatting
+ allowedFormats={ [
+ 'core/bold',
+ 'core/italic',
+ 'core/image',
+ 'core/strikethrough',
+ ] }
+ />
+
+
+ >
+ );
+}
diff --git a/packages/block-library/src/home-link/index.js b/packages/block-library/src/home-link/index.js
new file mode 100644
index 00000000000000..5bb3914bb1bf33
--- /dev/null
+++ b/packages/block-library/src/home-link/index.js
@@ -0,0 +1,30 @@
+/**
+ * WordPress dependencies
+ */
+import { _x } from '@wordpress/i18n';
+import { home } from '@wordpress/icons';
+
+/**
+ * Internal dependencies
+ */
+import metadata from './block.json';
+import edit from './edit';
+import save from './save';
+
+const { name } = metadata;
+
+export { metadata, name };
+
+export const settings = {
+ icon: home,
+
+ edit,
+
+ save,
+
+ example: {
+ attributes: {
+ label: _x( 'Home Link', 'block example' ),
+ },
+ },
+};
diff --git a/packages/block-library/src/home-link/index.php b/packages/block-library/src/home-link/index.php
new file mode 100644
index 00000000000000..eafd27461c0972
--- /dev/null
+++ b/packages/block-library/src/home-link/index.php
@@ -0,0 +1,178 @@
+ array(),
+ 'inline_styles' => '',
+ );
+
+ // Text color.
+ $has_named_text_color = array_key_exists( 'textColor', $context );
+ $has_custom_text_color = isset( $context['style']['color']['text'] );
+
+ // 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', $context['textColor'] );
+ } elseif ( $has_custom_text_color ) {
+ // Add the custom color inline style.
+ $colors['inline_styles'] .= sprintf( 'color: %s;', $context['style']['color']['text'] );
+ }
+
+ // Background color.
+ $has_named_background_color = array_key_exists( 'backgroundColor', $context );
+ $has_custom_background_color = isset( $context['style']['color']['background'] );
+
+ // If has background color.
+ if ( $has_custom_background_color || $has_named_background_color ) {
+ // Add has-background class.
+ $colors['css_classes'][] = 'has-background';
+ }
+
+ if ( $has_named_background_color ) {
+ // Add the background-color class.
+ $colors['css_classes'][] = sprintf( 'has-%s-background-color', $context['backgroundColor'] );
+ } elseif ( $has_custom_background_color ) {
+ // Add the custom background-color inline style.
+ $colors['inline_styles'] .= sprintf( 'background-color: %s;', $context['style']['color']['background'] );
+ }
+
+ return $colors;
+}
+
+/**
+ * Build an array with CSS classes and inline styles defining the font sizes
+ * which will be applied to the home link markup in the front-end.
+ *
+ * @param array $context Home link block context.
+ * @return array Font size CSS classes and inline styles.
+ */
+function block_core_home_link_build_css_font_sizes( $context ) {
+ // CSS classes.
+ $font_sizes = array(
+ 'css_classes' => array(),
+ 'inline_styles' => '',
+ );
+
+ $has_named_font_size = array_key_exists( 'fontSize', $context );
+ $has_custom_font_size = isset( $context['style']['typography']['fontSize'] );
+
+ if ( $has_named_font_size ) {
+ // Add the font size class.
+ $font_sizes['css_classes'][] = sprintf( 'has-%s-font-size', $context['fontSize'] );
+ } elseif ( $has_custom_font_size ) {
+ // Add the custom font size inline style.
+ $font_sizes['inline_styles'] = sprintf( 'font-size: %spx;', $context['style']['typography']['fontSize'] );
+ }
+
+ return $font_sizes;
+}
+
+/**
+ * Builds an array with classes and style for the li wrapper
+ *
+ * @param array $context Home link block context.
+ * @return array The li wrapper attributes.
+ */
+function block_core_home_link_build_li_wrapper_attributes( $context ) {
+ $colors = block_core_home_link_build_css_colors( $context );
+ $font_sizes = block_core_home_link_build_css_font_sizes( $context );
+ $classes = array_merge(
+ $colors['css_classes'],
+ $font_sizes['css_classes']
+ );
+ $style_attribute = ( $colors['inline_styles'] . $font_sizes['inline_styles'] );
+ $css_classes = trim( implode( ' ', $classes ) );
+
+ $wrapper_attributes = get_block_wrapper_attributes(
+ array(
+ 'class' => $css_classes,
+ 'style' => $style_attribute,
+ )
+ );
+
+ return $wrapper_attributes;
+}
+
+/**
+ * Renders the `core/home-link` block.
+ *
+ * @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 home url added.
+ */
+function render_block_core_home_link( $attributes, $content, $block ) {
+ if ( empty( $attributes['label'] ) ) {
+ return '';
+ }
+
+ $wrapper_attributes = block_core_home_link_build_li_wrapper_attributes( $block->context );
+
+ $html = ' array(),
+ 'em' => array(),
+ 'img' => array(
+ 'scale' => array(),
+ 'class' => array(),
+ 'style' => array(),
+ 'src' => array(),
+ 'alt' => array(),
+ ),
+ 's' => array(),
+ 'span' => array(
+ 'style' => array(),
+ ),
+ 'strong' => array(),
+ )
+ );
+ }
+
+ $html .= '';
+ return $html;
+}
+
+/**
+ * Register the home block
+ *
+ * @uses render_block_core_home_link()
+ * @throws WP_Error An WP_Error exception parsing the block definition.
+ */
+function register_block_core_home_link() {
+ register_block_type_from_metadata(
+ __DIR__ . '/home-link',
+ array(
+ 'render_callback' => 'render_block_core_home_link',
+ )
+ );
+}
+add_action( 'init', 'register_block_core_home_link' );
diff --git a/packages/block-library/src/home-link/save.js b/packages/block-library/src/home-link/save.js
new file mode 100644
index 00000000000000..17571d8f30d2de
--- /dev/null
+++ b/packages/block-library/src/home-link/save.js
@@ -0,0 +1,8 @@
+/**
+ * WordPress dependencies
+ */
+import { InnerBlocks } from '@wordpress/block-editor';
+
+export default function save() {
+ return ;
+}
diff --git a/packages/block-library/src/home-link/style.scss b/packages/block-library/src/home-link/style.scss
new file mode 100644
index 00000000000000..76f91efc581122
--- /dev/null
+++ b/packages/block-library/src/home-link/style.scss
@@ -0,0 +1,52 @@
+.wp-block-navigation {
+
+ .wp-block-home-link__content {
+ // Inherit colors set by the block color definition.
+ color: inherit;
+ display: block;
+ padding: 0.5em 1em;
+ }
+
+ // Force links to inherit text decoration applied to navigation block.
+ // The extra selector adds specificity to ensure it works when user-set.
+ &[style*="text-decoration"] {
+ .wp-block-home-link {
+ text-decoration: inherit;
+ }
+
+ .wp-block-home-link__content {
+ text-decoration: inherit;
+
+ &:focus,
+ &:active {
+ text-decoration: inherit;
+ }
+ }
+ }
+
+ &:not([style*="text-decoration"]) {
+ .wp-block-home-link__content {
+ text-decoration: none;
+
+ &:focus,
+ &:active {
+ text-decoration: none;
+ }
+ }
+ }
+}
+
+// Default background and font color.
+.wp-block-navigation:not(.has-background) {
+ .wp-block-navigation__container .wp-block-home-link__container {
+ // Set a background color for submenus so that they're not transparent.
+ background-color: #fff;
+ color: #000;
+ border: 1px solid rgba(0, 0, 0, 0.15);
+
+ .wp-block-home-link__container {
+ top: -1px;
+ }
+ }
+}
+
diff --git a/packages/block-library/src/index.js b/packages/block-library/src/index.js
index 26e22c76af314f..a4ec8243c4e74c 100644
--- a/packages/block-library/src/index.js
+++ b/packages/block-library/src/index.js
@@ -35,6 +35,7 @@ import * as html from './html';
import * as mediaText from './media-text';
import * as navigation from './navigation';
import * as navigationLink from './navigation-link';
+import * as homeLink from './home-link';
import * as latestComments from './latest-comments';
import * as latestPosts from './latest-posts';
import * as legacyWidget from './legacy-widget';
@@ -233,6 +234,7 @@ export const __experimentalRegisterExperimentalCoreBlocks =
[
navigation,
navigationLink,
+ homeLink,
// Register Legacy Widget block.
...( enableLegacyWidgetBlock ? [ legacyWidget ] : [] ),
diff --git a/packages/block-library/src/navigation/edit.js b/packages/block-library/src/navigation/edit.js
index 18d9da732015c9..b086931cb8bece 100644
--- a/packages/block-library/src/navigation/edit.js
+++ b/packages/block-library/src/navigation/edit.js
@@ -35,6 +35,7 @@ const ALLOWED_BLOCKS = [
'core/social-links',
'core/page-list',
'core/spacer',
+ 'core/home-link',
];
const LAYOUT = {
diff --git a/packages/block-library/src/style.scss b/packages/block-library/src/style.scss
index 03098c0a6b1521..6cab6d6a71f25e 100644
--- a/packages/block-library/src/style.scss
+++ b/packages/block-library/src/style.scss
@@ -23,6 +23,7 @@
@import "./media-text/style.scss";
@import "./navigation/style.scss";
@import "./navigation-link/style.scss";
+@import "./home-link/style.scss";
@import "./page-list/style.scss";
@import "./paragraph/style.scss";
@import "./post-author/style.scss";
diff --git a/packages/e2e-tests/fixtures/blocks/core__home-link.html b/packages/e2e-tests/fixtures/blocks/core__home-link.html
new file mode 100644
index 00000000000000..e1564a33298ae6
--- /dev/null
+++ b/packages/e2e-tests/fixtures/blocks/core__home-link.html
@@ -0,0 +1 @@
+
diff --git a/packages/e2e-tests/fixtures/blocks/core__home-link.json b/packages/e2e-tests/fixtures/blocks/core__home-link.json
new file mode 100644
index 00000000000000..1a2c5fc0c6c5d5
--- /dev/null
+++ b/packages/e2e-tests/fixtures/blocks/core__home-link.json
@@ -0,0 +1,12 @@
+[
+ {
+ "clientId": "_clientId_0",
+ "name": "core/home-link",
+ "isValid": true,
+ "attributes": {
+ "label": "Home"
+ },
+ "innerBlocks": [],
+ "originalContent": ""
+ }
+]
diff --git a/packages/e2e-tests/fixtures/blocks/core__home-link.parsed.json b/packages/e2e-tests/fixtures/blocks/core__home-link.parsed.json
new file mode 100644
index 00000000000000..7dee324f4fd40e
--- /dev/null
+++ b/packages/e2e-tests/fixtures/blocks/core__home-link.parsed.json
@@ -0,0 +1,11 @@
+[
+ {
+ "blockName": "core/home-link",
+ "attrs": {
+ "label": "Home"
+ },
+ "innerBlocks": [],
+ "innerHTML": "",
+ "innerContent": []
+ }
+]
diff --git a/packages/e2e-tests/fixtures/blocks/core__home-link.serialized.html b/packages/e2e-tests/fixtures/blocks/core__home-link.serialized.html
new file mode 100644
index 00000000000000..e1564a33298ae6
--- /dev/null
+++ b/packages/e2e-tests/fixtures/blocks/core__home-link.serialized.html
@@ -0,0 +1 @@
+