From 908801ec7e08497d6fd45f06f2f3f90aa7d03688 Mon Sep 17 00:00:00 2001 From: Renato Alves <19148962+renatonascalves@users.noreply.github.com> Date: Tue, 10 Sep 2024 12:51:31 -0300 Subject: [PATCH 1/3] WIP: issue-1157 From 1af588276369028daa81191ba4cd224b75b49ffb Mon Sep 17 00:00:00 2001 From: Renato Alves <19148962+renatonascalves@users.noreply.github.com> Date: Tue, 10 Sep 2024 23:38:36 -0300 Subject: [PATCH 2/3] Adjust base URL to reflect the value set in the `home` option field --- admin/apple-actions/index/class-export.php | 2 +- .../apple-exporter/class-exporter-content.php | 3 +- includes/apple-exporter/class-parser.php | 6 +- .../components/test-class-cover.php | 12 +- .../test-class-exporter-content.php | 40 +++++- tests/apple-exporter/test-class-parser.php | 124 ++++++++++++++++-- 6 files changed, 160 insertions(+), 27 deletions(-) diff --git a/admin/apple-actions/index/class-export.php b/admin/apple-actions/index/class-export.php index 7c602de4..b12a9175 100644 --- a/admin/apple-actions/index/class-export.php +++ b/admin/apple-actions/index/class-export.php @@ -141,7 +141,7 @@ public function fetch_exporter() { if ( ! empty( $post_thumb_url ) ) { // If the post thumb URL is root-relative, convert it to fully-qualified. if ( str_starts_with( $post_thumb_url, '/' ) ) { - $post_thumb_url = site_url( $post_thumb_url ); + $post_thumb_url = home_url( $post_thumb_url ); } // Compile the post_thumb object using the URL and caption from the featured image. diff --git a/includes/apple-exporter/class-exporter-content.php b/includes/apple-exporter/class-exporter-content.php index 988ce69a..6d2bde9c 100644 --- a/includes/apple-exporter/class-exporter-content.php +++ b/includes/apple-exporter/class-exporter-content.php @@ -103,14 +103,13 @@ class Exporter_Content { * * @param string $url The URL to format. * - * @access protected * @return string The formatted URL on success, or a blank string on failure. */ public static function format_src_url( $url ) { // If this is a root-relative path, make absolute. if ( 0 === strpos( $url, '/' ) ) { - $url = site_url( $url ); + $url = home_url( $url ); } // Decode the HTML entities since the URL is from the src attribute. diff --git a/includes/apple-exporter/class-parser.php b/includes/apple-exporter/class-parser.php index 9ed4c9a6..df29e44f 100644 --- a/includes/apple-exporter/class-parser.php +++ b/includes/apple-exporter/class-parser.php @@ -68,9 +68,9 @@ public function parse( $html ): string { // Fork for format. if ( 'html' === $this->format ) { return $this->parse_html( $html ); - } else { - return $this->parse_markdown( $html ); } + + return $this->parse_markdown( $html ); } /** @@ -204,7 +204,7 @@ private function remove_empty_a_tags( string $html ): string { private function handle_root_relative_urls( string $html ): string { return preg_replace_callback( '/(]+href=(["\'])\/[^\/].*?\2[^>]*>)/m', - fn( $matches ) => str_replace( 'href="/', 'href="' . get_site_url() . '/', $matches[0] ), + fn( $matches ) => str_replace( 'href="/', 'href="' . get_home_url() . '/', $matches[0] ), $html ); } diff --git a/tests/apple-exporter/components/test-class-cover.php b/tests/apple-exporter/components/test-class-cover.php index 6828589b..4972b370 100644 --- a/tests/apple-exporter/components/test-class-cover.php +++ b/tests/apple-exporter/components/test-class-cover.php @@ -35,7 +35,7 @@ public function filter_apple_news_cover_json( $json ) { * @return string The filtered URL, made root-relative. */ public function filter_wp_get_attachment_url( $url ) { - return str_replace( site_url(), '', $url ); + return str_replace( home_url(), '', $url ); } /** @@ -64,10 +64,10 @@ public function test_cover_role() { // Create test post. $post_id = self::factory()->post->create(); - // Create a new attachment and assign it as the featured image for the cover component. - set_post_thumbnail( - $post_id, - $this->get_new_attachment( 0 ) + // Create a new attachment and assign it as the featured image for the cover component. + set_post_thumbnail( + $post_id, + $this->get_new_attachment( 0 ) ); // Check that the cover component's default role is 'photo'. @@ -120,7 +120,7 @@ public function test_relative_url() { // Create a post with an image with a root-relative src property and ensure its URL is expanded fully when converted to a Cover component. $image_id_1 = $this->get_new_attachment( 0, 'Test Caption', 'Test alt text.' ); - $post_id_1 = self::factory()->post->create( [ 'post_content' => str_replace( site_url(), '', $this->get_image_with_caption( $image_id_1 ) ) ] ); + $post_id_1 = self::factory()->post->create( [ 'post_content' => str_replace( home_url(), '', $this->get_image_with_caption( $image_id_1 ) ) ] ); $json_1 = $this->get_json_for_post( $post_id_1 ); $this->assertEquals( wp_get_attachment_image_url( $image_id_1, 'full' ), $json_1['components'][0]['components'][0]['URL'] ); diff --git a/tests/apple-exporter/test-class-exporter-content.php b/tests/apple-exporter/test-class-exporter-content.php index 32d8ecd7..2aadd0ea 100644 --- a/tests/apple-exporter/test-class-exporter-content.php +++ b/tests/apple-exporter/test-class-exporter-content.php @@ -67,10 +67,48 @@ public function test_complete_content_with_cover_config() { /** * Ensure we decode the HTML entities in URLs extracted from HTML attributes.[type] */ - public function test_format_src_url() { + public function test_format_src_url(): void { $this->assertEquals( 'https://www.example.org/some.mp3?one=two&query=arg', Exporter_Content::format_src_url( 'https://www.example.org/some.mp3?one=two&query=arg' ) ); + + // Change the home URL. + update_option( 'home', 'https://www.custom-example.org' ); + + $this->assertEquals( + 'https://www.example.org/some.mp3?one=two&query=arg', + Exporter_Content::format_src_url( 'https://www.example.org/some.mp3?one=two&query=arg' ) + ); + + $this->assertEquals( + 'https://www.custom-example.org/', + Exporter_Content::format_src_url( '/' ) + ); + + $this->assertEquals( + 'https://www.custom-example.org', + Exporter_Content::format_src_url( 'https://www.custom-example.org' ) + ); + + $this->assertNotEquals( + 'https://www.custom-example.org', + Exporter_Content::format_src_url( '/' ), + 'Root URL is missing a trailing slash.' + ); + + $this->assertEquals( + 'https://www.example.org', + Exporter_Content::format_src_url( 'https://www.example.org' ) + ); + + $this->assertNotEquals( + 'https://www.example.org/', // The / here is intentional. + Exporter_Content::format_src_url( 'https://www.example.org' ), + 'Root URL has a trailing slash.' + ); + + // Reset the home URL. + update_option( 'home', 'https://www.example.org' ); } } diff --git a/tests/apple-exporter/test-class-parser.php b/tests/apple-exporter/test-class-parser.php index 3ff5db44..97147ad8 100644 --- a/tests/apple-exporter/test-class-parser.php +++ b/tests/apple-exporter/test-class-parser.php @@ -23,11 +23,11 @@ class Apple_News_Parser_Test extends Apple_News_Testcase { */ public function test_parse_markdown(): void { // Create a basic HTML post. - $post = '

A heading

This is strong.
This is a link

'; + $html = '

A heading

This is strong.
This is a link

'; // Convert to Markdown. $parser = new Parser( 'markdown' ); - $markdown = $parser->parse( $post ); + $markdown = $parser->parse( $html ); // Verify. $this->assertEquals( $markdown, "## A heading\n**This is strong.**\n[This is a link](https://www.apple.com)\n\n" ); @@ -38,10 +38,10 @@ public function test_parse_markdown(): void { */ public function test_parse_html(): void { // Create a basic HTML post. - $post = '

A heading

This is strong.
This is a link

The div tags will disappear.
'; + $html_post = '

A heading

This is strong.
This is a link

The div tags will disappear.
'; // Parse only HTML that's valid for Apple News. - $html = ( new Parser( 'html' ) )->parse( $post ); + $html = ( new Parser( 'html' ) )->parse( $html_post ); // Verify. $this->assertEquals( $html, 'A heading

This is strong.
This is a link

The div tags will disappear.' ); @@ -53,8 +53,6 @@ public function test_parse_html(): void { * @see \Apple_Exporter\Parser::parse */ public function test_clean_html_markdown(): void { - // Create a post. - global $post; $post_content = <<Absolute link @@ -70,18 +68,17 @@ public function test_clean_html_markdown(): void { Not a real URL HTML; - $post = $this->factory->post->create_and_get( // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited + $article = $this->factory->post->create_and_get( [ 'post_type' => 'article', 'post_title' => 'Test Article', 'post_content' => $post_content, ] ); - $permalink = get_permalink( $post ); // Convert to Markdown. $parser = new Parser( 'markdown' ); - $markdown = $parser->parse( apply_filters( 'the_content', $post->post_content ) ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound + $markdown = $parser->parse( apply_filters( 'the_content', $article->post_content ) ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound // Verify. $this->assertEquals( @@ -96,14 +93,63 @@ public function test_clean_html_markdown(): void { ); } + /** + * Test the anchor cleaning functions of the parser for Markdown. + * + * @see \Apple_Exporter\Parser::parse + */ + public function test_clean_html_markdown_with_diffent_home_url(): void { + update_option( 'home', 'https://www.custom-example.org' ); + + $post_content = <<Absolute link + +Root-relative link + +Test Anchor + +Anchor Link + +Legit empty link + +Link that trims to empty + +Not a real URL +HTML; + $article = $this->factory->post->create_and_get( + [ + 'post_type' => 'article', + 'post_title' => 'Test Article', + 'post_content' => $post_content, + ] + ); + + // Convert to Markdown. + $parser = new Parser( 'markdown' ); + $markdown = $parser->parse( apply_filters( 'the_content', $article->post_content ) ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound + + // Verify. + $this->assertEquals( + '[Absolute link](https://www.google.com)' + . '[Root-relative link](https://www.custom-example.org/2018/05/03/an-92-test)' + . 'Test Anchor' + . '[Anchor Link](#testanchor)' + . 'Legit empty link' + . 'Link that trims to empty' + . 'Not a real URL', + str_replace( "\n", '', $markdown ) + ); + + // Reset the home URL. + update_option( 'home', 'https://www.example.org' ); + } + /** * Test the anchor cleaning functions of the parser for HTML. * * @see \Apple_Exporter\Parser::parse */ public function test_clean_html(): void { - // Create a post. - global $post; $post_content = <<Absolute link @@ -119,18 +165,17 @@ public function test_clean_html(): void { Not a real URL HTML; - $post = $this->factory->post->create_and_get( // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited + $article = $this->factory->post->create_and_get( [ 'post_type' => 'article', 'post_title' => 'Test Article', 'post_content' => $post_content, ] ); - $permalink = get_permalink( $post ); // Parse the post with HTML content format. $parser = new Parser( 'html' ); - $parsed_html = $parser->parse( apply_filters( 'the_content', $post->post_content ) ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound + $parsed_html = $parser->parse( apply_filters( 'the_content', $article->post_content ) ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound // Verify. $this->assertEquals( @@ -144,4 +189,55 @@ public function test_clean_html(): void { str_replace( "\n", '', $parsed_html ) ); } + + /** + * Test the clean HTML function with a different root URL. + * + * @see \Apple_Exporter\Parser::parse + */ + public function test_clean_html_with_diffent_home_url(): void { + update_option( 'home', 'https://www.custom-example.org' ); + + $post_content = <<Absolute link + +Root-relative link + +Test Anchor + +Anchor Link + +Legit empty link + +Link that trims to empty + +Not a real URL +HTML; + $article = $this->factory->post->create_and_get( + [ + 'post_type' => 'article', + 'post_title' => 'Test Article', + 'post_content' => $post_content, + ] + ); + + // Parse the post with HTML content format. + $parser = new Parser( 'html' ); + $parsed_html = $parser->parse( apply_filters( 'the_content', $article->post_content ) ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound + + // Verify. + $this->assertEquals( + '

Absolute link

' + . '

Root-relative link

' + . '

Test Anchor

' + . '

Anchor Link

' + . '

Legit empty link

' + . '

Link that trims to empty

' + . '

Not a real URL

', + str_replace( "\n", '', $parsed_html ) + ); + + // Reset the home URL. + update_option( 'home', 'https://www.example.org' ); + } } From 47550f8c2066610300e9526c0ebbea335396611c Mon Sep 17 00:00:00 2001 From: Renato Alves <19148962+renatonascalves@users.noreply.github.com> Date: Tue, 10 Sep 2024 23:38:59 -0300 Subject: [PATCH 3/3] Ready for review