diff --git a/src/wp-includes/admin-bar.php b/src/wp-includes/admin-bar.php
index 2ab30a24c27ee..99bb122ec4c36 100644
--- a/src/wp-includes/admin-bar.php
+++ b/src/wp-includes/admin-bar.php
@@ -385,15 +385,35 @@ function wp_admin_bar_site_menu( $wp_admin_bar ) {
}
$title = wp_html_excerpt( $blogname, 40, '…' );
+ $meta = array(
+ 'menu_title' => $title,
+ );
+
+ if ( ! is_network_admin() && ! is_user_admin() ) {
+ /** This filter is documented in wp-includes/admin-bar.php */
+ $show_site_icons = apply_filters( 'wp_admin_bar_show_site_icons', true );
+
+ if ( true === $show_site_icons && has_site_icon() ) {
+ $site_icon_url = get_site_icon_url( 32 );
+ $site_icon_url_2x = get_site_icon_url( 64 );
+ $srcset = ( $site_icon_url_2x && $site_icon_url !== $site_icon_url_2x ) ? sprintf( ' srcset="%s 2x"', esc_url( $site_icon_url_2x ) ) : '';
+ $site_icon = sprintf(
+ '
',
+ esc_url( $site_icon_url ),
+ $srcset
+ );
+
+ $title = $site_icon . $title;
+ $meta['class'] = 'has-site-icon';
+ }
+ }
$wp_admin_bar->add_node(
array(
'id' => 'site-name',
'title' => $title,
'href' => ( is_admin() || ! current_user_can( 'read' ) ) ? home_url( '/' ) : admin_url(),
- 'meta' => array(
- 'menu_title' => $title,
- ),
+ 'meta' => $meta,
)
);
diff --git a/src/wp-includes/css/admin-bar.css b/src/wp-includes/css/admin-bar.css
index 7ab855fd919bb..9d16ac41f4ae2 100644
--- a/src/wp-includes/css/admin-bar.css
+++ b/src/wp-includes/css/admin-bar.css
@@ -539,6 +539,10 @@ html:lang(he-il) .rtl #wpadminbar * {
margin: 0 8px 2px -2px;
}
+#wpadminbar .quicklinks li img.blavatar {
+ border-radius: 2px;
+}
+
#wpadminbar .quicklinks li div.blavatar:before {
content: "\f120";
content: "\f120" / '';
@@ -584,6 +588,23 @@ html:lang(he-il) .rtl #wpadminbar * {
content: "\f102" / '';
}
+#wpadminbar #wp-admin-bar-site-name.has-site-icon > .ab-item {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+}
+
+#wpadminbar #wp-admin-bar-site-name.has-site-icon > .ab-item:before {
+ content: none;
+}
+
+#wpadminbar #wp-admin-bar-site-name > .ab-item .site-icon {
+ width: 20px;
+ height: 20px;
+ background: #f0f0f1; /* matching my-account (user avatar) node's background */
+ border-radius: 2px;
+}
+
/**
@@ -905,7 +926,7 @@ html:lang(he-il) .rtl #wpadminbar * {
#wpadminbar #wp-admin-bar-edit > .ab-item:before,
#wpadminbar #wp-admin-bar-my-sites > .ab-item:before,
- #wpadminbar #wp-admin-bar-site-name > .ab-item:before,
+ #wpadminbar #wp-admin-bar-site-name:not(.has-site-icon) > .ab-item:before,
#wpadminbar #wp-admin-bar-site-editor > .ab-item:before,
#wpadminbar #wp-admin-bar-customize > .ab-item:before,
#wpadminbar #wp-admin-bar-my-account > .ab-item:before,
@@ -920,6 +941,16 @@ html:lang(he-il) .rtl #wpadminbar * {
-moz-osx-font-smoothing: grayscale;
}
+ #wpadminbar #wp-admin-bar-site-name > .ab-item .site-icon {
+ position: absolute;
+ top: 9px;
+ left: 12px;
+ width: 28px;
+ height: 28px;
+ margin: 0;
+ border-radius: 4px;
+ }
+
#wpadminbar #wp-admin-bar-appearance {
margin-top: 0;
}
diff --git a/tests/phpunit/tests/adminbar.php b/tests/phpunit/tests/adminbar.php
index 27308bd82760e..fb29eaf39af42 100644
--- a/tests/phpunit/tests/adminbar.php
+++ b/tests/phpunit/tests/adminbar.php
@@ -810,6 +810,100 @@ public function data_my_sites_network_menu_items() {
);
}
+ /**
+ * @covers ::wp_admin_bar_site_menu
+ */
+ public function test_site_name_menu_has_no_site_icon_when_unset() {
+ wp_set_current_user( self::$editor_id );
+
+ $wp_admin_bar = $this->get_standard_admin_bar();
+ $node_site_name = $wp_admin_bar->get_node( 'site-name' );
+
+ $this->assertStringNotContainsString( 'site-icon', $node_site_name->title );
+ $this->assertArrayNotHasKey( 'class', $node_site_name->meta );
+ }
+
+ /**
+ * @covers ::wp_admin_bar_site_menu
+ * @requires function imagejpeg
+ */
+ public function test_site_name_menu_includes_site_icon_when_set() {
+ wp_set_current_user( self::$editor_id );
+
+ $attachment_id = self::factory()->attachment->create_upload_object( DIR_TESTDATA . '/images/test-image.jpg' );
+ update_option( 'site_icon', $attachment_id );
+
+ $wp_admin_bar = $this->get_standard_admin_bar();
+ $node_site_name = $wp_admin_bar->get_node( 'site-name' );
+
+ $this->assertStringContainsString( '
title );
+ $this->assertStringContainsString( esc_url( get_site_icon_url( 32 ) ), $node_site_name->title );
+ $this->assertSame( 'has-site-icon', $node_site_name->meta['class'] );
+ }
+
+ /**
+ * @covers ::wp_admin_bar_site_menu
+ * @requires function imagejpeg
+ */
+ public function test_site_name_menu_respects_show_site_icons_filter() {
+ wp_set_current_user( self::$editor_id );
+
+ $attachment_id = self::factory()->attachment->create_upload_object( DIR_TESTDATA . '/images/test-image.jpg' );
+ update_option( 'site_icon', $attachment_id );
+
+ add_filter( 'wp_admin_bar_show_site_icons', '__return_false' );
+
+ $wp_admin_bar = $this->get_standard_admin_bar();
+ $node_site_name = $wp_admin_bar->get_node( 'site-name' );
+
+ $this->assertStringNotContainsString( 'site-icon', $node_site_name->title );
+ $this->assertArrayNotHasKey( 'class', $node_site_name->meta );
+ }
+
+ /**
+ * @covers ::wp_admin_bar_site_menu
+ * @group multisite
+ * @group ms-required
+ * @requires function imagejpeg
+ */
+ public function test_site_name_menu_has_no_site_icon_in_network_admin() {
+ wp_set_current_user( self::$admin_id );
+
+ $attachment_id = self::factory()->attachment->create_upload_object( DIR_TESTDATA . '/images/test-image.jpg' );
+ update_option( 'site_icon', $attachment_id );
+
+ set_current_screen( 'dashboard-network' );
+
+ $wp_admin_bar = $this->get_standard_admin_bar();
+ $node_site_name = $wp_admin_bar->get_node( 'site-name' );
+
+ $this->assertTrue( is_network_admin() );
+ $this->assertStringNotContainsString( 'site-icon', $node_site_name->title );
+ $this->assertArrayNotHasKey( 'class', $node_site_name->meta );
+ }
+
+ /**
+ * @covers ::wp_admin_bar_site_menu
+ * @group multisite
+ * @group ms-required
+ * @requires function imagejpeg
+ */
+ public function test_site_name_menu_has_no_site_icon_in_user_admin() {
+ wp_set_current_user( self::$admin_id );
+
+ $attachment_id = self::factory()->attachment->create_upload_object( DIR_TESTDATA . '/images/test-image.jpg' );
+ update_option( 'site_icon', $attachment_id );
+
+ set_current_screen( 'dashboard-user' );
+
+ $wp_admin_bar = $this->get_standard_admin_bar();
+ $node_site_name = $wp_admin_bar->get_node( 'site-name' );
+
+ $this->assertTrue( is_user_admin() );
+ $this->assertStringNotContainsString( 'site-icon', $node_site_name->title );
+ $this->assertArrayNotHasKey( 'class', $node_site_name->meta );
+ }
+
/**
* This test ensures that WP_Admin_Bar::$proto is not defined (including magic methods).
*