Files
wordpress-theme-aksrt/inc/helpers/jio-links.php
T
kate522andClaude Opus 5 35bb96e82f refactor: rename the theme brand and every identifier from AKSRT to Jio
Full-project rename. `git grep -i aksrt` is now empty apart from the
DBMigrator 3.3.0 changelog note that documents the rename itself.

Code identifiers
- PHP namespace AKSRT\ -> Jio\ (composer PSR-4 + 378 declarations)
- global constants AKSRT_* -> JIO_* (VERSION/DIR/URI, PAY_TYPE_*, CAPTCHA_*)
- procedural functions, hooks, options, meta keys, table names,
  cookies, query vars, ajax actions and nonces: aksrt_ -> jio_
- text domain aksrt -> jio; Theme Name -> Jio
- JS globals: aksrtData/aksrtAdminData/... -> jioData/jioAdminData/...,
  window.AKSRTCaptcha & friends -> window.JioCaptcha, Aksrt* -> Jio*
- Vue components Aks*.vue -> Jio*.vue (15 files renamed + imports)
- CSS classes/data-attrs/custom properties: aksrt- -> jio-
- REST namespace aksrt/v1 -> jio/v1 (incl. payment gateway callbacks)

Storage layer
- DB tables {prefix}aksrt_* -> {prefix}jio_*; SCHEMA_VERSION 3.2.0 -> 3.3.0
  so dbDelta creates the new names on install
- widget id_base aksrt_widget_* -> jio_widget_*
- uninstall.php drop list rebuilt from the actual migrator tables
  (dropped 3 stale entries, added the 17 missing ones)

Removed
- hardcoded https://api.aksrt.com/version.json default update endpoint;
  get_endpoint() now reads the 「更新端点」 setting and do_check() no-ops
  when it is empty

Files renamed: inc/helpers/aksrt-*.php -> jio-*.php (54),
assets/admin/src/components/form/Aks*.vue -> Jio*.vue (15).
Build artifacts regenerated: assets/css/build, assets/js/runtime,
assets/admin/build.

Verified: audit-psr4-paths errors=0, audit-admin-contracts errors=0
(warnings=56, unchanged baseline), 813/813 widget-system tests,
44/44 phpunit, php -l clean across all PHP.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-11-01 20:05:04 +08:00

485 lines
21 KiB
PHP
Raw 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
/**
* 网址导航 / 书签链接渲染(legacy pages/links.php + legacy parity).
*
* @package Jio
*/
defined('ABSPATH') || exit;
if (!function_exists('jio_go_link')) :
/**
* Wrap external URL with /go/ intermediate page when enabled.
*/
function jio_go_link(string $url, bool $force = false): string {
$url = esc_url_raw($url);
if ($url === '') {
return '';
}
if (!$force && class_exists('\Jio\Settings\Settings') && empty(\Jio\Settings\Settings::get_value('seo_go_link', true))) {
return $url;
}
if (class_exists('\Jio\Core\GoRedirect')) {
return \Jio\Core\GoRedirect::get_instance()->create_go_link($url);
}
return $url;
}
endif;
if (!function_exists('jio_get_page_links_settings')) :
/**
* Read page_links_* meta for a page.
*
* @return array<string,mixed>
*/
function jio_get_page_links_settings(int $post_id = 0): array {
if ($post_id <= 0) {
$post_id = (int) get_queried_object_id();
}
$cats = get_post_meta($post_id, 'page_links_category', true);
if (!is_array($cats)) {
$cats = $cats !== '' && $cats !== null ? array_filter(array_map('intval', (array) $cats)) : [];
} else {
$cats = array_values(array_filter(array_map('intval', $cats)));
}
$search_types = get_post_meta($post_id, 'page_links_search_types', true);
if (!is_array($search_types)) {
$search_types = $search_types ? array_values(array_filter(array_map('sanitize_key', (array) $search_types))) : [];
} else {
$search_types = array_values(array_filter(array_map('sanitize_key', $search_types)));
}
$submit_cats = get_post_meta($post_id, 'page_links_submit_cats', true);
if (!is_array($submit_cats)) {
$submit_cats = $submit_cats !== '' && $submit_cats !== null ? array_filter(array_map('intval', (array) $submit_cats)) : [];
} else {
$submit_cats = array_values(array_filter(array_map('intval', $submit_cats)));
}
$style = sanitize_key((string) get_post_meta($post_id, 'page_links_style', true));
if (!in_array($style, ['card', 'bigcard', 'image', 'simple'], true)) {
$style = 'card';
}
$orderby = sanitize_key((string) get_post_meta($post_id, 'page_links_orderby', true));
if (!in_array($orderby, ['name', 'updated', 'rating', 'rand', 'id', 'length'], true)) {
$orderby = 'name';
}
$order = strtoupper((string) get_post_meta($post_id, 'page_links_order', true));
if (!in_array($order, ['ASC', 'DESC'], true)) {
$order = 'ASC';
}
$position = sanitize_key((string) get_post_meta($post_id, 'page_links_content_position', true));
if (!in_array($position, ['top', 'bottom'], true)) {
$position = 'top';
}
return [
'content_s' => (bool) get_post_meta($post_id, 'page_links_content_s', true),
'content_position' => $position,
'search_s' => (bool) get_post_meta($post_id, 'page_links_search_s', true),
'search_types' => $search_types,
'category' => $cats,
'style' => $style,
'limit' => max(0, (int) get_post_meta($post_id, 'page_links_limit', true)),
'orderby' => $orderby,
'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),
'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_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),
];
}
endif;
if (!function_exists('jio_links_box')) :
/**
* Render bookmark cards (legacy).
*
* @param array<int,object|array> $links Bookmark rows from get_bookmarks().
*/
function jio_links_box($links = [], string $type = 'card', bool $nofollow = true, bool $go_link = false, bool $blank_s = false): string {
if (empty($links) || !is_array($links)) {
return '';
}
$type = in_array($type, ['card', 'bigcard', 'image', 'simple'], true) ? $type : 'card';
$placeholder = get_template_directory_uri() . '/assets/img/placeholder.svg';
$html = '';
$i = 0;
foreach ($links as $raw) {
$link = (array) $raw;
if (empty($link['href']) && !empty($link['link_url'])) {
$link['href'] = $link['link_url'];
}
if (empty($link['title']) && !empty($link['link_name'])) {
$link['title'] = $link['link_name'];
}
if (empty($link['src']) && !empty($link['link_image'])) {
$link['src'] = $link['link_image'];
}
if (empty($link['desc']) && !empty($link['link_description'])) {
$link['desc'] = $link['link_description'];
}
if ($blank_s) {
$link['blank'] = true;
}
if (empty($link['blank']) && !empty($link['link_target'])) {
$link['blank'] = true;
}
$href = !empty($link['href']) ? (string) $link['href'] : '';
$title = !empty($link['title']) ? (string) $link['title'] : '';
if ($href === '' || $title === '') {
continue;
}
if ($go_link || !empty($link['go_link'])) {
$href = jio_go_link($href, true);
} else {
$href = esc_url($href);
}
$src = !empty($link['src']) ? esc_url((string) $link['src']) : '';
$blank = !empty($link['blank']) ? ' target="_blank"' : '';
$dec = !empty($link['desc']) ? (string) $link['desc'] : '';
$rel = $nofollow ? ' rel="nofollow noopener noreferrer"' : ' rel="noopener noreferrer"';
$img_src = $src !== '' ? $src : $placeholder;
$img = '<img' . jio_get_lazy_attr('lazy_other', $img_src, 'avatar') . ' alt="">';
$data_dec = $dec !== ''
? ' title="' . esc_attr($title) . '" data-content="' . esc_attr($dec) . '"'
: ' data-content="' . esc_attr($title) . '"';
if ($type === 'bigcard') {
$html .= '<div class="author-minicard links-card radius8 big-card">';
$html .= '<a' . $blank . ' href="' . esc_url($href) . '" title="' . esc_attr($dec) . '"' . $rel . '>';
$html .= '<div class="avatar-img link-img">' . $img . '</div>';
$html .= '<div class="text-ellipsis mt20 font-bold">' . esc_html($title) . '</div>';
if ($dec !== '') {
$html .= '<dd class="mt6 avatar-dest em09 muted-3-color text-ellipsis">' . esc_html($dec) . '</dd>';
}
$html .= '</a></div>';
} elseif ($type === 'image') {
$html .= '<a' . $blank . ' class="avatar-img link-img link-only-img" data-trigger="hover" data-toggle="popover" data-placement="top"'
. $data_dec . ' href="' . esc_url($href) . '"' . $rel . '>' . $img . '</a>';
} elseif ($type === 'simple') {
$sc = $i === 0 ? '' : 'icon-spot';
$html .= '<a' . $blank . ' class="' . esc_attr($sc) . '" data-trigger="hover" data-toggle="popover" data-placement="top"'
. $data_dec . ' href="' . esc_url($href) . '"' . $rel . '>' . esc_html($title) . '</a>';
} else {
$html .= '<div class="author-minicard links-card radius8"><a' . $blank . ' href="' . esc_url($href) . '" title="' . esc_attr($dec) . '"' . $rel . '>';
$html .= '<ul class="list-inline">';
$html .= '<li><div class="avatar-img link-img">' . $img . '</div></li>';
$html .= '<li><dl><dt class="text-ellipsis">' . esc_html($title) . '</dt>';
if ($dec !== '') {
$html .= '<dd class="mt3 avatar-dest em09 muted-3-color text-ellipsis">' . esc_html($dec) . '</dd>';
}
$html .= '</dl></li></ul></a></div>';
}
$i++;
}
return $html;
}
endif;
if (!function_exists('jio_page_links_html')) :
/**
* Build the multi/single category links block for a page.
*/
function jio_page_links_html(int $post_id = 0): string {
$post_id = $post_id > 0 ? $post_id : (int) get_queried_object_id();
$s = jio_get_page_links_settings($post_id);
$cats = $s['category'];
if (empty($cats)) {
if (current_user_can('manage_links')) {
return '<div class="mb20"><a class="author-minicard links-card radius8" href="' . esc_url(admin_url('link-manager.php')) . '" target="_blank" rel="noopener">'
. esc_html__('添加链接', 'jio') . '</a></div>';
}
return '<div class="author-minicard links-card radius8 mb20">' . esc_html__('暂无链接', 'jio') . '</div>';
}
$limit = (int) $s['limit'];
$orderby = (string) $s['orderby'];
$order = (string) $s['order'];
$style = (string) $s['style'];
$nofollow = (bool) $s['nofollow_s'];
$go_s = (bool) $s['go_s'];
$blank_s = (bool) $s['blank_s'];
$submit_s = (bool) $s['submit_s'];
$submit_title = (string) $s['submit_title'];
$is_mobile = wp_is_mobile();
$links_con = '';
if (count($cats) > 1) {
$link_cat_con = '';
$link_cat_nav = '';
foreach ($cats as $cat_id) {
$args = [
'orderby' => $orderby,
'order' => $order,
'limit' => $limit > 0 ? $limit : -1,
'category' => (int) $cat_id,
];
$_link = jio_links_box(get_bookmarks($args), $style, $nofollow, $go_s, $blank_s);
if (!$_link) {
continue;
}
$term = get_term((int) $cat_id, 'link_category');
if (!$term || is_wp_error($term)) {
continue;
}
$_id = 'links-' . (int) $cat_id;
$link_cat_con .= '<div class="mb20 links-cat-box"><div class="links-cat-header"><div class="title-theme"><div id="' . esc_attr($_id) . '">'
. esc_html($term->name) . '</div></div></div><div class="links-box links-style-' . esc_attr($style) . '">' . $_link . '</div></div>';
$link_cat_nav .= '<li class="n-H2"><a class="text-ellipsis" href="#' . esc_attr($_id) . '">' . esc_html($term->name) . '</a></li>';
}
if ($link_cat_con === '') {
$links_con = '';
} else {
$submit_nav = $submit_s
? '<div class="link-nav-submit"><a class="padding-h10 hollow but c-theme btn-block text-ellipsis" href="#submit-links-modal" data-toggle="modal">'
. esc_html($submit_title) . '</a></div>'
: '';
$submit_con = $submit_s
? '<div class="link-cat-submit"><a class="padding-h10 hollow but c-theme btn-block text-ellipsis" href="#submit-links-modal" data-toggle="modal">'
. esc_html($submit_title) . '</a></div>'
: '';
$offset_top = $is_mobile ? '-8' : '';
$offset_bottom = $is_mobile ? '20' : '-30';
$links_con = '<div class="fixed-wrap">'
. '<div class="fixed-wrap-nav affix-header-sm affix link-nav-box tab-auto-center-sm" data-offset-top="' . esc_attr((string) $offset_top) . '" data-offset-bottom="' . esc_attr((string) $offset_bottom) . '">'
. '<div class="jio-panel"><ul class="nav list-inline scroll-x mini-scrollbar tab-nav-theme">' . $link_cat_nav . '</ul></div>'
. $submit_nav
. '</div><div class="fixed-wrap-content">' . $link_cat_con . $submit_con . '</div></div>';
}
} else {
$cat_id = (int) $cats[0];
$args = [
'orderby' => $orderby,
'order' => $order,
'limit' => $limit > 0 ? $limit : -1,
'category' => $cat_id,
];
$submit_con = $submit_s
? '<div class="mt20"><a class="padding-h10 hollow but c-theme btn-block text-ellipsis" href="#submit-links-modal" data-toggle="modal">'
. esc_html($submit_title) . '</a></div>'
: '';
$links_con = '<div class="links-box links-style-' . esc_attr($style) . '">'
. jio_links_box(get_bookmarks($args), $style, $nofollow, $go_s, $blank_s)
. '</div>' . $submit_con;
}
if ($links_con === '') {
if (current_user_can('manage_links')) {
return '<div class="mb20"><a class="author-minicard links-card radius8" href="' . esc_url(admin_url('link-manager.php')) . '" target="_blank" rel="noopener">'
. esc_html__('添加链接', 'jio') . '</a></div>';
}
return '<div class="author-minicard links-card radius8 mb20">' . esc_html__('暂无链接', 'jio') . '</div>';
}
return '<div class="links-page-container mb20">' . $links_con . '</div>';
}
endif;
if (!function_exists('jio_link_get_search_cover')) :
/**
* Search cover with multi-engine tabs (legacy).
*/
function jio_link_get_search_cover(int $post_id = 0): string {
$post_id = $post_id > 0 ? $post_id : (int) get_queried_object_id();
$s = jio_get_page_links_settings($post_id);
if (empty($s['search_s']) || empty($s['search_types'])) {
return '';
}
$search_types_args = [
'self' => [
'name' => __('站内', 'jio'),
'input_name' => 's',
'url' => home_url('/'),
],
'baidu' => [
'name' => __('百度', 'jio'),
'input_name' => 'wd',
'url' => 'https://www.baidu.com/s',
],
'google' => [
'name' => __('谷歌', 'jio'),
'input_name' => 'q',
'url' => 'https://www.google.com/search',
],
'bing' => [
'name' => __('必应', 'jio'),
'input_name' => 'q',
'url' => 'https://cn.bing.com/search',
],
'sogou' => [
'name' => __('搜狗', 'jio'),
'input_name' => 'query',
'url' => 'https://www.sogou.com/web',
],
'360' => [
'name' => '360',
'input_name' => 'q',
'url' => 'https://www.so.com/s',
],
];
$type_nav = '';
$type_con = '';
$i = 0;
foreach ($s['search_types'] as $k) {
if (!isset($search_types_args[$k])) {
continue;
}
$cfg = $search_types_args[$k];
$active = $i === 0 ? ' active' : '';
$pane_id = 'link-page-' . $post_id . '-' . $k;
$type_nav .= '<li class="' . esc_attr(trim($active)) . '"><a href="javascript:;" data-jio-tab-target="#' . esc_attr($pane_id) . '">'
. esc_html($cfg['name']) . '</a></li>';
$type_con .= '<div class="tab-pane' . ($i === 0 ? ' in active' : '') . '" id="' . esc_attr($pane_id) . '">'
. '<form method="get" target="_blank" class="padding-10 search-form" action="' . esc_url($cfg['url']) . '">'
. '<div class="line-form blur-bg"><div class="search-input-text">'
. '<input type="text" name="' . esc_attr($cfg['input_name']) . '" class="line-form-input" tabindex="1" value="" autocomplete="off">'
. '<i class="line-form-line"></i>'
. '<div class="scale-placeholder">' . esc_html(sprintf(__('%s搜索', 'jio'), $cfg['name'])) . '</div>'
. '<div class="abs-right muted-color"><button type="submit" tabindex="2" class="null" aria-label="' . esc_attr__('搜索', 'jio') . '">'
. '<i class="fa fas fa-search" aria-hidden="true"></i></button></div>'
. '</div></div></form></div>';
$i++;
}
if ($type_nav === '') {
return '';
}
$title = get_the_title($post_id);
$img = '';
$thumb_id = get_post_thumbnail_id($post_id);
if ($thumb_id) {
$image = wp_get_attachment_image_src($thumb_id, 'full');
$img = !empty($image[0]) ? (string) $image[0] : '';
}
if ($img === '') {
$img = (string) get_post_meta($post_id, 'page_header_cover_img', true);
}
if ($img === '' && class_exists('\Jio\Settings\Settings')) {
$other = \Jio\Settings\Settings::get_other_page_settings();
$img = (string) ($other['header_cover_img'] ?? '');
}
if ($img === '') {
$img = get_template_directory_uri() . '/assets/img/placeholder.svg';
}
$src = get_template_directory_uri() . '/assets/img/placeholder.svg';
$search = '<div class="header-slider-search abs-center"><div class="header-slider-search-more text-center before">'
. '<div class="em14 font-bold mb10">' . esc_html($title) . '</div></div>'
. '<div class="search-input"><div class="flex jc"><ul class="list-inline scroll-x mini-scrollbar tab-nav-theme">' . $type_nav . '</ul></div>'
. '<div class="tab-content">' . $type_con . '</div></div></div>';
return '<div class="page-cover theme-box radius8 main-shadow link-page-search-cover">'
. '<img' . jio_get_lazy_attr('lazy_cover', (string) $img, 'fit-cover no-scale', (string) $src) . ' alt="">'
. $search . '</div>';
}
endif;
if (!function_exists('jio_submit_links_modal')) :
/**
* Frontend submit modal markup (legacy).
*
* @param array{title?:string,dec?:string,sign?:bool,cats?:int[]} $args
*/
function jio_submit_links_modal(array $args = []): string {
$defaults = [
'title' => __('申请入驻', 'jio'),
'dec' => '',
'sign' => true,
'cats' => [],
];
$args = array_merge($defaults, $args);
$title = (string) $args['title'];
$header = $title !== ''
? '<div class="mb20"><button type="button" class="close" data-dismiss="modal" aria-label="' . esc_attr__('关闭', 'jio') . '">'
. '<i class="fa fas fa-times" aria-hidden="true"></i></button>'
. '<b class="modal-title flex ac"><span class="toggle-radius mr10 b-theme"><i class="fa fas fa-edit" aria-hidden="true"></i></span>'
. esc_html($title) . '</b></div>'
: '';
$body = '';
if (!empty($args['dec'])) {
$body .= '<div class="muted-box em09">' . wp_kses_post((string) $args['dec']) . '</div>';
}
$need_login = !empty($args['sign']) && !is_user_logged_in();
if ($need_login) {
$sign_url = function_exists('jio_get_login_url')
? jio_get_login_url()
: (function_exists('jio_get_sign_page_url') ? jio_get_sign_page_url('login') : wp_login_url());
$body .= '<div class="muted-box text-center">';
$body .= '<div class="mb20 muted-3-color">' . esc_html__('请先登录', 'jio') . '</div>';
$body .= '<p><a href="' . esc_url($sign_url) . '" class="signin-loader but c-blue padding-lg">'
. '<i class="fa fas fa-fw fa-sign-in-alt mr10" aria-hidden="true"></i>' . esc_html__('登录', 'jio') . '</a></p>';
if (class_exists('\Jio\Auth\OAuth') && method_exists(\Jio\Auth\OAuth::get_instance(), 'render_social_buttons')) {
$body .= (string) \Jio\Auth\OAuth::get_instance()->render_social_buttons(__('使用以下方式快速登录', 'jio'));
}
$body .= '</div>';
} else {
$term_args = [
'taxonomy' => 'link_category',
'hide_empty' => false,
];
if (!empty($args['cats']) && is_array($args['cats'])) {
$term_args['include'] = array_map('intval', $args['cats']);
$term_args['orderby'] = 'include';
}
$terms = get_terms($term_args);
$cats_options = '';
if (!is_wp_error($terms) && !empty($terms)) {
foreach ($terms as $item) {
$cats_options .= '<option value="' . (int) $item->term_id . '">' . esc_html($item->name) . '</option>';
}
}
$cats_field = $cats_options !== ''
? '<div class="col-sm-12 mb10"><div class="em09 muted-2-color mb6">' . esc_html__('网站类别', 'jio') . '</div>'
. '<div class="form-select"><select name="link_category" class="form-control">' . $cats_options . '</select></div></div>'
: '';
$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 .= '<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>';
$body .= '<div class="col-sm-6 mb10"><div class="em09 muted-2-color mb6">' . esc_html__('网站地址(必填)', 'jio') . '</div>'
. '<input type="url" class="form-control" name="link_url" required placeholder="https://..."></div>';
$body .= '<div class="col-sm-12 mb10"><div class="em09 muted-2-color mb6">' . esc_html__('网站简介', 'jio') . '</div>'
. '<input type="text" class="form-control" name="link_description" placeholder="' . esc_attr__('一句话介绍网站', 'jio') . '"></div>';
$body .= $cats_field;
$body .= '<div class="col-sm-12 mb10"><div class="em09 muted-2-color mb6">' . esc_html__('LOGO图像', 'jio') . '</div>'
. '<label class="pointer"><div class="preview preview-square"><img class="fit-cover jio-links-logo-preview" src="'
. esc_url($placeholder_upload) . '" alt=""></div>'
. '<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>';
$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 .= '<input type="hidden" name="action" value="jio_frontend_links_submit">';
$body .= '</form>';
}
return '<div class="modal fade" id="submit-links-modal" tabindex="-1" role="dialog" aria-hidden="true">'
. '<div class="modal-dialog" role="document"><div class="modal-content"><div class="modal-body">'
. $header . $body
. '</div></div></div></div>';
}
endif;