2022-01-07 11:15:42 +08:00
|
|
|
|
<?php
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 核心函数
|
2026-10-23 12:55:41 +08:00
|
|
|
|
* @author Yongquan Yang <yangyq.net>
|
2022-01-07 11:15:42 +08:00
|
|
|
|
* @license MIT License
|
|
|
|
|
|
* @version 2020.08.04
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
2026-10-23 12:55:41 +08:00
|
|
|
|
// CDN 资源分支。
|
|
|
|
|
|
//
|
|
|
|
|
|
// ⚠️ 这里的地址必须是**能被 jsDelivr 拉取的 GitHub 仓库**(jsDelivr 只认
|
|
|
|
|
|
// github / npm / wordpress 等白名单源,不支持自建 Gitea/GitLab)。
|
|
|
|
|
|
// 本项目的主仓库在 https://code.yangyq.net/laoyang/wordpress-kratos-yang,
|
|
|
|
|
|
// 它**不能**直出给 jsDelivr(实测 404)。
|
|
|
|
|
|
// 因此:
|
|
|
|
|
|
// · 线上 g_cdn 选项默认关闭,走 get_template_directory_uri() 本地资源;
|
|
|
|
|
|
// · 若将来要启用 CDN,必须先把仓库镜像到 GitHub,再把下面的 owner/repo 换成镜像地址。
|
|
|
|
|
|
// 留一个 404 的地址比留空更危险:页面能打开、样式却全丢,排查成本极高。
|
|
|
|
|
|
if (kratos_option('g_cdn', false) && defined('YANG_THEME_CDN_REPO')) {
|
|
|
|
|
|
$asset_path = 'https://cdn.jsdelivr.net/gh/' . YANG_THEME_CDN_REPO . '@' . THEME_VERSION;
|
2022-01-07 11:15:42 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
$asset_path = get_template_directory_uri();
|
|
|
|
|
|
}
|
|
|
|
|
|
define('ASSET_PATH', $asset_path);
|
|
|
|
|
|
|
|
|
|
|
|
// 自动跳转主题设置
|
|
|
|
|
|
function init_theme()
|
|
|
|
|
|
{
|
|
|
|
|
|
global $pagenow;
|
|
|
|
|
|
if ('themes.php' == $pagenow && isset($_GET['activated'])) {
|
|
|
|
|
|
wp_redirect(admin_url('admin.php?page=kratos_options'));
|
|
|
|
|
|
exit;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
add_action('load-themes.php', 'init_theme');
|
|
|
|
|
|
|
|
|
|
|
|
// 语言国际化
|
|
|
|
|
|
function theme_languages()
|
|
|
|
|
|
{
|
|
|
|
|
|
load_theme_textdomain('kratos', get_template_directory() . '/languages');
|
|
|
|
|
|
}
|
|
|
|
|
|
add_action('after_setup_theme', 'theme_languages');
|
|
|
|
|
|
|
|
|
|
|
|
// 资源加载
|
|
|
|
|
|
function theme_autoload()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!is_admin()) {
|
|
|
|
|
|
// css
|
|
|
|
|
|
wp_enqueue_style('bootstrap', ASSET_PATH . '/assets/css/bootstrap.min.css', array(), '4.5.0');
|
|
|
|
|
|
wp_enqueue_style('kicon', ASSET_PATH . '/assets/css/iconfont.min.css', array(), THEME_VERSION);
|
|
|
|
|
|
wp_enqueue_style('layer', ASSET_PATH . '/assets/css/layer.min.css', array(), '3.1.1');
|
|
|
|
|
|
if (kratos_option('g_animate', false)) {
|
|
|
|
|
|
wp_enqueue_style('animate', ASSET_PATH . '/assets/css/animate.min.css', array(), '3.7.2');
|
|
|
|
|
|
}
|
|
|
|
|
|
wp_enqueue_style('kratos', ASSET_PATH . '/assets/css/kratos.min.css', array(), THEME_VERSION);
|
2026-10-25 10:36:29 +08:00
|
|
|
|
// 站点级公共样式:原「自定义 CSS」的内容已并入本文件(3.2.29)。
|
|
|
|
|
|
// 依赖 kratos ⇒ 一定排在主题样式之后,才压得住主题里的同名规则;
|
|
|
|
|
|
// 它自己也作为「自定义 CSS」的挂载点,保证站长临时覆盖仍排在最末。
|
|
|
|
|
|
wp_enqueue_style('kratos-site', ASSET_PATH . '/assets/css/site.css', array('kratos'), THEME_VERSION);
|
2022-01-07 11:15:42 +08:00
|
|
|
|
if (kratos_option('g_adminbar', true)) {
|
|
|
|
|
|
$admin_bar_css = "
|
|
|
|
|
|
@media screen and (max-width: 782px) {
|
|
|
|
|
|
.k-nav{
|
|
|
|
|
|
padding-top: 46px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
@media screen and (min-width: 782px) {
|
|
|
|
|
|
.k-nav{
|
|
|
|
|
|
padding-top: 32px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
";
|
|
|
|
|
|
if (current_user_can('level_10')) {
|
|
|
|
|
|
wp_add_inline_style('kratos', $admin_bar_css);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-10-23 10:35:56 +08:00
|
|
|
|
// 自定义样式:存在主题选项里(数据库),排在主题样式之后,优先级最高。
|
|
|
|
|
|
// 放选项而非主题目录,是为了让它在主题升级(升级会清空主题目录)后依然存在。
|
2026-10-25 10:36:29 +08:00
|
|
|
|
// 挂在 kratos-site 上(而非 kratos):站点公共样式 site.css 排在 kratos 之后,
|
|
|
|
|
|
// 自定义 CSS 必须继续排在 site.css 之后,否则临时覆盖会被公共样式反压。
|
2026-10-23 10:35:56 +08:00
|
|
|
|
$custom_css = yang_custom_css();
|
|
|
|
|
|
if (trim($custom_css) !== '') {
|
2026-10-25 10:36:29 +08:00
|
|
|
|
wp_add_inline_style('kratos-site', $custom_css);
|
2026-10-23 10:35:56 +08:00
|
|
|
|
}
|
2022-01-07 11:15:42 +08:00
|
|
|
|
// js
|
|
|
|
|
|
wp_deregister_script('jquery');
|
|
|
|
|
|
wp_enqueue_script('jquery', ASSET_PATH . '/assets/js/jquery.min.js', array(), '3.4.1', false);
|
|
|
|
|
|
wp_enqueue_script('bootstrap-bundle', ASSET_PATH . '/assets/js/bootstrap.bundle.min.js', array(), '4.5.0', true);
|
|
|
|
|
|
wp_enqueue_script('layer', ASSET_PATH . '/assets/js/layer.min.js', array(), '3.1.1', true);
|
|
|
|
|
|
wp_enqueue_script('kratos', ASSET_PATH . '/assets/js/kratos.min.js', array(), THEME_VERSION, true);
|
2026-10-23 10:35:56 +08:00
|
|
|
|
// 自定义脚本:同样存在主题选项里,挂在 kratos 之后(页脚输出)。
|
|
|
|
|
|
$custom_js = yang_custom_js();
|
|
|
|
|
|
if (trim($custom_js) !== '') {
|
|
|
|
|
|
wp_add_inline_script('kratos', $custom_js);
|
|
|
|
|
|
}
|
2022-01-07 11:15:42 +08:00
|
|
|
|
|
|
|
|
|
|
$data = array(
|
|
|
|
|
|
'site' => home_url(),
|
|
|
|
|
|
'directory' => get_stylesheet_directory_uri(),
|
2026-10-23 19:50:07 +08:00
|
|
|
|
'alipay' => yang_option_image('g_donate_alipay'),
|
|
|
|
|
|
'wechat' => yang_option_image('g_donate_wechat'),
|
2022-01-07 11:15:42 +08:00
|
|
|
|
'repeat' => __('您已经赞过了', 'kratos'),
|
|
|
|
|
|
'thanks' => __('感谢您的支持', 'kratos'),
|
|
|
|
|
|
'donate' => __('打赏作者', 'kratos'),
|
|
|
|
|
|
'scan' => __('扫码支付', 'kratos'),
|
|
|
|
|
|
);
|
|
|
|
|
|
wp_localize_script('kratos', 'kratos', $data);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
add_action('wp_enqueue_scripts', 'theme_autoload');
|
|
|
|
|
|
|
2026-10-23 12:55:41 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* Prism 前置兜底(修 Uncaught ReferenceError: Prism is not defined)
|
|
|
|
|
|
*
|
|
|
|
|
|
* 病因在 wp-editormd 插件,不在本主题。实测线上页面顺序:
|
|
|
|
|
|
* 668 行 Prism.plugins.autoloader.languages_path = "..."; ← 无条件赋值
|
|
|
|
|
|
* 695 行 <script src="prism-core.min.js">
|
|
|
|
|
|
* 696 行 <script src="prism-autoloader.min.js">
|
|
|
|
|
|
* 赋值语句在 Prism 加载**之前**执行 ⇒ 抛 ReferenceError,且这条赋值实际上
|
|
|
|
|
|
* 也完全没生效(真正的 languages_path 靠 footer.php 里那段带 if 防护的兜底设置)。
|
|
|
|
|
|
*
|
|
|
|
|
|
* 插件自己在页尾另一处写了 `if (window.Prism && ...)`,说明是它自己没改干净。
|
|
|
|
|
|
*
|
|
|
|
|
|
* 修法:在 <head> 极早位置(wp_head 优先级 0)先垫一个空壳 window.Prism,
|
|
|
|
|
|
* 把 plugins.autoloader 这条访问链路铺好,让插件那句赋值有地方可写,不再抛错。
|
|
|
|
|
|
*
|
|
|
|
|
|
* 关于「会不会被真实 Prism 冲掉」——已核对 prism-core.min.js 源码:
|
|
|
|
|
|
* 开头 `C={manual: u.Prism && u.Prism.manual, ...}` 只读取 manual /
|
|
|
|
|
|
* disableWorkerMessageHandler 两个开关;结尾 `global.Prism = Prism` 整体覆盖。
|
|
|
|
|
|
* 也就是说空壳对象**确实会被替换**,autoloader 也是随后由
|
|
|
|
|
|
* prism-autoloader.min.js 重新挂到新对象上的。
|
|
|
|
|
|
* 所以这里垫的对象只负责「让第 668 行不报错」,不承担持久职责 —— 正合适。
|
|
|
|
|
|
* 为避免误导后来人,这里刻意只做最小空壳,不塞任何逻辑。
|
|
|
|
|
|
*
|
|
|
|
|
|
* 用 var 而非 window.Prism= 是为了在严格模式下也能安全创建全局;
|
|
|
|
|
|
* 且仅在尚未存在时才创建,插件/主题自己先初始化时本段什么都不做。
|
|
|
|
|
|
*/
|
|
|
|
|
|
function yang_prism_early_shim()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (is_admin()) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
// 注意:这里是给浏览器执行的 JS,不是 PHP 字符串拼接出错也无妨,
|
|
|
|
|
|
// 但保持单行数组 + implode,避免 HEREDOC 里出现 <? 之类被误解析。
|
|
|
|
|
|
$lines = array(
|
|
|
|
|
|
"if (typeof window.Prism === 'undefined') {",
|
|
|
|
|
|
"\twindow.Prism = {};",
|
|
|
|
|
|
"\twindow.Prism.plugins = {};",
|
|
|
|
|
|
"\twindow.Prism.plugins.autoloader = {};",
|
|
|
|
|
|
"\twindow.Prism.plugins.autoloader.languages_path = '';",
|
|
|
|
|
|
"}",
|
|
|
|
|
|
);
|
|
|
|
|
|
echo '<script id="yang-prism-shim">' . "\n"
|
|
|
|
|
|
. implode("\n", $lines) . "\n"
|
|
|
|
|
|
. '</script>' . "\n";
|
|
|
|
|
|
}
|
|
|
|
|
|
add_action('wp_head', 'yang_prism_early_shim', 0);
|
|
|
|
|
|
|
2022-01-07 11:15:42 +08:00
|
|
|
|
// Admin Bar
|
|
|
|
|
|
if (! kratos_option('g_adminbar', true)) {
|
|
|
|
|
|
add_filter('show_admin_bar', '__return_false');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 移除自动保存、修订版本
|
|
|
|
|
|
remove_action('post_updated', 'wp_save_post_revision');
|
|
|
|
|
|
|
|
|
|
|
|
// 添加友情链接
|
|
|
|
|
|
add_filter('pre_option_link_manager_enabled', '__return_true');
|
|
|
|
|
|
|
|
|
|
|
|
// 禁用转义
|
|
|
|
|
|
$qmr_work_tags = array('the_title', 'the_excerpt', 'single_post_title', 'comment_author', 'comment_text', 'link_description', 'bloginfo', 'wp_title', 'term_description', 'category_description', 'widget_title', 'widget_text');
|
|
|
|
|
|
|
|
|
|
|
|
foreach ($qmr_work_tags as $qmr_work_tag) {
|
|
|
|
|
|
remove_filter($qmr_work_tag, 'wptexturize');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
remove_filter('the_content', 'wptexturize');
|
|
|
|
|
|
add_filter('run_wptexturize', '__return_false');
|
|
|
|
|
|
|
|
|
|
|
|
// 禁用 Emoji
|
|
|
|
|
|
add_filter('emoji_svg_url', '__return_false');
|
|
|
|
|
|
remove_action('admin_print_scripts', 'print_emoji_detection_script');
|
|
|
|
|
|
remove_action('admin_print_styles', 'print_emoji_styles');
|
|
|
|
|
|
remove_filter('the_content', 'wptexturize');
|
|
|
|
|
|
remove_filter('comment_text', 'wptexturize');
|
|
|
|
|
|
remove_action('wp_head', 'print_emoji_detection_script', 7);
|
|
|
|
|
|
remove_action('wp_print_styles', 'print_emoji_styles');
|
|
|
|
|
|
remove_action('embed_head', 'print_emoji_detection_script');
|
|
|
|
|
|
remove_filter('the_content_feed', 'wp_staticize_emoji');
|
|
|
|
|
|
remove_filter('comment_text_rss', 'wp_staticize_emoji');
|
|
|
|
|
|
remove_filter('wp_mail', 'wp_staticize_emoji_for_email');
|
|
|
|
|
|
|
|
|
|
|
|
// 禁用 Trackbacks
|
|
|
|
|
|
add_filter('xmlrpc_methods', function ($methods) {
|
|
|
|
|
|
$methods['pingback.ping'] = '__return_false';
|
|
|
|
|
|
$methods['pingback.extensions.getPingbacks'] = '__return_false';
|
|
|
|
|
|
return $methods;
|
|
|
|
|
|
});
|
|
|
|
|
|
remove_action('do_pings', 'do_all_pings', 10);
|
|
|
|
|
|
remove_action('publish_post', '_publish_post_hook', 5);
|
|
|
|
|
|
|
|
|
|
|
|
// 优化 wp_head() 内容
|
|
|
|
|
|
foreach (array('rss2_head', 'commentsrss2_head', 'rss_head', 'rdf_header', 'atom_head', 'comments_atom_head', 'opml_head', 'app_head') as $action) {
|
|
|
|
|
|
remove_action($action, 'the_generator');
|
|
|
|
|
|
}
|
|
|
|
|
|
remove_action('wp_head', 'wp_print_head_scripts', 9);
|
|
|
|
|
|
remove_action('wp_head', 'rel_canonical');
|
|
|
|
|
|
remove_action('wp_head', 'wp_generator');
|
|
|
|
|
|
remove_action('wp_head', 'rsd_link');
|
|
|
|
|
|
remove_action('wp_head', 'wlwmanifest_link');
|
|
|
|
|
|
remove_action('wp_head', 'feed_links_extra', 3);
|
|
|
|
|
|
remove_action('wp_head', 'feed_links', 2);
|
|
|
|
|
|
remove_action('wp_head', 'index_rel_link');
|
|
|
|
|
|
remove_action('wp_head', 'parent_post_rel_link', 10);
|
|
|
|
|
|
remove_action('wp_head', 'start_post_rel_link', 10);
|
|
|
|
|
|
remove_action('wp_head', 'adjacent_posts_rel_link_wp_head', 10);
|
|
|
|
|
|
remove_action('wp_head', 'wp_shortlink_wp_head', 10, 0);
|
|
|
|
|
|
remove_action('wp_head', 'rest_output_link_wp_head', 10);
|
|
|
|
|
|
remove_action('template_redirect', 'wp_shortlink_header', 11);
|
|
|
|
|
|
remove_action('template_redirect', 'rest_output_link_header', 11);
|
|
|
|
|
|
|
|
|
|
|
|
// 禁用 WordPress 拼写修正
|
|
|
|
|
|
remove_filter('the_title', 'capital_P_dangit', 11);
|
|
|
|
|
|
remove_filter('the_content', 'capital_P_dangit', 11);
|
|
|
|
|
|
remove_filter('comment_text', 'capital_P_dangit', 31);
|
|
|
|
|
|
|
|
|
|
|
|
// 禁用后台 Google Fonts
|
|
|
|
|
|
add_filter('style_loader_src', function ($href) {
|
|
|
|
|
|
if (strpos($href, "fonts.googleapis.com") === false) {
|
|
|
|
|
|
return $href;
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 禁用 Auto Embeds
|
|
|
|
|
|
remove_filter('the_content', array($GLOBALS['wp_embed'], 'autoembed'), 8);
|
|
|
|
|
|
|
|
|
|
|
|
// 替换国内 Gravatar 源
|
|
|
|
|
|
function get_https_avatar($avatar)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (kratos_option('g_gravatar', false)) {
|
|
|
|
|
|
$cdn = "gravatar.loli.net";
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$cdn = "cn.gravatar.com";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$avatar = str_replace(array("www.gravatar.com", "0.gravatar.com", "1.gravatar.com", "2.gravatar.com", "3.gravatar.com", "secure.gravatar.com"), $cdn, $avatar);
|
|
|
|
|
|
$avatar = str_replace("http://", "https://", $avatar);
|
|
|
|
|
|
return $avatar;
|
|
|
|
|
|
}
|
|
|
|
|
|
add_filter('get_avatar', 'get_https_avatar');
|
|
|
|
|
|
|
|
|
|
|
|
// 主题更新检测
|
2026-10-23 09:06:16 +08:00
|
|
|
|
//
|
|
|
|
|
|
// 更新元数据放在站点自己的域名下(/theme-update/update.json),不再单独占一个子域名。
|
|
|
|
|
|
// 好处是复用主站的证书、备案与 CDN,少维护一套站点。
|
|
|
|
|
|
// 注意:update.json 必须能被无条件公开访问。它落在 WordPress 根目录下,但主站 .htaccess
|
|
|
|
|
|
// 的重写规则带了 !-f 条件,真实存在的文件不会被送进 index.php,所以能正常直出。
|
|
|
|
|
|
// 若以后装了拦截直链的安全插件,先确认这个路径没被拦。
|
|
|
|
|
|
if (!defined('YANG_THEME_UPDATE_URL')) {
|
|
|
|
|
|
define('YANG_THEME_UPDATE_URL', 'https://yangyq.net/theme-update/update.json');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-01-07 11:15:42 +08:00
|
|
|
|
$myUpdateChecker = Puc_v4_Factory::buildUpdateChecker(
|
2026-10-23 09:06:16 +08:00
|
|
|
|
YANG_THEME_UPDATE_URL,
|
2022-01-07 11:15:42 +08:00
|
|
|
|
get_template_directory() . '/functions.php',
|
|
|
|
|
|
'Kratos_Yang'
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// 禁止生成多种尺寸图片
|
|
|
|
|
|
if (kratos_option('g_removeimgsize', false)) {
|
|
|
|
|
|
function remove_default_images($sizes)
|
|
|
|
|
|
{
|
|
|
|
|
|
unset($sizes['thumbnail']);
|
|
|
|
|
|
unset($sizes['medium']);
|
|
|
|
|
|
unset($sizes['large']);
|
|
|
|
|
|
unset($sizes['medium_large']);
|
|
|
|
|
|
return $sizes;
|
|
|
|
|
|
}
|
|
|
|
|
|
add_filter('intermediate_image_sizes_advanced', 'remove_default_images');
|
|
|
|
|
|
}
|