NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
Packagist · #88 most downloaded on Packagist
Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and GitHub-Flavored Markdown (GFM)
Last release 16 days ago
21 Sep 2026
Release timing varies
gaps range from 8 days to 4 months
Nearly every release is documented
notes for 60 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
12 years old
147 releases · first in 2014
Fixed incorrect error level for deprecation notices
Fixed HeadingPermalinkProcessor skipping text contents from certain nodes
One column per quarter.
Added new MarkdownConverter class for creating converters with custom environments; this replaces the previously-deprecated Converter class
Please see https://commonmark.thephpleague.com/1.6/upgrading/ for important information about this release and the upcoming 2.0.0 version.
Added forward-compatibility for configuration options which will be changing in 2.0 :
commonmark/enable_em (currently enable_em in 1.x)
commonmark/enable_strong (currently enable_strong in 1.x)
commonmark/use_asterisk (currently use_asterisk in 1.x)
commonmark/use_underscore (currently use_underscore in 1.x)
commonmark/unordered_list_markers (currently unordered_list_markers in 1.x)
mentions//prefix (currently mentions//symbol in 1.x)
mentions//pattern (currently mentions//regex in 1.x)
max_nesting_level (currently supports int and float values in 1.x; will only support int in 2.0)
Added new MarkdownConverter class for creating converters with custom environments; this replaces the previously-deprecated Converter class
Added new RegexHelper::matchFirst() method
Added new Configuration::exists() method
Deprecated the configuration options shown above
Deprecated the ability to pass a custom Environment into the constructors of CommonMarkConverter and GithubFlavoredMarkdownConverter ; use MarkdownConverter instead
Deprecated ConfigurableEnvironmentInterface::setConfig() ; use mergeConfig() instead
Deprecated calling ConfigurableEnvironmentInterface::mergeConfig() without any parameters
Deprecated calling Configuration::get() and EnvironmentInterface::getConfig() without any parameters
Deprecated calling Configuration::set() without the second $value parameter
Deprecated RegexHelper::matchAll() ; use RegexHelper::matchFirst() instead
Deprecated extending the ArrayCollection class; will be marked final in 2.0
Fixed Table of Contents not rendering heading inlines properly (#587, #588)
Fixed Table of Contents not rendering heading inlines properly (#587, #588)
Fixed parsing of tables within list items (#590)
Fixed mentions not being parsed when appearing after non-word characters
Blocks added outside of the parsing context now have their start/end line numbers defaulted to 0 to avoid type errors
Fixed replacement blocks not inheriting the start line number of the container they’re replacing (#579)
Fixed Table of Contents blocks not having correct start/end line numbers (#579)
Bumped CommonMark spec compliance to 0.28.2
Fixed textarea elements not being treated as a type 1 HTML block (like script , style , or pre )
Fixed autolink processor not handling other unmatched trailing parentheses
Fixed footnote ID configuration not taking effect (#524, #530)
Fixed footnote ID configuration not taking effect (#524, #530)
Fixed heading permalink slugs not being unique (#531, #534)
Fixed regression of multi-byte inline parser characters not being matched
Significantly improved performance of the inline parser regex
Fixed UTF-8 encoding not being checked in the UrlEncoder utility (#509) or the Cursor
Added a new heading_permalink/symbol configuration option to replace the now deprecated heading_permalink/inner_contents configuration option
Added new AttributesExtension based on https://github.com/webuni/commonmark-attributes-extension (#474)
Added new FootnoteExtension based on https://github.com/rezozero/commonmark-ext-footnotes (#474)
Added new MentionExtension to replace InlineMentionParser with more flexibility and customization
Added the ability to render TableOfContents nodes anywhere in a document (given by a placeholder)
Added the ability to properly clone Node objects
Added options to customize the value of rel attributes set via the ExternalLink extension (#476)
Added a new heading_permalink/slug_normalizer configuration option to allow custom slug generation (#460)
Added a new heading_permalink/symbol configuration option to replace the now deprecated heading_permalink/inner_contents configuration option (#505)
Added SlugNormalizer and TextNormalizer classes to make normalization reusable by extensions (#485)
Added new classes:
TableOfContentsGenerator
TableOfContentsGeneratorInterface
TableOfContentsPlaceholder
TableOfContentsPlaceholderParser
TableOfContentsPlaceholderRenderer
“Moved” the TableOfContents class into a new Node sub-namespace (with backward-compatibility)
Reference labels are now generated and stored in lower-case instead of upper-case
Reference labels are no longer normalized inside the Reference , only the ReferenceMap
Deprecated the CommonMarkConverter::VERSION constant (#496)
Deprecated League\CommonMark\Extension\Autolink\InlineMentionParser (use League\CommonMark\Extension\Mention\MentionParser instead)
Deprecated everything under League\CommonMark\Extension\HeadingPermalink\Slug (use the classes under League\CommonMark\Normalizer instead)
Deprecated League\CommonMark\Extension\TableOfContents\TableOfContents (use the one in the new Node sub-namespace instead)
Deprecated the STYLE_ and NORMALIZE_ constants in TableOfContentsBuilder (use the ones in TableOfContentsGenerator instead)
Deprecated the \League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkRenderer::DEFAULT_INNER_CONTENTS constant (#505)
Deprecated the heading_permalink/inner_contents configuration option in the HeadingPermalink extension (use the new heading_permalink/symbol configuration option instead) (#505)
Fixed certain Unicode letters, numbers, and marks not being preserved when generating URL slugs
Fixed inline code blocks not be included within heading permalinks
Fixed BC break caused by ConverterInterface alias not being used by some DI containers
The Converter class has been deprecated; use CommonMarkConverter instead (#438, #439)
Added new Heading Permalink extension (#420)
Added new Table of Contents extension (#441)
Added new MarkdownConverterInterface as a long-term replacement for ConverterInterface (#439)
Added new DocumentPreParsedEvent event (#427, #359, #399)
Added new ListBlock::TYPE_BULLET constant as a replacement for ListBlock::TYPE_UNORDERED
Added new MarkdownInput class and MarkdownInputInterface to handle pre-parsing and allow listeners to replace Markdown contents
Block & inline renderers will now render child classes automatically (#222, #209)
The ListBlock constants now use fully-lowercased values instead of titlecased values
Significantly improved typing
Fixed loose comparison when checking for table alignment
Fixed StaggeredDelimiterProcessor returning from a void function
The Converter class has been deprecated; use CommonMarkConverter instead (#438, #439)
The ConverterInterface has been deprecated; use MarkdownConverterInterface instead (#438, #439)
The bin/commonmark script has been deprecated
The following methods of ArrayCollection have been deprecated:
add()
set()
get()
remove()
isEmpty()
contains()
indexOf()
containsKey()
replaceWith()
removeGaps()
The ListBlock::TYPE_UNORDERED constant has been deprecated, use ListBlock::TYPE_BULLET instead
Fixed configuration/environment not being injected into event listeners when adding them via [$instance, 'method'] callable syntax
Fixed event listeners not having the environment or configuration injected if they implemented the EnvironmentAwareInterface or ConfigurationAwareInte
Optimized URL normalization in cases where URLs don’t contain special characters (#417, #418)
Fixed return types of Environment::createCommonMarkEnvironment() and Environment::createGFMEnvironment()
ℹ️ Do you use league/commonmark-ext* packages? Those features are now included directly in this library! See #409 for details on making the switch.
ℹ️ Do you use league/commonmark-ext* packages? Those features are now included directly in this library! See #409 for details on making the switch.
Added (optional) full GFM support! 🎉🎉🎉 (#409)
Added check to ensure Markdown input is valid UTF-8 (#401, #405)
Added new unordered_list_markers configuration option (#408, #411)
This release contains the same changes as 1.1.3:
This release contains the same changes as 1.1.3:
Introduced several micro-optimizations, reducing the parse time by 8%
Removed URL decoding step before encoding (more performant and better matches the JS library)
Removed URL decoding step before encoding (more performant and better matches the JS library)
Removed redundant token from HTML tag regex
### Fixed - Fixed link parsing edge case
Fixed URL normalization not handling non-UTF-8 sequences properly (#395, #396)
Fixed handling of link destinations with unbalanced unescaped parens
Fixed handling of link destinations with unbalanced unescaped parens
Fixed adding delimiters to stack which can neither open nor close a run
Deprecated the Html5Entities class - use Html5EntityDecoder instead
Improved performance by 10% (#389)
Made entity decoding less memory-intensive (#386, #387)
No code changes have been introduced since 1.0.0-rc1
First stable release! 🎉
No code changes have been introduced since 1.0.0-rc1
Extracted a ReferenceMapInterface from the ReferenceMap class
Extracted a ReferenceMapInterface from the ReferenceMap class
Added optional ReferenceMapInterface parameter to the Document constructor
Replaced all references to ReferenceMap with ReferenceMapInterface
ReferenceMap::addReference() no longer returns $this
Added event dispatcher functionality (#359, #372)
Made the Delimiter class final and extracted a new DelimiterInterface
Made the Delimiter class final and extracted a new DelimiterInterface
Modified most external usages to use this new interface
Renamed three Delimiter methods:
getOrigDelims() renamed to getOriginalLength()
getNumDelims() renamed to getLength()
setNumDelims() renamed to setLength()
Made additional classes final:
DelimiterStack
ReferenceMap
ReferenceParser
Moved ReferenceParser into the Reference sub-namespace
Removed unused Delimiter methods:
setCanOpen()
setCanClose()
setChar()
setIndex()
setInlineNode()
Removed fluent interface from Delimiter (setter methods now have no return values)
Removed all deprecated functionality:
This beta release fixes a couple of items that were not addressed in the previous beta.
DelimiterProcessorInterface::process() will accept any type of AbstractStringContainer now, not just Text nodes
The Delimiter constructor, getInlineNode() , and setInlineNode() no longer accept generic Node elements - only AbstractStringContainer s
Removed all deprecated functionality:
The safe option (use html_input and allow_unsafe_links options instead)
All deprecated RegexHelper constants
DocParser::getEnvironment() (you should obtain it some other way)
AbstractInlineContainer (use AbstractInline instead and make isContainer() return true )
Un-deprecated the CommonmarkConverter::VERSION constant
See the upgrading guide for additional information.
Added proper support for delimiters, including custom delimiters
addDelimiterProcessor() added to ConfigurableEnvironmentInterface and Environment
Basic delimiters no longer need custom parsers - they’ll be parsed automatically
Added new methods:
AdjacentTextMerger::mergeTextNodesBetweenExclusive()
CommonMarkConveter::getEnvironment()
Configuration::set()
Extracted some new interfaces from base classes:
DocParserInterface created from DocParser
ConfigurationInterface created from Configuration
ReferenceInterface created from Reference
Renamed several methods of the Configuration class:
getConfig() renamed to get()
mergeConfig() renamed to merge()
setConfig() renamed to replace()
Changed ConfigurationAwareInterface::setConfiguration() to accept the new ConfigurationInterface instead of the concrete class
Renamed the AdjoiningTextCollapser class to AdjacentTextMerger
Replaced its collapseTextNodes() method with the new mergeChildNodes() method
Made several classes final :
Configuration
DocParser
HtmlRenderer
InlineParserEngine
NodeWalker
Reference
All of the block/inline parsers and renderers
Reduced visibility of several internal methods to private :
DelimiterStack::findEarliest()
All protected methods in InlineParserEngine
Marked some classes and methods as @internal
ElementRendererInterface now requires a public renderInline() method; added this to HtmlRenderer
Changed InlineParserEngine::parse() to require an AbstractStringContainerBlock instead of the generic Node class
Un-deprecated the CommonmarkConverter::VERSION constant
The Converter constructor now requires an instance of DocParserInterface instead of the concrete DocParser
Changed Emphasis , Strong , and AbstractWebResource to directly extend AbstractInline instead of the (now-deprecated) intermediary AbstractInlineContainer class
Fixed null errors when inserting sibling Node s without parents
Fixed NodeWalkerEvent not requiring a Node via its constructor
Fixed Reference::normalizeReference() improperly converting to uppercase instead of performing proper Unicode case-folding
Fixed strong emphasis delimiters not being preserved when enable_strong is set to false (it now works identically to enable_em )
Deprecated DocParser::getEnvironment() (you should obtain it some other way)
Deprecated AbstractInlineContainer (use AbstractInline instead and make isContainer() return true )
Removed inline processor functionality now that we have proper delimiter support:
Removed addInlineProcessor() from ConfigurableEnvironmentInterface and Environment
Removed getInlineProcessors() from EnvironmentInterface and Environment
Removed EmphasisProcessor
Removed InlineProcessorInterface
Removed EmphasisParser now that we have proper delimiter support
Removed support for non-UTF-8-compatible encodings
Removed getEncoding() from ContextInterface
Removed getEncoding() , setEncoding() , and $encoding from Context
Removed getEncoding() and the second $encoding constructor param from Cursor
Removed now-unused methods
Removed DelimiterStack::getTop() (no replacement)
Removed DelimiterStack::iterateByCharacters() (use the new processDelimiters() method instead)
Removed the protected DelimiterStack::findMatchingOpener() method
Nothing published for this version
Fixed bug where default values for nested configuration paths were inadvertently cast to strings
0.19.1 is an immediate follow-up to 0.19.0 which fixes issues with extensions that register other extensions.
0.19.1 is an immediate follow-up to 0.19.0 which fixes issues with extensions that register other extensions.
(While this technically introduces a BC-break, it’s allowed under SemVer’s rules for 0.x releases and is necessary for 0.19.x code to work as expected.)
Removed previously-deprecated functionality:
The 50th release of league/commonmark is here! :tada:
The Environment and extension framework underwent some major changes in this release. Be sure to read the upgrade notes if you maintain any community extensions or have written custom functionality on top of this library.
The priority of parsers, processors, and renderers can now be set when add() ing them; you no longer need to rely on the order in which they are added
Added support for trying multiple parsers per block/inline
Extracted two new base interfaces from Environment :
EnvironmentInterface
ConfigurableEnvironmentInterface
Extracted a new AbstractStringContainerBlock base class and corresponding StringContainerInterface from AbstractBlock
Added Cursor::getEncoding() method
Added .phpstorm.meta.php file for better IDE code completion
Made some minor optimizations here and there
Pretty much everything now has parameter and return types (#346)
Attributes passed to HtmlElement will now be escaped by default
Environment is now a final class
Environment::getBlockRendererForClass() was replaced with Environment::getBlockRenderersForClass() (note the added s )
Environment::getInlineRendererForClass() was replaced with Environment::getInlineRenderersForClass() (note the added s )
The Environment::get____() methods now return an iterator instead of an array
Context::addBlock() no longer returns the same block instance you passed into the method, as this served no useful purpose
RegexHelper::isEscapable() no longer accepts null values
Node::replaceChildren() now accepts any type of iterable , not just array s
Some block elements now extend AbstractStringContainerBlock instead of AbstractBlock
InlineContainerInterface now extends the new StringContainerInterface
The handleRemainingContents() method (formerly on AbstractBlock , now on AbstractStringContainerBlock ) is now an `abstract method
The InlineParserContext constructor now requires an AbstractStringContainerBlock instead of an AbstractBlock
Removed support for PHP 5.6 and 7.0 (#346)
Removed support for add() ing parsers with just the target block/inline class name - you need to include the full namespace now
Removed the following unused methods from Environment :
getInlineParser($name)
getInlineParsers()
createInlineParserEngine()
Removed the unused getName() methods:
AbstractBlockParser::getName()
AbstractInlineParser::getName()
BlockParserInterface::getName()
InlinerParserInterface::getName()
Removed the now-useless classes:
AbstractBlockParser
AbstractInlinerParser
InlineContainer
Removed the AbstractBlock::acceptsLines() method
Removed the now-useless constructor from AbstractBlock
Removed previously-deprecated functionality:
InlineContainer class
RegexHelper::$instance
RegexHelper::getInstance()
RegexHelper::getPartialRegex()
RegexHelper::getHtmlTagRegex()
RegexHelper::getLinkTitleRegex()
RegexHelper::getLinkDestinationBracesRegex()
RegexHelper::getThematicBreakRegex()
Removed the second $preserveEntities parameter from Xml:escape()
Fixed the adjoining Text collapser not handling the full tree (thephpleague/commonmark-ext-autolink#10)
Modified how URL normalization decodes certain characters in order to align with the JS library’s output
Modified how URL normalization decodes certain characters in order to align with the JS library’s output
Disallowed unescaped ( in parenthesized link title
Fix XSS vulnerability caused by improper preservation of entities when rendering
This is a security update release.
Deprecated the CommonmarkConverter::VERSION constant for removal in 1.0.0
This release contains an important security update for CVE-2018-20583 .
This release contains an important security update for CVE-2018-20583 .
No breaking changes were introduced, but we did add a new interface: ConverterInterface . Consider depending on this interface in your code instead of…
No breaking changes were introduced, but we did add a new interface: ConverterInterface . Consider depending on this interface in your code instead of the concrete implementation. (See #330)
Added ConverterInterface to Converter and CommonMarkConverter (#330)
Added ListItem::getListData() method (#329)
Links with target="_blank" will also get rel="noopener noreferrer" by default (#331)
Implemented several performance optimizations (#324)
Fixed incorrect version constant value (again)
Fixed incorrect version constant value (again)
Fixed release checklist to prevent the above from happening
Fixed incorrect dates in CHANGELOG
Added ListBlock::setTight() method
Fixed incorrect version constant value
Added new RegexHelper::isEscapable() method
Added a new constant containing the current version: CommonMarkConverter::VERSION
This release contains several breaking changes and a minimum PHP version bump - see UPGRADE.md for more details.
This release contains several breaking changes and a minimum PHP version bump - see UPGRADE.md for more details.
Added new max_nesting_level setting (#243)
Added minor performance optimizations to Cursor
Minimum PHP version is now 5.6.5.
All full and partial regular expressions in RegexHelper are now defined as constants instead of being built on-the-fly.
Cursor::saveState() now returns an array instead of a CursorState object.
Cursor::restoreState() now accepts an array parameter instead of a CursorState object.
Saving/restoring the Cursor state no longer tracks things that don’t change (like the text content).
RegexHelper is now final .
References to InlineContainer changed to new InlineContainerInterface interface.
MiscExtension::addInlineParser() and MiscExtension::addBlockRenderer() now return $this instead of nothing.
RegexHelper::getInstance() and all instance (non-static) methods have been deprecated.
The InlineContainer interface has been deprecated. Use InlineContainerInterface instead.
Removed support for PHP 5.4 and 5.5.
Removed CursorState class
Removed all previous deprecations:
Cursor::getFirstNonSpacePosition()
Cursor::getFirstNonSpaceCharacter()
Cursor::advanceWhileMatches()
Cursor::advanceToFirstNonSpace()
ElementRendererInterface::escape()
HtmlRenderer::escape()
RegexHelper::REGEX_UNICODE_WHITESPACE
RegexHelper::getLinkDestinationRegex()
This release contains breaking changes, several performance improvements, and two deprecations:
This release contains breaking changes, several performance improvements, and two deprecations:
Environment::getInlineParsersForCharacter() now returns an empty array (instead of null ) when no matching parsers are found
Three utility classes are now marked final :
Html5Entities
LinkParserHelper
UrlEncoder
The following methods were deprecated and are scheduled for removal in 0.17.0 or 1.0.0 (whichever comes first). See UPGRADE.md for more information.
Cursor::advanceWhileMatches() deprecated; use Cursor::match() instead.
HtmlRenderer::escape() deprecated; use Xml::escape() instead.
Improved performance of Cursor::advanceBy() (for a 16% performance boost!) :tada:
Fixed URI normalization not properly encoding/decoding special characters in certain cases
This release bumps spec compliance to 0.28 without breaking changes to the API.
This release bumps spec compliance to 0.28 without breaking changes to the API.
Bumped CommonMark spec target to 0.28
Changed internal implementation of LinkParserHelper::parseLinkDestination() to allow nested parens
Changed precedence of strong/emph when both nestings are possible (rule 14)
Allow tabs before and after ATX closing header
Fixed HTML type 6 block regex matching against <pre> (it shouldn’t) and not matching <iframe> (it should)
Fixed reference parser incorrectly handling escaped ] characters
Fixed “multiple of 3” delimiter run calculations
An unused constant and static method were deprecated and will be removed in a future release. See for more information.
Deprecated RegexHelper::REGEX_UNICODE_WHITESPACE (no longer used)
Deprecated RegexHelper::getLinkDestinationRegex() (no longer used)
advanceToNextNonSpaceOrNewline() - Identical replacement for the (now-deprecated) advanceToFirstNonSpace() method
Added new methods to Cursor (#280):
advanceToNextNonSpaceOrNewline() - Identical replacement for the (now-deprecated) advanceToFirstNonSpace() method
advanceToNextNonSpaceOrTab() - Similar replacement for advanceToFirstNonSpace() but with proper tab handling
getNextNonSpaceCharacter() - Identical replacement for the (now-deprecated) getFirstNonSpaceCharacter() method
getNextNonSpacePosition() - Identical replacement for the (now-deprecated) getFirstNonSpacePosition() method
Added new method to CursorState (#280):
getNextNonSpaceCache() - Identical replacement for the (now-deprecated) getFirstNonSpaceCache() method
All deprecations listed here will be removed in a future 0.x release. See UPGRADE.md for instructions on preparing your code for the eventual removal of these methods.
Deprecated Cursor::advanceToFirstNonSpace() (#280)
Use advanceToNextNonSpaceOrTab() or advanceToNextNonSpaceOrNewline() instead, depending on your requirements
Deprecated Cursor::getFirstNonSpaceCharacter() (#280)
Use Cursor::getNextNonSpaceCharacter() instead
Deprecated Cursor::getFirstNonSpacePosition() (#280)
Use Cursor::getNextNonSpacePosition() instead
Deprecated CursorState::getFirstNonSpaceCache() (#280)
Use CursorState::getNextNonSpaceCache() instead
Allow inline parsers matching regex delimiter to be created (#271, #272)
Bumped spec target version to 0.27
Bumped spec target version to 0.27 (#268)
H2-H6 elements are now parsed as HTML block elements instead of HTML inlines
Fixed incomplete punctuation regex
Fixed shortcut links not being allowed before a (
Fixed distinction between Unicode whitespace and regular whitespace
Fixed setext heading underlines not allowing trailing tabs
Deprecated DelimiterStack::findFirstMatchingOpener() - use findMatchingOpener() instead
Added preliminary support for PHP 7.1 (#259)
Added more regression tests (#258, #260)
Bumped spec target version to 0.26 (#260)
The CursorState constructor requires an additional parameter (#258)
Ordered lists cannot interupt a paragraph unless they start with 1 (#260)
Blank list items cannot interupt a paragraph (#260)
Fixed tabs in ATX headers and thematic breaks (#260)
Fixed issue where cursor state was not being restored properly (#258, #260)
This fixed the lists-with-tabs regression reported in #258
Removed an unnecessary check in Cursor::advanceBy() (#260)
Removed the two-blanks-break-out-of-lists feature (#260)
The safe option is deprecated and replaced by 2 new options (#253, #255):
The safe option is deprecated and replaced by 2 new options (#253, #255):
html_input ( strip , allow or escape ): how to handle untrusted HTML input (the default is strip for BC reasons)
allow_unsafe_links ( true or false ): whether to allow risky image URLs and links (the default is true for BC reasons)
Your coding agent can read these notes before it upgrades. Set up the MCP server →