diff --git a/modules/cms/classes/Content.php b/modules/cms/classes/Content.php index 41d3a845e7..be1a0db07a 100644 --- a/modules/cms/classes/Content.php +++ b/modules/cms/classes/Content.php @@ -1,7 +1,9 @@ -markup); break; case 'md': - $result = Markdown::parse($this->markup); + $result = $this->parseMarkdownMarkup($this->markup); break; default: $result = $this->markup; @@ -70,4 +72,38 @@ public function parseMarkup() return $result; } + + /** + * Parse Markdown content files. + * + * This method replaces curly variables in the content temporarily while Markdown rendering takes place, to + * circumvent the escaping that Commonmark does on curly brackets in links. + * + * @param string $markup + * @return string + */ + protected function parseMarkdownMarkup(string $markup): string + { + /** + * Replace variables temporarily for Markdown parsing, as the Commonmark library escapes curly brackets in + * links. + * @see https://github.com/wintercms/winter/issues/992 + */ + $variables = []; + $markup = preg_replace_callback('/\{([^\n \}]+)\}/', function (array $matches) use (&$variables) { + $signature = hash('sha256', $matches[1]); + if (!array_key_exists($signature, $variables)) { + $variables[$signature] = $matches[1]; + } + return ".=VAR={$signature}=."; + }, $markup); + + $markup = Markdown::parse($markup); + + foreach ($variables as $signature => $variable) { + $markup = str_replace(".=VAR={$signature}=.", "{{$variable}}", $markup); + } + + return $markup; + } }