Files
argon-theme/friend-links.php
nanhaoluo 9c22b41a51 feat: 移除友链申请表单卡片 hover 效果
- 移除本站信息项的悬浮背景变化效果
2026-01-20 18:55:34 +08:00

1089 lines
61 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* 友情链接页面
* @package Argon
*/
$wp_load_path = dirname(dirname(dirname(dirname(__FILE__)))) . '/wp-load.php';
if (!file_exists($wp_load_path)) $wp_load_path = $_SERVER['DOCUMENT_ROOT'] . '/wp-load.php';
require_once($wp_load_path);
if (function_exists('argon_deduplicate_friend_links')) argon_deduplicate_friend_links();
// 权限检查
$is_admin = current_user_can('manage_options');
// AJAX 处理友链管理
if (isset($_POST['flink_action'])) {
header('Content-Type: application/json; charset=utf-8');
$response = array('success' => false, 'message' => '');
$action = sanitize_text_field($_POST['flink_action']);
// 以下操作需要管理员权限
if (!$is_admin) {
echo json_encode(array('success' => false, 'message' => '权限不足'));
exit;
}
if (!isset($_POST['flink_nonce']) || !wp_verify_nonce($_POST['flink_nonce'], 'argon_flink_manage')) {
echo json_encode(array('success' => false, 'message' => '安全验证失败'));
exit;
}
switch ($action) {
case 'add':
$id = argon_add_friend_link(array(
'name' => isset($_POST['name']) ? $_POST['name'] : '',
'display_name' => isset($_POST['display_name']) ? $_POST['display_name'] : '',
'url' => isset($_POST['url']) ? $_POST['url'] : '',
'avatar' => isset($_POST['avatar']) ? $_POST['avatar'] : '',
'description' => isset($_POST['description']) ? $_POST['description'] : '',
'auto_description' => isset($_POST['auto_description']) ? $_POST['auto_description'] : '',
'category' => isset($_POST['category']) ? $_POST['category'] : '',
'status' => 'approved'
));
$response = array('success' => $id !== false, 'id' => $id);
break;
case 'delete':
$id = isset($_POST['id']) ? sanitize_text_field($_POST['id']) : '';
$response = array('success' => argon_delete_friend_link($id));
break;
case 'approve':
$id = isset($_POST['id']) ? sanitize_text_field($_POST['id']) : '';
$result = argon_update_friend_link($id, array('status' => 'approved'));
if ($result) {
$link = argon_get_friend_link($id);
if ($link && !empty($link['email'])) {
$subject = sprintf('[%s] 您的友链申请已通过', get_bloginfo('name'));
$message = sprintf("您好!\n\n您申请的友链已通过审核。\n\n网站名称:%s\n网站地址:%s\n\n感谢您的支持!", $link['name'], $link['url']);
wp_mail($link['email'], $subject, $message);
}
}
$response = array('success' => $result);
break;
case 'reject':
$id = isset($_POST['id']) ? sanitize_text_field($_POST['id']) : '';
$response = array('success' => argon_delete_friend_link($id));
break;
case 'update':
$id = isset($_POST['id']) ? sanitize_text_field($_POST['id']) : '';
$data = array();
foreach (array('name', 'display_name', 'url', 'links_page', 'avatar', 'description', 'auto_description', 'category', 'hide_no_backlink', 'auto_approved') as $f) {
if (isset($_POST[$f])) $data[$f] = $_POST[$f];
}
$response = array('success' => argon_update_friend_link($id, $data));
break;
case 'get':
$id = isset($_POST['id']) ? sanitize_text_field($_POST['id']) : '';
$link = argon_get_friend_link($id);
$response = $link ? array('success' => true, 'data' => $link) : array('success' => false);
break;
case 'check_backlink':
$id = isset($_POST['id']) ? sanitize_text_field($_POST['id']) : '';
$link = argon_get_friend_link($id);
if ($link) {
$links_page = !empty($link['links_page']) ? $link['links_page'] : '';
$has_backlink = $links_page ? argon_check_backlink($links_page) : null;
$accessible = argon_check_site_accessible($link['url']);
argon_update_friend_link($id, array('has_backlink' => $has_backlink, 'accessible' => $accessible, 'last_check' => time()));
$response = array('success' => true, 'has_backlink' => $has_backlink, 'accessible' => $accessible, 'links_page' => $links_page);
}
break;
case 'check_all':
$links = argon_get_friend_links_raw('approved');
$results = array();
foreach ($links as $link) {
$links_page = !empty($link['links_page']) ? $link['links_page'] : '';
$has_backlink = $links_page ? argon_check_backlink($links_page) : null;
$accessible = argon_check_site_accessible($link['url']);
argon_update_friend_link($link['id'], array('has_backlink' => $has_backlink, 'accessible' => $accessible, 'last_check' => time()));
$results[$link['id']] = array('has_backlink' => $has_backlink, 'accessible' => $accessible);
}
$response = array('success' => true, 'results' => $results);
break;
case 'fetch_info':
$url = isset($_POST['url']) ? esc_url_raw($_POST['url']) : '';
if (empty($url)) {
$response = array('success' => false, 'message' => __('请输入网址', 'argon'));
} else {
$info = argon_fetch_site_info($url);
$response = array('success' => true, 'data' => $info);
}
break;
default:
$response = array('success' => false, 'message' => '未知操作');
}
echo json_encode($response);
exit;
}
// 处理访客申请
$apply_result = null;
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['argon_link_apply'])) {
$apply_result = argon_handle_link_application_v3($_POST);
// PRG 模式:成功后重定向避免表单重复提交
if ($apply_result) {
$redirect_url = remove_query_arg(array('apply_success', 'apply_error'), $_SERVER['REQUEST_URI']);
if ($apply_result['success']) {
wp_redirect($redirect_url . (strpos($redirect_url, '?') !== false ? '&' : '?') . 'apply_success=1');
exit;
} else {
// 失败时保存错误信息到 session
if (!session_id()) session_start();
$_SESSION['flink_apply_error'] = $apply_result['message'];
wp_redirect($redirect_url . (strpos($redirect_url, '?') !== false ? '&' : '?') . 'apply_error=1');
exit;
}
}
}
// 从 URL 参数或 session 获取申请结果
if (isset($_GET['apply_success'])) {
$apply_result = array('success' => true, 'message' => __('申请已提交,请等待审核', 'argon'));
} elseif (isset($_GET['apply_error'])) {
if (!session_id()) session_start();
$error_msg = isset($_SESSION['flink_apply_error']) ? $_SESSION['flink_apply_error'] : __('申请失败', 'argon');
unset($_SESSION['flink_apply_error']);
$apply_result = array('success' => false, 'message' => $error_msg);
}
// 获取友链数据
$all_approved_links = argon_get_friend_links_raw('approved');
$pending_links = $is_admin ? argon_get_friend_links_raw('pending') : array();
$show_apply_form = get_option('argon_friend_link_allow_apply', 'true') === 'true';
$requirements = get_option('argon_friend_link_requirements', '');
$hide_no_backlink = get_option('argon_friend_link_hide_no_backlink', 'true') === 'true';
// 过滤友链:非管理员时根据设置隐藏未上友链/失效的
$visible_links = array();
foreach ($all_approved_links as $link) {
$show = true;
if (!$is_admin && $hide_no_backlink) {
// 未填写友链页面的永不隐藏
if (!empty($link['links_page'])) {
$link_hide = $link['hide_no_backlink'] ?? '';
if ($link_hide === 'hide' || ($link_hide !== 'show' && $hide_no_backlink)) {
if (isset($link['has_backlink']) && $link['has_backlink'] === false) $show = false;
if (isset($link['accessible']) && $link['accessible'] === false) $show = false;
}
}
}
if ($show) $visible_links[] = $link;
}
// 按分类分组
$links = array();
foreach ($visible_links as $link) {
$cat = !empty($link['category']) ? $link['category'] : '';
if (!isset($links[$cat])) $links[$cat] = array();
$links[$cat][] = $link;
}
$total_links = count($visible_links);
// 验证码设置(支持独立配置)
$flink_captcha_setting = get_option('argon_friend_link_captcha', 'global');
if ($flink_captcha_setting === 'global' || $flink_captcha_setting === 'same') {
// 使用全局设置
$global_captcha = get_option('argon_need_captcha', get_option('argon_comment_need_captcha', 'true'));
$captcha_enabled = ($global_captcha === 'true');
} elseif ($flink_captcha_setting === 'enabled') {
$captcha_enabled = true;
} else {
$captcha_enabled = false;
}
$captcha_type = get_option('argon_captcha_type', 'math');
get_header();
?>
<div class="page-information-card-container"></div>
<?php get_sidebar(); ?>
<div id="primary" class="content-area">
<style id="flinks-page-style">
/* 桌面端隐藏侧边栏 */
@media screen and (min-width: 901px) {
body.flinks-page #leftbar_part, body.flinks-page #leftbar { display: none !important; }
}
/* 移动端侧边栏支持 - 使用全局样式 */
@media screen and (max-width: 900px) {
body.flinks-page #leftbar {
display: block;
position: fixed;
background: var(--color-foreground);
top: 0;
left: -300px;
height: 100vh;
width: 280px;
padding: 0;
overflow-y: auto;
overflow-x: hidden;
z-index: 1002;
box-shadow: 0 15px 35px rgba(50, 50, 93, 0.1), 0 5px 15px rgba(0, 0, 0, 0.07) !important;
transition: left 0.35s cubic-bezier(0.4, 0, 0.2, 1);
}
html.leftbar-opened body.flinks-page #leftbar { left: 0px; }
body.flinks-page .leftbar-mobile-nav { display: flex; flex-direction: column; min-height: 100%; }
body.flinks-page .leftbar-desktop-content { display: none !important; }
/* 底部操作区固定在底部 */
body.flinks-page .leftbar-mobile-footer {
margin-top: auto;
position: sticky;
bottom: 0;
background: var(--color-foreground);
z-index: 10;
}
}
body.flinks-page #primary { width: 100% !important; max-width: 1000px !important; margin: 0 auto !important; float: none !important; }
body.flinks-page #content { margin-top: -50vh !important; }
.flinks-header-card { text-align: center; padding: 40px 24px 32px; background: transparent !important; box-shadow: none !important; }
.flinks-header-icon { width: 64px; height: 64px; margin: 0 auto 20px; background: var(--themecolor-gradient); border-radius: var(--card-radius); display: flex; align-items: center; justify-content: center; font-size: 28px; color: #fff; box-shadow: 0 4px 12px rgba(var(--themecolor-rgbstr), 0.2); transition: transform var(--animation-fast) var(--ease-standard); }
.flinks-header-icon:hover { transform: translateY(-2px); }
.flinks-title { font-size: 24px; font-weight: 600; margin: 0 0 12px; color: var(--color-text-deeper); background: none !important; }
.flinks-title::before, .flinks-title::after { display: none !important; }
.flinks-subtitle { font-size: 14px; color: #888; margin: 0 0 20px; line-height: 1.6; }
.flinks-stats { display: flex; justify-content: center; gap: 12px; }
.flinks-stat { display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px; background: rgba(var(--themecolor-rgbstr), 0.08); border-radius: var(--card-radius-sm); font-size: 13px; font-weight: 500; color: var(--themecolor); transition: all var(--animation-fast) var(--ease-standard); }
.flinks-stat:hover { background: rgba(var(--themecolor-rgbstr), 0.12); }
html.darkmode .flinks-subtitle { color: #aaa; }
.flinks-welcome-text { font-size: 14px; color: #777; line-height: 1.6; margin-bottom: 16px; padding: 12px 16px; background: rgba(var(--themecolor-rgbstr), 0.05); border-radius: var(--card-radius-sm); border-left: 3px solid var(--themecolor); }
.flinks-category-card { padding: 24px 28px; }
.flinks-category-header { display: flex; align-items: center; margin-bottom: 20px; padding-bottom: 12px; border-bottom: 1px solid var(--color-border-on-foreground); }
.flinks-category-title { font-size: 17px; font-weight: 600; margin: 0; color: var(--color-text-deeper); display: flex; align-items: center; gap: 8px; background: none !important; }
.flinks-category-title::before, .flinks-category-title::after { display: none !important; }
.flinks-category-title i { color: var(--themecolor); font-size: 16px; }
.flinks-category-count { margin-left: auto; font-size: 12px; font-weight: 500; color: var(--themecolor); background: rgba(var(--themecolor-rgbstr), 0.1); padding: 4px 12px; border-radius: var(--card-radius-sm); }
.flinks-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 16px; }
.flink-card { display: flex; align-items: flex-start; gap: 14px; padding: 16px; background: transparent; border-radius: var(--card-radius); text-decoration: none !important; color: inherit; border: none; transition: all var(--animation-fast) var(--ease-standard); min-height: 88px; position: relative; }
.flink-card:hover {
box-shadow: 0 4px 12px rgba(var(--themecolor-rgbstr), 0.1);
transform: translateY(-2px);
background: rgba(var(--themecolor-rgbstr), 0.03);
}
html.darkmode .flinks-welcome-text { color: #aaa; }
.flink-card.editable { cursor: default; }
.flink-card .flink-edit-btn { position: absolute; top: 8px; right: 8px; width: 28px; height: 28px; border-radius: var(--card-radius-sm); background: rgba(var(--themecolor-rgbstr), 0.1); color: var(--themecolor); border: none; cursor: pointer; display: none; align-items: center; justify-content: center; font-size: 12px; transition: all var(--animation-fast) var(--ease-standard); }
.flink-card:hover .flink-edit-btn { display: flex; }
.flink-card .flink-edit-btn:hover { background: rgba(var(--themecolor-rgbstr), 0.2); }
@media (hover: none) and (pointer: coarse) {
.flink-card .flink-edit-btn { display: flex; opacity: 0.7; }
.flink-card .flink-edit-btn:active { opacity: 1; background: rgba(var(--themecolor-rgbstr), 0.2); }
}
/* 状态标记 */
.flink-status-badge { position: absolute; top: 6px; right: 6px; font-size: 10px; padding: 2px 6px; border-radius: 4px; font-weight: 500; cursor: help; }
.flink-status-badge.no-backlink { background: #fef3c7; color: #d97706; }
.flink-status-badge.inaccessible { background: #fee2e2; color: #dc2626; }
.flink-status-badge.waf-blocked { background: #fce7f3; color: #db2777; }
.flink-status-badge.auto-approved { background: #d1fae5; color: #059669; cursor: pointer; }
.flink-card.editable .flink-status-badge { right: 40px; }
.flink-avatar { width: 52px; height: 52px; flex-shrink: 0; border-radius: var(--card-radius); background: var(--themecolor-gradient); display: flex; align-items: center; justify-content: center; font-size: 20px; font-weight: 600; color: #fff; position: relative; overflow: hidden; box-shadow: 0 2px 8px rgba(var(--themecolor-rgbstr), 0.2); transition: transform var(--animation-fast) var(--ease-standard); }
.flink-card:hover .flink-avatar { transform: scale(1.05); }
.flink-avatar::before { content: attr(data-letter); }
.flink-avatar img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; border-radius: var(--card-radius); }
.flink-info { flex: 1; min-width: 0; padding-top: 2px; }
.flink-name { font-size: 15px; font-weight: 600; color: var(--color-text-deeper); margin-bottom: 4px; display: flex; align-items: center; flex-wrap: wrap; gap: 6px; line-height: 1.4; }
.flink-name .main-name { }
.flink-name .sub-name { font-size: 13px; font-weight: 400; color: #999; }
.flink-verified { color: #22c55e; font-size: 13px; flex-shrink: 0; }
.flink-desc { font-size: 13px; color: #888; line-height: 1.6; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; margin-top: 4px; }
.flink-url { font-size: 12px; color: #aaa; margin-top: 6px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
html.darkmode .flink-name .sub-name { color: #777; }
html.darkmode .flink-desc { color: #aaa; }
html.darkmode .flink-url { color: #888; }
.flinks-empty { padding: 60px 24px; text-align: center; }
.flinks-empty i { font-size: 48px; color: var(--color-border); margin-bottom: 16px; display: block; }
.flinks-empty p { font-size: 15px; color: #888; margin: 0; }
/* 申请区域 */
.flinks-apply-card { padding: 16px 22px; }
.flinks-apply-header { display: flex; align-items: center; justify-content: space-between; cursor: pointer; user-select: none; padding: 4px 0; }
.flinks-apply-header:hover { opacity: 0.8; }
.flinks-apply-title { display: flex; align-items: center; gap: 10px; font-size: 15px; font-weight: 600; color: var(--themecolor); }
.flinks-apply-arrow { color: var(--themecolor); font-size: 14px; transition: transform var(--animation-normal) var(--ease-standard); }
.flinks-apply-arrow.open { transform: rotate(180deg); }
.flinks-apply-content { max-height: 0; overflow: hidden; transition: max-height var(--animation-slow) var(--ease-standard); }
.flinks-apply-content.open { max-height: 1200px; }
.flinks-requirements { background: rgba(var(--themecolor-rgbstr), 0.05); border-radius: var(--card-radius); padding: 10px 12px; margin: 10px 0 8px; border: none; border-left: 3px solid var(--themecolor); font-size: 13px; line-height: 1.5; }
.flinks-requirements p { margin: 0; }
.flinks-mysite-info { background: transparent; border-radius: var(--card-radius); padding: 10px 12px; margin: 8px 0; border: none; }
.flinks-mysite-title { font-size: 12px; font-weight: 600; color: var(--themecolor); margin-bottom: 8px; display: flex; align-items: center; gap: 6px; }
.flinks-mysite-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.flinks-mysite-item { background: transparent; border-radius: calc(var(--card-radius) * 0.6); padding: 6px 10px; cursor: pointer; transition: all var(--animation-fast) var(--ease-standard); border: none; }
.flinks-mysite-item label { display: block; font-size: 10px; color: #999; margin-bottom: 1px; text-transform: uppercase; pointer-events: none; }
.flinks-mysite-item span { font-size: 12px; color: var(--color-text-deeper); word-break: break-all; font-weight: 500; pointer-events: none; }
.flinks-form { margin-top: 8px; font-family: var(--font); }
.flinks-form .row { margin-left: -6px; margin-right: -6px; }
.flinks-form .row > [class*="col-"] { padding-left: 6px; padding-right: 6px; }
.flinks-form .form-group { margin-bottom: 8px; }
.flinks-form .form-control-label { font-size: 12px; font-weight: 600; margin-bottom: 3px; color: var(--color-text-deeper); display: block; font-family: var(--font); }
.flinks-form .form-control { border-radius: calc(var(--card-radius) * 0.6); border: none; padding: 7px 10px; font-size: 13px; font-family: var(--font); background: rgba(var(--themecolor-rgbstr), 0.05); }
.flinks-form .form-control:focus { border: none; box-shadow: 0 0 0 2px rgba(var(--themecolor-rgbstr), 0.15); outline: none; }
.flinks-form .char-count { font-size: 11px; color: #999; float: right; }
.flinks-submit { margin-top: 10px; text-align: center; }
.flinks-submit .btn { padding: 8px 24px; font-size: 13px; font-weight: 600; font-family: var(--font); }
/* 自动获取预览 */
.flinks-auto-preview { background: transparent; border-radius: var(--card-radius); padding: 12px; margin: 10px 0; display: none; border: none; }
.flinks-auto-preview.show { display: block; }
.flinks-auto-preview-title { font-size: 12px; font-weight: 600; color: var(--themecolor); margin-bottom: 8px; display: flex; align-items: center; gap: 6px; }
.flinks-auto-preview-content { display: flex; gap: 12px; align-items: flex-start; }
.flinks-auto-preview-avatar { width: 48px; height: 48px; border-radius: 10px; background: var(--color-border); flex-shrink: 0; overflow: hidden; }
.flinks-auto-preview-avatar img { width: 100%; height: 100%; object-fit: cover; }
.flinks-auto-preview-info { flex: 1; min-width: 0; }
.flinks-auto-preview-name { font-size: 14px; font-weight: 600; color: var(--color-text-deeper); }
.flinks-auto-preview-desc { font-size: 12px; color: #888; margin-top: 4px; }
/* 验证码 */
.flinks-captcha { margin-top: 10px; }
.flinks-captcha .input-group { max-width: 280px; }
.flinks-captcha-text { background: var(--color-background); font-family: monospace; font-size: 14px; letter-spacing: 2px; cursor: pointer; user-select: none; }
/* 管理面板 */
.flinks-admin-card { padding: 16px 20px; }
.flinks-admin-title { font-size: 15px; font-weight: 600; color: var(--themecolor); margin: 0 0 12px; display: flex; align-items: center; gap: 8px; }
.flinks-admin-section { margin-bottom: 16px; }
.flinks-admin-section:last-child { margin-bottom: 0; }
.flinks-admin-section h4 { font-size: 13px; font-weight: 600; color: var(--color-text-deeper); margin: 0 0 8px; display: flex; align-items: center; gap: 6px; }
.flinks-pending-item { display: flex; align-items: flex-start; gap: 12px; padding: 12px; background: transparent; border: 1px solid #fcd34d; border-radius: var(--card-radius); margin-bottom: 8px; }
.flinks-pending-avatar { width: 40px; height: 40px; border-radius: 8px; background: var(--color-border); flex-shrink: 0; overflow: hidden; }
.flinks-pending-avatar img { width: 100%; height: 100%; object-fit: cover; }
.flinks-pending-info { flex: 1; min-width: 0; }
.flinks-pending-name { font-weight: 600; font-size: 14px; margin-bottom: 2px; }
.flinks-pending-name .sub-name { font-weight: 400; font-size: 12px; color: #888; margin-left: 6px; }
.flinks-pending-url { font-size: 12px; color: #666; margin-bottom: 4px; }
.flinks-pending-url a { color: var(--themecolor); }
.flinks-pending-desc { font-size: 12px; color: #888; }
.flinks-pending-actions { display: flex; gap: 6px; flex-shrink: 0; }
.flinks-pending-actions .btn { padding: 4px 12px; font-size: 12px; }
.flinks-add-form { background: transparent; border-radius: var(--card-radius); padding: 14px; border: none; }
.flinks-add-form .form-row { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; margin-bottom: 8px; }
.flinks-add-form .form-row.full { grid-template-columns: 1fr; }
.flinks-add-form label { font-size: 12px; font-weight: 500; color: var(--color-text-deeper); margin-bottom: 3px; display: block; }
.flinks-add-form input { width: 100%; padding: 6px 10px; font-size: 13px; border: 1px solid var(--color-border); border-radius: calc(var(--card-radius) * 0.6); font-family: var(--font); box-sizing: border-box; }
.flinks-add-form input:focus { border-color: var(--themecolor); outline: none; }
.flinks-add-form .input-with-btn { display: flex; gap: 6px; }
.flinks-add-form .input-with-btn input { flex: 1; min-width: 0; }
.flinks-add-form .input-with-btn .btn { flex-shrink: 0; padding: 6px 10px; font-size: 12px; }
.flinks-add-form .form-actions { margin-top: 10px; display: flex; gap: 8px; }
.flinks-add-form .form-actions .btn { display: inline-flex; align-items: center; justify-content: center; text-align: center; }
/* 编辑弹窗 */
.flink-modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 9998; display: none; align-items: center; justify-content: center; }
.flink-modal-overlay.show { display: flex; }
.flink-modal { background: var(--color-foreground); border-radius: var(--card-radius); padding: 20px; width: 90%; max-width: 500px; max-height: 90vh; overflow-y: auto; }
.flink-modal-title { font-size: 16px; font-weight: 600; margin-bottom: 16px; display: flex; align-items: center; justify-content: space-between; }
.flink-modal-close { background: none; border: none; font-size: 20px; cursor: pointer; color: #999; padding: 0; line-height: 1; }
.flink-modal .form-group { margin-bottom: 12px; }
.flink-modal .form-group label { font-size: 12px; font-weight: 600; color: var(--color-text-deeper); margin-bottom: 4px; display: block; }
.flink-modal .form-group input, .flink-modal .form-group select { width: 100%; padding: 8px 10px; font-size: 13px; border: 1px solid var(--color-border); border-radius: calc(var(--card-radius) * 0.6); font-family: var(--font); box-sizing: border-box; }
.flink-modal .form-group input:focus { border-color: var(--themecolor); outline: none; }
.flink-modal .form-actions { margin-top: 16px; display: flex; gap: 8px; justify-content: flex-end; flex-wrap: nowrap; }
.flink-modal .form-actions .btn { display: inline-flex; align-items: center; justify-content: center; text-align: center; min-width: auto; }
.flink-modal .btn-danger { background: #ef4444; border-color: #ef4444; }
.flink-modal .btn-danger:hover { background: #dc2626; border-color: #dc2626; }
.flink-modal .status-info { font-size: 12px; color: #888; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--color-border); }
.flink-modal .status-info .badge { font-size: 11px; padding: 2px 6px; border-radius: 4px; margin-left: 6px; }
.flink-modal .status-info .badge-warning { background: #fef3c7; color: #d97706; }
.flink-modal .status-info .badge-danger { background: #fee2e2; color: #dc2626; }
.flink-modal .status-info .badge-success { background: #d1fae5; color: #059669; }
@media (max-width: 768px) {
.flinks-grid { grid-template-columns: 1fr; }
.flinks-mysite-grid { grid-template-columns: 1fr; }
.flinks-add-form .form-row { grid-template-columns: 1fr; }
.flink-card { min-height: auto; }
}
html.darkmode .flink-card { background: rgba(255, 255, 255, 0.03); }
html.darkmode .flink-card:hover { background: rgba(255, 255, 255, 0.05); }
html.darkmode .flinks-pending-item { background: rgba(251, 191, 36, 0.1); border-color: rgba(251, 191, 36, 0.3); }
html.darkmode .flink-modal { background: var(--color-background); }
.flink-avatar[data-color="1"] { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); }
.flink-avatar[data-color="2"] { background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); }
.flink-avatar[data-color="3"] { background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); }
.flink-avatar[data-color="4"] { background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%); }
.flink-avatar[data-color="5"] { background: linear-gradient(135deg, #fa709a 0%, #fee140 100%); }
.flink-avatar[data-color="6"] { background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%); }
</style>
<script data-pjax>
(function() {
// 清理函数
function cleanupFlinksPage() {
document.body.classList.remove('flinks-page');
var s = document.getElementById('flinks-page-style');
if (s) s.remove();
}
// 先清理可能残留的状态(处理后退情况)
// 如果当前不是友链页面但有残留 class清理它
if (!document.getElementById('flinks-page-style')) {
document.body.classList.remove('flinks-page');
}
// 添加页面标识 class
document.body.classList.add('flinks-page');
// PJAX 离开时清理
if (typeof jQuery !== 'undefined') {
var $ = jQuery;
$(document).off('pjax:start.flinks pjax:popstate.flinks');
// 正常跳转离开
$(document).on('pjax:start.flinks', function() {
cleanupFlinksPage();
$(document).off('pjax:start.flinks pjax:popstate.flinks');
});
// 浏览器后退/前进
$(document).on('pjax:popstate.flinks', function() {
// 延迟检查,等 PJAX 完成内容替换
setTimeout(function() {
if (!document.getElementById('flinks-page-style')) {
document.body.classList.remove('flinks-page');
}
}, 50);
});
}
})();
</script>
<main id="main" class="site-main" role="main">
<?php
// 获取自定义标语
$flink_slogan = get_option('argon_friend_link_slogan', __('海内存知己,天涯若比邻', 'argon'));
$flink_welcome = get_option('argon_friend_link_welcome', __('欢迎与我交换友链!如果您的网站已添加本站链接,填写友链页面地址可自动通过审核。', 'argon'));
?>
<!-- 头部卡片 -->
<div class="flinks-header-card" style="margin-bottom: 16px;">
<div class="flinks-header-icon"><i class="fa fa-link"></i></div>
<h1 class="flinks-title"><?php _e('友情链接', 'argon'); ?></h1>
<p class="flinks-subtitle"><?php echo esc_html($flink_slogan); ?></p>
<div class="flinks-stats">
<div class="flinks-stat"><i class="fa fa-heart"></i><span><?php echo $total_links; ?> <?php _e('位朋友', 'argon'); ?></span></div>
<?php if (count($links) > 1) : ?>
<div class="flinks-stat"><i class="fa fa-folder-open"></i><span><?php echo count($links); ?> <?php _e('个分类', 'argon'); ?></span></div>
<?php endif; ?>
</div>
</div>
<!-- 管理面板(仅管理员可见) -->
<?php if ($is_admin) : ?>
<article class="post card shadow-sm bg-white border-0 flinks-admin-card" style="margin-bottom: 16px;" id="admin-panel">
<div class="flinks-admin-title"><i class="fa fa-cog"></i><?php _e('友链管理', 'argon'); ?> <button class="btn btn-sm btn-secondary" style="margin-left:auto;font-size:11px;" id="check-all-btn"><?php _e('检测所有友链', 'argon'); ?></button></div>
<?php if (!empty($pending_links)) : ?>
<div class="flinks-admin-section">
<h4><i class="fa fa-clock-o"></i> <?php _e('待审核', 'argon'); ?> (<?php echo count($pending_links); ?>)</h4>
<?php foreach ($pending_links as $link) :
$main_name = esc_html($link['name']);
$sub_name = !empty($link['display_name']) ? esc_html($link['display_name']) : '';
?>
<div class="flinks-pending-item" data-id="<?php echo esc_attr($link['id']); ?>">
<div class="flinks-pending-avatar">
<?php if (!empty($link['avatar'])) : ?><img src="<?php echo esc_url($link['avatar']); ?>" alt=""><?php endif; ?>
</div>
<div class="flinks-pending-info">
<div class="flinks-pending-name"><?php echo $main_name; ?><?php if ($sub_name) : ?><span class="sub-name"><?php echo $sub_name; ?></span><?php endif; ?></div>
<div class="flinks-pending-url"><a href="<?php echo esc_url($link['url']); ?>" target="_blank"><?php echo esc_html($link['url']); ?></a></div>
<?php if (!empty($link['description'])) : ?><div class="flinks-pending-desc"><?php echo esc_html($link['description']); ?></div><?php endif; ?>
</div>
<div class="flinks-pending-actions">
<button class="btn btn-sm btn-primary flink-approve" data-id="<?php echo esc_attr($link['id']); ?>"><?php _e('通过', 'argon'); ?></button>
<button class="btn btn-sm btn-secondary flink-reject" data-id="<?php echo esc_attr($link['id']); ?>"><?php _e('拒绝', 'argon'); ?></button>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
<div class="flinks-admin-section">
<h4><i class="fa fa-plus"></i> <?php _e('添加友链', 'argon'); ?></h4>
<div class="flinks-add-form">
<div class="form-row">
<div>
<label><?php _e('网站地址', 'argon'); ?> *</label>
<div class="input-with-btn">
<input type="url" id="add-url" placeholder="https://example.com">
<button type="button" class="btn btn-secondary" id="fetch-info"><?php _e('获取', 'argon'); ?></button>
</div>
</div>
<div><label><?php _e('网站名称', 'argon'); ?> *</label><input type="text" id="add-name" placeholder="<?php _e('主标题', 'argon'); ?>"></div>
</div>
<div class="form-row">
<div><label><?php _e('副标题', 'argon'); ?></label><input type="text" id="add-display-name" placeholder="<?php _e('自动获取的标题', 'argon'); ?>"></div>
<div><label><?php _e('分类', 'argon'); ?></label><input type="text" id="add-category" placeholder="<?php _e('留空为默认', 'argon'); ?>"></div>
</div>
<div class="form-row">
<div><label><?php _e('头像', 'argon'); ?></label><input type="url" id="add-avatar" placeholder="<?php _e('自动获取', 'argon'); ?>"></div>
<div><label><?php _e('描述', 'argon'); ?></label><input type="text" id="add-desc" maxlength="100" placeholder="<?php _e('主描述', 'argon'); ?>"></div>
</div>
<div class="form-actions">
<button type="button" class="btn btn-primary" id="add-link-btn"><?php _e('添加', 'argon'); ?></button>
</div>
</div>
</div>
</article>
<?php endif; ?>
<!-- 友链列表 -->
<?php if (!empty($links)) : ?>
<?php $color_index = 0; foreach ($links as $category => $category_links) : ?>
<article class="post card shadow-sm bg-white border-0 flinks-category-card" style="margin-bottom: 16px;">
<div class="flinks-category-header">
<h2 class="flinks-category-title">
<i class="fa fa-<?php echo empty($category) ? 'star' : 'folder-open'; ?>"></i>
<?php echo empty($category) ? __('友情链接', 'argon') : esc_html($category); ?>
</h2>
<span class="flinks-category-count"><?php echo count($category_links); ?></span>
</div>
<div class="flinks-grid">
<?php foreach ($category_links as $link) :
$host = parse_url($link['url'], PHP_URL_HOST);
$main_name = $link['name'];
$sub_name = !empty($link['display_name']) ? $link['display_name'] : '';
$first_letter = mb_substr($main_name, 0, 1);
$color_index = ($color_index % 6) + 1;
$desc = !empty($link['description']) ? $link['description'] : (!empty($link['auto_description']) ? $link['auto_description'] : __('暂无描述', 'argon'));
// 状态检测
$has_backlink = isset($link['has_backlink']) ? $link['has_backlink'] : null;
$accessible = isset($link['accessible']) ? $link['accessible'] : null;
$blocked_by_waf = isset($link['blocked_by_waf']) ? $link['blocked_by_waf'] : false;
$error_reason = isset($link['error_reason']) ? $link['error_reason'] : '';
$auto_approved = !empty($link['auto_approved']);
$status_badge = '';
if ($is_admin) {
if ($blocked_by_waf) {
$status_badge = '<span class="flink-status-badge waf-blocked" title="' . esc_attr($error_reason) . '">' . __('WAF拦截', 'argon') . '</span>';
} elseif ($accessible === false) {
$title = $error_reason ? esc_attr($error_reason) : '';
$status_badge = '<span class="flink-status-badge inaccessible" title="' . $title . '">' . __('失效', 'argon') . '</span>';
} elseif ($has_backlink === false) {
$status_badge = '<span class="flink-status-badge no-backlink">' . __('未上链', 'argon') . '</span>';
} elseif ($auto_approved) {
$status_badge = '<span class="flink-status-badge auto-approved" data-id="' . esc_attr($link['id']) . '" onclick="event.preventDefault();event.stopPropagation();removeAutoTag(this)" title="' . __('点击移除标记', 'argon') . '">' . __('自动', 'argon') . '</span>';
}
}
?>
<a href="<?php echo esc_url($link['url']); ?>" class="flink-card <?php echo $is_admin ? 'editable' : ''; ?>" target="_blank" rel="noopener noreferrer" data-id="<?php echo esc_attr($link['id']); ?>">
<?php echo $status_badge; ?>
<?php if ($is_admin) : ?><button type="button" class="flink-edit-btn" onclick="event.preventDefault();event.stopPropagation();openEditModal('<?php echo esc_attr($link['id']); ?>')"><i class="fa fa-pencil"></i></button><?php endif; ?>
<div class="flink-avatar" data-letter="<?php echo esc_attr($first_letter); ?>" data-color="<?php echo $color_index; ?>">
<?php if (!empty($link['avatar'])) : ?><img src="<?php echo esc_url($link['avatar']); ?>" alt="" loading="lazy" onerror="this.style.display='none'"><?php endif; ?>
</div>
<div class="flink-info">
<div class="flink-name">
<span class="main-name"><?php echo esc_html($main_name); ?></span>
<?php if ($sub_name) : ?><span class="sub-name"><?php echo esc_html($sub_name); ?></span><?php endif; ?>
<?php if (!empty($link['verified'])) : ?><i class="fa fa-check-circle flink-verified"></i><?php endif; ?>
</div>
<div class="flink-desc"><?php echo esc_html($desc); ?></div>
<div class="flink-url"><i class="fa fa-link" style="margin-right:4px;font-size:10px;"></i><?php echo esc_html($host); ?></div>
</div>
</a>
<?php endforeach; ?>
</div>
</article>
<?php endforeach; ?>
<?php else : ?>
<article class="post card shadow-sm bg-white border-0 flinks-empty" style="margin-bottom: 16px;">
<i class="fa fa-inbox"></i>
<p><?php _e('暂无友情链接', 'argon'); ?></p>
</article>
<?php endif; ?>
<!-- 申请友链 -->
<?php if ($show_apply_form && !$is_admin) : ?>
<article class="post card shadow-sm bg-white border-0 flinks-apply-card" style="margin-bottom: 16px;" id="apply-section">
<div class="flinks-apply-header" onclick="toggleApplyForm()">
<div class="flinks-apply-title"><i class="fa fa-plus-circle"></i><span><?php _e('申请友链', 'argon'); ?></span></div>
<i class="fa fa-chevron-down flinks-apply-arrow <?php echo $apply_result ? 'open' : ''; ?>"></i>
</div>
<div class="flinks-apply-content <?php echo $apply_result ? 'open' : ''; ?>">
<?php if ($apply_result) : ?>
<div class="alert alert-<?php echo $apply_result['success'] ? 'success' : 'danger'; ?>" style="margin-top:10px;padding:8px 12px;font-size:13px;"><?php echo esc_html($apply_result['message']); ?></div>
<?php endif; ?>
<?php if (!empty($requirements)) : ?>
<div class="flinks-requirements"><?php echo wp_kses_post($requirements); ?></div>
<?php endif; ?>
<div class="flinks-welcome-text">
<?php echo wp_kses_post($flink_welcome); ?>
</div>
<div class="flinks-mysite-info">
<div class="flinks-mysite-title"><i class="fa fa-bookmark"></i><?php _e('本站信息(点击复制)', 'argon'); ?></div>
<div class="flinks-mysite-grid">
<div class="flinks-mysite-item" onclick="copyText('<?php echo esc_js(get_bloginfo('name')); ?>')"><label><?php _e('名称', 'argon'); ?></label><span><?php echo get_bloginfo('name'); ?></span></div>
<div class="flinks-mysite-item" onclick="copyText('<?php echo esc_js(home_url()); ?>')"><label><?php _e('地址', 'argon'); ?></label><span><?php echo home_url(); ?></span></div>
<div class="flinks-mysite-item" onclick="copyText('<?php echo esc_js(get_bloginfo('description')); ?>')"><label><?php _e('描述', 'argon'); ?></label><span><?php echo get_bloginfo('description') ?: '-'; ?></span></div>
</div>
</div>
<form method="post" action="<?php echo esc_url($_SERVER['REQUEST_URI']); ?>" class="flinks-form" id="apply-form">
<?php wp_nonce_field('argon_link_apply', 'argon_link_apply_nonce'); ?>
<input type="hidden" name="argon_link_apply" value="1">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label class="form-control-label"><?php _e('网站地址', 'argon'); ?> <span class="text-danger">*</span></label>
<input type="url" name="apply_url" id="apply-url" class="form-control" required placeholder="https://example.com">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label class="form-control-label"><?php _e('网站名称', 'argon'); ?></label>
<input type="text" name="apply_name" id="apply-name" class="form-control" placeholder="<?php _e('选填', 'argon'); ?>">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label class="form-control-label"><?php _e('网站图标', 'argon'); ?></label>
<input type="url" name="apply_avatar" id="apply-avatar" class="form-control" placeholder="<?php _e('选填', 'argon'); ?>">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label class="form-control-label"><?php _e('联系邮箱', 'argon'); ?></label>
<input type="email" name="apply_email" class="form-control" placeholder="<?php _e('选填', 'argon'); ?>">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label class="form-control-label"><?php _e('友链页面', 'argon'); ?> <small style="color:#4caf50;font-weight:normal;"><?php _e('填写可自动通过', 'argon'); ?></small></label>
<input type="url" name="apply_links_page" class="form-control" placeholder="<?php _e('您放置友链的页面地址', 'argon'); ?>">
</div>
</div>
<div class="col-12">
<div class="form-group">
<label class="form-control-label"><?php _e('网站描述', 'argon'); ?> <span class="char-count"><span id="desc-count">0</span>/100</span></label>
<textarea name="apply_description" id="apply-desc" class="form-control" maxlength="100" rows="2" placeholder="<?php _e('选填', 'argon'); ?>" oninput="document.getElementById('desc-count').textContent=this.value.length" style="resize:vertical;min-height:60px;"></textarea>
</div>
</div>
</div>
<!-- 验证码 -->
<?php if ($captcha_enabled) : ?>
<div class="flinks-captcha">
<?php if ($captcha_type === 'geetest') : ?>
<div id="flink-geetest-captcha"></div>
<input type="hidden" name="lot_number" id="flink-lot-number">
<input type="hidden" name="captcha_output" id="flink-captcha-output">
<input type="hidden" name="pass_token" id="flink-pass-token">
<input type="hidden" name="gen_time" id="flink-gen-time">
<?php else : ?>
<div class="input-group input-group-sm">
<input type="text" name="comment_captcha" id="flink-captcha-input" class="form-control" placeholder="<?php _e('验证码', 'argon'); ?>" required style="max-width:120px;">
<div class="input-group-append">
<span class="input-group-text flinks-captcha-text" id="flink-captcha-text" onclick="refreshCaptcha()" title="<?php _e('点击刷新', 'argon'); ?>"><?php echo get_comment_captcha(); ?></span>
</div>
</div>
<?php endif; ?>
</div>
<?php endif; ?>
<div class="flinks-submit">
<button type="submit" class="btn btn-primary" id="apply-submit-btn"><i class="fa fa-paper-plane"></i> <?php _e('提交申请', 'argon'); ?></button>
</div>
</form>
</div>
</article>
<?php endif; ?>
<!-- 编辑弹窗 -->
<?php if ($is_admin) : ?>
<div class="flink-modal-overlay" id="edit-modal">
<div class="flink-modal">
<div class="flink-modal-title">
<span><i class="fa fa-pencil"></i> <?php _e('编辑友链', 'argon'); ?></span>
<button type="button" class="flink-modal-close" onclick="closeEditModal()">&times;</button>
</div>
<input type="hidden" id="edit-id">
<div class="form-group">
<label><?php _e('网站名称', 'argon'); ?> *</label>
<input type="text" id="edit-name" placeholder="<?php _e('主标题', 'argon'); ?>">
</div>
<div class="form-group">
<label><?php _e('副标题', 'argon'); ?></label>
<input type="text" id="edit-display-name" placeholder="<?php _e('自动获取的标题', 'argon'); ?>">
</div>
<div class="form-group">
<label><?php _e('网站地址', 'argon'); ?> *</label>
<input type="url" id="edit-url">
</div>
<div class="form-group">
<label><?php _e('友链页面', 'argon'); ?></label>
<input type="url" id="edit-links-page" placeholder="<?php _e('对方放置友链的页面地址', 'argon'); ?>">
</div>
<div class="form-group">
<label><?php _e('头像地址', 'argon'); ?></label>
<input type="url" id="edit-avatar">
</div>
<div class="form-group">
<label><?php _e('描述', 'argon'); ?></label>
<input type="text" id="edit-desc" maxlength="100">
</div>
<div class="form-group">
<label><?php _e('分类', 'argon'); ?></label>
<input type="text" id="edit-category">
</div>
<div class="form-group">
<label><?php _e('未上友链时', 'argon'); ?></label>
<select id="edit-hide-no-backlink">
<option value=""><?php _e('跟随全局设置', 'argon'); ?></option>
<option value="hide"><?php _e('隐藏', 'argon'); ?></option>
<option value="show"><?php _e('仍然显示', 'argon'); ?></option>
</select>
</div>
<div class="status-info" id="edit-status-info"></div>
<div class="form-actions">
<button type="button" class="btn btn-secondary" id="edit-fetch-btn"><?php _e('更新信息', 'argon'); ?></button>
<button type="button" class="btn btn-secondary" id="edit-check-btn"><?php _e('检测互链', 'argon'); ?></button>
<button type="button" class="btn btn-danger" id="edit-delete-btn"><?php _e('删除', 'argon'); ?></button>
<button type="button" class="btn btn-primary" id="edit-save-btn"><?php _e('保存', 'argon'); ?></button>
</div>
</div>
</div>
<?php endif; ?>
<script data-pjax>
function toggleApplyForm() {
var c = document.querySelector('.flinks-apply-content');
var a = document.querySelector('.flinks-apply-arrow');
if (c && a) { c.classList.toggle('open'); a.classList.toggle('open'); }
}
function copyText(t) {
navigator.clipboard ? navigator.clipboard.writeText(t).then(showCopyTip) : (function() {
var ta = document.createElement('textarea'); ta.value = t; document.body.appendChild(ta); ta.select(); document.execCommand('copy'); document.body.removeChild(ta); showCopyTip();
})();
}
function showCopyTip() {
var tip = document.createElement('span');
tip.textContent = '<?php _e('已复制', 'argon'); ?>';
tip.style.cssText = 'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);background:rgba(0,0,0,0.75);color:#fff;padding:10px 20px;border-radius:8px;font-size:14px;z-index:9999;';
document.body.appendChild(tip);
setTimeout(function() { tip.remove(); }, 1200);
}
// 刷新验证码
function refreshCaptcha() {
fetch('<?php echo admin_url('admin-ajax.php'); ?>?action=argon_get_captcha')
.then(function(r) { return r.json(); })
.then(function(res) {
if (res.captcha) {
document.getElementById('flink-captcha-text').textContent = res.captcha;
}
});
}
<?php if ($apply_result) : ?>
document.addEventListener('DOMContentLoaded', function() {
var s = document.getElementById('apply-section');
if (s) s.scrollIntoView({ behavior: 'smooth', block: 'center' });
// 清除 URL 中的申请结果参数
if (window.history && window.history.replaceState) {
var url = new URL(window.location.href);
url.searchParams.delete('apply_success');
url.searchParams.delete('apply_error');
window.history.replaceState({}, '', url.toString());
}
});
<?php endif; ?>
<?php if ($captcha_enabled && $captcha_type === 'geetest') : ?>
// 极验验证码
if (typeof initGeetest4 === 'function') {
initGeetest4({
captchaId: '<?php echo get_option('argon_geetest_captcha_id', ''); ?>',
product: 'bind'
}, function(captcha) {
captcha.appendTo('#flink-geetest-captcha');
document.getElementById('apply-submit-btn').addEventListener('click', function(e) {
e.preventDefault();
captcha.showCaptcha();
});
captcha.onSuccess(function() {
var result = captcha.getValidate();
document.getElementById('flink-lot-number').value = result.lot_number;
document.getElementById('flink-captcha-output').value = result.captcha_output;
document.getElementById('flink-pass-token').value = result.pass_token;
document.getElementById('flink-gen-time').value = result.gen_time;
document.getElementById('apply-form').submit();
});
});
}
<?php endif; ?>
<?php if ($is_admin) : ?>
(function() {
var nonce = '<?php echo wp_create_nonce('argon_flink_manage'); ?>';
var ajaxUrl = '<?php echo esc_url($_SERVER['REQUEST_URI']); ?>';
function flinkAction(action, data, callback) {
data.flink_action = action;
data.flink_nonce = nonce;
var fd = new FormData();
for (var k in data) fd.append(k, data[k]);
fetch(ajaxUrl, { method: 'POST', body: fd })
.then(function(r) { return r.json(); })
.then(callback)
.catch(function(e) { alert('<?php _e('操作失败', 'argon'); ?>'); });
}
// 移除自动审核标记
window.removeAutoTag = function(el) {
if (!confirm('<?php _e('确定移除自动审核标记?', 'argon'); ?>')) return;
var id = el.getAttribute('data-id');
flinkAction('update', { id: id, auto_approved: '' }, function(res) {
if (res.success) el.remove();
});
};
// 获取网站信息(服务器端)
document.getElementById('fetch-info')?.addEventListener('click', function() {
var url = document.getElementById('add-url').value.trim();
if (!url) return alert('<?php _e('请输入网址', 'argon'); ?>');
if (!/^https?:\/\//i.test(url)) url = 'https://' + url;
document.getElementById('add-url').value = url;
this.disabled = true; this.textContent = '...';
var btn = this;
flinkAction('fetch_info', { url: url }, function(res) {
btn.disabled = false; btn.textContent = '<?php _e('获取', 'argon'); ?>';
if (res.success && res.data) {
if (res.data.title) document.getElementById('add-display-name').value = res.data.title;
// 优先使用作者头像,没有才用 favicon
var avatar = res.data.author_avatar || res.data.favicon || '';
if (avatar) document.getElementById('add-avatar').value = avatar;
} else {
alert(res.message || '<?php _e('获取失败', 'argon'); ?>');
}
});
});
// 添加友链
document.getElementById('add-link-btn')?.addEventListener('click', function() {
var name = document.getElementById('add-name').value.trim();
var url = document.getElementById('add-url').value.trim();
if (!url) return alert('<?php _e('请填写网址', 'argon'); ?>');
if (!name) {
name = document.getElementById('add-display-name').value.trim();
if (!name) return alert('<?php _e('请填写名称', 'argon'); ?>');
}
this.disabled = true; this.textContent = '<?php _e('添加中...', 'argon'); ?>';
var btn = this;
flinkAction('add', {
name: name,
url: url,
display_name: document.getElementById('add-display-name').value.trim(),
avatar: document.getElementById('add-avatar').value.trim(),
description: document.getElementById('add-desc').value.trim(),
category: document.getElementById('add-category').value.trim()
}, function(res) {
if (res.success) location.reload();
else { btn.disabled = false; btn.textContent = '<?php _e('添加', 'argon'); ?>'; alert(res.message || '<?php _e('添加失败', 'argon'); ?>'); }
});
});
// 审核操作
document.querySelectorAll('.flink-approve').forEach(function(btn) {
btn.addEventListener('click', function() {
var id = this.dataset.id;
this.disabled = true;
flinkAction('approve', { id: id }, function(res) { if (res.success) location.reload(); });
});
});
document.querySelectorAll('.flink-reject').forEach(function(btn) {
btn.addEventListener('click', function() {
if (!confirm('<?php _e('确定拒绝?', 'argon'); ?>')) return;
var id = this.dataset.id;
this.disabled = true;
flinkAction('reject', { id: id }, function(res) { if (res.success) location.reload(); });
});
});
// 检测所有友链
document.getElementById('check-all-btn')?.addEventListener('click', function() {
if (!confirm('<?php _e('将检测所有友链的状态,可能需要一些时间,确定继续?', 'argon'); ?>')) return;
this.disabled = true; this.textContent = '<?php _e('检测中...', 'argon'); ?>';
flinkAction('check_all', {}, function(res) {
if (res.success) location.reload();
else alert('<?php _e('检测失败', 'argon'); ?>');
});
});
// 编辑弹窗
window.openEditModal = function(id) {
flinkAction('get', { id: id }, function(res) {
if (res.success && res.data) {
var link = res.data;
document.getElementById('edit-id').value = link.id;
document.getElementById('edit-name').value = link.name || '';
document.getElementById('edit-display-name').value = link.display_name || '';
document.getElementById('edit-url').value = link.url || '';
document.getElementById('edit-links-page').value = link.links_page || '';
document.getElementById('edit-avatar').value = link.avatar || '';
document.getElementById('edit-desc').value = link.description || '';
document.getElementById('edit-category').value = link.category || '';
document.getElementById('edit-hide-no-backlink').value = link.hide_no_backlink || '';
// 显示状态信息
var statusHtml = '';
if (link.last_check) {
var date = new Date(link.last_check * 1000);
statusHtml += '<?php _e('上次检测', 'argon'); ?>: ' + date.toLocaleString() + '<br>';
}
if (link.accessible === false) {
statusHtml += '<?php _e('网站状态', 'argon'); ?>: <span class="badge badge-danger"><?php _e('无法访问', 'argon'); ?></span><br>';
} else if (link.accessible === true) {
statusHtml += '<?php _e('网站状态', 'argon'); ?>: <span class="badge badge-success"><?php _e('正常', 'argon'); ?></span><br>';
}
if (link.has_backlink === false) {
statusHtml += '<?php _e('互链状态', 'argon'); ?>: <span class="badge badge-warning"><?php _e('未检测到本站链接', 'argon'); ?></span>';
} else if (link.has_backlink === true) {
statusHtml += '<?php _e('互链状态', 'argon'); ?>: <span class="badge badge-success"><?php _e('已上友链', 'argon'); ?></span>';
} else if (!link.links_page) {
statusHtml += '<?php _e('互链状态', 'argon'); ?>: <span class="badge badge-secondary"><?php _e('未填写友链页面', 'argon'); ?></span>';
}
document.getElementById('edit-status-info').innerHTML = statusHtml || '<?php _e('暂无检测记录', 'argon'); ?>';
document.getElementById('edit-modal').classList.add('show');
}
});
};
window.closeEditModal = function() {
document.getElementById('edit-modal').classList.remove('show');
};
document.getElementById('edit-modal')?.addEventListener('click', function(e) {
if (e.target === this) closeEditModal();
});
// 更新信息(从网站获取最新数据)
document.getElementById('edit-fetch-btn')?.addEventListener('click', function() {
var url = document.getElementById('edit-url').value.trim();
if (!url) return alert('<?php _e('请先填写网址', 'argon'); ?>');
if (!/^https?:\/\//i.test(url)) url = 'https://' + url;
this.disabled = true; this.textContent = '<?php _e('获取中...', 'argon'); ?>';
var btn = this;
flinkAction('fetch_info', { url: url }, function(res) {
btn.disabled = false; btn.textContent = '<?php _e('更新信息', 'argon'); ?>';
if (res.success && res.data) {
var displayName = document.getElementById('edit-display-name');
var avatar = document.getElementById('edit-avatar');
var desc = document.getElementById('edit-desc');
// 直接替换数据
if (res.data.title) displayName.value = res.data.title;
var newAvatar = res.data.author_avatar || res.data.favicon || '';
if (newAvatar) avatar.value = newAvatar;
if (res.data.description) desc.value = res.data.description;
// 显示获取结果
var statusInfo = document.getElementById('edit-status-info');
var infoHtml = '<div style="margin-top:10px;padding:10px;background:#e8f5e9;border-radius:6px;font-size:13px;">';
infoHtml += '<strong><?php _e('已更新', 'argon'); ?></strong>';
if (res.data.blocked_by_waf) {
infoHtml += ' <span style="color:#e91e63;">(<?php _e('被WAF拦截', 'argon'); ?>)</span>';
}
infoHtml += '</div>';
statusInfo.innerHTML = infoHtml;
} else {
alert(res.data?.error_reason || '<?php _e('获取失败', 'argon'); ?>');
}
});
});
// 检测互链
document.getElementById('edit-check-btn')?.addEventListener('click', function() {
var linksPage = document.getElementById('edit-links-page').value.trim();
if (!linksPage) {
return alert('<?php _e('请先填写对方的友链页面地址', 'argon'); ?>');
}
var id = document.getElementById('edit-id').value;
this.disabled = true; this.textContent = '<?php _e('检测中...', 'argon'); ?>';
var btn = this;
flinkAction('check_backlink', { id: id }, function(res) {
btn.disabled = false; btn.textContent = '<?php _e('检测互链', 'argon'); ?>';
if (res.success) {
openEditModal(id); // 刷新显示
}
});
});
// 保存编辑
document.getElementById('edit-save-btn')?.addEventListener('click', function() {
var id = document.getElementById('edit-id').value;
var name = document.getElementById('edit-name').value.trim();
var url = document.getElementById('edit-url').value.trim();
if (!name || !url) return alert('<?php _e('名称和网址不能为空', 'argon'); ?>');
this.disabled = true; this.textContent = '<?php _e('保存中...', 'argon'); ?>';
var btn = this;
flinkAction('update', {
id: id,
name: name,
display_name: document.getElementById('edit-display-name').value.trim(),
url: url,
links_page: document.getElementById('edit-links-page').value.trim(),
avatar: document.getElementById('edit-avatar').value.trim(),
description: document.getElementById('edit-desc').value.trim(),
category: document.getElementById('edit-category').value.trim(),
hide_no_backlink: document.getElementById('edit-hide-no-backlink').value
}, function(res) {
if (res.success) location.reload();
else { btn.disabled = false; btn.textContent = '<?php _e('保存', 'argon'); ?>'; alert('<?php _e('保存失败', 'argon'); ?>'); }
});
});
// 删除
document.getElementById('edit-delete-btn')?.addEventListener('click', function() {
if (!confirm('<?php _e('确定删除这个友链?', 'argon'); ?>')) return;
var id = document.getElementById('edit-id').value;
this.disabled = true; this.textContent = '<?php _e('删除中...', 'argon'); ?>';
flinkAction('delete', { id: id }, function(res) {
if (res.success) location.reload();
else alert('<?php _e('删除失败', 'argon'); ?>');
});
});
})();
<?php endif; ?>
</script>
<?php get_footer(); ?>