Weave Code
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

Parsedown Laravel Package

erusev/parsedown

Parsedown is a fast, lightweight PHP Markdown parser with CommonMark-style syntax support. It converts Markdown to HTML with sensible defaults, minimal dependencies, and easy integration—ideal for blogs, docs, and templating in PHP and Laravel apps.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install via Composer

    composer require erusev/parsedown
    
  2. Basic Usage in Laravel
    In a controller or service class:

    use Parsedown;
    
    $parsedown = new Parsedown();
    $html = $parsedown->text('# Hello, world!');
    // Outputs: <h1>Hello, world!</h1>
    
  3. First Use Case
    Render Markdown stored in a database field (e.g., blog content):

    $post = Post::find($id);
    $content = $parsedown->text($post->markdown_body);
    return view('posts.show', compact('post', 'content'));
    
  4. Where to Look First

    • Parsedown.php — read inline docblocks and method signatures.
    • Parsedown Demo — test syntax and see output.
    • Focus on text() and line() methods — text() for full documents, line() for inline-only.
    • New in v1.8.0: Consider enabling setStrictMode(true) for CommonMark-compliant ATX headings (requires a space after #), especially if rendering user content where # alone should not produce a heading.

Implementation Patterns

  1. Service Binding in Laravel
    Register a shared instance via AppServiceProvider:

    $this->app->singleton(\Parsedown::class, function () {
        return (new \Parsedown())->setBreaksEnabled(true); // optional: better newline handling
    });
    

    Tip (v1.8.0): If rendering untrusted input, instantiate with ->setSafeMode(true) and pair with HTML Purifier — safe mode is now recursively applied.

  2. Blade Component Wrapper
    Create a reusable component:

    {{-- resources/views/components/markdown.blade.php --}}
    <div class="markdown-content">
        @php
            $parsedown = new \Parsedown();
            $parsedown->setBreaksEnabled(true);
            // Uncomment for strict CommonMark compliance:
            // $parsedown->setStrictMode(true);
        @endphp
        {!! $parsedown->text($slot) !!}
    </div>
    

    Usage:

    <x-markdown>
        ## Notes  
        - *Lightweight*  
        - **Fast**
    </x-markdown>
    
  3. Caching Renders
    Cache parsed HTML to avoid repeated parsing — especially important given improved security via strict parsing (reduces ReDoS risk, but still expensive for high-throughput):

    $cacheKey = "markdown:{$id}";
    $html = Cache::remember($cacheKey, now()->addDay(), function () use ($parsedown, $markdown) {
        return $parsedown->text($markdown);
    });
    
  4. Extending for Custom Features
    Subclass to add GitHub-style task lists or custom syntax — note significant structural changes for v1.8.0:

    class ExtendedParsedown extends \Parsedown
    {
        protected function blockTaskList($Line)
        {
            if (preg_match('/^\s*-\s*\[(x| )\]\s+(.*)$/i', $Line['text'], $matches)) {
                $checked = $matches[1] === 'x' ? 'checked' : '';
                return [
                    'element' => [
                        'name' => 'li',
                        'text' => "<input type='checkbox' disabled {$checked}> {$matches[2]}"
                    ]
                ];
            }
        }
    
        // ⚠️ Breaking in v1.8.0: Element structure changed
        // Previously: $Block['element']['text']['text']
        // Now: $Block['element']['element']['text']
    }
    

Gotchas and Tips

  1. Safe Mode Is Now Safer (but Still Not Enough)
    setSafeMode(true) now recursively sanitizes nested elements — a major improvement. However, it does not prevent all XSS (e.g., onerror on <img>). For untrusted input:

    • Always sanitize output with HTML Purifier after parsing.
    • Use setStrictMode(true) to avoid edge cases like #-only headings becoming paras.
  2. Performance Considerations

    • Regex ReDoS mitigation (via possessive quantifiers) improves security but may cause minor slowdowns on pathological inputs — still far faster than most CMS WYSIWYGs.
    • Caching is now more critical: Parsing 500+ lines of complex Markdown once (e.g., docs) before caching avoids repeated performance hit.
  3. Markdown Behavior Changes (v1.8.0)

    • Lists: Mixing markers (*, -, +) or switching between . and ) in ordered lists creates separate lists (CommonMark-compliant).
      Example:
      - Item
      * Item 2  # ← Now starts a *new* list instead of continuing
      
    • Blockquotes: Blank lines separate them — no more merging.
      > First  
      
      > Second  # ← Now two `<blockquote>`s, not one.
      
    • Empty headings: # now outputs <h1></h1>, not a paragraph.
    • Tables: One-column tables now work; table headers must not contain newlines.
  4. Extensibility Updates (v1.8.0)

    • Block element structure has changed — text may now be nested under elementelement.
    • Use $this->allowRawHtmlInSafeMode($element) in extensions to exempt trusted HTML in safe mode.
  5. PHP & Laravel Compatibility

    • PHP 7.1+ required — old apps on PHP 5.6/7.0 must upgrade first.
    • Resolves deprecations for PHP 8.4 (e.g., nullable parameters).
    • PSR-0 autoloading remains — no change, but ensure classmap isn’t overriding Parsedown.
  6. Table Alignment Still Not Supported
    Custom subclassing (blockTable()) remains necessary for alignment — no change in v1.8.0.

  7. Emoji & Shortcode Handling
    Parsedown still doesn’t support emoji shortcodes (e.g., :smile:) — use a preprocessor (e.g., ParsedownExtra) or Laravel mix-in if needed.

  8. Breaking Extension Changes
    If using third-party Parsedown extensions (e.g., ParsedownExtra), verify compatibility. The internal AST restructuring may require updates for custom block/inline handlers.

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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport