Imports classes in core code with "use" instead of full references.
parent
cfed37ef8f
commit
896249f833
|
|
@ -5,6 +5,8 @@
|
||||||
* Used when code does require_once '../app/classes/log.php'.
|
* Used when code does require_once '../app/classes/log.php'.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use App\Core\NullLogger;
|
||||||
|
|
||||||
// If there is already a Log plugin loaded
|
// If there is already a Log plugin loaded
|
||||||
if (class_exists('Log')) {
|
if (class_exists('Log')) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -24,7 +26,7 @@ class Log {
|
||||||
if (isset($logObject) && method_exists($logObject, 'insertLog')) {
|
if (isset($logObject) && method_exists($logObject, 'insertLog')) {
|
||||||
$this->logger = $logObject;
|
$this->logger = $logObject;
|
||||||
} else {
|
} else {
|
||||||
$this->logger = new \App\Core\NullLogger();
|
$this->logger = new NullLogger();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
namespace App\Core;
|
namespace App\Core;
|
||||||
|
|
||||||
|
use App\App;
|
||||||
|
|
||||||
class PluginManager
|
class PluginManager
|
||||||
{
|
{
|
||||||
/** @var array<string, array{path: string, meta: array}> */
|
/** @var array<string, array{path: string, meta: array}> */
|
||||||
|
|
@ -168,7 +170,7 @@ class PluginManager
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use App API to get database connection
|
// Use App API to get database connection
|
||||||
$db = \App\App::db();
|
$db = App::db();
|
||||||
$pdo = ($db instanceof \PDO) ? $db : $db->getConnection();
|
$pdo = ($db instanceof \PDO) ? $db : $db->getConnection();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -214,7 +216,7 @@ class PluginManager
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use App API to get database connection
|
// Use App API to get database connection
|
||||||
$db = \App\App::db();
|
$db = App::db();
|
||||||
|
|
||||||
// If database unavailable, fallback to manifest
|
// If database unavailable, fallback to manifest
|
||||||
if (!$db) {
|
if (!$db) {
|
||||||
|
|
@ -283,7 +285,7 @@ class PluginManager
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$db = \App\App::db();
|
$db = App::db();
|
||||||
if (!$db) {
|
if (!$db) {
|
||||||
app_log('error', 'PluginManager::purge: Database connection not available', ['scope' => 'plugin']);
|
app_log('error', 'PluginManager::purge: Database connection not available', ['scope' => 'plugin']);
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Core\NullLogger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a logger instance: plugin Log if available, otherwise NullLogger.
|
* Returns a logger instance: plugin Log if available, otherwise NullLogger.
|
||||||
*
|
*
|
||||||
|
|
@ -11,7 +13,7 @@ function getLoggerInstance($database) {
|
||||||
return new Log($database);
|
return new Log($database);
|
||||||
}
|
}
|
||||||
require_once __DIR__ . '/../core/NullLogger.php';
|
require_once __DIR__ . '/../core/NullLogger.php';
|
||||||
return new \App\Core\NullLogger();
|
return new NullLogger();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!function_exists('app_log')) {
|
if (!function_exists('app_log')) {
|
||||||
|
|
@ -29,7 +31,7 @@ if (!function_exists('app_log')) {
|
||||||
static $fallbackLogger = null;
|
static $fallbackLogger = null;
|
||||||
if ($fallbackLogger === null) {
|
if ($fallbackLogger === null) {
|
||||||
require_once __DIR__ . '/../core/NullLogger.php';
|
require_once __DIR__ . '/../core/NullLogger.php';
|
||||||
$fallbackLogger = new \App\Core\NullLogger();
|
$fallbackLogger = new NullLogger();
|
||||||
}
|
}
|
||||||
|
|
||||||
$fallbackLogger->log($level, $message, $context);
|
$fallbackLogger->log($level, $message, $context);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\App;
|
||||||
|
use App\Core\HookDispatcher;
|
||||||
|
use App\Core\Maintenance;
|
||||||
|
use App\Core\MigrationRunner;
|
||||||
|
use App\Core\PluginManager;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Admin control center
|
* Admin control center
|
||||||
*
|
*
|
||||||
|
|
@ -111,7 +117,7 @@ foreach ($sectionRegistry as $key => $meta) {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
$sectionStatePayload = \App\Core\HookDispatcher::applyFilters('admin.sections.state', [
|
$sectionStatePayload = HookDispatcher::applyFilters('admin.sections.state', [
|
||||||
'sections' => $sectionRegistry,
|
'sections' => $sectionRegistry,
|
||||||
'state' => [],
|
'state' => [],
|
||||||
'db' => $db ?? null,
|
'db' => $db ?? null,
|
||||||
|
|
@ -125,9 +131,9 @@ if (is_array($sectionStatePayload)) {
|
||||||
|
|
||||||
// Get plugin catalog and list of loaded plugins
|
// Get plugin catalog and list of loaded plugins
|
||||||
// with their dependencies
|
// with their dependencies
|
||||||
$pluginCatalog = \App\Core\PluginManager::getCatalog();
|
$pluginCatalog = PluginManager::getCatalog();
|
||||||
$pluginLoadedMap = \App\Core\PluginManager::getLoaded();
|
$pluginLoadedMap = PluginManager::getLoaded();
|
||||||
$pluginDependencyErrors = \App\Core\PluginManager::getDependencyErrors();
|
$pluginDependencyErrors = PluginManager::getDependencyErrors();
|
||||||
|
|
||||||
$normalizeDependencies = static function ($meta): array {
|
$normalizeDependencies = static function ($meta): array {
|
||||||
$deps = $meta['dependencies'] ?? [];
|
$deps = $meta['dependencies'] ?? [];
|
||||||
|
|
@ -154,14 +160,14 @@ $pluginAdminMap = [];
|
||||||
foreach ($pluginCatalog as $slug => $info) {
|
foreach ($pluginCatalog as $slug => $info) {
|
||||||
$meta = $info['meta'] ?? [];
|
$meta = $info['meta'] ?? [];
|
||||||
$name = trim((string)($meta['name'] ?? $slug));
|
$name = trim((string)($meta['name'] ?? $slug));
|
||||||
$enabled = \App\Core\PluginManager::isEnabled($slug); // Use database setting
|
$enabled = PluginManager::isEnabled($slug); // Use database setting
|
||||||
$dependencies = $normalizeDependencies($meta);
|
$dependencies = $normalizeDependencies($meta);
|
||||||
$dependents = array_values($pluginDependentsIndex[$slug] ?? []);
|
$dependents = array_values($pluginDependentsIndex[$slug] ?? []);
|
||||||
$enabledDependents = array_values(array_filter($dependents, static function($depSlug) {
|
$enabledDependents = array_values(array_filter($dependents, static function($depSlug) {
|
||||||
return \App\Core\PluginManager::isEnabled($depSlug); // Use database setting
|
return PluginManager::isEnabled($depSlug); // Use database setting
|
||||||
}));
|
}));
|
||||||
$missingDependencies = array_values(array_filter($dependencies, static function($depSlug) use ($pluginCatalog) {
|
$missingDependencies = array_values(array_filter($dependencies, static function($depSlug) use ($pluginCatalog) {
|
||||||
return !isset($pluginCatalog[$depSlug]) || !\App\Core\PluginManager::isEnabled($depSlug); // Use database setting
|
return !isset($pluginCatalog[$depSlug]) || !PluginManager::isEnabled($depSlug); // Use database setting
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Check for migration files and existing tables
|
// Check for migration files and existing tables
|
||||||
|
|
@ -170,7 +176,7 @@ foreach ($pluginCatalog as $slug => $info) {
|
||||||
$existingTables = [];
|
$existingTables = [];
|
||||||
|
|
||||||
if ($hasMigration) {
|
if ($hasMigration) {
|
||||||
$db = \App\App::db();
|
$db = App::db();
|
||||||
if ($db instanceof PDO) {
|
if ($db instanceof PDO) {
|
||||||
$stmt = $db->query("SHOW TABLES");
|
$stmt = $db->query("SHOW TABLES");
|
||||||
$allTables = $stmt->fetchAll(PDO::FETCH_COLUMN, 0);
|
$allTables = $stmt->fetchAll(PDO::FETCH_COLUMN, 0);
|
||||||
|
|
@ -260,7 +266,7 @@ if ($postAction === 'read_migration') {
|
||||||
|
|
||||||
// Hooks actions for plugins
|
// Hooks actions for plugins
|
||||||
if ($action !== '' && $action !== 'read_migration') {
|
if ($action !== '' && $action !== 'read_migration') {
|
||||||
$customActionPayload = \App\Core\HookDispatcher::applyFilters('admin.actions.handle', [
|
$customActionPayload = HookDispatcher::applyFilters('admin.actions.handle', [
|
||||||
'handled' => false,
|
'handled' => false,
|
||||||
'action' => $action,
|
'action' => $action,
|
||||||
'request_method' => $_SERVER['REQUEST_METHOD'] ?? 'GET',
|
'request_method' => $_SERVER['REQUEST_METHOD'] ?? 'GET',
|
||||||
|
|
@ -295,18 +301,18 @@ if ($postAction !== '' && $postAction !== 'read_migration') {
|
||||||
// Maintenance actions
|
// Maintenance actions
|
||||||
if ($postAction === 'maintenance_on') {
|
if ($postAction === 'maintenance_on') {
|
||||||
$msg = trim($_POST['maintenance_message'] ?? '');
|
$msg = trim($_POST['maintenance_message'] ?? '');
|
||||||
\App\Core\Maintenance::enable($msg);
|
Maintenance::enable($msg);
|
||||||
Feedback::flash('NOTICE', 'DEFAULT', 'Maintenance mode enabled.', true);
|
Feedback::flash('NOTICE', 'DEFAULT', 'Maintenance mode enabled.', true);
|
||||||
} elseif ($postAction === 'maintenance_off') {
|
} elseif ($postAction === 'maintenance_off') {
|
||||||
\App\Core\Maintenance::disable();
|
Maintenance::disable();
|
||||||
Feedback::flash('NOTICE', 'DEFAULT', 'Maintenance mode disabled.', true);
|
Feedback::flash('NOTICE', 'DEFAULT', 'Maintenance mode disabled.', true);
|
||||||
// DB migrations actions
|
// DB migrations actions
|
||||||
} elseif ($postAction === 'migrate_up') {
|
} elseif ($postAction === 'migrate_up') {
|
||||||
$runner = new \App\Core\MigrationRunner($db, $migrationsDir);
|
$runner = new MigrationRunner($db, $migrationsDir);
|
||||||
$applied = $runner->applyPendingMigrations();
|
$applied = $runner->applyPendingMigrations();
|
||||||
Feedback::flash('NOTICE', 'DEFAULT', empty($applied) ? 'No pending migrations.' : 'Applied migrations: ' . implode(', ', $applied), true);
|
Feedback::flash('NOTICE', 'DEFAULT', empty($applied) ? 'No pending migrations.' : 'Applied migrations: ' . implode(', ', $applied), true);
|
||||||
} elseif ($postAction === 'migrate_apply_one') {
|
} elseif ($postAction === 'migrate_apply_one') {
|
||||||
$runner = new \App\Core\MigrationRunner($db, $migrationsDir);
|
$runner = new MigrationRunner($db, $migrationsDir);
|
||||||
$migrationName = trim($_POST['migration_name'] ?? '');
|
$migrationName = trim($_POST['migration_name'] ?? '');
|
||||||
$applied = $migrationName !== '' ? $runner->applyMigrationByName($migrationName) : [];
|
$applied = $migrationName !== '' ? $runner->applyMigrationByName($migrationName) : [];
|
||||||
if (empty($applied)) {
|
if (empty($applied)) {
|
||||||
|
|
@ -342,11 +348,11 @@ if ($postAction !== '' && $postAction !== 'read_migration') {
|
||||||
$reason = 'Enable required plugins first: ' . implode(', ', $pluginMeta['missing_dependencies']);
|
$reason = 'Enable required plugins first: ' . implode(', ', $pluginMeta['missing_dependencies']);
|
||||||
}
|
}
|
||||||
Feedback::flash('ERROR', 'DEFAULT', $reason, false);
|
Feedback::flash('ERROR', 'DEFAULT', $reason, false);
|
||||||
} elseif (!\App\Core\PluginManager::setEnabled($slug, true)) {
|
} elseif (!PluginManager::setEnabled($slug, true)) {
|
||||||
Feedback::flash('ERROR', 'DEFAULT', 'Failed to enable plugin. Check database connection and error logs.', false);
|
Feedback::flash('ERROR', 'DEFAULT', 'Failed to enable plugin. Check database connection and error logs.', false);
|
||||||
} else {
|
} else {
|
||||||
// Automatically install plugin tables when enabling
|
// Automatically install plugin tables when enabling
|
||||||
$installResult = \App\Core\PluginManager::install($slug);
|
$installResult = PluginManager::install($slug);
|
||||||
if ($installResult) {
|
if ($installResult) {
|
||||||
Feedback::flash('NOTICE', 'DEFAULT', sprintf('Plugin "%s" enabled and installed successfully.', $pluginMeta['name']), true);
|
Feedback::flash('NOTICE', 'DEFAULT', sprintf('Plugin "%s" enabled and installed successfully.', $pluginMeta['name']), true);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -357,7 +363,7 @@ if ($postAction !== '' && $postAction !== 'read_migration') {
|
||||||
if (!$pluginMeta['can_disable']) {
|
if (!$pluginMeta['can_disable']) {
|
||||||
$reason = 'Disable dependent plugins first: ' . implode(', ', $pluginMeta['enabled_dependents']);
|
$reason = 'Disable dependent plugins first: ' . implode(', ', $pluginMeta['enabled_dependents']);
|
||||||
Feedback::flash('ERROR', 'DEFAULT', $reason, false);
|
Feedback::flash('ERROR', 'DEFAULT', $reason, false);
|
||||||
} elseif (!\App\Core\PluginManager::setEnabled($slug, false)) {
|
} elseif (!PluginManager::setEnabled($slug, false)) {
|
||||||
Feedback::flash('ERROR', 'DEFAULT', 'Failed to disable plugin. Check database connection and error logs.', false);
|
Feedback::flash('ERROR', 'DEFAULT', 'Failed to disable plugin. Check database connection and error logs.', false);
|
||||||
} else {
|
} else {
|
||||||
Feedback::flash('NOTICE', 'DEFAULT', sprintf('Plugin "%s" disabled.', $pluginMeta['name']), true);
|
Feedback::flash('NOTICE', 'DEFAULT', sprintf('Plugin "%s" disabled.', $pluginMeta['name']), true);
|
||||||
|
|
@ -370,7 +376,7 @@ if ($postAction !== '' && $postAction !== 'read_migration') {
|
||||||
if ($slug === '' || !isset($pluginAdminMap[$slug])) {
|
if ($slug === '' || !isset($pluginAdminMap[$slug])) {
|
||||||
Feedback::flash('ERROR', 'DEFAULT', 'Unknown plugin specified.', false);
|
Feedback::flash('ERROR', 'DEFAULT', 'Unknown plugin specified.', false);
|
||||||
} else {
|
} else {
|
||||||
if (\App\Core\PluginManager::install($slug)) {
|
if (PluginManager::install($slug)) {
|
||||||
Feedback::flash('NOTICE', 'DEFAULT', sprintf('Plugin "%s" installed successfully.', $pluginAdminMap[$slug]['name']), true);
|
Feedback::flash('NOTICE', 'DEFAULT', sprintf('Plugin "%s" installed successfully.', $pluginAdminMap[$slug]['name']), true);
|
||||||
} else {
|
} else {
|
||||||
Feedback::flash('ERROR', 'DEFAULT', 'Plugin installation failed. Check migration files.', false);
|
Feedback::flash('ERROR', 'DEFAULT', 'Plugin installation failed. Check migration files.', false);
|
||||||
|
|
@ -382,7 +388,7 @@ if ($postAction !== '' && $postAction !== 'read_migration') {
|
||||||
if ($slug === '' || !isset($pluginAdminMap[$slug])) {
|
if ($slug === '' || !isset($pluginAdminMap[$slug])) {
|
||||||
Feedback::flash('ERROR', 'DEFAULT', 'Unknown plugin specified.', false);
|
Feedback::flash('ERROR', 'DEFAULT', 'Unknown plugin specified.', false);
|
||||||
} else {
|
} else {
|
||||||
if (\App\Core\PluginManager::purge($slug)) {
|
if (PluginManager::purge($slug)) {
|
||||||
Feedback::flash('NOTICE', 'DEFAULT', sprintf('Plugin "%s" purged successfully. All data and tables removed.', $pluginAdminMap[$slug]['name']), true);
|
Feedback::flash('NOTICE', 'DEFAULT', sprintf('Plugin "%s" purged successfully. All data and tables removed.', $pluginAdminMap[$slug]['name']), true);
|
||||||
} else {
|
} else {
|
||||||
Feedback::flash('ERROR', 'DEFAULT', 'Plugin purge failed. Check database permissions.', false);
|
Feedback::flash('ERROR', 'DEFAULT', 'Plugin purge failed. Check database permissions.', false);
|
||||||
|
|
@ -471,8 +477,8 @@ if ($postAction !== '' && $postAction !== 'read_migration') {
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$maintenance_enabled = \App\Core\Maintenance::isEnabled();
|
$maintenance_enabled = Maintenance::isEnabled();
|
||||||
$maintenance_message = \App\Core\Maintenance::getMessage();
|
$maintenance_message = Maintenance::getMessage();
|
||||||
|
|
||||||
$pending = [];
|
$pending = [];
|
||||||
$applied = [];
|
$applied = [];
|
||||||
|
|
@ -492,7 +498,7 @@ if (isset($_SESSION['migration_modal_open'])) {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$runner = new \App\Core\MigrationRunner($db, $migrationsDir);
|
$runner = new MigrationRunner($db, $migrationsDir);
|
||||||
$pending = $runner->listPendingMigrations();
|
$pending = $runner->listPendingMigrations();
|
||||||
$applied = $runner->listAppliedMigrations();
|
$applied = $runner->listAppliedMigrations();
|
||||||
|
|
||||||
|
|
@ -602,7 +608,7 @@ if ($queryAction === 'plugin_check_page' && isset($_GET['plugin'])) {
|
||||||
];
|
];
|
||||||
|
|
||||||
// Check database tables
|
// Check database tables
|
||||||
$db = \App\App::db();
|
$db = App::db();
|
||||||
$pluginOwnedTables = [];
|
$pluginOwnedTables = [];
|
||||||
$pluginReferencedTables = [];
|
$pluginReferencedTables = [];
|
||||||
if ($db && method_exists($db, 'getConnection')) {
|
if ($db && method_exists($db, 'getConnection')) {
|
||||||
|
|
@ -685,7 +691,7 @@ if ($queryAction === 'plugin_check_page' && isset($_GET['plugin'])) {
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$overviewPillsPayload = \App\Core\HookDispatcher::applyFilters('admin.overview.pills', [
|
$overviewPillsPayload = HookDispatcher::applyFilters('admin.overview.pills', [
|
||||||
'pills' => [],
|
'pills' => [],
|
||||||
'sections' => $sectionRegistry,
|
'sections' => $sectionRegistry,
|
||||||
'section_state' => $sectionState,
|
'section_state' => $sectionState,
|
||||||
|
|
@ -697,7 +703,7 @@ if (is_array($overviewPillsPayload)) {
|
||||||
$adminOverviewPills = $overviewPillsPayload['pills'] ?? (is_array($overviewPillsPayload) ? $overviewPillsPayload : []);
|
$adminOverviewPills = $overviewPillsPayload['pills'] ?? (is_array($overviewPillsPayload) ? $overviewPillsPayload : []);
|
||||||
}
|
}
|
||||||
|
|
||||||
$overviewStatusesPayload = \App\Core\HookDispatcher::applyFilters('admin.overview.statuses', [
|
$overviewStatusesPayload = HookDispatcher::applyFilters('admin.overview.statuses', [
|
||||||
'statuses' => [],
|
'statuses' => [],
|
||||||
'sections' => $sectionRegistry,
|
'sections' => $sectionRegistry,
|
||||||
'section_state' => $sectionState,
|
'section_state' => $sectionState,
|
||||||
|
|
@ -709,7 +715,7 @@ if (is_array($overviewStatusesPayload)) {
|
||||||
$adminOverviewStatuses = $overviewStatusesPayload['statuses'] ?? (is_array($overviewStatusesPayload) ? $overviewStatusesPayload : []);
|
$adminOverviewStatuses = $overviewStatusesPayload['statuses'] ?? (is_array($overviewStatusesPayload) ? $overviewStatusesPayload : []);
|
||||||
}
|
}
|
||||||
|
|
||||||
$adminTabDotsPayload = \App\Core\HookDispatcher::applyFilters('admin.tabs.dot_indicators', [
|
$adminTabDotsPayload = HookDispatcher::applyFilters('admin.tabs.dot_indicators', [
|
||||||
'dots' => [],
|
'dots' => [],
|
||||||
'sections' => $sectionRegistry,
|
'sections' => $sectionRegistry,
|
||||||
'section_state' => $sectionState,
|
'section_state' => $sectionState,
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@
|
||||||
* - `edit`: Edit user profile details, rights, or avatar.
|
* - `edit`: Edit user profile details, rights, or avatar.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use App\Core\HookDispatcher;
|
||||||
|
|
||||||
require_once '../app/helpers/url_canonicalizer.php';
|
require_once '../app/helpers/url_canonicalizer.php';
|
||||||
|
|
||||||
$action = $_REQUEST['action'] ?? '';
|
$action = $_REQUEST['action'] ?? '';
|
||||||
|
|
@ -43,8 +45,8 @@ $profileHooksContext = [
|
||||||
'user' => $userDetails[0] ?? null,
|
'user' => $userDetails[0] ?? null,
|
||||||
];
|
];
|
||||||
|
|
||||||
if (class_exists('\\App\\Core\\HookDispatcher')) {
|
if (class_exists(HookDispatcher::class)) {
|
||||||
$profileHooksContext = \App\Core\HookDispatcher::applyFilters('profile.context', $profileHooksContext);
|
$profileHooksContext = HookDispatcher::applyFilters('profile.context', $profileHooksContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
// plugins can add additional panels to the profile page
|
// plugins can add additional panels to the profile page
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Helpers\Theme;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Theme Management Controller
|
* Theme Management Controller
|
||||||
*
|
*
|
||||||
|
|
@ -57,7 +60,7 @@ if (isset($_GET['switch_to'])) {
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (\App\Helpers\Theme::setCurrentTheme($themeName)) {
|
if (Theme::setCurrentTheme($themeName)) {
|
||||||
// Set success message
|
// Set success message
|
||||||
Feedback::flash('THEME', 'THEME_CHANGED');
|
Feedback::flash('THEME', 'THEME_CHANGED');
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -72,13 +75,13 @@ if (isset($_GET['switch_to'])) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get available themes and current theme for the view
|
// Get available themes and current theme for the view
|
||||||
$themes = \App\Helpers\Theme::getAvailableThemes();
|
$themes = Theme::getAvailableThemes();
|
||||||
$currentTheme = \App\Helpers\Theme::getCurrentThemeName();
|
$currentTheme = Theme::getCurrentThemeName();
|
||||||
|
|
||||||
// Prepare theme data with screenshot URLs and metadata for the view
|
// Prepare theme data with screenshot URLs and metadata for the view
|
||||||
$themeData = [];
|
$themeData = [];
|
||||||
foreach ($themes as $id => $name) {
|
foreach ($themes as $id => $name) {
|
||||||
$meta = \App\Helpers\Theme::getThemeMetadata($id);
|
$meta = Theme::getThemeMetadata($id);
|
||||||
$themeData[$id] = [
|
$themeData[$id] = [
|
||||||
'name' => $meta['name'] ?? $name,
|
'name' => $meta['name'] ?? $name,
|
||||||
'description' => $meta['description'] ?? '',
|
'description' => $meta['description'] ?? '',
|
||||||
|
|
@ -89,7 +92,7 @@ foreach ($themes as $id => $name) {
|
||||||
'path' => $meta['path'] ?? '',
|
'path' => $meta['path'] ?? '',
|
||||||
'last_modified' => $meta['last_modified'] ?? null,
|
'last_modified' => $meta['last_modified'] ?? null,
|
||||||
'file_count' => $meta['file_count'] ?? null,
|
'file_count' => $meta['file_count'] ?? null,
|
||||||
'screenshotUrl' => \App\Helpers\Theme::getAssetUrl($id, 'screenshot.png'),
|
'screenshotUrl' => Theme::getAssetUrl($id, 'screenshot.png'),
|
||||||
'isActive' => $id === $currentTheme
|
'isActive' => $id === $currentTheme
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,9 @@
|
||||||
/** @var array $adminOverviewPills */
|
/** @var array $adminOverviewPills */
|
||||||
/** @var array $adminOverviewStatuses */
|
/** @var array $adminOverviewStatuses */
|
||||||
/** @var array $sectionState */
|
/** @var array $sectionState */
|
||||||
?>
|
|
||||||
|
|
||||||
<?php
|
use App\App;
|
||||||
|
|
||||||
$preselectModalId = null;
|
$preselectModalId = null;
|
||||||
if (!empty($modal_to_open)) {
|
if (!empty($modal_to_open)) {
|
||||||
$preselectModalId = 'migrationModal' . md5($modal_to_open);
|
$preselectModalId = 'migrationModal' . md5($modal_to_open);
|
||||||
|
|
@ -642,7 +642,7 @@ endif; ?>
|
||||||
];
|
];
|
||||||
|
|
||||||
// Check database tables
|
// Check database tables
|
||||||
$db = \App\App::db();
|
$db = App::db();
|
||||||
$pluginOwnedTables = [];
|
$pluginOwnedTables = [];
|
||||||
$pluginReferencedTables = [];
|
$pluginReferencedTables = [];
|
||||||
if ($db && method_exists($db, 'getConnection')) {
|
if ($db && method_exists($db, 'getConnection')) {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@
|
||||||
/**
|
/**
|
||||||
* Maintenance mode page
|
* Maintenance mode page
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use App\Core\Maintenance;
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<div class="container mt-5">
|
<div class="container mt-5">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
|
|
@ -12,7 +15,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p class="lead">The site is temporarily unavailable due to maintenance.</p>
|
<p class="lead">The site is temporarily unavailable due to maintenance.</p>
|
||||||
<?php $mm = \App\Core\Maintenance::getMessage(); ?>
|
<?php $mm = Maintenance::getMessage(); ?>
|
||||||
<?php if ($mm): ?>
|
<?php if ($mm): ?>
|
||||||
<p class="mb-0"><em><?= htmlspecialchars($mm) ?></em></p>
|
<p class="mb-0"><em><?= htmlspecialchars($mm) ?></em></p>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
$navMainDotsPayload = \App\Core\HookDispatcher::applyFilters('nav.main.dot_indicators', [
|
|
||||||
|
use App\Core\HookDispatcher;
|
||||||
|
|
||||||
|
$navMainDotsPayload = HookDispatcher::applyFilters('nav.main.dot_indicators', [
|
||||||
'dots' => [],
|
'dots' => [],
|
||||||
'app_root' => $app_root,
|
'app_root' => $app_root,
|
||||||
'user_id' => $userId ?? 0,
|
'user_id' => $userId ?? 0,
|
||||||
|
|
@ -17,7 +20,7 @@ if (!empty($navMainDots) && is_array($navMainDots)) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$navSettingsDotsPayload = \App\Core\HookDispatcher::applyFilters('nav.settings.dot_indicators', [
|
$navSettingsDotsPayload = HookDispatcher::applyFilters('nav.settings.dot_indicators', [
|
||||||
'dots' => [],
|
'dots' => [],
|
||||||
'app_root' => $app_root,
|
'app_root' => $app_root,
|
||||||
'user_id' => $userId ?? 0,
|
'user_id' => $userId ?? 0,
|
||||||
|
|
@ -28,7 +31,7 @@ if (is_array($navSettingsDotsPayload)) {
|
||||||
$navSettingsDots = $navSettingsDotsPayload['dots'] ?? (is_array($navSettingsDotsPayload) ? $navSettingsDotsPayload : []);
|
$navSettingsDots = $navSettingsDotsPayload['dots'] ?? (is_array($navSettingsDotsPayload) ? $navSettingsDotsPayload : []);
|
||||||
}
|
}
|
||||||
|
|
||||||
$navAccountDotsPayload = \App\Core\HookDispatcher::applyFilters('nav.account.dot_indicators', [
|
$navAccountDotsPayload = HookDispatcher::applyFilters('nav.account.dot_indicators', [
|
||||||
'dots' => [],
|
'dots' => [],
|
||||||
'app_root' => $app_root,
|
'app_root' => $app_root,
|
||||||
'user_id' => $userId ?? 0,
|
'user_id' => $userId ?? 0,
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,9 @@
|
||||||
* - screenshotUrl: URL to the screenshot (or null if not available)
|
* - screenshotUrl: URL to the screenshot (or null if not available)
|
||||||
* - isActive: Whether this is the current theme
|
* - isActive: Whether this is the current theme
|
||||||
*/
|
*/
|
||||||
?>
|
|
||||||
<?php
|
use App\App;
|
||||||
|
|
||||||
$activeThemeName = 'Default';
|
$activeThemeName = 'Default';
|
||||||
foreach ($themes as $themeData) {
|
foreach ($themes as $themeData) {
|
||||||
if (!empty($themeData['isActive'])) {
|
if (!empty($themeData['isActive'])) {
|
||||||
|
|
@ -18,7 +19,7 @@ foreach ($themes as $themeData) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$userTimezone = \App\App::get('user_timezone') ?: 'UTC';
|
$userTimezone = App::get('user_timezone') ?: 'UTC';
|
||||||
$totalThemes = count($themes);
|
$totalThemes = count($themes);
|
||||||
?>
|
?>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,21 @@
|
||||||
* Version: 0.4.1
|
* Version: 0.4.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Load application classes
|
||||||
|
use App\App;
|
||||||
|
use App\Core\ConfigLoader;
|
||||||
|
use App\Core\DatabaseConnector;
|
||||||
|
use App\Core\HookDispatcher;
|
||||||
|
use App\Core\LogThrottler;
|
||||||
|
use App\Core\Maintenance;
|
||||||
|
use App\Core\MiddlewarePipeline;
|
||||||
|
use App\Core\MigrationRunner;
|
||||||
|
use App\Core\NullLogger;
|
||||||
|
use App\Core\PluginManager;
|
||||||
|
use App\Core\PluginRouteRegistry;
|
||||||
|
use App\Core\Router;
|
||||||
|
use App\Helpers\Theme;
|
||||||
|
|
||||||
// error reporting, comment out in production
|
// error reporting, comment out in production
|
||||||
//ini_set('display_errors', 1);
|
//ini_set('display_errors', 1);
|
||||||
//ini_set('display_startup_errors', 1);
|
//ini_set('display_startup_errors', 1);
|
||||||
|
|
@ -23,9 +38,6 @@ define('APP_PATH', __DIR__ . '/../app/');
|
||||||
require_once APP_PATH . 'core/ConfigLoader.php';
|
require_once APP_PATH . 'core/ConfigLoader.php';
|
||||||
require_once APP_PATH . 'core/App.php';
|
require_once APP_PATH . 'core/App.php';
|
||||||
require_once APP_PATH . 'core/PluginRouteRegistry.php';
|
require_once APP_PATH . 'core/PluginRouteRegistry.php';
|
||||||
use App\Core\ConfigLoader;
|
|
||||||
use App\App;
|
|
||||||
use App\Core\PluginRouteRegistry;
|
|
||||||
|
|
||||||
// Load the core datetime helper for all user-facing dates/times
|
// Load the core datetime helper for all user-facing dates/times
|
||||||
require_once APP_PATH . 'helpers/datetime.php';
|
require_once APP_PATH . 'helpers/datetime.php';
|
||||||
|
|
@ -57,8 +69,6 @@ App::set('app_root', $app_root);
|
||||||
// Initialize HookDispatcher and plugin system
|
// Initialize HookDispatcher and plugin system
|
||||||
require_once APP_PATH . 'core/HookDispatcher.php';
|
require_once APP_PATH . 'core/HookDispatcher.php';
|
||||||
require_once APP_PATH . 'core/PluginManager.php';
|
require_once APP_PATH . 'core/PluginManager.php';
|
||||||
use App\Core\HookDispatcher;
|
|
||||||
use App\Core\PluginManager;
|
|
||||||
|
|
||||||
// Global allowed URLs registration
|
// Global allowed URLs registration
|
||||||
register_hook('filter_allowed_urls', function($urls) {
|
register_hook('filter_allowed_urls', function($urls) {
|
||||||
|
|
@ -106,7 +116,6 @@ require_once APP_PATH . 'classes/session.php';
|
||||||
|
|
||||||
// Initialize themes system after session is started
|
// Initialize themes system after session is started
|
||||||
require_once APP_PATH . 'helpers/theme.php';
|
require_once APP_PATH . 'helpers/theme.php';
|
||||||
use app\Helpers\Theme;
|
|
||||||
|
|
||||||
Session::startSession();
|
Session::startSession();
|
||||||
|
|
||||||
|
|
@ -119,7 +128,7 @@ if (!isset($page)) {
|
||||||
|
|
||||||
// Middleware pipeline for security, sanitization & CSRF
|
// Middleware pipeline for security, sanitization & CSRF
|
||||||
require_once APP_PATH . 'core/MiddlewarePipeline.php';
|
require_once APP_PATH . 'core/MiddlewarePipeline.php';
|
||||||
$pipeline = new \App\Core\MiddlewarePipeline();
|
$pipeline = new MiddlewarePipeline();
|
||||||
App::set('middleware.pipeline', $pipeline);
|
App::set('middleware.pipeline', $pipeline);
|
||||||
$pipeline->add(function() {
|
$pipeline->add(function() {
|
||||||
// Apply security headers
|
// Apply security headers
|
||||||
|
|
@ -143,7 +152,6 @@ require APP_PATH . 'includes/errors.php';
|
||||||
|
|
||||||
// Connect to DB via DatabaseConnector (before loading plugins so their hooks are available)
|
// Connect to DB via DatabaseConnector (before loading plugins so their hooks are available)
|
||||||
require_once APP_PATH . 'core/DatabaseConnector.php';
|
require_once APP_PATH . 'core/DatabaseConnector.php';
|
||||||
use App\Core\DatabaseConnector;
|
|
||||||
$db = DatabaseConnector::connect($config);
|
$db = DatabaseConnector::connect($config);
|
||||||
App::set('db', $db);
|
App::set('db', $db);
|
||||||
|
|
||||||
|
|
@ -178,7 +186,6 @@ $allowed_urls = PluginRouteRegistry::injectAllowedPages($allowed_urls);
|
||||||
|
|
||||||
// Dispatch routing and auth (after plugins added public/allowed entries)
|
// Dispatch routing and auth (after plugins added public/allowed entries)
|
||||||
require_once APP_PATH . 'core/Router.php';
|
require_once APP_PATH . 'core/Router.php';
|
||||||
use App\Core\Router;
|
|
||||||
$currentUser = Router::checkAuth($config, $app_root, $public_pages, $page);
|
$currentUser = Router::checkAuth($config, $app_root, $public_pages, $page);
|
||||||
if ($currentUser === null && $validSession) {
|
if ($currentUser === null && $validSession) {
|
||||||
$currentUser = Session::getUsername();
|
$currentUser = Session::getUsername();
|
||||||
|
|
@ -186,11 +193,9 @@ if ($currentUser === null && $validSession) {
|
||||||
|
|
||||||
// Initialize Log throttler
|
// Initialize Log throttler
|
||||||
require_once APP_PATH . 'core/LogThrottler.php';
|
require_once APP_PATH . 'core/LogThrottler.php';
|
||||||
use App\Core\LogThrottler;
|
|
||||||
|
|
||||||
// Logging: default to NullLogger, plugin can override
|
// Logging: default to NullLogger, plugin can override
|
||||||
require_once APP_PATH . 'core/NullLogger.php';
|
require_once APP_PATH . 'core/NullLogger.php';
|
||||||
use App\Core\NullLogger;
|
|
||||||
$logObject = new NullLogger();
|
$logObject = new NullLogger();
|
||||||
App::set('logger', $logObject);
|
App::set('logger', $logObject);
|
||||||
|
|
||||||
|
|
@ -218,7 +223,7 @@ try {
|
||||||
$migrationsDir = APP_PATH . '../doc/database/migrations';
|
$migrationsDir = APP_PATH . '../doc/database/migrations';
|
||||||
if (is_dir($migrationsDir) && $userId !== null && $page !== 'login') {
|
if (is_dir($migrationsDir) && $userId !== null && $page !== 'login') {
|
||||||
require_once APP_PATH . 'core/MigrationRunner.php';
|
require_once APP_PATH . 'core/MigrationRunner.php';
|
||||||
$runner = new \App\Core\MigrationRunner($db, $migrationsDir);
|
$runner = new MigrationRunner($db, $migrationsDir);
|
||||||
if ($runner->hasPendingMigrations()) {
|
if ($runner->hasPendingMigrations()) {
|
||||||
$pending = $runner->listPendingMigrations();
|
$pending = $runner->listPendingMigrations();
|
||||||
$msg = 'Database schema is out of date. There are pending migrations. Run "<code>php scripts/migrate.php up</code>" or use the <a href="?page=admin§ion=migrations">Admin center</a>';
|
$msg = 'Database schema is out of date. There are pending migrations. Run "<code>php scripts/migrate.php up</code>" or use the <a href="?page=admin§ion=migrations">Admin center</a>';
|
||||||
|
|
@ -276,7 +281,7 @@ if (!$pipeline->run()) {
|
||||||
// Maintenance mode: show maintenance page to non-superusers
|
// Maintenance mode: show maintenance page to non-superusers
|
||||||
try {
|
try {
|
||||||
require_once APP_PATH . 'core/Maintenance.php';
|
require_once APP_PATH . 'core/Maintenance.php';
|
||||||
if (\App\Core\Maintenance::isEnabled()) {
|
if (Maintenance::isEnabled()) {
|
||||||
$isSuperuser = false;
|
$isSuperuser = false;
|
||||||
if ($validSession && isset($userId) && isset($userObject) && method_exists($userObject, 'hasRight')) {
|
if ($validSession && isset($userId) && isset($userObject) && method_exists($userObject, 'hasRight')) {
|
||||||
// user 1 is always superuser per implementation, but also check explicit right
|
// user 1 is always superuser per implementation, but also check explicit right
|
||||||
|
|
@ -287,15 +292,15 @@ try {
|
||||||
// Advise clients to retry after 10 minutes (600 seconds; configure here)
|
// Advise clients to retry after 10 minutes (600 seconds; configure here)
|
||||||
header('Retry-After: 600');
|
header('Retry-After: 600');
|
||||||
// Show themed maintenance page
|
// Show themed maintenance page
|
||||||
\App\Helpers\Theme::include('page-header');
|
Theme::include('page-header');
|
||||||
\App\Helpers\Theme::include('page-menu');
|
Theme::include('page-menu');
|
||||||
include APP_PATH . 'templates/maintenance.php';
|
include APP_PATH . 'templates/maintenance.php';
|
||||||
\App\Helpers\Theme::include('page-footer');
|
Theme::include('page-footer');
|
||||||
ob_end_flush();
|
ob_end_flush();
|
||||||
exit;
|
exit;
|
||||||
} else {
|
} else {
|
||||||
// Superusers bypass maintenance; show a small banner
|
// Superusers bypass maintenance; show a small banner
|
||||||
$maintMsg = \App\Core\Maintenance::getMessage();
|
$maintMsg = Maintenance::getMessage();
|
||||||
$custom = 'Maintenance mode is enabled.';
|
$custom = 'Maintenance mode is enabled.';
|
||||||
if (!empty($maintMsg)) {
|
if (!empty($maintMsg)) {
|
||||||
$custom .= ' <em>' . htmlspecialchars($maintMsg) . '</em>';
|
$custom .= ' <em>' . htmlspecialchars($maintMsg) . '</em>';
|
||||||
|
|
@ -314,7 +319,7 @@ if ($validSession && isset($userId) && isset($userObject) && is_object($userObje
|
||||||
try {
|
try {
|
||||||
$dbTheme = $userObject->getUserTheme((int)$userId);
|
$dbTheme = $userObject->getUserTheme((int)$userId);
|
||||||
if ($dbTheme) {
|
if ($dbTheme) {
|
||||||
\App\Helpers\Theme::setCurrentTheme($dbTheme, false);
|
Theme::setCurrentTheme($dbTheme, false);
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
// Non-fatal if theme load fails
|
// Non-fatal if theme load fails
|
||||||
|
|
@ -357,10 +362,10 @@ if ($page == 'logout') {
|
||||||
Feedback::flash('LOGIN', 'LOGOUT_SUCCESS');
|
Feedback::flash('LOGIN', 'LOGOUT_SUCCESS');
|
||||||
|
|
||||||
// Use theme helper to include templates
|
// Use theme helper to include templates
|
||||||
\App\Helpers\Theme::include('page-header');
|
Theme::include('page-header');
|
||||||
\App\Helpers\Theme::include('page-menu');
|
Theme::include('page-menu');
|
||||||
include APP_PATH . 'pages/login.php';
|
include APP_PATH . 'pages/login.php';
|
||||||
\App\Helpers\Theme::include('page-footer');
|
Theme::include('page-footer');
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// if user is logged in, we need user details and rights
|
// if user is logged in, we need user details and rights
|
||||||
|
|
@ -444,36 +449,36 @@ if ($page == 'logout') {
|
||||||
ob_end_flush();
|
ob_end_flush();
|
||||||
exit;
|
exit;
|
||||||
} else {
|
} else {
|
||||||
\App\Helpers\Theme::include('page-header');
|
Theme::include('page-header');
|
||||||
\App\Helpers\Theme::include('page-menu');
|
Theme::include('page-menu');
|
||||||
if ($validSession) {
|
if ($validSession) {
|
||||||
\App\Helpers\Theme::include('page-sidebar');
|
Theme::include('page-sidebar');
|
||||||
}
|
}
|
||||||
PluginRouteRegistry::dispatch($page, $routeContext);
|
PluginRouteRegistry::dispatch($page, $routeContext);
|
||||||
\App\Helpers\Theme::include('page-footer');
|
Theme::include('page-footer');
|
||||||
}
|
}
|
||||||
} elseif (in_array($page, $allowed_urls)) {
|
} elseif (in_array($page, $allowed_urls)) {
|
||||||
// The page is from a core controller
|
// The page is from a core controller
|
||||||
\App\Helpers\Theme::include('page-header');
|
Theme::include('page-header');
|
||||||
\App\Helpers\Theme::include('page-menu');
|
Theme::include('page-menu');
|
||||||
if ($validSession) {
|
if ($validSession) {
|
||||||
\App\Helpers\Theme::include('page-sidebar');
|
Theme::include('page-sidebar');
|
||||||
}
|
}
|
||||||
if (file_exists(APP_PATH . "pages/{$page}.php")) {
|
if (file_exists(APP_PATH . "pages/{$page}.php")) {
|
||||||
include APP_PATH . "pages/{$page}.php";
|
include APP_PATH . "pages/{$page}.php";
|
||||||
} else {
|
} else {
|
||||||
include APP_PATH . 'templates/error-notfound.php';
|
include APP_PATH . 'templates/error-notfound.php';
|
||||||
}
|
}
|
||||||
\App\Helpers\Theme::include('page-footer');
|
Theme::include('page-footer');
|
||||||
} else {
|
} else {
|
||||||
// The page is not in allowed URLs
|
// The page is not in allowed URLs
|
||||||
\App\Helpers\Theme::include('page-header');
|
Theme::include('page-header');
|
||||||
\App\Helpers\Theme::include('page-menu');
|
Theme::include('page-menu');
|
||||||
if ($validSession) {
|
if ($validSession) {
|
||||||
\App\Helpers\Theme::include('page-sidebar');
|
Theme::include('page-sidebar');
|
||||||
}
|
}
|
||||||
include APP_PATH . 'templates/error-notfound.php';
|
include APP_PATH . 'templates/error-notfound.php';
|
||||||
\App\Helpers\Theme::include('page-footer');
|
Theme::include('page-footer');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Helpers\Theme;
|
||||||
|
?>
|
||||||
<!-- Modern Theme Footer -->
|
<!-- Modern Theme Footer -->
|
||||||
<footer class="footer mt-5 py-3 bg-light">
|
<footer class="footer mt-5 py-3 bg-light">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
@ -17,7 +21,7 @@
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<!-- Theme-specific JavaScript -->
|
<!-- Theme-specific JavaScript -->
|
||||||
<script src="<?= \App\Helpers\Theme::asset('js/theme.js') ?>"></script>
|
<script src="<?= Theme::asset('js/theme.js') ?>"></script>
|
||||||
|
|
||||||
<!-- Global site scripts -->
|
<!-- Global site scripts -->
|
||||||
<script src="<?= htmlspecialchars($app_root) ?>static/js/messages.js"></script>
|
<script src="<?= htmlspecialchars($app_root) ?>static/js/messages.js"></script>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Helpers\Theme;
|
||||||
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
|
|
@ -15,7 +19,7 @@
|
||||||
<link rel="stylesheet" type="text/css" href="<?= htmlspecialchars($app_root) ?>static/css/main.css">
|
<link rel="stylesheet" type="text/css" href="<?= htmlspecialchars($app_root) ?>static/css/main.css">
|
||||||
|
|
||||||
<!-- Theme-specific CSS -->
|
<!-- Theme-specific CSS -->
|
||||||
<link rel="stylesheet" type="text/css" href="<?= \App\Helpers\Theme::asset('css/theme.css') ?>">
|
<link rel="stylesheet" type="text/css" href="<?= Theme::asset('css/theme.css') ?>">
|
||||||
|
|
||||||
<!-- jQuery -->
|
<!-- jQuery -->
|
||||||
<script src="<?= htmlspecialchars($app_root) ?>static/libs/jquery/jquery.min.js"></script>
|
<script src="<?= htmlspecialchars($app_root) ?>static/libs/jquery/jquery.min.js"></script>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Helpers\Theme;
|
||||||
|
?>
|
||||||
<!-- Retro Theme Footer -->
|
<!-- Retro Theme Footer -->
|
||||||
<footer class="footer mt-5 py-3 bg-light">
|
<footer class="footer mt-5 py-3 bg-light">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
@ -17,7 +21,7 @@
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<!-- Theme-specific JavaScript -->
|
<!-- Theme-specific JavaScript -->
|
||||||
<script src="<?= \App\Helpers\Theme::asset('js/theme.js') ?>"></script>
|
<script src="<?= Theme::asset('js/theme.js') ?>"></script>
|
||||||
|
|
||||||
<!-- Global site scripts -->
|
<!-- Global site scripts -->
|
||||||
<script src="<?= htmlspecialchars($app_root) ?>static/js/messages.js"></script>
|
<script src="<?= htmlspecialchars($app_root) ?>static/js/messages.js"></script>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Helpers\Theme;
|
||||||
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
|
|
@ -15,7 +19,7 @@
|
||||||
<link rel="stylesheet" type="text/css" href="<?= htmlspecialchars($app_root) ?>static/css/main.css">
|
<link rel="stylesheet" type="text/css" href="<?= htmlspecialchars($app_root) ?>static/css/main.css">
|
||||||
|
|
||||||
<!-- Theme-specific CSS -->
|
<!-- Theme-specific CSS -->
|
||||||
<link rel="stylesheet" type="text/css" href="<?= \App\Helpers\Theme::asset('css/theme.css') ?>">
|
<link rel="stylesheet" type="text/css" href="<?= Theme::asset('css/theme.css') ?>">
|
||||||
|
|
||||||
<!-- jQuery -->
|
<!-- jQuery -->
|
||||||
<script src="<?= htmlspecialchars($app_root) ?>static/libs/jquery/jquery.min.js"></script>
|
<script src="<?= htmlspecialchars($app_root) ?>static/libs/jquery/jquery.min.js"></script>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue