'; echo '
'; echo ''; } public function enqueue_admin_assets($hook): void { $screen = function_exists('get_current_screen') ? get_current_screen() : null; if (!$screen || $screen->base !== 'toplevel_page_' . self::PAGE_SLUG) { return; } $build_dir = trailingslashit(AKSRT_DIR) . 'assets/admin/build/'; $build_uri = trailingslashit(AKSRT_URI) . 'assets/admin/build/'; $entry = $build_dir . 'index.js'; if (!is_file($entry)) { add_action('admin_notices', static function (): void { if (!current_user_can('manage_options')) { return; } echo '

'; echo esc_html__('AKSRT 管理后台构建缺失:请在 assets/admin 执行 npm run build,并完整部署 build/ 目录。', 'aksrt'); echo '

'; }); return; } $missing_chunks = self::find_missing_admin_chunks($build_dir, $entry); if ($missing_chunks !== []) { add_action('admin_notices', static function () use ($missing_chunks): void { if (!current_user_can('manage_options')) { return; } echo '

'; echo esc_html__('AKSRT 管理后台构建不完整(动态模块缺失),请重新完整部署 assets/admin/build/,不要只覆盖 index.js。缺失:', 'aksrt'); echo ' ' . esc_html(implode(', ', array_slice($missing_chunks, 0, 8))); if (count($missing_chunks) > 8) { echo '…'; } echo '

'; }); // Still enqueue entry so console shows the real import error if an admin insists; // notice makes the deploy mistake explicit. } $css_files = [ 'naive-ui.css', 'index.css', 'index2.css', ]; foreach ($css_files as $css_file) { $path = $build_dir . $css_file; if (file_exists($path)) { wp_enqueue_style( 'aksrt-admin-' . sanitize_key(str_replace(['.', '/'], '-', $css_file)), $build_uri . $css_file, [], (string) filemtime($path) ); } } // Match frontend FA5 pack so FaIcon / menu glyphs render in the SPA. wp_enqueue_style( 'aksrt-font-awesome-5', 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css', [], '5.15.4' ); wp_enqueue_script( 'aksrt-admin-app', $build_uri . 'index.js', [], (string) filemtime($entry), true ); wp_localize_script('aksrt-admin-app', 'aksrtAdminData', [ 'apiUrl' => esc_url_raw(rest_url(self::API_NAMESPACE)), 'nonce' => wp_create_nonce('wp_rest'), 'siteUrl' => home_url('/'), 'adminUrl' => admin_url('/'), 'themeVersion' => wp_get_theme()->get('Version') ?: '3.4.0-dev', 'themeUri' => defined('AKSRT_URI') ? AKSRT_URI : get_template_directory_uri(), 'buildOk' => $missing_chunks === [], ]); wp_enqueue_media(); } /** * Parse index.js dynamic imports and report missing chunk files. * * @return string[] */ private static function find_missing_admin_chunks(string $build_dir, string $entry_file): array { $src = file_get_contents($entry_file); if (!is_string($src) || $src === '') { return ['index.js unreadable']; } if (!preg_match_all('/\.\/([A-Za-z0-9_.-]+\.js)/', $src, $matches)) { return []; } $missing = []; foreach (array_unique($matches[1]) as $chunk) { if (!is_file($build_dir . $chunk)) { $missing[] = $chunk; } } return $missing; } public function add_module_type_attribute(string $tag, string $handle): string { if ('aksrt-admin-app' === $handle) { return str_replace('