Wire MediaEmbedExtension into Document::renderMarkdown

The extension registers a DocumentParsedEvent listener that walks the
AST, finds Image nodes whose URLs match media patterns (via
MediaUrlResolver), and replaces them with MediaEmbedNode instances
containing the appropriate <video>/<audio>/<iframe> markup.

A custom MediaEmbedNode + MediaEmbedNodeRenderer pair bypasses the
html_input filter (which would strip raw HTML when set to 'strip'),
allowing programmatically generated embed HTML to pass through safely
while user-authored raw HTML remains stripped.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Yutaka Kurosaki
2026-05-09 11:03:09 +09:00
parent 6ee4dcfc21
commit f26b930b5f
6 changed files with 130 additions and 0 deletions
@@ -0,0 +1,38 @@
<?php
namespace Tests\Unit\Markdown;
use App\Models\Document;
use Tests\TestCase;
class MediaEmbedExtensionTest extends TestCase
{
public function test_normal_image_still_renders_as_img(): void
{
$html = Document::renderMarkdown('![alt](/photo.png)');
$this->assertStringContainsString('<img', $html);
$this->assertStringContainsString('src="/photo.png"', $html);
}
public function test_video_url_renders_as_video_tag(): void
{
$html = Document::renderMarkdown('![](/demo.mp4)');
$this->assertStringContainsString('<video', $html);
$this->assertStringContainsString('src="/demo.mp4"', $html);
$this->assertStringNotContainsString('<img', $html);
}
public function test_youtube_url_renders_as_iframe(): void
{
$html = Document::renderMarkdown('![](https://youtu.be/dQw4w9WgXcQ)');
$this->assertStringContainsString('<iframe', $html);
$this->assertStringContainsString('youtube-nocookie.com', $html);
}
public function test_vimeo_url_renders_as_iframe(): void
{
$html = Document::renderMarkdown('![](https://vimeo.com/123456789)');
$this->assertStringContainsString('<iframe', $html);
$this->assertStringContainsString('player.vimeo.com', $html);
}
}