diff --git a/src/wp-includes/widgets.php b/src/wp-includes/widgets.php
index 31fce41b65954..64a86d82713ad 100644
--- a/src/wp-includes/widgets.php
+++ b/src/wp-includes/widgets.php
@@ -1822,8 +1822,8 @@ function wp_widget_rss_process( $widget_rss, $check_feed = true ) {
if ( is_wp_error( $rss ) ) {
$error = $rss->get_error_message();
} else {
- $link = esc_url( strip_tags( $rss->get_permalink() ) );
- while ( stristr( $link, 'http' ) !== $link ) {
+ $link = esc_url( strip_tags( (string) $rss->get_permalink() ) );
+ while ( ! empty( $link ) && stristr( $link, 'http' ) !== $link ) {
$link = substr( $link, 1 );
}
diff --git a/tests/phpunit/tests/widgets/wpWidgetRss.php b/tests/phpunit/tests/widgets/wpWidgetRss.php
index f93f7810fde5b..47aed729f6210 100644
--- a/tests/phpunit/tests/widgets/wpWidgetRss.php
+++ b/tests/phpunit/tests/widgets/wpWidgetRss.php
@@ -95,6 +95,67 @@ public static function data_url_happy_path() {
);
}
+ /**
+ * Ensures that processing a feed returns when its channel link is not an HTTP URL.
+ *
+ * @ticket 62341
+ * @covers ::wp_widget_rss_process
+ * @dataProvider data_wp_widget_rss_process_channel_link
+ *
+ * @param string $channel_link Markup of the channel link in the feed.
+ * @param string $expected Expected link.
+ */
+ public function test_wp_widget_rss_process_channel_link( $channel_link, $expected ) {
+ add_filter(
+ 'pre_http_request',
+ static function () use ( $channel_link ) {
+ return array(
+ 'headers' => new WpOrg\Requests\Utility\CaseInsensitiveDictionary(
+ array( 'Content-Type' => 'application/rss+xml; charset=UTF-8' )
+ ),
+ 'body' => 'Feed' . $channel_link . '',
+ 'response' => array(
+ 'code' => 200,
+ 'message' => 'OK',
+ ),
+ 'cookies' => array(),
+ 'filename' => null,
+ );
+ }
+ );
+
+ $result = wp_widget_rss_process(
+ array(
+ 'url' => 'https://example.org/feed/',
+ 'items' => 5,
+ )
+ );
+
+ $this->assertSame( $expected, $result['link'] );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array[]
+ */
+ public static function data_wp_widget_rss_process_channel_link() {
+ return array(
+ 'HTTPS URL' => array(
+ 'channel_link' => 'https://example.com/',
+ 'expected' => 'https://example.com/',
+ ),
+ 'FTP URL' => array(
+ 'channel_link' => 'ftp://example.com/',
+ 'expected' => '',
+ ),
+ 'no link element' => array(
+ 'channel_link' => '',
+ 'expected' => '',
+ ),
+ );
+ }
+
public function mocked_rss_response() {
$single_value_headers = array(
'Content-Type' => 'application/rss+xml; charset=UTF-8',