diff --git a/src/wp-includes/embed.php b/src/wp-includes/embed.php index 3fb8968c7c62c..b53c00f67ddc7 100644 --- a/src/wp-includes/embed.php +++ b/src/wp-includes/embed.php @@ -1233,11 +1233,23 @@ function print_embed_sharing_dialog() { * @since 4.5.0 */ function the_embed_site_title() { + $site_icon_url = get_site_icon_url( 32, includes_url( 'images/w-logo-blue.png' ) ); + + $icon_img = ''; + if ( $site_icon_url ) { + $site_icon_url_2x = get_site_icon_url( 64, includes_url( 'images/w-logo-blue.png' ) ); + $srcset = ( $site_icon_url_2x && $site_icon_url !== $site_icon_url_2x ) ? sprintf( ' srcset="%s 2x"', esc_url( $site_icon_url_2x ) ) : ''; + $icon_img = sprintf( + '', + esc_url( $site_icon_url ), + $srcset + ); + } + $site_title = sprintf( - '%s', + '%s%s', esc_url( home_url() ), - esc_url( get_site_icon_url( 32, includes_url( 'images/w-logo-blue.png' ) ) ), - esc_url( get_site_icon_url( 64, includes_url( 'images/w-logo-blue.png' ) ) ), + $icon_img, esc_html( get_bloginfo( 'name' ) ) ); diff --git a/src/wp-includes/general-template.php b/src/wp-includes/general-template.php index 47e2aeb2ebb05..1ba2912953ae8 100644 --- a/src/wp-includes/general-template.php +++ b/src/wp-includes/general-template.php @@ -978,7 +978,10 @@ function get_site_icon_url( $size = 512, $url = '', $blog_id = 0 ) { } else { $size_data = array( $size, $size ); } - $url = wp_get_attachment_image_url( $site_icon_id, $size_data ); + $attachment_url = wp_get_attachment_image_url( $site_icon_id, $size_data ); + if ( $attachment_url ) { + $url = $attachment_url; + } } if ( $switched_blog ) { diff --git a/tests/phpunit/tests/general/template.php b/tests/phpunit/tests/general/template.php index d3b35a2c46c2b..23c689466c162 100644 --- a/tests/phpunit/tests/general/template.php +++ b/tests/phpunit/tests/general/template.php @@ -122,6 +122,27 @@ public function test_get_site_icon_url() { $this->assertEmpty( get_site_icon_url(), 'Site icon URL should not be set after removal.' ); } + /** + * @ticket 65098 + * @group site_icon + * @covers ::get_site_icon_url + * @requires function imagejpeg + */ + public function test_get_site_icon_url_returns_fallback_when_attachment_url_fails() { + $this->set_site_icon(); + + $fallback = 'https://example.com/fallback-icon.png'; + add_filter( 'wp_get_attachment_image_src', '__return_false' ); + + try { + $url = get_site_icon_url( 32, $fallback ); + } finally { + remove_filter( 'wp_get_attachment_image_src', '__return_false' ); + } + + $this->assertSame( $fallback, $url, 'Fallback URL should be returned when attachment URL lookup fails.' ); + } + /** * @group site_icon * @covers ::site_icon_url @@ -807,4 +828,116 @@ public function test_get_the_archive_title_is_correct_for_author_queries() { $this->assertSame( $user_with_posts->display_name, $title_when_posts ); $this->assertSame( $user_with_no_posts->display_name, $title_when_no_posts ); } + + /** + * @ticket 65098 + * @group site_icon + * @covers ::the_embed_site_title + * @requires function imagejpeg + */ + public function test_the_embed_site_title_contains_site_icon_when_set() { + $this->set_site_icon(); + + $url_32 = get_site_icon_url( 32 ); + $url_64 = get_site_icon_url( 64 ); + + ob_start(); + the_embed_site_title(); + $output = ob_get_clean(); + + $this->assertStringContainsString( 'wp-embed-site-icon', $output, 'Output should contain site icon img tag.' ); + $this->assertStringContainsString( esc_url( $url_32 ), $output, 'Output should contain 32px site icon URL.' ); + $this->assertStringContainsString( esc_url( $url_64 ), $output, 'Output should contain 64px site icon URL in srcset.' ); + } + + /** + * @ticket 65098 + * @group site_icon + * @covers ::the_embed_site_title + * @requires function imagejpeg + */ + public function test_the_embed_site_title_uses_fallback_when_attachment_url_fails() { + $this->set_site_icon(); + + // Simulate wp_get_attachment_image_url() failing. + add_filter( 'wp_get_attachment_image_src', '__return_false' ); + + try { + ob_start(); + the_embed_site_title(); + $output = ob_get_clean(); + } finally { + remove_filter( 'wp_get_attachment_image_src', '__return_false' ); + } + + $fallback = includes_url( 'images/w-logo-blue.png' ); + $this->assertStringContainsString( 'wp-embed-site-icon', $output, 'Output should contain site icon img tag with fallback.' ); + $this->assertStringContainsString( esc_url( $fallback ), $output, 'Output should contain fallback URL when attachment URL fails.' ); + $this->assertStringNotContainsString( 'src=""', $output, 'Output should not contain empty src attribute.' ); + } + + /** + * @ticket 65098 + * @group site_icon + * @covers ::the_embed_site_title + */ + public function test_the_embed_site_title_omits_img_when_url_is_empty() { + // Force get_site_icon_url() to return empty string via filter. + add_filter( 'get_site_icon_url', '__return_empty_string' ); + + try { + ob_start(); + the_embed_site_title(); + $output = ob_get_clean(); + } finally { + remove_filter( 'get_site_icon_url', '__return_empty_string' ); + } + + $this->assertStringNotContainsString( 'wp-embed-site-icon', $output, 'img tag should be omitted when URL is empty.' ); + $this->assertStringNotContainsString( 'src=""', $output, 'Output should not contain empty src attribute.' ); + $this->assertStringContainsString( get_bloginfo( 'name' ), $output, 'Site name should still be present.' ); + } + + /** + * @ticket 65098 + * @group site_icon + * @covers ::the_embed_site_title + */ + public function test_the_embed_site_title_omits_srcset_when_1x_and_2x_urls_are_identical() { + // Force both sizes to return the same URL. + $svg_url = 'https://example.com/icon.svg'; + $filter = static function () use ( $svg_url ) { + return $svg_url; + }; + + add_filter( 'get_site_icon_url', $filter ); + + try { + ob_start(); + the_embed_site_title(); + $output = ob_get_clean(); + } finally { + remove_filter( 'get_site_icon_url', $filter ); + } + + $this->assertStringNotContainsString( 'srcset=', $output, 'srcset should be omitted when 1x and 2x URLs are identical.' ); + $this->assertStringContainsString( esc_url( $svg_url ), $output, '1x URL should still be present in src.' ); + } + + /** + * @ticket 65098 + * @group site_icon + * @covers ::the_embed_site_title + */ + public function test_the_embed_site_title_uses_fallback_without_srcset_when_no_site_icon_set() { + ob_start(); + the_embed_site_title(); + $output = ob_get_clean(); + + $fallback = includes_url( 'images/w-logo-blue.png' ); + + $this->assertStringContainsString( 'wp-embed-site-icon', $output, 'Fallback icon img should be present when no site icon is set.' ); + $this->assertStringContainsString( esc_url( $fallback ), $output, 'Output should contain fallback icon URL.' ); + $this->assertStringNotContainsString( 'srcset=', $output, 'srcset should be omitted when 1x and 2x fallback URLs are identical.' ); + } }