Generated from MDParser.php's actual implementation as of today's GFM-conformance pass. Every row below is something the parser genuinely handles, not aspirational.
Before posting any part of this document to the forum: SMF has no automatic escaping for text that merely looks like BBCode. A literal
[md]typed or pasted into a normal post is a real tag-open, not example text — and since it's registered asunparsed_content, everything after it gets swallowed until a matching[/md](or the rest of the post just disappears into the block). Backticks/code formatting do not protect against this — that's a markdown convention, meaningless to SMF's BBC parser, which runs before markdown rendering ever happens. Wrap any literal[md]/[/md]in[nobbc]...[/nobbc], or HTML-entity-encode the brackets ([md]), before posting.
Forum BBC policy: all standard BBCode tags are disabled on this forum except
[nobbc](kept enabled/exempt — it's the escape hatch that makes the warning above possible to follow) and[md]itself (the tag this whole document is about). Every other bracket-tag typed in a post is inert, literal text.
| Element | Raw source (unrendered) | Rendered output |
|---|---|---|
| Heading (ATX) | # H1 … ###### H6 |
<h1>H1</h1> … <h6>H6</h6> |
| Heading (Setext) | Title\n===== / Title\n----- |
<h1>Title</h1> / <h2>Title</h2> |
| Bold | **bold** or __bold__ |
<strong>bold</strong> |
| Italic | *italic* or _italic_ |
<em>italic</em> |
| Bold + italic | ***both*** or ___both___ |
<em><strong>both</strong></em> |
| Strikethrough | ~~struck~~ |
<del>struck</del> |
| Inline code | `code` |
<code>code</code> |
| Inline code (contains a backtick) | code with inside` `` |
<code>code with inside</code>` |
| Fenced code block | ``php/ code / ` (also~~~`) |
<pre class="md-code-block"><code class="language-php">...</code></pre> (the class="language-X" only appears when a language is specified after the fence) |
| Indented code block | 4 spaces or a tab before each line (blank lines inside stay part of the same block) | <pre class="md-code-block"><code>...</code></pre> |
| Blockquote | > quoted (nested: >> quoted) |
<blockquote><p>quoted</p></blockquote> |
| Unordered list (tight) | - item / * item / + item |
<ul><li>item</li></ul> |
| Unordered list (loose — blank line between items) | - one\n\n- two |
<ul><li><p>one</p></li><li><p>two</p></li></ul> |
| Ordered list | 1. item or 1) item |
<ol><li>item</li></ol> |
| Ordered list, custom start | 7. item |
<ol start="7"><li>item</li></ol> |
| List marker change starts a new list | - foo\n- bar\n+ baz |
two separate <ul> elements (different bullet char = different list) |
| Ordered list can't interrupt a paragraph unless it starts at 1 | Some text\n14. more text |
stays one <p>, not a <p> + <ol start="14"> |
| Empty list item (bare marker, nothing after it) | - alone on a line |
<ul><li></li></ul> |
| Link | [text](url "title") |
<a href="url" title="title" rel="noopener noreferrer nofollow">text</a> |
| Link title, alternative delimiters | [text](url 'title') or [text](url (title)) |
same as above |
| Link text with nested brackets | [link [foo] bar](url) |
<a href="url">link [foo] bar</a> |
| Link, empty URL | [text]() |
<a href="">text</a> |
| Link, angle-bracket destination (allows spaces) | [text](<my file.pdf>) |
<a href="my%20file.pdf">text</a> |
| Link destination, balanced parens | [text](foo(and(bar))) |
<a href="foo(and(bar))">text</a> |
| Link destination, percent-encoding | [text](foo bä) |
<a href="foo%20b%C3%A4">text</a> (HTML entities decoded, then unsafe bytes percent-encoded; existing %XX sequences left alone) |
| Image |  |
<img src="url" alt="alt" title="title"> |
| Autolink (angle brackets) | <https://example.com> or <user@example.com> |
<a href="https://example.com" rel="noopener noreferrer nofollow">https://example.com</a> (mailto autolinks omit rel) |
| Bare URL autolink (GFM ext.) | plain https://example.com in running text |
auto-linked, trailing .,!?: etc. left outside the link |
Bare www. autolink (GFM ext.) |
plain www.example.com in running text |
linked with href="http://www.example.com" |
| Bare email autolink (GFM ext.) | plain name@example.com in running text |
<a href="mailto:name@example.com">name@example.com</a> |
| Horizontal rule | ---, ***, or ___ alone on a line |
<hr> |
| Hard line break | line ending in two trailing spaces | <br> |
| Paragraph break | blank line between blocks | separate <p> elements |
| Escaping | 0not italic1 — any ASCII punctuation character can be escaped this way, not just markdown-syntax ones |
*not italic* (literal) |
| GFM table | <code>| a | b |<br>|---|---:|<br>| 1 | 2 |</code> | <table class="md-table"> with style="text-align:right" etc. from the :---/---:/:---: header row |
| Element | Raw source (unrendered) | Rendered output |
|---|---|---|
| Wikipedia link | {wiki:Article Name} |
<a href="https://en.wikipedia.org/wiki/Article_Name" rel="noopener noreferrer nofollow">Article Name</a> — same tab, no target="_blank" |
Everything the parser doesn't do, grouped by why — because "not spec-complete" covers two very different situations: things we chose not to build, and things security requires us not to build.
| Excluded | Reason |
|---|---|
| Raw HTML blocks (multi-line embedded HTML in a post) | The mod's entire security model is "escape everything on input, then selectively re-decode only what's explicitly recognized as markdown syntax." Parsing raw HTML blocks back into the page means accepting arbitrary user-supplied HTML — exactly the attack surface the last external security review closed (the stored-XSS-via-code-span and control-character URL bypass findings). Re-opening this for GFM conformance would undo that work. |
Autolinking arbitrary URI schemes (<irc://...>, <made-up-scheme://...>) |
isSafeUrl() only allows http, https, ftp, ftps, mailto. CommonMark's actual rule permits any scheme matching [a-zA-Z][a-zA-Z0-9+.-]{1,31}: — a superset that, unfiltered, would also cover javascript:, data:, vbscript:. Broadening the allowlist to add specific safe schemes (irc://, magnet:, etc.) is a legitimate future option, but it's a deliberate allowlist decision to make each time, not something that should get widened automatically in the name of spec coverage. |
| Excluded | Reason |
|---|---|
Reference-style links [text][ref] + [ref]: url |
Adds a second-pass resolution step for a syntax forum posters essentially never use |
| Footnotes | Same reasoning as reference-style links |
Task-list checkboxes - [ ] |
Low forum-relevance extension |
[link](<foo\nbar>), which per spec should not be a valid link) currently isn't rejected — a structural side-effect of paragraph line-joining happening at the block level before this inline check can see the newline.> quote) isn't tracked precisely — ordinary paragraph laziness is handled correctly.__foo, __bar__, baz__) where our output disagrees with the npm commonmark reference package but matches the literal cmark-gfm spec.txt expectation — a documented gray area, not chased further.