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

Commonmark Laravel Package

league/commonmark

Highly extensible PHP Markdown parser supporting full CommonMark and GitHub-Flavored Markdown. Convert Markdown to HTML with simple converters, customize rendering via extensions, and run safely with options like stripping HTML and blocking unsafe links.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require league/commonmark
    
  2. Basic Usage:

    use League\CommonMark\CommonMarkConverter;
    
    $converter = new CommonMarkConverter();
    $html = $converter->convert('# Hello World!');
    
  3. First Use Case: Render markdown content from a database or user input into HTML for display in a Laravel blade template:

    $markdown = "## Features
    - **Fast**: Optimized for performance
    - **Extensible**: Supports custom extensions";
    
    $converter = new CommonMarkConverter();
    $html = $converter->convert($markdown);
    
    return view('post.show', ['content' => $html]);
    

Where to Look First


Implementation Patterns

Core Workflows

1. Basic Markdown Conversion

// In a Laravel service or controller
public function renderMarkdown(string $markdown): string
{
    $converter = new CommonMarkConverter([
        'html_input' => 'strip', // Security best practice
    ]);

    return $converter->convert($markdown);
}

2. GitHub-Flavored Markdown (GFM)

use League\CommonMark\GithubFlavoredMarkdownConverter;

$gfmConverter = new GithubFlavoredMarkdownConverter([
    'html_input' => 'strip',
    'tables' => true, // Enable tables if needed
]);

3. Integration with Laravel Blade Directives

Create a custom Blade directive in AppServiceProvider@boot():

Blade::directive('markdown', function ($expression) {
    $markdown = $expression;
    $converter = new CommonMarkConverter();
    return "<?php echo \\League\\CommonMark\\CommonMarkConverter::convertToHtml({$markdown}); ?>";
});

Usage in Blade:

@markdown($post->content)

4. Caching Parsed Markdown

use Illuminate\Support\Facades\Cache;

public function getCachedMarkdown(string $key, string $markdown, int $ttl = 3600)
{
    return Cache::remember("markdown.{$key}", $ttl, function () use ($markdown) {
        return (new CommonMarkConverter())->convert($markdown);
    });
}

5. Extending with Custom Extensions

use League\CommonMark\Extension\ExtensionInterface;
use League\CommonMark\Environment\Environment;

public function getExtendedConverter(): CommonMarkConverter
{
    $environment = new Environment();
    $environment->addExtension(new CustomExtension());

    return new CommonMarkConverter($environment);
}

Integration Tips

Laravel-Specific Patterns

  1. Service Container Binding:

    $this->app->bind(CommonMarkConverter::class, function ($app) {
        return new CommonMarkConverter([
            'html_input' => 'strip',
            'allow_unsafe_links' => false,
        ]);
    });
    
  2. Form Request Validation:

    public function rules()
    {
        return [
            'content' => 'required|markdown', // Custom rule for markdown validation
        ];
    }
    
  3. API Responses:

    return response()->json([
        'content' => (new CommonMarkConverter())->convert($request->markdown),
    ]);
    

Performance Optimization

  • Reuse Converters: Instantiate converters once and reuse them (they are thread-safe).
  • Disable Unused Extensions: Reduce memory usage by only enabling required extensions.
  • Lazy Loading: Load markdown content only when needed (e.g., in Blade templates).

Testing

public function testMarkdownConversion()
{
    $converter = new CommonMarkConverter();
    $html = $converter->convert('# Test');

    $this->assertStringContainsString('<h1>Test</h1>', $html);
}

Gotchas and Tips

