v2.6.1d (Lyra): Plugin i18n, plugin editor vernieuwd, media invoegen
Plugin internationalisatie: plugins hebben eigen language/ mappen. Systeem plugins volgen admin taal (admin.php), content plugins volgen content taal (site.php). Fallback chain: geselecteerd -> plugin default_language -> CMS default. PluginManager/AdminPluginAPI/CMSAPI uitgebreid met getPluginTranslations()/t(). plugin.json settings ondersteunen label_key/help_key/option_label_key. Plugin uniformiteit: alle 6 plugins hebben uniforme structuur (README.md, assets/.gitkeep, language/nl|en/). plugins/README.md herschreven. guide plugin-development.md (NL+EN) volledig herschreven. Plugin editor vernieuwd: geneste bestandsbrowser zijbalk, nieuw bestand aanmaken, uploaden naar assets/, verwijderen en verplaatsen. Nieuwe routes: plugins-file-upload, plugins-file-delete, plugins-file-move. Path-traversal bescherming + protected plugins geblokkeerd. Media invoegen in editor: nieuw /admin/media-list JSON endpoint + herbruikbare _media-modal.twig include. Plugin-context scant assets/ map. editor-toolbar.js modeMap uitgebreid voor css/scss/js/json. Plugin overzicht knoppen: alleen iconen met title/aria-label. Tests: pentest 30/30, WCAG 2.1 AA 25/25.
This commit is contained in:
@@ -25,8 +25,10 @@ class Dashboard
|
||||
'plugin' => 'Dashboard',
|
||||
'route' => 'dashboard',
|
||||
'label' => 'Dashboard',
|
||||
'label_key' => 'menu_label',
|
||||
'icon' => 'bi-speedometer2',
|
||||
'section' => 'general',
|
||||
'permission' => 'dashboard',
|
||||
],
|
||||
];
|
||||
}
|
||||
@@ -39,6 +41,12 @@ class Dashboard
|
||||
$enabledPlugins = $this->api ? $this->api->getEnabledPlugins() : [];
|
||||
$versionInfo = $this->api ? $this->api->getVersionInfo() : ['version' => '0.0.0'];
|
||||
|
||||
// Plugin translations (admin context). Falls back to plugin default_language.
|
||||
$t = $this->api ? $this->api->getPluginTranslations('Dashboard') : [];
|
||||
$tr = function (string $key) use ($t): string {
|
||||
return $t[$key] ?? $key;
|
||||
};
|
||||
|
||||
$stats = [
|
||||
'pages' => $this->countFiles($contentDir, ['md', 'php', 'html']),
|
||||
'directories' => $this->countDirs($contentDir),
|
||||
@@ -68,20 +76,20 @@ class Dashboard
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<h2 class="mb-4"><i class="bi bi-speedometer2"></i> Dashboard</h2>
|
||||
<h2 class="mb-4"><i class="bi bi-speedometer2"></i> <?= htmlspecialchars($tr('page_title')) ?></h2>
|
||||
|
||||
<div class="row g-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header"><i class="bi bi-info-circle"></i> Site informatie</div>
|
||||
<div class="card-header"><i class="bi bi-info-circle"></i> <?= htmlspecialchars($tr('site_info')) ?></div>
|
||||
<div class="card-body">
|
||||
<table class="table table-sm mb-0">
|
||||
<tr><td class="text-muted">Site titel</td><td><?= htmlspecialchars($siteTitle) ?></td></tr>
|
||||
<tr><td class="text-muted">Standaard taal</td><td><?= htmlspecialchars($defaultLang) ?></td></tr>
|
||||
<tr><td class="text-muted">CodePress versie</td><td><?= htmlspecialchars($stats['cms_version']) ?></td></tr>
|
||||
<tr><td class="text-muted">PHP versie</td><td><?= htmlspecialchars($stats['php_version']) ?></td></tr>
|
||||
<tr><td class="text-muted">Besturingssysteem</td><td><?= htmlspecialchars($stats['os']) ?></td></tr>
|
||||
<tr><td class="text-muted">Config geladen</td><td><?php if ($stats['config_exists']): ?><span class="badge bg-success">Ja</span><?php else: ?><span class="badge bg-danger">Nee</span><?php endif; ?></td></tr>
|
||||
<tr><td class="text-muted"><?= htmlspecialchars($tr('site_title')) ?></td><td><?= htmlspecialchars($siteTitle) ?></td></tr>
|
||||
<tr><td class="text-muted"><?= htmlspecialchars($tr('default_lang')) ?></td><td><?= htmlspecialchars($defaultLang) ?></td></tr>
|
||||
<tr><td class="text-muted"><?= htmlspecialchars($tr('cms_version')) ?></td><td><?= htmlspecialchars($stats['cms_version']) ?></td></tr>
|
||||
<tr><td class="text-muted"><?= htmlspecialchars($tr('php_version')) ?></td><td><?= htmlspecialchars($stats['php_version']) ?></td></tr>
|
||||
<tr><td class="text-muted"><?= htmlspecialchars($tr('os')) ?></td><td><?= htmlspecialchars($stats['os']) ?></td></tr>
|
||||
<tr><td class="text-muted"><?= htmlspecialchars($tr('config_loaded')) ?></td><td><?php if ($stats['config_exists']): ?><span class="badge bg-success"><?= htmlspecialchars($tr('yes')) ?></span><?php else: ?><span class="badge bg-danger"><?= htmlspecialchars($tr('no')) ?></span><?php endif; ?></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -89,12 +97,12 @@ class Dashboard
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header"><i class="bi bi-folder2-open"></i> Content informatie</div>
|
||||
<div class="card-header"><i class="bi bi-folder2-open"></i> <?= htmlspecialchars($tr('content_info')) ?></div>
|
||||
<div class="card-body">
|
||||
<table class="table table-sm mb-0">
|
||||
<tr><td class="text-muted">Pagina's</td><td><span class="badge bg-primary"><?= $stats['pages'] ?></span></td></tr>
|
||||
<tr><td class="text-muted">Mappen</td><td><span class="badge bg-warning text-dark"><?= $stats['directories'] ?></span></td></tr>
|
||||
<tr><td class="text-muted">Content grootte</td><td><?= htmlspecialchars($stats['content_size']) ?></td></tr>
|
||||
<tr><td class="text-muted"><?= htmlspecialchars($tr('pages')) ?></td><td><span class="badge bg-primary"><?= $stats['pages'] ?></span></td></tr>
|
||||
<tr><td class="text-muted"><?= htmlspecialchars($tr('folders')) ?></td><td><span class="badge bg-warning text-dark"><?= $stats['directories'] ?></span></td></tr>
|
||||
<tr><td class="text-muted"><?= htmlspecialchars($tr('content_size')) ?></td><td><?= htmlspecialchars($stats['content_size']) ?></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -103,8 +111,8 @@ class Dashboard
|
||||
<div class="col-md-6">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<span><i class="bi bi-plug"></i> Plugins</span>
|
||||
<a href="/admin/plugins" class="btn btn-sm btn-outline-secondary">Beheren</a>
|
||||
<span><i class="bi bi-plug"></i> <?= htmlspecialchars($tr('plugins')) ?></span>
|
||||
<a href="/admin/plugins" class="btn btn-sm btn-outline-secondary"><?= htmlspecialchars($tr('manage')) ?></a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-sm mb-0">
|
||||
@@ -113,22 +121,22 @@ class Dashboard
|
||||
<td>
|
||||
<i class="bi bi-plug-fill"></i> <?= htmlspecialchars($pluginName) ?>
|
||||
<?php if ($info['type'] === 'system'): ?>
|
||||
<span class="badge bg-secondary fs-7">systeem</span>
|
||||
<span class="badge bg-secondary fs-7"><?= htmlspecialchars($tr('plugin_type_system')) ?></span>
|
||||
<?php else: ?>
|
||||
<span class="badge bg-info fs-7">content</span>
|
||||
<span class="badge bg-info fs-7"><?= htmlspecialchars($tr('plugin_type_content')) ?></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($info['enabled']): ?>
|
||||
<span class="badge bg-success">Actief</span>
|
||||
<span class="badge bg-success"><?= htmlspecialchars($tr('active')) ?></span>
|
||||
<?php else: ?>
|
||||
<span class="badge bg-secondary">Inactief</span>
|
||||
<span class="badge bg-secondary"><?= htmlspecialchars($tr('inactive')) ?></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php if (empty($pluginOverview)): ?>
|
||||
<tr><td colspan="2" class="text-muted text-center">Geen plugins gevonden.</td></tr>
|
||||
<tr><td colspan="2" class="text-muted text-center"><?= htmlspecialchars($tr('no_plugins')) ?></td></tr>
|
||||
<?php endif; ?>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
# Dashboard Plugin
|
||||
|
||||
Toont site informatie, content statistieken en een plugin overzicht op het admin dashboard.
|
||||
|
||||
## Plugin type
|
||||
|
||||
**Systeem** plugin. De plugin-output volgt de geselecteerde **admin taal** (via `AdminPluginAPI::getPluginTranslations()` met `admin.php`).
|
||||
|
||||
## Bestandsstructuur
|
||||
|
||||
```
|
||||
Dashboard/
|
||||
├── Dashboard.php # Hoofd plugin class
|
||||
├── plugin.json # Plugin metadata + instellingen
|
||||
├── README.md # Dit bestand
|
||||
├── assets/ # Optionele CSS/JS (leeg)
|
||||
└── language/ # Vertalingen
|
||||
├── nl/admin.php # Nederlandse admin labels
|
||||
└── en/admin.php # Engelse admin labels
|
||||
```
|
||||
|
||||
## Functies
|
||||
|
||||
- **Site informatie**: Site titel, standaard taal, CodePress/PHP versie, OS, config status
|
||||
- **Content informatie**: Aantal pagina's, mappen, content grootte
|
||||
- **Plugin overzicht**: Lijst van alle plugins met type (systeem/content) en actief/inactief status
|
||||
|
||||
## Instellingen
|
||||
|
||||
Deze plugin heeft geen instelbare configuratie (`hasConfig: false`).
|
||||
|
||||
## Taal support
|
||||
|
||||
De plugin gebruikt `AdminPluginAPI::getPluginTranslations('Dashboard')` om labels op te halen. Fallback chain:
|
||||
1. Geselecteerde admin taal
|
||||
2. Plugin `default_language` (`nl`)
|
||||
3. Lege array (sleutel wordt ongewijzigd getoond)
|
||||
|
||||
Beschikbare sleutels staan in `language/<lang>/admin.php`. Het admin-menu label wordt vertaald via `label_key: 'menu_label'` in `getAdminMenu()`.
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
return [
|
||||
// Menu
|
||||
'menu_label' => 'Dashboard',
|
||||
|
||||
// Page header
|
||||
'page_title' => 'Dashboard',
|
||||
|
||||
// Site information card
|
||||
'site_info' => 'Site information',
|
||||
'site_title' => 'Site title',
|
||||
'default_lang' => 'Default language',
|
||||
'cms_version' => 'CodePress version',
|
||||
'php_version' => 'PHP version',
|
||||
'os' => 'Operating system',
|
||||
'config_loaded' => 'Config loaded',
|
||||
'yes' => 'Yes',
|
||||
'no' => 'No',
|
||||
|
||||
// Content information card
|
||||
'content_info' => 'Content information',
|
||||
'pages' => 'Pages',
|
||||
'folders' => 'Folders',
|
||||
'content_size' => 'Content size',
|
||||
|
||||
// Plugins card
|
||||
'plugins' => 'Plugins',
|
||||
'manage' => 'Manage',
|
||||
'plugin_type_system' => 'system',
|
||||
'plugin_type_content' => 'content',
|
||||
'active' => 'Active',
|
||||
'inactive' => 'Inactive',
|
||||
'no_plugins' => 'No plugins found.',
|
||||
];
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
return [
|
||||
// Menu
|
||||
'menu_label' => 'Dashboard',
|
||||
|
||||
// Page header
|
||||
'page_title' => 'Dashboard',
|
||||
|
||||
// Site informatie card
|
||||
'site_info' => 'Site informatie',
|
||||
'site_title' => 'Site titel',
|
||||
'default_lang' => 'Standaard taal',
|
||||
'cms_version' => 'CodePress versie',
|
||||
'php_version' => 'PHP versie',
|
||||
'os' => 'Besturingssysteem',
|
||||
'config_loaded' => 'Config geladen',
|
||||
'yes' => 'Ja',
|
||||
'no' => 'Nee',
|
||||
|
||||
// Content informatie card
|
||||
'content_info' => 'Content informatie',
|
||||
'pages' => "Pagina's",
|
||||
'folders' => 'Mappen',
|
||||
'content_size' => 'Content grootte',
|
||||
|
||||
// Plugins card
|
||||
'plugins' => 'Plugins',
|
||||
'manage' => 'Beheren',
|
||||
'plugin_type_system' => 'systeem',
|
||||
'plugin_type_content' => 'content',
|
||||
'active' => 'Actief',
|
||||
'inactive' => 'Inactief',
|
||||
'no_plugins' => 'Geen plugins gevonden.',
|
||||
];
|
||||
@@ -5,5 +5,7 @@
|
||||
"description": "Toont site informatie, content statistieken en plugin overzicht op het dashboard.",
|
||||
"type": "system",
|
||||
"essential": true,
|
||||
"hasConfig": false
|
||||
"hasConfig": false,
|
||||
"default_language": "nl",
|
||||
"settings": []
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
class GeoIPInfo
|
||||
{
|
||||
private ?CMSAPI $api = null;
|
||||
private ?PluginAPIInterface $api = null;
|
||||
|
||||
public function setAPI(CMSAPI $api): void
|
||||
public function setAPI(PluginAPIInterface $api): void
|
||||
{
|
||||
$this->api = $api;
|
||||
}
|
||||
@@ -23,7 +23,13 @@ class GeoIPInfo
|
||||
public function getAdminMenu(): array
|
||||
{
|
||||
return [
|
||||
['label' => 'GeoIP Info', 'route' => 'geoip-info', 'icon' => 'bi-globe2'],
|
||||
[
|
||||
'plugin' => 'GeoIPInfo',
|
||||
'label' => 'GeoIP Info',
|
||||
'label_key' => 'menu_label',
|
||||
'route' => 'geoip-info',
|
||||
'icon' => 'bi-globe2',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -46,11 +52,16 @@ class GeoIPInfo
|
||||
$country = GeoIP::getCountryName($countryCode);
|
||||
$flag = GeoIP::getCountryFlagEmoji($countryCode);
|
||||
|
||||
echo '<h2 class="mb-4"><i class="bi bi-globe2"></i> GeoIP Info</h2>';
|
||||
$t = $this->api ? $this->api->getPluginTranslations('GeoIPInfo') : [];
|
||||
$tr = function (string $key) use ($t): string {
|
||||
return $t[$key] ?? $key;
|
||||
};
|
||||
|
||||
echo '<h2 class="mb-4"><i class="bi bi-globe2"></i> ' . htmlspecialchars($tr('page_title')) . '</h2>';
|
||||
echo '<div class="card shadow-sm"><div class="card-body">';
|
||||
echo '<table class="table table-sm">';
|
||||
echo '<tr><td>IP adres</td><td><code>' . htmlspecialchars($ip) . '</code></td></tr>';
|
||||
echo '<tr><td>Land</td><td>' . $flag . ' ' . htmlspecialchars($country) . '</td></tr>';
|
||||
echo '<tr><td>' . htmlspecialchars($tr('ip_address')) . '</td><td><code>' . htmlspecialchars($ip) . '</code></td></tr>';
|
||||
echo '<tr><td>' . htmlspecialchars($tr('country')) . '</td><td>' . $flag . ' ' . htmlspecialchars($country) . '</td></tr>';
|
||||
echo '</table>';
|
||||
echo '</div></div>';
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# GeoIPInfo Plugin
|
||||
|
||||
Systeem plugin die GeoIP-informatie (IP adres en land) toont op een admin-pagina.
|
||||
|
||||
## Plugin type
|
||||
|
||||
**Systeem** plugin. De plugin-output volgt de geselecteerde **admin taal** (via `AdminPluginAPI::getPluginTranslations()` met `admin.php`).
|
||||
|
||||
## Bestandsstructuur
|
||||
|
||||
```
|
||||
GeoIPInfo/
|
||||
├── GeoIPInfo.php # Hoofd plugin class
|
||||
├── plugin.json # Plugin metadata + instellingen
|
||||
├── README.md # Dit bestand
|
||||
├── assets/ # Optionele CSS/JS (leeg)
|
||||
└── language/ # Vertalingen
|
||||
├── nl/admin.php # Nederlandse admin labels
|
||||
└── en/admin.php # Engelse admin labels
|
||||
```
|
||||
|
||||
## Functies
|
||||
|
||||
- Toont het IP adres van de bezoeker
|
||||
- Toont het land (met vlag-emoji) gebaseerd op GeoIP lookup
|
||||
|
||||
## Instellingen
|
||||
|
||||
Deze plugin heeft geen instelbare configuratie (`hasConfig: false`).
|
||||
|
||||
## Taal support
|
||||
|
||||
De plugin gebruikt `AdminPluginAPI::getPluginTranslations('GeoIPInfo')` om labels op te halen. Fallback chain:
|
||||
1. Geselecteerde admin taal
|
||||
2. Plugin `default_language` (`nl`)
|
||||
3. Lege array (sleutel wordt ongewijzigd getoond)
|
||||
|
||||
Beschikbare sleutels staan in `language/<lang>/admin.php`. Het admin-menu label wordt vertaald via `label_key: 'menu_label'` in `getAdminMenu()`.
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
return [
|
||||
// Menu
|
||||
'menu_label' => 'GeoIP Info',
|
||||
|
||||
// Page
|
||||
'page_title' => 'GeoIP Info',
|
||||
'ip_address' => 'IP address',
|
||||
'country' => 'Country',
|
||||
];
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
return [
|
||||
// Menu
|
||||
'menu_label' => 'GeoIP Info',
|
||||
|
||||
// Page
|
||||
'page_title' => 'GeoIP Info',
|
||||
'ip_address' => 'IP adres',
|
||||
'country' => 'Land',
|
||||
];
|
||||
@@ -3,5 +3,9 @@
|
||||
"version": "1.0.0",
|
||||
"author": "CodePress",
|
||||
"description": "Systeem plugin voor GeoIP informatie in admin",
|
||||
"type": "system"
|
||||
"type": "system",
|
||||
"essential": false,
|
||||
"hasConfig": false,
|
||||
"default_language": "nl",
|
||||
"settings": []
|
||||
}
|
||||
@@ -20,16 +20,22 @@ class HTMLBlock
|
||||
|
||||
public function getSidebarContent(): string
|
||||
{
|
||||
$currentPage = $this->api ? $this->api->getCurrentPageTitle() : 'Onbekend';
|
||||
// Content plugin: translations follow the current content language.
|
||||
$t = $this->api ? $this->api->getPluginTranslations('HTMLBlock') : [];
|
||||
$tr = function (string $key) use ($t): string {
|
||||
return $t[$key] ?? $key;
|
||||
};
|
||||
|
||||
$currentPage = $this->api ? $this->api->getCurrentPageTitle() : $tr('unknown');
|
||||
$isHomepage = $this->api ? $this->api->isHomepage() : false;
|
||||
$currentLang = $this->api ? $this->api->getCurrentLanguage() : 'nl';
|
||||
$currentPath = $_GET['page'] ?? '';
|
||||
$currentPath = preg_replace('/\.(md|php|html)$/', '', $currentPath);
|
||||
|
||||
$content = '
|
||||
<p class="mb-2"><strong>Huidige pagina:</strong> ' . htmlspecialchars($currentPage) . '</p>
|
||||
<p class="mb-2"><strong>Taal:</strong> ' . strtoupper($currentLang) . '</p>
|
||||
<p class="mb-3"><strong>Homepage:</strong> ' . ($isHomepage ? 'Ja' : 'Nee') . '</p>';
|
||||
<p class="mb-2"><strong>' . htmlspecialchars($tr('current_page')) . ':</strong> ' . htmlspecialchars($currentPage) . '</p>
|
||||
<p class="mb-2"><strong>' . htmlspecialchars($tr('language')) . ':</strong> ' . strtoupper($currentLang) . '</p>
|
||||
<p class="mb-3"><strong>' . htmlspecialchars($tr('homepage')) . ':</strong> ' . htmlspecialchars($isHomepage ? $tr('yes') : $tr('no')) . '</p>';
|
||||
|
||||
// Add page-specific content
|
||||
if ($this->api) {
|
||||
@@ -38,9 +44,9 @@ class HTMLBlock
|
||||
$content .= '
|
||||
<div class="alert alert-info mb-3">
|
||||
<small>
|
||||
<strong>Bestandsinfo:</strong><br>
|
||||
Aangemaakt: ' . htmlspecialchars($fileInfo['created']) . '<br>
|
||||
Gewijzigd: ' . htmlspecialchars($fileInfo['modified']) . '
|
||||
<strong>' . htmlspecialchars($tr('file_info')) . ':</strong><br>
|
||||
' . htmlspecialchars($tr('created')) . ': ' . htmlspecialchars($fileInfo['created']) . '<br>
|
||||
' . htmlspecialchars($tr('modified')) . ': ' . htmlspecialchars($fileInfo['modified']) . '
|
||||
</small>
|
||||
</div>';
|
||||
}
|
||||
@@ -49,7 +55,7 @@ class HTMLBlock
|
||||
$menu = $this->api->getMenu();
|
||||
if (!empty($menu)) {
|
||||
$content .= '
|
||||
<h6>Quick Navigation</h6>
|
||||
<h6>' . htmlspecialchars($tr('quick_navigation')) . '</h6>
|
||||
<ul class="list-unstyled mb-3">';
|
||||
|
||||
foreach ($menu as $item) {
|
||||
|
||||
+30
-91
@@ -1,100 +1,39 @@
|
||||
# HTMLBlock Plugin
|
||||
|
||||
Deze plugin toont een custom HTML blok in de sidebar met pagina-informatie en navigatie.
|
||||
Toont een custom HTML-blok in de sidebar van content-pagina's met pagina-informatie en quick navigation.
|
||||
|
||||
## Functies
|
||||
## Plugin type
|
||||
|
||||
- **Pagina informatie**: Toont huidige pagina titel en metadata
|
||||
- **Bestandsinfo**: Aanmaak- en wijzigingsdatums
|
||||
- **Dynamische navigatie**: Genereert quick links uit het menu
|
||||
- **Interactive controls**: Verversen en sidebar toggle
|
||||
- **Responsive**: Werkt op desktop en mobiel
|
||||
|
||||
## Installatie
|
||||
|
||||
1. Kopieer de `HTMLBlock` map naar `plugins/`
|
||||
2. De plugin wordt automatisch geladen
|
||||
|
||||
## Gebruik
|
||||
|
||||
De plugin wordt automatisch in de sidebar geladen en toont:
|
||||
|
||||
### Huidige Pagina Info
|
||||
- Pagina titel
|
||||
- Huidige taal
|
||||
- Homepage status
|
||||
|
||||
### Bestandsinformatie
|
||||
- Aanmaakdatum
|
||||
- Laatste wijziging
|
||||
- Bestandsgrootte
|
||||
|
||||
### Quick Navigation
|
||||
- Dynamische links uit het CMS menu
|
||||
- Automatische URL generatie
|
||||
|
||||
### Interactive Controls
|
||||
- **Ververs Content**: Herlaadt de huidige pagina
|
||||
- **Toggle Sidebar**: Toont/verbergt de sidebar
|
||||
|
||||
## Customization
|
||||
|
||||
De plugin content kan worden aangepast door de `getSidebarContent()` methode te wijzigen in `HTMLBlock.php`.
|
||||
|
||||
### Voorbeeld Custom Content
|
||||
|
||||
```php
|
||||
public function getSidebarContent(): string
|
||||
{
|
||||
$currentPage = $this->api ? $this->api->getCurrentPageTitle() : 'Onbekend';
|
||||
|
||||
return '
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5>Mijn Custom Block</h5>
|
||||
<p>Huidige pagina: ' . htmlspecialchars($currentPage) . '</p>
|
||||
</div>
|
||||
</div>';
|
||||
}
|
||||
```
|
||||
|
||||
## API Integration
|
||||
|
||||
De plugin maakt gebruik van de CMS API voor:
|
||||
|
||||
- `getCurrentPageTitle()` - Huidige pagina titel
|
||||
- `getCurrentLanguage()` - Huidige taal
|
||||
- `isHomepage()` - Check of homepage
|
||||
- `getCurrentPageFileInfo()` - Bestandsinformatie
|
||||
- `getMenu()` - Menu structuur
|
||||
- `createUrl($page, $lang)` - URL generatie
|
||||
|
||||
## Styling
|
||||
|
||||
De plugin gebruikt Bootstrap 5 classes:
|
||||
- `card`, `card-header`, `card-body` voor kaarten
|
||||
- `btn`, `btn-outline-primary` voor knoppen
|
||||
- `list-unstyled` voor navigatie
|
||||
|
||||
## JavaScript
|
||||
|
||||
De plugin bevat JavaScript voor:
|
||||
- Pagina verversen
|
||||
- Sidebar toggle functionaliteit
|
||||
- Dynamische content updates
|
||||
|
||||
## Development
|
||||
|
||||
De plugin is een goed voorbeeld voor:
|
||||
- API integratie
|
||||
- Dynamic content generatie
|
||||
- User interface components
|
||||
- Responsive design
|
||||
**Content** plugin. De plugin-output volgt de geselecteerde **content taal** (via `CMSAPI::getPluginTranslations()` met `site.php`).
|
||||
|
||||
## Bestandsstructuur
|
||||
|
||||
```
|
||||
HTMLBlock/
|
||||
├── HTMLBlock.php # Hoofd plugin bestand
|
||||
└── README.md # Deze documentatie
|
||||
```
|
||||
├── HTMLBlock.php # Hoofd plugin class
|
||||
├── plugin.json # Plugin metadata + instellingen
|
||||
├── README.md # Dit bestand
|
||||
├── assets/ # Optionele CSS/JS (leeg)
|
||||
└── language/ # Vertalingen
|
||||
├── nl/site.php # Nederlandse front-end labels
|
||||
└── en/site.php # Engelse front-end labels
|
||||
```
|
||||
|
||||
## Functies
|
||||
|
||||
- **Pagina informatie**: Toont huidige pagina titel en metadata
|
||||
- **Bestandsinfo**: Aanmaak- en wijzigingsdatums
|
||||
- **Quick Navigation**: Genereert quick links uit het CMS menu
|
||||
|
||||
## Instellingen
|
||||
|
||||
Deze plugin heeft geen instelbare configuratie (`hasConfig: false`).
|
||||
|
||||
## Taal support
|
||||
|
||||
De plugin gebruikt `CMSAPI::getPluginTranslations('HTMLBlock')` om labels op te halen. Fallback chain:
|
||||
1. Geselecteerde content taal
|
||||
2. Plugin `default_language` (`nl`)
|
||||
3. Lege array (sleutel wordt ongewijzigd getoond)
|
||||
|
||||
Beschikbare sleutels staan in `language/<lang>/site.php`.
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
return [
|
||||
// Sidebar card
|
||||
'title' => 'HTML Block',
|
||||
'current_page' => 'Current page',
|
||||
'language' => 'Language',
|
||||
'homepage' => 'Homepage',
|
||||
'yes' => 'Yes',
|
||||
'no' => 'No',
|
||||
'unknown' => 'Unknown',
|
||||
'file_info' => 'File info',
|
||||
'created' => 'Created',
|
||||
'modified' => 'Modified',
|
||||
'quick_navigation' => 'Quick Navigation',
|
||||
];
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
return [
|
||||
// Sidebar card
|
||||
'title' => 'HTML Block',
|
||||
'current_page' => 'Huidige pagina',
|
||||
'language' => 'Taal',
|
||||
'homepage' => 'Homepage',
|
||||
'yes' => 'Ja',
|
||||
'no' => 'Nee',
|
||||
'unknown' => 'Onbekend',
|
||||
'file_info' => 'Bestandsinfo',
|
||||
'created' => 'Aangemaakt',
|
||||
'modified' => 'Gewijzigd',
|
||||
'quick_navigation' => 'Quick Navigation',
|
||||
];
|
||||
@@ -5,5 +5,7 @@
|
||||
"description": "Toont aangepaste HTML-blokken in de sidebar van content-pagina's.",
|
||||
"type": "content",
|
||||
"essential": false,
|
||||
"hasConfig": false
|
||||
"hasConfig": false,
|
||||
"default_language": "nl",
|
||||
"settings": []
|
||||
}
|
||||
+59
-9
@@ -20,19 +20,63 @@ class Logs
|
||||
|
||||
public function getAdminMenu(): array
|
||||
{
|
||||
$config = $this->getPluginConfig();
|
||||
$requiredRoles = $config['required_roles'] ?? ['bi-manager', 'site-admin', 'admin'];
|
||||
|
||||
return [
|
||||
[
|
||||
'plugin' => 'Logs',
|
||||
'route' => 'logs',
|
||||
'label' => 'Logs',
|
||||
'label_key' => 'menu_label',
|
||||
'icon' => 'bi-journal-text',
|
||||
'section' => 'general',
|
||||
'permission' => 'logs',
|
||||
'required_roles' => $requiredRoles,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this plugin's runtime config (defaults + overrides).
|
||||
*/
|
||||
private function getPluginConfig(): array
|
||||
{
|
||||
$pluginDir = dirname(__DIR__);
|
||||
$pluginJsonFile = $pluginDir . '/plugin.json';
|
||||
$configJsonFile = $pluginDir . '/config.json';
|
||||
|
||||
$defaults = [];
|
||||
if (file_exists($pluginJsonFile)) {
|
||||
$pluginJson = json_decode(file_get_contents($pluginJsonFile), true) ?? [];
|
||||
foreach ($pluginJson['settings'] ?? [] as $setting) {
|
||||
if (isset($setting['key'])) {
|
||||
$defaults[$setting['key']] = $setting['default'] ?? null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$overrides = [];
|
||||
if (file_exists($configJsonFile)) {
|
||||
$overrides = json_decode(file_get_contents($configJsonFile), true) ?? [];
|
||||
}
|
||||
|
||||
return array_merge($defaults, $overrides);
|
||||
}
|
||||
|
||||
public function handleAdminRoute(string $action): ?string
|
||||
{
|
||||
$config = $this->getPluginConfig();
|
||||
$maxLines = (int)($config['max_lines'] ?? 100);
|
||||
$showAdminTab = $config['show_admin_tab'] ?? true;
|
||||
$showRequestsTab = $config['show_requests_tab'] ?? true;
|
||||
|
||||
// System plugin: translations resolve against the admin language.
|
||||
$t = $this->api ? $this->api->getPluginTranslations('Logs') : [];
|
||||
$tr = function (string $key) use ($t): string {
|
||||
return $t[$key] ?? $key;
|
||||
};
|
||||
|
||||
$tab = $_GET['tab'] ?? 'admin';
|
||||
$logDir = dirname(__DIR__, 2) . '/admin/storage/logs';
|
||||
$logFile = $tab === 'requests' ? $logDir . '/requests.log' : $logDir . '/admin.log';
|
||||
@@ -40,7 +84,7 @@ class Logs
|
||||
$logs = [];
|
||||
if (file_exists($logFile)) {
|
||||
$lines = file($logFile) ?: [];
|
||||
$lines = array_slice($lines, -100);
|
||||
$lines = array_slice($lines, -$maxLines);
|
||||
foreach ($lines as $line) {
|
||||
if (preg_match('/^\[([^\]]+)\] \[([^\]]+)\] \[([^\]]+)\] (.+)$/', trim($line), $m)) {
|
||||
$logs[] = [
|
||||
@@ -56,31 +100,37 @@ class Logs
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<h2 class="mb-4"><i class="bi bi-journal-text"></i> Logs</h2>
|
||||
<h2 class="mb-4"><i class="bi bi-journal-text"></i> <?= htmlspecialchars($tr('page_title')) ?></h2>
|
||||
|
||||
<?php if ($showAdminTab || $showRequestsTab): ?>
|
||||
<ul class="nav nav-tabs mb-3">
|
||||
<?php if ($showAdminTab): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= $tab === 'admin' ? 'active' : '' ?>" href="/admin/logs?tab=admin">Admin</a>
|
||||
<a class="nav-link <?= $tab === 'admin' ? 'active' : '' ?>" href="/admin/logs?tab=admin"><?= htmlspecialchars($tr('tab_admin')) ?></a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<?php if ($showRequestsTab): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= $tab === 'requests' ? 'active' : '' ?>" href="/admin/logs?tab=requests">Requests</a>
|
||||
<a class="nav-link <?= $tab === 'requests' ? 'active' : '' ?>" href="/admin/logs?tab=requests"><?= htmlspecialchars($tr('tab_requests')) ?></a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body p-0">
|
||||
<table class="table table-hover mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Tijd</th>
|
||||
<th>Level</th>
|
||||
<th>IP</th>
|
||||
<th>Bericht</th>
|
||||
<th><?= htmlspecialchars($tr('col_time')) ?></th>
|
||||
<th><?= htmlspecialchars($tr('col_level')) ?></th>
|
||||
<th><?= htmlspecialchars($tr('col_ip')) ?></th>
|
||||
<th><?= htmlspecialchars($tr('col_message')) ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($logs)): ?>
|
||||
<tr><td colspan="4" class="text-muted text-center py-4">Geen logs gevonden.</td></tr>
|
||||
<tr><td colspan="4" class="text-muted text-center py-4"><?= htmlspecialchars($tr('no_logs')) ?></td></tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($logs as $log): ?>
|
||||
<tr>
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# Logs Plugin
|
||||
|
||||
Toont admin activiteitlogs en front-end request logs met filter tabs op een admin-pagina.
|
||||
|
||||
## Plugin type
|
||||
|
||||
**Systeem** plugin. De plugin-output volgt de geselecteerde **admin taal** (via `AdminPluginAPI::getPluginTranslations()` met `admin.php`).
|
||||
|
||||
## Bestandsstructuur
|
||||
|
||||
```
|
||||
Logs/
|
||||
├── Logs.php # Hoofd plugin class
|
||||
├── plugin.json # Plugin metadata + instellingen
|
||||
├── README.md # Dit bestand
|
||||
├── assets/ # Optionele CSS/JS (leeg)
|
||||
└── language/ # Vertalingen
|
||||
├── nl/admin.php # Nederlandse admin labels
|
||||
└── en/admin.php # Engelse admin labels
|
||||
```
|
||||
|
||||
## Functies
|
||||
|
||||
- **Admin tab**: Toont admin activiteitlogs (uit `admin/storage/logs/admin.log`)
|
||||
- **Requests tab**: Toont front-end request logs (uit `admin/storage/logs/requests.log`)
|
||||
- Tabbladen kunnen via de instellingen in/uitgeschakeld worden
|
||||
- Aantal getoonde regels is instelbaar (meest recente eerst)
|
||||
|
||||
## Instellingen
|
||||
|
||||
Deze plugin heeft instelbare configuratie (`hasConfig: true`). Instellingen worden gedefinieerd in `plugin.json` onder `settings` en overschreven via `config.json`.
|
||||
|
||||
| Sleutel | Type | Standaard | Beschrijving |
|
||||
|---------|------|-----------|--------------|
|
||||
| `required_roles` | multi-select | `bi-manager, site-admin, admin` | Rollen die deze plugin mogen zien |
|
||||
| `max_lines` | number | `100` | Aantal logregels dat getoond wordt (meest recente eerst) |
|
||||
| `show_admin_tab` | checkbox | `true` | Schakel de admin activiteit-log tab in of uit |
|
||||
| `show_requests_tab` | checkbox | `true` | Schakel de front-end request-log tab in of uit |
|
||||
|
||||
De label- en help-teksten voor instellingen worden vertaald via `label_key`/`help_key` (verwijst naar sleutels in `language/<lang>/admin.php`).
|
||||
|
||||
## Taal support
|
||||
|
||||
De plugin gebruikt `AdminPluginAPI::getPluginTranslations('Logs')` om labels op te halen. Fallback chain:
|
||||
1. Geselecteerde admin taal
|
||||
2. Plugin `default_language` (`nl`)
|
||||
3. Lege array (sleutel wordt ongewijzigd getoond)
|
||||
|
||||
Beschikbare sleutels staan in `language/<lang>/admin.php`. Het admin-menu label wordt vertaald via `label_key: 'menu_label'` in `getAdminMenu()`.
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
return [
|
||||
// Menu
|
||||
'menu_label' => 'Logs',
|
||||
|
||||
// Page
|
||||
'page_title' => 'Logs',
|
||||
'tab_admin' => 'Admin',
|
||||
'tab_requests' => 'Requests',
|
||||
'col_time' => 'Time',
|
||||
'col_level' => 'Level',
|
||||
'col_ip' => 'IP',
|
||||
'col_message' => 'Message',
|
||||
'no_logs' => 'No logs found.',
|
||||
'analytics_disabled' => 'Analytics is disabled.',
|
||||
|
||||
// Settings (plugin.json label_key/help_key)
|
||||
'setting_required_roles' => 'Roles allowed to view this plugin',
|
||||
'setting_required_roles_help' => 'Determines which roles can access the logs page in the admin panel. Admin always has access.',
|
||||
'role_options' => [
|
||||
'admin' => 'Admin',
|
||||
'content-manager' => 'Content Manager',
|
||||
'bi-manager' => 'BI Manager',
|
||||
'site-admin' => 'Site Admin',
|
||||
],
|
||||
'setting_max_lines' => 'Maximum number of lines',
|
||||
'setting_max_lines_help' => 'Number of log lines shown (most recent first).',
|
||||
'setting_show_admin_tab' => 'Show admin log tab',
|
||||
'setting_show_admin_tab_help' => 'Enable or disable the admin activity log tab.',
|
||||
'setting_show_requests_tab' => 'Show request log tab',
|
||||
'setting_show_requests_tab_help' => 'Enable or disable the front-end request log tab.',
|
||||
];
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
return [
|
||||
// Menu
|
||||
'menu_label' => 'Logs',
|
||||
|
||||
// Page
|
||||
'page_title' => 'Logs',
|
||||
'tab_admin' => 'Admin',
|
||||
'tab_requests' => 'Requests',
|
||||
'col_time' => 'Tijd',
|
||||
'col_level' => 'Level',
|
||||
'col_ip' => 'IP',
|
||||
'col_message' => 'Bericht',
|
||||
'no_logs' => 'Geen logs gevonden.',
|
||||
'analytics_disabled' => 'Analytics is uitgeschakeld.',
|
||||
|
||||
// Settings (plugin.json label_key/help_key)
|
||||
'setting_required_roles' => 'Rollen die deze plugin mogen zien',
|
||||
'setting_required_roles_help' => 'Bepaalt welke rollen toegang hebben tot de logs-pagina in het admin-paneel. Admin heeft altijd toegang.',
|
||||
'role_options' => [
|
||||
'admin' => 'Admin',
|
||||
'content-manager' => 'Content Beheerder',
|
||||
'bi-manager' => 'BI Beheerder',
|
||||
'site-admin' => 'Site Admin',
|
||||
],
|
||||
'setting_max_lines' => 'Maximaal aantal regels',
|
||||
'setting_max_lines_help' => 'Aantal logregels dat getoond wordt (meest recente eerst).',
|
||||
'setting_show_admin_tab' => 'Toon admin-log tab',
|
||||
'setting_show_admin_tab_help' => 'Schakel de admin activiteit-log tab in of uit.',
|
||||
'setting_show_requests_tab' => 'Toon request-log tab',
|
||||
'setting_show_requests_tab_help' => 'Schakel de front-end request-log tab in of uit.',
|
||||
];
|
||||
@@ -5,5 +5,43 @@
|
||||
"description": "Toont admin activiteitlogs en front-end request logs met filter tabs.",
|
||||
"type": "system",
|
||||
"essential": false,
|
||||
"hasConfig": true
|
||||
"hasConfig": true,
|
||||
"default_language": "nl",
|
||||
"settings": [
|
||||
{
|
||||
"key": "required_roles",
|
||||
"label_key": "setting_required_roles",
|
||||
"help_key": "setting_required_roles_help",
|
||||
"option_label_key": "role_options",
|
||||
"type": "multi-select",
|
||||
"default": ["bi-manager", "site-admin", "admin"],
|
||||
"options": {
|
||||
"admin": "Admin",
|
||||
"content-manager": "Content Beheerder",
|
||||
"bi-manager": "BI Beheerder",
|
||||
"site-admin": "Site Admin"
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": "max_lines",
|
||||
"label_key": "setting_max_lines",
|
||||
"help_key": "setting_max_lines_help",
|
||||
"type": "number",
|
||||
"default": 100
|
||||
},
|
||||
{
|
||||
"key": "show_admin_tab",
|
||||
"label_key": "setting_show_admin_tab",
|
||||
"help_key": "setting_show_admin_tab_help",
|
||||
"type": "checkbox",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"key": "show_requests_tab",
|
||||
"label_key": "setting_show_requests_tab",
|
||||
"help_key": "setting_show_requests_tab_help",
|
||||
"type": "checkbox",
|
||||
"default": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
# Navigation Plugin
|
||||
|
||||
Essentiële content plugin die navigatie toont voor handleidingen en content in de sidebar.
|
||||
|
||||
## Plugin type
|
||||
|
||||
**Content** plugin. De plugin-output volgt de geselecteerde **content taal** (via `CMSAPI::getPluginTranslations()` met `site.php`).
|
||||
|
||||
## Bestandsstructuur
|
||||
|
||||
```
|
||||
Navigation/
|
||||
├── Navigation.php # Hoofd plugin class
|
||||
├── plugin.json # Plugin metadata + instellingen
|
||||
├── README.md # Dit bestand
|
||||
├── assets/ # CSS/SCSS voor navigatie
|
||||
│ ├── css/navigation.css
|
||||
│ └── scss/navigation.scss
|
||||
└── language/ # Vertalingen
|
||||
├── nl/site.php # Nederlandse front-end labels
|
||||
└── en/site.php # Engelse front-end labels
|
||||
```
|
||||
|
||||
## Functies
|
||||
|
||||
- **Content navigatie**: Bouwt een sidebar navigatie uit de content-mapstructuur
|
||||
- **Handleiding navigatie**: Bouwt een sidebar navigatie uit de guide-mapstructuur
|
||||
- Detecteert automatisch of de huidige pagina een handleiding of content pagina is
|
||||
- Toont mappen (met kinderen) en bestanden (.md, .php, .html)
|
||||
- Strip taal-prefixen uit bestandsnamen (bijv. `nl.pagina.md` → `Pagina`)
|
||||
|
||||
## Instellingen
|
||||
|
||||
Deze plugin heeft geen instelbare configuratie (`hasConfig: false`). Wel levert hij een CSS-URL via `getCssUrl()`.
|
||||
|
||||
## Taal support
|
||||
|
||||
De plugin-output bestaat voornamelijk uit bestands- en mapnamen (die uit de content zelf komen), dus er zijn weinig te vertalen UI-strings. De `language/<lang>/site.php` bestanden bevatten momenteel alleen `plugin_title` voor uniformiteit met de andere plugins en toekomstige uitbreiding.
|
||||
|
||||
De plugin gebruikt `CMSAPI::getPluginTranslations('Navigation')` om labels op te halen. Fallback chain:
|
||||
1. Geselecteerde content taal
|
||||
2. Plugin `default_language` (`nl`)
|
||||
3. Lege array (sleutel wordt ongewijzigd getoond)
|
||||
|
||||
## Beschermd
|
||||
|
||||
Deze plugin is **protected**: hardcoded in `public/admin.php` (`getProtectedPlugins()`) en kan niet worden uitgeschakeld, verwijderd of bewerkt via de admin interface.
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
// Navigation is a content plugin. Its sidebar output is built from file and
|
||||
// directory names, so there are very few translatable UI strings. This file
|
||||
// exists for uniformity with the other plugins and to allow future labels.
|
||||
return [
|
||||
'plugin_title' => 'Navigation',
|
||||
];
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
// Navigation is a content plugin. Its sidebar output is built from file and
|
||||
// directory names, so there are very few translatable UI strings. This file
|
||||
// exists for uniformity with the other plugins and to allow future labels.
|
||||
return [
|
||||
'plugin_title' => 'Navigatie',
|
||||
];
|
||||
@@ -5,5 +5,7 @@
|
||||
"description": "Essentiële navigatie plugin voor handleidingen en content",
|
||||
"type": "content",
|
||||
"essential": true,
|
||||
"hasConfig": false
|
||||
"hasConfig": false,
|
||||
"default_language": "nl",
|
||||
"settings": []
|
||||
}
|
||||
+76
-79
@@ -1,102 +1,99 @@
|
||||
# CodePress CMS Plugins
|
||||
|
||||
Deze map bevat plugins voor de CodePress CMS. Elke plugin heeft zijn eigen submap met de plugin code.
|
||||
Deze map bevat alle plugins voor de CodePress CMS. Elke plugin heeft zijn eigen submap.
|
||||
|
||||
## Plugin Structuur
|
||||
## Plugin overzicht
|
||||
|
||||
Elke plugin map moet het volgende bevatten:
|
||||
| Plugin | Type | Essentieel | Beschrijving |
|
||||
|--------|------|------------|--------------|
|
||||
| Dashboard | system | ja | Site informatie, content statistieken en plugin overzicht op het dashboard |
|
||||
| GeoIPInfo | system | nee | GeoIP-informatie (IP adres en land) in admin |
|
||||
| HTMLBlock | content | nee | Custom HTML-blok in de sidebar van content-pagina's |
|
||||
| Logs | system | nee | Admin activiteitlogs en front-end request logs met filter tabs |
|
||||
| Navigation | content | ja | Navigatie voor handleidingen en content (beschermd) |
|
||||
| Statistics | system | nee | Bezoekersstatistieken: views, unieke bezoekers, landen, top pagina's |
|
||||
|
||||
Elke plugin heeft een eigen `README.md` met specifieke documentatie.
|
||||
|
||||
## Plugin structuur (uniform)
|
||||
|
||||
Elke plugin-map heeft de volgende structuur:
|
||||
|
||||
```
|
||||
PluginName/
|
||||
├── PluginName.php # Hoofd plugin bestand
|
||||
├── README.md # Plugin documentatie (optioneel)
|
||||
├── config.json # Plugin configuratie (optioneel)
|
||||
└── assets/ # CSS, JS, images (optioneel)
|
||||
├── css/
|
||||
├── js/
|
||||
└── images/
|
||||
├── PluginName.php # Hoofd plugin class (naam = mapnaam)
|
||||
├── plugin.json # Plugin metadata + instellingen-schema
|
||||
├── README.md # Plugin documentatie
|
||||
├── config.json # Optionele runtime configuratie (overschrijft defaults)
|
||||
├── assets/ # Optionele CSS/JS/SCSS (.gitkeep als leeg)
|
||||
│ ├── css/
|
||||
│ └── scss/
|
||||
└── language/ # Vertalingen
|
||||
├── nl/
|
||||
│ ├── admin.php # Admin labels (systeem plugins)
|
||||
│ └── site.php # Front-end labels (content plugins)
|
||||
└── en/
|
||||
├── admin.php
|
||||
└── site.php
|
||||
```
|
||||
|
||||
## Beschikbare Plugins
|
||||
## plugin.json velden
|
||||
|
||||
### HTMLBlock
|
||||
Toont een custom HTML blok in de sidebar met pagina-informatie en navigatie.
|
||||
| Veld | Waarde | Beschrijving |
|
||||
|------|--------|--------------|
|
||||
| `name` | string | Weergavenaam in admin |
|
||||
| `version` | string | Versienummer |
|
||||
| `author` | string | Auteur |
|
||||
| `description` | string | Korte beschrijving |
|
||||
| `type` | `"system"` of `"content"` | Systeem (blauwe badge) of content (groene badge) |
|
||||
| `essential` | boolean | Essentiële plugins kunnen niet worden bewerkt/verwijderd |
|
||||
| `hasConfig` | boolean | Toont een Config-knop in admin |
|
||||
| `default_language` | string | Fallback taal voor plugin-vertalingen (bijv. `nl`) |
|
||||
| `settings` | array | Instellingen-schema (zie hieronder) |
|
||||
|
||||
**Locatie:** `HTMLBlock/HTMLBlock.php`
|
||||
### Instellingen-schema
|
||||
|
||||
**Functies:**
|
||||
- Toont huidige pagina informatie
|
||||
- Dynamische navigatie
|
||||
- Bestandsinformatie
|
||||
- Interactive controls
|
||||
Elke instelling in `settings` ondersteunt:
|
||||
|
||||
## Plugin Development
|
||||
| Veld | Beschrijving |
|
||||
|------|--------------|
|
||||
| `key` | Instelling-sleutel (opgeslagen in `config.json`) |
|
||||
| `type` | `text`, `checkbox`, `number`, `select`, `multi-select` |
|
||||
| `default` | Standaardwaarde |
|
||||
| `label` | Hardcoded label (fallback als geen `label_key`) |
|
||||
| `help` | Hardcoded help-tekst (fallback als geen `help_key`) |
|
||||
| `label_key` | Sleutel in plugin `language/<lang>/admin.php` voor vertaald label |
|
||||
| `help_key` | Sleutel in plugin `language/<lang>/admin.php` voor vertaalde help-tekst |
|
||||
| `option_label_key` | Sleutel naar een array met optie-labels voor `select`/`multi-select` |
|
||||
| `options` | Opties voor `select`/`multi-select` (`{waarde: label}`) |
|
||||
|
||||
### Basis Plugin Class
|
||||
## Taal support
|
||||
|
||||
```php
|
||||
<?php
|
||||
- **Systeem plugins** volgen de geselecteerde **admin taal** (uit `config.admin_language`).
|
||||
- **Content plugins** volgen de geselecteerde **content taal** (uit de URL of `config.language.default`).
|
||||
|
||||
class MyPlugin
|
||||
{
|
||||
private ?CMSAPI $api = null;
|
||||
|
||||
public function setAPI(CMSAPI $api): void
|
||||
{
|
||||
$this->api = $api;
|
||||
}
|
||||
|
||||
public function getSidebarContent(): string
|
||||
{
|
||||
return '<div>Mijn plugin content</div>';
|
||||
}
|
||||
}
|
||||
```
|
||||
Fallback chain voor plugin-vertalingen:
|
||||
1. Geselecteerde taal (`language/<lang>/admin.php` of `site.php`)
|
||||
2. Plugin `default_language` (`plugin.json`)
|
||||
3. CMS `language.default`
|
||||
4. Lege array (sleutel wordt ongewijzigd getoond)
|
||||
|
||||
### Beschikbare API Methodes
|
||||
Plugins halen hun vertalingen op via de API:
|
||||
- Systeem plugins: `$this->api->getPluginTranslations('PluginName')` (AdminPluginAPI)
|
||||
- Content plugins: `$this->api->getPluginTranslations('PluginName')` (CMSAPI)
|
||||
|
||||
- `getCurrentPage()` - Huidige pagina data
|
||||
- `getCurrentPageTitle()` - Huidige pagina titel
|
||||
- `getMenu()` - Menu structuur
|
||||
- `getConfig($key)` - Configuratie waardes
|
||||
- `translate($key)` - Vertalingen
|
||||
- `getCurrentLanguage()` - Huidige taal
|
||||
- `isHomepage()` - Check of homepage
|
||||
- `getCurrentPageFileInfo()` - Bestandsinformatie
|
||||
- `createUrl($page, $lang)` - URL generatie
|
||||
## Uitgebreide documentatie
|
||||
|
||||
### Plugin Hooks
|
||||
Zie de handleiding voor uitgebreide plugin development documentatie:
|
||||
|
||||
Plugins kunnen de volgende methodes implementeren:
|
||||
|
||||
- `getSidebarContent()` - Content voor sidebar
|
||||
- `setAPI(CMSAPI $api)` - API injectie
|
||||
|
||||
## Configuratie
|
||||
|
||||
Plugins kunnen een `config.json` bestand hebben:
|
||||
|
||||
```json
|
||||
{
|
||||
"enabled": true,
|
||||
"settings": {
|
||||
"option1": "value1",
|
||||
"option2": "value2"
|
||||
}
|
||||
}
|
||||
```
|
||||
- `guide/nl/codepress-developer/plugin-development.md`
|
||||
- `guide/en/codepress-developer/plugin-development.md`
|
||||
|
||||
## Installatie
|
||||
|
||||
1. Maak een nieuwe map in `plugins/`
|
||||
2. Plaats de plugin class in `PluginName/PluginName.php`
|
||||
3. Optioneel: voeg README.md en config.json toe
|
||||
4. De plugin wordt automatisch geladen door de CMS
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Gebruik `htmlspecialchars()` voor output
|
||||
- Implementeer `setAPI()` voor CMS toegang
|
||||
- Volg PSR-12 coding standards
|
||||
- Gebruik namespace indien nodig
|
||||
- Documenteer je plugin met README.md
|
||||
1. Maak een nieuwe map in `plugins/` (mapnaam = plugin class naam)
|
||||
2. Voeg de hoofd plugin class toe als `<Naam>.php`
|
||||
3. Maak een `plugin.json` met metadata en (optioneel) instellingen-schema
|
||||
4. Voeg een `README.md` toe met plugin documentatie
|
||||
5. Voeg `language/<lang>/admin.php` of `site.php` toe voor vertalingen
|
||||
6. Schakel de plugin in via `enabled_plugins` in `config.json` (of via de admin Plugins-pagina)
|
||||
@@ -0,0 +1,51 @@
|
||||
# Statistics Plugin
|
||||
|
||||
Toont bezoekersstatistieken: totaal aantal views, unieke bezoekers, landen en top pagina's op een admin-pagina.
|
||||
|
||||
## Plugin type
|
||||
|
||||
**Systeem** plugin. De plugin-output volgt de geselecteerde **admin taal** (via `AdminPluginAPI::getPluginTranslations()` met `admin.php`).
|
||||
|
||||
## Bestandsstructuur
|
||||
|
||||
```
|
||||
Statistics/
|
||||
├── Statistics.php # Hoofd plugin class
|
||||
├── plugin.json # Plugin metadata + instellingen
|
||||
├── README.md # Dit bestand
|
||||
├── assets/ # Optionele CSS/JS (leeg)
|
||||
└── language/ # Vertalingen
|
||||
├── nl/admin.php # Nederlandse admin labels
|
||||
└── en/admin.php # Engelse admin labels
|
||||
```
|
||||
|
||||
## Functies
|
||||
|
||||
- **Totaal aantal views**: Totaal aantal paginaweergaven
|
||||
- **Unieke bezoekers**: Aantal unieke bezoekers
|
||||
- **Pagina views**: Totaal aantal pagina views
|
||||
- **Landen**: Overzicht van bezoekers per land (met vlag-emoji)
|
||||
- **Top pagina's**: Meest bezochte pagina's
|
||||
|
||||
Statistieken worden alleen getoond als Analytics is ingeschakeld in de site configuratie; anders wordt een waarschuwing getoond.
|
||||
|
||||
## Instellingen
|
||||
|
||||
Deze plugin heeft instelbare configuratie (`hasConfig: true`). Instellingen worden gedefinieerd in `plugin.json` onder `settings` en overschreven via `config.json`.
|
||||
|
||||
| Sleutel | Type | Standaard | Beschrijving |
|
||||
|---------|------|-----------|--------------|
|
||||
| `required_roles` | multi-select | `bi-manager, site-admin, admin` | Rollen die deze plugin mogen zien |
|
||||
| `show_countries` | checkbox | `true` | Schakel het landen-overzicht in of uit |
|
||||
| `show_top_pages` | checkbox | `true` | Schakel het top pagina's overzicht in of uit |
|
||||
|
||||
De label- en help-teksten voor instellingen worden vertaald via `label_key`/`help_key` (verwijst naar sleutels in `language/<lang>/admin.php`).
|
||||
|
||||
## Taal support
|
||||
|
||||
De plugin gebruikt `AdminPluginAPI::getPluginTranslations('Statistics')` om labels op te halen. Fallback chain:
|
||||
1. Geselecteerde admin taal
|
||||
2. Plugin `default_language` (`nl`)
|
||||
3. Lege array (sleutel wordt ongewijzigd getoond)
|
||||
|
||||
Beschikbare sleutels staan in `language/<lang>/admin.php`. Het admin-menu label wordt vertaald via `label_key: 'menu_label'` in `getAdminMenu()`.
|
||||
@@ -20,24 +20,67 @@ class Statistics
|
||||
|
||||
public function getAdminMenu(): array
|
||||
{
|
||||
$config = $this->getPluginConfig();
|
||||
$requiredRoles = $config['required_roles'] ?? ['bi-manager', 'site-admin', 'admin'];
|
||||
|
||||
return [
|
||||
[
|
||||
'plugin' => 'Statistics',
|
||||
'route' => 'statistics',
|
||||
'label' => 'Statistieken',
|
||||
'label_key' => 'menu_label',
|
||||
'icon' => 'bi-bar-chart',
|
||||
'section' => 'general',
|
||||
'permission' => 'statistics',
|
||||
'required_roles' => $requiredRoles,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this plugin's runtime config (defaults + overrides).
|
||||
*/
|
||||
private function getPluginConfig(): array
|
||||
{
|
||||
$pluginDir = dirname(__DIR__);
|
||||
$pluginJsonFile = $pluginDir . '/plugin.json';
|
||||
$configJsonFile = $pluginDir . '/config.json';
|
||||
|
||||
$defaults = [];
|
||||
if (file_exists($pluginJsonFile)) {
|
||||
$pluginJson = json_decode(file_get_contents($pluginJsonFile), true) ?? [];
|
||||
foreach ($pluginJson['settings'] ?? [] as $setting) {
|
||||
if (isset($setting['key'])) {
|
||||
$defaults[$setting['key']] = $setting['default'] ?? null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$overrides = [];
|
||||
if (file_exists($configJsonFile)) {
|
||||
$overrides = json_decode(file_get_contents($configJsonFile), true) ?? [];
|
||||
}
|
||||
|
||||
return array_merge($defaults, $overrides);
|
||||
}
|
||||
|
||||
public function handleAdminRoute(string $action): ?string
|
||||
{
|
||||
// System plugin: translations resolve against the admin language.
|
||||
$t = $this->api ? $this->api->getPluginTranslations('Statistics') : [];
|
||||
$tr = function (string $key) use ($t): string {
|
||||
return $t[$key] ?? $key;
|
||||
};
|
||||
|
||||
$analytics = $this->getAnalytics();
|
||||
if ($analytics === null) {
|
||||
return '<div class="alert alert-warning">Analytics is uitgeschakeld.</div>';
|
||||
return '<div class="alert alert-warning">' . htmlspecialchars($tr('analytics_disabled')) . '</div>';
|
||||
}
|
||||
|
||||
$config = $this->getPluginConfig();
|
||||
$showCountries = $config['show_countries'] ?? true;
|
||||
$showTopPages = $config['show_top_pages'] ?? true;
|
||||
|
||||
$stats = $analytics->getStats();
|
||||
$totals = $stats['totals'] ?? ['views' => 0, 'uniques' => 0, 'pages' => []];
|
||||
$countries = $stats['countries'] ?? [];
|
||||
@@ -45,14 +88,14 @@ class Statistics
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<h2 class="mb-4"><i class="bi bi-bar-chart"></i> Statistieken</h2>
|
||||
<h2 class="mb-4"><i class="bi bi-bar-chart"></i> <?= htmlspecialchars($tr('page_title')) ?></h2>
|
||||
|
||||
<div class="row g-4 mb-4">
|
||||
<div class="col-md-4">
|
||||
<div class="card stat-card shadow-sm">
|
||||
<div class="card-body d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="text-muted mb-1">Totaal aantal views</h6>
|
||||
<h6 class="text-muted mb-1"><?= htmlspecialchars($tr('total_views')) ?></h6>
|
||||
<h3 class="mb-0"><?= number_format($totals['views'] ?? 0, 0, ',', '.') ?></h3>
|
||||
</div>
|
||||
<i class="bi bi-eye stat-icon text-primary"></i>
|
||||
@@ -63,7 +106,7 @@ class Statistics
|
||||
<div class="card stat-card shadow-sm">
|
||||
<div class="card-body d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="text-muted mb-1">Unieke bezoekers</h6>
|
||||
<h6 class="text-muted mb-1"><?= htmlspecialchars($tr('unique_visitors')) ?></h6>
|
||||
<h3 class="mb-0"><?= number_format($totals['uniques'] ?? 0, 0, ',', '.') ?></h3>
|
||||
</div>
|
||||
<i class="bi bi-people stat-icon text-success"></i>
|
||||
@@ -74,7 +117,7 @@ class Statistics
|
||||
<div class="card stat-card shadow-sm">
|
||||
<div class="card-body d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="text-muted mb-1">Pagina views</h6>
|
||||
<h6 class="text-muted mb-1"><?= htmlspecialchars($tr('page_views')) ?></h6>
|
||||
<h3 class="mb-0"><?= number_format($totals['page_views'] ?? ($totals['views'] ?? 0), 0, ',', '.') ?></h3>
|
||||
</div>
|
||||
<i class="bi bi-file-earmark-text stat-icon text-info"></i>
|
||||
@@ -83,16 +126,18 @@ class Statistics
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($showCountries || $showTopPages): ?>
|
||||
<div class="row g-4">
|
||||
<?php if ($showCountries): ?>
|
||||
<div class="col-md-6">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header"><i class="bi bi-globe"></i> Landen</div>
|
||||
<div class="card-header"><i class="bi bi-globe"></i> <?= htmlspecialchars($tr('countries')) ?></div>
|
||||
<div class="card-body">
|
||||
<?php if (empty($countries)): ?>
|
||||
<p class="text-muted mb-0">Geen data</p>
|
||||
<p class="text-muted mb-0"><?= htmlspecialchars($tr('no_data')) ?></p>
|
||||
<?php else: ?>
|
||||
<table class="table table-sm mb-0">
|
||||
<thead><tr><th>Land</th><th>Views</th></tr></thead>
|
||||
<thead><tr><th><?= htmlspecialchars($tr('col_country')) ?></th><th><?= htmlspecialchars($tr('col_views')) ?></th></tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ($countries as $country => $count): ?>
|
||||
<tr>
|
||||
@@ -106,15 +151,17 @@ class Statistics
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ($showTopPages): ?>
|
||||
<div class="col-md-6">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header"><i class="bi bi-file-earmark-bar"></i> Top pagina's</div>
|
||||
<div class="card-header"><i class="bi bi-file-earmark-bar"></i> <?= htmlspecialchars($tr('top_pages')) ?></div>
|
||||
<div class="card-body">
|
||||
<?php if (empty($topPages)): ?>
|
||||
<p class="text-muted mb-0">Geen data</p>
|
||||
<p class="text-muted mb-0"><?= htmlspecialchars($tr('no_data')) ?></p>
|
||||
<?php else: ?>
|
||||
<table class="table table-sm mb-0">
|
||||
<thead><tr><th>Pagina</th><th>Views</th></tr></thead>
|
||||
<thead><tr><th><?= htmlspecialchars($tr('col_page')) ?></th><th><?= htmlspecialchars($tr('col_views')) ?></th></tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ($topPages as $page => $count): ?>
|
||||
<tr>
|
||||
@@ -128,7 +175,9 @@ class Statistics
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
return [
|
||||
// Menu
|
||||
'menu_label' => 'Statistics',
|
||||
|
||||
// Page
|
||||
'page_title' => 'Statistics',
|
||||
'total_views' => 'Total views',
|
||||
'unique_visitors' => 'Unique visitors',
|
||||
'page_views' => 'Page views',
|
||||
'countries' => 'Countries',
|
||||
'top_pages' => 'Top pages',
|
||||
'no_data' => 'No data',
|
||||
'col_country' => 'Country',
|
||||
'col_views' => 'Views',
|
||||
'col_page' => 'Page',
|
||||
'analytics_disabled' => 'Analytics is disabled.',
|
||||
|
||||
// Settings (plugin.json label_key/help_key)
|
||||
'setting_required_roles' => 'Roles allowed to view this plugin',
|
||||
'setting_required_roles_help' => 'Determines which roles can access the statistics page in the admin panel. Admin always has access.',
|
||||
'role_options' => [
|
||||
'admin' => 'Admin',
|
||||
'content-manager' => 'Content Manager',
|
||||
'bi-manager' => 'BI Manager',
|
||||
'site-admin' => 'Site Admin',
|
||||
],
|
||||
'setting_show_countries' => 'Show countries overview',
|
||||
'setting_show_countries_help' => 'Enable or disable the countries overview on the statistics page.',
|
||||
'setting_show_top_pages' => 'Show top pages',
|
||||
'setting_show_top_pages_help' => 'Enable or disable the top pages overview.',
|
||||
];
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
return [
|
||||
// Menu
|
||||
'menu_label' => 'Statistieken',
|
||||
|
||||
// Page
|
||||
'page_title' => 'Statistieken',
|
||||
'total_views' => 'Totaal aantal views',
|
||||
'unique_visitors' => 'Unieke bezoekers',
|
||||
'page_views' => 'Pagina views',
|
||||
'countries' => 'Landen',
|
||||
'top_pages' => "Top pagina's",
|
||||
'no_data' => 'Geen data',
|
||||
'col_country' => 'Land',
|
||||
'col_views' => 'Views',
|
||||
'col_page' => 'Pagina',
|
||||
'analytics_disabled' => 'Analytics is uitgeschakeld.',
|
||||
|
||||
// Settings (plugin.json label_key/help_key)
|
||||
'setting_required_roles' => 'Rollen die deze plugin mogen zien',
|
||||
'setting_required_roles_help' => 'Bepaalt welke rollen toegang hebben tot de statistieken-pagina in het admin-paneel. Admin heeft altijd toegang.',
|
||||
'role_options' => [
|
||||
'admin' => 'Admin',
|
||||
'content-manager' => 'Content Beheerder',
|
||||
'bi-manager' => 'BI Beheerder',
|
||||
'site-admin' => 'Site Admin',
|
||||
],
|
||||
'setting_show_countries' => 'Toon landen-overzicht',
|
||||
'setting_show_countries_help' => 'Schakel het landen-overzicht in of uit op de statistieken-pagina.',
|
||||
'setting_show_top_pages' => "Toon top pagina's",
|
||||
'setting_show_top_pages_help' => "Schakel het top pagina's overzicht in of uit.",
|
||||
];
|
||||
@@ -5,5 +5,36 @@
|
||||
"description": "Bezoekersstatistieken: totaal aantal views, unieke bezoekers, landen en top pagina's.",
|
||||
"type": "system",
|
||||
"essential": false,
|
||||
"hasConfig": true
|
||||
"hasConfig": true,
|
||||
"default_language": "nl",
|
||||
"settings": [
|
||||
{
|
||||
"key": "required_roles",
|
||||
"label_key": "setting_required_roles",
|
||||
"help_key": "setting_required_roles_help",
|
||||
"option_label_key": "role_options",
|
||||
"type": "multi-select",
|
||||
"default": ["bi-manager", "site-admin", "admin"],
|
||||
"options": {
|
||||
"admin": "Admin",
|
||||
"content-manager": "Content Beheerder",
|
||||
"bi-manager": "BI Beheerder",
|
||||
"site-admin": "Site Admin"
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": "show_countries",
|
||||
"label_key": "setting_show_countries",
|
||||
"help_key": "setting_show_countries_help",
|
||||
"type": "checkbox",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"key": "show_top_pages",
|
||||
"label_key": "setting_show_top_pages",
|
||||
"help_key": "setting_show_top_pages_help",
|
||||
"type": "checkbox",
|
||||
"default": true
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user