Installation
composer require knplabs/knp-markdown-bundle
Add to config/bundles.php (Laravel 5.5+ auto-discovers, but explicit inclusion ensures compatibility):
Knp\Bundle\MarkdownBundle\KnpMarkdownBundle::class => ['all' => true],
Basic Usage
Inject the KnpMarkdownBundle\MarkdownService into a controller or service:
use Knp\Bundle\MarkdownBundle\MarkdownService;
public function __construct(private MarkdownService $markdown)
{
}
public function renderMarkdown(string $markdownContent): string
{
return $this->markdown->transformMarkdown($markdownContent);
}
First Use Case Render a blog post or comment in a view:
{{ markdown(content) }} {# Twig filter #}
Or in PHP:
$html = $this->markdown->transformMarkdown($markdownText);
return view('post.show', ['content' => $html]);
Twig Integration
Use the markdown filter in Twig templates:
{{ post.content|markdown }}
Configure extensions (e.g., tables, footnotes) via config/packages/knp_markdown.yaml:
twig:
markdown_extensions: [extra, tables]
Dynamic Processing Process markdown in controllers/services:
$html = $this->markdown->transformMarkdown($rawMarkdown, [
'extra' => true,
'safe_mode' => false,
]);
Caching Cache rendered markdown to avoid reprocessing:
$cacheKey = 'markdown_'.$post->id;
$html = Cache::remember($cacheKey, now()->addHours(1), function() use ($post) {
return $this->markdown->transformMarkdown($post->content);
});
Form Handling Sanitize markdown input (e.g., from forms) to prevent XSS:
$sanitized = $this->markdown->transformMarkdown($userInput, [
'safe_mode' => true, // Disables dangerous HTML tags
]);
Custom Extensions Register a custom extension (e.g., for Laravel-specific syntax):
$markdown = new \Michelf\MarkdownExtra();
$markdown->addExtension(new class extends \Michelf\MarkdownExtra_Extension {
public function getName() { return 'laravel'; }
public function getPattern() { return '/\[@(\w+)\]/'; }
public function handle($text, $matches) {
return '<a href="/user/'.$matches[1].'">@'.$matches[1].'</a>';
}
});
$this->markdown->setMarkdown($markdown);
Event Listeners Hook into markdown processing via events (e.g., log processed content):
public function handle(KnpMarkdownEvent $event)
{
Log::debug('Markdown processed', ['content' => $event->getContent()]);
}
Register in EventServiceProvider:
protected $listen = [
KnpMarkdownEvent::MARKDOWN_TRANSFORMED => [
\App\Listeners\LogMarkdown::class,
],
];
API Responses Return markdown-rendered content in API responses:
return response()->json([
'content' => $this->markdown->transformMarkdown($post->content),
]);
XSS Vulnerabilities
safe_mode: false allows arbitrary HTML/JS injection.safe_mode: true in production or sanitize output:
$html = $this->markdown->transformMarkdown($input, ['safe_mode' => true]);
$html = strip_tags($html, '<p><a><strong><em><ul><ol><li><br>');
Extension Conflicts
tables) may break rendering.# config/packages/knp_markdown.yaml
twig:
markdown_extensions: [extra] # Exclude problematic extensions
Performance
now()->addDays(7) for static content.Twig vs. PHP API
$this->markdown->transformMarkdown($text, $this->getMarkdownOptions());
Inspect Extensions Dump enabled extensions to debug issues:
$markdown = $this->markdown->getMarkdown();
dump(get_class_methods($markdown));
Raw Output Compare raw vs. processed markdown to spot parsing errors:
$raw = $request->input('content');
$processed = $this->markdown->transformMarkdown($raw);
dd(['raw' => $raw, 'processed' => $processed]);
Configuration Overrides Override global config per request:
$this->markdown->setMarkdownOptions([
'extra' => true,
'safe_mode' => false,
]);
Custom Markdown Parser Replace the default parser (Michelf/Markdown) with Parsedown or [CommonMark]:
$this->markdown->setMarkdown(new \Parsedown());
Pre/Post-Processing Wrap the service to add logic:
class CustomMarkdownService
{
public function __construct(private MarkdownService $markdown) {}
public function render(string $content): string
{
$html = $this->markdown->transformMarkdown($content);
return $this->postProcess($html);
}
private function postProcess(string $html): string
{
// Add custom logic (e.g., analytics tags)
return str_replace('<p>', '<p data-track="true">', $html);
}
}
Environment-Specific Config Use Laravel’s config caching to switch extensions per environment:
# config/packages/knp_markdown/dev.yaml
twig:
markdown_extensions: [extra, footnotes]
# config/packages/knp_markdown/prod.yaml
twig:
markdown_extensions: [extra]
safe_mode: true
How can I help you explore Laravel packages today?