update
This commit is contained in:
@@ -15,6 +15,114 @@
|
||||
padding: 24px 20px 48px;
|
||||
}
|
||||
|
||||
.kb-docs-app {
|
||||
display: grid;
|
||||
grid-template-columns: 320px minmax(0, 1fr);
|
||||
gap: 32px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.kb-app-sidebar {
|
||||
position: sticky;
|
||||
top: 24px;
|
||||
max-height: calc(100vh - 48px);
|
||||
overflow: auto;
|
||||
border: 1px solid var(--kb-border);
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
background: var(--kb-surface);
|
||||
}
|
||||
|
||||
.kb-app-sidebar__brand {
|
||||
margin-bottom: 14px;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.kb-app-sidebar__brand a {
|
||||
color: var(--kb-text);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.kb-app-sidebar__search {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.kb-app-sidebar__search .kb-search {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.kb-app-sidebar__search .kb-search h2,
|
||||
.kb-app-sidebar__search .kb-search-results {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.kb-app-nav,
|
||||
.kb-app-nav ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.kb-app-product {
|
||||
padding: 10px 0;
|
||||
border-top: 1px solid var(--kb-border);
|
||||
}
|
||||
|
||||
.kb-app-product:first-child {
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
.kb-app-product__link,
|
||||
.kb-app-version-list a,
|
||||
.kb-app-page-list a {
|
||||
display: block;
|
||||
border-radius: 6px;
|
||||
color: var(--kb-text);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.kb-app-product__link {
|
||||
padding: 8px 10px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.kb-app-version-list a {
|
||||
padding: 6px 10px 6px 22px;
|
||||
color: var(--kb-muted);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.kb-app-page-list a {
|
||||
padding: 5px 10px 5px 36px;
|
||||
color: var(--kb-muted);
|
||||
font-size: 13px;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.kb-app-product__link:hover,
|
||||
.kb-app-version-list a:hover,
|
||||
.kb-app-page-list a:hover,
|
||||
.kb-app-product.is-active > .kb-app-product__link,
|
||||
.kb-app-version-list li.is-active > a,
|
||||
.kb-app-page-list li.is-active > a {
|
||||
background: var(--kb-accent-soft);
|
||||
color: var(--kb-accent);
|
||||
}
|
||||
|
||||
.kb-app-main {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.kb-docs-home > h1,
|
||||
.kb-docs-product > h1,
|
||||
.kb-docs-version > h1 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.kb-product-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
@@ -195,6 +303,15 @@
|
||||
}
|
||||
|
||||
@media (max-width: 780px) {
|
||||
.kb-docs-app {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.kb-app-sidebar {
|
||||
position: static;
|
||||
max-height: none;
|
||||
}
|
||||
|
||||
.kb-doc-layout {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
@@ -68,12 +68,38 @@
|
||||
}
|
||||
|
||||
.kb-product-card,
|
||||
.kb-search {
|
||||
.kb-search,
|
||||
.kb-app-sidebar {
|
||||
border-radius: var(--kb-radius);
|
||||
border-color: var(--kb-border);
|
||||
box-shadow: var(--kb-shadow);
|
||||
}
|
||||
|
||||
.kb-app-sidebar {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
}
|
||||
|
||||
.kb-app-sidebar__brand a {
|
||||
font-family: var(--kb-font-strong);
|
||||
color: var(--kb-text);
|
||||
}
|
||||
|
||||
.kb-app-product__link,
|
||||
.kb-app-version-list a,
|
||||
.kb-app-page-list a {
|
||||
border-radius: 11px;
|
||||
}
|
||||
|
||||
.kb-app-product__link:hover,
|
||||
.kb-app-version-list a:hover,
|
||||
.kb-app-page-list a:hover,
|
||||
.kb-app-product.is-active > .kb-app-product__link,
|
||||
.kb-app-version-list li.is-active > a,
|
||||
.kb-app-page-list li.is-active > a {
|
||||
background: rgba(0, 167, 230, 0.12);
|
||||
color: var(--kb-primary-shade);
|
||||
}
|
||||
|
||||
.kb-product-card h2 a {
|
||||
color: var(--kb-text);
|
||||
text-decoration: none;
|
||||
|
||||
125
kb-markdown-importer/includes/Admin/ProductsPage.php
Normal file
125
kb-markdown-importer/includes/Admin/ProductsPage.php
Normal file
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace KbMarkdownImporter\Admin;
|
||||
|
||||
use KbMarkdownImporter\Repository\ProductRepository;
|
||||
|
||||
final class ProductsPage
|
||||
{
|
||||
public static function render(): void
|
||||
{
|
||||
if (! current_user_can('manage_kb_docs')) {
|
||||
wp_die(esc_html__('You do not have permission to manage documentation products.', 'kb-markdown-importer'));
|
||||
}
|
||||
|
||||
$repository = new ProductRepository();
|
||||
self::handleActions($repository);
|
||||
$products = $repository->allWithStats();
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php esc_html_e('Documentation Products', 'kb-markdown-importer'); ?></h1>
|
||||
<p><?php esc_html_e('Manage imported products, repair their URL slugs, or remove a broken import from the frontend.', 'kb-markdown-importer'); ?></p>
|
||||
<?php settings_errors('kb_markdown_products'); ?>
|
||||
|
||||
<table class="widefat striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php esc_html_e('Product', 'kb-markdown-importer'); ?></th>
|
||||
<th><?php esc_html_e('Slug', 'kb-markdown-importer'); ?></th>
|
||||
<th><?php esc_html_e('Versions', 'kb-markdown-importer'); ?></th>
|
||||
<th><?php esc_html_e('Pages', 'kb-markdown-importer'); ?></th>
|
||||
<th><?php esc_html_e('Actions', 'kb-markdown-importer'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (! $products) : ?>
|
||||
<tr><td colspan="5"><?php esc_html_e('No products have been imported yet.', 'kb-markdown-importer'); ?></td></tr>
|
||||
<?php endif; ?>
|
||||
<?php foreach ($products as $item) : ?>
|
||||
<?php
|
||||
$term = $item['term'];
|
||||
$formId = 'kb-markdown-product-' . (int) $term->term_id;
|
||||
$versions = array_map(static fn (\WP_Term $version): string => $version->name, (array) $item['versions']);
|
||||
?>
|
||||
<tr>
|
||||
<td>
|
||||
<input form="<?php echo esc_attr($formId); ?>" class="regular-text" type="text" name="product_name" value="<?php echo esc_attr($term->name); ?>" aria-label="<?php esc_attr_e('Product name', 'kb-markdown-importer'); ?>">
|
||||
</td>
|
||||
<td>
|
||||
<input form="<?php echo esc_attr($formId); ?>" class="regular-text" type="text" name="product_slug" value="<?php echo esc_attr($term->slug); ?>" aria-label="<?php esc_attr_e('Product slug', 'kb-markdown-importer'); ?>">
|
||||
</td>
|
||||
<td><?php echo esc_html($versions ? implode(', ', $versions) : __('No versions', 'kb-markdown-importer')); ?></td>
|
||||
<td><?php echo esc_html((string) $item['page_count']); ?></td>
|
||||
<td>
|
||||
<form id="<?php echo esc_attr($formId); ?>" method="post" action="">
|
||||
<?php wp_nonce_field('kb_markdown_update_product_' . $term->term_id); ?>
|
||||
<input type="hidden" name="kb_markdown_product_action" value="update">
|
||||
<input type="hidden" name="term_id" value="<?php echo esc_attr((string) $term->term_id); ?>">
|
||||
<?php submit_button(__('Save', 'kb-markdown-importer'), 'secondary small', 'submit', false); ?>
|
||||
</form>
|
||||
<form method="post" action="" style="margin-top:8px;" onsubmit="return window.confirm('<?php echo esc_js(__('Move this product and its imported pages to the trash?', 'kb-markdown-importer')); ?>');">
|
||||
<?php wp_nonce_field('kb_markdown_delete_product_' . $term->term_id); ?>
|
||||
<input type="hidden" name="kb_markdown_product_action" value="delete">
|
||||
<input type="hidden" name="term_id" value="<?php echo esc_attr((string) $term->term_id); ?>">
|
||||
<label>
|
||||
<input type="checkbox" name="trash_pages" value="1" checked>
|
||||
<?php esc_html_e('Trash imported pages', 'kb-markdown-importer'); ?>
|
||||
</label>
|
||||
<?php submit_button(__('Delete product', 'kb-markdown-importer'), 'delete small', 'submit', false); ?>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
private static function handleActions(ProductRepository $repository): void
|
||||
{
|
||||
$action = sanitize_key(wp_unslash((string) ($_POST['kb_markdown_product_action'] ?? '')));
|
||||
|
||||
if (! $action) {
|
||||
return;
|
||||
}
|
||||
|
||||
$termId = absint($_POST['term_id'] ?? 0);
|
||||
|
||||
if (! $termId) {
|
||||
add_settings_error('kb_markdown_products', 'missing_term', __('Missing product ID.', 'kb-markdown-importer'), 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if ('update' === $action) {
|
||||
check_admin_referer('kb_markdown_update_product_' . $termId);
|
||||
$result = $repository->update(
|
||||
$termId,
|
||||
sanitize_text_field(wp_unslash((string) ($_POST['product_name'] ?? ''))),
|
||||
sanitize_title(wp_unslash((string) ($_POST['product_slug'] ?? '')))
|
||||
);
|
||||
|
||||
if (is_wp_error($result)) {
|
||||
add_settings_error('kb_markdown_products', 'update_failed', $result->get_error_message(), 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
add_settings_error('kb_markdown_products', 'updated', __('Product saved.', 'kb-markdown-importer'), 'success');
|
||||
return;
|
||||
}
|
||||
|
||||
if ('delete' === $action) {
|
||||
check_admin_referer('kb_markdown_delete_product_' . $termId);
|
||||
$trashPages = ! empty($_POST['trash_pages']);
|
||||
$result = $repository->deleteProduct($termId, $trashPages);
|
||||
|
||||
if (is_wp_error($result)) {
|
||||
add_settings_error('kb_markdown_products', 'delete_failed', $result->get_error_message(), 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
add_settings_error('kb_markdown_products', 'deleted', __('Product deleted.', 'kb-markdown-importer'), 'success');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -143,11 +143,7 @@ final class Router
|
||||
|
||||
public static function shortcodeDocsIndex(): string
|
||||
{
|
||||
return (new TemplateLoader())->capture('documentation-index', [
|
||||
'products' => self::productsWithVersions(),
|
||||
'base_slug' => trim((string) Plugin::settings()['docs_base_slug'], '/'),
|
||||
'url_builder' => UrlBuilder::class,
|
||||
]);
|
||||
return (new self())->captureRoute('index');
|
||||
}
|
||||
|
||||
public static function shortcodeDocsApp(array $atts = []): string
|
||||
@@ -188,12 +184,12 @@ final class Router
|
||||
$atts = shortcode_atts(['product' => ''], $atts, 'kb_product_index');
|
||||
$router = new self();
|
||||
|
||||
return $router->captureProduct((string) $atts['product']);
|
||||
return $router->captureRoute('product', sanitize_title((string) $atts['product']));
|
||||
}
|
||||
|
||||
private function renderIndex(): void
|
||||
{
|
||||
echo $this->captureIndex();
|
||||
echo $this->captureRoute('index');
|
||||
}
|
||||
|
||||
private function captureIndex(): string
|
||||
@@ -207,7 +203,7 @@ final class Router
|
||||
|
||||
private function renderProduct(string $productSlug): void
|
||||
{
|
||||
echo $this->captureProduct($productSlug);
|
||||
echo $this->captureRoute('product', $productSlug);
|
||||
}
|
||||
|
||||
private function captureProduct(string $productSlug): string
|
||||
@@ -229,7 +225,7 @@ final class Router
|
||||
|
||||
private function renderVersion(string $productSlug, string $versionSlug): void
|
||||
{
|
||||
echo $this->captureVersion($productSlug, $versionSlug);
|
||||
echo $this->captureRoute('version', $productSlug, $versionSlug);
|
||||
}
|
||||
|
||||
private function captureVersion(string $productSlug, string $versionSlug): string
|
||||
@@ -257,7 +253,7 @@ final class Router
|
||||
|
||||
private function renderPage(string $productSlug, string $versionSlug, string $pageSlug): void
|
||||
{
|
||||
echo $this->capturePage($productSlug, $versionSlug, $pageSlug);
|
||||
echo $this->captureRoute('page', $productSlug, $versionSlug, $pageSlug);
|
||||
}
|
||||
|
||||
private function capturePage(string $productSlug, string $versionSlug, string $pageSlug): string
|
||||
@@ -301,13 +297,35 @@ final class Router
|
||||
|
||||
private function captureRoute(string $route, string $productSlug = '', string $versionSlug = '', string $pageSlug = ''): string
|
||||
{
|
||||
return match ($route) {
|
||||
$content = match ($route) {
|
||||
'index' => $this->captureIndex(),
|
||||
'product' => $productSlug ? $this->captureProduct($productSlug) : $this->captureIndex(),
|
||||
'version' => ($productSlug && $versionSlug) ? $this->captureVersion($productSlug, $versionSlug) : $this->captureIndex(),
|
||||
'page' => ($productSlug && $versionSlug) ? $this->capturePage($productSlug, $versionSlug, $pageSlug) : $this->captureIndex(),
|
||||
default => $this->captureIndex(),
|
||||
};
|
||||
|
||||
return $this->captureShell($content, $productSlug, $versionSlug, $pageSlug);
|
||||
}
|
||||
|
||||
private function captureShell(string $content, string $productSlug = '', string $versionSlug = '', string $pageSlug = ''): string
|
||||
{
|
||||
$activePages = [];
|
||||
|
||||
if ($productSlug && $versionSlug) {
|
||||
$activePages = $this->pagesForVersion($productSlug, $versionSlug);
|
||||
}
|
||||
|
||||
return (new TemplateLoader())->capture('docs-app', [
|
||||
'content' => $content,
|
||||
'products' => self::productsWithVersions(),
|
||||
'active_product_slug' => $productSlug,
|
||||
'active_version_slug' => $versionSlug,
|
||||
'active_page_slug' => $pageSlug,
|
||||
'active_pages' => $activePages,
|
||||
'base_slug' => trim((string) Plugin::settings()['docs_base_slug'], '/'),
|
||||
'url_builder' => UrlBuilder::class,
|
||||
]);
|
||||
}
|
||||
|
||||
private function render404(): void
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
namespace KbMarkdownImporter;
|
||||
|
||||
use KbMarkdownImporter\Admin\SettingsPage;
|
||||
use KbMarkdownImporter\Admin\ProductsPage;
|
||||
use KbMarkdownImporter\Admin\StatusPage;
|
||||
use KbMarkdownImporter\Admin\SyncPage;
|
||||
use KbMarkdownImporter\Frontend\Router;
|
||||
@@ -119,6 +120,7 @@ final class Plugin
|
||||
);
|
||||
|
||||
add_submenu_page('kb-markdown-importer', __('Overview', 'kb-markdown-importer'), __('Overview', 'kb-markdown-importer'), 'manage_kb_docs', 'kb-markdown-importer', [StatusPage::class, 'render']);
|
||||
add_submenu_page('kb-markdown-importer', __('Products', 'kb-markdown-importer'), __('Products', 'kb-markdown-importer'), 'manage_kb_docs', 'kb-markdown-products', [ProductsPage::class, 'render']);
|
||||
add_submenu_page('kb-markdown-importer', __('Synchronization', 'kb-markdown-importer'), __('Synchronization', 'kb-markdown-importer'), 'sync_kb_docs', 'kb-markdown-sync', [SyncPage::class, 'render']);
|
||||
add_submenu_page('kb-markdown-importer', __('Settings', 'kb-markdown-importer'), __('Settings', 'kb-markdown-importer'), 'manage_kb_docs', 'kb-markdown-settings', [SettingsPage::class, 'render']);
|
||||
}
|
||||
|
||||
@@ -16,4 +16,117 @@ final class ProductRepository
|
||||
|
||||
return is_wp_error($term) ? 0 : (int) ($term['term_id'] ?? $term);
|
||||
}
|
||||
|
||||
public function allWithStats(): array
|
||||
{
|
||||
$terms = get_terms([
|
||||
'taxonomy' => 'kb_product',
|
||||
'hide_empty' => false,
|
||||
'orderby' => 'name',
|
||||
'order' => 'ASC',
|
||||
]);
|
||||
|
||||
if (is_wp_error($terms)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$items = [];
|
||||
|
||||
foreach ($terms as $term) {
|
||||
$pageIds = $this->pageIdsForProduct((int) $term->term_id);
|
||||
$versions = [];
|
||||
|
||||
foreach ($pageIds as $pageId) {
|
||||
$pageVersions = wp_get_object_terms($pageId, 'kb_version');
|
||||
|
||||
if (is_wp_error($pageVersions)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($pageVersions as $version) {
|
||||
$versions[$version->slug] = $version;
|
||||
}
|
||||
}
|
||||
|
||||
uasort($versions, static fn ($a, $b): int => strnatcasecmp($b->name, $a->name));
|
||||
|
||||
$items[] = [
|
||||
'term' => $term,
|
||||
'page_count' => count($pageIds),
|
||||
'versions' => array_values($versions),
|
||||
];
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
public function update(int $termId, string $name, string $slug): \WP_Term|\WP_Error
|
||||
{
|
||||
$name = trim($name);
|
||||
$slug = sanitize_title($slug ?: $name);
|
||||
|
||||
if ('' === $name || '' === $slug) {
|
||||
return new \WP_Error('kb_product_invalid', __('Product name and slug are required.', 'kb-markdown-importer'));
|
||||
}
|
||||
|
||||
$updated = wp_update_term($termId, 'kb_product', [
|
||||
'name' => $name,
|
||||
'slug' => $slug,
|
||||
]);
|
||||
|
||||
if (is_wp_error($updated)) {
|
||||
return $updated;
|
||||
}
|
||||
|
||||
foreach ($this->pageIdsForProduct($termId) as $pageId) {
|
||||
update_post_meta($pageId, '_kb_product_slug', $slug);
|
||||
}
|
||||
|
||||
$term = get_term((int) $updated['term_id'], 'kb_product');
|
||||
|
||||
return $term instanceof \WP_Term ? $term : new \WP_Error('kb_product_missing', __('Product could not be loaded after update.', 'kb-markdown-importer'));
|
||||
}
|
||||
|
||||
public function trashProductPages(int $termId): int
|
||||
{
|
||||
$count = 0;
|
||||
|
||||
foreach ($this->pageIdsForProduct($termId, ['publish', 'draft', 'private', 'pending', 'future']) as $pageId) {
|
||||
if (wp_trash_post($pageId)) {
|
||||
++$count;
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
public function deleteProduct(int $termId, bool $trashPages): true|\WP_Error
|
||||
{
|
||||
if ($trashPages) {
|
||||
$this->trashProductPages($termId);
|
||||
}
|
||||
|
||||
$deleted = wp_delete_term($termId, 'kb_product');
|
||||
|
||||
if (is_wp_error($deleted)) {
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function pageIdsForProduct(int $termId, array $postStatus = ['publish']): array
|
||||
{
|
||||
$query = new \WP_Query([
|
||||
'post_type' => 'kb_doc_page',
|
||||
'post_status' => $postStatus,
|
||||
'posts_per_page' => -1,
|
||||
'fields' => 'ids',
|
||||
'tax_query' => [
|
||||
['taxonomy' => 'kb_product', 'field' => 'term_id', 'terms' => $termId],
|
||||
],
|
||||
]);
|
||||
|
||||
return array_map('intval', $query->posts);
|
||||
}
|
||||
}
|
||||
|
||||
58
kb-markdown-importer/templates/docs-app.php
Normal file
58
kb-markdown-importer/templates/docs-app.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
$active_product_slug = (string) ($active_product_slug ?? '');
|
||||
$active_version_slug = (string) ($active_version_slug ?? '');
|
||||
$active_page_slug = (string) ($active_page_slug ?? '');
|
||||
?>
|
||||
<div class="kb-docs-wrap kb-docs-app">
|
||||
<aside class="kb-app-sidebar" aria-label="<?php esc_attr_e('Documentation navigation', 'kb-markdown-importer'); ?>">
|
||||
<div class="kb-app-sidebar__brand">
|
||||
<a href="<?php echo esc_url($url_builder::docsIndex()); ?>"><?php esc_html_e('Knowledgebase', 'kb-markdown-importer'); ?></a>
|
||||
</div>
|
||||
<div class="kb-app-sidebar__search">
|
||||
<?php echo do_shortcode('[kb_search]'); ?>
|
||||
</div>
|
||||
<nav class="kb-app-nav">
|
||||
<?php foreach ((array) $products as $item) : ?>
|
||||
<?php
|
||||
$term = $item['term'];
|
||||
$versions = (array) $item['versions'];
|
||||
$latest = $versions[0] ?? null;
|
||||
$isActiveProduct = $term->slug === $active_product_slug;
|
||||
?>
|
||||
<section class="kb-app-product <?php echo $isActiveProduct ? 'is-active' : ''; ?>">
|
||||
<a class="kb-app-product__link" href="<?php echo esc_url($latest ? $url_builder::version($term->slug, $latest->slug) : $url_builder::product($term->slug)); ?>">
|
||||
<?php echo esc_html($term->name); ?>
|
||||
</a>
|
||||
<?php if ($versions) : ?>
|
||||
<ul class="kb-app-version-list">
|
||||
<?php foreach ($versions as $version) : ?>
|
||||
<?php $isActiveVersion = $isActiveProduct && $version->slug === $active_version_slug; ?>
|
||||
<li class="<?php echo $isActiveVersion ? 'is-active' : ''; ?>">
|
||||
<a href="<?php echo esc_url($url_builder::version($term->slug, $version->slug)); ?>"><?php echo esc_html($version->name); ?></a>
|
||||
<?php if ($isActiveVersion && ! empty($active_pages)) : ?>
|
||||
<ul class="kb-app-page-list">
|
||||
<?php foreach ((array) $active_pages as $page) : ?>
|
||||
<?php
|
||||
$pageSlug = (string) get_post_meta($page->ID, '_kb_page_slug', true);
|
||||
$isActivePage = $pageSlug === $active_page_slug || ('' === $active_page_slug && in_array($pageSlug, ['', 'index'], true));
|
||||
?>
|
||||
<li class="<?php echo $isActivePage ? 'is-active' : ''; ?>">
|
||||
<a href="<?php echo esc_url($url_builder::page($term->slug, $version->slug, $pageSlug)); ?>"><?php echo esc_html(get_the_title($page)); ?></a>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
<?php endforeach; ?>
|
||||
</nav>
|
||||
</aside>
|
||||
<section class="kb-app-main">
|
||||
<?php echo $content; ?>
|
||||
</section>
|
||||
</div>
|
||||
@@ -1,14 +1,14 @@
|
||||
<?php
|
||||
defined('ABSPATH') || exit;
|
||||
?>
|
||||
<main class="kb-docs-wrap">
|
||||
<section class="kb-docs-home">
|
||||
<h1><?php esc_html_e('Knowledgebase', 'kb-markdown-importer'); ?></h1>
|
||||
<?php echo do_shortcode('[kb_search]'); ?>
|
||||
<div class="kb-product-list">
|
||||
<?php foreach ((array) $products as $item) : ?>
|
||||
<?php $term = $item['term']; ?>
|
||||
<?php $latest = $item['versions'][0] ?? null; ?>
|
||||
<section class="kb-product-card">
|
||||
<h2><a href="<?php echo esc_url($url_builder::product($term->slug)); ?>"><?php echo esc_html($term->name); ?></a></h2>
|
||||
<h2><a href="<?php echo esc_url($latest ? $url_builder::version($term->slug, $latest->slug) : $url_builder::product($term->slug)); ?>"><?php echo esc_html($term->name); ?></a></h2>
|
||||
<?php if (! empty($item['versions'])) : ?>
|
||||
<ul>
|
||||
<?php foreach ($item['versions'] as $version) : ?>
|
||||
@@ -19,4 +19,4 @@ defined('ABSPATH') || exit;
|
||||
</section>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</main>
|
||||
</section>
|
||||
|
||||
@@ -1,59 +1,17 @@
|
||||
<?php
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
$render_nav = static function (array $nodes) use (&$render_nav, $base_slug, $product_slug, $version_slug, $url_builder): void {
|
||||
if (! $nodes) {
|
||||
return;
|
||||
}
|
||||
|
||||
echo '<ul>';
|
||||
foreach ($nodes as $node) {
|
||||
$target = (string) ($node['target'] ?? '');
|
||||
$label = (string) ($node['title'] ?? '');
|
||||
$href = '';
|
||||
|
||||
if ($target) {
|
||||
$slug = preg_replace('/\.md(#.+)?$/', '', basename($target)) ?: basename($target);
|
||||
$slug = in_array(strtolower($slug), ['doku', 'index'], true) ? '' : sanitize_title($slug);
|
||||
$href = $url_builder::page($product_slug, $version_slug, $slug);
|
||||
}
|
||||
|
||||
echo '<li>';
|
||||
if ($href) {
|
||||
printf('<a href="%s">%s</a>', esc_url($href), esc_html($label));
|
||||
} else {
|
||||
echo '<span>' . esc_html($label) . '</span>';
|
||||
}
|
||||
$render_nav((array) ($node['children'] ?? []));
|
||||
echo '</li>';
|
||||
}
|
||||
echo '</ul>';
|
||||
};
|
||||
?>
|
||||
<main class="kb-docs-wrap kb-doc-layout">
|
||||
<aside class="kb-sidebar">
|
||||
<label class="screen-reader-text" for="kb-version-switcher"><?php esc_html_e('Version', 'kb-markdown-importer'); ?></label>
|
||||
<select id="kb-version-switcher">
|
||||
<?php foreach ((array) $versions as $item) : ?>
|
||||
<option value="<?php echo esc_attr($item->slug); ?>" data-url="<?php echo esc_url($url_builder::version($product_slug, $item->slug)); ?>" <?php selected($item->slug, $version_slug); ?>><?php echo esc_html($item->name); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<nav class="kb-sidebar-nav" aria-label="<?php esc_attr_e('Documentation navigation', 'kb-markdown-importer'); ?>">
|
||||
<?php $render_nav((array) $nav_tree); ?>
|
||||
</nav>
|
||||
</aside>
|
||||
<article class="kb-doc-content">
|
||||
<nav class="kb-breadcrumbs">
|
||||
<a href="<?php echo esc_url($url_builder::docsIndex()); ?>"><?php esc_html_e('Docs', 'kb-markdown-importer'); ?></a><span>/</span>
|
||||
<a href="<?php echo esc_url($url_builder::product($product_slug)); ?>"><?php echo esc_html($product ? $product->name : $product_slug); ?></a><span>/</span>
|
||||
<a href="<?php echo esc_url($url_builder::version($product_slug, $version_slug)); ?>"><?php echo esc_html($version ? $version->name : $version_slug); ?></a>
|
||||
</nav>
|
||||
<h1><?php echo esc_html(get_the_title($post)); ?></h1>
|
||||
<div class="kb-rendered-content">
|
||||
<?php
|
||||
$rendered_content = $url_builder::rewriteHtml(apply_filters('the_content', $post->post_content));
|
||||
echo wp_kses_post($rendered_content);
|
||||
?>
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
<article class="kb-doc-content">
|
||||
<nav class="kb-breadcrumbs">
|
||||
<a href="<?php echo esc_url($url_builder::docsIndex()); ?>"><?php esc_html_e('Docs', 'kb-markdown-importer'); ?></a><span>/</span>
|
||||
<a href="<?php echo esc_url($url_builder::product($product_slug)); ?>"><?php echo esc_html($product ? $product->name : $product_slug); ?></a><span>/</span>
|
||||
<a href="<?php echo esc_url($url_builder::version($product_slug, $version_slug)); ?>"><?php echo esc_html($version ? $version->name : $version_slug); ?></a>
|
||||
</nav>
|
||||
<h1><?php echo esc_html(get_the_title($post)); ?></h1>
|
||||
<div class="kb-rendered-content">
|
||||
<?php
|
||||
$rendered_content = $url_builder::rewriteHtml(apply_filters('the_content', $post->post_content));
|
||||
echo wp_kses_post($rendered_content);
|
||||
?>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
defined('ABSPATH') || exit;
|
||||
?>
|
||||
<main class="kb-docs-wrap">
|
||||
<section class="kb-docs-product">
|
||||
<nav class="kb-breadcrumbs"><a href="<?php echo esc_url($url_builder::docsIndex()); ?>"><?php esc_html_e('Docs', 'kb-markdown-importer'); ?></a><span>/</span><?php echo esc_html($product->name); ?></nav>
|
||||
<h1><?php echo esc_html($product->name); ?></h1>
|
||||
<h2><?php esc_html_e('Available Versions', 'kb-markdown-importer'); ?></h2>
|
||||
@@ -13,4 +13,4 @@ defined('ABSPATH') || exit;
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</main>
|
||||
</section>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
defined('ABSPATH') || exit;
|
||||
?>
|
||||
<main class="kb-docs-wrap">
|
||||
<section class="kb-docs-version">
|
||||
<nav class="kb-breadcrumbs">
|
||||
<a href="<?php echo esc_url($url_builder::docsIndex()); ?>"><?php esc_html_e('Docs', 'kb-markdown-importer'); ?></a><span>/</span>
|
||||
<a href="<?php echo esc_url($url_builder::product($product->slug)); ?>"><?php echo esc_html($product->name); ?></a><span>/</span>
|
||||
@@ -14,4 +14,4 @@ defined('ABSPATH') || exit;
|
||||
<li><a href="<?php echo esc_url($url_builder::page($product->slug, $version->slug, $slug)); ?>"><?php echo esc_html(get_the_title($page)); ?></a></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</main>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user