Make WordPress Core

Changeset 62502


Ignore:
Timestamp:
06/15/2026 08:47:05 PM (3 months ago)
Author:
westonruter
Message:

Embeds: Preserve the site icon fallback URL.

Previously, get_site_icon_url() overwrote a caller-supplied fallback URL with the return value of wp_get_attachment_image_url() even when that lookup returned false, so a defined fallback (such as the bundled WordPress logo) was silently discarded whenever the assigned site icon attachment could not be resolved. Only update the URL when a non-empty attachment URL is returned.

Additionally, the_embed_site_title() now renders the site icon <img> only when a URL is available, and omits the srcset attribute when the 2x URL is missing or identical to the 1x URL. This avoids the malformed markup (an empty src and a bare 2x srcset) that produced a broken image and spurious requests in oEmbed cards.

Developed in https://github.com/WordPress/wordpress-develop/pull/11601.
Follow-up to r35571, r36693, r47832.

Props sukhendu2002, sabernhardt, mukesh27, westonruter, pontocinza, mohamedahamed, abcd95, manhar, rollybueno.
Fixes #65098.

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/embed.php

    r62176 r62502  
    12331233 * @since 4.5.0
    12341234 */
    1235 function the_embed_site_title() {
     1235function the_embed_site_title(): void {
     1236        $fallback_icon_url = includes_url( 'images/w-logo-blue.png' );
     1237        $site_icon_url     = get_site_icon_url( 32, $fallback_icon_url );
     1238
     1239        $icon_img = '';
     1240        if ( $site_icon_url ) {
     1241                $site_icon_url_2x = get_site_icon_url( 64, $fallback_icon_url );
     1242                $srcset           = ( $site_icon_url_2x && $site_icon_url !== $site_icon_url_2x ) ? sprintf( ' srcset="%s 2x"', esc_url( $site_icon_url_2x ) ) : '';
     1243                $icon_img         = sprintf(
     1244                        '<img src="%s"%s width="32" height="32" alt="" class="wp-embed-site-icon" />',
     1245                        esc_url( $site_icon_url ),
     1246                        $srcset
     1247                );
     1248        }
     1249
    12361250        $site_title = sprintf(
    1237                 '<a href="%s" target="_top"><img src="%s" srcset="%s 2x" width="32" height="32" alt="" class="wp-embed-site-icon" /><span>%s</span></a>',
     1251                '<a href="%s" target="_top">%s<span>%s</span></a>',
    12381252                esc_url( home_url() ),
    1239                 esc_url( get_site_icon_url( 32, includes_url( 'images/w-logo-blue.png' ) ) ),
    1240                 esc_url( get_site_icon_url( 64, includes_url( 'images/w-logo-blue.png' ) ) ),
     1253                $icon_img,
    12411254                esc_html( get_bloginfo( 'name' ) )
    12421255        );
  • trunk/src/wp-includes/general-template.php

    r62454 r62502  
    979979                        $size_data = array( $size, $size );
    980980                }
    981                 $url = wp_get_attachment_image_url( $site_icon_id, $size_data );
     981                $attachment_url = wp_get_attachment_image_url( $site_icon_id, $size_data );
     982                if ( $attachment_url ) {
     983                        $url = $attachment_url;
     984                }
    982985        }
    983986
  • trunk/tests/phpunit/tests/general/template.php

    r60253 r62502  
    124124
    125125        /**
     126         * @ticket 65098
     127         * @group site_icon
     128         * @covers ::get_site_icon_url
     129         * @requires function imagejpeg
     130         */
     131        public function test_get_site_icon_url_returns_fallback_when_attachment_url_fails(): void {
     132                $this->set_site_icon();
     133
     134                $fallback = 'https://example.com/fallback-icon.png';
     135                add_filter( 'wp_get_attachment_image_src', '__return_false' );
     136                $url = get_site_icon_url( 32, $fallback );
     137
     138                $this->assertSame( $fallback, $url, 'Fallback URL should be returned when attachment URL lookup fails.' );
     139        }
     140
     141        /**
    126142         * @group site_icon
    127143         * @covers ::site_icon_url
     
    808824                $this->assertSame( $user_with_no_posts->display_name, $title_when_no_posts );
    809825        }
     826
     827        /**
     828         * @ticket 65098
     829         * @group site_icon
     830         * @covers ::the_embed_site_title
     831         * @requires function imagejpeg
     832         */
     833        public function test_the_embed_site_title_contains_site_icon_when_set(): void {
     834                $this->set_site_icon();
     835
     836                $url_32 = get_site_icon_url( 32 );
     837                $url_64 = get_site_icon_url( 64 );
     838
     839                $output    = get_echo( 'the_embed_site_title' );
     840                $processor = new WP_HTML_Tag_Processor( $output );
     841
     842                $this->assertTrue( $processor->next_tag( 'IMG' ), 'Expected IMG tag.' );
     843                $this->assertTrue( $processor->has_class( 'wp-embed-site-icon' ), 'Expected IMG to have wp-embed-site-icon class.' );
     844                $this->assertSame( $url_32, $processor->get_attribute( 'src' ), 'Output should contain 32px site icon URL in src.' );
     845                $srcset = $processor->get_attribute( 'srcset' );
     846                $this->assertIsString( $srcset, 'Expected srcset to be present.' );
     847                $this->assertStringContainsString( $url_64, $srcset, 'Output should contain 64px site icon URL in srcset.' );
     848        }
     849
     850        /**
     851         * @ticket 65098
     852         * @group site_icon
     853         * @covers ::the_embed_site_title
     854         * @requires function imagejpeg
     855         */
     856        public function test_the_embed_site_title_uses_fallback_when_attachment_url_fails(): void {
     857                $this->set_site_icon();
     858
     859                // Simulate wp_get_attachment_image_url() failing.
     860                add_filter( 'wp_get_attachment_image_src', '__return_false' );
     861                $output = get_echo( 'the_embed_site_title' );
     862
     863                $fallback  = includes_url( 'images/w-logo-blue.png' );
     864                $processor = new WP_HTML_Tag_Processor( $output );
     865
     866                $this->assertTrue( $processor->next_tag( 'IMG' ), 'Expected IMG tag with fallback.' );
     867                $this->assertTrue( $processor->has_class( 'wp-embed-site-icon' ), 'Expected IMG to have wp-embed-site-icon class.' );
     868                $this->assertSame( $fallback, $processor->get_attribute( 'src' ), 'Output should contain fallback URL in src when attachment URL fails.' );
     869        }
     870
     871        /**
     872         * @ticket 65098
     873         * @group site_icon
     874         * @covers ::the_embed_site_title
     875         */
     876        public function test_the_embed_site_title_omits_img_when_url_is_empty(): void {
     877                // Force get_site_icon_url() to return empty string via filter.
     878                add_filter( 'get_site_icon_url', '__return_empty_string' );
     879                $output = get_echo( 'the_embed_site_title' );
     880
     881                $processor = new WP_HTML_Tag_Processor( $output );
     882
     883                $this->assertFalse( $processor->next_tag( 'IMG' ), 'IMG tag should be omitted when URL is empty.' );
     884                $this->assertStringContainsString( get_bloginfo( 'name' ), $output, 'Site name should still be present.' );
     885        }
     886
     887        /**
     888         * @ticket 65098
     889         * @group site_icon
     890         * @covers ::the_embed_site_title
     891         */
     892        public function test_the_embed_site_title_omits_srcset_when_1x_and_2x_urls_are_identical(): void {
     893                // Force both sizes to return the same URL.
     894                $svg_url = 'https://example.com/icon.svg';
     895                $filter  = static function () use ( $svg_url ) {
     896                        return $svg_url;
     897                };
     898
     899                add_filter( 'get_site_icon_url', $filter );
     900                $output = get_echo( 'the_embed_site_title' );
     901
     902                $processor = new WP_HTML_Tag_Processor( $output );
     903
     904                $this->assertTrue( $processor->next_tag( 'IMG' ), 'Expected IMG tag.' );
     905                $this->assertTrue( $processor->has_class( 'wp-embed-site-icon' ), 'Expected IMG to have wp-embed-site-icon class.' );
     906                $this->assertSame( $svg_url, $processor->get_attribute( 'src' ), '1x URL should be present in src.' );
     907                $this->assertNull( $processor->get_attribute( 'srcset' ), 'srcset should be omitted when 1x and 2x URLs are identical.' );
     908        }
     909
     910        /**
     911         * @ticket 65098
     912         * @group site_icon
     913         * @covers ::the_embed_site_title
     914         */
     915        public function test_the_embed_site_title_uses_fallback_without_srcset_when_no_site_icon_set(): void {
     916                $output   = get_echo( 'the_embed_site_title' );
     917                $fallback = includes_url( 'images/w-logo-blue.png' );
     918
     919                $processor = new WP_HTML_Tag_Processor( $output );
     920
     921                $this->assertTrue( $processor->next_tag( 'IMG' ), 'Expected IMG tag with fallback.' );
     922                $this->assertTrue( $processor->has_class( 'wp-embed-site-icon' ), 'Expected IMG to have wp-embed-site-icon class.' );
     923                $this->assertSame( $fallback, $processor->get_attribute( 'src' ), 'Output should contain fallback icon URL in src.' );
     924                $this->assertNull( $processor->get_attribute( 'srcset' ), 'srcset should be omitted when 1x and 2x fallback URLs are identical.' );
     925        }
    810926}
Note: See TracChangeset for help on using the changeset viewer.