Replace the loose page-count label with a SaBlog-style 6 / 316 chip, wire inject/stylevar HTML into list and post views, and flush page cache when ads are saved. Co-authored-by: Cursor <cursoragent@cursor.com>
142 lines
4.6 KiB
PHP
142 lines
4.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Blog\Support;
|
|
|
|
use App\Models\Setting;
|
|
|
|
/**
|
|
* 主题内容注入点:在标准位置注入广告/统计/临时链接等 HTML。
|
|
*
|
|
* 注入点(Blade @stack,主题视图内置):
|
|
* head / header / sidebar_top / sidebar_bottom / content_top / content_bottom
|
|
* post_content_top / post_content_bottom / footer / body_end
|
|
*
|
|
* 特性:
|
|
* 1. 同一位置可配置「多条」注入块(后台主题注入页管理),按 sort 顺序渲染
|
|
* 2. 每条可启停
|
|
* 3. 插件可通过 filter `theme.inject.{point}` 追加
|
|
* 4. 主题变量(stylevar):theme('var', 'key') 引用任意键值 HTML
|
|
*/
|
|
class ThemeInjector
|
|
{
|
|
public const POINTS = [
|
|
'head' => '页头(</head> 前)',
|
|
'header' => '页头下方',
|
|
'sidebar_top' => '侧边栏顶部',
|
|
'sidebar_bottom' => '侧边栏底部',
|
|
'content_top' => '内容区顶部',
|
|
'content_bottom' => '内容区底部',
|
|
'post_content_top' => '文章正文前',
|
|
'post_content_bottom' => '文章正文后',
|
|
'footer' => '页脚前',
|
|
'body_end' => '页面末尾(</body> 前)',
|
|
];
|
|
|
|
/**
|
|
* Old SaBlog stylevar names → inject points. Unmapped HTML vars go to footer.
|
|
*
|
|
* @var array<string, list<string>>
|
|
*/
|
|
public const STYLEVAR_POINTS = [
|
|
'head' => ['ad_head', 'headad'],
|
|
'header' => ['headerad', 'header_ad', 'ad_header', 'topad', 'ad_top', 'sitead', 'site_ad'],
|
|
'sidebar_top' => ['sidebarad', 'sidebar_ad', 'ad_sidebar', 'leftad', 'ad_left'],
|
|
'sidebar_bottom' => ['ad_sidebar_bottom'],
|
|
'content_top' => ['indexad', 'ad_index', 'contentad', 'ad_content'],
|
|
'content_bottom' => ['ad_content_bottom'],
|
|
'post_content_top' => ['ad_post_top', 'insad'],
|
|
'post_content_bottom' => ['ad_post_bottom'],
|
|
'footer' => ['footerad', 'footer_ad', 'ad_footer', 'huangjinlian', 'huangjinlian2', 'huangjinlian3'],
|
|
'body_end' => ['ad_body_end'],
|
|
];
|
|
|
|
/**
|
|
* 读取某一注入点的所有注入块(多条,已排序、已过滤停用),
|
|
* 并把插件追加的 HTML 合并进来。
|
|
*/
|
|
public static function blocksFor(string $point): array
|
|
{
|
|
$raw = Setting::get('inject.blocks', []);
|
|
$raw = is_array($raw) ? $raw : (json_decode((string) $raw, true) ?: []);
|
|
|
|
$blocks = collect($raw)
|
|
->filter(fn (array $b) => ($b['point'] ?? null) === $point && ($b['enabled'] ?? true))
|
|
->sortBy(fn (array $b) => (int) ($b['sort'] ?? 0))
|
|
->pluck('html')
|
|
->filter()
|
|
->values()
|
|
->all();
|
|
|
|
foreach (self::stylevarBlocks($point) as $html) {
|
|
$blocks[] = $html;
|
|
}
|
|
|
|
$extra = (string) app(PluginManager::class)->applyFilters("theme.inject.{$point}", '');
|
|
|
|
if ($extra !== '') {
|
|
$blocks[] = $extra;
|
|
}
|
|
|
|
return $blocks;
|
|
}
|
|
|
|
/**
|
|
* 注册 View Composer:渲染前台视图前把各注入点内容 push 到对应 @stack。
|
|
*/
|
|
public static function registerComposer(): void
|
|
{
|
|
$views = ['index', 'show', 'list', 'archives', 'tags', 'tag', 'search', 'links', 'comments', 'login', 'register', 'profile', 'membership.*', 'payments.*'];
|
|
|
|
\Illuminate\Support\Facades\View::composer($views, function (\Illuminate\View\View $view) {
|
|
foreach (array_keys(self::POINTS) as $point) {
|
|
foreach (self::blocksFor($point) as $html) {
|
|
$view->getFactory()->startPush("theme:{$point}", $html);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @return list<string>
|
|
*/
|
|
private static function stylevarBlocks(string $point): array
|
|
{
|
|
$vars = app(ThemeManager::class)->variables();
|
|
if ($vars === []) {
|
|
return [];
|
|
}
|
|
|
|
$html = [];
|
|
foreach (self::STYLEVAR_POINTS[$point] ?? [] as $key) {
|
|
$value = trim((string) ($vars[$key] ?? ''));
|
|
if ($value !== '') {
|
|
$html[] = $value;
|
|
}
|
|
}
|
|
|
|
if ($point !== 'footer') {
|
|
return $html;
|
|
}
|
|
|
|
$mapped = [];
|
|
foreach (self::STYLEVAR_POINTS as $keys) {
|
|
foreach ($keys as $key) {
|
|
$mapped[$key] = true;
|
|
}
|
|
}
|
|
|
|
foreach ($vars as $key => $value) {
|
|
$value = trim((string) $value);
|
|
if ($value === '' || isset($mapped[$key]) || ! str_contains($value, '<')) {
|
|
continue;
|
|
}
|
|
|
|
$html[] = $value;
|
|
}
|
|
|
|
return $html;
|
|
}
|
|
}
|