$siteTitle, 'site_logo' => mnbt_home_asset(mnbt_home_option('home_logo', '') ?: 'imsetes/upload_logo/logo.index.png'), 'site_primary' => mnbt_home_option('home_primary', '#4f46e5'), 'site_hero' => mnbt_home_option('home_hero', '高性能虚拟主机,即买即用'), 'site_footer' => mnbt_home_option('home_footer', '') ?: ($conf['hxp'] ?? ''), 'favicon' => mnbt_home_asset(mnbt_home_option('home_favicon', '') ?: 'imsetes/images/logo-ico.png'), // 公告与区块开关 'notice' => mnbt_home_option('gg', ''), 'show_notice' => mnbt_home_option('home_show_notice', 'true') === 'true', 'show_plans' => mnbt_home_option('home_show_plans', 'true') === 'true', // 登录态与能力探测(不强依赖插件) 'logged_in' => isset($_COOKIE['user_token']) && $_COOKIE['user_token'] !== '', 'has_shop' => function_exists('mnbt_plugin_enabled') && mnbt_plugin_enabled('hosting_shop'), 'has_balance' => function_exists('mnbt_plugin_enabled') && mnbt_plugin_enabled('balance'), 'has_user' => function_exists('mnbt_plugin_enabled') && mnbt_plugin_enabled('user_info'), 'has_site' => function_exists('mnbt_plugin_enabled') && mnbt_plugin_enabled('official_site'), 'has_docker' => function_exists('mnbt_plugin_enabled') && mnbt_plugin_enabled('docker_shop'), // 业务数据 'plans' => [], 'blocks' => [], // URL 生成回调 'url' => function (string $path = '') { return mnbt_home_url($path); }, 'coreUrl' => function (string $path = '') { return mnbt_home_core_url($path); }, ]; // 套餐区(hosting_shop 启用且有有效套餐时展示,查询失败静默降级为空) if ($data['has_shop'] && $data['show_plans'] && isset($DB)) { $rows = @$DB->get_all_prepare("SELECT * FROM MN_plugin_hosting_plan WHERE status='active' ORDER BY sort ASC, id ASC") ?: []; foreach ($rows as $p) { $minPrice = 0; if ((int)($p['price_month_cents'] ?? 0) > 0) { $minPrice = (int)$p['price_month_cents'] / 100; } if ((int)($p['price_year_cents'] ?? 0) > 0) { $yearPrice = (int)$p['price_year_cents'] / 100; if ($minPrice == 0 || $yearPrice / 12 < $minPrice) { $minPrice = $yearPrice / 12; } } $feats = []; if (!empty($p['spec_web'])) $feats[] = '网页空间 ' . $p['spec_web'] . ' MB'; if (!empty($p['spec_sql'])) $feats[] = '数据库 ' . $p['spec_sql'] . ' MB'; if (!empty($p['spec_flow'])) $feats[] = '月流量 ' . $p['spec_flow'] . ' GB'; if (!empty($p['spec_domain'])) $feats[] = '可绑定 ' . $p['spec_domain'] . ' 个域名'; $data['plans'][] = [ 'id' => (int)$p['id'], 'name' => (string)$p['name'], 'desc' => (string)($p['description'] ?? ''), 'price' => $minPrice > 0 ? '¥' . number_format($minPrice, 2) . ' 起/月' : '免费', 'feats' => $feats, ]; } } // 插件扩展区块(home.blocks 过滤器,按 order 升序;仅取结构化字段) if (function_exists('mnbt_apply_filters')) { $blocks = mnbt_apply_filters('home.blocks', []); if (is_array($blocks)) { $clean = []; foreach ($blocks as $b) { if (!is_array($b) || !isset($b['html'])) { continue; } $clean[] = [ 'id' => (string)($b['id'] ?? ''), 'title' => (string)($b['title'] ?? ''), 'html' => (string)$b['html'], 'order' => (int)($b['order'] ?? 50), ]; } usort($clean, function ($a, $b) { return $a['order'] - $b['order']; }); $data['blocks'] = $clean; } } return $data; } /** 渲染内置主页(组装数据 → 加载主题模板 → 终止请求) */ function mnbt_home_render(): void { $path = mnbt_home_resolve(); if ($path === null) { http_response_code(500); echo 'Home template not found'; exit; } if (!headers_sent()) { @header('Content-Type: text/html; charset=UTF-8'); } $vars = mnbt_home_data(); $bufferLevel = ob_get_level(); ob_start('mnbt_csrf_inject_html'); try { extract($vars, EXTR_SKIP); include $path; } finally { while (ob_get_level() > $bufferLevel) { ob_end_flush(); } } exit; } /** 分发入口:index.php 在插件首页接管之后调用;仅路径为 / 且启用时生效 */ function mnbt_home_dispatch(): bool { if (!function_exists('mnbt_plugin_request_info')) { return false; } $info = mnbt_plugin_request_info(); if ($info['path'] !== '/') { return false; } if (!mnbt_home_enabled()) { return false; } mnbt_home_render(); return true; } /* ============================================================ * V1.84 主题注册自定义设置(结构化字段声明) * ============================================================ * * 主页主题可在 templates/{theme}/theme.php 中声明自定义设置字段: * * mnbt_register_home_setting([ * 'key' => 'bg_color', * 'label' => '背景颜色', * 'type' => 'color', // text | color | select | switch | textarea | number | image * 'default' => '#f0f4ff', * 'placeholder' => '#f0f4ff', * 'hint' => '可选提示文本', * 'options' => [['value'=>'a','label'=>'A'], ...], // select 专用 * ]); * * 字段统一持久化到 MN_config.home_theme_settings(JSON),模板端通过 * mnbt_home_theme_setting($key, $default) 读取当前值。 * * 渲染由当前 Admin 主题负责(default 用原生 HTML,tdesign 用 TDesign 组件), * 主题只需声明字段结构,不需要关心样式。 */ $GLOBALS['mnbt_home_settings_fields'] = []; /** 注册主页自定义设置字段(由主题 theme.php 调用) */ function mnbt_register_home_setting(array $config): bool { $key = trim((string)($config['key'] ?? '')); if ($key === '' || !preg_match('/^[a-zA-Z_][a-zA-Z0-9_]{0,63}$/', $key)) { return false; } $type = (string)($config['type'] ?? 'text'); if (!in_array($type, ['text', 'color', 'select', 'switch', 'textarea', 'number', 'image'], true)) { $type = 'text'; } if (isset($GLOBALS['mnbt_home_settings_fields'][$key])) { return false; // 重复 key } $GLOBALS['mnbt_home_settings_fields'][$key] = [ 'key' => $key, 'label' => (string)($config['label'] ?? $key), 'type' => $type, 'default' => $config['default'] ?? ($type === 'switch' ? false : ''), 'placeholder' => (string)($config['placeholder'] ?? ''), 'hint' => (string)($config['hint'] ?? ''), 'options' => ($type === 'select' && isset($config['options']) && is_array($config['options'])) ? $config['options'] : [], ]; return true; } /** 读取当前主页主题所有已保存的自定义设置值 */ function mnbt_home_theme_settings_all(): array { global $conf; if (is_array($conf) && !empty($conf['home_theme_settings'])) { $v = $conf['home_theme_settings']; if (is_string($v) && $v !== '') { $decoded = json_decode($v, true); if (is_array($decoded)) return $decoded; } } return []; } /** 读取单个主题自定义设置值(供模板使用) */ function mnbt_home_theme_setting(string $key, $default = null) { $all = mnbt_home_theme_settings_all(); return $all[$key] ?? $default; } /** 获取已注册字段列表(确保 theme.php 已加载) */ function mnbt_home_get_settings_fields(): array { mnbt_home_ensure_theme_loaded(); return $GLOBALS['mnbt_home_settings_fields'] ?? []; } /** 合并字段定义 + 已存值 → 渲染用数据 */ function mnbt_home_settings_view_data(): array { $fields = mnbt_home_get_settings_fields(); $values = mnbt_home_theme_settings_all(); $result = []; foreach ($fields as $f) { $key = $f['key']; $item = $f; $item['value'] = $values[$key] ?? $f['default']; $result[] = $item; } return $result; } /** 加载当前主页主题的 theme.php(若存在),确保字段已注册 */ function mnbt_home_ensure_theme_loaded(): void { static $done = false; if ($done) return; $done = true; if (function_exists('mnbt_theme_ensure_loaded')) { mnbt_theme_ensure_loaded('home'); } } /** 保存主题自定义设置(从 POST 收集注册字段的值,合并 JSON 写入 MN_config) */ function mnbt_home_settings_save(): void { mnbt_home_ensure_theme_loaded(); $fields = $GLOBALS['mnbt_home_settings_fields'] ?? []; if (empty($fields)) return; global $DB, $siteid; $existing = mnbt_home_theme_settings_all(); foreach ($fields as $f) { $k = $f['key']; if ($f['type'] === 'switch') { $existing[$k] = (isset($_POST['home_ts_' . $k]) && $_POST['home_ts_' . $k] === 'true'); } else { $existing[$k] = trim((string)($_POST['home_ts_' . $k] ?? '')); } } $json = json_encode($existing, JSON_UNESCAPED_UNICODE); if ($json === false) $json = '{}'; $sid = isset($siteid) ? $siteid : 1; @$DB->query_prepare("UPDATE `MN_config` SET `home_theme_settings` = ? WHERE `id` = ?", [$json, $sid]); } /* ============================================================ * 默认 Admin 主题渲染器 * ============================================================ */ /** 在 default 主题后台渲染主页自定义设置字段 HTML */ function mnbt_home_render_settings_fields_default(): string { $items = mnbt_home_settings_view_data(); if (empty($items)) return ''; $html = ''; foreach ($items as $f) { $label = htmlspecialchars($f['label']); $key = 'home_ts_' . $f['key']; $hint = $f['hint'] !== '' ? '' . htmlspecialchars($f['hint']) . '' : ''; $val = htmlspecialchars((string)$f['value']); $ph = htmlspecialchars($f['placeholder']); switch ($f['type']) { case 'color': $html .= '