twig/markdown-extra
Twig extension adding Markdown support: convert Markdown to HTML with the markdown_to_html filter, and convert HTML back to Markdown with html_to_markdown. Ideal for rendering user content and round-tripping between formats in Twig templates.
Install the Package:
composer require twig/markdown-extra
If using Laravel with Twig (via twig/laravel), ensure your composer.json includes:
"require": {
"twig/laravel": "^3.0",
"twig/markdown-extra": "^3.26.0"
}
Register the Extension:
In your AppServiceProvider (or TwigServiceProvider if using a custom setup):
use Twig\Extension\MarkdownExtraExtension;
public function boot()
{
$this->app->make(\Twig\Environment::class)->addExtension(new MarkdownExtraExtension());
}
First Use Case: Render Markdown in a Twig template:
{{ markdown_content|markdown_to_html }}
Convert HTML back to Markdown:
{{ html_content|html_to_markdown }}
vendor/twig/laravel/src/TwigServiceProvider.php for Twig environment setup.{# Forum post rendering #}
<div class="post">
{{ user_post.markdown|markdown_to_html }}
</div>
|e escaping needed.// Laravel Controller: Convert HTML to Markdown for version control
public function updateLegacyContent()
{
$html = file_get_contents('legacy_post.html');
$markdown = $this->twig->getTwig()->render(
'{{ html|html_to_markdown }}',
['html' => $html]
);
file_put_contents('post.md', $markdown);
}
// Blade directive for Markdown (custom extension)
Blade::directive('markdown', function ($expression) {
return "<?php echo \Twig\MarkdownExtra\MarkdownExtraExtension::renderMarkdown({$expression}); ?>";
});
Usage:
@markdown($post->content)
// Cache the rendered HTML for 1 hour
$cachedHtml = Cache::remember("markdown_{$post->id}", now()->addHour(), function () use ($post) {
return $this->twig->render('{{ content|markdown_to_html }}', ['content' => $post->markdown]);
});
markdown_to_html filter in custom fields to render Markdown in the admin panel.public function updatedMarkdown()
{
$this->renderedHtml = $this->twig->render(
'{{ markdown|markdown_to_html }}',
['markdown' => $this->markdown]
);
}
return response()->json([
'content' => $this->twig->render('{{ body|markdown_to_html }}', ['body' => $request->body]),
]);
$markdown = $this->twig->render('{{ html_content|html_to_markdown }}', ['html_content' => $request->html]);
// Override escaping for trusted Markdown (e.g., admin-only)
$twig->addFilter(new \Twig\TwigFilter('trusted_markdown', function ($markdown) {
$extension = new MarkdownExtraExtension();
return $extension->getMarkdown()->parse($markdown); // Bypasses auto-escaping
}));
Warning: Only use this for explicitly trusted sources (e.g., admin inputs).
// Add custom syntax (e.g., {{ alert }} blocks)
$markdown = new \Symfony\Markdown\MarkdownConverter([
new \Symfony\Markdown\Extension\AlertExtension(), // Hypothetical
]);
$extension = new MarkdownExtraExtension($markdown);
$twig->addExtension($extension);
Double Escaping:
|e (Twig’s escape filter) after markdown_to_html breaks HTML rendering.{# Wrong: Double-escapes #}
{{ user_comment|markdown_to_html|e }}
{# Correct: Auto-escaping is handled #}
{{ user_comment|markdown_to_html }}
Legacy HTML Breakage:
<div><a href="..."> in Markdown).html_to_markdown cautiously for complex HTML. Test with:
{{ legacy_html|html_to_markdown|markdown_to_html }}
Custom Filter XSS Risks:
$twig->addFilter('safe_markdown', [$extension, 'renderMarkdown'], ['is_safe' => ['html']]);
Twig Version Conflicts:
composer.json:
"require": {
"twig/twig": "^3.0",
"twig/markdown-extra": "^3.26.0"
}
Performance with Large Content:
$markdown = file_get_contents('large_file.md');
$html = $twig->render('{{ content|markdown_to_html }}', ['content' => $markdown]);
dump filter to debug Markdown parsing:
{{ markdown_content|markdown_to_html|dump }}
{{ '<script>alert(1)</script>'|markdown_to_html }} {# Should render as text #}
config/twig.php:
'debug' => env('APP_DEBUG', true),
Auto-Escaping Override: The package cannot disable auto-escaping post-v3.26.0. For trusted content, use custom filters (see above).
Extension Registration:
twig/laravel, the extension is auto-registered. Manual registration may cause duplicates.MarkdownExtraExtension instances in your Twig environment.Markdown Flavor: The package uses Symfony’s CommonMark, which may differ from GitHub-flavored Markdown (e.g., tables, task lists). For full compatibility, extend the converter:
$converter = new \Symfony\Markdown\MarkdownConverter([
new \Symfony\Markdown\Extension\TableExtension(),
]);
Custom Markdown Extensions: Extend Symfony’s Markdown converter to add syntax (e.g., Mermaid diagrams):
$converter = new \Symfony\Markdown\MarkdownConverter([
new \Symfony\Markdown\Extension\CustomExtension(),
]);
$extension = new MarkdownExtraExtension($converter);
Pre/Post-Processing: Hook into the parsing pipeline:
$extension = new MarkdownExtraExtension();
How can I help you explore Laravel packages today?