PackageTrack
Sign in Get early access

league/commonmark

Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and GitHub-Flavored Markdown (GFM)

2.10.0 462M downloads/mo #94 most downloaded on composer thephpleague/commonmark

What this package is like to depend on

Last release 12 days ago

11 Aug 2026

Release timing varies

gaps range from 8 days to 4 months

Nearly every release is documented

notes for 124 of 134 stable releases

Nothing withdrawn

no release was ever pulled

12 years old

144 releases · first in 2014

8 releases in the last 12 months

see the full history below

Release timeline

144 releases · Sep 2014 to Aug 2026
2015 2017 2019 2021 2023 2025
Release Pre-release

Releases

latest 60 of 144
  1. 2.10.0 11 Aug 2026
    Release notes

    This is a security release to address a denial of service vulnerability in the AttributesExtension.

    Added

    • Added a new table_of_contents/max_placeholder_entries option to limit how many table of contents entries a document may render across all of its placeholders (#1134)
    • Added Cursor::matchInPlace(), which matches a regular expression at the cursor's position within the line using PCRE's native offset semantics instead of copying the remainder (#1145)
      • \G anchors at the cursor, ^ anchors at the start of the line, and lookbehinds and \b see the characters actually preceding the cursor; this keeps scanning loops linear and enables left-context assertions that match() cannot express
    • Added RegexHelper::PARTIAL_LINK_TITLE_UNANCHORED and RegexHelper::PARTIAL_LINK_DESTINATION_BRACES, unanchored fragments so each call site can supply its own anchor
    • Added a default_attributes configuration format which pairs the node attribute map with a new strict_callables option: ['default_attributes' => ['attributes' => [...], 'strict_callables' => true]]. With strict_callables enabled, only closures and invokable objects are treated as callbacks, so strings and arrays are always used as literal attribute values. Callbacks written as string or array callables can be wrapped with Closure::fromCallable(). The original format - passing the node map directly - is still accepted, and defaults strict_callables to false.
    • Added a new slug_normalizer/reserved option which treats the given slugs as already-used, so colliding headings receive an incremental numeric suffix just like duplicate headings do (#1080)

    Changed

    • Changed the TableOfContents extension to render the table of contents once and share it across all placeholders instead of cloning it into each one (#1134)
      • A custom renderer registered for the TableOfContents node is no longer called once per placeholder, so it must return the same markup each time it is called for a given document (#1134)
      • The first placeholder receives the table of contents itself, so a document still contains a TableOfContents node for listeners which locate and reposition it (#1143)
    • $environment->getConfiguration()->get('default_attributes') now returns the normalized structure with attributes and strict_callables keys instead of the node map; read default_attributes/attributes to get the map. Configuration written in either format continues to work unchanged.

    Deprecated

    • Deprecated RegexHelper::PARTIAL_LINK_TITLE and RegexHelper::REGEX_LINK_DESTINATION_BRACES; use the unanchored variants with an explicit anchor instead
    • Deprecated the default_attributes strict_callables option, which will be removed in 3.0 when only closures and invokable objects will ever be treated as callbacks.

    Fixed

    • Fixed default_attributes values which happen to match the name of a PHP function - such as 'class' => 'link', 'header', 'key', 'range', or 'current' - being invoked as callbacks, producing errors like link() expects exactly 2 arguments, 1 given. Enable strict_callables to treat strings and arrays as literal attribute values (#1123)
    • Fixed the DefaultAttributesExtension re-testing every configured value with is_callable() once per matching node, which asked the autoloader whether the first element of each array value named a real class every single time
    • Fixed a default_attributes value which PHP treats as callable reporting its failure from inside whichever function it collided with; the error now names the attribute and node class responsible, and keeps the original error as its previous exception
    • Fixed custom UniqueSlugNormalizerInterface implementations being wrapped by the built-in UniqueSlugNormalizer and never receiving the documented clearHistory() calls, which caused slug history to leak across documents when slug_normalizer/unique was set to 'document' (#1080)
      • Custom implementations are now trusted to enforce uniqueness themselves, per the interface contract; the extra deduplication layer the wrapper used to provide is no longer applied on top of them
    • Fixed the AttributesExtension re-merging and re-filtering everything a node had already collected each time another attribute node was applied to it, causing long runs of distinctly-named attributes to be resolved in quadratic time, which could be abused to cause a denial of service - this completes the fix for GHSA-jjv6-8j6v-6j52, which covered only the class attribute (GHSA-8rr7-cvq3-gmfh)
    • Fixed the AttributesExtension re-merging everything an attribute block had already collected on each of its continuation lines, causing long runs of distinctly-named attributes on consecutive lines to be resolved in quadratic time, which could be abused to cause a denial of service (GHSA-8rr7-cvq3-gmfh)
    Open source →
    Release notes

    This is a security release to address a denial of service vulnerability in the AttributesExtension.

    Added

    • Added a new table_of_contents/max_placeholder_entries option to limit how many table of contents entries a document may render across all of its placeholders (#1134)
    • Added Cursor::matchInPlace(), which matches a regular expression at the cursor's position within the line using PCRE's native offset semantics instead of copying the remainder (#1145)
      • \G anchors at the cursor, ^ anchors at the start of the line, and lookbehinds and \b see the characters actually preceding the cursor; this keeps scanning loops linear and enables left-context assertions that match() cannot express
    • Added RegexHelper::PARTIAL_LINK_TITLE_UNANCHORED and RegexHelper::PARTIAL_LINK_DESTINATION_BRACES, unanchored fragments so each call site can supply its own anchor
    • Added a default_attributes configuration format which pairs the node attribute map with a new strict_callables option: ['default_attributes' => ['attributes' => [...], 'strict_callables' => true]]. With strict_callables enabled, only closures and invokable objects are treated as callbacks, so strings and arrays are always used as literal attribute values. Callbacks written as string or array callables can be wrapped with Closure::fromCallable(). The original format - passing the node map directly - is still accepted, and defaults strict_callables to false.
    • Added a new slug_normalizer/reserved option which treats the given slugs as already-used, so colliding headings receive an incremental numeric suffix just like duplicate headings do (#1080)

    Changed

    • Changed the TableOfContents extension to render the table of contents once and share it across all placeholders instead of cloning it into each one (#1134)
      • A custom renderer registered for the TableOfContents node is no longer called once per placeholder, so it must return the same markup each time it is called for a given document (#1134)
      • The first placeholder receives the table of contents itself, so a document still contains a TableOfContents node for listeners which locate and reposition it (#1143)
    • $environment->getConfiguration()->get('default_attributes') now returns the normalized structure with attributes and strict_callables keys instead of the node map; read default_attributes/attributes to get the map. Configuration written in either format continues to work unchanged.

    Deprecated

    • Deprecated RegexHelper::PARTIAL_LINK_TITLE and RegexHelper::REGEX_LINK_DESTINATION_BRACES; use the unanchored variants with an explicit anchor instead
    • Deprecated the default_attributes strict_callables option, which will be removed in 3.0 when only closures and invokable objects will ever be treated as callbacks.

    Fixed

    • Fixed default_attributes values which happen to match the name of a PHP function - such as 'class' => 'link', 'header', 'key', 'range', or 'current' - being invoked as callbacks, producing errors like link() expects exactly 2 arguments, 1 given. Enable strict_callables to treat strings and arrays as literal attribute values (#1123)
    • Fixed the DefaultAttributesExtension re-testing every configured value with is_callable() once per matching node, which asked the autoloader whether the first element of each array value named a real class every single time
    • Fixed a default_attributes value which PHP treats as callable reporting its failure from inside whichever function it collided with; the error now names the attribute and node class responsible, and keeps the original error as its previous exception
    • Fixed custom UniqueSlugNormalizerInterface implementations being wrapped by the built-in UniqueSlugNormalizer and never receiving the documented clearHistory() calls, which caused slug history to leak across documents when slug_normalizer/unique was set to 'document' (#1080)
      • Custom implementations are now trusted to enforce uniqueness themselves, per the interface contract; the extra deduplication layer the wrapper used to provide is no longer applied on top of them
    • Fixed the AttributesExtension re-merging and re-filtering everything a node had already collected each time another attribute node was applied to it, causing long runs of distinctly-named attributes to be resolved in quadratic time, which could be abused to cause a denial of service - this completes the fix for GHSA-jjv6-8j6v-6j52, which covered only the class attribute (GHSA-8rr7-cvq3-gmfh)
    • Fixed the AttributesExtension re-merging everything an attribute block had already collected on each of its continuation lines, causing long runs of distinctly-named attributes on consecutive lines to be resolved in quadratic time, which could be abused to cause a denial of service (GHSA-8rr7-cvq3-gmfh)
    Open source →
    Release notes

    This is a security release to address a denial of service vulnerability in the AttributesExtension .

    Added

    • Added a new table_of_contents/max_placeholder_entries option to limit how many table of contents entries a document may render across all of its placeholders (#1134)

    • Added Cursor::matchInPlace() , which matches a regular expression at the cursor’s position within the line using PCRE’s native offset semantics instead of copying the remainder (#1145)

    • \G anchors at the cursor, ^ anchors at the start of the line, and lookbehinds and \b see the characters actually preceding the cursor; this keeps scanning loops linear and enables left-context assertions that match() cannot express

    • Added RegexHelper::PARTIAL_LINK_TITLE_UNANCHORED and RegexHelper::PARTIAL_LINK_DESTINATION_BRACES , unanchored fragments so each call site can supply its own anchor

    • Added a default_attributes configuration format which pairs the node attribute map with a new strict_callables option: ['default_attributes' => ['attributes' => [...], 'strict_callables' => true]] . With strict_callables enabled, only closures and invokable objects are treated as callbacks, so strings and arrays are always used as literal attribute values. Callbacks written as string or array callables can be wrapped with Closure::fromCallable() . The original format - passing the node map directly - is still accepted, and defaults strict_callables to false .

    • Added a new slug_normalizer/reserved option which treats the given slugs as already-used, so colliding headings receive an incremental numeric suffix just like duplicate headings do (#1080)

    Changed

    • Changed the TableOfContents extension to render the table of contents once and share it across all placeholders instead of cloning it into each one (#1134)

    • A custom renderer registered for the TableOfContents node is no longer called once per placeholder, so it must return the same markup each time it is called for a given document (#1134)

    • The first placeholder receives the table of contents itself, so a document still contains a TableOfContents node for listeners which locate and reposition it (#1143)

    • $environment->getConfiguration()->get('default_attributes') now returns the normalized structure with attributes and strict_callables keys instead of the node map; read default_attributes/attributes to get the map. Configuration written in either format continues to work unchanged.

    Deprecated

    • Deprecated RegexHelper::PARTIAL_LINK_TITLE and RegexHelper::REGEX_LINK_DESTINATION_BRACES ; use the unanchored variants with an explicit anchor instead

    • Deprecated the default_attributes strict_callables option, which will be removed in 3.0 when only closures and invokable objects will ever be treated as callbacks.

    Fixed

    • Fixed default_attributes values which happen to match the name of a PHP function - such as 'class' => 'link' , 'header' , 'key' , 'range' , or 'current' - being invoked as callbacks, producing errors like link() expects exactly 2 arguments, 1 given . Enable strict_callables to treat strings and arrays as literal attribute values (#1123)

    • Fixed the DefaultAttributesExtension re-testing every configured value with is_callable() once per matching node, which asked the autoloader whether the first element of each array value named a real class every single time

    • Fixed a default_attributes value which PHP treats as callable reporting its failure from inside whichever function it collided with; the error now names the attribute and node class responsible, and keeps the original error as its previous exception

    • Fixed custom UniqueSlugNormalizerInterface implementations being wrapped by the built-in UniqueSlugNormalizer and never receiving the documented clearHistory() calls, which caused slug history to leak across documents when slug_normalizer/unique was set to 'document' (#1080)

    • Custom implementations are now trusted to enforce uniqueness themselves, per the interface contract; the extra deduplication layer the wrapper used to provide is no longer applied on top of them

    • Fixed the AttributesExtension re-merging and re-filtering everything a node had already collected each time another attribute node was applied to it, causing long runs of distinctly-named attributes to be resolved in quadratic time, which could be abused to cause a denial of service - this completes the fix for GHSA-jjv6-8j6v-6j52, which covered only the class attribute (GHSA-8rr7-cvq3-gmfh)

    • Fixed the AttributesExtension re-merging everything an attribute block had already collected on each of its continuation lines, causing long runs of distinctly-named attributes on consecutive lines to be resolved in quadratic time, which could be abused to cause a denial of service (GHSA-8rr7-cvq3-gmfh)

    Open source →
  2. 2.9.2 11 Aug 2026
    Release notes

    This release fixes a regression introduced in 2.9.0 which changed the behavior of Cursor::match() for certain regular expression patterns.

    Changed

    • Improved performance of reading single characters from multibyte lines
    • Improved performance of locating the next non-space character on lines without tabs
    • Optimized Cursor::advanceToNextNonSpaceOrNewline() to scan the line in place instead of copying everything left in the block on every call
    • Optimized inline link destination parsing to scan the line in place, so its cost follows the length of the destination rather than the length of everything left in the block

    Fixed

    • Fixed a regression introduced in 2.9.0 where Cursor::match() treated text before the cursor as part of the match subject (#1145). Patterns were matched against the whole line at an offset, which silently changed the meaning of \b, \B, \A, lookbehinds, a ^ anywhere other than the very start of the pattern, and a leading ^ combined with the m modifier. match() once again matches against the remainder, exactly as it did in 2.8; the core parsers keep the optimized in-place matching via a new internal method with PCRE's native offset semantics, anchoring their patterns at the cursor with \G
    • Fixed heading permalinks rendered with aria-hidden="true" remaining in the keyboard tab order; they are now also given tabindex="-1", as a focusable element removed from the accessibility tree has no accessible name to announce when focused (WCAG 4.1.2)
    • Fixed cloning a node breaking the link from the original node's children back to their parent, silently corrupting the document that node belonged to; detaching or inserting around those children afterwards could drop nodes from the tree
    • Fixed cloned nodes sharing their data with the node they were cloned from, so that setting an attribute on either one also set it on the other
    Open source →
    Release notes

    This release fixes a regression introduced in 2.9.0 which changed the behavior of Cursor::match() for certain regular expression patterns.

    Changed

    • Improved performance of reading single characters from multibyte lines
    • Improved performance of locating the next non-space character on lines without tabs
    • Optimized Cursor::advanceToNextNonSpaceOrNewline() to scan the line in place instead of copying everything left in the block on every call
    • Optimized inline link destination parsing to scan the line in place, so its cost follows the length of the destination rather than the length of everything left in the block

    Fixed

    • Fixed a regression introduced in 2.9.0 where Cursor::match() treated text before the cursor as part of the match subject (#1145). Patterns were matched against the whole line at an offset, which silently changed the meaning of \b, \B, \A, lookbehinds, a ^ anywhere other than the very start of the pattern, and a leading ^ combined with the m modifier. match() once again matches against the remainder, exactly as it did in 2.8; the core parsers keep the optimized in-place matching via a new internal method with PCRE's native offset semantics, anchoring their patterns at the cursor with \G
    • Fixed heading permalinks rendered with aria-hidden="true" remaining in the keyboard tab order; they are now also given tabindex="-1", as a focusable element removed from the accessibility tree has no accessible name to announce when focused (WCAG 4.1.2)
    • Fixed cloning a node breaking the link from the original node's children back to their parent, silently corrupting the document that node belonged to; detaching or inserting around those children afterwards could drop nodes from the tree
    • Fixed cloned nodes sharing their data with the node they were cloned from, so that setting an attribute on either one also set it on the other
    Open source →
    Release notes

    This release fixes a regression introduced in 2.9.0 which changed the behavior of Cursor::match() for certain regular expression patterns.

    Changed

    • Improved performance of reading single characters from multibyte lines

    • Improved performance of locating the next non-space character on lines without tabs

    • Optimized Cursor::advanceToNextNonSpaceOrNewline() to scan the line in place instead of copying everything left in the block on every call

    • Optimized inline link destination parsing to scan the line in place, so its cost follows the length of the destination rather than the length of everything left in the block

    Fixed

    • Fixed a regression introduced in 2.9.0 where Cursor::match() treated text before the cursor as part of the match subject (#1145). Patterns were matched against the whole line at an offset, which silently changed the meaning of \b , \B , \A , lookbehinds, a ^ anywhere other than the very start of the pattern, and a leading ^ combined with the m modifier. match() once again matches against the remainder, exactly as it did in 2.8; the core parsers keep the optimized in-place matching via a new internal method with PCRE’s native offset semantics, anchoring their patterns at the cursor with \G

    • Fixed heading permalinks rendered with aria-hidden="true" remaining in the keyboard tab order; they are now also given tabindex="-1" , as a focusable element removed from the accessibility tree has no accessible name to announce when focused (WCAG 4.1.2)

    • Fixed cloning a node breaking the link from the original node’s children back to their parent, silently corrupting the document that node belonged to; detaching or inserting around those children afterwards could drop nodes from the tree

    • Fixed cloned nodes sharing their data with the node they were cloned from, so that setting an attribute on either one also set it on the other

    Open source →
  3. 2.9.1 09 Aug 2026
    Release notes

    This is a security release to address multiple denial-of-service vulnerabilities and one cross-site scripting (XSS) vulnerability.

    Changed

    • Shortcut and collapsed reference links ([label] and [label][]) now apply the spec's 999-character link label limit when resolving the label, matching the limit already enforced when parsing reference definitions and when resolving the [text][label] form. A label longer than 999 characters which collapsed to a shorter, defined label once whitespace was normalized will no longer resolve; this matches cmark's behavior.

    Fixed

    • Fixed attribute names prefixed with a form feed (such as {<FF>onclick="..."}) bypassing both the on* event handler filter and the allow_unsafe_links protection, as browsers treat that byte as whitespace and parse the name as a genuine onclick or href (GHSA-f8fg-pg57-v4j8)
    • Fixed catastrophic backtracking in the fenced code block start pattern, causing a single line of backticks to be scanned in quadratic time, which could be abused to cause a denial of service (GHSA-j8pm-gj4c-rq4x)
    • Fixed shortcut reference link lookups normalizing arbitrarily long labels once a single reference definition is present, causing nested brackets to be resolved in quadratic time, which could be abused to cause a denial of service (GHSA-j8pm-gj4c-rq4x)
    • Fixed delimiter processors keying the opener-search cache on the raw closer run length, leaving the cache key space unbounded and causing emphasis, strikethrough, and highlight runs to be processed in super-linear time, which could be abused to cause a denial of service (GHSA-j8pm-gj4c-rq4x)
    • Fixed the SmartPunctExtension recopying the whole preceding text node when replacing each unpaired quote, causing documents with many apostrophes to be processed in quadratic time, which could be abused to cause a denial of service (GHSA-jjv6-8j6v-6j52)
    • Fixed the AttributesExtension scanning the remaining siblings of every block-level attribute node, causing long runs of adjacent attribute blocks to be resolved in quadratic time, which could be abused to cause a denial of service - this completes the fix for GHSA-g2gp-3wwq-f4ph, which covered only inline attributes (GHSA-jjv6-8j6v-6j52)
    • Fixed the AttributesExtension rebuilding the accumulated class list on every merge, causing long runs of .class attributes to be resolved in quadratic time, which could be abused to cause a denial of service (GHSA-jjv6-8j6v-6j52)
    Open source →
    Release notes

    This is a security release to address multiple denial of service vulnerabilities and one cross-site scripting (XSS) vulnerability.

    Changed

    • Shortcut and collapsed reference links ([label] and [label][]) now apply the spec's 999-character link label limit when resolving the label, matching the limit already enforced when parsing reference definitions and when resolving the [text][label] form. A label longer than 999 characters which collapsed to a shorter, defined label once whitespace was normalized will no longer resolve; this matches cmark's behavior.

    Fixed

    • Fixed attribute names prefixed with a form feed (such as {<FF>onclick="..."}) bypassing both the on* event handler filter and the allow_unsafe_links protection, as browsers treat that byte as whitespace and parse the name as a genuine onclick or href (GHSA-f8fg-pg57-v4j8)
    • Fixed catastrophic backtracking in the fenced code block start pattern, causing a single line of backticks to be scanned in quadratic time, which could be abused to cause a denial of service (GHSA-j8pm-gj4c-rq4x)
    • Fixed shortcut reference link lookups normalizing arbitrarily long labels once a single reference definition is present, causing nested brackets to be resolved in quadratic time, which could be abused to cause a denial of service (GHSA-j8pm-gj4c-rq4x)
    • Fixed delimiter processors keying the opener-search cache on the raw closer run length, leaving the cache key space unbounded and causing emphasis, strikethrough, and highlight runs to be processed in super-linear time, which could be abused to cause a denial of service (GHSA-j8pm-gj4c-rq4x)
    • Fixed the SmartPunctExtension recopying the whole preceding text node when replacing each unpaired quote, causing documents with many apostrophes to be processed in quadratic time, which could be abused to cause a denial of service (GHSA-jjv6-8j6v-6j52)
    • Fixed the AttributesExtension scanning the remaining siblings of every block-level attribute node, causing long runs of adjacent attribute blocks to be resolved in quadratic time, which could be abused to cause a denial of service - this completes the fix for GHSA-g2gp-3wwq-f4ph, which covered only inline attributes (GHSA-jjv6-8j6v-6j52)
    • Fixed the AttributesExtension rebuilding the accumulated class list on every merge, causing long runs of .class attributes to be resolved in quadratic time, which could be abused to cause a denial of service (GHSA-jjv6-8j6v-6j52)
    Open source →
    Release notes

    This is a security release to address multiple denial-of-service vulnerabilities and one cross-site scripting (XSS) vulnerability.

    Changed

    • Shortcut and collapsed reference links ( [label] and [label][] ) now apply the spec’s 999-character link label limit when resolving the label, matching the limit already enforced when parsing reference definitions and when resolving the [text][label] form. A label longer than 999 characters which collapsed to a shorter, defined label once whitespace was normalized will no longer resolve; this matches cmark’s behavior.

    Fixed

    • Fixed attribute names prefixed with a form feed (such as {<FF>onclick="..."} ) bypassing both the on* event handler filter and the allow_unsafe_links protection, as browsers treat that byte as whitespace and parse the name as a genuine onclick or href (GHSA-f8fg-pg57-v4j8)

    • Fixed catastrophic backtracking in the fenced code block start pattern, causing a single line of backticks to be scanned in quadratic time, which could be abused to cause a denial of service (GHSA-j8pm-gj4c-rq4x)

    • Fixed shortcut reference link lookups normalizing arbitrarily long labels once a single reference definition is present, causing nested brackets to be resolved in quadratic time, which could be abused to cause a denial of service (GHSA-j8pm-gj4c-rq4x)

    • Fixed delimiter processors keying the opener-search cache on the raw closer run length, leaving the cache key space unbounded and causing emphasis, strikethrough, and highlight runs to be processed in super-linear time, which could be abused to cause a denial of service (GHSA-j8pm-gj4c-rq4x)

    • Fixed the SmartPunctExtension recopying the whole preceding text node when replacing each unpaired quote, causing documents with many apostrophes to be processed in quadratic time, which could be abused to cause a denial of service (GHSA-jjv6-8j6v-6j52)

    • Fixed the AttributesExtension scanning the remaining siblings of every block-level attribute node, causing long runs of adjacent attribute blocks to be resolved in quadratic time, which could be abused to cause a denial of service - this completes the fix for GHSA-g2gp-3wwq-f4ph, which covered only inline attributes (GHSA-jjv6-8j6v-6j52)

    • Fixed the AttributesExtension rebuilding the accumulated class list on every merge, causing long runs of .class attributes to be resolved in quadratic time, which could be abused to cause a denial of service (GHSA-jjv6-8j6v-6j52)

    Open source →
  4. 2.9.0 03 Aug 2026
    Release notes

    This is a security release to address five denial-of-service vulnerabilities and one cross-site scripting (XSS) vulnerability.

    Added

    • Added a new NormalizeHeadingsExtension to constrain headings to a configured level range (#989)
      • Rewrites headings that skip levels so the resulting HTML is valid (#1115)
      • normalize_headings/rebase_to_min_level - rebases each document so its headings begin at min_level
    • Added a new footnote/enable_inline_footnotes config option to disable the inline ^[Footnote text] syntax (#1112)
    • Added Cursor::getBytePosition() for obtaining the cursor's current byte offset within the line
    • Added a new xml/max_indentation_level config option to control how far XmlRenderer indents nested elements (default: 16; set to 0 for unindented output)

    Changed

    • The FootnoteExtension now uses only the first definition of a footnote label, removing any duplicate definitions instead of rendering them in place
    • NumberFootnotesListener now stores footnote backrefs under a single footnote/backrefs key in the document data instead of one key per footnote destination
    • Optimized Cursor to translate character positions to byte offsets in constant time instead of re-decoding the line with mb_substr()
    • Optimized Cursor::match() to match against the line at the cursor's byte offset instead of copying the remaining line on every call
    • Optimized InlineParserEngine and UrlAutolinkParser to work with byte offsets directly

    Fixed

    • Fixed quadratic parsing performance on lines containing multibyte characters, which could be abused to cause a denial of service (GHSA-2q4p-g7hv-5rgv)
    • Fixed the unsafe link filter failing to detect dangerous schemes obfuscated with embedded tabs, newlines, or leading control characters (such as java<TAB>script:), which allowed the allow_unsafe_links protection to be bypassed via href and src attributes (GHSA-29pj-957v-52mc)
    • Fixed duplicate footnote definitions each claiming the full list of backrefs for their label, causing a quadratic number of backrefs to be generated, which could be abused to cause a denial of service (GHSA-jfm3-95jq-q3rf)
    • Fixed footnote labels being treated as .//-delimited key paths when storing backrefs, which allowed distinct labels such as [^a.b] and [^a/b] to share a single backref list (GHSA-jfm3-95jq-q3rf)
    • Fixed a fatal error when one footnote label was a prefix of another, such as [^a] and [^a.b]
    • Fixed the unique slug normalizer restarting its suffix search from 1 on every collision, causing headings or inline footnotes which normalize to the same slug to be de-duplicated in quadratic time, which could be abused to cause a denial of service (GHSA-mh25-x5hq-wrqp)
    • Fixed the AttributesExtension scanning the remaining siblings of an inline attribute which can only apply to its parent block, causing long runs of adjacent inline attributes to be resolved in quadratic time, which could be abused to cause a denial of service (GHSA-g2gp-3wwq-f4ph)
    • Fixed XmlRenderer indenting every element by its full nesting depth without any upper bound, causing deeply-nested documents to render as quadratically-sized XML, which could be abused to cause a denial of service (GHSA-mj63-m3rc-8ppr)
    • Fixed MarkDelimiterProcessor not being declared as a CacheableDelimiterProcessorInterface, preventing the delimiter stack from caching the opener search for == runs (#1133)

    New Contributors

    Special Thanks

    Special thanks to @GrahamCampbell and @TungNGo02 for responsibly disclosing the security vulnerabilities and contributing to the fixes in this release.


    Full Changelog: 2.8.3...2.9.0

    Open source →
    Release notes

    This is a security release to address five denial of service vulnerabilities and one cross-site scripting (XSS) vulnerability.

    Added

    • Added a new NormalizeHeadingsExtension to constrain headings to a configured level range (#989)
      • Rewrites headings that skip levels so the resulting HTML is valid (#1115)
      • normalize_headings/rebase_to_min_level - rebases each document so its headings begin at min_level
    • Added a new footnote/enable_inline_footnotes config option to disable the inline ^[Footnote text] syntax (#1112)
    • Added Cursor::getBytePosition() for obtaining the cursor's current byte offset within the line
    • Added a new xml/max_indentation_level config option to control how far XmlRenderer indents nested elements (default: 16; set to 0 for unindented output)

    Changed

    • The FootnoteExtension now uses only the first definition of a footnote label, removing any duplicate definitions instead of rendering them in place
    • NumberFootnotesListener now stores footnote backrefs under a single footnote/backrefs key in the document data instead of one key per footnote destination
    • Optimized Cursor to translate character positions to byte offsets in constant time instead of re-decoding the line with mb_substr()
    • Optimized Cursor::match() to match against the line at the cursor's byte offset instead of copying the remaining line on every call
    • Optimized InlineParserEngine and UrlAutolinkParser to work with byte offsets directly

    Fixed

    • Fixed quadratic parsing performance on lines containing multibyte characters, which could be abused to cause a denial of service (GHSA-2q4p-g7hv-5rgv)
    • Fixed the unsafe link filter failing to detect dangerous schemes obfuscated with embedded tabs, newlines, or leading control characters (such as java<TAB>script:), which allowed the allow_unsafe_links protection to be bypassed via href and src attributes (GHSA-29pj-957v-52mc)
    • Fixed duplicate footnote definitions each claiming the full list of backrefs for their label, causing a quadratic number of backrefs to be generated, which could be abused to cause a denial of service (GHSA-jfm3-95jq-q3rf)
    • Fixed footnote labels being treated as .//-delimited key paths when storing backrefs, which allowed distinct labels such as [^a.b] and [^a/b] to share a single backref list (GHSA-jfm3-95jq-q3rf)
    • Fixed a fatal error when one footnote label was a prefix of another, such as [^a] and [^a.b]
    • Fixed the unique slug normalizer restarting its suffix search from 1 on every collision, causing headings or inline footnotes which normalize to the same slug to be de-duplicated in quadratic time, which could be abused to cause a denial of service (GHSA-mh25-x5hq-wrqp)
    • Fixed the AttributesExtension scanning the remaining siblings of an inline attribute which can only apply to its parent block, causing long runs of adjacent inline attributes to be resolved in quadratic time, which could be abused to cause a denial of service (GHSA-g2gp-3wwq-f4ph)
    • Fixed XmlRenderer indenting every element by its full nesting depth without any upper bound, causing deeply-nested documents to render as quadratically-sized XML, which could be abused to cause a denial of service (GHSA-mj63-m3rc-8ppr)
    • Fixed MarkDelimiterProcessor not being declared as a CacheableDelimiterProcessorInterface, preventing the delimiter stack from caching the opener search for == runs (#1133)
    Open source →
    Release notes

    This is a security release to address five denial-of-service vulnerabilities and one cross-site scripting (XSS) vulnerability.

    Added

    • Added a new NormalizeHeadingsExtension to constrain headings to a configured level range (#989)

    • Rewrites headings that skip levels so the resulting HTML is valid (#1115)

    • normalize_headings/rebase_to_min_level - rebases each document so its headings begin at min_level

    • Added a new footnote/enable_inline_footnotes config option to disable the inline ^[Footnote text] syntax (#1112)

    • Added Cursor::getBytePosition() for obtaining the cursor’s current byte offset within the line

    • Added a new xml/max_indentation_level config option to control how far XmlRenderer indents nested elements (default: 16 ; set to 0 for unindented output)

    Changed

    • The FootnoteExtension now uses only the first definition of a footnote label, removing any duplicate definitions instead of rendering them in place

    • NumberFootnotesListener now stores footnote backrefs under a single footnote/backrefs key in the document data instead of one key per footnote destination

    • Optimized Cursor to translate character positions to byte offsets in constant time instead of re-decoding the line with mb_substr()

    • Optimized Cursor::match() to match against the line at the cursor’s byte offset instead of copying the remaining line on every call

    • Optimized InlineParserEngine and UrlAutolinkParser to work with byte offsets directly

    Fixed

    • Fixed quadratic parsing performance on lines containing multibyte characters, which could be abused to cause a denial of service (GHSA-2q4p-g7hv-5rgv)

    • Fixed the unsafe link filter failing to detect dangerous schemes obfuscated with embedded tabs, newlines, or leading control characters (such as java<TAB>script: ), which allowed the allow_unsafe_links protection to be bypassed via href and src attributes (GHSA-29pj-957v-52mc)

    • Fixed duplicate footnote definitions each claiming the full list of backrefs for their label, causing a quadratic number of backrefs to be generated, which could be abused to cause a denial of service (GHSA-jfm3-95jq-q3rf)

    • Fixed footnote labels being treated as . / / -delimited key paths when storing backrefs, which allowed distinct labels such as [^a.b] and [^a/b] to share a single backref list (GHSA-jfm3-95jq-q3rf)

    • Fixed a fatal error when one footnote label was a prefix of another, such as [^a] and [^a.b]

    • Fixed the unique slug normalizer restarting its suffix search from 1 on every collision, causing headings or inline footnotes which normalize to the same slug to be de-duplicated in quadratic time, which could be abused to cause a denial of service (GHSA-mh25-x5hq-wrqp)

    • Fixed the AttributesExtension scanning the remaining siblings of an inline attribute which can only apply to its parent block, causing long runs of adjacent inline attributes to be resolved in quadratic time, which could be abused to cause a denial of service (GHSA-g2gp-3wwq-f4ph)

    • Fixed XmlRenderer indenting every element by its full nesting depth without any upper bound, causing deeply-nested documents to render as quadratically-sized XML, which could be abused to cause a denial of service (GHSA-mj63-m3rc-8ppr)

    • Fixed MarkDelimiterProcessor not being declared as a CacheableDelimiterProcessorInterface , preventing the delimiter stack from caching the opener search for == runs (#1133)

    New Contributors

    • @AJenbo made their first contribution in https://github.com/thephpleague/commonmark/pull/1108

    • @eyupcanakman made their first contribution in https://github.com/thephpleague/commonmark/pull/1113

    Special Thanks

    Special thanks to @GrahamCampbell and @TungNGo02 for responsibly disclosing the security vulnerabilities and contributing to the fixes in this release.

    Full Changelog : https://github.com/thephpleague/commonmark/compare/2.8.3…2.9.0

    Open source →
  5. 2.8.3 12 Jul 2026
    Release notes

    What's Changed

    Fixed

    • Fixed tab-indented fenced code blocks inside list items losing the first character of each line and having their info string mangled (#981, #1130)
    • Fixed the unsafe link filter incorrectly blocking safe URLs containing vbscript:, file:, or data: anywhere after the start (#1131)

    Full Changelog: 2.8.2...2.8.3

    Open source →
    Release notes

    Fixed

    • Fixed tab-indented fenced code blocks inside list items losing the first character of each line and having their info string mangled (#981, #1130)
    • Fixed the unsafe link filter incorrectly blocking safe URLs containing vbscript:, file:, or data: anywhere after the start (#1131)
    Open source →
  6. 2.8.2 19 Mar 2026
    Release notes

    This is a security release to address an issue where the allowed_domains setting for the Embed extension can be bypassed, resulting in a possible SSRF and XSS vulnerabilities.

    Fixed

    • Fixed DomainFilteringAdapter hostname boundary bypass where domains like youtube.com.evil could match an allowlist entry for youtube.com (GHSA-hh8v-hgvp-g3f5)

    Full Changelog: 2.8.1...2.8.2

    Open source →
    Release notes

    This is a security release to address an issue where the allowed_domains setting for the Embed extension can be bypassed, resulting in a possible SSRF and XSS vulnerabilities.

    Fixed

    • Fixed DomainFilteringAdapter hostname boundary bypass where domains like youtube.com.evil could match an allowlist entry for youtube.com (GHSA-hh8v-hgvp-g3f5)
    Open source →
    Release notes

    This is a security release to address an issue where the allowed_domains setting for the Embed extension can be bypassed, resulting in a possible SSRF and XSS vulnerabilities.

    Fixed

    • Fixed DomainFilteringAdapter hostname boundary bypass where domains like youtube.com.evil could match an allowlist entry for youtube.com (GHSA-hh8v-hgvp-g3f5)

    Full Changelog : https://github.com/thephpleague/commonmark/compare/2.8.1…2.8.2

    Open source →
  7. 2.8.1 05 Mar 2026
    Release notes

    What's Changed

    This is a security release to address an issue where DisallowedRawHtml can be bypassed, resulting in a possible cross-site scripting (XSS) vulnerability.

    Fixed

    • Fixed DisallowedRawHtmlRenderer not blocking raw HTML tags with trailing ASCII whitespace (GHSA-4v6x-c7xx-hw9f)
    • Fixed PHP 8.5 deprecation (#1107)

    New Contributors

    Full Changelog: 2.8.0...2.8.1

    Open source →
    Release notes

    This is a security release to address an issue where DisallowedRawHtml can be bypassed, resulting in a possible cross-site scripting (XSS) vulnerability.

    Fixed

    • Fixed DisallowedRawHtmlRenderer not blocking raw HTML tags with trailing ASCII whitespace (GHSA-4v6x-c7xx-hw9f)
    • Fixed PHP 8.5 deprecation (#1107)
    Open source →
  8. 2.8.0 26 Nov 2025
    Release notes

    What's Changed

    Added

    • Added a new HighlightExtension for marking important text using == syntax (#1100)

    Fixed

    • Fixed AutolinkExtension incorrectly matching URLs after invalid www. prefix (#1095, #1103)

    New Contributors

    Full Changelog: 2.7.1...2.8.0

    Open source →
    Release notes

    Added

    • Added a new HighlightExtension for marking important text using == syntax (#1100)

    Fixed

    • Fixed AutolinkExtension incorrectly matching URLs after invalid www. prefix (#1095, #1103)
    Open source →
  9. 2.7.1 20 Jul 2025
    Release notes

    Notable Changes

    Changed

    • Optimized several regular expressions in RegexHelper to improve performance (#674, #1086)

    Fixed

    • EmbedProcessor no longer calls updateEmbeds() when there are no embeds to update (#1081)
    • Fixed missing benchmark.php CSV path validation for non-existent files (#1068, #1085)

    New Contributors

    Full Changelog: 2.7.0...2.7.1

    Open source →
    Release notes

    Changed

    • Optimized several regular expressions in RegexHelper to improve performance (#674, #1086)

    Fixed

    • EmbedProcessor no longer calls updateEmbeds() when there are no embeds to update (#1081)
    • Fixed missing benchmark.php CSV path validation for non-existent files (#1068, #1085)
    Open source →
  10. 2.7.0 05 May 2025
    Release notes

    This is a security release to address a potential cross-site scripting (XSS) vulnerability when using the AttributesExtension with untrusted user input.

    Added

    • Added attributes/allow config option to specify which attributes users are allowed to set on elements (default allows virtually all attributes)

    Changed

    • The AttributesExtension blocks all attributes starting with on unless explicitly allowed via the attributes/allow config option
    • The allow_unsafe_links option is now respected by the AttributesExtension when users specify href and src attributes
    Open source →
    Release notes

    This is a security release to address a potential cross-site scripting (XSS) vulnerability when using the AttributesExtension with untrusted user input.

    Added

    • Added attributes/allow config option to specify which attributes users are allowed to set on elements (default allows virtually all attributes)

    Changed

    • The AttributesExtension blocks all attributes starting with on unless explicitly allowed via the attributes/allow config option
    • The allow_unsafe_links option is now respected by the AttributesExtension when users specify href and src attributes
    Open source →
    Release notes

    This is a security release to address a potential cross-site scripting (XSS) vulnerability when using the AttributesExtension with untrusted user input .

    Added

    • Added attributes/allow config option to specify which attributes users are allowed to set on elements (default allows virtually all attributes)

    Changed

    • The AttributesExtension blocks all attributes starting with on unless explicitly allowed via the attributes/allow config option

    • The allow_unsafe_links option is now respected by the AttributesExtension when users specify href and src attributes

    Open source →
  11. 2.6.2 18 Apr 2025
    Release notes

    Fixed

    • Fixed Attributes extension parsing regression (#1071)
    Open source →
  12. 2.6.1 29 Dec 2024
    Release notes

    Fixed

    • Rendered list items should only add newlines around block-level children (#1059, #1061)
    Open source →
    Release notes

    Fixed

    • Rendered list items should only add newlines around block-level children (#1059, #1061)

    Full Changelog : https://github.com/thephpleague/commonmark/compare/2.6.0…2.6.1

    Open source →
  13. 2.6.0 07 Dec 2024
    Release notes

    This is a security release to address potential denial of service attacks when parsing specially crafted, malicious input from untrusted sources (like user input).

    Added

    • Added max_delimiters_per_line config option to prevent denial of service attacks when parsing malicious input
    • Added table/max_autocompleted_cells config option to prevent denial of service attacks when parsing large tables
    • The AttributesExtension now supports attributes without values (#985, #986)
    • The AutolinkExtension exposes two new configuration options to override the default behavior (#969, #987):
      • autolink/allowed_protocols - an array of protocols to allow autolinking for
      • autolink/default_protocol - the default protocol to use when none is specified
    • Added RegexHelper::isWhitespace() method to check if a given character is an ASCII whitespace character
    • Added CacheableDelimiterProcessorInterface to ensure linear complexity for dynamic delimiter processing
    • Added Bracket delimiter type to optimize bracket parsing

    Changed

    • [ and ] are no longer added as Delimiter objects on the stack; a new Bracket type with its own stack is used instead
    • UrlAutolinkParser no longer parses URLs with more than 127 subdomains
    • Expanded reference links can no longer exceed 100kb, or the size of the input document (whichever is greater)
    • Delimiters should always provide a non-null value via DelimiterInterface::getIndex()
      • We'll attempt to infer the index based on surrounding delimiters where possible
    • The DelimiterStack now accepts integer positions for any $stackBottom argument
    • Several small performance optimizations
    Open source →
    Release notes

    This is a security release to address potential denial of service attacks when parsing specially crafted, malicious input from untrusted sources (like user input). See https://github.com/thephpleague/commonmark/security/advisories/GHSA-c2pc-g5qf-rfrf for more details.

    Added

    • Added max_delimiters_per_line config option to prevent denial of service attacks when parsing malicious input

    • Added table/max_autocompleted_cells config option to prevent denial of service attacks when parsing large tables

    • The AttributesExtension now supports attributes without values (#985, #986)

    • The AutolinkExtension exposes two new configuration options to override the default behavior (#969, #987):

    • autolink/allowed_protocols - an array of protocols to allow autolinking for

    • autolink/default_protocol - the default protocol to use when none is specified

    • Added RegexHelper::isWhitespace() method to check if a given character is an ASCII whitespace character

    • Added CacheableDelimiterProcessorInterface to ensure linear complexity for dynamic delimiter processing

    • Added Bracket delimiter type to optimize bracket parsing

    Changed

    • [ and ] are no longer added as Delimiter objects on the stack; a new Bracket type with its own stack is used instead

    • UrlAutolinkParser no longer parses URLs with more than 127 subdomains

    • Expanded reference links can no longer exceed 100kb, or the size of the input document (whichever is greater)

    • Delimiters should always provide a non-null value via DelimiterInterface::getIndex()

    • We’ll attempt to infer the index based on surrounding delimiters where possible

    • The DelimiterStack now accepts integer positions for any $stackBottom argument

    • Several small performance optimizations

    Open source →
  14. 2.5.3 16 Aug 2024
    Release notes

    Changed

    • Made compatible with CommonMark spec 0.31.1, including:
      • Remove source, add search to list of recognized block tags
    Open source →
    Release notes

    Changed

    • Made compatible with CommonMark spec 0.31.1, including:
    • Remove source , add search to list of recognized block tags

    Full Changelog : https://github.com/thephpleague/commonmark/compare/2.5.2…2.5.3

    Open source →
  15. 2.5.2 14 Aug 2024
    Release notes

    Changed

    • Boolean attributes now require an explicit true value (#1040)

    Fixed

    • Fixed regression where text could be misinterpreted as an attribute (#1040)
    Open source →
    Release notes

    Changed

    • Boolean attributes now require an explicit true value (#1040)

    Fixed

    • Fixed regression where text could be misinterpreted as an attribute (#1040)

    Full Changelog : https://github.com/thephpleague/commonmark/compare/2.5.1…2.5.2

    Open source →
  16. 2.5.1 24 Jul 2024
    Release notes

    Fixed

    • Fixed attribute parsing incorrectly parsing mustache-like syntax (#1035)
    • Fixed incorrect Table start line numbers (#1037)
    Open source →
  17. 2.5.0 22 Jul 2024
    Release notes

    Added

    • The AttributesExtension now supports attributes without values (#985, #986)
    • The AutolinkExtension exposes two new configuration options to override the default behavior (#969, #987):
      • autolink/allowed_protocols - an array of protocols to allow autolinking for
      • autolink/default_protocol - the default protocol to use when none is specified

    Changed

    • Made compatible with CommonMark spec 0.31.0, including:
      • Allow closing fence to be followed by tabs
      • Remove restrictive limitation on inline comments
      • Unicode symbols now treated like punctuation (for purposes of flankingness)
      • Trailing tabs on the last line of indented code blocks will be excluded
      • Improved HTML comment matching
    • Paragraphs only containing link reference definitions will be kept in the AST until the Document is finalized
      • (These were previously removed immediately after parsing the Paragraph)

    Fixed

    • Fixed list tightness not being determined properly in some edge cases
    • Fixed incorrect ending line numbers for several block types in various scenarios
    • Fixed lowercase inline HTML declarations not being accepted
    Open source →
  18. 2.4.4 22 Jul 2024
    Release notes

    Fixed

    • Fixed SmartPunct extension changing already-formatted quotation marks (#1030)
    Open source →
    Release notes

    Fixed

    • Fixed SmartPunct extension changing already-formatted quotation marks (#1030)

    Full Changelog : https://github.com/thephpleague/commonmark/compare/2.4.3…2.4.4

    Open source →
  19. 2.4.3 22 Jul 2024
    Release notes

    Fixed

    • Fixed the Attributes extension not supporting CSS level 3 selectors (#1013)
    • Fixed UrlAutolinkParser incorrectly parsing text containing www anywhere before an autolink (#1025)
    Open source →
  20. 2.4.2 02 Feb 2024
    Release notes

    Fixed

    • Fixed declaration parser being too strict
    • FencedCodeRenderer: don't add language- to class if already prefixed

    Deprecated

    • Returning dynamic values from DelimiterProcessorInterface::getDelimiterUse() is deprecated
      • You should instead implement CacheableDelimiterProcessorInterface to help the engine perform caching to avoid performance issues.
    • Failing to set a delimiter's index (or returning null from DelimiterInterface::getIndex()) is deprecated and will not be supported in 3.0
    • Deprecated DelimiterInterface::isActive() and DelimiterInterface::setActive(), as these are no longer used by the engine
    • Deprecated DelimiterStack::removeEarlierMatches() and DelimiterStack::searchByCharacter(), as these are no longer used by the engine
    • Passing a DelimiterInterface as the $stackBottom argument to DelimiterStack::processDelimiters() or ::removeAll() is deprecated and will not be supported in 3.0; pass the integer position instead.

    Fixed

    • Fixed NUL characters not being replaced in the input
    • Fixed quadratic complexity parsing unclosed inline links
    • Fixed quadratic complexity parsing emphasis and strikethrough delimiters
    • Fixed issue where having 500,000+ delimiters could trigger a known segmentation fault issue in PHP's garbage collection
    • Fixed quadratic complexity deactivating link openers
    • Fixed quadratic complexity parsing long backtick code spans with no matching closers
    • Fixed catastrophic backtracking when parsing link labels/titles
    Open source →
    Release notes

    Fixed

    • Fixed declaration parser being too strict

    • FencedCodeRenderer : don’t add language- to class if already prefixed

    Open source →
  21. 2.4.1 30 Aug 2023
    Release notes

    Fixed

    • Fixed ExternalLinkProcessor not fully disabling the rel attribute when configured to do so (#992)
    Open source →
    Release notes

    Fixed

    • Fixed ExternalLinkProcessor not fully disabling the rel attribute when configured to do so (#992)
    Open source →
  22. 2.4.0 24 Mar 2023
    Release notes

    Added

    • Added generic CommonMarkException marker interface for all exceptions thrown by the library
    • Added several new specific exception types implementing that marker interface:
      • AlreadyInitializedException
      • InvalidArgumentException
      • IOException
      • LogicException
      • MissingDependencyException
      • NoMatchingRendererException
      • ParserLogicException
    • Added more configuration options to the Heading Permalinks extension (#939):
      • heading_permalink/apply_id_to_heading - When true, the id attribute will be applied to the heading element itself instead of the <a> tag
      • heading_permalink/heading_class - class to apply to the heading element
      • heading_permalink/insert - now accepts none to prevent the creation of the <a> link
    • Added new table/alignment_attributes configuration option to control how table cell alignment is rendered (#959)

    Changed

    • Change several thrown exceptions from RuntimeException to LogicException (or something extending it), including:
      • CallbackGenerators that fail to set a URL or return an expected value
      • MarkdownParser when deactivating the last block parser or attempting to get an active block parser when they've all been closed
      • Adding items to an already-initialized Environment
      • Rendering a Node when no renderer has been registered for it
    • HeadingPermalinkProcessor now throws InvalidConfigurationException instead of RuntimeException when invalid config values are given.
    • HtmlElement::setAttribute() no longer requires the second parameter for boolean attributes
    • Several small micro-optimizations
    • Changed Strikethrough to only allow 1 or 2 tildes per the updated GFM spec

    Fixed

    • Fixed inaccurate @throws docblocks throughout the codebase, including ConverterInterface, MarkdownConverter, and MarkdownConverterInterface.
      • These previously suggested that only \RuntimeExceptions were thrown, which was inaccurate as \LogicExceptions were also possible.
    Open source →
    Release notes

    See the upgrading guide for more information about the exception-related changes

    Added

    • Added generic CommonMarkException marker interface for all exceptions thrown by the library

    • Added several new specific exception types implementing that marker interface:

    • AlreadyInitializedException

    • InvalidArgumentException

    • IOException

    • LogicException

    • MissingDependencyException

    • NoMatchingRendererException

    • ParserLogicException

    • Added more configuration options to the Heading Permalinks extension (#939):

    • heading_permalink/apply_id_to_heading - When true , the id attribute will be applied to the heading element itself instead of the <a> tag

    • heading_permalink/heading_class - class to apply to the heading element

    • heading_permalink/insert - now accepts none to prevent the creation of the <a> link

    • Added new table/alignment_attributes configuration option to control how table cell alignment is rendered (#959)

    Changed

    • Change several thrown exceptions from RuntimeException to LogicException (or something extending it), including:

    • CallbackGenerator s that fail to set a URL or return an expected value

    • MarkdownParser when deactivating the last block parser or attempting to get an active block parser when they’ve all been closed

    • Adding items to an already-initialized Environment

    • Rendering a Node when no renderer has been registered for it

    • HeadingPermalinkProcessor now throws InvalidConfigurationException instead of RuntimeException when invalid config values are given.

    • HtmlElement::setAttribute() no longer requires the second parameter for boolean attributes

    • Several small micro-optimizations

    • Changed Strikethrough to only allow 1 or 2 tildes per the updated GFM spec

    Fixed

    • Fixed inaccurate @throws docblocks throughout the codebase, including ConverterInterface , MarkdownConverter , and MarkdownConverterInterface .
    • These previously suggested that only \RuntimeException s were thrown, which was inaccurate as \LogicException s were also possible.
    Open source →
  23. 2.3.9 15 Feb 2023
    Release notes

    Fixed

    • Fixed autolink extension not detecting some URIs with underscores (#956)
    Open source →
  24. 2.3.8 10 Dec 2022
    Release notes

    Fixed

    • Fixed parsing issues when mb_internal_encoding() is set to something other than UTF-8 (#951)
    Open source →
    Release notes

    Fixed

    • Fixed parsing issues when mb_internal_encoding() is set to something other than UTF-8 (#951)
    Open source →
  25. 2.3.7 03 Nov 2022
    Release notes

    Fixed

    • Fixed TaskListItemMarkerRenderer not including HTML attributes set on the node by other extensions (#947)
    Open source →
    Release notes

    Fixed

    • Fixed TaskListItemMarkerRenderer not including HTML attributes set on the node by other extensions (#947)
    Open source →
  26. 2.3.6 30 Oct 2022
    Release notes

    Fixed

    • Fixed unquoted attribute parsing when closing curly brace is followed by certain characters (like a .) (#943)
    Open source →
    Release notes

    Fixed

    • Fixed unquoted attribute parsing when closing curly brace is followed by certain characters (like a . ) (#943)
    Open source →
  27. 2.3.5 29 Jul 2022
    Release notes

    Fixed

    • Fixed error using InlineParserEngine when no inline parsers are registered in the Environment (#908)
    Open source →
    Release notes

    Fixed

    • Fixed error using InlineParserEngine when no inline parsers are registered in the Environment (#908)
    Open source →
  28. 2.3.4 17 Jul 2022
    Release notes

    Changed

    • Made a number of small tweaks to the embed extension's parsing behavior to fix #898:
      • Changed EmbedStartParser to always capture embed-like lines in container blocks, regardless of parent block type
      • Changed EmbedProcessor to also remove Embed blocks that aren't direct children of the Document
      • Increased the priority of EmbedProcessor to 1010

    Fixed

    • Fixed EmbedExtension not parsing embeds following a list block (#898)
    Open source →
    Release notes

    Changed

    • Made a number of small tweaks to the embed extension’s parsing behavior to fix #898:

    • Changed EmbedStartParser to always capture embed-like lines in container blocks, regardless of parent block type

    • Changed EmbedProcessor to also remove Embed blocks that aren’t direct children of the Document

    • Increased the priority of EmbedProcessor to 1010

    Fixed

    • Fixed EmbedExtension not parsing embeds following a list block (#898)
    Open source →
  29. 2.3.3 07 Jun 2022
    Release notes

    Fixed

    • Fixed DomainFilteringAdapter not reindexing the embed list (#884, #885)
    Open source →
    Release notes

    Fixed

    • Fixed DomainFilteringAdapter not reindexing the embed list (#884, #885)
    Open source →
  30. 2.3.2 03 Jun 2022
    Release notes

    Fixed

    • Fixed FootnoteExtension stripping extra characters from tab-indented footnotes (#881)
    Open source →
  31. 2.3.1 14 May 2022
    Release notes

    Fixed

    • Fixed AutolinkExtension not ignoring trailing strikethrough syntax (#867)
    Open source →
  32. 2.3.0 07 Apr 2022
    Release notes

    Added

    • Added new EmbedExtension (#805)
    • Added DocumentRendererInterface as a replacement for the now-deprecated MarkdownRendererInterface

    Deprecated

    • Deprecated MarkdownRendererInterface; use DocumentRendererInterface instead
    Open source →
    Release notes

    Added

    • Added new EmbedExtension (#805)

    • Added DocumentRendererInterface as a replacement for the now-deprecated MarkdownRendererInterface

    Deprecated

    • Deprecated MarkdownRendererInterface ; use DocumentRendererInterface instead
    Open source →
  33. 2.2.5 03 Jun 2022
    Release notes

    Fixed

    • Fixed FootnoteExtension stripping extra characters from tab-indented footnotes (#881)
    Open source →
  34. 2.2.4 14 May 2022
    Release notes

    Fixed

    • Fixed AutolinkExtension not ignoring trailing strikethrough syntax (#867)
    Open source →
  35. 2.2.3 26 Feb 2022
    Release notes

    Fixed

    • Fixed front matter parsing with Windows line endings (#821)
    Open source →
  36. 2.2.2 13 Feb 2022
    Release notes

    Fixed

    • Fixed double-escaping of image alt text (#806, #810)
    • Fixed Psalm typehints for event class names
    Open source →
  37. 2.2.1 25 Jan 2022
    Release notes

    Fixed

    • Fixed symfony/deprecation-contracts constraint

    Removed

    • Removed deprecation trigger from MarkdownConverterInterface to reduce noise
    Open source →
    Release notes

    Fixed

    • Fixed symfony/deprecation-contracts constraint

    Removed

    • Removed deprecation trigger from MarkdownConverterInterface to reduce noise
    Open source →
  38. 2.2.0 22 Jan 2022
    Release notes

    Added

    • Added new ConverterInterface
    • Added new MarkdownToXmlConverter class
    • Added new HtmlDecorator class which can wrap existing renderers with additional HTML tags
    • Added new table/wrap config to apply an optional wrapping/container element around a table (#780)

    Changed

    • HtmlElement contents can now consist of any Stringable, not just HtmlElement and string

    Deprecated

    • Deprecated MarkdownConverterInterface and its convertToHtml() method; use ConverterInterface and convert() instead
    Open source →
    Release notes

    Added

    • Added new ConverterInterface

    • Added new MarkdownToXmlConverter class

    • Added new HtmlDecorator class which can wrap existing renderers with additional HTML tags

    • Added new table/wrap config to apply an optional wrapping/container element around a table (#780)

    Changed

    • HtmlElement contents can now consist of any Stringable , not just HtmlElement and string

    Deprecated

    • Deprecated MarkdownConverterInterface and its convertToHtml() method; use ConverterInterface and convert() instead
    Open source →
  39. 2.1.3 26 Feb 2022
    Release notes

    Fixed

    • Fixed front matter parsing with Windows line endings (#821)
    Open source →
  40. 2.1.2 13 Feb 2022
    Release notes

    Fixed

    • Fixed double-escaping of image alt text (#806, #810)
    • Fixed Psalm typehints for event class names
    Open source →
  41. 2.1.1 02 Jan 2022
    Release notes

    Added

    • Added missing return type to Environment::dispatch() to fix deprecation warning (#778)
    Open source →
    Release notes

    Added

    • Added missing return type to Environment::dispatch() to fix deprecation warning (#778)
    Open source →
  42. 2.1.0 05 Dec 2021
    Release notes

    Added

    • Added support for ext-yaml in FrontMatterExtension (#715)
    • Added support for symfony/yaml v6.0 in FrontMatterExtension (#739)
    • Added new heading_permalink/aria_hidden config option (#741)

    Fixed

    • Fixed PHP 8.1 deprecation warning (#759, #762)
    Open source →
    Release notes

    Added

    • Added support for ext-yaml in FrontMatterExtension (#715)

    • Added support for symfony/yaml v6.0 in FrontMatterExtension (#739)

    • Added new heading_permalink/aria_hidden config option (#741)

    Fixed

    • Fixed PHP 8.1 deprecation warning (#759, #762)
    Open source →
  43. 2.0.4 26 Feb 2022
    Release notes

    Fixed

    • Fixed front matter parsing with Windows line endings (#821)
    Open source →
  44. 2.0.3 13 Feb 2022
    Release notes

    Fixed

    • Fixed double-escaping of image alt text (#806, #810)
    • Fixed Psalm typehints for event class names
    Open source →
  45. 2.0.2 14 Aug 2021
    Release notes

    Changed

    • Bumped minimum version of league/config to support PHP 8.1

    Fixed

    • Fixed ability to register block parsers that identify lines starting with letters (#706)
    Open source →
  46. 2.0.1 31 Jul 2021
    Release notes

    Fixed

    • Fixed nested autolinks (#689)
    • Fixed description lists being parsed incorrectly (#692)
    • Fixed Table of Contents not respecting Heading Permalink prefixes (#690)
    Open source →
  47. 2.0.0 24 Jul 2021
    Release notes

    No changes were introduced since the previous RC2 release. See all entries below for a list of changes between 1.x and 2.0.

    Open source →
    Release notes

    No changes were introduced since the previous 2.0.0-rc2 release.

    Please refer to the full Changelog for a list of all changes between 1.x and 2.0. An upgrading guide is also available.

    Open source →
  48. 2.0.0-rc2 17 Jul 2021 pre-release
    Release notes

    Fixed

    • Fixed Mentions inside of links creating nested links against the spec's rules (#688)
    Open source →
  49. 2.0.0-rc1 10 Jul 2021 pre-release
    Release notes

    No changes were introduced since the previous release.

    Open source →
  50. 2.0.0-beta3 03 Jul 2021 pre-release
    Release notes

    Changed

    • Any leading UTF-8 BOM will be stripped from the input
    • The getEnvironment() method of CommonMarkConverter and GithubFlavoredMarkdownConverter will always return the concrete, configurable Environment for upgrading convenience
    • Optimized AST iteration
    • Lots of small micro-optimizations
    Open source →
    Release notes

    Changed

    • Any leading UTF-8 BOM will be stripped from the input

    • The getEnvironment() method of CommonMarkConverter and GithubFlavoredMarkdownConverter will always return the concrete, configurable Environment for upgrading convenience

    • Optimized AST iteration

    • Lots of small micro-optimizations

    Open source →
  51. 2.0.0-beta2 27 Jun 2021 pre-release
    Release notes

    Added

    • Added new Node::iterator() method and NodeIterator class for faster AST iteration (#683, #684)

    Changed

    • Made compatible with CommonMark spec 0.30.0
    • Optimized link label parsing
    • Optimized AST iteration for a 50% performance boost in some event listeners (#683, #684)

    Fixed

    • Fixed processing instructions with EOLs
    • Fixed case-insensitive matching for HTML tag types
    • Fixed type 7 HTML blocks incorrectly interrupting lazy paragraphs
    • Fixed newlines in reference labels not collapsing into spaces
    • Fixed link label normalization with escaped newlines
    • Fixed unnecessary AST iteration when no default attributes are configured
    Open source →
    Release notes

    See https://commonmark.thephpleague.com/2.0/upgrading/ for detailed information on upgrading to version 2.0.

    Added

    • Added new Node::iterator() method and NodeIterator class for faster AST iteration (#683, #684)

    Changed

    • Made compatible with CommonMark spec 0.30.0

    • Optimized link label parsing

    • Optimized AST iteration for a 50% performance boost in some event listeners (#683, #684)

    Fixed

    • Fixed processing instructions with EOLs

    • Fixed case-insensitive matching for HTML tag types

    • Fixed type 7 HTML blocks incorrectly interrupting lazy paragraphs

    • Fixed newlines in reference labels not collapsing into spaces

    • Fixed link label normalization with escaped newlines

    • Fixed unnecessary AST iteration when no default attributes are configured

    Open source →
  52. 2.0.0-beta1 20 Jun 2021 pre-release
    Release notes

    Added

    • Added three new extensions:
    • Added new XmlRenderer to simplify AST debugging (see documentation) (#431)
    • Added the ability to configure disallowed raw HTML tags (#507)
    • Added the ability for Mentions to use multiple characters for their symbol (#514, #550)
    • Added the ability to delegate event dispatching to PSR-14 compliant event dispatcher libraries
    • Added new configuration options:
      • Added heading_permalink/min_heading_level and heading_permalink/max_heading_level options to control which headings get permalinks (#519)
      • Added heading_permalink/fragment_prefix to allow customizing the URL fragment prefix (#602)
      • Added footnote/backref_symbol option for customizing backreference link appearance (#522)
      • Added slug_normalizer/max_length option to control the maximum length of generated URL slugs
      • Added slug_normalizer/unique option to control whether unique slugs should be generated per-document or per-environment
    • Added purity markers throughout the codebase (verified with Psalm)
    • Added Query class to simplify Node traversal when looking to take action on certain Nodes
    • Added new HtmlFilter and StringContainerHelper utility classes
    • Added new AbstractBlockContinueParser class to simplify the creation of custom block parsers
    • Added several new classes and interfaces:
      • BlockContinue
      • BlockContinueParserInterface
      • BlockContinueParserWithInlinesInterface
      • BlockStart
      • BlockStartParserInterface
      • ChildNodeRendererInterface
      • ConfigurableExtensionInterface
      • CursorState
      • DashParser (extracted from PunctuationParser)
      • DelimiterParser
      • DocumentBlockParser
      • DocumentPreRenderEvent
      • DocumentRenderedEvent
      • EllipsesParser (extracted from PunctuationParser)
      • ExpressionInterface
      • FallbackNodeXmlRenderer
      • InlineParserEngineInterface
      • InlineParserMatch
      • MarkdownParserState
      • MarkdownParserStateInterface
      • MarkdownRendererInterface
      • Query
      • RawMarkupContainerInterface
      • ReferenceableInterface
      • RenderedContent
      • RenderedContentInterface
      • ReplaceUnpairedQuotesListener
      • SpecReader
      • TableOfContentsRenderer
      • UniqueSlugNormalizer
      • UniqueSlugNormalizerInterface
      • XmlRenderer
      • XmlNodeRendererInterface
    • Added several new methods:
      • Cursor::getCurrentCharacter()
      • Environment::createDefaultConfiguration()
      • Environment::setEventDispatcher()
      • EnvironmentInterface::getExtensions()
      • EnvironmentInterface::getInlineParsers()
      • EnvironmentInterface::getSlugNormalizer()
      • FencedCode::setInfo()
      • Heading::setLevel()
      • HtmlRenderer::renderDocument()
      • InlineParserContext::getFullMatch()
      • InlineParserContext::getFullMatchLength()
      • InlineParserContext::getMatches()
      • InlineParserContext::getSubMatches()
      • LinkParserHelper::parsePartialLinkLabel()
      • LinkParserHelper::parsePartialLinkTitle()
      • Node::assertInstanceOf()
      • RegexHelper::isLetter()
      • StringContainerInterface::setLiteral()
      • TableCell::getType()
      • TableCell::setType()
      • TableCell::getAlign()
      • TableCell::setAlign()

    Changed

    • Changed the converter return type
      • CommonMarkConverter::convertToHtml() now returns an instance of RenderedContentInterface. This can be cast to a string for backward compatibility with 1.x.
    • Table of Contents items are no longer wrapped with <p> tags (#613)
    • Heading Permalinks now link to element IDs instead of using name attributes (#602)
    • Heading Permalink IDs and URL fragments now have a content prefix by default (#602)
    • Changes to configuration options:
      • enable_em has been renamed to commonmark/enable_em
      • enable_strong has been renamed to commonmark/enable_strong
      • use_asterisk has been renamed to commonmark/use_asterisk
      • use_underscore has been renamed to commonmark/use_underscore
      • unordered_list_markers has been renamed to commonmark/unordered_list_markers
      • mentions/*/symbol has been renamed to mentions/*/prefix
      • mentions/*/regex has been renamed to mentions/*/pattern and requires partial regular expressions (without delimiters or flags)
      • max_nesting_level now defaults to PHP_INT_MAX and no longer supports floats
      • heading_permalink/slug_normalizer has been renamed to slug_normalizer/instance
    • Event dispatching is now fully PSR-14 compliant
    • Moved and renamed several classes - see the full list here
    • The HeadingPermalinkExtension and FootnoteExtension were modified to ensure they never produce a slug which conflicts with slugs created by the other extension
    • SlugNormalizer::normalizer() now supports optional prefixes and max length options passed in via the $context argument
    • The AbstractBlock::$data and AbstractInline::$data arrays were replaced with a Data array-like object on the base Node class
    • Implemented a new approach to block parsing. This was a massive change, so here are the highlights:
      • Functionality previously found in block parsers and node elements has moved to block parser factories and block parsers, respectively (more details)
      • ConfigurableEnvironmentInterface::addBlockParser() is now EnvironmentBuilderInterface::addBlockParserFactory()
      • ReferenceParser was re-implemented and works completely different than before
      • The paragraph parser no longer needs to be added manually to the environment
    • Implemented a new approach to inline parsing where parsers can now specify longer strings or regular expressions they want to parse (instead of just single characters):
      • InlineParserInterface::getCharacters() is now getMatchDefinition() and returns an instance of InlineParserMatch
      • InlineParserContext::__construct() now requires the contents to be provided as a Cursor instead of a string
    • Implemented delimiter parsing as a special type of inline parser (via the new DelimiterParser class)
    • Changed block and inline rendering to use common methods and interfaces
      • BlockRendererInterface and InlineRendererInterface were replaced by NodeRendererInterface with slightly different parameters. All core renderers now implement this interface.
      • ConfigurableEnvironmentInterface::addBlockRenderer() and addInlineRenderer() were combined into EnvironmentBuilderInterface::addRenderer()
      • EnvironmentInterface::getBlockRenderersForClass() and getInlineRenderersForClass() are now just getRenderersForClass()
    • Completely refactored the Configuration implementation
      • All configuration-specific classes have been moved into a new league/config package with a new namespace
      • Configuration objects must now be configured with a schema and all options must match that schema - arbitrary keys are no longer permitted
      • Configuration::__construct() no longer accepts the default configuration values - use Configuration::merge() instead
      • ConfigurationInterface now only contains a get(string $key); this method no longer allows arbitrary default values to be returned if the option is missing
      • ConfigurableEnvironmentInterface was renamed to EnvironmentBuilderInterface
      • ExtensionInterface::register() now requires an EnvironmentBuilderInterface param instead of ConfigurableEnvironmentInterface
    • Added missing return types to virtually every class and interface method
    • Re-implemented the GFM Autolink extension using the new inline parser approach instead of document processors
      • EmailAutolinkProcessor is now EmailAutolinkParser
      • UrlAutolinkProcessor is now UrlAutolinkParser
    • HtmlElement can now properly handle array (i.e. class) and boolean (i.e. checked) attribute values
    • HtmlElement automatically flattens any attributes with array values into space-separated strings, removing duplicate entries
    • Combined separate classes/interfaces into one:
      • DisallowedRawHtmlRenderer replaces DisallowedRawHtmlBlockRenderer and DisallowedRawHtmlInlineRenderer
      • NodeRendererInterface replaces BlockRendererInterface and InlineRendererInterface
    • Renamed the following methods:
      • Environment and ConfigurableEnvironmentInterface:
        • addBlockParser() is now addBlockStartParser()
      • ReferenceMap and ReferenceMapInterface:
        • addReference() is now add()
        • getReference() is now get()
        • listReferences() is now getIterator()
      • Various node (block/inline) classes:
        • getContent() is now getLiteral()
        • setContent() is now setLiteral()
    • Moved and renamed the following constants:
      • EnvironmentInterface::HTML_INPUT_ALLOW is now HtmlFilter::ALLOW
      • EnvironmentInterface::HTML_INPUT_ESCAPE is now HtmlFilter::ESCAPE
      • EnvironmentInterface::HTML_INPUT_STRIP is now HtmlFilter::STRIP
      • TableCell::TYPE_HEAD is now TableCell::TYPE_HEADER
      • TableCell::TYPE_BODY is now TableCell::TYPE_DATA
    • Changed the visibility of the following properties:
      • AttributesInline::$attributes is now private
      • AttributesInline::$block is now private
      • TableCell::$align is now private
      • TableCell::$type is now private
      • TableSection::$type is now private
    • Several methods which previously returned $this now return void
      • Delimiter::setPrevious()
      • Node::replaceChildren()
      • Context::setTip()
      • Context::setContainer()
      • Context::setBlocksParsed()
      • AbstractStringContainer::setContent()
      • AbstractWebResource::setUrl()
    • Several classes are now marked final:
      • ArrayCollection
      • Emphasis
      • FencedCode
      • Heading
      • HtmlBlock
      • HtmlElement
      • HtmlInline
      • IndentedCode
      • Newline
      • Strikethrough
      • Strong
      • Text
    • Heading nodes no longer directly contain a copy of their inner text
    • StringContainerInterface can now be used for inlines, not just blocks
    • ArrayCollection only supports integer keys
    • HtmlElement now implements Stringable
    • Cursor::saveState() and Cursor::restoreState() now use CursorState objects instead of arrays
    • NodeWalker::next() now enters, traverses any children, and leaves all elements which may have children (basically all blocks plus any inlines with children). Previously, it only did this for elements explicitly marked as "containers".
    • InvalidOptionException was removed
    • Anything with a getReference(): ReferenceInterface method now implements ReferencableInterface
    • The SmartPunct extension now replaces all unpaired Quote elements with Text elements towards the end of parsing, making the QuoteRenderer unnecessary
    • Several changes made to the Footnote extension:
      • Footnote identifiers can no longer contain spaces
      • Anonymous footnotes can now span subsequent lines
      • Footnotes can now contain multiple lines of content, including sub-blocks, by indenting them
      • Footnote event listeners now have numbered priorities (but still execute in the same order)
      • Footnotes must now be separated from previous content by a blank line
    • The line numbers (keys) returned via MarkdownInput::getLines() now start at 1 instead of 0
    • DelimiterProcessorCollectionInterface now extends Countable
    • RegexHelper::PARTIAL_ constants must always be used in case-insensitive contexts
    • HeadingPermalinkProcessor no longer accepts text normalizers via the constructor - these must be provided via configuration instead
    • Blocks which can't contain inlines will no longer be asked to render inlines
    • AnonymousFootnoteRefParser and HeadingPermalinkProcessor now implement EnvironmentAwareInterface instead of ConfigurationAwareInterface
    • The second argument to TextNormalizerInterface::normalize() must now be an array
    • The title attribute for Link and Image nodes is now stored using a dedicated property instead of stashing it in $data
    • ListData::$delimiter now returns either ListBlock::DELIM_PERIOD or ListBlock::DELIM_PAREN instead of the literal delimiter

    Fixed

    • Fixed parsing of footnotes without content
    • Fixed rendering of orphaned footnotes and footnote refs
    • Fixed some URL autolinks breaking too early (#492)
    • Fixed AbstractStringContainer not actually being abstract

    Removed

    • Removed support for PHP 7.1, 7.2, and 7.3 (#625, #671)
    • Removed all previously-deprecated functionality:
      • Removed the ability to pass custom Environment instances into the CommonMarkConverter and GithubFlavoredMarkdownConverter constructors
      • Removed the Converter class and ConverterInterface
      • Removed the bin/commonmark script
      • Removed the Html5Entities utility class
      • Removed the InlineMentionParser (use MentionParser instead)
      • Removed DefaultSlugGenerator and SlugGeneratorInterface from the Extension/HeadingPermalink/Slug sub-namespace (use the new ones under ./SlugGenerator instead)
      • Removed the following ArrayCollection methods:
        • add()
        • set()
        • get()
        • remove()
        • isEmpty()
        • contains()
        • indexOf()
        • containsKey()
        • replaceWith()
        • removeGaps()
      • Removed the ConfigurableEnvironmentInterface::setConfig() method
      • Removed the ListBlock::TYPE_UNORDERED constant
      • Removed the CommonMarkConverter::VERSION constant
      • Removed the HeadingPermalinkRenderer::DEFAULT_INNER_CONTENTS constant
      • Removed the heading_permalink/inner_contents configuration option
    • Removed now-unused classes:
      • AbstractStringContainerBlock
      • BlockRendererInterface
      • Context
      • ContextInterface
      • Converter
      • ConverterInterface
      • InlineRendererInterface
      • PunctuationParser (was split into two classes: DashParser and EllipsesParser)
      • QuoteRenderer
      • UnmatchedBlockCloser
    • Removed the following methods, properties, and constants:
      • AbstractBlock::$open
      • AbstractBlock::$lastLineBlank
      • AbstractBlock::isContainer()
      • AbstractBlock::canContain()
      • AbstractBlock::isCode()
      • AbstractBlock::matchesNextLine()
      • AbstractBlock::endsWithBlankLine()
      • AbstractBlock::setLastLineBlank()
      • AbstractBlock::shouldLastLineBeBlank()
      • AbstractBlock::isOpen()
      • AbstractBlock::finalize()
      • AbstractBlock::getData()
      • AbstractInline::getData()
      • ConfigurableEnvironmentInterface::addBlockParser()
      • ConfigurableEnvironmentInterface::mergeConfig()
      • Delimiter::setCanClose()
      • EnvironmentInterface::getConfig()
      • EnvironmentInterface::getInlineParsersForCharacter()
      • EnvironmentInterface::getInlineParserCharacterRegex()
      • HtmlRenderer::renderBlock()
      • HtmlRenderer::renderBlocks()
      • HtmlRenderer::renderInline()
      • HtmlRenderer::renderInlines()
      • Node::isContainer()
      • RegexHelper::matchAll() (use the new matchFirst() method instead)
      • RegexHelper::REGEX_WHITESPACE
    • Removed the second $contents argument from the Heading constructor

    Deprecated

    The following things have been deprecated and will not be supported in v3.0:

    • Environment::mergeConfig() (set configuration before instantiation instead)
    • Environment::createCommonMarkEnvironment() and Environment::createGFMEnvironment()
      • Alternative 1: Use CommonMarkConverter or GithubFlavoredMarkdownConverter if you don't need to customize the environment
      • Alternative 2: Instantiate a new Environment and add the necessary extensions yourself
    Open source →
    Release notes

    See https://commonmark.thephpleague.com/2.0/upgrading/ for detailed information on upgrading to version 2.0.

    Added

    • Added three new extensions:

    • FrontMatterExtension ( see documentation )

    • DescriptionListExtension ( see documentation )

    • DefaultAttributesExtension ( see documentation )

    • Added new XmlRenderer to simplify AST debugging ( see documentation ) (#431)

    • Added the ability to configure disallowed raw HTML tags (#507)

    • Added the ability for Mentions to use multiple characters for their symbol (#514, #550)

    • Added the ability to delegate event dispatching to PSR-14 compliant event dispatcher libraries

    • Added new configuration options:

    • Added heading_permalink/min_heading_level and heading_permalink/max_heading_level options to control which headings get permalinks (#519)

    • Added heading_permalink/fragment_prefix to allow customizing the URL fragment prefix (#602)

    • Added footnote/backref_symbol option for customizing backreference link appearance (#522)

    • Added slug_normalizer/max_length option to control the maximum length of generated URL slugs

    • Added slug_normalizer/unique option to control whether unique slugs should be generated per-document or per-environment

    • Added purity markers throughout the codebase (verified with Psalm)

    • Added Query class to simplify Node traversal when looking to take action on certain Nodes

    • Added new HtmlFilter and StringContainerHelper utility classes

    • Added new AbstractBlockContinueParser class to simplify the creation of custom block parsers

    • Added several new classes and interfaces:

    • BlockContinue

    • BlockContinueParserInterface

    • BlockContinueParserWithInlinesInterface

    • BlockStart

    • BlockStartParserInterface

    • ChildNodeRendererInterface

    • ConfigurableExtensionInterface

    • CursorState

    • DashParser (extracted from PunctuationParser )

    • DelimiterParser

    • DocumentBlockParser

    • DocumentPreRenderEvent

    • DocumentRenderedEvent

    • EllipsesParser (extracted from PunctuationParser )

    • ExpressionInterface

    • FallbackNodeXmlRenderer

    • InlineParserEngineInterface

    • InlineParserMatch

    • MarkdownParserState

    • MarkdownParserStateInterface

    • MarkdownRendererInterface

    • Query

    • RawMarkupContainerInterface

    • ReferenceableInterface

    • RenderedContent

    • RenderedContentInterface

    • ReplaceUnpairedQuotesListener

    • SpecReader

    • TableOfContentsRenderer

    • UniqueSlugNormalizer

    • UniqueSlugNormalizerInterface

    • XmlRenderer

    • XmlNodeRendererInterface

    • Added several new methods:

    • Cursor::getCurrentCharacter()

    • Environment::createDefaultConfiguration()

    • Environment::setEventDispatcher()

    • EnvironmentInterface::getExtensions()

    • EnvironmentInterface::getInlineParsers()

    • EnvironmentInterface::getSlugNormalizer()

    • FencedCode::setInfo()

    • Heading::setLevel()

    • HtmlRenderer::renderDocument()

    • InlineParserContext::getFullMatch()

    • InlineParserContext::getFullMatchLength()

    • InlineParserContext::getMatches()

    • InlineParserContext::getSubMatches()

    • LinkParserHelper::parsePartialLinkLabel()

    • LinkParserHelper::parsePartialLinkTitle()

    • Node::assertInstanceOf()

    • RegexHelper::isLetter()

    • StringContainerInterface::setLiteral()

    • TableCell::getType()

    • TableCell::setType()

    • TableCell::getAlign()

    • TableCell::setAlign()

    Changed

    • Changed the converter return type

    • CommonMarkConverter::convertToHtml() now returns an instance of RenderedContentInterface . This can be cast to a string for backward compatibility with 1.x.

    • Table of Contents items are no longer wrapped with <p> tags (#613)

    • Heading Permalinks now link to element IDs instead of using name attributes (#602)

    • Heading Permalink IDs and URL fragments now have a content prefix by default (#602)

    • Changes to configuration options:

    • enable_em has been renamed to commonmark/enable_em

    • enable_strong has been renamed to commonmark/enable_strong

    • use_asterisk has been renamed to commonmark/use_asterisk

    • use_underscore has been renamed to commonmark/use_underscore

    • unordered_list_markers has been renamed to commonmark/unordered_list_markers

    • mentions//symbol has been renamed to mentions//prefix

    • mentions//regex has been renamed to mentions//pattern and requires partial regular expressions (without delimiters or flags)

    • max_nesting_level now defaults to PHP_INT_MAX and no longer supports floats

    • heading_permalink/slug_normalizer has been renamed to slug_normalizer/instance

    • Event dispatching is now fully PSR-14 compliant

    • Moved and renamed several classes - see the full list here

    • The HeadingPermalinkExtension and FootnoteExtension were modified to ensure they never produce a slug which conflicts with slugs created by the other extension

    • SlugNormalizer::normalizer() now supports optional prefixes and max length options passed in via the $context argument

    • The AbstractBlock::$data and AbstractInline::$data arrays were replaced with a Data array-like object on the base Node class

    • Implemented a new approach to block parsing. This was a massive change, so here are the highlights:

    • Functionality previously found in block parsers and node elements has moved to block parser factories and block parsers, respectively ( more details )

    • ConfigurableEnvironmentInterface::addBlockParser() is now EnvironmentBuilderInterface::addBlockParserFactory()

    • ReferenceParser was re-implemented and works completely different than before

    • The paragraph parser no longer needs to be added manually to the environment

    • Implemented a new approach to inline parsing where parsers can now specify longer strings or regular expressions they want to parse (instead of just single characters):

    • InlineParserInterface::getCharacters() is now getMatchDefinition() and returns an instance of InlineParserMatch

    • InlineParserContext::__construct() now requires the contents to be provided as a Cursor instead of a string

    • Implemented delimiter parsing as a special type of inline parser (via the new DelimiterParser class)

    • Changed block and inline rendering to use common methods and interfaces

    • BlockRendererInterface and InlineRendererInterface were replaced by NodeRendererInterface with slightly different parameters. All core renderers now implement this interface.

    • ConfigurableEnvironmentInterface::addBlockRenderer() and addInlineRenderer() were combined into EnvironmentBuilderInterface::addRenderer()

    • EnvironmentInterface::getBlockRenderersForClass() and getInlineRenderersForClass() are now just getRenderersForClass()

    • Completely refactored the Configuration implementation

    • All configuration-specific classes have been moved into a new league/config package with a new namespace

    • Configuration objects must now be configured with a schema and all options must match that schema - arbitrary keys are no longer permitted

    • Configuration::__construct() no longer accepts the default configuration values - use Configuration::merge() instead

    • ConfigurationInterface now only contains a get(string $key) ; this method no longer allows arbitrary default values to be returned if the option is missing

    • ConfigurableEnvironmentInterface was renamed to EnvironmentBuilderInterface

    • ExtensionInterface::register() now requires an EnvironmentBuilderInterface param instead of ConfigurableEnvironmentInterface

    • Added missing return types to virtually every class and interface method

    • Re-implemented the GFM Autolink extension using the new inline parser approach instead of document processors

    • EmailAutolinkProcessor is now EmailAutolinkParser

    • UrlAutolinkProcessor is now UrlAutolinkParser

    • HtmlElement can now properly handle array (i.e. class ) and boolean (i.e. checked ) attribute values

    • HtmlElement automatically flattens any attributes with array values into space-separated strings, removing duplicate entries

    • Combined separate classes/interfaces into one:

    • DisallowedRawHtmlRenderer replaces DisallowedRawHtmlBlockRenderer and DisallowedRawHtmlInlineRenderer

    • NodeRendererInterface replaces BlockRendererInterface and InlineRendererInterface

    • Renamed the following methods:

    • Environment and ConfigurableEnvironmentInterface :

    • addBlockParser() is now addBlockStartParser()

    • ReferenceMap and ReferenceMapInterface :

    • addReference() is now add()

    • getReference() is now get()

    • listReferences() is now getIterator()

    • Various node (block/inline) classes:

    • getContent() is now getLiteral()

    • setContent() is now setLiteral()

    • Moved and renamed the following constants:

    • EnvironmentInterface::HTML_INPUT_ALLOW is now HtmlFilter::ALLOW

    • EnvironmentInterface::HTML_INPUT_ESCAPE is now HtmlFilter::ESCAPE

    • EnvironmentInterface::HTML_INPUT_STRIP is now HtmlFilter::STRIP

    • TableCell::TYPE_HEAD is now TableCell::TYPE_HEADER

    • TableCell::TYPE_BODY is now TableCell::TYPE_DATA

    • Changed the visibility of the following properties:

    • AttributesInline::$attributes is now private

    • AttributesInline::$block is now private

    • TableCell::$align is now private

    • TableCell::$type is now private

    • TableSection::$type is now private

    • Several methods which previously returned $this now return void

    • Delimiter::setPrevious()

    • Node::replaceChildren()

    • Context::setTip()

    • Context::setContainer()

    • Context::setBlocksParsed()

    • AbstractStringContainer::setContent()

    • AbstractWebResource::setUrl()

    • Several classes are now marked final :

    • ArrayCollection

    • Emphasis

    • FencedCode

    • Heading

    • HtmlBlock

    • HtmlElement

    • HtmlInline

    • IndentedCode

    • Newline

    • Strikethrough

    • Strong

    • Text

    • Heading nodes no longer directly contain a copy of their inner text

    • StringContainerInterface can now be used for inlines, not just blocks

    • ArrayCollection only supports integer keys

    • HtmlElement now implements Stringable

    • Cursor::saveState() and Cursor::restoreState() now use CursorState objects instead of arrays

    • NodeWalker::next() now enters, traverses any children, and leaves all elements which may have children (basically all blocks plus any inlines with children). Previously, it only did this for elements explicitly marked as “containers”.

    • InvalidOptionException was removed

    • Anything with a getReference(): ReferenceInterface method now implements ReferencableInterface

    • The SmartPunct extension now replaces all unpaired Quote elements with Text elements towards the end of parsing, making the QuoteRenderer unnecessary

    • Several changes made to the Footnote extension:

    • Footnote identifiers can no longer contain spaces

    • Anonymous footnotes can now span subsequent lines

    • Footnotes can now contain multiple lines of content, including sub-blocks, by indenting them

    • Footnote event listeners now have numbered priorities (but still execute in the same order)

    • Footnotes must now be separated from previous content by a blank line

    • The line numbers (keys) returned via MarkdownInput::getLines() now start at 1 instead of 0

    • DelimiterProcessorCollectionInterface now extends Countable

    • RegexHelper::PARTIAL_ constants must always be used in case-insensitive contexts

    • HeadingPermalinkProcessor no longer accepts text normalizers via the constructor - these must be provided via configuration instead

    • Blocks which can’t contain inlines will no longer be asked to render inlines

    • AnonymousFootnoteRefParser and HeadingPermalinkProcessor now implement EnvironmentAwareInterface instead of ConfigurationAwareInterface

    • The second argument to TextNormalizerInterface::normalize() must now be an array

    • The title attribute for Link and Image nodes is now stored using a dedicated property instead of stashing it in $data

    • ListData::$delimiter now returns either ListBlock::DELIM_PERIOD or ListBlock::DELIM_PAREN instead of the literal delimiter

    Fixed

    • Fixed parsing of footnotes without content

    • Fixed rendering of orphaned footnotes and footnote refs

    • Fixed some URL autolinks breaking too early (#492)

    • Fixed AbstractStringContainer not actually being abstract

    Removed

    • Removed support for PHP 7.1, 7.2, and 7.3 (#625, #671)

    • Removed all previously-deprecated functionality:

    • Removed the ability to pass custom Environment instances into the CommonMarkConverter and GithubFlavoredMarkdownConverter constructors

    • Removed the Converter class and ConverterInterface

    • Removed the bin/commonmark script

    • Removed the Html5Entities utility class

    • Removed the InlineMentionParser (use MentionParser instead)

    • Removed DefaultSlugGenerator and SlugGeneratorInterface from the Extension/HeadingPermalink/Slug sub-namespace (use the new ones under ./SlugGenerator instead)

    • Removed the following ArrayCollection methods:

    • add()

    • set()

    • get()

    • remove()

    • isEmpty()

    • contains()

    • indexOf()

    • containsKey()

    • replaceWith()

    • removeGaps()

    • Removed the ConfigurableEnvironmentInterface::setConfig() method

    • Removed the ListBlock::TYPE_UNORDERED constant

    • Removed the CommonMarkConverter::VERSION constant

    • Removed the HeadingPermalinkRenderer::DEFAULT_INNER_CONTENTS constant

    • Removed the heading_permalink/inner_contents configuration option

    • Removed now-unused classes:

    • AbstractStringContainerBlock

    • BlockRendererInterface

    • Context

    • ContextInterface

    • Converter

    • ConverterInterface

    • InlineRendererInterface

    • PunctuationParser (was split into two classes: DashParser and EllipsesParser )

    • QuoteRenderer

    • UnmatchedBlockCloser

    • Removed the following methods, properties, and constants:

    • AbstractBlock::$open

    • AbstractBlock::$lastLineBlank

    • AbstractBlock::isContainer()

    • AbstractBlock::canContain()

    • AbstractBlock::isCode()

    • AbstractBlock::matchesNextLine()

    • AbstractBlock::endsWithBlankLine()

    • AbstractBlock::setLastLineBlank()

    • AbstractBlock::shouldLastLineBeBlank()

    • AbstractBlock::isOpen()

    • AbstractBlock::finalize()

    • AbstractBlock::getData()

    • AbstractInline::getData()

    • ConfigurableEnvironmentInterface::addBlockParser()

    • ConfigurableEnvironmentInterface::mergeConfig()

    • Delimiter::setCanClose()

    • EnvironmentInterface::getConfig()

    • EnvironmentInterface::getInlineParsersForCharacter()

    • EnvironmentInterface::getInlineParserCharacterRegex()

    • HtmlRenderer::renderBlock()

    • HtmlRenderer::renderBlocks()

    • HtmlRenderer::renderInline()

    • HtmlRenderer::renderInlines()

    • Node::isContainer()

    • RegexHelper::matchAll() (use the new matchFirst() method instead)

    • RegexHelper::REGEX_WHITESPACE

    • Removed the second $contents argument from the Heading constructor

    Deprecated

    The following things have been deprecated and will not be supported in v3.0:

    • Environment::mergeConfig() (set configuration before instantiation instead)

    • Environment::createCommonMarkEnvironment() and Environment::createGFMEnvironment()

    • Alternative 1: Use CommonMarkConverter or GithubFlavoredMarkdownConverter if you don’t need to customize the environment

    • Alternative 2: Instantiate a new Environment and add the necessary extensions yourself

    Open source →
  53. 1.6.7 13 Jan 2022
    Release notes

    Changed

    • Added ReturnTypeWillChange attribute to prevent PHP 8.1 deprecation warnings (#785)

    • Coerced punctuation counts to integers to ensure floats are never used

    Open source →
  54. 1.6.6 17 Jul 2021
    Release notes

    Fixed

    • Fixed Mentions inside of links creating nested links against the spec’s rules (#688)
    Open source →
  55. 1.6.5 26 Jun 2021
    Release notes

    Changed

    • Simplified checks for thematic breaks

    Fixed

    • Fixed ExternalLinkProcessor not handling autolinks by adjusting its priority to -50 (#681)
    Open source →
  56. 1.6.4 19 Jun 2021
    Release notes

    Changed

    • Optimized attribute parsing to avoid inspecting every space character (30% performance boost)
    Open source →
  57. 1.6.3 19 Jun 2021
    Release notes

    Fixed

    • Fixed incorrect parsing of tilde-fenced code blocks with leading spaces (#676)
    Open source →
  58. 1.6.2 12 May 2021
    Release notes

    Fixed

    • Fixed incorrect error level for deprecation notices
    Open source →
  59. 1.6.1 08 May 2021
    Release notes

    Fixed

    • Fixed HeadingPermalinkProcessor skipping text contents from certain nodes (#615)
    Open source →
  60. 1.6.0 01 May 2021
    Release notes

    Please see https://commonmark.thephpleague.com/1.6/upgrading/ for important information about this release and the upcoming 2.0.0 version.

    Added

    • 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

    Changed

    • The max_nesting_level option now defaults to PHP_INT_MAX instead of INF

    Deprecated

    • 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

    • Fixed missing check for empty arrays being passed into the unordered_list_markers configuration option
    Open source →

Every package, every release, already written down.

The archive is open and free. Watching your own project is what we are building next.

Browse the archive