164 lines
4.7 KiB
PHP
164 lines
4.7 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace KbMarkdownImporter\Frontend;
|
|
|
|
use KbMarkdownImporter\Plugin;
|
|
|
|
final class UrlBuilder
|
|
{
|
|
private static string $embedBaseUrl = '';
|
|
|
|
public static function beginEmbed(string $baseUrl): void
|
|
{
|
|
self::$embedBaseUrl = remove_query_arg(['kb_docs_route', 'kb_docs_product', 'kb_docs_version', 'kb_docs_page'], $baseUrl);
|
|
}
|
|
|
|
public static function endEmbed(): void
|
|
{
|
|
self::$embedBaseUrl = '';
|
|
}
|
|
|
|
public static function isEmbed(): bool
|
|
{
|
|
return '' !== self::$embedBaseUrl;
|
|
}
|
|
|
|
public static function docsIndex(): string
|
|
{
|
|
return self::route('index');
|
|
}
|
|
|
|
public static function product(string $productSlug): string
|
|
{
|
|
return self::route('product', $productSlug);
|
|
}
|
|
|
|
public static function version(string $productSlug, string $versionSlug): string
|
|
{
|
|
return self::route('version', $productSlug, $versionSlug);
|
|
}
|
|
|
|
public static function page(string $productSlug, string $versionSlug, string $pageSlug = ''): string
|
|
{
|
|
return self::route('page', $productSlug, $versionSlug, $pageSlug);
|
|
}
|
|
|
|
private static function route(string $route, string $productSlug = '', string $versionSlug = '', string $pageSlug = ''): string
|
|
{
|
|
if (self::isEmbed()) {
|
|
$args = ['kb_docs_route' => $route];
|
|
|
|
if ($productSlug) {
|
|
$args['kb_docs_product'] = $productSlug;
|
|
}
|
|
|
|
if ($versionSlug) {
|
|
$args['kb_docs_version'] = $versionSlug;
|
|
}
|
|
|
|
if ($pageSlug) {
|
|
$args['kb_docs_page'] = $pageSlug;
|
|
}
|
|
|
|
return add_query_arg($args, self::$embedBaseUrl);
|
|
}
|
|
|
|
$base = trim((string) Plugin::settings()['docs_base_slug'], '/') ?: 'docs';
|
|
|
|
if (self::supportsPrettyPermalinks()) {
|
|
$parts = array_filter([$base, $productSlug, $versionSlug, $pageSlug], static fn (string $part): bool => '' !== $part);
|
|
return home_url('/' . implode('/', array_map('rawurlencode', $parts)) . '/');
|
|
}
|
|
|
|
$args = ['kb_markdown_route' => $route];
|
|
|
|
if ($productSlug) {
|
|
$args['kb_product_slug'] = $productSlug;
|
|
}
|
|
|
|
if ($versionSlug) {
|
|
$args['kb_version_slug'] = $versionSlug;
|
|
}
|
|
|
|
if ($pageSlug) {
|
|
$args['kb_page_slug'] = $pageSlug;
|
|
}
|
|
|
|
return add_query_arg($args, home_url('/'));
|
|
}
|
|
|
|
private static function supportsPrettyPermalinks(): bool
|
|
{
|
|
return '' !== (string) get_option('permalink_structure', '');
|
|
}
|
|
|
|
public static function rewriteHtml(string $html): string
|
|
{
|
|
if (! self::isEmbed()) {
|
|
return $html;
|
|
}
|
|
|
|
return preg_replace_callback('/href=(["\'])([^"\']+)\1/i', static function (array $matches): string {
|
|
$url = html_entity_decode((string) $matches[2], ENT_QUOTES);
|
|
$replacement = self::rewriteUrl($url);
|
|
|
|
if (! $replacement) {
|
|
return $matches[0];
|
|
}
|
|
|
|
return 'href=' . $matches[1] . esc_url($replacement) . $matches[1];
|
|
}, $html) ?? $html;
|
|
}
|
|
|
|
private static function rewriteUrl(string $url): string
|
|
{
|
|
$parts = wp_parse_url($url);
|
|
|
|
if (! is_array($parts)) {
|
|
return '';
|
|
}
|
|
|
|
$query = [];
|
|
if (! empty($parts['query'])) {
|
|
wp_parse_str((string) $parts['query'], $query);
|
|
}
|
|
|
|
if (! empty($query['kb_markdown_route'])) {
|
|
return self::route(
|
|
sanitize_key((string) $query['kb_markdown_route']),
|
|
sanitize_title((string) ($query['kb_product_slug'] ?? '')),
|
|
sanitize_title((string) ($query['kb_version_slug'] ?? '')),
|
|
sanitize_title((string) ($query['kb_page_slug'] ?? ''))
|
|
);
|
|
}
|
|
|
|
$base = trim((string) Plugin::settings()['docs_base_slug'], '/') ?: 'docs';
|
|
$path = trim((string) ($parts['path'] ?? ''), '/');
|
|
|
|
if ($path === $base) {
|
|
return self::docsIndex();
|
|
}
|
|
|
|
if (! str_starts_with($path . '/', $base . '/')) {
|
|
return '';
|
|
}
|
|
|
|
$routeParts = array_values(array_filter(explode('/', substr($path, strlen($base))), static fn (string $part): bool => '' !== $part));
|
|
|
|
if (1 === count($routeParts)) {
|
|
return self::product(sanitize_title($routeParts[0]));
|
|
}
|
|
|
|
if (2 === count($routeParts)) {
|
|
return self::version(sanitize_title($routeParts[0]), sanitize_title($routeParts[1]));
|
|
}
|
|
|
|
return self::page(
|
|
sanitize_title($routeParts[0] ?? ''),
|
|
sanitize_title($routeParts[1] ?? ''),
|
|
sanitize_title(implode('/', array_slice($routeParts, 2)))
|
|
);
|
|
}
|
|
}
|