Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Markdown Bundle Laravel Package

ornj/markdown-bundle

ornj/markdown-bundle is a Symfony bundle for parsing and rendering Markdown as HTML. It integrates Markdown conversion into Symfony services and templating, making it easy to add Markdown support to content, controllers, and Twig views with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

First, correct the premise before you do anything else. ornj/markdown-bundle is a Symfony2 bundle, not a Laravel package. It has no service provider, no facade, no Blade integration, and its Twig filter, FormType, and DI wiring don't map onto Laravel's container or view layer. There is no composer require ornj/markdown-bundle path into a Laravel app that ends well: the package is pinned to Symfony2's EOL'd kernel, the Form component, Twig, and (likely) Assetic-era asset handling. Its dependencies will collide with a modern Laravel/PHP stack.

So the honest "getting started" depends on which stack you're actually on:

  • Laravel (the brief's implied target): treat the repo as reference prior art only. Clone it, read the FormType, the JS preview code, and the Twig templates, and note the interaction shape (textarea + preview target + debounced render). Then build the feature natively — don't install.
  • Legacy Symfony2 (the only legitimate consumer): register the bundle in AppKernel.php (new Ornj\MarkdownBundle\OrnjMarkdownBundle()), expose the service in config.yml, and use the Twig filter in templates. This is the one scenario where the package works as advertised.

Where to look first in the source:

  1. The bundle class — confirms the service IDs and Twig extension registration.
  2. The Markdown service / renderer wrapper — this is the piece whose behavior you'd actually replicate (league/commonmark in Laravel).
  3. The FormType and its Twig template — the input + preview interaction contract; discard the Symfony-specific wiring, keep the UX shape.
  4. The JavaScript — debounce strategy, preview endpoint vs. client-side render, toolbar behavior.

First use case for a Laravel dev (build, don't install):

composer require league/commonmark mews/purifier

Then a minimal Blade component:

{{-- resources/views/components/markdown-editor.blade.php --}}
<div x-data="{ md: @entangle($model).live }">
    <textarea x-model="md"></textarea>
    <div>{!! $previewHtml !!}</div>
</div>

…with the server-side render going through league/commonmark + mews/purifier, never the raw parser output.

Implementation Patterns

If you legitimately run Symfony2 (legacy):

  • Service injection: constructor-inject the bundle's markdown service into controllers or services rather than instantiating a parser yourself; the whole point of the bundle is centralizing parser config.
  • Twig filter: render with the provided filter in templates, e.g. {{ article.body|markdown }}. Be explicit about escaping — see gotchas.
  • Config options: tune the parser (extensions, HTML handling) in the bundle's config block, not inline in templates, so behavior is consistent across the app.

If you're porting the pattern to Laravel (the realistic path):

  • Single rendering path (non-negotiable): preview and published output must go through the same function. Encapsulate it once:

    final class MarkdownRenderer
    {
        public function __construct(private CommonMarkConverter $parser, private Purifier $purifier) {}
        public function toHtml(string $md): string
        {
            return $this->purifier->purify((string) $this->parser->convert($md));
        }
    }
    

    Call it from both the preview endpoint and the Blade render of stored content. Divergence between the two is the classic markdown-editor bug.

  • Canonical source is markdown: store the raw markdown in the DB (diffable, version-controllable); treat rendered HTML as disposable/cacheable output. This is the pattern the bundle models and the one worth carrying forward.

  • Preview strategy: prefer client-side preview (marked/remark in the browser, sanitized with DOMPurify) to avoid a render request per keystroke-debounce. If you need server parity, expose one debounced endpoint (e.g. POST /markdown/preview) that returns the sanitized HTML from your MarkdownRenderer, and rate-limit it.

  • Editor component: wrap a maintained editor (EasyMDE, Toast UI, or a CodeMirror-based one) inside a Livewire component or Blade + Alpine. This replaces the bundle's JS/FormType entirely, with active maintenance.

  • Form integration: on the Laravel side the "form field" is a Blade/Livewire component bound to a model attribute; validation (size limits, allowed chars) belongs in a FormRequest — none of this comes from the bundle.

Gotchas and Tips

  • Stack mismatch is the headline gotcha. No Laravel adapter exists; any attempt to force the bundle in produces dependency-resolution failures at best and an unpatched, EOL attack surface at worst. If you're on Laravel, this is read-only reference code.
  • XSS is the real risk, and it lives in the parser, not the widget. Markdown permits raw HTML by default. The bundle does not solve sanitization for your public rendering path — you must own an HTML allow-list (mews/purifier, HTML Purifier, DOMPurify client-side). Treat the preview as not a trust boundary.
  • Twig auto-escaping vs. rendered HTML: if you're on the Symfony path, the markdown filter output must be marked raw (or returned as a safe type), or you'll see escaped tags. That's also where accidental double-escaping bugs appear.
  • Preview ≠ published output. Wire both through one renderer (see the pattern above) and add a test asserting they match for a fixture document. This bug class is embarrassing and easy to ship.
  • Cache rendered HTML keyed on a content hash; don't re-parse on every page load. The bundle gives you no caching — layer it yourself.
  • Debugging (Symfony2 path): dump the container (debug:container) to confirm the service ID and parser config actually registered; misconfigured bundle registration silently falls back or throws at boot, not at render.
  • Debugging (Laravel port): isolate the parser from the sanitizer when output looks wrong — parse first, inspect raw HTML, then purify. Symptom "my tables/links disappeared" almost always means the sanitizer stripped them, not the parser.
  • Extension points: the bundle's "configurable parser options" are your model for what to expose — enable/disable GFM (tables, task lists, strikethrough), heading anchors, autolinks. On Laravel this maps to league/commonmark extensions; centralize the config so preview and stored output enable the same set.
  • Maintenance reality: zero stars, zero dependents, EOL framework target — no upstream fixes, no CVE response, no compatibility guarantees. If you fork it, you own every future PHP/parser bump. Budget the effort as build-from-maintained-parts in days, not install-and-go.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package