232 lines
8.7 KiB
PHP
232 lines
8.7 KiB
PHP
<?php
|
|
defined('ABSPATH') || exit;
|
|
|
|
// EnlighterJS 代码高亮 — 白名单 data-enlighter-* 属性
|
|
// ============================================================
|
|
|
|
add_filter('wp_kses_allowed_html', function ($allowed, $context) {
|
|
if ($context !== 'post') {
|
|
return $allowed;
|
|
}
|
|
|
|
// Allow data-enlighter-* attributes on <pre> and <code>
|
|
$enlighter_attrs = [
|
|
'data-enlighter-language' => true,
|
|
'data-enlighter-theme' => true,
|
|
'data-enlighter-group' => true,
|
|
'data-enlighter-title' => true,
|
|
'data-enlighter-linenumbers' => true,
|
|
'data-enlighter-highlight' => true,
|
|
'data-enlighter-lineoffset' => true,
|
|
];
|
|
|
|
if (isset($allowed['pre'])) {
|
|
$allowed['pre'] = array_merge($allowed['pre'], $enlighter_attrs);
|
|
}
|
|
if (isset($allowed['code'])) {
|
|
$allowed['code'] = array_merge($allowed['code'], $enlighter_attrs);
|
|
}
|
|
|
|
return $allowed;
|
|
}, 10, 2);
|
|
|
|
// ============================================================
|
|
// WP 后台文章列表增强列 — 浏览/点赞/收藏/下载
|
|
// ============================================================
|
|
|
|
add_filter('manage_post_posts_columns', function ($columns) {
|
|
$new_columns = [];
|
|
foreach ($columns as $key => $label) {
|
|
$new_columns[$key] = $label;
|
|
if ($key === 'title') {
|
|
$new_columns['aksrt_stats'] = __('互动数据', 'aksrt');
|
|
}
|
|
}
|
|
return $new_columns;
|
|
});
|
|
|
|
add_action('admin_enqueue_scripts', function ($hook) {
|
|
if ($hook !== 'edit.php') return;
|
|
wp_enqueue_style('font-awesome-5', 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css', [], '5.15.4');
|
|
});
|
|
|
|
add_action('manage_post_posts_custom_column', function ($column, $post_id) {
|
|
if ($column !== 'aksrt_stats') return;
|
|
|
|
$views = (int) get_post_meta($post_id, 'views', true);
|
|
$likes = (int) get_post_meta($post_id, 'like', true);
|
|
$favorites = (int) get_post_meta($post_id, 'favorite', true);
|
|
$downloads = (int) get_post_meta($post_id, 'download_count', true);
|
|
|
|
$format = function (int $n): string {
|
|
if ($n >= 10000) return round($n / 10000, 1) . '万';
|
|
if ($n >= 1000) return round($n / 1000, 1) . 'k';
|
|
return (string) $n;
|
|
};
|
|
|
|
$parts = [];
|
|
$parts[] = '<span title="' . esc_attr__('浏览', 'aksrt') . '" style="margin-right:4px;"><i class="fas fa-eye" style="color:#8a909c;font-size:12px;"></i> ' . esc_html($format($views)) . '</span>';
|
|
$parts[] = '<span title="' . esc_attr__('点赞', 'aksrt') . '" style="margin-right:4px;"><i class="fas fa-thumbs-up" style="color:#1890ff;font-size:12px;"></i> ' . esc_html($format($likes)) . '</span>';
|
|
$parts[] = '<span title="' . esc_attr__('收藏', 'aksrt') . '" style="margin-right:4px;"><i class="fas fa-star" style="color:#f39c12;font-size:12px;"></i> ' . esc_html($format($favorites)) . '</span>';
|
|
|
|
if ($downloads > 0) {
|
|
$parts[] = '<span title="' . esc_attr__('下载', 'aksrt') . '"><i class="fas fa-download" style="color:#52c41a;font-size:12px;"></i> ' . esc_html($format($downloads)) . '</span>';
|
|
}
|
|
|
|
echo implode(' · ', $parts);
|
|
}, 10, 2);
|
|
|
|
// Support sorting by views/likes/favorites in admin
|
|
add_action('pre_get_posts', function ($query) {
|
|
if (!is_admin() || !$query->is_main_query()) return;
|
|
|
|
$orderby = $query->get('orderby');
|
|
$allowed = ['views', 'like', 'favorite', 'download_count'];
|
|
|
|
if (in_array($orderby, $allowed, true)) {
|
|
$query->set('meta_key', $orderby);
|
|
$query->set('orderby', 'meta_value_num');
|
|
}
|
|
});
|
|
|
|
// ============================================================
|
|
// 评论提交:单一合同
|
|
// ------------------------------------------------------------
|
|
// 评论提交统一走 WordPress 原生 wp-comments-post.php,由前端
|
|
// main.js initCommentSystem() 以 AJAX 拦截:它负责人机验证、频率
|
|
// 限制、审核管线,并在成功后通过 reloadCommentList() 重新拉取,
|
|
// 列表仍由 aksrt_comment_callback 这一规范渲染器输出。
|
|
// 不再保留并行的 aksrt_submit_comment 动作(避免绕过验证码的第二套提交合同)。
|
|
// 详见 comment-contract.md。
|
|
// ============================================================
|
|
|
|
// ============================================================
|
|
// Gutenberg 自定义块注册
|
|
// ============================================================
|
|
|
|
// Register category server-side so it exists before JS registerBlockType runs.
|
|
// Keep untyped + defensive: some plugins pass unexpected shapes; typed params can 500 the editor.
|
|
add_filter('block_categories_all', static function ($categories, $context = null) {
|
|
if (!is_array($categories)) {
|
|
return $categories;
|
|
}
|
|
|
|
foreach ($categories as $category) {
|
|
$slug = '';
|
|
if (is_array($category)) {
|
|
$slug = (string) ($category['slug'] ?? '');
|
|
} elseif (is_object($category) && isset($category->slug)) {
|
|
$slug = (string) $category->slug;
|
|
}
|
|
if ($slug === 'aksrt-blocks') {
|
|
return $categories;
|
|
}
|
|
}
|
|
|
|
$categories[] = [
|
|
'slug' => 'aksrt-blocks',
|
|
'title' => 'AKSRT',
|
|
'icon' => null,
|
|
];
|
|
|
|
return $categories;
|
|
}, 10, 2);
|
|
|
|
add_action('enqueue_block_editor_assets', function () {
|
|
$base_uri = get_template_directory_uri();
|
|
$version = wp_get_theme()->get('Version');
|
|
|
|
$blocks_js = get_template_directory() . '/assets/js/gutenberg-blocks.js';
|
|
if (file_exists($blocks_js)) {
|
|
wp_enqueue_script(
|
|
'aksrt-gutenberg-blocks',
|
|
$base_uri . '/assets/js/gutenberg-blocks.js',
|
|
// wp-media-utils: MediaUpload for carousel block
|
|
['wp-blocks', 'wp-element', 'wp-components', 'wp-block-editor', 'wp-hooks', 'wp-media-utils'],
|
|
(string) filemtime($blocks_js),
|
|
true
|
|
);
|
|
}
|
|
|
|
$blocks_css = get_template_directory() . '/assets/css/gutenberg-blocks.css';
|
|
if (file_exists($blocks_css)) {
|
|
wp_enqueue_style(
|
|
'aksrt-gutenberg-blocks',
|
|
$base_uri . '/assets/css/gutenberg-blocks.css',
|
|
[],
|
|
(string) filemtime($blocks_css)
|
|
);
|
|
}
|
|
});
|
|
|
|
// Front-end styles for Gutenberg blocks
|
|
add_action('enqueue_block_assets', function () {
|
|
if (is_admin()) return; // Already loaded in editor
|
|
|
|
$base_uri = get_template_directory_uri();
|
|
$blocks_css = get_template_directory() . '/assets/css/gutenberg-blocks.css';
|
|
if (file_exists($blocks_css)) {
|
|
wp_enqueue_style(
|
|
'aksrt-gutenberg-blocks-front',
|
|
$base_uri . '/assets/css/gutenberg-blocks.css',
|
|
[],
|
|
(string) filemtime($blocks_css)
|
|
);
|
|
}
|
|
});
|
|
|
|
// ============================================================
|
|
// Gutenberg Carousel Block 渲染回调
|
|
// ============================================================
|
|
add_action('init', function () {
|
|
if (!function_exists('register_block_type')) return;
|
|
|
|
register_block_type('aksrt/carousel', [
|
|
'render_callback' => function (array $attributes): string {
|
|
$images = $attributes['images'] ?? [];
|
|
if (empty($images)) return '';
|
|
|
|
$autoplay = !empty($attributes['autoplay']) ? 'true' : 'false';
|
|
$delay = absint($attributes['delay'] ?? 3000);
|
|
$effect = sanitize_text_field($attributes['effect'] ?? 'slide');
|
|
|
|
$slides = '';
|
|
foreach ($images as $img) {
|
|
if (empty($img['url'])) continue;
|
|
$alt = esc_attr($img['alt'] ?? '');
|
|
$url = esc_url($img['url']);
|
|
$slides .= '<div class="swiper-slide"><img src="' . $url . '" alt="' . $alt . '" loading="lazy"></div>';
|
|
}
|
|
|
|
if (empty($slides)) return '';
|
|
|
|
return '<div class="aksrt-carousel-block swiper" data-autoplay="' . $autoplay . '" data-delay="' . $delay . '" data-effect="' . $effect . '">'
|
|
. '<div class="swiper-wrapper">' . $slides . '</div>'
|
|
. '<div class="swiper-pagination"></div>'
|
|
. '<div class="swiper-button-prev"></div><div class="swiper-button-next"></div>'
|
|
. '</div>';
|
|
},
|
|
]);
|
|
});
|
|
|
|
// ============================================================
|
|
// 付费内容系统:the_content 过滤器
|
|
// ============================================================
|
|
|
|
/**
|
|
* 未付费内容:替换为付费墙。
|
|
*/
|
|
add_filter('the_content', 'aksrt_paid_content_filter', 20);
|
|
|
|
/**
|
|
* 已付费内容增强:追加图库轮播/视频播放器。
|
|
*/
|
|
add_filter('the_content', 'aksrt_paid_content_enhance', 25);
|
|
|
|
/**
|
|
* 付费文章使用统一的 single.php(不再路由到 single-aksrt_resource.php)。
|
|
*/
|
|
add_filter('single_template', function (string $template): string {
|
|
return $template;
|
|
});
|