Skip to content

Commit

Permalink
Merge pull request #25 from alleyinteractive/hotfix/24-embed
Browse files Browse the repository at this point in the history
Allow <embed> elements to be converted properly, fix blockquote format
  • Loading branch information
srtfisher authored Jul 25, 2024
2 parents 2145f4b + cbf40ec commit dbea4ac
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 136 deletions.
42 changes: 42 additions & 0 deletions .github/workflows/all-pr-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: "All Pull Request Tests"

on:
pull_request:
branches:
- develop
types: [opened, synchronize, reopened, ready_for_review]

jobs:
# We use a single job to ensure that all steps run in the same environment and
# reduce the number of minutes used.
pr-tests:
# Don't run on draft PRs
if: github.event.pull_request.draft == false
# Timeout after 10 minutes
timeout-minutes: 10
# Define a matrix of PHP/WordPress versions to test against
strategy:
matrix:
php: [8.1, 8.2, 8.3]
wordpress: ["latest"]
runs-on: ubuntu-latest
# Cancel any existing runs of this workflow
concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }}-P${{ matrix.php }}-WP${{ matrix.wordpress }}
cancel-in-progress: true
# Name the job in the matrix
name: "PR Tests PHP ${{ matrix.php }} WordPress ${{ matrix.wordpress }}"
steps:
- uses: actions/checkout@v4

- name: Run General Tests
# See https://github.com/alleyinteractive/action-test-general for more options
uses: alleyinteractive/action-test-general@develop

- name: Run PHP Tests
# See https://github.com/alleyinteractive/action-test-php for more options
uses: alleyinteractive/action-test-php@develop
with:
php-version: '${{ matrix.php }}'
wordpress-version: '${{ matrix.wordpress }}'
skip-wordpress-install: 'true'
14 changes: 0 additions & 14 deletions .github/workflows/coding-standards.yml

This file was deleted.

21 changes: 0 additions & 21 deletions .github/workflows/unit-test.yml

This file was deleted.

5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

All notable changes to `WP Block Converter` will be documented in this file.

## 1.4.0

- Drops support for PHP 8.0.
- Fixes issue with `<embed>` elements.

## 1.3.2

