From ec8f62769641b681128f865836b96e4e7ed98ce2 Mon Sep 17 00:00:00 2001 From: Pablo Estevez Date: Fri, 13 Mar 2026 20:15:17 -0400 Subject: [PATCH 01/11] Add Threads as an oEmbed provider --- src/wp-includes/class-wp-oembed.php | 4 + .../tests/oembed/wpOembedThreadsProvider.php | 123 ++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 tests/phpunit/tests/oembed/wpOembedThreadsProvider.php diff --git a/src/wp-includes/class-wp-oembed.php b/src/wp-includes/class-wp-oembed.php index 3bc5de556c49e..98706e753c5bc 100644 --- a/src/wp-includes/class-wp-oembed.php +++ b/src/wp-includes/class-wp-oembed.php @@ -110,6 +110,8 @@ public function __construct() { '#https?://((play|www)\.)?anghami\.com/.*#i' => array( 'https://api.anghami.com/rest/v1/oembed.view', true ), '#https?://bsky.app/profile/.*/post/.*#i' => array( 'https://embed.bsky.app/oembed', true ), '#https?://(www\.)?canva\.com/design/.*/view.*#i' => array( 'https://canva.com/_oembed', true ), + '#https?://(www\.)?threads\.(com|net)/@[^/]+/post/.+#i' => array( 'https://graph.threads.com/oembed', true ), + '#https?://(www\.)?threads\.(com|net)/t/.+#i' => array( 'https://graph.threads.com/oembed', true ), ); if ( ! empty( self::$early_providers['add'] ) ) { @@ -191,6 +193,8 @@ public function __construct() { * | Anghami | anghami.com | 6.3.0 | * | Bluesky | bsky.app | 6.6.0 | * | Canva | canva.com | 6.8.0 | + * | Threads | threads.com | 6.9.0 | + * | Threads | threads.net | 6.9.0 | * * No longer supported providers: * diff --git a/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php b/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php new file mode 100644 index 0000000000000..887c981f7d917 --- /dev/null +++ b/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php @@ -0,0 +1,123 @@ +oembed = _wp_oembed_get_object(); + } + + /** + * @dataProvider data_threads_provider_urls + * + * @param string $url The URL to test. + * @param string $expected The expected oEmbed provider URL. + */ + public function test_threads_provider_url( $url, $expected ) { + $provider = $this->oembed->get_provider( $url, array( 'discover' => false ) ); + $this->assertSame( $expected, $provider ); + } + + /** + * Data provider for valid Threads URLs. + * + * @return array[] + */ + public function data_threads_provider_urls() { + return array( + // threads.com post URLs. + 'threads.com post URL' => array( + 'https://www.threads.com/@zuck/post/C1234567890', + 'https://graph.threads.com/oembed', + ), + 'threads.com post URL no www' => array( + 'https://threads.com/@zuck/post/C1234567890', + 'https://graph.threads.com/oembed', + ), + 'threads.com post URL http' => array( + 'http://www.threads.com/@zuck/post/C1234567890', + 'https://graph.threads.com/oembed', + ), + + // threads.com short URLs. + 'threads.com short URL' => array( + 'https://www.threads.com/t/C1234567890', + 'https://graph.threads.com/oembed', + ), + 'threads.com short URL no www' => array( + 'https://threads.com/t/C1234567890', + 'https://graph.threads.com/oembed', + ), + 'threads.com short URL http' => array( + 'http://www.threads.com/t/C1234567890', + 'https://graph.threads.com/oembed', + ), + + // threads.net post URLs. + 'threads.net post URL' => array( + 'https://www.threads.net/@zuck/post/C1234567890', + 'https://graph.threads.com/oembed', + ), + 'threads.net post URL no www' => array( + 'https://threads.net/@zuck/post/C1234567890', + 'https://graph.threads.com/oembed', + ), + + // threads.net short URLs. + 'threads.net short URL' => array( + 'https://www.threads.net/t/C1234567890', + 'https://graph.threads.com/oembed', + ), + 'threads.net short URL no www' => array( + 'https://threads.net/t/C1234567890', + 'https://graph.threads.com/oembed', + ), + ); + } + + /** + * @dataProvider data_threads_non_matching_urls + * + * @param string $url The URL to test. + */ + public function test_threads_provider_does_not_match_non_post_urls( $url ) { + $provider = $this->oembed->get_provider( $url, array( 'discover' => false ) ); + $this->assertFalse( $provider ); + } + + /** + * Data provider for URLs that should not match the Threads provider. + * + * @return array[] + */ + public function data_threads_non_matching_urls() { + return array( + 'threads.com profile URL' => array( + 'https://www.threads.com/@zuck', + ), + 'threads.com homepage' => array( + 'https://www.threads.com/', + ), + 'threads.com search' => array( + 'https://www.threads.com/search', + ), + 'non-threads URL with threads in path' => array( + 'https://example.com/threads/post/123', + ), + ); + } +} From 85551676d4e5223ab0040c58a917ac6c6b513478 Mon Sep 17 00:00:00 2001 From: Pablo Estevez Date: Fri, 13 Mar 2026 20:31:08 -0400 Subject: [PATCH 02/11] Fix array alignment per WordPress coding standards --- src/wp-includes/class-wp-oembed.php | 2 +- .../tests/oembed/wpOembedThreadsProvider.php | 26 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/wp-includes/class-wp-oembed.php b/src/wp-includes/class-wp-oembed.php index 98706e753c5bc..69e7fde56bd71 100644 --- a/src/wp-includes/class-wp-oembed.php +++ b/src/wp-includes/class-wp-oembed.php @@ -111,7 +111,7 @@ public function __construct() { '#https?://bsky.app/profile/.*/post/.*#i' => array( 'https://embed.bsky.app/oembed', true ), '#https?://(www\.)?canva\.com/design/.*/view.*#i' => array( 'https://canva.com/_oembed', true ), '#https?://(www\.)?threads\.(com|net)/@[^/]+/post/.+#i' => array( 'https://graph.threads.com/oembed', true ), - '#https?://(www\.)?threads\.(com|net)/t/.+#i' => array( 'https://graph.threads.com/oembed', true ), + '#https?://(www\.)?threads\.(com|net)/t/.+#i' => array( 'https://graph.threads.com/oembed', true ), ); if ( ! empty( self::$early_providers['add'] ) ) { diff --git a/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php b/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php index 887c981f7d917..44b209599728f 100644 --- a/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php +++ b/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php @@ -40,49 +40,49 @@ public function test_threads_provider_url( $url, $expected ) { public function data_threads_provider_urls() { return array( // threads.com post URLs. - 'threads.com post URL' => array( + 'threads.com post URL' => array( 'https://www.threads.com/@zuck/post/C1234567890', 'https://graph.threads.com/oembed', ), - 'threads.com post URL no www' => array( + 'threads.com post URL no www' => array( 'https://threads.com/@zuck/post/C1234567890', 'https://graph.threads.com/oembed', ), - 'threads.com post URL http' => array( + 'threads.com post URL http' => array( 'http://www.threads.com/@zuck/post/C1234567890', 'https://graph.threads.com/oembed', ), // threads.com short URLs. - 'threads.com short URL' => array( + 'threads.com short URL' => array( 'https://www.threads.com/t/C1234567890', 'https://graph.threads.com/oembed', ), - 'threads.com short URL no www' => array( + 'threads.com short URL no www' => array( 'https://threads.com/t/C1234567890', 'https://graph.threads.com/oembed', ), - 'threads.com short URL http' => array( + 'threads.com short URL http' => array( 'http://www.threads.com/t/C1234567890', 'https://graph.threads.com/oembed', ), // threads.net post URLs. - 'threads.net post URL' => array( + 'threads.net post URL' => array( 'https://www.threads.net/@zuck/post/C1234567890', 'https://graph.threads.com/oembed', ), - 'threads.net post URL no www' => array( + 'threads.net post URL no www' => array( 'https://threads.net/@zuck/post/C1234567890', 'https://graph.threads.com/oembed', ), // threads.net short URLs. - 'threads.net short URL' => array( + 'threads.net short URL' => array( 'https://www.threads.net/t/C1234567890', 'https://graph.threads.com/oembed', ), - 'threads.net short URL no www' => array( + 'threads.net short URL no www' => array( 'https://threads.net/t/C1234567890', 'https://graph.threads.com/oembed', ), @@ -106,13 +106,13 @@ public function test_threads_provider_does_not_match_non_post_urls( $url ) { */ public function data_threads_non_matching_urls() { return array( - 'threads.com profile URL' => array( + 'threads.com profile URL' => array( 'https://www.threads.com/@zuck', ), - 'threads.com homepage' => array( + 'threads.com homepage' => array( 'https://www.threads.com/', ), - 'threads.com search' => array( + 'threads.com search' => array( 'https://www.threads.com/search', ), 'non-threads URL with threads in path' => array( From fb03e0e1eff177d91c6f39a76e9c33c0ca4a54fc Mon Sep 17 00:00:00 2001 From: Pablo Estevez Date: Sat, 14 Mar 2026 14:49:07 -0400 Subject: [PATCH 03/11] Update src/wp-includes/class-wp-oembed.php Co-authored-by: Weston Ruter --- src/wp-includes/class-wp-oembed.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/class-wp-oembed.php b/src/wp-includes/class-wp-oembed.php index 69e7fde56bd71..23ebce4f2f5bc 100644 --- a/src/wp-includes/class-wp-oembed.php +++ b/src/wp-includes/class-wp-oembed.php @@ -193,8 +193,8 @@ public function __construct() { * | Anghami | anghami.com | 6.3.0 | * | Bluesky | bsky.app | 6.6.0 | * | Canva | canva.com | 6.8.0 | - * | Threads | threads.com | 6.9.0 | - * | Threads | threads.net | 6.9.0 | + * | Threads | threads.com | 7.0.0 | + * | Threads | threads.net | 7.0.0 | * * No longer supported providers: * From d8d4009d66acaa689a4cd9c2123ae87537c3c505 Mon Sep 17 00:00:00 2001 From: Pablo Estevez Date: Sat, 14 Mar 2026 14:49:21 -0400 Subject: [PATCH 04/11] Update tests/phpunit/tests/oembed/wpOembedThreadsProvider.php Co-authored-by: Weston Ruter --- tests/phpunit/tests/oembed/wpOembedThreadsProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php b/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php index 44b209599728f..21da9b4a87de7 100644 --- a/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php +++ b/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php @@ -14,7 +14,7 @@ class Tests_oEmbed_wpOembedThreadsProvider extends WP_UnitTestCase { */ protected $oembed; - public function set_up() { + public function set_up(): void { parent::set_up(); require_once ABSPATH . WPINC . '/class-wp-oembed.php'; From 18172d2970f4e4bd6931c4929141f1e38937537f Mon Sep 17 00:00:00 2001 From: Pablo Estevez Date: Sat, 14 Mar 2026 14:49:34 -0400 Subject: [PATCH 05/11] Update tests/phpunit/tests/oembed/wpOembedThreadsProvider.php Co-authored-by: Weston Ruter --- tests/phpunit/tests/oembed/wpOembedThreadsProvider.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php b/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php index 21da9b4a87de7..5cb827b04dd24 100644 --- a/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php +++ b/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php @@ -9,10 +9,7 @@ */ class Tests_oEmbed_wpOembedThreadsProvider extends WP_UnitTestCase { - /** - * @var WP_oEmbed - */ - protected $oembed; + protected WP_oEmbed $oembed; public function set_up(): void { parent::set_up(); From 09ff93f5456d442e4a349391a3071b8e4bedf882 Mon Sep 17 00:00:00 2001 From: Pablo Estevez Date: Sat, 14 Mar 2026 14:49:46 -0400 Subject: [PATCH 06/11] Update tests/phpunit/tests/oembed/wpOembedThreadsProvider.php Co-authored-by: Weston Ruter --- tests/phpunit/tests/oembed/wpOembedThreadsProvider.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php b/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php index 5cb827b04dd24..a1facccbafa25 100644 --- a/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php +++ b/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php @@ -99,9 +99,9 @@ public function test_threads_provider_does_not_match_non_post_urls( $url ) { /** * Data provider for URLs that should not match the Threads provider. * - * @return array[] + * @return array */ - public function data_threads_non_matching_urls() { + public function data_threads_non_matching_urls(): array { return array( 'threads.com profile URL' => array( 'https://www.threads.com/@zuck', From 660939aa9ae9c40c7f035a7bf791bf53e49bbbec Mon Sep 17 00:00:00 2001 From: Pablo Estevez Date: Sat, 14 Mar 2026 14:51:24 -0400 Subject: [PATCH 07/11] Update tests/phpunit/tests/oembed/wpOembedThreadsProvider.php Co-authored-by: Weston Ruter --- tests/phpunit/tests/oembed/wpOembedThreadsProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php b/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php index a1facccbafa25..b0605282845a6 100644 --- a/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php +++ b/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php @@ -91,7 +91,7 @@ public function data_threads_provider_urls() { * * @param string $url The URL to test. */ - public function test_threads_provider_does_not_match_non_post_urls( $url ) { + public function test_threads_provider_does_not_match_non_post_urls( string $url ): void { $provider = $this->oembed->get_provider( $url, array( 'discover' => false ) ); $this->assertFalse( $provider ); } From 301ead7979fb88b505bb875d72f5a6d6c9addbde Mon Sep 17 00:00:00 2001 From: Pablo Estevez Date: Sat, 14 Mar 2026 14:51:32 -0400 Subject: [PATCH 08/11] Update tests/phpunit/tests/oembed/wpOembedThreadsProvider.php Co-authored-by: Weston Ruter --- tests/phpunit/tests/oembed/wpOembedThreadsProvider.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php b/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php index b0605282845a6..c56848d0aa617 100644 --- a/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php +++ b/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php @@ -32,9 +32,9 @@ public function test_threads_provider_url( $url, $expected ) { /** * Data provider for valid Threads URLs. * - * @return array[] + * @return array */ - public function data_threads_provider_urls() { + public function data_threads_provider_urls(): array { return array( // threads.com post URLs. 'threads.com post URL' => array( From 279493204301320067554fdbf97c88a98c5e4a03 Mon Sep 17 00:00:00 2001 From: Pablo Estevez Date: Sat, 14 Mar 2026 14:51:42 -0400 Subject: [PATCH 09/11] Update tests/phpunit/tests/oembed/wpOembedThreadsProvider.php Co-authored-by: Weston Ruter --- tests/phpunit/tests/oembed/wpOembedThreadsProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php b/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php index c56848d0aa617..f3485ceee58d7 100644 --- a/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php +++ b/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php @@ -24,7 +24,7 @@ public function set_up(): void { * @param string $url The URL to test. * @param string $expected The expected oEmbed provider URL. */ - public function test_threads_provider_url( $url, $expected ) { + public function test_threads_provider_url( string $url, string $expected ): void { $provider = $this->oembed->get_provider( $url, array( 'discover' => false ) ); $this->assertSame( $expected, $provider ); } From c1a5fb4995b8aae2518321e5700c362b76ea639a Mon Sep 17 00:00:00 2001 From: Pablo Estevez Date: Mon, 16 Mar 2026 12:29:05 -0400 Subject: [PATCH 10/11] Update tests/phpunit/tests/oembed/wpOembedThreadsProvider.php Co-authored-by: Mukesh Panchal --- tests/phpunit/tests/oembed/wpOembedThreadsProvider.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php b/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php index f3485ceee58d7..49fb251347c5e 100644 --- a/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php +++ b/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php @@ -19,6 +19,8 @@ public function set_up(): void { } /** + * @ticket 64858 + * * @dataProvider data_threads_provider_urls * * @param string $url The URL to test. From aea427fa3383c7c19da4541f5406436c5403a2dd Mon Sep 17 00:00:00 2001 From: Pablo Estevez Date: Wed, 18 Mar 2026 20:17:10 -0400 Subject: [PATCH 11/11] Add @ticket annotation to second test method and update target version to 7.1.0 --- src/wp-includes/class-wp-oembed.php | 4 ++-- .../tests/oembed/wpOembedThreadsProvider.php | 23 ++++++++++--------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/wp-includes/class-wp-oembed.php b/src/wp-includes/class-wp-oembed.php index 69e7fde56bd71..b66c5e03afaf1 100644 --- a/src/wp-includes/class-wp-oembed.php +++ b/src/wp-includes/class-wp-oembed.php @@ -193,8 +193,8 @@ public function __construct() { * | Anghami | anghami.com | 6.3.0 | * | Bluesky | bsky.app | 6.6.0 | * | Canva | canva.com | 6.8.0 | - * | Threads | threads.com | 6.9.0 | - * | Threads | threads.net | 6.9.0 | + * | Threads | threads.com | 7.1.0 | + * | Threads | threads.net | 7.1.0 | * * No longer supported providers: * diff --git a/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php b/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php index 44b209599728f..c313f3b68d3bf 100644 --- a/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php +++ b/tests/phpunit/tests/oembed/wpOembedThreadsProvider.php @@ -9,12 +9,9 @@ */ class Tests_oEmbed_wpOembedThreadsProvider extends WP_UnitTestCase { - /** - * @var WP_oEmbed - */ - protected $oembed; + protected WP_oEmbed $oembed; - public function set_up() { + public function set_up(): void { parent::set_up(); require_once ABSPATH . WPINC . '/class-wp-oembed.php'; @@ -22,12 +19,14 @@ public function set_up() { } /** + * @ticket 64858 + * * @dataProvider data_threads_provider_urls * * @param string $url The URL to test. * @param string $expected The expected oEmbed provider URL. */ - public function test_threads_provider_url( $url, $expected ) { + public function test_threads_provider_url( string $url, string $expected ): void { $provider = $this->oembed->get_provider( $url, array( 'discover' => false ) ); $this->assertSame( $expected, $provider ); } @@ -35,9 +34,9 @@ public function test_threads_provider_url( $url, $expected ) { /** * Data provider for valid Threads URLs. * - * @return array[] + * @return array */ - public function data_threads_provider_urls() { + public function data_threads_provider_urls(): array { return array( // threads.com post URLs. 'threads.com post URL' => array( @@ -90,11 +89,13 @@ public function data_threads_provider_urls() { } /** + * @ticket 64858 + * * @dataProvider data_threads_non_matching_urls * * @param string $url The URL to test. */ - public function test_threads_provider_does_not_match_non_post_urls( $url ) { + public function test_threads_provider_does_not_match_non_post_urls( string $url ): void { $provider = $this->oembed->get_provider( $url, array( 'discover' => false ) ); $this->assertFalse( $provider ); } @@ -102,9 +103,9 @@ public function test_threads_provider_does_not_match_non_post_urls( $url ) { /** * Data provider for URLs that should not match the Threads provider. * - * @return array[] + * @return array */ - public function data_threads_non_matching_urls() { + public function data_threads_non_matching_urls(): array { return array( 'threads.com profile URL' => array( 'https://www.threads.com/@zuck',