alfredo-ramos/parsedown-extra-laravel
Laravel integration for Parsedown Extra, bringing Markdown parsing with support for tables, footnotes, and other extended syntax to your Blade views and PHP code through a simple facade and service provider.
Install into the Laravel app:
composer require alfredo-ramos/parsedown-extra-laravel
The package pulls in erusev/parsedown-extra, which itself extends erusev/parsedown.
Register it:
config/app.php under providers and the facade under aliases.Publish the config (if the package exposes one):
php artisan vendor:publish --tag=parsedown-extra
This usually produces config/parsedown-extra.php, where you can toggle Parsedown Extra options such as line breaks, markup escaping, URL linking, and safe mode.
Where to look first:
config/parsedown-extra.php — the supported knobs.src/ service provider — confirms the binding name and whether a Blade directive is registered.First use case — render a Markdown body stored in a model into HTML inside a Blade view:
{!! ParsedownExtra::text($post->body) !!}
If the package registers a Blade directive (check the provider), you may also be able to write @markdown($post->body).
Facade for one-off rendering. The most common pattern is calling the facade (or resolved singleton) wherever you need HTML:
$html = ParsedownExtra::text($markdown);
Parsedown's text() returns the rendered HTML string; line() handles a single line. The Extra subclass enables the extended syntax, so tables, footnotes, and definition lists work without extra configuration.
Dependency injection for testability. Instead of the facade, type-hint the Parsedown Extra instance in a service or controller so you can swap or mock it in tests. The container binding is a singleton, so repeated calls in one request reuse the same parser.
Keep Markdown and HTML separate. Store the raw Markdown in the database and render on read (or on write into a cached column). This preserves the source if you later change renderers or config, and makes search/rewrites easier. A common pattern is a body_markdown + body_html pair, with body_html regenerated by an observer or queue job when the Markdown changes.
Cache the output. Parsing is cheap but not free, and the output is deterministic for a given config. Wrap rendering:
$html = Cache::remember("post:{$post->id}:html", 3600, fn () => ParsedownExtra::text($post->body));
Flush the key in your model's saved/deleted events. For pages with many short snippets (comments, chat), batch-render or cache per fragment.
Tune behavior via config, not code. Rather than calling setters all over the app, configure defaults centrally in config/parsedown-extra.php (or by re-binding a configured instance in a service provider). If the package's config only covers a subset of Parsedown's options, extend it by resolving the singleton and applying setters in a AppServiceProvider::boot().
Custom rendering/extensions. If you need altered output — custom link targets, attribute injection, syntax highlighting of code blocks — subclass ParsedownExtra, override the relevant methods (element(), blockFencedCode(), etc.), and rebind the singleton in a service provider so the facade and any injected instances pick up your subclass.
Rendering untrusted content. For user-submitted Markdown (comments, profiles), enable safe mode and/or markup escaping in config so raw HTML is not passed through. For trusted editorial content, the defaults that allow inline HTML may be preferable. Decide per content type, not globally — often you want two configured instances (editorial vs user).
Blade integration. If the package registers a directive, use it for inline cases; for anything more complex (caching, safe-mode switching) prefer a helper/service so the logic is testable outside views.
league/commonmark (MIT/BSD) instead. This alone often decides adoption.setSafeMode(true) blocks some vectors but has had bypasses historically. Treat it as defense-in-depth, not the only layer.<br>; writers used to GitHub-flavored rendering will be confused. Enable breaks in config if that's the expectation — and document it.<script> is also surviving, you forgot markup escaping or safe mode. Check with a payload like <img src=x onerror=alert(1)>.Markdown or Parsedown) can clash with other packages. If you install a second Markdown integration, verify which alias wins in config/app.php.php artisan config:clear (and config:cache in production). A stale cached config is a classic "my setting didn't apply" debugging trap.vendor:publish with a tag fails, run it without --tag and inspect the provider's publishes() call to find the correct key.@foreach over hundreds of items without caching is a common accidental hot path. Render once, cache, or precompute on save.composer.json and add a rendering test (tables, footnotes, fenced code, safe-mode payload) so an upstream or transitive bump is caught by CI rather than by users.How can I help you explore Laravel packages today?