feat(links): move friend links to native WordPress links with review flow

- enable the native Links manager and drop the custom friend-link option/REST path
- add per-page link settings for the friends template
- render link categories from get_bookmarks() with search and page-content options
- add a validated public link submission endpoint with logo upload, captcha, rate limiting and duplicate checks
- create pending links for review and notify administrators by email and in-app message
- add native Links admin pending count, columns and edit notes
- cover the new submission and cleanup contracts

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
kate522andClaude Opus 5 committed 2026-11-05 19:54:33 +08:00
1 parent ef7b5939ba
commit 4c562428b4
24 files changed
+792 -273

No files matched your search

+19 -11
View File
@@ -84,14 +84,14 @@ if (!function_exists('jio_get_page_links_settings')) :
'order' => $order,
'go_s' => (bool) get_post_meta($post_id, 'page_links_go_s', true),
'blank_s' => (bool) get_post_meta($post_id, 'page_links_blank_s', true),
// Default nofollow ON (legacy default true).
'nofollow_s' => get_post_meta($post_id, 'page_links_nofollow_s', true) === ''
? true
: (bool) get_post_meta($post_id, 'page_links_nofollow_s', true),
// Default nofollow ON unless the page meta explicitly turns it off.
'nofollow_s' => metadata_exists('post', $post_id, 'page_links_nofollow_s')
? (bool) get_post_meta($post_id, 'page_links_nofollow_s', true)
: true,
'submit_s' => (bool) get_post_meta($post_id, 'page_links_submit_s', true),
'submit_sign_s' => get_post_meta($post_id, 'page_links_submit_sign_s', true) === ''
? true
: (bool) get_post_meta($post_id, 'page_links_submit_sign_s', true),
'submit_sign_s' => metadata_exists('post', $post_id, 'page_links_submit_sign_s')
? (bool) get_post_meta($post_id, 'page_links_submit_sign_s', true)
: true,
'submit_cats' => $submit_cats,
'submit_title' => (string) (get_post_meta($post_id, 'page_links_submit_title', true) ?: __('申请入驻', 'jio')),
'submit_dec' => (string) get_post_meta($post_id, 'page_links_submit_dec', true),
@@ -393,11 +393,11 @@ endif;
if (!function_exists('jio_submit_links_modal')) :
/**
* Frontend submit modal markup (legacy).
* Frontend link submission modal.
*
* @param array{title?:string,dec?:string,sign?:bool,cats?:int[]} $args
*/
function jio_submit_links_modal(array $args = []): string {
function jio_submit_links_modal(array $args = [], int $post_id = 0): string {
$defaults = [
'title' => __('申请入驻', 'jio'),
'dec' => '',
@@ -405,6 +405,7 @@ if (!function_exists('jio_submit_links_modal')) :
'cats' => [],
];
$args = array_merge($defaults, $args);
$post_id = $post_id > 0 ? $post_id : (int) get_queried_object_id();
$title = (string) $args['title'];
$header = $title !== ''
? '<div class="mb20"><button type="button" class="close" data-dismiss="modal" aria-label="' . esc_attr__('关闭', 'jio') . '">'
@@ -453,7 +454,7 @@ if (!function_exists('jio_submit_links_modal')) :
: '';
$placeholder_upload = get_template_directory_uri() . '/assets/img/placeholder.svg';
$body .= '<form class="form-horizontal mt10 form-upload jio-links-submit-form" enctype="multipart/form-data">';
$body .= '<form class="form-horizontal mt10 jio-links-submit-form" action="' . esc_url(admin_url('admin-ajax.php')) . '" method="post" enctype="multipart/form-data">';
$body .= '<div class="row gutters-5">';
$body .= '<div class="col-sm-6 mb10"><div class="em09 muted-2-color mb6">' . esc_html__('网站名称(必填)', 'jio') . '</div>'
. '<input type="text" class="form-control" name="link_name" required placeholder="' . esc_attr__('请输入网站名称', 'jio') . '"></div>';
@@ -468,11 +469,18 @@ if (!function_exists('jio_submit_links_modal')) :
. '<input class="hide jio-links-logo-input" type="file" accept="image/gif,image/jpeg,image/jpg,image/png" name="image"></label>'
. '<div class="px12 muted-2-color mb6">' . esc_html__('请选择正方形 LOGO,支持 jpg/png/gif', 'jio') . '</div></div>';
$body .= '</div>';
if (function_exists('jio_render_captcha')) {
ob_start();
jio_render_captcha('friend_link');
$body .= (string) ob_get_clean();
}
$body .= '<div class="jio-links-submit-status" role="status" aria-live="polite"></div>';
$body .= '<div class="text-right edit-footer">'
. '<button type="submit" class="but c-blue padding-lg jio-links-submit-btn"><i class="fa fas fa-check" aria-hidden="true"></i>'
. esc_html__('确认提交', 'jio') . '</button></div>';
$body .= wp_nonce_field('jio_frontend_links_submit', '_wpnonce', false, false);
$body .= wp_nonce_field('jio_frontend_links_submit_' . $post_id, '_wpnonce', false, false);
$body .= '<input type="hidden" name="action" value="jio_frontend_links_submit">';
$body .= '<input type="hidden" name="page_id" value="' . (int) $post_id . '">';
$body .= '</form>';
}
-18
View File
@@ -10,24 +10,6 @@ defined('ABSPATH') || exit;
// 模板标签:友情链接
// ============================================================
if (!function_exists('jio_get_friend_links')):
/**
* 获取友情链接列表(已激活的)
*
* @return array
*/
function jio_get_friend_links() {
if (class_exists('\Jio\Settings\Settings')) {
return \Jio\Settings\Settings::get_friend_links();
}
$links = get_option('jio_friend_links', array());
return array_values(array_filter($links, function($l) {
return !empty($l['active']);
}));
}
endif;
// ============================================================
// 模板标签:站点 Logo / Favicon / About
// ============================================================
+1
View File
@@ -377,6 +377,7 @@ function jio_captcha_scenes(): array {
'tip_user' => __('打赏用户', 'jio'),
'ticket_create' => __('提交工单', 'jio'),
'ticket_reply' => __('回复工单', 'jio'),
'friend_link' => __('友情链接申请', 'jio'),
];
}