MD Umbau
This commit is contained in:
209
kb-markdown-importer/includes/Admin/SettingsPage.php
Normal file
209
kb-markdown-importer/includes/Admin/SettingsPage.php
Normal file
@@ -0,0 +1,209 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace KbMarkdownImporter\Admin;
|
||||
|
||||
use KbMarkdownImporter\GitLab\GitLabClient;
|
||||
use KbMarkdownImporter\Import\ImportLogger;
|
||||
use KbMarkdownImporter\Plugin;
|
||||
use KbMarkdownImporter\Settings;
|
||||
|
||||
final class SettingsPage
|
||||
{
|
||||
public static function registerSettings(): void
|
||||
{
|
||||
register_setting('kb_markdown_importer_settings', 'kb_markdown_importer_settings', [
|
||||
'type' => 'array',
|
||||
'sanitize_callback' => [self::class, 'sanitize'],
|
||||
'default' => Settings::defaults(),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function sanitize(array $input): array
|
||||
{
|
||||
$old = Plugin::settings();
|
||||
$settings = Settings::defaults();
|
||||
|
||||
$settings['gitlab_base_url'] = esc_url_raw(GitLabClient::normalizeBaseUrl((string) ($input['gitlab_base_url'] ?? '')));
|
||||
$settings['gitlab_token'] = trim((string) ($input['gitlab_token'] ?? '')) ?: (string) $old['gitlab_token'];
|
||||
$settings['gitlab_group'] = sanitize_text_field((string) ($input['gitlab_group'] ?? 'knowledgebase'));
|
||||
$settings['branch_pattern'] = sanitize_text_field((string) ($input['branch_pattern'] ?? '^v.*'));
|
||||
$settings['docs_base_slug'] = sanitize_title((string) ($input['docs_base_slug'] ?? 'docs')) ?: 'docs';
|
||||
$settings['image_lightbox'] = ! empty($input['image_lightbox']) ? '1' : '0';
|
||||
$settings['public_docs'] = ! empty($input['public_docs']) ? '1' : '0';
|
||||
$settings['allow_svg'] = ! empty($input['allow_svg']) ? '1' : '0';
|
||||
$settings['cron_interval'] = in_array(($input['cron_interval'] ?? 'disabled'), ['disabled', 'hourly', 'daily', 'weekly'], true) ? (string) $input['cron_interval'] : 'disabled';
|
||||
$settings['design_theme'] = in_array(($input['design_theme'] ?? 'obyte'), ['obyte', 'inherit'], true) ? (string) $input['design_theme'] : 'obyte';
|
||||
$settings['design_primary_color'] = self::sanitizeHexColor((string) ($input['design_primary_color'] ?? '#00A7E6'), '#00A7E6');
|
||||
$settings['design_accent_color'] = self::sanitizeHexColor((string) ($input['design_accent_color'] ?? '#F59C00'), '#F59C00');
|
||||
$settings['design_radius'] = (string) max(0, min(32, (int) ($input['design_radius'] ?? 14)));
|
||||
$settings['custom_theme_css_url'] = esc_url_raw((string) ($input['custom_theme_css_url'] ?? ''));
|
||||
|
||||
Plugin::syncCronSchedule($settings);
|
||||
if (($old['docs_base_slug'] ?? 'docs') !== $settings['docs_base_slug']) {
|
||||
flush_rewrite_rules(false);
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
public static function render(): void
|
||||
{
|
||||
if (! current_user_can('manage_kb_docs')) {
|
||||
wp_die(esc_html__('Insufficient permissions.', 'kb-markdown-importer'));
|
||||
}
|
||||
|
||||
if (isset($_POST['kb_markdown_test_connection']) && check_admin_referer('kb_markdown_test_connection')) {
|
||||
self::handleConnectionTest();
|
||||
}
|
||||
|
||||
$settings = Plugin::settings();
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php esc_html_e('Markdown Knowledgebase Settings', 'kb-markdown-importer'); ?></h1>
|
||||
<form method="post" action="options.php">
|
||||
<?php settings_fields('kb_markdown_importer_settings'); ?>
|
||||
<table class="form-table" role="presentation">
|
||||
<tr>
|
||||
<th scope="row"><label for="gitlab_base_url">GitLab Base URL</label></th>
|
||||
<td>
|
||||
<input class="regular-text" id="gitlab_base_url" name="kb_markdown_importer_settings[gitlab_base_url]" type="url" value="<?php echo esc_attr($settings['gitlab_base_url']); ?>" placeholder="https://git.example.de">
|
||||
<p class="description"><?php esc_html_e('Use the GitLab root URL, for example https://git.example.de. Do not include /api/v4.', 'kb-markdown-importer'); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><label for="gitlab_token">GitLab API Token</label></th>
|
||||
<td><input class="regular-text" id="gitlab_token" name="kb_markdown_importer_settings[gitlab_token]" type="password" value="" placeholder="<?php echo $settings['gitlab_token'] ? esc_attr__('Token is stored; leave blank to keep it', 'kb-markdown-importer') : ''; ?>"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><label for="gitlab_group">GitLab Group Path / ID</label></th>
|
||||
<td><input class="regular-text" id="gitlab_group" name="kb_markdown_importer_settings[gitlab_group]" type="text" value="<?php echo esc_attr($settings['gitlab_group']); ?>"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><label for="branch_pattern">Branch Pattern</label></th>
|
||||
<td><input class="regular-text" id="branch_pattern" name="kb_markdown_importer_settings[branch_pattern]" type="text" value="<?php echo esc_attr($settings['branch_pattern']); ?>"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><label for="docs_base_slug">Frontend Base Slug</label></th>
|
||||
<td><input class="regular-text" id="docs_base_slug" name="kb_markdown_importer_settings[docs_base_slug]" type="text" value="<?php echo esc_attr($settings['docs_base_slug']); ?>"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Markdown Project Structure</th>
|
||||
<td>
|
||||
<p class="description"><?php esc_html_e('Each version branch must contain doku.md, stepbystep.md and an images/ folder. Optional files such as faq.md and doku.yml are supported.', 'kb-markdown-importer'); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Options</th>
|
||||
<td>
|
||||
<label><input type="checkbox" name="kb_markdown_importer_settings[image_lightbox]" value="1" <?php checked($settings['image_lightbox'], '1'); ?>> Link images with lightbox class</label><br>
|
||||
<label><input type="checkbox" name="kb_markdown_importer_settings[public_docs]" value="1" <?php checked($settings['public_docs'], '1'); ?>> Show documentation publicly</label><br>
|
||||
<label><input type="checkbox" name="kb_markdown_importer_settings[allow_svg]" value="1" <?php checked($settings['allow_svg'], '1'); ?>> Allow SVG image import</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><label for="cron_interval">Automatic Sync</label></th>
|
||||
<td>
|
||||
<select id="cron_interval" name="kb_markdown_importer_settings[cron_interval]">
|
||||
<option value="disabled" <?php selected($settings['cron_interval'], 'disabled'); ?>>Disabled</option>
|
||||
<option value="hourly" <?php selected($settings['cron_interval'], 'hourly'); ?>>Hourly</option>
|
||||
<option value="daily" <?php selected($settings['cron_interval'], 'daily'); ?>>Daily</option>
|
||||
<option value="weekly" <?php selected($settings['cron_interval'], 'weekly'); ?>>Weekly</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h2><?php esc_html_e('Frontend Design', 'kb-markdown-importer'); ?></h2>
|
||||
<table class="form-table" role="presentation">
|
||||
<tr>
|
||||
<th scope="row"><label for="design_theme">Design Theme</label></th>
|
||||
<td>
|
||||
<select id="design_theme" name="kb_markdown_importer_settings[design_theme]">
|
||||
<option value="obyte" <?php selected($settings['design_theme'], 'obyte'); ?>>o-byte</option>
|
||||
<option value="inherit" <?php selected($settings['design_theme'], 'inherit'); ?>>Theme inherit / neutral</option>
|
||||
</select>
|
||||
<p class="description"><?php esc_html_e('The bundled o-byte theme is loaded by default. A custom theme.css is loaded after it and can override everything.', 'kb-markdown-importer'); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><label for="design_primary_color">Primary Color</label></th>
|
||||
<td><input id="design_primary_color" name="kb_markdown_importer_settings[design_primary_color]" type="color" value="<?php echo esc_attr($settings['design_primary_color']); ?>"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><label for="design_accent_color">Accent Color</label></th>
|
||||
<td><input id="design_accent_color" name="kb_markdown_importer_settings[design_accent_color]" type="color" value="<?php echo esc_attr($settings['design_accent_color']); ?>"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><label for="design_radius">Border Radius</label></th>
|
||||
<td>
|
||||
<input id="design_radius" name="kb_markdown_importer_settings[design_radius]" type="number" min="0" max="32" value="<?php echo esc_attr($settings['design_radius']); ?>"> px
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><label for="custom_theme_css_url">Custom theme.css</label></th>
|
||||
<td>
|
||||
<input class="regular-text" id="custom_theme_css_url" name="kb_markdown_importer_settings[custom_theme_css_url]" type="url" value="<?php echo esc_attr($settings['custom_theme_css_url']); ?>" placeholder="https://example.com/theme.css">
|
||||
<button type="button" class="button" id="kb-markdown-upload-theme-css"><?php esc_html_e('Upload/select theme.css', 'kb-markdown-importer'); ?></button>
|
||||
<p class="description"><?php esc_html_e('Upload a CSS file in the media library or paste a CSS URL. It is enqueued last, so it can override the bundled theme.', 'kb-markdown-importer'); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php submit_button(); ?>
|
||||
</form>
|
||||
<form method="post">
|
||||
<?php wp_nonce_field('kb_markdown_test_connection'); ?>
|
||||
<?php submit_button(__('Test GitLab Connection', 'kb-markdown-importer'), 'secondary', 'kb_markdown_test_connection'); ?>
|
||||
</form>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
private static function handleConnectionTest(): void
|
||||
{
|
||||
$client = new GitLabClient(Plugin::settings());
|
||||
$result = $client->getGroup(Plugin::settings()['gitlab_group']);
|
||||
|
||||
if (is_wp_error($result)) {
|
||||
$message = self::formatConnectionError($result);
|
||||
ImportLogger::error('GitLab connection failed: ' . $message);
|
||||
add_settings_error('kb_markdown_importer', 'connection_failed', esc_html($message), 'error');
|
||||
settings_errors('kb_markdown_importer');
|
||||
return;
|
||||
}
|
||||
|
||||
ImportLogger::info('GitLab connection successful.');
|
||||
add_settings_error('kb_markdown_importer', 'connection_ok', esc_html__('GitLab connection successful.', 'kb-markdown-importer'), 'success');
|
||||
settings_errors('kb_markdown_importer');
|
||||
}
|
||||
|
||||
private static function formatConnectionError(\WP_Error $error): string
|
||||
{
|
||||
$message = $error->get_error_message();
|
||||
$data = $error->get_error_data();
|
||||
|
||||
if (! is_array($data)) {
|
||||
return $message;
|
||||
}
|
||||
|
||||
if (! empty($data['url'])) {
|
||||
$message .= ' Target: ' . $data['url'];
|
||||
}
|
||||
|
||||
if (! empty($data['retry_after'])) {
|
||||
$message .= ' Retry-After: ' . $data['retry_after'];
|
||||
}
|
||||
|
||||
if (! empty($data['response_excerpt'])) {
|
||||
$message .= ' Response: ' . $data['response_excerpt'];
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
private static function sanitizeHexColor(string $value, string $fallback): string
|
||||
{
|
||||
$value = trim($value);
|
||||
|
||||
return preg_match('/^#[0-9a-fA-F]{6}$/', $value) ? strtoupper($value) : $fallback;
|
||||
}
|
||||
}
|
||||
78
kb-markdown-importer/includes/Admin/StatusPage.php
Normal file
78
kb-markdown-importer/includes/Admin/StatusPage.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace KbMarkdownImporter\Admin;
|
||||
|
||||
use KbMarkdownImporter\Import\ImportLogger;
|
||||
use KbMarkdownImporter\Plugin;
|
||||
|
||||
final class StatusPage
|
||||
{
|
||||
public static function render(): void
|
||||
{
|
||||
if (! current_user_can('manage_kb_docs')) {
|
||||
wp_die(esc_html__('Insufficient permissions.', 'kb-markdown-importer'));
|
||||
}
|
||||
|
||||
$settings = Plugin::settings();
|
||||
$counts = self::counts();
|
||||
$logs = ImportLogger::recent(20);
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php esc_html_e('Knowledgebase Overview', 'kb-markdown-importer'); ?></h1>
|
||||
<div class="kb-admin-grid">
|
||||
<div class="kb-admin-card"><strong>GitLab</strong><span><?php echo esc_html($settings['gitlab_base_url'] ?: __('Not configured', 'kb-markdown-importer')); ?></span></div>
|
||||
<div class="kb-admin-card"><strong>Products</strong><span><?php echo esc_html((string) $counts['products']); ?></span></div>
|
||||
<div class="kb-admin-card"><strong>Versions</strong><span><?php echo esc_html((string) $counts['versions']); ?></span></div>
|
||||
<div class="kb-admin-card"><strong>Pages</strong><span><?php echo esc_html((string) $counts['pages']); ?></span></div>
|
||||
<div class="kb-admin-card"><strong>Last sync</strong><span><?php echo esc_html((string) get_option('kb_markdown_importer_last_sync', __('Never', 'kb-markdown-importer'))); ?></span></div>
|
||||
<div class="kb-admin-card"><strong>Format</strong><span>Markdown</span></div>
|
||||
</div>
|
||||
<h2><?php esc_html_e('Recent Import Logs', 'kb-markdown-importer'); ?></h2>
|
||||
<?php self::renderLogTable($logs); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
public static function restStatus(): \WP_REST_Response
|
||||
{
|
||||
return new \WP_REST_Response([
|
||||
'settings_complete' => (bool) (Plugin::settings()['gitlab_base_url'] && Plugin::settings()['gitlab_token']),
|
||||
'counts' => self::counts(),
|
||||
'last_sync' => get_option('kb_markdown_importer_last_sync', ''),
|
||||
'last_error' => get_option('kb_markdown_importer_last_error', ''),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function renderLogTable(array $logs): void
|
||||
{
|
||||
if (! $logs) {
|
||||
echo '<p>' . esc_html__('No logs yet.', 'kb-markdown-importer') . '</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
echo '<table class="widefat striped"><thead><tr><th>Time</th><th>Level</th><th>Message</th></tr></thead><tbody>';
|
||||
foreach ($logs as $entry) {
|
||||
printf(
|
||||
'<tr><td>%s</td><td><strong>%s</strong></td><td>%s</td></tr>',
|
||||
esc_html((string) ($entry['time'] ?? '')),
|
||||
esc_html((string) ($entry['level'] ?? 'INFO')),
|
||||
esc_html((string) ($entry['message'] ?? ''))
|
||||
);
|
||||
}
|
||||
echo '</tbody></table>';
|
||||
}
|
||||
|
||||
private static function counts(): array
|
||||
{
|
||||
$pages = wp_count_posts('kb_doc_page');
|
||||
$products = wp_count_terms(['taxonomy' => 'kb_product', 'hide_empty' => false]);
|
||||
$versions = wp_count_terms(['taxonomy' => 'kb_version', 'hide_empty' => false]);
|
||||
|
||||
return [
|
||||
'products' => is_wp_error($products) ? 0 : (int) $products,
|
||||
'versions' => is_wp_error($versions) ? 0 : (int) $versions,
|
||||
'pages' => (int) ($pages->publish ?? 0),
|
||||
];
|
||||
}
|
||||
}
|
||||
98
kb-markdown-importer/includes/Admin/SyncPage.php
Normal file
98
kb-markdown-importer/includes/Admin/SyncPage.php
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace KbMarkdownImporter\Admin;
|
||||
|
||||
use KbMarkdownImporter\GitLab\GitLabClient;
|
||||
use KbMarkdownImporter\Import\ImportLogger;
|
||||
use KbMarkdownImporter\Import\ImportManager;
|
||||
use KbMarkdownImporter\Plugin;
|
||||
|
||||
final class SyncPage
|
||||
{
|
||||
public static function render(): void
|
||||
{
|
||||
if (! current_user_can('sync_kb_docs')) {
|
||||
wp_die(esc_html__('Insufficient permissions.', 'kb-markdown-importer'));
|
||||
}
|
||||
|
||||
self::handleActions();
|
||||
$projects = self::loadProjects();
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php esc_html_e('Knowledgebase Synchronization', 'kb-markdown-importer'); ?></h1>
|
||||
<form method="post" class="kb-sync-actions">
|
||||
<?php wp_nonce_field('kb_markdown_sync'); ?>
|
||||
<?php submit_button(__('Sync All', 'kb-markdown-importer'), 'primary', 'kb_markdown_sync_all', false); ?>
|
||||
<?php submit_button(__('Dry Run', 'kb-markdown-importer'), 'secondary', 'kb_markdown_dry_run', false); ?>
|
||||
</form>
|
||||
|
||||
<h2><?php esc_html_e('Projects', 'kb-markdown-importer'); ?></h2>
|
||||
<?php if (is_wp_error($projects)) : ?>
|
||||
<div class="notice notice-error"><p><?php echo esc_html($projects->get_error_message()); ?></p></div>
|
||||
<?php elseif (! $projects) : ?>
|
||||
<p><?php esc_html_e('No projects loaded. Check GitLab settings first.', 'kb-markdown-importer'); ?></p>
|
||||
<?php else : ?>
|
||||
<table class="widefat striped">
|
||||
<thead><tr><th>Name</th><th>Path</th><th>Action</th></tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ($projects as $project) : ?>
|
||||
<tr>
|
||||
<td><?php echo esc_html((string) ($project['name'] ?? '')); ?></td>
|
||||
<td><code><?php echo esc_html((string) ($project['path_with_namespace'] ?? $project['path'] ?? '')); ?></code></td>
|
||||
<td>
|
||||
<form method="post">
|
||||
<?php wp_nonce_field('kb_markdown_sync_project'); ?>
|
||||
<input type="hidden" name="project_id" value="<?php echo esc_attr((string) ($project['id'] ?? '')); ?>">
|
||||
<?php submit_button(__('Sync Project', 'kb-markdown-importer'), 'secondary small', 'kb_markdown_sync_project', false); ?>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
|
||||
<h2><?php esc_html_e('Import Logs', 'kb-markdown-importer'); ?></h2>
|
||||
<?php StatusPage::renderLogTable(ImportLogger::recent(100)); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
private static function handleActions(): void
|
||||
{
|
||||
if (isset($_POST['kb_markdown_sync_all']) && check_admin_referer('kb_markdown_sync')) {
|
||||
(new ImportManager())->syncAll(false);
|
||||
echo '<div class="notice notice-success"><p>' . esc_html__('Synchronization finished.', 'kb-markdown-importer') . '</p></div>';
|
||||
}
|
||||
|
||||
if (isset($_POST['kb_markdown_dry_run']) && check_admin_referer('kb_markdown_sync')) {
|
||||
(new ImportManager())->syncAll(true);
|
||||
echo '<div class="notice notice-info"><p>' . esc_html__('Dry run finished.', 'kb-markdown-importer') . '</p></div>';
|
||||
}
|
||||
|
||||
if (isset($_POST['kb_markdown_sync_project']) && check_admin_referer('kb_markdown_sync_project')) {
|
||||
$projectId = sanitize_text_field(wp_unslash((string) ($_POST['project_id'] ?? '')));
|
||||
(new ImportManager())->syncProject($projectId, false);
|
||||
echo '<div class="notice notice-success"><p>' . esc_html__('Project synchronization finished.', 'kb-markdown-importer') . '</p></div>';
|
||||
}
|
||||
}
|
||||
|
||||
private static function loadProjects(): array|\WP_Error
|
||||
{
|
||||
$settings = Plugin::settings();
|
||||
|
||||
if (! $settings['gitlab_base_url'] || ! $settings['gitlab_token'] || ! $settings['gitlab_group']) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$client = new GitLabClient($settings);
|
||||
$group = $client->getGroup($settings['gitlab_group']);
|
||||
|
||||
if (is_wp_error($group)) {
|
||||
return $group;
|
||||
}
|
||||
|
||||
return $client->getProjects((string) ($group['id'] ?? $settings['gitlab_group']));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user