Pitfalls

  1. XSS Vulnerabilities:

    • Always set 'html_input' => 'strip' and 'allow_unsafe_links' => false when parsing user input.
    • Example of unsafe usage:
      // UNSAFE: Allows arbitrary HTML/JS injection
      $converter = new CommonMarkConverter(['html_input' => 'allow']);
      
  2. Encoding Issues:

    • The library only supports UTF-8 and ASCII. Ensure input is UTF-8 encoded:
      $markdown = mb_convert_encoding($userInput, 'UTF-8');
      
  3. Breaking Changes in Minor Versions:

    • Minor updates may change HTML output (e.g., bug fixes, spec updates). Test thoroughly after updates.
  4. Extension Conflicts:

    • Some extensions may override or conflict with core functionality. Test combinations carefully.
  5. AST Modifications:

    • Modifying the Abstract Syntax Tree (AST) directly can lead to unexpected behavior. Use extensions for custom logic.

Debugging Tips

  1. XML Output for Debugging: Use MarkdownToXmlConverter to inspect the AST:

    use League\CommonMark\Xml\MarkdownToXmlConverter;
    
    $xmlConverter = new MarkdownToXmlConverter($environment);
    $xml = $xmlConverter->convert($markdown);
    
  2. Logging Extensions: Create a debug extension to log parsing events:

    use League\CommonMark\Event\DocumentParsed;
    use League\CommonMark\Extension\ExtensionInterface;
    
    class DebugExtension implements ExtensionInterface
    {
        public function register(Environment $environment)
        {
            $environment->addEventListener(DocumentParsed::class, function (DocumentParsed $event) {
                \Log::debug('Parsed document:', ['ast' => $event->getDocument()->children()]);
            });
        }
    }
    
  3. CommonMark Spec Validation: Use the CommonMark Spec Tests to validate edge cases.

Configuration Quirks

  1. Environment vs. Converter Options:

    • Converter options (e.g., html_input) are applied at runtime.
    • Environment extensions are applied once during initialization.
  2. GFM vs. CommonMark:

    • GithubFlavoredMarkdownConverter includes additional features (tables, task lists) but may have slightly different behavior for overlapping syntax.
  3. Lazy Loading Extensions: Some extensions (e.g., TableExtension) are lazy-loaded and may not be available until first use.

Extension Points

  1. Custom Inline Parsers: Override inline parsing logic (e.g., for Twitter handles or emoticons):

    use League\CommonMark\InlineParser\ElementContentParserInterface;
    
    class CustomInlineParser implements ElementContentParserInterface
    {
        public function parse(InlineParserContext $context)
        {
            // Custom parsing logic
        }
    }
    
  2. Renderer Decorators: Modify HTML output without changing parsing logic:

    use League\CommonMark\Renderer\NodeRendererInterface;
    
    class CustomHeadingRenderer implements NodeRendererInterface
    {
        public function render(Node $node, NodeRendererContext $context)
        {
            // Custom rendering logic
        }
    }
    
  3. Event Listeners: Hook into parsing events (e.g., DocumentParsed, BlockParsed):

    $environment->addEventListener(DocumentParsed::class, function (DocumentParsed $event) {
        // Post-processing logic
    });
    

Laravel-Specific Gotchas

  1. Blade Caching: Ensure markdown content is not cached in Blade if it changes dynamically:

    @verbatim
        {!! (new League\CommonMark\CommonMarkConverter())->convert($post->content) !!}
    @endverbatim
    
  2. Queue Jobs: Avoid instantiating converters in queue jobs (reuse them via the service container).

  3. File Storage: Cache parsed markdown in files for performance:

    $path = storage_path("cache/markdown/{$key}.html");
    if (!file_exists($path)) {
        file_put_contents($path, $converter->convert($markdown));
    }
    return file_get_contents($path);
    

Pro Tips

  1. Combine with HTML Purifier: For additional security when allowing raw HTML:

    use HTMLPurifier;
    
    $purifier = new HTMLPurifier();
    $safeHtml = $purifier->purify($converter->convert($markdown));
    
  2. Use CommonMarkCoreExtension: Explicitly include core extensions for clarity:

    $environment->addExtension(new CommonMarkCoreExtension());
    
  3. Benchmark Extensions: Profile extensions to identify performance bottlenecks:

    $start = microtime(true);
    $converter->convert($markdown
    
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