feat(share): align social sharing runtime

This commit is contained in:
2026-09-27 13:49:32 +08:00
parent 26ac8167f3
commit cf6c11852e
33 changed files with 802 additions and 1919 deletions
+1
View File
@@ -33,6 +33,7 @@ require_once AKSRT_DIR . '/inc/helpers/homepage/content.php';
require_once AKSRT_DIR . '/inc/helpers/homepage/header-components.php';
require_once AKSRT_DIR . '/inc/helpers/homepage/layout.php';
require_once AKSRT_DIR . '/inc/helpers/aksrt-single-components.php';
require_once AKSRT_DIR . '/inc/helpers/aksrt-share.php';
require_once AKSRT_DIR . '/inc/helpers/aksrt-single.php';
require_once AKSRT_DIR . '/inc/helpers/aksrt-yiyan.php';
require_once AKSRT_DIR . '/inc/helpers/aksrt-single-render.php';
-4
View File
@@ -61,10 +61,6 @@ if (!function_exists('aksrt_resolve_single_post_display_settings')) :
'yiyan_footer' => false,
'yiyan_box' => false,
];
// Normalize legacy aliases → canonical render keys (idempotent).
if (!array_key_exists('share_enabled', $settings) && array_key_exists('share_s', $settings)) {
$settings['share_enabled'] = !empty($settings['share_s']);
}
if (!array_key_exists('hide_time', $settings) && array_key_exists('single_hide_time_s', $settings)) {
$settings['hide_time'] = !empty($settings['single_hide_time_s']);
}
+262
View File
@@ -0,0 +1,262 @@
<?php
/**
* Social sharing and poster runtime.
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
if (!function_exists('aksrt_share_platform_labels')) {
/** @return array<string,string> */
function aksrt_share_platform_labels(): array {
return [
'qzone' => __('QQ空间', 'aksrt'), 'weibo' => __('微博', 'aksrt'), 'qq' => __('QQ好友', 'aksrt'),
'facebook' => 'Facebook', 'twitter' => 'X', 'telegram' => 'Telegram', 'whatsapp' => 'WhatsApp',
'linkedin' => 'LinkedIn', 'reddit' => 'Reddit', 'line' => 'LINE', 'vk' => 'VK',
'email' => __('邮件', 'aksrt'), 'poster' => __('海报分享', 'aksrt'), 'copy' => __('复制链接', 'aksrt'),
];
}
}
if (!function_exists('aksrt_active_share_items')) {
/** @return string[] */
function aksrt_active_share_items(): array {
$config = class_exists('\\AKSRT\\Settings\\Settings') ? \AKSRT\Settings\Settings::get_share_settings() : [];
return !empty($config['enabled']) && is_array($config['items'] ?? null) ? $config['items'] : [];
}
}
if (!function_exists('aksrt_build_share_url')) {
/** @param array<string,string> $params */
function aksrt_build_share_url(string $base, array $params): string {
$query = [];
foreach ($params as $key => $value) {
if ($value !== '') {
$query[] = rawurlencode($key) . '=' . rawurlencode($value);
}
}
return $query ? $base . (str_contains($base, '?') ? '&' : '?') . implode('&', $query) : $base;
}
}
if (!function_exists('aksrt_share_context')) {
/** @return array{id:int,title:string,link_title:string,desc:string,image:string,url:string,tags:string} */
function aksrt_share_context($post = null): array {
$post = get_post($post);
if (!$post instanceof WP_Post) {
return ['id' => 0, 'title' => '', 'link_title' => '', 'desc' => '', 'image' => '', 'url' => '', 'tags' => ''];
}
$subtitle = class_exists('\\AKSRT\\Core\\PostMetaBox')
? trim((string) \AKSRT\Core\PostMetaBox::get_meta_value((int) $post->ID, 'subtitle', ''))
: '';
$title = trim(wp_strip_all_tags(get_the_title($post))) . $subtitle;
$desc = trim(wp_strip_all_tags((string) get_the_excerpt($post)));
if ($desc === '') {
$desc = wp_trim_words(wp_strip_all_tags(strip_shortcodes($post->post_content)), 70, '...');
}
$url = (string) (get_permalink($post) ?: '');
if (is_user_logged_in() && class_exists('\\AKSRT\\Settings\\Settings') && \AKSRT\Settings\Settings::affiliate_enabled()
&& class_exists('\\AKSRT\\Payment\\ReferralAttribution')) {
$link = \AKSRT\Payment\ReferralAttribution::get_instance()->create_link(get_current_user_id(), $url);
if (!empty($link['url'])) {
$url = (string) $link['url'];
}
}
$tags = '';
if ($post->post_type === 'post') {
$author = get_the_author_meta('display_name', (int) $post->post_author);
$cats = get_the_category((int) $post->ID);
$tags = sprintf(__('作者: %s', 'aksrt'), $author);
if (!empty($cats[0])) {
$tags .= sprintf(__(' · 分类: %s', 'aksrt'), $cats[0]->name);
}
}
$site = (string) get_bloginfo('name');
return [
'id' => (int) $post->ID,
'title' => $title,
'link_title' => $title . ($site !== '' ? ' - ' . $site : ''),
'desc' => $desc,
'image' => (string) (get_the_post_thumbnail_url($post, 'full') ?: ''),
'url' => $url,
'tags' => $tags,
];
}
}
if (!function_exists('aksrt_share_platform_href')) {
/** @param array<string,mixed> $ctx */
function aksrt_share_platform_href(string $key, array $ctx): string {
$url = (string) ($ctx['url'] ?? '');
$title = (string) ($ctx['link_title'] ?? '');
$desc = (string) ($ctx['desc'] ?? '');
$image = (string) ($ctx['image'] ?? '');
switch ($key) {
case 'qzone': return aksrt_build_share_url('https://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey', ['url' => $url, 'title' => $title, 'pics' => $image, 'summary' => $desc]);
case 'weibo': return aksrt_build_share_url('https://service.weibo.com/share/share.php', ['url' => $url, 'title' => $title, 'pic' => $image, 'searchPic' => 'false']);
case 'qq': return aksrt_build_share_url('https://connect.qq.com/widget/shareqq/index.html', ['url' => $url, 'title' => $title, 'pics' => $image, 'desc' => $desc]);
case 'facebook': return aksrt_build_share_url('https://www.facebook.com/sharer/sharer.php', ['u' => $url]);
case 'twitter': return aksrt_build_share_url('https://twitter.com/intent/tweet', ['url' => $url, 'text' => $title]);
case 'telegram': return aksrt_build_share_url('https://t.me/share/url', ['url' => $url, 'text' => $title]);
case 'whatsapp': return aksrt_build_share_url('https://api.whatsapp.com/send', ['text' => trim($title . ' ' . $url)]);
case 'linkedin': return aksrt_build_share_url('https://www.linkedin.com/sharing/share-offsite/', ['url' => $url]);
case 'reddit': return aksrt_build_share_url('https://www.reddit.com/submit', ['url' => $url, 'title' => $title]);
case 'line': return aksrt_build_share_url('https://social-plugins.line.me/lineit/share', ['url' => $url]);
case 'vk': return aksrt_build_share_url('https://vk.com/share.php', ['url' => $url, 'title' => $title, 'image' => $image]);
case 'email': return aksrt_build_share_url('mailto:', ['subject' => $title, 'body' => trim($title . "\n" . $url . ($desc !== '' ? "\n\n" . $desc : ''))]);
default: return '#';
}
}
}
if (!function_exists('aksrt_get_share_buttons')) {
/** @param string[] $items */
function aksrt_get_share_buttons(array $items, $post = null): string {
$ctx = aksrt_share_context($post);
if ($ctx['id'] <= 0 || $ctx['url'] === '') {
return '';
}
$labels = aksrt_share_platform_labels();
$html = '';
foreach ($items as $key) {
$key = sanitize_key((string) $key);
if (!isset($labels[$key])) {
continue;
}
$icon_key = $key === 'email' ? 'd-email' : $key . '-color';
$icon = function_exists('aksrt_icon_markup') ? aksrt_icon_markup('zibsvg-' . $icon_key) : '';
$attr = '';
$target = ' target="_blank"';
$href = aksrt_share_platform_href($key, $ctx);
if ($key === 'poster') {
$target = '';
$attr = ' poster-share="' . esc_attr((string) $ctx['id']) . '"';
} elseif ($key === 'copy') {
$target = '';
$attr = ' data-clipboard-text="' . esc_attr($ctx['url']) . '" data-clipboard-tag="' . esc_attr__('链接', 'aksrt') . '"';
}
$safe_href = $href === '#' ? '#' : esc_url($href);
$html .= '<a rel="nofollow noopener" class="share-btn ' . esc_attr($key) . '"' . $target . $attr
. ' title="' . esc_attr($labels[$key]) . '" href="' . $safe_href . '"><icon>' . $icon
. '</icon><text>' . esc_html($labels[$key]) . '</text></a>';
}
return $html;
}
}
if (!function_exists('aksrt_get_share_html')) {
function aksrt_get_share_html(string $class = '', $post = null): string {
$buttons = aksrt_get_share_buttons(aksrt_active_share_items(), $post);
return $buttons === '' ? '' : '<div' . ($class !== '' ? ' class="' . esc_attr($class) . '"' : '') . '>' . $buttons . '</div>';
}
}
if (!function_exists('aksrt_render_share_buttons')) {
/** @param array<string,mixed> $args */
function aksrt_render_share_buttons(array $args = []): void {
echo aksrt_get_share_html(!empty($args['horizontal']) ? 'horizontal' : '', $args['post'] ?? null); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
}
if (!function_exists('aksrt_get_post_share_btn')) {
function aksrt_get_post_share_btn($post = null, string $class = '', bool $modal = false, bool $show_text = true): string {
$post = get_post($post);
if (!$post instanceof WP_Post || aksrt_active_share_items() === []) {
return '';
}
$icon = function_exists('aksrt_icon_markup') ? aksrt_icon_markup('zibsvg-share') : '<i class="fa fas fa-share-alt"></i>';
$text = $show_text ? '<text>' . esc_html__('分享', 'aksrt') . '</text>' : '';
if ($modal || wp_is_mobile()) {
$count = max(1, count(aksrt_active_share_items()));
$url = add_query_arg(['action' => 'aksrt_share_modal', 'id' => (int) $post->ID, 'nonce' => wp_create_nonce('aksrt_public_nonce')], admin_url('admin-ajax.php'));
return '<a class="' . esc_attr(trim($class . ' aksrt-modal-link')) . '" href="' . esc_url($url) . '" data-aksrt-modal="remote" data-aksrt-modal-url="' . esc_url($url)
. '" data-aksrt-modal-class="modal-mini" data-aksrt-modal-height="' . esc_attr((string) min(520, 180 + (int) ceil($count / 5) * 72))
. '" data-aksrt-modal-mobile-bottom="true" data-aksrt-modal-cache="false">' . $icon . $text . '</a>';
}
return '<span class="hover-show dropup ' . esc_attr($class) . '">' . $icon . $text
. '<div class="zib-widget hover-show-con share-button dropdown-menu">' . aksrt_get_share_html('', $post) . '</div></span>';
}
}
if (!function_exists('aksrt_share_modal_ajax')) {
function aksrt_share_modal_ajax(): void {
check_ajax_referer('aksrt_public_nonce', 'nonce');
$post = get_post(absint($_REQUEST['id'] ?? 0));
if (!$post instanceof WP_Post || get_post_status($post) !== 'publish') {
status_header(404);
echo '<div class="box-body text-center">' . esc_html__('内容不存在或参数错误', 'aksrt') . '</div>';
exit;
}
$icon = function_exists('aksrt_icon_markup') ? aksrt_icon_markup('zibsvg-share', 'em14') : '';
echo '<div class="modal-colorful-header colorful-bg jb-vip1"><button type="button" class="close" data-aksrt-modal-close aria-label="' . esc_attr__('关闭', 'aksrt') . '">'
. (function_exists('aksrt_icon_markup') ? aksrt_icon_markup('zibsvg-close', 'ic-close') : '&times;')
. '</button><div class="colorful-make"></div><div class="text-center"><div class="em2x">' . $icon
. '</div><div class="mt10 em12 padding-w10"><span class="em09">' . esc_html__('分享内容', 'aksrt') . '</span></div></div></div>'
. aksrt_get_share_html('horizontal', $post); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
exit;
}
add_action('wp_ajax_aksrt_share_modal', 'aksrt_share_modal_ajax');
add_action('wp_ajax_nopriv_aksrt_share_modal', 'aksrt_share_modal_ajax');
}
if (!function_exists('aksrt_share_image_data_url')) {
function aksrt_share_image_data_url(string $url): string {
if ($url === '' || !wp_http_validate_url($url)) {
return $url;
}
$key = 'aksrt_share_img_' . md5($url);
$cached = wp_cache_get($key, 'aksrt_share');
if (is_string($cached)) {
return $cached;
}
$response = wp_safe_remote_get($url, ['timeout' => 8, 'redirection' => 3, 'limit_response_size' => 5 * MB_IN_BYTES]);
if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
return $url;
}
$mime = strtolower(trim((string) wp_remote_retrieve_header($response, 'content-type')));
$mime = trim(explode(';', $mime)[0]);
if (!in_array($mime, ['image/jpeg', 'image/png', 'image/gif', 'image/webp'], true)) {
return $url;
}
$body = wp_remote_retrieve_body($response);
if ($body === '') {
return $url;
}
$data = 'data:' . $mime . ';base64,' . base64_encode($body);
wp_cache_set($key, $data, 'aksrt_share', HOUR_IN_SECONDS);
return $data;
}
}
if (!function_exists('aksrt_poster_share_data_ajax')) {
function aksrt_poster_share_data_ajax(): void {
check_ajax_referer('aksrt_public_nonce', 'nonce');
$post = get_post(absint($_POST['id'] ?? 0));
if (!$post instanceof WP_Post || get_post_status($post) !== 'publish') {
wp_send_json_error(['message' => __('参数错误,或内容已删除', 'aksrt')], 404);
}
$config = class_exists('\\AKSRT\\Settings\\Settings') ? \AKSRT\Settings\Settings::get_share_settings() : [];
if (empty($config['poster_enabled'])) {
wp_send_json_error(['message' => __('海报分享未启用', 'aksrt')], 403);
}
$ctx = aksrt_share_context($post);
$data = [
'url' => esc_url_raw($ctx['url']), 'banner' => esc_url_raw($ctx['image']),
'banner_default' => esc_url_raw((string) ($config['poster_img'] ?? '')),
'banner_spare' => get_template_directory_uri() . '/assets/img/share_img.jpg',
'logo' => esc_url_raw((string) ($config['poster_logo'] ?? '')),
'title' => function_exists('aksrt_str_cut') ? aksrt_str_cut($ctx['title'], 0, 32) : $ctx['title'],
'content' => function_exists('aksrt_str_cut') ? aksrt_str_cut($ctx['desc'], 0, 70) : $ctx['desc'],
'tags' => $ctx['tags'], 'description' => (string) ($config['share_desc'] ?? __('扫一扫 立即查看', 'aksrt')),
];
if (!empty($config['compatible_s'])) {
foreach (['banner', 'banner_default', 'logo'] as $key) {
$data[$key] = aksrt_share_image_data_url((string) $data[$key]);
}
}
wp_send_json_success(apply_filters('aksrt_poster_share_data', $data, $post));
}
add_action('wp_ajax_aksrt_poster_share_data', 'aksrt_poster_share_data_ajax');
add_action('wp_ajax_nopriv_aksrt_poster_share_data', 'aksrt_poster_share_data_ajax');
}
+1 -1
View File
@@ -141,7 +141,7 @@ if (!function_exists('aksrt_get_single_meta_box')) :
if ($edit_link) {
$more .= '<a href="' . esc_url($edit_link) . '" class="post-drop-meta__item"><i class="fa fas fa-edit" aria-hidden="true"></i><span>' . esc_html__('编辑文章', 'aksrt') . '</span></a>';
}
$more .= '<button type="button" class="post-drop-meta__item" data-share-copy data-share-url="' . esc_url((string) $permalink) . '"><i class="fa fas fa-link" aria-hidden="true"></i><span>' . esc_html__('复制链接', 'aksrt') . '</span></button>';
$more .= '<button type="button" class="post-drop-meta__item" data-clipboard-text="' . esc_attr((string) $permalink) . '" data-clipboard-tag="' . esc_attr__('链接', 'aksrt') . '"><i class="fa fas fa-link" aria-hidden="true"></i><span>' . esc_html__('复制链接', 'aksrt') . '</span></button>';
$post_author_id = (int) get_post_field('post_author', $post_id);
if ($ban_item === '' && is_user_logged_in() && !(function_exists('aksrt_is_user_ban_restricted') && $post_author_id > 0 && aksrt_is_user_ban_restricted($post_author_id))) {
$report_payload = wp_json_encode([
+2 -44
View File
@@ -178,40 +178,6 @@ if (!function_exists('aksrt_single_render_box_header')) :
}
endif;
if (!function_exists('aksrt_render_share_dropdown')) :
/**
* Shared #share-dropdown markup (actions row + tabbar fallback).
*
* @param array<string,mixed> $attrs Optional data-share-* overrides.
*/
function aksrt_render_share_dropdown(array $attrs = []): void {
static $printed = false;
if ($printed) {
return;
}
$printed = true;
$title = (string) ($attrs['title'] ?? get_the_title());
$url = (string) ($attrs['url'] ?? (get_permalink() ?: ''));
$image = (string) ($attrs['image'] ?? (get_the_post_thumbnail_url(null, 'large') ?: ''));
?>
<div class="share-dropdown" id="share-dropdown" aria-hidden="true"
data-share-title="<?php echo esc_attr($title); ?>"
data-share-url="<?php echo esc_url($url); ?>"
<?php if ($image !== '') : ?>data-share-image="<?php echo esc_url($image); ?>"<?php endif; ?>>
<div class="share-dropdown__grid">
<button type="button" class="share-item" data-platform="qq"><i class="fa fab fa-qq"></i><span>QQ</span></button>
<button type="button" class="share-item" data-platform="weibo"><i class="fa fab fa-weibo"></i><span>微博</span></button>
<button type="button" class="share-item" data-platform="twitter"><i class="fa fab fa-twitter"></i><span>X</span></button>
<button type="button" class="share-item" data-platform="wechat"><i class="fa fab fa-weixin"></i><span>微信</span></button>
<button type="button" class="share-item" data-platform="copy"><i class="fa fas fa-link"></i><span><?php esc_html_e('复制链接', 'aksrt'); ?></span></button>
<button type="button" class="share-item" data-platform="poster"><i class="fa fas fa-image"></i><span><?php esc_html_e('海报分享', 'aksrt'); ?></span></button>
</div>
<div id="share-qrcode-box" aria-hidden="true"><img id="share-qrcode-image" src="" alt="QR Code"></div>
</div>
<?php
}
endif;
if (!function_exists('aksrt_single_render_actions')) :
/**
* Like / reward / share / favorite row.
@@ -247,11 +213,8 @@ if (!function_exists('aksrt_single_render_actions')) :
}
?>
<?php if (!empty($settings['share_enabled'])) : ?>
<button type="button" class="action action-share" id="action-share-trigger" aria-haspopup="true" aria-expanded="false">
<i class="fa fas fa-share-alt" aria-hidden="true"></i>
<span class="action-btn__label"><?php esc_html_e('分享', 'aksrt'); ?></span>
</button>
<?php if (!empty($settings['share_enabled']) && function_exists('aksrt_get_post_share_btn')) : ?>
<?php echo aksrt_get_post_share_btn($post_id, 'action action-share'); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<?php endif; ?>
<?php if (!empty($settings['favorite_enabled'])) : ?>
@@ -261,11 +224,6 @@ if (!function_exists('aksrt_single_render_actions')) :
</button>
<?php endif; ?>
</div>
<?php if (!empty($settings['share_enabled']) && function_exists('aksrt_render_share_dropdown')) : ?>
<?php aksrt_render_share_dropdown();
?>
<?php endif; ?>
</div>
<?php
@@ -448,43 +448,8 @@ if (!function_exists('aksrt_render_footer_tabbar_single_extend')) :
<?php
endif;
if ($share_on) :
$share_title = get_the_title($post_id);
$share_url = get_permalink($post_id) ?: '';
$share_image = get_the_post_thumbnail_url($post_id, 'large') ?: '';
?>
<button type="button"
class="tabbar-item single-action-tabbar action-share"
data-type="share"
data-share-title="<?php echo esc_attr((string) $share_title); ?>"
data-share-url="<?php echo esc_url((string) $share_url); ?>"
<?php if ($share_image !== '') : ?>data-share-image="<?php echo esc_url((string) $share_image); ?>"<?php endif; ?>
aria-haspopup="true"
aria-expanded="false"
aria-label="<?php esc_attr_e('分享', 'aksrt'); ?>">
<i class="fa fas fa-share-alt" aria-hidden="true"></i>
<?php if ($show_text) : ?><span><?php esc_html_e('分享', 'aksrt'); ?></span><?php endif; ?>
</button>
<button type="button"
class="tabbar-item single-action-tabbar action-poster"
data-type="poster"
data-share-platform="poster"
data-share-title="<?php echo esc_attr((string) $share_title); ?>"
data-share-url="<?php echo esc_url((string) $share_url); ?>"
<?php if ($share_image !== '') : ?>data-share-image="<?php echo esc_url((string) $share_image); ?>"<?php endif; ?>
aria-label="<?php esc_attr_e('海报', 'aksrt'); ?>">
<i class="fa fas fa-image" aria-hidden="true"></i>
<?php if ($show_text) : ?><span><?php esc_html_e('海报', 'aksrt'); ?></span><?php endif; ?>
</button>
<?php
endif;
if ($share_on && function_exists('aksrt_render_share_dropdown')) {
aksrt_render_share_dropdown([
'title' => get_the_title($post_id),
'url' => get_permalink($post_id) ?: '',
'image' => get_the_post_thumbnail_url($post_id, 'large') ?: '',
]);
if ($share_on && function_exists('aksrt_get_post_share_btn')) {
echo aksrt_get_post_share_btn($post_id, 'tabbar-item single-action-tabbar', true, $show_text); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
if ($comments_open) :