" . __("Argon 主题不支持 Wordpress 4.4 以下版本,请更新 Wordpress", 'argon') . ""; } function theme_slug_setup() { add_theme_support('title-tag'); add_theme_support('post-thumbnails'); load_theme_textdomain('argon', get_template_directory() . '/languages'); } add_action('after_setup_theme','theme_slug_setup'); $argon_version = !(wp_get_theme() -> Template) ? wp_get_theme() -> Version : wp_get_theme(wp_get_theme() -> Template) -> Version; $GLOBALS['theme_version'] = $argon_version; // 强制使用本地资源,避免 CDN 加载问题 $GLOBALS['assets_path'] = get_bloginfo('template_url'); //翻译 Hook function argon_locate_filter($locate){ if (substr($locate, 0, 2) == 'zh'){ if ($locate == 'zh_TW'){ return $locate; } return 'zh_CN'; } if (substr($locate, 0, 2) == 'en'){ return 'en_US'; } if (substr($locate, 0, 2) == 'ru'){ return 'ru_RU'; } return 'en_US'; } function argon_get_locate(){ if (function_exists("determine_locale")){ return argon_locate_filter(determine_locale()); } $determined_locale = get_locale(); if (is_admin()){ $determined_locale = get_user_locale(); } } function theme_locale_hook($locate, $domain){ if ($domain == 'argon'){ return argon_locate_filter($locate); } return $locate; } add_filter('theme_locale', 'theme_locale_hook', 10, 2); //更新主题版本后的兼容 $argon_last_version = get_option("argon_last_version"); if ($argon_last_version == ""){ $argon_last_version = "0.0"; } if (version_compare($argon_last_version, $GLOBALS['theme_version'], '<' )){ if (version_compare($argon_last_version, '0.940', '<')){ if (get_option('argon_mathjax_v2_enable') == 'true' && get_option('argon_mathjax_enable') != 'true'){ update_option("argon_math_render", 'mathjax2'); } if (get_option('argon_mathjax_enable') == 'true'){ update_option("argon_math_render", 'mathjax3'); } } if (version_compare($argon_last_version, '0.970', '<')){ if (get_option('argon_show_author') == 'true'){ update_option("argon_article_meta", 'time|views|comments|categories|author'); } } if (version_compare($argon_last_version, '1.1.0', '<')){ if (get_option('argon_enable_zoomify') != 'false'){ update_option("argon_enable_fancybox", 'true'); update_option("argon_enable_zoomify", 'false'); } } if (version_compare($argon_last_version, '1.3.4', '<')){ switch (get_option('argon_search_post_filter', 'post,page')){ case 'post,page': update_option("argon_enable_search_filters", 'true'); update_option("argon_search_filters_type", '*post,*page,shuoshuo'); break; case 'post,page,shuoshuo': update_option("argon_enable_search_filters", 'true'); update_option("argon_search_filters_type", '*post,*page,*shuoshuo'); break; case 'post,page,hide_shuoshuo': update_option("argon_enable_search_filters", 'true'); update_option("argon_search_filters_type", '*post,*page'); break; case 'off': default: update_option("argon_enable_search_filters", 'false'); break; } } update_option("argon_last_version", $GLOBALS['theme_version']); } //引入邮件模板系统 require_once(get_template_directory() . '/email-templates/base.php'); require_once(get_template_directory() . '/email-templates/comment-notify.php'); require_once(get_template_directory() . '/email-templates/reply-notify.php'); //检测更新 require_once(get_template_directory() . '/theme-update-checker/plugin-update-checker.php'); $argon_update_source = get_option('argon_update_source'); switch ($argon_update_source) { case "stop": break; case "fastgit": $argonThemeUpdateChecker = Puc_v4_Factory::buildUpdateChecker( 'https://api.solstice23.top/argon/info.json?source=fastgit', get_template_directory() . '/functions.php', 'argon' ); break; case "cfworker": $argonThemeUpdateChecker = Puc_v4_Factory::buildUpdateChecker( 'https://api.solstice23.top/argon/info.json?source=cfworker', get_template_directory() . '/functions.php', 'argon' ); break; case "solstice23top": $argonThemeUpdateChecker = Puc_v4_Factory::buildUpdateChecker( 'https://api.solstice23.top/argon/info.json?source=0', get_template_directory() . '/functions.php', 'argon' ); break; case "github": default: $argonThemeUpdateChecker = Puc_v4_Factory::buildUpdateChecker( 'https://raw.githubusercontent.com/solstice23/argon-theme/master/info.json', get_template_directory() . '/functions.php', 'argon' ); } //初次使用时发送安装量统计信息 (数据仅用于统计安装量) function post_analytics_info(){ if(function_exists('file_get_contents')){ $contexts = stream_context_create( array( 'http' => array( 'method'=>"GET", 'header'=>"User-Agent: ArgonTheme\r\n" ) ) ); $result = file_get_contents('http://api.solstice23.top/argon_analytics/index.php?domain=' . urlencode($_SERVER['HTTP_HOST']) . '&version='. urlencode($GLOBALS['theme_version']), false, $contexts); update_option('argon_has_inited', 'true'); return $result; }else{ update_option('argon_has_inited', 'true'); } } if (get_option('argon_has_inited') != 'true'){ post_analytics_info(); } //时区修正 if (get_option('argon_enable_timezone_fix') == 'true'){ date_default_timezone_set('UTC'); } //注册小工具 function argon_widgets_init() { register_sidebar( array( 'name' => __('左侧栏小工具', 'argon'), 'id' => 'leftbar-tools', 'description' => __( '左侧栏小工具 (如果设置会在侧栏增加一个 Tab)', 'argon'), 'before_widget' => '
', 'before_title' => '[\S\s]*?([\S\s]*?)<\/code>[\S\s]*?<\/pre>/im', $str, $codeSegments, PREG_PATTERN_ORDER);
$codeSegments = $codeSegments[3];
$codeTotal = 0;
foreach ($codeSegments as $codeSegment){
$codeLines = preg_split('/\r\n|\n|\r/', $codeSegment);
foreach ($codeLines as $line){
if (strlen(trim($str)) > 0){
$codeTotal++;
}
}
}
$str = preg_replace(
'/[\S\s]*?<\/code>/im',
'',
$str
);
$str = preg_replace(
'/[\S\s]*?<\/pre>/im',
'',
$str
);
$str = preg_replace(
'/";
}
return $content;
}
add_filter('the_content' , 'the_content_filter',20);
//使用 CDN 加速 gravatar
function gravatar_cdn($url){
$cdn = get_option('argon_gravatar_cdn', 'gravatar.pho.ink/avatar/');
$cdn = str_replace("http://", "", $cdn);
$cdn = str_replace("https://", "", $cdn);
if (substr($cdn, -1) != '/'){
$cdn .= "/";
}
$url = preg_replace("/\/\/(.*?).gravatar.com\/avatar\//", "//" . $cdn, $url);
return $url;
}
if (get_option('argon_gravatar_cdn' , '') != ''){
add_filter('get_avatar_url', 'gravatar_cdn');
}
function text_gravatar($url){
$url = preg_replace("/[?&]d[^&]+/i", "" , $url);
$url .= '&d=404';
return $url;
}
if (get_option('argon_text_gravatar', 'false') == 'true' && !is_admin()){
add_filter('get_avatar_url', 'text_gravatar');
}
//说说点赞
function get_shuoshuo_upvotes($ID){
$count_key = 'upvotes';
$count = get_post_meta($ID, $count_key, true);
if ($count==''){
delete_post_meta($ID, $count_key);
add_post_meta($ID, $count_key, '0');
$count = '0';
}
return number_format_i18n($count);
}
function set_shuoshuo_upvotes($ID){
if (get_post_type($ID) != 'shuoshuo'){
return;
}
$count_key = 'upvotes';
$count = get_post_meta($ID, $count_key, true);
if ($count==''){
delete_post_meta($ID, $count_key);
add_post_meta($ID, $count_key, '1');
} else {
update_post_meta($ID, $count_key, $count + 1);
}
}
function upvote_shuoshuo(){
header('Content-Type:application/json; charset=utf-8');
$ID = $_POST["shuoshuo_id"];
$upvotedList = isset( $_COOKIE['argon_shuoshuo_upvoted'] ) ? $_COOKIE['argon_shuoshuo_upvoted'] : '';
if (in_array($ID, explode(',', $upvotedList))){
exit(json_encode(array(
'status' => 'failed',
'msg' => __('该说说已被赞过', 'argon'),
'total_upvote' => get_shuoshuo_upvotes($ID)
)));
}
set_shuoshuo_upvotes($ID);
setcookie('argon_shuoshuo_upvoted', $upvotedList . $ID . "," , array(
'expires' => time() + 3153600000,
'path' => '/',
'secure' => is_ssl(),
'httponly' => true,
'samesite' => 'Lax'
));
exit(json_encode(array(
'ID' => $ID,
'status' => 'success',
'msg' => __('点赞成功', 'argon'),
'total_upvote' => get_shuoshuo_upvotes($ID)
)));
}
add_action('wp_ajax_upvote_shuoshuo' , 'upvote_shuoshuo');
add_action('wp_ajax_nopriv_upvote_shuoshuo' , 'upvote_shuoshuo');
//检测页面底部版权是否被修改
function alert_footer_copyright_changed(){ ?>
template . "/footer.php");
if ((strpos($footer, "github.com/solstice23/argon-theme") === false) && (strpos($footer, "solstice23.top") === false)){
add_action('admin_notices', 'alert_footer_copyright_changed');
}
}
check_footer_copyright();
//颜色计算
function rgb2hsl($R,$G,$B){
$r = $R / 255;
$g = $G / 255;
$b = $B / 255;
$var_Min = min($r, $g, $b);
$var_Max = max($r, $g, $b);
$del_Max = $var_Max - $var_Min;
$L = ($var_Max + $var_Min) / 2;
if ($del_Max == 0){
$H = 0;
$S = 0;
}else{
if ($L < 0.5){
$S = $del_Max / ($var_Max + $var_Min);
}else{
$S = $del_Max / (2 - $var_Max - $var_Min);
}
$del_R = ((($var_Max - $r) / 6) + ($del_Max / 2)) / $del_Max;
$del_G = ((($var_Max - $g) / 6) + ($del_Max / 2)) / $del_Max;
$del_B = ((($var_Max - $b) / 6) + ($del_Max / 2)) / $del_Max;
if ($r == $var_Max){
$H = $del_B - $del_G;
}
else if ($g == $var_Max){
$H = (1 / 3) + $del_R - $del_B;
}
else if ($b == $var_Max){
$H = (2 / 3) + $del_G - $del_R;
}
if ($H < 0) $H += 1;
if ($H > 1) $H -= 1;
}
return array(
'h' => $H,//0~1
's' => $S,
'l' => $L,
'H' => round($H * 360),//0~360
'S' => round($S * 100),//0~100
'L' => round($L * 100),//0~100
);
}
function Hue_2_RGB($v1,$v2,$vH){
if ($vH < 0) $vH += 1;
if ($vH > 1) $vH -= 1;
if ((6 * $vH) < 1) return ($v1 + ($v2 - $v1) * 6 * $vH);
if ((2 * $vH) < 1) return $v2;
if ((3 * $vH) < 2) return ($v1 + ($v2 - $v1) * ((2 / 3) - $vH) * 6);
return $v1;
}
function hsl2rgb($h,$s,$l){
if ($s == 0){
$r = $l;
$g = $l;
$b = $l;
}
else{
if ($l < 0.5){
$var_2 = $l * (1 + $s);
}
else{
$var_2 = ($l + $s) - ($s * $l);
}
$var_1 = 2 * $l - $var_2;
$r = Hue_2_RGB($var_1, $var_2, $h + (1 / 3));
$g = Hue_2_RGB($var_1, $var_2, $h);
$b = Hue_2_RGB($var_1, $var_2, $h - (1 / 3));
}
return array(
'R' => round($r * 255),//0~255
'G' => round($g * 255),
'B' => round($b * 255),
'r' => $r,//0~1
'g' => $g,
'b' => $b
);
}
function rgb2hex($r,$g,$b){
$hex = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
$rh = "";
$gh = "";
$bh = "";
while (strlen($rh) < 2){
$rh = $hex[$r%16] . $rh;
$r = floor($r / 16);
}
while (strlen($gh) < 2){
$gh = $hex[$g%16] . $gh;
$g = floor($g / 16);
}
while (strlen($bh) < 2){
$bh = $hex[$b%16] . $bh;
$b = floor($b / 16);
}
return "#".$rh.$gh.$bh;
}
function hexstr2rgb($hex){
//$hex: #XXXXXX
return array(
'R' => hexdec(substr($hex,1,2)),//0~255
'G' => hexdec(substr($hex,3,2)),
'B' => hexdec(substr($hex,5,2)),
'r' => hexdec(substr($hex,1,2)) / 255,//0~1
'g' => hexdec(substr($hex,3,2)) / 255,
'b' => hexdec(substr($hex,5,2)) / 255
);
}
function rgb2str($rgb){
return $rgb['R']. "," .$rgb['G']. "," .$rgb['B'];
}
function hex2str($hex){
return rgb2str(hexstr2rgb($hex));
}
function rgb2gray($R,$G,$B){
return round($R * 0.299 + $G * 0.587 + $B * 0.114);
}
function hex2gray($hex){
$rgb_array = hexstr2rgb($hex);
return rgb2gray($rgb_array['R'], $rgb_array['G'], $rgb_array['B']);
}
function checkHEX($hex){
if (strlen($hex) != 7){
return False;
}
if (substr($hex,0,1) != "#"){
return False;
}
return True;
}
//编辑文章界面新增 Meta 编辑模块
function argon_meta_box_1(){
wp_nonce_field("argon_meta_box_nonce_action", "argon_meta_box_nonce");
global $post;
?>
ID, "argon_hide_readingtime", true);?>
ID, "argon_meta_simple", true);?>
ID, "argon_first_image_as_thumbnail", true);?>
ID, "argon_show_post_outdated_info", true);?>
ID, "argon_after_post", true);?>
--none--
则不显示。", 'argon');?>
ID, "argon_custom_css", true);?>
'success'
)));
return;
}
$result = update_post_meta($post_id, $meta_key, $meta_value);
if ($result){
exit(json_encode(array(
'status' => 'success'
)));
}else{
exit(json_encode(array(
'status' => 'failed'
)));
}
}
add_action('wp_ajax_update_post_meta_ajax' , 'update_post_meta_ajax');
add_action('wp_ajax_nopriv_update_post_meta_ajax' , 'update_post_meta_ajax');
//首页显示说说
function argon_home_add_post_type_shuoshuo($query){
if (is_home() && $query -> is_main_query()){
$query -> set('post_type', array('post', 'shuoshuo'));
}
return $query;
}
if (get_option("argon_home_show_shuoshuo") == "true"){
add_action('pre_get_posts', 'argon_home_add_post_type_shuoshuo');
}
//首页隐藏特定分类文章
function argon_home_hide_categories($query){
if (is_home() && $query -> is_main_query()){
$excludeCategories = explode(",", get_option("argon_hide_categories"));
$excludeCategories = array_map(function($cat) { return -$cat; }, $excludeCategories);
$query -> set('category__not_in', $excludeCategories);
$query -> set('tag__not_in', $excludeCategories);
}
return $query;
}
if (get_option("argon_hide_categories") != ""){
add_action('pre_get_posts', 'argon_home_hide_categories');
}
//文章过时信息显示
function argon_get_post_outdated_info(){
global $post;
$post_show_outdated_info_status = strval(get_post_meta($post -> ID, 'argon_show_post_outdated_info', true));
if (get_option("argon_outdated_info_tip_type") == "toast"){
$before = "";
}else{
$before = "";
$after = "";
}
$content = get_option('argon_outdated_info_tip_content') == '' ? '本文最后更新于 %date_delta% 天前,其中的信息可能已经有所发展或是发生改变。' : get_option('argon_outdated_info_tip_content');
$delta = get_option('argon_outdated_info_days') == '' ? (-1) : get_option('argon_outdated_info_days');
if ($delta == -1){
$delta = 2147483647;
}
$post_date_delta = floor((current_time('timestamp') - get_the_time("U")) / (60 * 60 * 24));
$modify_date_delta = floor((current_time('timestamp') - get_the_modified_time("U")) / (60 * 60 * 24));
if (get_option("argon_outdated_info_time_type") == "createdtime"){
$date_delta = $post_date_delta;
}else{
$date_delta = $modify_date_delta;
}
if (($date_delta <= $delta && $post_show_outdated_info_status != 'always') || $post_show_outdated_info_status == 'never'){
return "";
}
$content = str_replace("%date_delta%", $date_delta, $content);
$content = str_replace("%modify_date_delta%", $modify_date_delta, $content);
$content = str_replace("%post_date_delta%", $post_date_delta, $content);
return $before . $content . $after;
}
//Gutenberg 编辑器区块
function argon_init_gutenberg_blocks() {
wp_register_script(
'argon-gutenberg-block-js',
$GLOBALS['assets_path'].'/gutenberg/dist/blocks.build.js',
array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-editor'),
null,
true
);
wp_register_style(
'argon-gutenberg-block-backend-css',
$GLOBALS['assets_path'].'/gutenberg/dist/blocks.editor.build.css',
array('wp-edit-blocks'),
filemtime(get_template_directory() . '/gutenberg/dist/blocks.editor.build.css')
);
register_block_type(
'argon/argon-gutenberg-block', array(
//'style' => 'argon-gutenberg-block-frontend-css',
'editor_script' => 'argon-gutenberg-block-js',
'editor_style' => 'argon-gutenberg-block-backend-css',
)
);
}
add_action('init', 'argon_init_gutenberg_blocks');
function argon_add_gutenberg_category($block_categories, $editor_context) {
if (!empty($editor_context->post)){
array_push(
$block_categories,
array(
'slug' => 'argon',
'title' => 'Argon',
'icon' => null,
)
);
}
return $block_categories;
}
add_filter('block_categories_all', 'argon_add_gutenberg_category', 10, 2);
function argon_admin_i18n_info(){
echo "";
}
add_filter('admin_head', 'argon_admin_i18n_info');
//主题文章短代码解析
function shortcode_content_preprocess($attr, $content = ""){
if ( isset( $attr['nested'] ) ? $attr['nested'] : 'true' != 'false' ){
return do_shortcode($content);
}else{
return $content;
}
}
add_shortcode('br','shortcode_br');
function shortcode_br($attr,$content=""){
return "";
}
add_shortcode('label','shortcode_label');
function shortcode_label($attr,$content=""){
$content = shortcode_content_preprocess($attr, $content);
$out = "";
return $out;
}
add_shortcode('progressbar','shortcode_progressbar');
function shortcode_progressbar($attr,$content=""){
$content = shortcode_content_preprocess($attr, $content);
$out = "";
if ($content != ""){
$out .= "" . $content . "";
}
$progress = isset( $attr['progress'] ) ? $attr['progress'] : 100;
$out .= "" . $progress . "%";
$out .= "";
return $out;
}
add_shortcode('checkbox','shortcode_checkbox');
function shortcode_checkbox($attr,$content=""){
$content = shortcode_content_preprocess($attr, $content);
$checked = isset( $attr['checked'] ) ? $attr['checked'] : 'false';
$inline = isset($attr['inline']) ? $attr['checked'] : 'false';
$out = "
";
return $out;
}
add_shortcode('alert','shortcode_alert');
function shortcode_alert($attr,$content=""){
$content = shortcode_content_preprocess($attr, $content);
$out = "";
}
$out .= "";
if (isset($attr['title'])){
$out .= "" . $attr['title'] . " ";
}
$out .= $content . "";
return $out;
}
add_shortcode('admonition','shortcode_admonition');
function shortcode_admonition($attr,$content=""){
$content = shortcode_content_preprocess($attr, $content);
$out = " ";
}
$out .= $attr['title'] . "";
}
if ($content != ''){
$out .= "" . $content . "";
}
$out .= "";
return $out;
}
add_shortcode('collapse','shortcode_collapse_block');
add_shortcode('fold','shortcode_collapse_block');
function shortcode_collapse_block($attr,$content=""){
$content = shortcode_content_preprocess($attr, $content);
$collapsed = isset( $attr['collapsed'] ) ? $attr['collapsed'] : 'true';
$show_border_left = isset( $attr['showleftborder'] ) ? $attr['showleftborder'] : 'false';
$out = " ";
}
$out .= "" . $title . "";
$out .= "";
$out .= "";
return $out;
}
add_shortcode('friendlinks','shortcode_friend_link');
function shortcode_friend_link($attr,$content=""){
$sort = isset( $attr['sort'] ) ? $attr['sort'] : 'name';
$order = isset( $attr['order'] ) ? $attr['order'] : 'ASC';
$friendlinks = get_bookmarks( array(
'orderby' => $sort ,
'order' => $order
));
$style = isset( $attr['style'] ) ? $attr['style'] : '1';
switch ($style) {
case '1':
$class = "friend-links-style1";
break;
case '1-square':
$class = "friend-links-style1 friend-links-style1-square";
break;
case '2':
$class = "friend-links-style2";
break;
case '2-big':
$class = "friend-links-style2 friend-links-style2-big";
break;
default:
$class = "friend-links-style1";
break;
}
$out = "";
foreach ($friendlinks as $friendlink){
$out .= "
";
if ($friendlink -> link_image != ''){
$out .= "
";
}
$out .= "
" . esc_html($friendlink -> link_description) . "";
$out .= "
";
}
$out .= "";
return $out;
}
add_shortcode('sfriendlinks','shortcode_friend_link_simple');
function shortcode_friend_link_simple($attr,$content=""){
$content = shortcode_content_preprocess($attr, $content);
$content = trim(strip_tags($content));
$entries = explode("\n" , $content);
$shuffle = isset( $attr['shuffle'] ) ? $attr['shuffle'] : 'false';
if ($shuffle == "true"){
mt_srand();
$group_start = 0;
foreach ($entries as $index => $value){
$now = explode("|" , $value);
if ($now[0] == 'category'){
echo ($index-1).",".$group_start." | ";
for ($i = $index - 1; $i >= $group_start; $i--){
echo $i."#";
$tar = mt_rand($group_start , $i);
$tmp = $entries[$tar];
$entries[$tar] = $entries[$i];
$entries[$i] = $tmp;
}
$group_start = $index + 1;
}
}
for ($i = count($entries) - 1; $i >= $group_start; $i--){
$tar = mt_rand($group_start , $i);
$tmp = $entries[$tar];
$entries[$tar] = $entries[$i];
$entries[$i] = $tmp;
}
}
$row_tag_open = False;
$out = "";
foreach($entries as $index => $value){
$now = explode("|" , $value);
if ($now[0] == 'category'){
if ($row_tag_open == True){
$row_tag_open = False;
$out .= "";
}
$out .= "" . $now[1] . "";
}
if ($now[0] == 'link'){
if ($row_tag_open == False){
$row_tag_open = True;
$out .= "";
}
$out .= "
";
if (!ctype_space($now[3]) && $now[3] != '' && isset($now[3])){
$out .= "" . $now[3] . "
";
}else{
/*$out .= "
";*/
}
$out .= " 前往
";
}
}
if ($row_tag_open == True){
$row_tag_open = False;
$out .= "";
}
$out .= "";
return $out;
}
add_shortcode('timeline','shortcode_timeline');
function shortcode_timeline($attr,$content=""){
$content = shortcode_content_preprocess($attr, $content);
$content = trim(strip_tags($content));
$entries = explode("\n" , $content);
$out = "";
foreach($entries as $index => $value){
$now = explode("|" , $value);
$now[0] = str_replace("/" , "" , $now[0]);
$out .= "
" . $now[0] . "
";
if ($now[1] != ''){
$out .= " " . $now[1] . "";
}
$out .= " ";
foreach($now as $index => $value){
if ($index < 2){
continue;
}
if ($index > 2){
$out .= "";
}
$out .= $value;
}
$out .= "
";
}
$out .= "";
return $out;
}
add_shortcode('hidden','shortcode_hidden');
add_shortcode('spoiler','shortcode_hidden');
function shortcode_hidden($attr,$content=""){
$content = shortcode_content_preprocess($attr, $content);
$out = "";
return $out;
}
add_shortcode('github','shortcode_github');
function shortcode_github($attr,$content=""){
$github_info_card_id = mt_rand(1000000000 , 9999999999);
$author = isset( $attr['author'] ) ? $attr['author'] : '';
$project = isset( $attr['project'] ) ? $attr['project'] : '';
$getdata = isset( $attr['getdata'] ) ? $attr['getdata'] : 'frontend';
$size = isset( $attr['size'] ) ? $attr['size'] : 'full';
$description = "";
$stars = "";
$forks = "";
if ($getdata == "backend"){
set_error_handler(function($errno, $errstr, $errfile, $errline, $errcontext) {
if (error_reporting() === 0) {
return false;
}
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
});
try{
$contexts = stream_context_create(
array(
'http' => array(
'method'=>"GET",
'header'=>"User-Agent: ArgonTheme\r\n"
)
)
);
$json = file_get_contents("https://api.github.com/repos/" . $author . "/" . $project, false, $contexts);
if (empty($json)){
throw new Exception("");
}
$json = json_decode($json);
$description = esc_html($json -> description);
if (!empty($json -> homepage)){
$description .= esc_html(" " . $json -> homepage . "");
}
$stars = $json -> stargazers_count;
$forks = $json -> forks_count;
}catch (Exception $e){
$getdata = "frontend";
}
restore_error_handler();
}
$out = "";
$out .= "";
$out .= "";
$out .= "
";
$out .= "";
return $out;
}
add_shortcode('video','shortcode_video');
function shortcode_video($attr,$content=""){
$url = isset( $attr['mp4'] ) ? $attr['mp4'] : '';
$url = isset( $attr['url'] ) ? $attr['url'] : $url;
$width = isset( $attr['width'] ) ? $attr['width'] : '';
$height = isset( $attr['height'] ) ? $attr['height'] : '';
$autoplay = isset( $attr['autoplay'] ) ? $attr['autoplay'] : 'false';
$out = "";
return $out;
}
add_shortcode('hide_reading_time','shortcode_hide_reading_time');
function shortcode_hide_reading_time($attr,$content=""){
return "";
}
add_shortcode('post_time','shortcode_post_time');
function shortcode_post_time($attr,$content=""){
$format = isset( $attr['format'] ) ? $attr['format'] : 'Y-n-d G:i:s';
return get_the_time($format);
}
add_shortcode('post_modified_time','shortcode_post_modified_time');
function shortcode_post_modified_time($attr,$content=""){
$format = isset( $attr['format'] ) ? $attr['format'] : 'Y-n-d G:i:s';
return get_the_modified_time($format);
}
add_shortcode('noshortcode','shortcode_noshortcode');
function shortcode_noshortcode($attr,$content=""){
return $content;
}
//Reference Footnote
add_shortcode('ref','shortcode_ref');
$post_references = array();
$post_reference_keys_first_index = array();
$post_reference_contents_first_index = array();
function argon_get_ref_html($content, $index, $subIndex){
$index++;
return "[" . $index . "]";
}
function shortcode_ref($attr,$content=""){
global $post_references;
global $post_reference_keys_first_index;
global $post_reference_contents_first_index;
$content = preg_replace(
'/(.*?)<\/p>/is',
'$1',
$content
);
$content = wp_kses($content, array(
'a' => array(
'href' => array(),
'title' => array(),
'target' => array()
),
'br' => array(),
'em' => array(),
'strong' => array(),
'b' => array(),
'sup' => array(),
'sub' => array(),
'small' => array()
));
if (isset($attr['id'])){
if (isset($post_reference_keys_first_index[$attr['id']])){
$post_references[$post_reference_keys_first_index[$attr['id']]]['count']++;
}else{
array_push($post_references, array('content' => $content, 'count' => 1));
$post_reference_keys_first_index[$attr['id']] = count($post_references) - 1;
}
$index = $post_reference_keys_first_index[$attr['id']];
return argon_get_ref_html($post_references[$index]['content'], $index, $post_references[$index]['count']);
}else{
if (isset($post_reference_contents_first_index[$content])){
$post_references[$post_reference_contents_first_index[$content]]['count']++;
$index = $post_reference_contents_first_index[$content];
return argon_get_ref_html($post_references[$index]['content'], $index, $post_references[$index]['count']);
}else{
array_push($post_references, array('content' => $content, 'count' => 1));
$post_reference_contents_first_index[$content] = count($post_references) - 1;
$index = count($post_references) - 1;
return argon_get_ref_html($post_references[$index]['content'], $index, $post_references[$index]['count']);
}
}
}
function get_reference_list(){
global $post_references;
if (count($post_references) == 0){
return "";
}
$res = "
";
$res .= "" . (get_option('argon_reference_list_title') == "" ? __('参考', 'argon') : get_option('argon_reference_list_title')) . "
";
$res .= "";
foreach ($post_references as $index => $ref) {
$res .= "- ";
if ($ref['count'] == 1){
$res .= "^";
}else{
$res .= "^";
for ($i = 1, $j = 'a'; $i <= $ref['count']; $i++, $j++){
$res .= "" . $j . "";
}
}
$res .= "" . $ref['content'] . "";
$res .= "";
$res .= "
";
}
$res .= "
";
$res .= "";
return $res;
}
//TinyMce 按钮
function argon_tinymce_extra_buttons(){
if(!current_user_can('edit_posts') && !current_user_can('edit_pages')){
return;
}
if(get_user_option('rich_editing') == 'true'){
add_filter('mce_external_plugins', 'argon_tinymce_add_plugin');
add_filter('mce_buttons', 'argon_tinymce_register_button');
add_editor_style($GLOBALS['assets_path'] . "/assets/tinymce_assets/tinymce_editor_codeblock.css");
}
}
add_action('init', 'argon_tinymce_extra_buttons');
function argon_tinymce_register_button($buttons){
array_push($buttons, "|", "codeblock");
array_push($buttons, "|", "label");
array_push($buttons, "", "checkbox");
array_push($buttons, "", "progressbar");
array_push($buttons, "", "alert");
array_push($buttons, "", "admonition");
array_push($buttons, "", "collapse");
array_push($buttons, "", "timeline");
array_push($buttons, "", "github");
array_push($buttons, "", "video");
array_push($buttons, "", "hiddentext");
return $buttons;
}
function argon_tinymce_add_plugin($plugins){
$plugins['codeblock'] = get_bloginfo('template_url') . '/assets/tinymce_assets/tinymce_btns.js';
$plugins['label'] = get_bloginfo('template_url') . '/assets/tinymce_assets/tinymce_btns.js';
$plugins['checkbox'] = get_bloginfo('template_url') . '/assets/tinymce_assets/tinymce_btns.js';
$plugins['progressbar'] = get_bloginfo('template_url') . '/assets/tinymce_assets/tinymce_btns.js';
$plugins['alert'] = get_bloginfo('template_url') . '/assets/tinymce_assets/tinymce_btns.js';
$plugins['admonition'] = get_bloginfo('template_url') . '/assets/tinymce_assets/tinymce_btns.js';
$plugins['collapse'] = get_bloginfo('template_url') . '/assets/tinymce_assets/tinymce_btns.js';
$plugins['timeline'] = get_bloginfo('template_url') . '/assets/tinymce_assets/tinymce_btns.js';
$plugins['github'] = get_bloginfo('template_url') . '/assets/tinymce_assets/tinymce_btns.js';
$plugins['video'] = get_bloginfo('template_url') . '/assets/tinymce_assets/tinymce_btns.js';
$plugins['hiddentext'] = get_bloginfo('template_url') . '/assets/tinymce_assets/tinymce_btns.js';
return $plugins;
}
//主题选项页面
function themeoptions_admin_menu(){
/*后台管理面板侧栏添加选项*/
add_menu_page(__("Argon 主题设置", 'argon'), __("Argon 主题选项", 'argon'), 'edit_theme_options', basename(__FILE__), 'themeoptions_page');
}
include_once(get_template_directory() . '/settings.php');
/*主题菜单*/
add_action('init', 'init_nav_menus');
function init_nav_menus(){
register_nav_menus( array(
'toolbar_menu' => __('顶部导航', 'argon'),
'leftbar_menu' => __('左侧栏菜单', 'argon'),
'leftbar_author_links' => __('左侧栏作者个人链接', 'argon'),
'leftbar_friend_links' => __('左侧栏友情链接', 'argon')
));
}
// 友情链接页面 URL 重写
add_action('init', 'argon_friend_links_rewrite');
function argon_friend_links_rewrite() {
add_rewrite_rule('^friends/?$', 'index.php?argon_friend_links=1', 'top');
}
// 主题激活或更新时刷新重写规则
add_action('after_switch_theme', 'argon_flush_rewrite_rules');
add_action('upgrader_process_complete', 'argon_flush_rewrite_rules');
function argon_flush_rewrite_rules() {
argon_friend_links_rewrite();
flush_rewrite_rules();
}
add_filter('query_vars', 'argon_friend_links_query_vars');
function argon_friend_links_query_vars($vars) {
$vars[] = 'argon_friend_links';
return $vars;
}
add_action('template_redirect', 'argon_friend_links_template');
function argon_friend_links_template() {
if (get_query_var('argon_friend_links')) {
include(get_template_directory() . '/friend-links.php');
exit;
}
}
//隐藏 admin 管理条
//show_admin_bar(false);
/*说说*/
add_action('init', 'init_shuoshuo');
function init_shuoshuo(){
$labels = array(
'name' => __('说说', 'argon'),
'singular_name' => __('说说', 'argon'),
'add_new' => __('发表说说', 'argon'),
'add_new_item' => __('发表说说', 'argon'),
'edit_item' => __('编辑说说', 'argon'),
'new_item' => __('新说说', 'argon'),
'view_item' => __('查看说说', 'argon'),
'search_items' => __('搜索说说', 'argon'),
'not_found' => __('暂无说说', 'argon'),
'not_found_in_trash' => __('没有已遗弃的说说', 'argon'),
'parent_item_colon' => '',
'menu_name' => __('说说', 'argon')
);
$args = array(
'labels' => $labels,
'public' => true,
'publicly_queryable' => true,
'show_ui' => true,
'show_in_menu' => true,
'exclude_from_search' => true,
'query_var' => true,
'rewrite' => array(
'slug' => 'shuoshuo',
'with_front' => false
),
'capability_type' => 'post',
'has_archive' => false,
'hierarchical' => false,
'menu_position' => null,
'menu_icon' => 'dashicons-format-quote',
'supports' => array('editor', 'author', 'title', 'custom-fields', 'comments')
);
register_post_type('shuoshuo', $args);
}
function argon_get_search_post_type_array(){
$search_filters_type = get_option("argon_search_filters_type", "*post,*page,shuoshuo");
$search_filters_type = explode(',', $search_filters_type);
if (!isset($_GET['post_type'])) {
$default = array_filter($search_filters_type, function ($str) { return $str[0] == '*'; });
$default = array_map(function ($str) { return substr($str, 1) ;}, $default);
return $default;
}
$search_filters_type = array_map(function ($str) { return $str[0] == '*' ? substr($str, 1) : $str; }, $search_filters_type);
$post_type = explode(',', $_GET['post_type']);
$arr = array();
foreach ($search_filters_type as $type) {
if (in_array($type, $post_type)) {
array_push($arr, $type);
}
}
if (count($arr) == 0) {
array_push($arr, 'none');
}
return $arr;
}
function search_filter($query) {
if (!$query -> is_search || is_admin()) {
return $query;
}
if (get_option('argon_enable_search_filters', 'true') == 'false'){
return $query;
}
$query -> set('post_type', argon_get_search_post_type_array());
return $query;
}
add_filter('pre_get_posts', 'search_filter');
/*恢复链接管理器*/
add_filter('pre_option_link_manager_enabled', '__return_true');
/*登录界面 CSS*/
function argon_login_page_style() {
wp_enqueue_style("argon_login_css", $GLOBALS['assets_path'] . "/login.css", null, $GLOBALS['theme_version']);
}
if (get_option('argon_enable_login_css') == 'true'){
add_action('login_head', 'argon_login_page_style');
}
// 修复 wp_mail 的 Date 头:确保使用 WordPress 时区的本地时间
add_action('phpmailer_init', function($phpmailer) {
// 使用 WordPress 的 current_time('U') 获取带时区偏移的时间戳
$local_timestamp = current_time('U'); // 返回考虑 WordPress 时区的 Unix 时间戳
$correct_date = date('D, d M Y H:i:s O', $local_timestamp);
$phpmailer->MessageDate = $correct_date;
});
// 引入二维码库 QRCode.js
function argon_enqueue_qrcode_script() {
if (is_single()) {
// 使用备用机制加载QRCode
wp_enqueue_script('resource_loader', get_template_directory_uri() . '/assets/vendor/external/resource-loader.js', array(), '1.4.0', true);
wp_add_inline_script('resource_loader', '
document.addEventListener("DOMContentLoaded", function() {
if (typeof ArgonResourceLoader !== "undefined") {
ArgonResourceLoader.smartLoad("https://cdn.jsdelivr.net/npm/qrcodejs@1.0.0/qrcode.min.js", "js")
.then(function() {
console.log("QRCode 加载成功");
})
.catch(function(error) {
console.warn("QRCode 加载失败,已使用本地备用版本");
});
}
});
');
}
}
add_action('wp_enqueue_scripts', 'argon_enqueue_qrcode_script');
// 获取 Git 版本信息
function argon_get_git_info() {
$theme_dir = get_template_directory();
$git_dir = $theme_dir . '/.git';
// 检查是否存在 .git 目录
if (!is_dir($git_dir)) {
return false;
}
$branch = '';
$commit = '';
// 获取当前分支
$head_file = $git_dir . '/HEAD';
if (file_exists($head_file)) {
$head_content = trim(file_get_contents($head_file));
if (strpos($head_content, 'ref: ') === 0) {
// 指向分支引用
$ref = substr($head_content, 5);
$branch = basename($ref);
// 获取该分支的 commit hash
$ref_file = $git_dir . '/' . $ref;
if (file_exists($ref_file)) {
$commit = substr(trim(file_get_contents($ref_file)), 0, 7);
}
} else {
// detached HEAD,直接是 commit hash
$branch = 'HEAD';
$commit = substr($head_content, 0, 7);
}
}
// 如果还没获取到 commit,尝试从 packed-refs 获取
if (empty($commit) && !empty($branch)) {
$packed_refs = $git_dir . '/packed-refs';
if (file_exists($packed_refs)) {
$refs_content = file_get_contents($packed_refs);
if (preg_match('/([a-f0-9]{40})\s+refs\/heads\/' . preg_quote($branch, '/') . '/', $refs_content, $matches)) {
$commit = substr($matches[1], 0, 7);
}
}
}
if (empty($branch) && empty($commit)) {
return false;
}
return array(
'branch' => $branch ?: 'unknown',
'commit' => $commit ?: 'unknown'
);
}
// ========== TODO 列表功能 ==========
// 获取 TODO 列表
function argon_get_todo_list() {
$todos = get_option('argon_todo_list', array());
if (!is_array($todos)) {
$todos = array();
}
return $todos;
}
// 添加 TODO 项
function argon_ajax_add_todo() {
// 验证权限
if (!current_user_can('publish_posts')) {
wp_send_json_error('无权限');
}
check_ajax_referer('argon_todo_nonce', 'nonce');
$content = sanitize_text_field($_POST['content']);
if (empty($content)) {
wp_send_json_error('内容不能为空');
}
$todos = argon_get_todo_list();
$new_todo = array(
'id' => uniqid(),
'content' => $content,
'completed' => false,
'created_at' => time()
);
array_unshift($todos, $new_todo);
update_option('argon_todo_list', $todos);
wp_send_json_success($new_todo);
}
add_action('wp_ajax_argon_add_todo', 'argon_ajax_add_todo');
// 完成 TODO 项(标记为完成,添加删除线)
function argon_ajax_complete_todo() {
if (!current_user_can('publish_posts')) {
wp_send_json_error('无权限');
}
check_ajax_referer('argon_todo_nonce', 'nonce');
$id = sanitize_text_field($_POST['id']);
$todos = argon_get_todo_list();
foreach ($todos as $key => $todo) {
if ($todo['id'] === $id) {
$todos[$key]['completed'] = true;
$todos[$key]['completed_at'] = time();
break;
}
}
update_option('argon_todo_list', $todos);
wp_send_json_success();
}
add_action('wp_ajax_argon_complete_todo', 'argon_ajax_complete_todo');
// 催促作者完成 TODO
function argon_ajax_urge_todo() {
check_ajax_referer('argon_todo_nonce', 'nonce');
$captcha_result = argon_verify_captcha('todo');
if (!$captcha_result['success']) {
wp_send_json_error($captcha_result['error']);
}
$ip = $_SERVER['REMOTE_ADDR'];
$id = sanitize_text_field($_POST['id']);
// 检查该任务今天是否已被提醒过
$task_urge_key = 'argon_todo_task_urged_' . md5($id);
if (get_transient($task_urge_key)) {
wp_send_json_error(__('该任务今天已被提醒过', 'argon'));
}
// 检查该 IP 一小时内是否已提醒过任务
$ip_urge_key = 'argon_todo_ip_urged_' . md5($ip);
if (get_transient($ip_urge_key)) {
wp_send_json_error(__('一小时内只能提醒一次', 'argon'));
}
$todos = argon_get_todo_list();
$todo_content = '';
foreach ($todos as $todo) {
if ($todo['id'] === $id) {
$todo_content = $todo['content'];
break;
}
}
if (empty($todo_content)) {
wp_send_json_error(__('TODO 不存在', 'argon'));
}
// 使用邮件模板系统发送
$admin_email = get_option('admin_email');
$vars = array(
'todo_content' => $todo_content,
'todo_id' => $id,
'urge_time' => date_i18n(get_option('date_format') . ' ' . get_option('time_format')),
);
argon_send_email($admin_email, 'todo_urge', $vars);
// 该任务今天不能再被提醒(到明天0点)
$tomorrow = strtotime('tomorrow');
set_transient($task_urge_key, true, $tomorrow - time());
// 该 IP 一小时内不能再提醒
set_transient($ip_urge_key, true, HOUR_IN_SECONDS);
// 刷新验证码
$new_captcha = '';
$captcha_type = get_option('argon_captcha_type', 'math');
if (argon_is_captcha_enabled() && $captcha_type == 'math') {
get_comment_captcha_seed(true);
$new_captcha = get_comment_captcha();
}
wp_send_json_success(array('message' => __('已提醒作者', 'argon'), 'captcha' => $new_captcha));
}
// 检查 TODO 是否已被提醒
function argon_check_todo_urged($id) {
$task_urge_key = 'argon_todo_task_urged_' . md5($id);
return get_transient($task_urge_key) ? true : false;
}
add_action('wp_ajax_argon_urge_todo', 'argon_ajax_urge_todo');
add_action('wp_ajax_nopriv_argon_urge_todo', 'argon_ajax_urge_todo');
// 删除 TODO 项
function argon_ajax_delete_todo() {
if (!current_user_can('publish_posts')) {
wp_send_json_error('无权限');
}
check_ajax_referer('argon_todo_nonce', 'nonce');
$id = sanitize_text_field($_POST['id']);
$todos = argon_get_todo_list();
foreach ($todos as $key => $todo) {
if ($todo['id'] === $id) {
unset($todos[$key]);
break;
}
}
$todos = array_values($todos);
update_option('argon_todo_list', $todos);
wp_send_json_success();
}
add_action('wp_ajax_argon_delete_todo', 'argon_ajax_delete_todo');
// ========== 多邻国连胜功能 ==========
// 获取多邻国连胜数据
function argon_get_duolingo_streak() {
$data = argon_get_duolingo_data();
return $data ? $data['streak'] : false;
}
// 获取多邻国完整数据(包含今日是否完成)
function argon_get_duolingo_data() {
$username = get_option('argon_duolingo_username', '');
if (empty($username)) {
return false;
}
$cache_key = 'argon_duolingo_v2_' . md5($username);
$cached = get_transient($cache_key);
// 如果有缓存
if ($cached !== false) {
// 如果今日已完成,直接返回缓存(到第二天0点前不会变)
if (isset($cached['today']) && $cached['today']) {
// 检查是否还是同一天
if (isset($cached['date']) && $cached['date'] === date('Y-m-d')) {
return $cached;
}
// 已经是新的一天,需要重新请求
} else {
// 未完成时使用缓存(15分钟内)
return $cached;
}
}
$url = 'https://www.duolingo.com/2017-06-30/users?username=' . urlencode($username) . '&fields=streak,streakData%7BcurrentStreak,previousStreak%7D%7D';
$response = wp_remote_get($url, array(
'timeout' => 10,
'headers' => array(
'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
)
));
if (is_wp_error($response)) {
// 请求失败时返回旧缓存(如果有)
return $cached !== false ? $cached : false;
}
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
if (empty($data['users'][0])) {
return $cached !== false ? $cached : false;
}
$user = $data['users'][0];
$today = date('Y-m-d');
// 获取连胜数
$streak = max(
isset($user['streak']) ? intval($user['streak']) : 0,
isset($user['streakData']['currentStreak']['length']) ? intval($user['streakData']['currentStreak']['length']) : 0,
isset($user['streakData']['previousStreak']['length']) ? intval($user['streakData']['previousStreak']['length']) : 0
);
// 判断今日是否完成(通过 currentStreak 的 endDate)
$end_date = isset($user['streakData']['currentStreak']['endDate']) ? $user['streakData']['currentStreak']['endDate'] : '';
$is_today_done = ($end_date === $today);
$result = array(
'streak' => $streak,
'today' => $is_today_done,
'date' => $today
);
// 如果今日已完成,缓存到明天0点;否则缓存15分钟
if ($is_today_done) {
$tomorrow = strtotime('tomorrow');
$seconds_until_tomorrow = $tomorrow - time();
set_transient($cache_key, $result, $seconds_until_tomorrow);
} else {
set_transient($cache_key, $result, 15 * MINUTE_IN_SECONDS);
}
return $result;
}
// ========== 友情链接功能 ==========
/**
* 获取友情链接列表
* @param string $status 状态筛选: all/approved/pending/rejected
* @return array 按分类分组的链接数组
*/
function argon_get_friend_links($status = 'all') {
$links = get_option('argon_friend_links', array());
if (empty($links)) {
return array();
}
// 自动去重(按域名)
$seen_hosts = array();
$unique_links = array();
foreach ($links as $link) {
$host = parse_url($link['url'], PHP_URL_HOST);
$host = preg_replace('/^www\./', '', $host);
if (!isset($seen_hosts[$host])) {
$seen_hosts[$host] = true;
$unique_links[] = $link;
}
}
// 如果有重复,更新数据库
if (count($unique_links) < count($links)) {
update_option('argon_friend_links', $unique_links);
}
$links = $unique_links;
// 状态筛选
if ($status !== 'all') {
$links = array_filter($links, function($link) use ($status) {
$link_status = isset($link['status']) ? $link['status'] : 'approved';
return $link_status === $status;
});
}
// 按分类分组
$grouped = array();
foreach ($links as $link) {
$category = isset($link['category']) ? $link['category'] : '';
if (!isset($grouped[$category])) {
$grouped[$category] = array();
}
$grouped[$category][] = $link;
}
return $grouped;
}
/**
* 获取友链原始列表(不分组)
*/
function argon_get_friend_links_raw($status = 'all') {
$links = get_option('argon_friend_links', array());
if ($status === 'all') {
return $links;
}
return array_filter($links, function($link) use ($status) {
$link_status = isset($link['status']) ? $link['status'] : 'approved';
return $link_status === $status;
});
}
/**
* 检查友链是否重复
*/
function argon_check_duplicate_link($url, $exclude_id = null) {
$links = get_option('argon_friend_links', array());
$new_host = parse_url($url, PHP_URL_HOST);
$new_host = preg_replace('/^www\./', '', $new_host);
foreach ($links as $link) {
if ($exclude_id && $link['id'] === $exclude_id) continue;
$existing_host = parse_url($link['url'], PHP_URL_HOST);
$existing_host = preg_replace('/^www\./', '', $existing_host);
if ($existing_host === $new_host) {
return $link;
}
}
return false;
}
/**
* 通过代理获取网站信息(防止源站 IP 泄露)
* 注意:由于服务器在国内,代理服务可能不可用,建议使用浏览器端获取
*/
function argon_fetch_site_info_proxy($url) {
// 直接使用本地获取(浏览器端已处理)
return argon_fetch_site_info($url);
}
/**
* 自动获取网站信息
*/
function argon_fetch_site_info($url) {
$info = array(
'favicon' => '',
'title' => '',
'description' => '',
'author_avatar' => '',
'is_wordpress' => false,
'accessible' => false,
'blocked_by_waf' => false,
'error_reason' => ''
);
// 模拟真实浏览器请求,避免被识别为爬虫
$browser_headers = array(
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
'Accept-Language' => 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'Accept-Encoding' => 'gzip, deflate',
'Cache-Control' => 'no-cache',
'Pragma' => 'no-cache',
'Sec-Ch-Ua' => '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
'Sec-Ch-Ua-Mobile' => '?0',
'Sec-Ch-Ua-Platform' => '"Windows"',
'Sec-Fetch-Dest' => 'document',
'Sec-Fetch-Mode' => 'navigate',
'Sec-Fetch-Site' => 'none',
'Sec-Fetch-User' => '?1',
'Upgrade-Insecure-Requests' => '1',
'Referer' => $url
);
$response = wp_remote_get($url, array(
'timeout' => 20,
'sslverify' => false,
'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'headers' => $browser_headers,
'redirection' => 5
));
if (is_wp_error($response)) {
$info['error_reason'] = $response->get_error_message();
return $info;
}
$code = wp_remote_retrieve_response_code($response);
$body = wp_remote_retrieve_body($response);
// 检测 WAF 拦截(雷池、云锁、安全狗等)
$waf_patterns = array(
'safeline' => array('safeline', '雷池'),
'yunsuo' => array('yunsuo', '云锁'),
'safedog' => array('safedog', '安全狗'),
'cloudflare' => array('cloudflare', 'cf-ray'),
'generic' => array('access denied', 'forbidden', '访问被拒绝', '请求被拦截', 'blocked', 'waf')
);
$body_lower = strtolower($body);
foreach ($waf_patterns as $waf_name => $patterns) {
foreach ($patterns as $pattern) {
if (strpos($body_lower, strtolower($pattern)) !== false && $code >= 400) {
$info['blocked_by_waf'] = true;
$info['error_reason'] = sprintf(__('被 WAF 拦截(%s)', 'argon'), $waf_name);
break 2;
}
}
}
// 检测 403/503 等状态码
if ($code == 403) {
$info['blocked_by_waf'] = true;
$info['error_reason'] = __('访问被拒绝 (403)', 'argon');
} elseif ($code == 503) {
$info['error_reason'] = __('服务暂时不可用 (503)', 'argon');
}
$info['accessible'] = ($code >= 200 && $code < 400);
if (!$info['accessible']) {
return $info;
}
$host = parse_url($url, PHP_URL_HOST);
$scheme = parse_url($url, PHP_URL_SCHEME) ?: 'https';
$base_url = $scheme . '://' . $host;
// 检测是否为 WordPress(多种方式)
$wp_indicators = array(
'wp-content', 'wp-includes', 'wordpress', 'wp-json',
'generator" content="WordPress', 'powered by WordPress'
);
foreach ($wp_indicators as $indicator) {
if (stripos($body, $indicator) !== false) {
$info['is_wordpress'] = true;
break;
}
}
// 如果页面检测不到,尝试访问 wp-json 端点确认
if (!$info['is_wordpress']) {
$wp_json_url = $base_url . '/wp-json/';
$wp_check = wp_remote_head($wp_json_url, array(
'timeout' => 5,
'sslverify' => false,
'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
));
if (!is_wp_error($wp_check) && wp_remote_retrieve_response_code($wp_check) == 200) {
$info['is_wordpress'] = true;
}
}
// 获取标题
if (preg_match('/]*>([^<]+)<\/title>/i', $body, $matches)) {
$info['title'] = trim(html_entity_decode($matches[1], ENT_QUOTES, 'UTF-8'));
}
// 获取描述
if (preg_match('/]+name=["\']description["\'][^>]+content=["\']([^"\']+)["\'][^>]*>/i', $body, $matches)) {
$info['description'] = trim(html_entity_decode($matches[1], ENT_QUOTES, 'UTF-8'));
} elseif (preg_match('/]+content=["\']([^"\']+)["\'][^>]+name=["\']description["\'][^>]*>/i', $body, $matches)) {
$info['description'] = trim(html_entity_decode($matches[1], ENT_QUOTES, 'UTF-8'));
}
// 获取 favicon
$favicon_patterns = array(
'/]+rel=["\'](?:shortcut )?icon["\'][^>]+href=["\']([^"\']+)["\'][^>]*>/i',
'/]+href=["\']([^"\']+)["\'][^>]+rel=["\'](?:shortcut )?icon["\'][^>]*>/i',
'/]+rel=["\']apple-touch-icon["\'][^>]+href=["\']([^"\']+)["\'][^>]*>/i'
);
foreach ($favicon_patterns as $pattern) {
if (preg_match($pattern, $body, $matches)) {
$info['favicon'] = argon_normalize_url($matches[1], $scheme, $host);
break;
}
}
// 如果没找到 favicon,尝试默认路径
if (empty($info['favicon'])) {
$default_favicon = $base_url . '/favicon.ico';
$favicon_check = wp_remote_head($default_favicon, array('timeout' => 5, 'sslverify' => false, 'user-agent' => 'Mozilla/5.0'));
if (!is_wp_error($favicon_check) && wp_remote_retrieve_response_code($favicon_check) == 200) {
$info['favicon'] = $default_favicon;
}
}
// ========== 获取作者头像 ==========
if ($info['is_wordpress']) {
// WordPress 站点:通过 REST API 获取作者头像
$api_url = rtrim($url, '/') . '/wp-json/wp/v2/users?per_page=1';
$api_response = wp_remote_get($api_url, array(
'timeout' => 15,
'sslverify' => false,
'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
));
if (!is_wp_error($api_response)) {
$api_code = wp_remote_retrieve_response_code($api_response);
$api_body = wp_remote_retrieve_body($api_response);
if ($api_code == 200) {
$users = json_decode($api_body, true);
if (is_array($users) && !empty($users[0]['avatar_urls'])) {
$avatar_urls = $users[0]['avatar_urls'];
// 优先取 96px
$avatar_url = $avatar_urls['96'] ?? $avatar_urls['48'] ?? $avatar_urls['24'] ?? '';
if (!empty($avatar_url)) {
// 检查是否为默认头像(Gravatar/Weavatar/Cravatar 带 d=xxx 参数)
$is_default = preg_match('/[?&](d|default)=(mm|mp|identicon|monsterid|wavatar|retro|robohash|blank)/i', $avatar_url);
if (!$is_default) {
// 处理协议相对 URL
if (strpos($avatar_url, '//') === 0) {
$avatar_url = $scheme . ':' . $avatar_url;
}
$info['author_avatar'] = $avatar_url;
}
}
}
}
}
// 如果 API 没有获取到头像,尝试从页面中提取
if (empty($info['author_avatar'])) {
$avatar_patterns = array(
'/
]+class=["\'][^"\']*(?:avatar|author-avatar|blogger-avatar|profile-img)[^"\']*["\'][^>]+src=["\']([^"\']+)["\'][^>]*>/i',
'/
]+src=["\']([^"\']+)["\'][^>]+class=["\'][^"\']*(?:avatar|author-avatar|blogger-avatar|profile-img)[^"\']*["\'][^>]*>/i'
);
foreach ($avatar_patterns as $pattern) {
if (preg_match($pattern, $body, $matches)) {
$info['author_avatar'] = argon_normalize_url($matches[1], $scheme, $host);
break;
}
}
}
// 仍然没有,尝试常见头像路径
if (empty($info['author_avatar'])) {
$common_avatar_paths = array('/avatar.png', '/avatar.jpg', '/avatar.webp');
foreach ($common_avatar_paths as $path) {
$avatar_url = $base_url . $path;
$check = wp_remote_head($avatar_url, array('timeout' => 3, 'sslverify' => false));
if (!is_wp_error($check) && wp_remote_retrieve_response_code($check) == 200) {
$info['author_avatar'] = $avatar_url;
break;
}
}
}
} else {
// 非 WordPress 站点:尝试多种方式获取头像
// 1. 尝试获取 Open Graph 图片(og:image)
if (preg_match('/]+property=["\']og:image["\'][^>]+content=["\']([^"\']+)["\'][^>]*>/i', $body, $matches)) {
$og_image = argon_normalize_url($matches[1], $scheme, $host);
// 检查是否为有效图片
$img_check = wp_remote_head($og_image, array('timeout' => 5, 'sslverify' => false));
if (!is_wp_error($img_check) && wp_remote_retrieve_response_code($img_check) == 200) {
$info['author_avatar'] = $og_image;
}
}
// 2. 尝试常见的头像路径
if (empty($info['author_avatar'])) {
$common_avatar_paths = array(
'/avatar.png', '/avatar.jpg', '/avatar.webp',
'/img/avatar.png', '/img/avatar.jpg',
'/images/avatar.png', '/images/avatar.jpg',
'/assets/avatar.png', '/assets/img/avatar.png'
);
foreach ($common_avatar_paths as $path) {
$avatar_url = $base_url . $path;
$check = wp_remote_head($avatar_url, array('timeout' => 3, 'sslverify' => false));
if (!is_wp_error($check) && wp_remote_retrieve_response_code($check) == 200) {
$info['author_avatar'] = $avatar_url;
break;
}
}
}
// 3. 尝试从页面中提取作者头像(常见的 class 名)
if (empty($info['author_avatar'])) {
$avatar_patterns = array(
'/
]+class=["\'][^"\']*(?:avatar|author-avatar|blogger-avatar|profile-img)[^"\']*["\'][^>]+src=["\']([^"\']+)["\'][^>]*>/i',
'/
]+src=["\']([^"\']+)["\'][^>]+class=["\'][^"\']*(?:avatar|author-avatar|blogger-avatar|profile-img)[^"\']*["\'][^>]*>/i'
);
foreach ($avatar_patterns as $pattern) {
if (preg_match($pattern, $body, $matches)) {
$info['author_avatar'] = argon_normalize_url($matches[1], $scheme, $host);
break;
}
}
}
}
return $info;
}
/**
* 规范化 URL(处理相对路径)
*/
function argon_normalize_url($url, $scheme, $host) {
if (strpos($url, '//') === 0) {
return $scheme . ':' . $url;
} elseif (strpos($url, '/') === 0) {
return $scheme . '://' . $host . $url;
} elseif (strpos($url, 'http') !== 0) {
return $scheme . '://' . $host . '/' . $url;
}
return $url;
}
/**
* 去重友链数据
*/
function argon_deduplicate_friend_links() {
$links = get_option('argon_friend_links', array());
$seen_hosts = array();
$unique_links = array();
$removed = 0;
foreach ($links as $link) {
$host = parse_url($link['url'], PHP_URL_HOST);
$host = preg_replace('/^www\./', '', $host);
if (!isset($seen_hosts[$host])) {
$seen_hosts[$host] = true;
$unique_links[] = $link;
} else {
$removed++;
}
}
if ($removed > 0) {
update_option('argon_friend_links', $unique_links);
}
return $removed;
}
/**
* 添加友情链接(带智能功能)
*/
function argon_add_friend_link($data) {
$links = get_option('argon_friend_links', array());
$url = esc_url_raw($data['url']);
// 检查重复
$duplicate = argon_check_duplicate_link($url);
if ($duplicate) {
return false; // 返回 false 表示重复
}
// 自动获取网站信息
$site_info = array();
if (empty($data['avatar']) || empty($data['description'])) {
$site_info = argon_fetch_site_info($url);
}
$new_link = array(
'id' => uniqid('fl_'),
'name' => sanitize_text_field($data['name']),
'url' => $url,
'avatar' => !empty($data['avatar']) ? esc_url_raw($data['avatar']) : (!empty($site_info['favicon']) ? $site_info['favicon'] : (!empty($site_info['author_avatar']) ? $site_info['author_avatar'] : '')),
'description' => !empty($data['description']) ? sanitize_text_field($data['description']) : (!empty($site_info['description']) ? mb_substr($site_info['description'], 0, 100) : ''),
'category' => isset($data['category']) ? sanitize_text_field($data['category']) : '',
'email' => isset($data['email']) ? sanitize_email($data['email']) : '',
'message' => isset($data['message']) ? sanitize_textarea_field($data['message']) : '',
'status' => isset($data['status']) ? $data['status'] : 'approved',
'verified' => false,
'is_wordpress' => !empty($site_info['is_wordpress']),
'accessible' => !empty($site_info['accessible']),
'last_check' => time(),
'created_at' => time()
);
$links[] = $new_link;
update_option('argon_friend_links', $links);
return $new_link['id'];
}
/**
* 更新友情链接
*/
function argon_update_friend_link($id, $data) {
$links = get_option('argon_friend_links', array());
foreach ($links as $key => $link) {
if ($link['id'] === $id) {
foreach ($data as $field => $value) {
if ($field === 'url' || $field === 'avatar') {
$links[$key][$field] = esc_url_raw($value);
} elseif ($field === 'email') {
$links[$key][$field] = sanitize_email($value);
} elseif ($field !== 'id' && $field !== 'created_at') {
$links[$key][$field] = is_bool($value) ? $value : sanitize_text_field($value);
}
}
$links[$key]['updated_at'] = time();
break;
}
}
update_option('argon_friend_links', $links);
return true;
}
/**
* 删除友情链接
*/
function argon_delete_friend_link($id) {
$links = get_option('argon_friend_links', array());
foreach ($links as $key => $link) {
if ($link['id'] === $id) {
unset($links[$key]);
break;
}
}
update_option('argon_friend_links', array_values($links));
return true;
}
/**
* 获取单个友链
*/
function argon_get_friend_link($id) {
$links = get_option('argon_friend_links', array());
foreach ($links as $link) {
if ($link['id'] === $id) {
return $link;
}
}
return null;
}
/**
* 处理友链申请 V2(支持主标题/副标题)
* 用户填写的作为主标题,自动获取的作为副标题
*/
function argon_handle_link_application_v2($post_data) {
return argon_handle_link_application_v3($post_data);
}
/**
* 处理友链申请 V3(服务器端获取网站信息)
*/
function argon_handle_link_application_v3($post_data) {
// 验证 nonce
if (!isset($post_data['argon_link_apply_nonce']) ||
!wp_verify_nonce($post_data['argon_link_apply_nonce'], 'argon_link_apply')) {
return array('success' => false, 'message' => __('安全验证失败,请刷新页面重试', 'argon'));
}
// 验证码检查
if (function_exists('argon_is_captcha_enabled') && argon_is_captcha_enabled()) {
$captcha_result = argon_verify_captcha('flink');
if (!$captcha_result['success']) {
return array('success' => false, 'message' => $captcha_result['error']);
}
}
$url = isset($post_data['apply_url']) ? trim($post_data['apply_url']) : '';
if (empty($url)) {
return array('success' => false, 'message' => __('网站地址为必填项', 'argon'));
}
// 自动补全 URL 协议
if (!preg_match('/^https?:\/\//i', $url)) {
$url = 'https://' . $url;
}
// 检查 URL 格式
if (!filter_var($url, FILTER_VALIDATE_URL)) {
return array('success' => false, 'message' => __('请输入有效的网站地址', 'argon'));
}
// 检查是否重复
$duplicate = argon_check_duplicate_link($url);
if ($duplicate) {
$status_text = ($duplicate['status'] === 'pending') ? __('正在审核中', 'argon') : __('已在友链列表中', 'argon');
return array('success' => false, 'message' => sprintf(__('该网站(%s)%s', 'argon'), $duplicate['name'], $status_text));
}
// 服务器端获取网站信息
$site_info = argon_fetch_site_info($url);
// 获取用户填写的内容
$user_name = isset($post_data['apply_name']) ? trim($post_data['apply_name']) : '';
$user_avatar = isset($post_data['apply_avatar']) ? trim($post_data['apply_avatar']) : '';
$user_desc = isset($post_data['apply_description']) ? trim($post_data['apply_description']) : '';
// 确定最终使用的值
$final_name = !empty($user_name) ? $user_name : $site_info['title'];
$display_name = '';
// 如果用户填了名称,且自动获取的标题与用户填的相似度低,则标题作为副标题
if (!empty($user_name) && !empty($site_info['title'])) {
$similarity = argon_string_similarity($user_name, $site_info['title']);
if ($similarity < 0.6) { // 相似度低于60%时显示副标题
$display_name = $site_info['title'];
}
}
// 头像优先级:用户填写 > 作者头像 > favicon
$final_avatar = $user_avatar;
if (empty($final_avatar) && !empty($site_info['author_avatar'])) {
$final_avatar = $site_info['author_avatar'];
}
if (empty($final_avatar) && !empty($site_info['favicon'])) {
$final_avatar = $site_info['favicon'];
}
// 保存用户是否自定义了头像(用于后续更新时判断)
$user_custom_avatar = !empty($user_avatar);
// 描述
$final_desc = !empty($user_desc) ? $user_desc : '';
$auto_description = $site_info['description'];
if (empty($final_name)) {
return array('success' => false, 'message' => __('无法获取网站标题,请手动填写网站名称', 'argon'));
}
$accessible = $site_info['accessible'];
// 获取申请者填写的友链页面
$links_page = isset($post_data['apply_links_page']) ? esc_url_raw($post_data['apply_links_page']) : '';
// 如果填写了友链页面,检测是否已添加本站链接
$has_backlink = null;
$auto_approved = false;
$status = 'pending';
if (!empty($links_page)) {
$has_backlink = argon_check_backlink($links_page);
if ($has_backlink) {
$status = 'approved';
$auto_approved = true;
}
}
// 添加友链
$links = get_option('argon_friend_links', array());
$new_link = array(
'id' => uniqid('fl_'),
'name' => sanitize_text_field($final_name),
'display_name' => sanitize_text_field($display_name),
'url' => esc_url_raw($url),
'links_page' => $links_page,
'avatar' => $final_avatar,
'user_avatar' => $user_custom_avatar,
'author_avatar' => $site_info['author_avatar'],
'favicon' => $site_info['favicon'],
'description' => sanitize_text_field($final_desc),
'auto_description' => sanitize_text_field($auto_description),
'category' => '',
'email' => isset($post_data['apply_email']) ? sanitize_email($post_data['apply_email']) : '',
'status' => $status,
'has_backlink' => $has_backlink,
'auto_approved' => $auto_approved,
'accessible' => $accessible,
'blocked_by_waf' => $site_info['blocked_by_waf'],
'is_wordpress' => $site_info['is_wordpress'],
'last_check' => time(),
'created_at' => time()
);
$links[] = $new_link;
update_option('argon_friend_links', $links);
if ($auto_approved) {
return array('success' => true, 'message' => __('检测到您已添加本站链接,友链已自动通过!', 'argon'));
}
// 发送通知邮件给管理员
if (function_exists('argon_notify_admin_new_link_application')) {
argon_notify_admin_new_link_application($new_link['id']);
}
return array('success' => true, 'message' => __('申请已提交,请等待审核。', 'argon'));
}
/**
* 计算两个字符串的相似度
*/
function argon_string_similarity($str1, $str2) {
$str1 = mb_strtolower(trim($str1));
$str2 = mb_strtolower(trim($str2));
if ($str1 === $str2) return 1.0;
if (empty($str1) || empty($str2)) return 0.0;
// 如果一个包含另一个
if (mb_strpos($str1, $str2) !== false || mb_strpos($str2, $str1) !== false) {
return 0.8;
}
// 使用 similar_text 计算相似度
similar_text($str1, $str2, $percent);
return $percent / 100;
}
/**
* 检测网站是否可访问
*/
function argon_check_site_accessible($url) {
$response = wp_remote_head($url, array(
'timeout' => 10,
'sslverify' => false,
'user-agent' => 'Mozilla/5.0 (compatible; Argon Friend Link Checker)'
));
if (is_wp_error($response)) {
return false;
}
$code = wp_remote_retrieve_response_code($response);
return ($code >= 200 && $code < 400);
}
/**
* 处理友链申请(旧版本,保留兼容)
*/
function argon_handle_link_application($post_data) {
return argon_handle_link_application_v2($post_data);
}
/**
* 检查指定页面是否有本站链接
*
* @param string $links_page 对方的友链页面地址
* @return bool 是否找到本站链接
*/
function argon_check_backlink($links_page) {
if (empty($links_page)) {
return null;
}
$site_url = home_url();
$site_host = parse_url($site_url, PHP_URL_HOST);
$site_host_nowww = preg_replace('/^www\./i', '', $site_host);
$response = wp_remote_get($links_page, array(
'timeout' => 15,
'sslverify' => false,
'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
));
if (is_wp_error($response)) {
return false;
}
$body = wp_remote_retrieve_body($response);
if (empty($body)) {
return false;
}
// 提取所有 标签的 href,检查是否指向本站
if (preg_match_all('/]+href=["\']([^"\']+)["\'][^>]*>/i', $body, $matches)) {
foreach ($matches[1] as $href) {
$href_host = parse_url($href, PHP_URL_HOST);
if ($href_host) {
$href_host_nowww = preg_replace('/^www\./i', '', $href_host);
if (strcasecmp($href_host_nowww, $site_host_nowww) === 0) {
return true;
}
}
}
}
return false;
}
/**
* 验证所有友链的互链状态
*/
function argon_verify_all_friend_links() {
$links = argon_get_friend_links_raw('approved');
$results = array();
foreach ($links as $link) {
$has_backlink = argon_check_backlink($link['url']);
argon_update_friend_link($link['id'], array(
'verified' => $has_backlink,
'last_check' => time()
));
$results[$link['id']] = $has_backlink;
}
return $results;
}
/**
* 通知管理员有新的友链申请
*/
function argon_notify_admin_new_link_application($link_id) {
$link = argon_get_friend_link($link_id);
if (!$link) return;
$admin_email = get_option('admin_email');
$subject = sprintf(__('[%s] 新的友链申请', 'argon'), get_bloginfo('name'));
$message = sprintf(__("收到新的友链申请:\n\n网站名称:%s\n网站地址:%s\n描述:%s\n邮箱:%s\n留言:%s\n\n请前往后台审核。", 'argon'),
$link['name'],
$link['url'],
$link['description'],
$link['email'],
$link['message']
);
wp_mail($admin_email, $subject, $message);
}
/**
* AJAX: 管理友情链接
*/
function argon_ajax_manage_friend_link() {
if (!current_user_can('manage_options')) {
wp_send_json_error('权限不足');
}
if (!wp_verify_nonce($_POST['nonce'], 'argon_friend_link_nonce')) {
wp_send_json_error('安全验证失败');
}
$action = isset($_POST['link_action']) ? $_POST['link_action'] : '';
$id = isset($_POST['id']) ? sanitize_text_field($_POST['id']) : '';
switch ($action) {
case 'add':
$link_id = argon_add_friend_link(array(
'name' => $_POST['name'],
'url' => $_POST['url'],
'avatar' => isset($_POST['avatar']) ? $_POST['avatar'] : '',
'description' => isset($_POST['description']) ? $_POST['description'] : '',
'category' => isset($_POST['category']) ? $_POST['category'] : '',
'status' => 'approved'
));
wp_send_json_success(array('id' => $link_id));
break;
case 'update':
if (empty($id)) wp_send_json_error('ID 不能为空');
$update_data = array();
foreach (array('name', 'url', 'avatar', 'description', 'category', 'status') as $field) {
if (isset($_POST[$field])) {
$update_data[$field] = $_POST[$field];
}
}
argon_update_friend_link($id, $update_data);
wp_send_json_success();
break;
case 'delete':
if (empty($id)) wp_send_json_error('ID 不能为空');
argon_delete_friend_link($id);
wp_send_json_success();
break;
case 'approve':
if (empty($id)) wp_send_json_error('ID 不能为空');
argon_update_friend_link($id, array('status' => 'approved'));
// 发送通知邮件
$link = argon_get_friend_link($id);
if ($link && !empty($link['email'])) {
$subject = sprintf(__('[%s] 您的友链申请已通过', 'argon'), get_bloginfo('name'));
$message = sprintf(__("您好!\n\n您申请的友链已通过审核。\n\n网站名称:%s\n网站地址:%s\n\n感谢您的支持!", 'argon'),
$link['name'], $link['url']);
wp_mail($link['email'], $subject, $message);
}
wp_send_json_success();
break;
case 'reject':
if (empty($id)) wp_send_json_error('ID 不能为空');
argon_update_friend_link($id, array('status' => 'rejected'));
wp_send_json_success();
break;
case 'verify':
if (empty($id)) {
// 验证所有
$results = argon_verify_all_friend_links();
wp_send_json_success(array('results' => $results));
} else {
$link = argon_get_friend_link($id);
if (!$link) wp_send_json_error('链接不存在');
$has_backlink = argon_check_backlink($link['url']);
argon_update_friend_link($id, array('verified' => $has_backlink, 'last_check' => time()));
wp_send_json_success(array('verified' => $has_backlink));
}
break;
case 'check_access':
$results = argon_check_all_links_accessibility();
wp_send_json_success(array('results' => $results));
break;
default:
wp_send_json_error('未知操作');
}
}
add_action('wp_ajax_argon_manage_friend_link', 'argon_ajax_manage_friend_link');
// 兼容旧的 AJAX 接口
add_action('wp_ajax_argon_add_friend_link', function() {
$_POST['link_action'] = 'add';
argon_ajax_manage_friend_link();
});
add_action('wp_ajax_argon_delete_friend_link', function() {
$_POST['link_action'] = 'delete';
argon_ajax_manage_friend_link();
});
// ========== 友链调试和高级功能 ==========
/**
* 修复旧数据状态
*/
add_action('wp_ajax_argon_debug_fix_link_status', function() {
if (!current_user_can('manage_options')) wp_send_json_error('权限不足');
if (!wp_verify_nonce($_POST['nonce'], 'argon_debug')) wp_send_json_error('安全验证失败');
$links = get_option('argon_friend_links', array());
$fixed = 0;
foreach ($links as $key => $link) {
if (!isset($link['status']) || empty($link['status'])) {
$links[$key]['status'] = 'approved';
$fixed++;
}
if (!isset($link['id']) || empty($link['id'])) {
$links[$key]['id'] = uniqid('fl_');
$fixed++;
}
}
update_option('argon_friend_links', $links);
wp_send_json_success(array('message' => "已修复 {$fixed} 条数据"));
});
/**
* 添加测试友链
*/
add_action('wp_ajax_argon_debug_add_test_link', function() {
if (!current_user_can('manage_options')) wp_send_json_error('权限不足');
if (!wp_verify_nonce($_POST['nonce'], 'argon_debug')) wp_send_json_error('安全验证失败');
argon_add_friend_link(array(
'name' => '测试友链 ' . date('H:i:s'),
'url' => 'https://example.com',
'avatar' => '',
'description' => '这是一个测试友链',
'category' => '测试',
'status' => 'approved'
));
wp_send_json_success();
});
/**
* 清空所有友链
*/
add_action('wp_ajax_argon_debug_clear_links', function() {
if (!current_user_can('manage_options')) wp_send_json_error('权限不足');
if (!wp_verify_nonce($_POST['nonce'], 'argon_debug')) wp_send_json_error('安全验证失败');
update_option('argon_friend_links', array());
wp_send_json_success();
});
/**
* 去重友链
*/
add_action('wp_ajax_argon_debug_dedupe_links', function() {
if (!current_user_can('manage_options')) wp_send_json_error('权限不足');
if (!wp_verify_nonce($_POST['nonce'], 'argon_debug')) wp_send_json_error('安全验证失败');
$removed = argon_deduplicate_friend_links();
wp_send_json_success(array('message' => sprintf('已移除 %d 条重复友链', $removed)));
});
/**
* 导入友链
*/
add_action('wp_ajax_argon_debug_import_links', function() {
if (!current_user_can('manage_options')) wp_send_json_error('权限不足');
if (!wp_verify_nonce($_POST['nonce'], 'argon_debug')) wp_send_json_error('安全验证失败');
$data = isset($_POST['data']) ? $_POST['data'] : '';
$merge = isset($_POST['merge']) && $_POST['merge'] === '1';
$import_links = json_decode(stripslashes($data), true);
if (!is_array($import_links)) {
wp_send_json_error('JSON 格式错误');
}
// 确保每条数据都有必要字段
foreach ($import_links as $key => $link) {
if (!isset($link['id'])) $import_links[$key]['id'] = uniqid('fl_');
if (!isset($link['status'])) $import_links[$key]['status'] = 'approved';
if (!isset($link['created_at'])) $import_links[$key]['created_at'] = time();
}
if ($merge) {
$existing = get_option('argon_friend_links', array());
$import_links = array_merge($existing, $import_links);
}
update_option('argon_friend_links', $import_links);
wp_send_json_success(array('message' => '已导入 ' . count($import_links) . ' 条友链'));
});
/**
* 检查友链是否可访问(失效检测)
*/
function argon_check_link_accessible($url) {
$response = wp_remote_head($url, array(
'timeout' => 10,
'sslverify' => false,
'redirection' => 3,
'user-agent' => 'Mozilla/5.0 (compatible; Argon Link Checker)'
));
if (is_wp_error($response)) {
return array('accessible' => false, 'error' => $response->get_error_message());
}
$code = wp_remote_retrieve_response_code($response);
return array(
'accessible' => ($code >= 200 && $code < 400),
'status_code' => $code
);
}
/**
* 检查所有友链的可访问性
*/
function argon_check_all_links_accessibility() {
$links = argon_get_friend_links_raw('approved');
$results = array();
foreach ($links as $link) {
$check = argon_check_link_accessible($link['url']);
argon_update_friend_link($link['id'], array(
'accessible' => $check['accessible'],
'last_access_check' => time(),
'access_status_code' => isset($check['status_code']) ? $check['status_code'] : 0
));
$results[$link['id']] = $check;
// 每次请求后随机延迟 2-5 秒,避免频繁访问
sleep(rand(2, 5));
}
return $results;
}
/**
* 定时检查友链(可通过 WP Cron 调用)
* 每次只检查部分友链,分散压力
*/
function argon_scheduled_link_check() {
// 每天只更新约 1/3 的友链,分散到多天完成全部更新
argon_check_partial_links();
}
/**
* 分批检查友链,每次只检查部分
*/
function argon_check_partial_links() {
$links = get_option('argon_friend_links', array());
$approved_links = array_filter($links, function($l) { return $l['status'] === 'approved'; });
if (empty($approved_links)) return;
// 按上次检查时间排序,优先检查最久未检查的
usort($approved_links, function($a, $b) {
$a_time = isset($a['last_info_update']) ? $a['last_info_update'] : 0;
$b_time = isset($b['last_info_update']) ? $b['last_info_update'] : 0;
return $a_time - $b_time;
});
// 每次最多检查 5 个
$to_check = array_slice($approved_links, 0, 5);
foreach ($to_check as $link) {
// 随机延迟 3-10 秒
sleep(rand(3, 10));
$site_info = argon_fetch_site_info($link['url']);
$update_data = array(
'last_info_update' => time(),
'accessible' => $site_info['accessible'],
'blocked_by_waf' => $site_info['blocked_by_waf'],
'error_reason' => $site_info['error_reason']
);
if ($site_info['accessible']) {
// 更新 favicon
if (!empty($site_info['favicon'])) {
$update_data['auto_favicon'] = $site_info['favicon'];
if (empty($link['user_avatar'])) {
$update_data['avatar'] = $site_info['favicon'];
}
}
// 更新作者头像
if (!empty($site_info['author_avatar'])) {
$update_data['author_avatar'] = $site_info['author_avatar'];
}
// 更新描述
if (!empty($site_info['description'])) {
$update_data['auto_description'] = $site_info['description'];
}
// 更新标题(副标题)
if (!empty($site_info['title']) && !empty($link['name'])) {
$similarity = argon_string_similarity($link['name'], $site_info['title']);
if ($similarity < 0.6) {
$update_data['display_name'] = $site_info['title'];
}
}
// 检查回链
$update_data['has_backlink'] = argon_check_backlink($link['url']);
}
argon_update_friend_link($link['id'], $update_data);
}
}
// 注册定时任务
if (!wp_next_scheduled('argon_daily_link_check')) {
wp_schedule_event(time(), 'daily', 'argon_daily_link_check');
}
add_action('argon_daily_link_check', 'argon_scheduled_link_check');