- Preserve new lines in embed blocks. They are required for proper front end rendering.
Expand Down
6 changes: 3 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
}
],
"require": {
"php": "^8.0|^8.1|^8.2",
"php": "^8.1|^8.2",
"alleyinteractive/composer-wordpress-autoloader": "^1.0",
"mantle-framework/support": "^0.12"
"mantle-framework/support": "^1.0"
},
"require-dev": {
"alleyinteractive/alley-coding-standards": "^2.0",
"mantle-framework/testkit": "^0.12"
"mantle-framework/testkit": "^1.0"
},
"config": {
"allow-plugins": {
Expand Down
28 changes: 16 additions & 12 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
<?xml version="1.0"?>
<phpunit
bootstrap="tests/bootstrap.php"
backupGlobals="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
printerClass="NunoMaduro\Collision\Adapters\Phpunit\Printer"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd"
bootstrap="tests/bootstrap.php"
backupGlobals="false"
colors="true"
cacheDirectory=".phpunit.result.cache"
>
<testsuites>
<testsuite name="Feature">
<directory prefix="test-" suffix=".php">tests/feature</directory>
</testsuite>
</testsuites>
<testsuites>
<testsuite name="feature">
<directory suffix=".php">tests/feature</directory>
</testsuite>
</testsuites>
<php>
<env name="MANTLE_USE_SQLITE" value="true" />
<env name="WP_SKIP_DB_CREATE" value="true" />
</php>
</phpunit>
43 changes: 40 additions & 3 deletions src/class-block-converter.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,34 @@ public function __call( $name, $arguments ): ?Block {
};
}

/**
* Convert the children of a node to blocks.
*
* @param DOMNode $node The node.
* @return string The children as blocks.
*/
public function convert_with_children( DOMNode $node ): string {
$children = '';

// Recursively convert the children of the node.
foreach ( $node->childNodes as $child ) {
$child_block = $this->{$child->nodeName}( $child );

if ( ! empty( $child_block ) ) {
$children .= $this->minify_block( (string) $child_block );
}
}

$node->nodeValue = '__CHILDREN__';

$content = static::get_node_html( $node );

// Replace the placeholder with the children.
$content = str_replace( '__CHILDREN__', $children, $content );

return $content;
}

/**
* Magic function to convert to a string.
*/
Expand Down Expand Up @@ -148,7 +176,12 @@ protected function h( DOMNode $node ): ?Block {
* @return Block|null
*/
protected function blockquote( DOMNode $node ): ?Block {
$content = static::get_node_html( $node );
// Set the class on the node equal to wp-block-quote.
if ( $node instanceof DOMElement && empty( $node->getAttribute( 'class' ) ) ) {
$node->setAttribute( 'class', 'wp-block-quote' );
}

$content = $this->convert_with_children( $node );

if ( empty( $content ) ) {
return null;
Expand All @@ -174,15 +207,19 @@ protected function p( DOMNode $node ): ?Block {
if ( \str_contains( $node->textContent, '//x.com' ) || \str_contains( $node->textContent, '//www.x.com' ) ) {
$node->textContent = str_replace( 'x.com', 'twitter.com', $node->textContent );
}

// Instagram and Facebook embeds require an api key to retrieve oEmbed data.
if ( \str_contains( $node->textContent, 'instagram.com' ) ) {
return $this->instagram_embed( $node->textContent );
}

if ( \str_contains( $node->textContent, 'facebook.com' ) ) {
return $this->facebook_embed( $node->textContent );
}

// Check if the URL is an oEmbed URL and return the oEmbed block if it is.
if ( false !== wp_oembed_get( $node->textContent ) ) {
return $this->embed( $node->textContent );
return $this->oembed( $node->textContent );
}
}

Expand Down Expand Up @@ -270,7 +307,7 @@ protected function ol( DOMNode $node ): Block {
* @param string $url The URL.
* @return Block
*/
protected function embed( string $url ): Block {
protected function oembed( string $url ): Block {
// This would probably be better as an internal request to /wp-json/oembed/1.0/proxy?url=...
$data = _wp_oembed_get_object()->get_data( $url, [] );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,97 +9,88 @@

use Alley\WP\Block_Converter\Block;
use Alley\WP\Block_Converter\Block_Converter;
use Alley\WP\Block_Converter\Tests\Test_Case;
use DOMNode;
use Mantle\Testing\Concerns\Prevent_Remote_Requests;
use Mantle\Testkit\Test_Case;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Group;

use function Mantle\Testing\mock_http_response;

/**
* Test case for Block Block_Converter Module.
*
* @group block
*/
class Test_Block_Block_Converter extends Test_Case {
public function test_convert_content_to_blocks() {
$html = '<p>Content to migrate</p><h1>Heading 01</h1>';
$converter = new Block_Converter( $html );
$block = $converter->convert();

$this->assertNotEmpty( $block );
$this->assertEquals(
'<!-- wp:paragraph --><p>Content to migrate</p><!-- /wp:paragraph -->
<!-- wp:heading {"level":1} --><h1>Heading 01</h1><!-- /wp:heading -->',
$block,
);
}

public function test_convert_heading_h1_to_block() {
$html = '<h1>Another content</h1>';
$converter = new Block_Converter( $html );
$block = $converter->convert();

$this->assertNotEmpty( $block );
$this->assertSame(
'<!-- wp:heading {"level":1} -->' . $html . '<!-- /wp:heading -->',
$block,
);
}

public function test_convert_heading_h2_to_block() {
$html = '<h2>Another content</h2>';
$converter = new Block_Converter( $html );
$block = $converter->convert();

$this->assertNotEmpty( $block );
$this->assertSame(
'<!-- wp:heading {"level":2} -->' . $html . '<!-- /wp:heading -->',
$block,
);
}

public function test_convert_ol_to_block() {
$html = '<ol><li>Random content</li><li>Another random content</li></ol>';
$converter = new Block_Converter( $html );
$block = $converter->convert();

$this->assertNotEmpty( $block );
$this->assertSame(
'<!-- wp:list {"ordered":true} -->' . $html . '<!-- /wp:list -->',
$block,
);
}
#[Group( 'block' )]
class BlockConverterTest extends Test_Case {
use Prevent_Remote_Requests;

public function test_convert_ul_to_block() {
$html = '<ul><li>Random content</li><li>Another random content</li></ul>';
$converter = new Block_Converter( $html );
$block = $converter->convert();
protected function setUp(): void {
parent::setUp();

$this->assertNotEmpty( $block );
$this->assertSame(
"<!-- wp:list -->{$html}<!-- /wp:list -->",
$block,
);
$this->fake_request( [
'https://publish.twitter.com/oembed?maxwidth=500&maxheight=750&url=https%3A%2F%2Ftwitter.com%2Falleyco%2Fstatus%2F1679189879086018562&dnt=1&format=json' => mock_http_response()->with_json( '{"url":"https:\/\/twitter.com\/alleyco\/status\/1679189879086018562","author_name":"Alley","author_url":"https:\/\/twitter.com\/alleyco","html":"\u003Cblockquote class=\"twitter-tweet\" data-width=\"500\" data-dnt=\"true\"\u003E\u003Cp lang=\"en\" dir=\"ltr\"\u003EWe’re a full-service digital agency with the foresight, perspective, and grit to power your brightest ideas and build solutions for your most evasive problems. Learn more about our services here:\u003Ca href=\"https:\/\/t.co\/8zZ5zP1Oyc\"\u003Ehttps:\/\/t.co\/8zZ5zP1Oyc\u003C\/a\u003E\u003C\/p\u003E&mdash; Alley (@alleyco) \u003Ca href=\"https:\/\/twitter.com\/alleyco\/status\/1679189879086018562?ref_src=twsrc%5Etfw\"\u003EJuly 12, 2023\u003C\/a\u003E\u003C\/blockquote\u003E\n\u003Cscript async src=\"https:\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"\u003E\u003C\/script\u003E\n\n","width":500,"height":null,"type":"rich","cache_age":"3153600000","provider_name":"Twitter","provider_url":"https:\/\/twitter.com","version":"1.0"}' ),
'https://www.tiktok.com/oembed?maxwidth=500&maxheight=750&url=https%3A%2F%2Fwww.tiktok.com%2F%40atribecalledval%2Fvideo%2F7348705314746699054&dnt=1&format=json' => mock_http_response()->with_json( '{"version":"1.0","type":"video","title":"Andre 3000 performing at Luna Luna was such an incredible night. I will never forget this night. #losangeles #andre3000 #fyp #foryou #foryoupage ","author_url":"https://www.tiktok.com/@atribecalledval","author_name":"Valeria Cardona","width":"100%","height":"100%","html":"<blockquote class=\"tiktok-embed\" cite=\"https://www.tiktok.com/@atribecalledval/video/7348705314746699054\" data-video-id=\"7348705314746699054\" data-embed-from=\"oembed\" style=\"max-width:605px; min-width:325px;\"> <section> <a target=\"_blank\" title=\"@atribecalledval\" href=\"https://www.tiktok.com/@atribecalledval?refer=embed\">@atribecalledval</a> <p>Andre 3000 performing at Luna Luna was such an incredible night. I will never forget this night. <a title=\"losangeles\" target=\"_blank\" href=\"https://www.tiktok.com/tag/losangeles?refer=embed\">#losangeles</a> <a title=\"andre3000\" target=\"_blank\" href=\"https://www.tiktok.com/tag/andre3000?refer=embed\">#andre3000</a> <a title=\"fyp\" target=\"_blank\" href=\"https://www.tiktok.com/tag/fyp?refer=embed\">#fyp</a> <a title=\"foryou\" target=\"_blank\" href=\"https://www.tiktok.com/tag/foryou?refer=embed\">#foryou</a> <a title=\"foryoupage\" target=\"_blank\" href=\"https://www.tiktok.com/tag/foryoupage?refer=embed\">#foryoupage</a> </p> <a target=\"_blank\" title=\"♬ I swear, I Really Wanted To Make A\" href=\"https://www.tiktok.com/music/I-swear-I-Really-Wanted-To-Make-A-Rap-Album-But-This-Is-Literally-The-Way-The-Wind-Blew-Me-This-Time-7302364812792547330?refer=embed\">♬ I swear, I Really Wanted To Make A \"Rap\" Album But This Is Literally The Way The Wind Blew Me This Time - André 3000</a> </section> </blockquote> <script async src=\"https://www.tiktok.com/embed.js\"></script>","thumbnail_width":576,"thumbnail_height":1024,"thumbnail_url":"https://p19-pu-sign-useast8.tiktokcdn-us.com/obj/tos-useast5-p-0068-tx/afac3ae6ea3343c890e12e3cbbca1218_1711003872?lk3s=b59d6b55&nonce=81617&refresh_token=bf81ce66fb4d648cbd499791f37a6354&x-expires=1722110400&x-signature=tpTiBYwvSXjjAEgNRU2F%2BUAz7jo%3D&shp=b59d6b55&shcp=-","provider_url":"https://www.tiktok.com","provider_name":"TikTok","author_unique_id":"atribecalledval","embed_product_id":"7348705314746699054","embed_type":"video"}' ),
] );
}

public function test_convert_paragraphs_to_block() {
$converter = new Block_Converter( '<p>bar</p>' );
$block = $converter->convert();

$this->assertNotEmpty( $block );
$this->assertSame(
'<!-- wp:paragraph --><p>bar</p><!-- /wp:paragraph -->',
$block,
);
#[DataProvider( 'converter_data_provider' )]
public function test_convert_to_blocks( string $html, string $expected ) {
$this->assertSame( $expected, ( new Block_Converter( $html ) )->convert() );
}

public function test_convert_with_empty_paragraphs_to_block() {
$converter = new Block_Converter( '<p>bar</p><p></p>' );
$block = $converter->convert();
public static function converter_data_provider() {
return [
'paragraph' => [
'<p>Content to migrate</p>',
'<!-- wp:paragraph --><p>Content to migrate</p><!-- /wp:paragraph -->',
],
'empty-paragraphs' => [
'<p>Content to migrate</p><p></p>',
'<!-- wp:paragraph --><p>Content to migrate</p><!-- /wp:paragraph -->',
],
'paragraph-heading' => [
'<p>Content to migrate</p><h1>Heading 01</h1>',
'<!-- wp:paragraph --><p>Content to migrate</p><!-- /wp:paragraph -->
$this->assertNotEmpty( $block );
$this->assertSame(
'<!-- wp:paragraph --><p>bar</p><!-- /wp:paragraph -->',
$block,
);
<!-- wp:heading {"level":1} --><h1>Heading 01</h1><!-- /wp:heading -->',
],
'h1' => [
'<h1>Another content</h1>',
'<!-- wp:heading {"level":1} --><h1>Another content</h1><!-- /wp:heading -->',
],
'h2' => [
'<h2>Another content</h2>',
'<!-- wp:heading {"level":2} --><h2>Another content</h2><!-- /wp:heading -->',
],
'h3' => [
'<h3>Another content</h3>',
'<!-- wp:heading {"level":3} --><h3>Another content</h3><!-- /wp:heading -->',
],
'h4' => [
'<h4>Another content</h4>',
'<!-- wp:heading {"level":4} --><h4>Another content</h4><!-- /wp:heading -->',
],
'h5' => [
'<h5>Another content</h5>',
'<!-- wp:heading {"level":5} --><h5>Another content</h5><!-- /wp:heading -->',
],
'ol' => [
'<ol><li>Random content</li><li>Another random content</li></ol>',
'<!-- wp:list {"ordered":true} --><ol><li>Random content</li><li>Another random content</li></ol><!-- /wp:list -->',
],
'ul' => [
'<ul><li>Random content</li><li>Another random content</li></ul>',
'<!-- wp:list --><ul><li>Random content</li><li>Another random content</li></ul><!-- /wp:list -->',
],
'blockquote' => [
'<blockquote><p>Lorem ipsum</p></blockquote>',
'<!-- wp:quote --><blockquote class="wp-block-quote"><!-- wp:paragraph --><p>Lorem ipsum</p><!-- /wp:paragraph --></blockquote><!-- /wp:quote -->',
],
'non-oembed-embed' => [
'<embed type="video/webm" src="/media/mr-arnold.mp4" width="250" height="200" />',
'<!-- wp:html --><embed type="video/webm" src="/media/mr-arnold.mp4" width="250" height="200"></embed><!-- /wp:html -->',
],
];
}

public function test_convert_with_empty_paragraphs_of_arbitrary_length_to_block() {
Expand Down Expand Up @@ -177,10 +168,6 @@ public function test_youtube_url_to_embed() {
}

public function test_twitter_url_to_embed() {
$this->fake_request( 'https://publish.twitter.com/oembed?maxwidth=500&maxheight=750&url=https%3A%2F%2Ftwitter.com%2Falleyco%2Fstatus%2F1679189879086018562&dnt=1&format=json' )
->with_response_code( 200 )
->with_body( '{"url":"https:\/\/twitter.com\/alleyco\/status\/1679189879086018562","author_name":"Alley","author_url":"https:\/\/twitter.com\/alleyco","html":"\u003Cblockquote class=\"twitter-tweet\"\u003E\u003Cp lang=\"en\" dir=\"ltr\"\u003EWe’re a full-service digital agency with the foresight, perspective, and grit to power your brightest ideas and build solutions for your most evasive problems. Learn more about our services here:\u003Ca href=\"https:\/\/t.co\/8zZ5zP1Oyc\"\u003Ehttps:\/\/t.co\/8zZ5zP1Oyc\u003C\/a\u003E\u003C\/p\u003E&mdash; Alley (@alleyco) \u003Ca href=\"https:\/\/twitter.com\/alleyco\/status\/1679189879086018562?ref_src=twsrc%5Etfw\"\u003EJuly 12, 2023\u003C\/a\u003E\u003C\/blockquote\u003E\n\u003Cscript async src=\"https:\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"\u003E\u003C\/script\u003E\n\n","width":550,"height":null,"type":"rich","cache_age":"3153600000","provider_name":"Twitter","provider_url":"https:\/\/twitter.com","version":"1.0"}' );

$converter = new Block_Converter( '<p>https://twitter.com/alleyco/status/1679189879086018562</p>' );
$block = $converter->convert();

Expand Down

0 comments on commit dbea4ac

Please sign in to comment.