vtalbot/markdown
A Laravel package that integrates Markdown parsing into your app, with a Markdown facade and Blade directive for converting Markdown text to HTML. Useful for rendering user content, documentation, and other formatted text with configurable parser options.
Install via Composer:
composer require vtalbot/markdown
Laravel 5.5+ – auto-discovery registers the service provider and alias. No config changes needed.
Laravel ≤5.4 (and any framework without discovery) – register manually in config/app.php:
// providers
Vtalbot\Markdown\MarkdownServiceProvider::class,
// aliases
'Markdown' => Vtalbot\Markdown\Facades\Markdown::class,
First thing to look at: open the facade class and service provider in vendor/vtalbot/markdown/src. The entire package surface is small — a single binding plus a parse() method (and typically a parseFile() helper). Reading them takes two minutes and tells you exactly which underlying compiler it wraps (Historically michelf/php-markdown), which matters for dialect support and later debugging.
First use case – the canonical "render a string as HTML":
use Vtalbot\Markdown\Facades\Markdown;
$html = Markdown::parse('# Hello **world**');
// <h1>Hello <strong>world</strong></h1>
From here, the most common integration is rendering a .md document or a user-submitted field into a Blade view. The package simply gives you a Laravel-idiomatic facade over a PHP Markdown compiler; treat it as a thin convenience layer, not a full content pipeline.
Render inside a view / Blade directive
// Controller
return view('docs.show', ['body' => Markdown::parse($doc->markdown)]);
// Or inline in Blade with raw output
{!! Markdown::parse($post->body) !!}
If you want a reusable directive, register a Blade @markdown in a service provider:
Blade::directive('markdown', function ($expression) {
return "<?php echo app('markdown')->parse($expression); ?>";
});
Render markdown stored on disk
$html = Markdown::parseFile(resource_path('docs/getting-started.md'));
For anything beyond trivial, prefer file_get_contents() + Markdown::parse() so you control the path, encoding, and error handling yourself. parseFile will fail silently or throw on missing paths depending on the underlying engine.
Cache compiled output – markdown compilation is CPU work you don't need to repeat on every request. Cache at the source-hash level so edits invalidate automatically:
$html = Cache::remember('md:'.md5($markdown), now()->addDay(), function () use ($markdown) {
return Markdown::parse($markdown);
});
Sanitize before saving or rendering – this package deliberately does not escape HTML. Pair it with a sanitizer (HTMLPurifier, or league/html-sanitizer) if the source is user-controlled:
$html = Markdown::parse($input);
$safe = Purifier::clean($html);
Notifications and mail – markdown output pairs well with Laravel's Mailable ->markdown() view helper, but the two systems are independent. Use vtalbot/markdown when you already have stored markdown strings you want to render; use Laravel's native markdown mail components when the content is authored as a Blade-markdown template.
Testing – mock the facade when asserting controller output, so you don't couple tests to the compiler's HTML formatting:
Markdown::shouldReceive('parse')->once()->andReturn('<h1>Stubbed</h1>');
Output is unsafe by default. Markdown permits inline HTML, and the underlying engine passes it through. An attacker can embed <script> or onerror= inside a code fence escape. Never render user markdown with {!! !!} without sanitization. This is the single biggest production risk with the package.
Laravel version drift. The last tagged release is from March 2021 and the description only claims Laravel 4 and 5. Auto-discovery was added for Laravel 5.5 but later versions (9/10/11) are untested. The facade binding still works in practice because the package is thin, but if you hit "target class [markdown] does not exist" or a container resolution error, fall back to manual provider registration — and don't expect upstream fixes for modern-version issues.
Facade alias collisions. If your app also pulls in a different markdown wrapper (GrahamCampbell's, spatie/laravel-markdown, etc.), the Markdown alias will clash. Use the FQCN in code or rename the alias in config/app.php to something like 'Md'.
Dialect quirks. The behavior of tables, fenced code blocks, footnotes, and strikethrough depends entirely on the underlying compiler version pinned in composer.lock. If a feature "doesn't work," check the engine before assuming the Laravel wrapper is at fault. Compare raw output against the engine's own CLI/example to isolate.
parseFile path resolution. Relative paths are resolved against the process working directory, not base_path(). Always pass an absolute path (base_path(), resource_path(), storage_path()) to avoid surprises when running queue workers, artisan commands, or tests from different directories.
No config file to publish. There's generally nothing to php artisan vendor:publish. Tuning (line breaks, HTML escaping, extensions) requires either editing the underlying engine or subclassing/replacing the binding. If you need GFM, footnotes, or custom extensions, it's often cheaper to swap the package for league/commonmark than to patch this one.
Watch for PHP 8 deprecations. With a 2021 release and a small dependency tree, dynamic property deprecations or null-to-string deprecations in the wrapper can surface on PHP 8.2+. Run your test suite on the target PHP version before shipping; pin PHP if you must.
When to reach for something else. This package is best when you need a five-line "markdown string → HTML" helper inside an existing Laravel 5 app. For a new install, a CMS, or anything requiring sanitization guarantees, GFM parity, or active maintenance, league/commonmark (with league/html-sanitizer) is the safer day-to-day choice.
How can I help you explore Laravel packages today?