orchestra/kurenai
Orchestra Kurenai is a Laravel package for managing URL redirects in a clean, centralized way. It helps preserve SEO and keep legacy links working by letting you define and handle redirections that integrate smoothly with modern Laravel applications.
php artisan vendor:publish --tag=markdown-config. The config file is where the parser/driver is selected — from v0.2.0 onward you can point it at the CommonMark implementation rather than the legacy renderer.convert() / toHtml() method. Those are the only surfaces you normally touch.// config/markdown.php
'driver' => 'commonmark',
'commonmark' => [
'html_input' => 'escape', // or 'strip'
'allow_unsafe_links' => false,
],
<div class="prose">{!! $markdown->convert($post->body) !!}</div>
Once that round-trips correctly, add extensions (tables, autolinks, strikethrough) one at a time rather than all at once, so you can attribute any output change to a single feature.
Facade/helper in views and mailables. Wrap conversion in a small Blade component (<x-markdown :text="$body" />) so sanitization and caching live in one place instead of being repeated with {!! !!} across templates. The same component is the natural fit for Mailables rendered server-side.
Store raw, render on read (with cache). Keep the Markdown source in the database and cache the HTML keyed by a hash of the source plus a parser-version string. This lets you re-render every post when you change config (for example, enabling CommonMark extensions) without a data migration.
$html = Cache::remember(
"md:".sha1($post->body).":".config('markdown.version'),
now()->addDay(),
fn () => $markdown->convert($post->body)
);
Register extensions explicitly. With CommonMark as the engine, GitHub-flavoured extras are opt-in. Enable tables, autolinks and strikethrough in config, and register custom extensions in a service provider so they're discoverable and testable in isolation.
Sanitization as a pipeline stage. Treat the parser as one step and an HTML sanitizer (or html_input => 'escape'/'strip') as the next. Do this in the component, not at every call site — it's the single easiest way to avoid an XSS regression when someone adds a new render path.
Testing. Assert on rendered HTML in feature tests, and keep a fixture corpus of tricky documents (nested lists, fenced code containing Markdown, mixed indentation). The CommonMark spec examples make a good smoke test, and pinning a few of them guards against behaviour drift on future upgrades.
Integration tips. Register the package's parser as a singleton if you enable extensions with state; resolve it from the container in queued jobs that pre-render content; and if you expose a preview endpoint, run it through the exact same component so preview and published output can't diverge.
html_input / sanitizer config. Verify with a payload like <img src=x onerror=alert(1)> before trusting any output path.~~strikethrough~~ are not core — they need extensions enabled. If content rendered fine on the previous driver, diff the output after switching; indentation rules and list-marker handling are the usual regressions.<br> by default. If your authors rely on that, you need the hard_break/breaks option or an extension — otherwise every paragraph silently reflows.config:cache in production. Config is read once at boot; a stale cached config after changing driver or extensions produces confusing "my change did nothing" behaviour. php artisan config:clear before debugging anything about output.markdown.version value whenever you change driver, extensions, or sanitizer settings — otherwise old HTML survives the deploy.app('markdown')::class) — a wrong binding looks exactly like a parsing bug.DocumentParsedEvent listener; keep these in dedicated classes and unit-test them against a string in / AST or HTML out, since they're the part most likely to break on a minor upgrade.How can I help you explore Laravel packages today?