' . $this->renderInline(trim(implode(' ', $paragraph)), $context) . '
'; $paragraph = []; }; $closeList = function () use (&$html, &$listType): void { if ('' === $listType) { return; } $html[] = '' . $listType . '>'; $listType = ''; }; foreach ($lines as $line) { if (preg_match('/^\s*```/', $line)) { if ($codeFence) { $html[] = '' . esc_html(implode("\n", $code)) . '';
$code = [];
$codeFence = false;
} else {
$flushParagraph();
$closeList();
$codeFence = true;
}
continue;
}
if ($codeFence) {
$code[] = $line;
continue;
}
if ('' === trim($line)) {
$flushParagraph();
$closeList();
continue;
}
if (preg_match('/^(#{1,6})\s+(.+)$/', $line, $matches)) {
$flushParagraph();
$closeList();
$level = strlen($matches[1]);
$text = trim($matches[2]);
$id = sanitize_title(wp_strip_all_tags($text));
$html[] = sprintf(''; continue; } $paragraph[] = trim($line); } if ($codeFence) { $html[] = '' . $this->renderInline(trim($matches[1]), $context) . '
' . esc_html(implode("\n", $code)) . '';
}
$flushParagraph();
$closeList();
return wp_kses_post(implode("\n", $html));
}
private function renderInline(string $text, array $context): string
{
$escaped = esc_html($text);
$escaped = preg_replace_callback('/!\[([^\]]*)\]\(([^)]+)\)/', function (array $matches) use ($context): string {
$alt = html_entity_decode($matches[1], ENT_QUOTES);
$src = html_entity_decode($matches[2], ENT_QUOTES);
$url = $this->resolveImageUrl($src, (array) ($context['images'] ?? []));
$image = sprintf('$1', $escaped) ?? $escaped;
$escaped = preg_replace('/\*\*([^*]+)\*\*/', '$1', $escaped) ?? $escaped;
$escaped = preg_replace('/\*([^*]+)\*/', '$1', $escaped) ?? $escaped;
return $escaped;
}
private function rewriteLink(string $href, array $context): string
{
if ('' === $href || str_starts_with($href, '#') || preg_match('#^(?:https?:|mailto:|tel:)#i', $href)) {
return '';
}
$parts = wp_parse_url($href);
if (! is_array($parts)) {
return '';
}
$path = (string) ($parts['path'] ?? '');
if (! preg_match('/\.md$/i', $path)) {
return '';
}
$page = preg_replace('/\.md$/i', '', basename($path)) ?: basename($path);
$slug = in_array(strtolower($page), ['doku', 'index'], true) ? '' : sanitize_title($page);
$fragment = isset($parts['fragment']) ? '#' . sanitize_title((string) $parts['fragment']) : '';
return UrlBuilder::page((string) $context['product_slug'], (string) $context['version_slug'], $slug) . $fragment;
}
private function resolveImageUrl(string $src, array $images): string
{
if ('' === $src || preg_match('#^(?:https?:|data:)#i', $src)) {
return '';
}
$candidates = array_unique([
$src,
ltrim($src, '/'),
basename($src),
preg_replace('#^images/#', '', $src) ?: $src,
]);
foreach ($candidates as $candidate) {
if (isset($images[$candidate])) {
return (string) $images[$candidate];
}
}
return '';
}
}