league/commonmark
| Language | PHP (7.4+ / 8.x) |
|---|---|
| License | BSD-3-Clause |
| Repository | github.com/thephpleague/commonmark |
| Documentation | commonmark.thephpleague.com |
| Depends on | ext-mbstring, league/config, psr/event-dispatcher, symfony/deprecation-contracts, symfony/polyfill-php80; symfony/yaml for front matter |
| Read / write | parses CommonMark + GFM + extensions; renders HTML |
league/commonmark parses Markdown into an AST of block and inline nodes and renders it to HTML. It passes the CommonMark and GFM spec tests. CommonMarkConverter gives plain CommonMark, GithubFlavoredMarkdownConverter adds tables, task lists, strikethrough, autolinks and the disallowed-raw-HTML filter. For anything else you build an Environment, add extensions and use MarkdownConverter.
Bundled extensions include attributes, autolink, default attributes, description lists, disallowed raw HTML, embeds, external links, footnotes, front matter, heading permalinks, inlines-only mode, mentions, smart punctuation, strikethrough, tables, table of contents and task lists. Configuration such as html_input and allow_unsafe_links controls security.
Installation#
composer require league/commonmark
Basic usage: convert Markdown to HTML#
<?php
require 'vendor/autoload.php';
use League\CommonMark\GithubFlavoredMarkdownConverter;
$converter = new GithubFlavoredMarkdownConverter([
'html_input' => 'strip', // or 'escape'; 'allow' only for trusted input
'allow_unsafe_links' => false, // drop javascript:, vbscript:, file: and data: links
]);
$markdown = file_get_contents('README.md');
echo $converter->convert($markdown); // RenderedContent, castable to string
Use CommonMarkConverter for plain CommonMark without GFM.
How to add footnotes, heading permalinks and a table of contents#
use League\CommonMark\Environment\Environment;
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
use League\CommonMark\Extension\Footnote\FootnoteExtension;
use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension;
use League\CommonMark\Extension\TableOfContents\TableOfContentsExtension;
use League\CommonMark\MarkdownConverter;
$environment = new Environment([
'html_input' => 'escape',
'table_of_contents' => ['position' => 'top'],
]);
$environment->addExtension(new CommonMarkCoreExtension());
$environment->addExtension(new GithubFlavoredMarkdownExtension());
$environment->addExtension(new FootnoteExtension());
$environment->addExtension(new HeadingPermalinkExtension());
$environment->addExtension(new TableOfContentsExtension()); // needs heading permalinks
$converter = new MarkdownConverter($environment);
echo $converter->convert($markdown);
How to read YAML front matter#
use League\CommonMark\Extension\FrontMatter\FrontMatterExtension;
use League\CommonMark\Extension\FrontMatter\Output\RenderedContentWithFrontMatter;
$environment = new Environment();
$environment->addExtension(new CommonMarkCoreExtension());
$environment->addExtension(new FrontMatterExtension()); // composer require symfony/yaml
$converter = new MarkdownConverter($environment);
$result = $converter->convert("---\ntitle: Release notes\n---\n\n# Notes\n");
if ($result instanceof RenderedContentWithFrontMatter) {
$meta = $result->getFrontMatter(); // ['title' => 'Release notes']
}
echo $result->getContent();
How to list all links (walk the AST)#
use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
use League\CommonMark\Parser\MarkdownParser;
$environment = new Environment();
$environment->addExtension(new CommonMarkCoreExtension());
$document = (new MarkdownParser($environment))->parse($markdown);
$walker = $document->walker();
while ($event = $walker->next()) {
$node = $event->getNode();
if ($event->isEntering() && $node instanceof Link) {
echo $node->getUrl(), "\n";
}
}
You can modify nodes here (for example rewrite URLs) and then render the document with HtmlRenderer.
Tips#
'max_nesting_level' => 100limits deeply nested input, which protects against slow pathological documents.ExternalLinkExtensionaddsrel="noopener nofollow"andtarget="_blank"to links outside your domain.- Reuse the converter object; building the environment is the expensive part.