feat: add admin env badge, quick post button, and harden plugin enable
Build and Deploy / verify (push) Failing after 15m17s
Build and Deploy / deploy (push) Skipped

Show local/prod in the Filament topbar, jump to create post in one click, tighten sidebar spacing, and stop Hello World from 500ing when its tables are missing.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
gouki
2026-09-18 08:24:16 +00:00
co-authored by Cursor
parent b39423831c
commit 469160dc3f
19 changed files with 825 additions and 43 deletions
@@ -45,7 +45,11 @@ class PluginManagerServiceProvider extends ServiceProvider
$provider = $manager->resolveProvider($key);
if ($provider && class_exists($provider)) {
$provider::bootPlugin($manager);
try {
$provider::bootPlugin($manager);
} catch (\Throwable $e) {
report($e);
}
}
}
}
@@ -49,6 +49,7 @@ class PostContentRenderer
// 插件钩子:付费内容过滤、AI 处理等
$html = app(\App\Blog\Support\PluginManager::class)->applyFilters('post.rendered', $html, $post);
$html = is_string($html) ? $html : '';
// 兜底:任何情况下不把裸 [paid] 标签输出到页面(如会员插件被停用时)
return preg_replace('/\[(\/?paid)\]/i', '', $html);
+36 -2
View File
@@ -6,6 +6,7 @@ declare(strict_types=1);
namespace App\Blog\Support;
use App\Models\PluginRecord;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
use RuntimeException;
@@ -155,6 +156,8 @@ class PluginManager
throw new RuntimeException('无法启用 '.$plugin.':'.implode(';', $problems));
}
$this->migratePlugin($plugin);
[$vendor, $name] = array_pad(explode('.', $plugin), 2, $plugin);
PluginRecord::query()->updateOrCreate(
['vendor' => $vendor, 'name' => $name],
@@ -162,6 +165,29 @@ class PluginManager
);
}
/**
* Run the plugin's own migrations so enabling a demo/third-party plugin
* does not 500 on missing tables.
*/
public function migratePlugin(string $plugin): void
{
$relativePath = 'plugins/'.$plugin.'/database/migrations';
if (! is_dir(base_path($relativePath))) {
return;
}
$exitCode = Artisan::call('migrate', [
'--path' => $relativePath,
'--force' => true,
'--no-interaction' => true,
]);
if ($exitCode !== 0) {
throw new RuntimeException('插件迁移失败:'.$plugin.'。'.trim(Artisan::output()));
}
}
public function disable(string $plugin): void
{
$dependents = $this->dependents($plugin);
@@ -243,7 +269,11 @@ class PluginManager
{
foreach ($this->actions[$hook] ?? [] as $callbacks) {
foreach ($callbacks as $callback) {
$callback(...$args);
try {
$callback(...$args);
} catch (\Throwable $e) {
report($e);
}
}
}
}
@@ -252,7 +282,11 @@ class PluginManager
{
foreach ($this->filters[$hook] ?? [] as $callbacks) {
foreach ($callbacks as $callback) {
$value = $callback($value, ...$args);
try {
$value = $callback($value, ...$args);
} catch (\Throwable $e) {
report($e);
}
}
}