From dc54b02c541168a225b1c4f98872d47ac6d7e9d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E6=B4=BE=E5=A4=87=E6=A1=88?= <130886204+modiqi@users.noreply.github.com> Date: Wed, 21 May 2025 01:26:21 +0800 Subject: [PATCH] =?UTF-8?q?v1.9.2=20=E7=A8=B3=E5=AE=9A=E7=89=88=E5=8F=91?= =?UTF-8?q?=E5=B8=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/js/admin.js | 51 ++- includes/admin.php | 207 +++++++----- includes/core.php | 8 +- includes/marketing.php | 573 ++++++++++++++++++++++++++++++++ includes/multisite.php | 189 ++++++++++- includes/wpcy-compatibility.php | 131 ++++++++ wpavatar.php | 96 ++---- 7 files changed, 1090 insertions(+), 165 deletions(-) create mode 100644 includes/marketing.php create mode 100644 includes/wpcy-compatibility.php diff --git a/assets/js/admin.js b/assets/js/admin.js index aa4ac7a..b6f7da0 100644 --- a/assets/js/admin.js +++ b/assets/js/admin.js @@ -20,6 +20,7 @@ jQuery(document).ready(function($) { $('.wpavatar-section').hide(); $('#wpavatar-section-' + tab).show(); + // 当切换到缓存标签页时自动检查缓存状态 if (tab === 'cache' && $('#cache-stats').is(':empty')) { setTimeout(function() { if (wpavatar.is_network_admin === '1') { @@ -30,6 +31,11 @@ jQuery(document).ready(function($) { }, 300); } + // 当切换到营销组件标签页时的特殊处理 + if (tab === 'marketing') { + // 可以在这里添加特殊初始化代码,如果需要的话 + } + if (window.history && window.history.pushState) { var url = new URL(window.location.href); url.searchParams.set('tab', tab); @@ -323,6 +329,47 @@ jQuery(document).ready(function($) { return true; }); + // 添加营销组件表单的验证 + $('#wpavatar-marketing-form').on('submit', function(e) { + var isValid = true; + var $status = $('#wpavatar-status'); + + // 验证最近评论者设置 + var commentersCount = parseInt($('input[name="wpavatar_commenters_count"]').val()); + var commentersSize = parseInt($('input[name="wpavatar_commenters_size"]').val()); + + if (isNaN(commentersCount) || commentersCount < 1 || commentersCount > 50) { + $status.removeClass('notice-success').addClass('notice-error').text('请设置有效的评论者显示数量(1-50)').show(); + $('input[name="wpavatar_commenters_count"]').focus(); + isValid = false; + } else if (isNaN(commentersSize) || commentersSize < 20 || commentersSize > 150) { + $status.removeClass('notice-success').addClass('notice-error').text('请设置有效的评论者头像大小(20-150像素)').show(); + $('input[name="wpavatar_commenters_size"]').focus(); + isValid = false; + } + + // 验证用户设置 + var usersCount = parseInt($('input[name="wpavatar_users_count"]').val()); + var usersSize = parseInt($('input[name="wpavatar_users_size"]').val()); + + if (isNaN(usersCount) || usersCount < 1 || usersCount > 50) { + $status.removeClass('notice-success').addClass('notice-error').text('请设置有效的用户显示数量(1-50)').show(); + $('input[name="wpavatar_users_count"]').focus(); + isValid = false; + } else if (isNaN(usersSize) || usersSize < 20 || usersSize > 150) { + $status.removeClass('notice-success').addClass('notice-error').text('请设置有效的用户头像大小(20-150像素)').show(); + $('input[name="wpavatar_users_size"]').focus(); + isValid = false; + } + + if (!isValid) { + e.preventDefault(); + return false; + } + + return true; + }); + // For network import and bulk operations if ($('#import-site-settings').length) { $('#import-site-settings').on('click', function(e) { @@ -369,8 +416,8 @@ jQuery(document).ready(function($) { // Applied to all sites notification if (window.location.search.indexOf('applied=true') > -1) { $('#wpavatar-status') - .removeClass('notice-error') - .addClass('notice-success') + .removeClass('notice-success') + .addClass('notice-error') .text('网络设置已成功应用到所有站点。') .show() .delay(3000) diff --git a/includes/admin.php b/includes/admin.php index 441c08c..0f5eeb2 100644 --- a/includes/admin.php +++ b/includes/admin.php @@ -43,6 +43,12 @@ class Settings { register_setting('wpavatar_shortcodes', 'wpavatar_shortcode_size', ['type' => 'integer']); register_setting('wpavatar_shortcodes', 'wpavatar_shortcode_class', ['type' => 'string']); register_setting('wpavatar_shortcodes', 'wpavatar_shortcode_shape', ['type' => 'string']); + + // 注册营销组件设置 + register_setting('wpavatar_marketing', 'wpavatar_commenters_count', ['type' => 'integer']); + register_setting('wpavatar_marketing', 'wpavatar_commenters_size', ['type' => 'integer']); + register_setting('wpavatar_marketing', 'wpavatar_users_count', ['type' => 'integer']); + register_setting('wpavatar_marketing', 'wpavatar_users_size', ['type' => 'integer']); } public static function sanitize_cache_path($value) { @@ -164,10 +170,11 @@ class Settings { settings_errors('wpavatar_cache'); settings_errors('wpavatar_advanced'); settings_errors('wpavatar_shortcodes'); + settings_errors('wpavatar_marketing'); } public static function render_settings_page() { - // Check for network control in multisite + // 检查多站点网络控制 if (is_multisite()) { $network_enabled = get_site_option('wpavatar_network_enabled', 1); $network_enforce = get_site_option('wpavatar_network_enforce', 0); @@ -182,9 +189,9 @@ class Settings { ?>

- - - + + +

@@ -203,6 +210,9 @@ class Settings { +
@@ -338,7 +348,7 @@ class Settings {

-

+

@@ -694,91 +704,122 @@ class Settings { + + +
+

+

+ + +
+

+ +
+ + +
+ + +
+ + +
+ + + + + +

+
+ + + +
- - + display_name ? $user->display_name : __('匿名用户', 'wpavatar'); - return $atts['before'] . $username . $atts['after']; + // 检查用户是否已登录且有显示名称,如果没有则返回空字符串 + if (!$user || !$user->ID || empty($user->display_name)) { + return ''; + } + + return $atts['before'] . $user->display_name . $atts['after']; } public static function menu_item_replace($item_output, $item, $depth, $args) { diff --git a/includes/marketing.php b/includes/marketing.php new file mode 100644 index 0000000..9f540af --- /dev/null +++ b/includes/marketing.php @@ -0,0 +1,573 @@ + 'integer', 'default' => 15]); + register_setting('wpavatar_marketing', 'wpavatar_commenters_size', ['type' => 'integer', 'default' => 45]); + register_setting('wpavatar_marketing', 'wpavatar_users_count', ['type' => 'integer', 'default' => 15]); + register_setting('wpavatar_marketing', 'wpavatar_users_size', ['type' => 'integer', 'default' => 40]); + } + + /** + * 添加前端样式 + */ + public static function add_frontend_styles() { + echo ' + + '; + } + + /** + * 渲染最近评论者头像 + */ + public static function render_latest_commenters($atts) { + $default_count = wpavatar_get_option('wpavatar_commenters_count', 15); + $default_size = wpavatar_get_option('wpavatar_commenters_size', 45); + + $atts = shortcode_atts([ + 'size' => $default_size, + 'number' => $default_count, + ], $atts, 'wpavatar_latest_commenters'); + + // 获取全部文章的最新评论,限制为指定的评论者数量 + $comments = get_comments(array( + 'number' => $atts['number'] * 3, // 获取更多评论以确保有足够不重复的评论者 + 'status' => 'approve', + )); + + if (empty($comments)) { + return '
暂无评论用户头像
'; + } + + // 初始化一个数组用于存储已显示的评论者 + $seen_emails = array(); + $output = '
'; + + foreach ($comments as $comment) { + // 检查评论者的电子邮件地址 + $comment_email = $comment->comment_author_email; + + // 如果该评论者已经显示过,则跳过 + if (in_array($comment_email, $seen_emails) || empty($comment_email)) { + continue; + } + + // 获取评论的链接 + $comment_link = get_comment_link($comment); + + // 创建带链接的头像 + $avatar_with_link = ''; + $avatar_with_link .= get_avatar($comment, $atts['size'], '', $comment->comment_author); + $avatar_with_link .= ''; + + // 添加头像到输出 + $output .= '
' . $avatar_with_link . '
'; + + // 记录该评论者,防止重复显示 + $seen_emails[] = $comment_email; + + // 如果已经达到了显示数量限制,跳出循环 + if (count($seen_emails) >= $atts['number']) { + break; + } + } + + $output .= '
'; + + return $output; + } + + /** + * 渲染最新用户头像 + */ + public static function render_latest_users($atts) { + $default_count = wpavatar_get_option('wpavatar_users_count', 15); + $default_size = wpavatar_get_option('wpavatar_users_size', 40); + + $atts = shortcode_atts([ + 'number' => $default_count, + 'size' => $default_size + ], $atts); + + $users = get_users([ + 'orderby' => 'registered', + 'order' => 'DESC', + 'number' => $atts['number'] + ]); + + if (empty($users)) { + return '
暂无用户
'; + } + + $output = '
'; + foreach ($users as $user) { + $output .= '
'; + $output .= get_avatar($user->ID, $atts['size'], '', $user->display_name); + $output .= '
' . esc_html($user->display_name) . '
'; + $output .= '
'; + } + $output .= '
'; + + return $output; + } + + /** + * 渲染随机用户头像 + */ + public static function render_random_users($atts) { + $default_count = wpavatar_get_option('wpavatar_users_count', 15); + $default_size = wpavatar_get_option('wpavatar_users_size', 40); + + $atts = shortcode_atts([ + 'number' => $default_count, + 'size' => $default_size + ], $atts); + + $args = [ + 'orderby' => 'registered', + 'order' => 'DESC', + 'number' => intval($atts['number']) * 2 // 获取更多用户以便随机选择 + ]; + $users = get_users($args); + + if (empty($users)) { + return '
暂无用户
'; + } + + // 打乱用户数组以随机化顺序 + shuffle($users); + + // 限制显示的用户数量 + $users = array_slice($users, 0, intval($atts['number'])); + + $output = '
'; + foreach ($users as $user) { + $output .= '
'; + $output .= get_avatar($user->ID, $atts['size'], '', $user->display_name); + $output .= '
' . esc_html($user->display_name) . '
'; + $output .= '
'; + } + $output .= '
'; + + return $output; + } + + /** + * 渲染文章作者头像 + */ + public static function render_author_avatar($atts) { + $atts = shortcode_atts([ + 'size' => '96', + ], $atts); + + $post_id = get_the_ID(); + if (!$post_id) { + return ''; + } + + $author_id = get_post_field('post_author', $post_id); + if (!$author_id) { + return ''; + } + + $avatar = get_avatar($author_id, $atts['size']); + + return $avatar; + } + + /** + * 生成预览头像 + */ + public static function generate_preview($shape = 'square', $size = 96, $count = 6) { + global $wpdb; + + // 获取最近的评论者 + $sql = "SELECT DISTINCT comment_author_email, comment_author + FROM {$wpdb->comments} + WHERE comment_approved = '1' + AND comment_author_email != '' + ORDER BY comment_date DESC + LIMIT %d"; + + $commenters = $wpdb->get_results($wpdb->prepare($sql, $count)); + + $output = '
'; + + if (!empty($commenters)) { + $output .= '
'; + $output .= '

最近评论者预览

'; + $output .= '
'; + + foreach ($commenters as $commenter) { + if (empty($commenter->comment_author_email)) continue; + + $output .= '
'; + $avatar_args = [ + 'class' => 'preview-avatar', + 'size' => $size + ]; + + if ($shape === 'circle') { + $avatar_args['extra_attr'] = 'style="border-radius: 50%; overflow: hidden;"'; + } elseif ($shape === 'rounded') { + $avatar_args['extra_attr'] = 'style="border-radius: 8px; overflow: hidden;"'; + } + + $output .= get_avatar($commenter->comment_author_email, $size, '', $commenter->comment_author, $avatar_args); + $output .= '
'; + } + + $output .= '
'; + $output .= '
'; + } + + // 获取最新用户 + $recent_users = get_users([ + 'orderby' => 'registered', + 'order' => 'DESC', + 'number' => $count + ]); + + if (!empty($recent_users)) { + $output .= '
'; + $output .= '

最新用户预览

'; + $output .= '
'; + + foreach ($recent_users as $user) { + $output .= '
'; + $avatar_args = [ + 'class' => 'preview-avatar', + 'size' => $size + ]; + + if ($shape === 'circle') { + $avatar_args['extra_attr'] = 'style="border-radius: 50%; overflow: hidden;"'; + } elseif ($shape === 'rounded') { + $avatar_args['extra_attr'] = 'style="border-radius: 8px; overflow: hidden;"'; + } + + $output .= get_avatar($user->ID, $size, '', $user->display_name, $avatar_args); + $output .= '' . esc_html($user->display_name) . ''; + $output .= '
'; + } + + $output .= '
'; + $output .= '
'; + } + + $output .= '
'; + + return $output; + } + + /** + * 渲染管理界面 + */ + public static function render_admin_page() { + // 使用wpavatar_get_option而不是get_option获取设置 + $commenters_count = wpavatar_get_option('wpavatar_commenters_count', 15); + $commenters_size = wpavatar_get_option('wpavatar_commenters_size', 45); + $users_count = wpavatar_get_option('wpavatar_users_count', 15); + $users_size = wpavatar_get_option('wpavatar_users_size', 40); + + // 检查多站点网络控制 + $is_option_disabled = false; + if (is_multisite() && get_site_option('wpavatar_network_enabled', 1)) { + $network_controlled_options = get_site_option('wpavatar_network_controlled_options', array()); + if (!is_array($network_controlled_options)) { + $network_controlled_options = explode(',', $network_controlled_options); + } + + // 检查营销组件选项是否由网络控制 + $is_commenters_count_disabled = in_array('wpavatar_commenters_count', $network_controlled_options) ? 'disabled' : ''; + $is_commenters_size_disabled = in_array('wpavatar_commenters_size', $network_controlled_options) ? 'disabled' : ''; + $is_users_count_disabled = in_array('wpavatar_users_count', $network_controlled_options) ? 'disabled' : ''; + $is_users_size_disabled = in_array('wpavatar_users_size', $network_controlled_options) ? 'disabled' : ''; + + // 检查是否强制使用网络设置 + if (get_site_option('wpavatar_network_enforce', 0)) { + $is_commenters_count_disabled = 'disabled'; + $is_commenters_size_disabled = 'disabled'; + $is_users_count_disabled = 'disabled'; + $is_users_size_disabled = 'disabled'; + } + } else { + $is_commenters_count_disabled = ''; + $is_commenters_size_disabled = ''; + $is_users_count_disabled = ''; + $is_users_size_disabled = ''; + } + + ?> +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ > +

+
+ > +

+

+ > +

+
+ > +

+
+ +
+

+ +

+
+ +
+ +
+ +
+

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
[wpavatar_latest_commenters] +
    +
  • number -
  • +
  • size -
  • +
+
[wpavatar_latest_commenters number="10" size="50"]
[wpavatar_latest_users] +
    +
  • number -
  • +
  • size -
  • +
+
[wpavatar_latest_users number="12" size="40"]
[wpavatar_random_users] +
    +
  • number -
  • +
  • size -
  • +
+
[wpavatar_random_users number="12" size="40"]
[wpavatar_author] +
    +
  • size -
  • +
+
[wpavatar_author size="96"]
+
+

+

+ +

+
+
+ + +
-

- - - +

+ + +

@@ -261,8 +266,11 @@ class Network { +
@@ -327,6 +335,10 @@ class Network { 'wpavatar_shortcode_size' => __('默认头像大小', 'wpavatar'), 'wpavatar_shortcode_class' => __('默认CSS类名', 'wpavatar'), 'wpavatar_shortcode_shape' => __('默认头像形状', 'wpavatar'), + 'wpavatar_commenters_count' => __('评论者数量', 'wpavatar'), + 'wpavatar_commenters_size' => __('评论者头像大小', 'wpavatar'), + 'wpavatar_users_count' => __('用户数量', 'wpavatar'), + 'wpavatar_users_size' => __('用户头像大小', 'wpavatar'), ]; // Group options by category @@ -366,6 +378,15 @@ class Network { 'wpavatar_shortcode_class', 'wpavatar_shortcode_shape' ] + ], + 'marketing' => [ + 'title' => __('营销组件', 'wpavatar'), + 'options' => [ + 'wpavatar_commenters_count', + 'wpavatar_commenters_size', + 'wpavatar_users_count', + 'wpavatar_users_size' + ] ] ]; @@ -398,7 +419,7 @@ class Network {
- +
@@ -500,7 +521,7 @@ class Network {
- +
@@ -553,7 +574,7 @@ class Network {
- +
@@ -609,7 +630,7 @@ class Network {
- +
@@ -671,7 +692,121 @@ class Network {
- + +
+ + + + +
+

+

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ +

+
+ +

+

+ +

+
+ +

+
+ +
+ +
+ +
+

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
[wpavatar_latest_commenters] +
    +
  • number -
  • +
  • size -
  • +
+
[wpavatar_latest_commenters number="10" size="50"]
[wpavatar_latest_users] +
    +
  • number -
  • +
  • size -
  • +
+
[wpavatar_latest_users number="12" size="40"]
[wpavatar_random_users] +
    +
  • number -
  • +
  • size -
  • +
+
[wpavatar_random_users number="12" size="40"]
[wpavatar_author] +
    +
  • size -
  • +
+
[wpavatar_author size="96"]
+
@@ -994,6 +1129,14 @@ class Network { update_site_option('wpavatar_shortcode_shape', sanitize_text_field($_POST['wpavatar_shortcode_shape'] ?? 'square')); } + // Process marketing settings + if ($current_tab === 'marketing') { + update_site_option('wpavatar_commenters_count', intval($_POST['wpavatar_commenters_count'] ?? 15)); + update_site_option('wpavatar_commenters_size', intval($_POST['wpavatar_commenters_size'] ?? 45)); + update_site_option('wpavatar_users_count', intval($_POST['wpavatar_users_count'] ?? 15)); + update_site_option('wpavatar_users_size', intval($_POST['wpavatar_users_size'] ?? 40)); + } + // Redirect back to the appropriate page with update message $redirect_url = add_query_arg([ 'page' => 'wpavatar-network', @@ -1046,7 +1189,12 @@ class Network { 'wpavatar_fallback_avatar', 'wpavatar_shortcode_size', 'wpavatar_shortcode_class', - 'wpavatar_shortcode_shape' + 'wpavatar_shortcode_shape', + // 添加营销组件选项 + 'wpavatar_commenters_count', + 'wpavatar_commenters_size', + 'wpavatar_users_count', + 'wpavatar_users_size' ]; // Copy options from site to network @@ -1101,6 +1249,23 @@ class Network { } } + // 确保也应用营销组件设置 + $marketing_options = [ + 'wpavatar_commenters_count', + 'wpavatar_commenters_size', + 'wpavatar_users_count', + 'wpavatar_users_size' + ]; + + foreach ($marketing_options as $option) { + if (in_array($option, $controlled_options)) { + $network_value = get_site_option($option); + if ($network_value !== false) { + update_option($option, $network_value); + } + } + } + // Ensure site cache directory exists $cache_base = get_site_option('wpavatar_cache_path', WPAVATAR_CACHE_DIR); $site_cache_dir = trailingslashit($cache_base) . 'site-' . $site->blog_id; diff --git a/includes/wpcy-compatibility.php b/includes/wpcy-compatibility.php new file mode 100644 index 0000000..92af1bf --- /dev/null +++ b/includes/wpcy-compatibility.php @@ -0,0 +1,131 @@ +callbacks as $priority => $callbacks) { + foreach ($callbacks as $callback_key => $callback_data) { + if (is_array($callback_data['function']) && + is_object($callback_data['function'][0]) && + get_class($callback_data['function'][0]) === 'WenPai\\ChinaYes\\Service\\Super') { + + $method_name = $callback_data['function'][1]; + remove_filter($filter_name, [$callback_data['function'][0], $method_name], $priority); + } + } + } + } + } + } + + /** + * 重新初始化 WPAvatar 的 Cravatar 过滤器,使用更高的优先级 + */ + private static function reinitialize_wpavatar_filters() { + if (wpavatar_get_option('wpavatar_enable_cravatar', true)) { + // 使用高优先级再次添加过滤器 + add_filter('um_user_avatar_url_filter', ['\WPAvatar\Cravatar', 'replace_avatar_url'], 9999); + add_filter('bp_gravatar_url', ['\WPAvatar\Cravatar', 'replace_avatar_url'], 9999); + add_filter('user_profile_picture_description', ['\WPAvatar\Cravatar', 'modify_profile_picture_description'], 9999); + + // 确保 get_avatar_url 过滤器的优先级高于其他插件 + remove_filter('get_avatar_url', ['\WPAvatar\Cravatar', 'get_avatar_url'], 999); + add_filter('get_avatar_url', ['\WPAvatar\Cravatar', 'get_avatar_url'], 9999, 2); + } + } + + /** + * 管理界面兼容性通知 + */ + public static function admin_compatibility_notice() { + $screen = get_current_screen(); + if ($screen && $screen->id === 'settings_page_wpavatar-settings') { + echo '
'; + echo '

检测到文派叶子(WPCY.COM)插件,WPAvatar 生态组件兼容补丁已生效,确保文派头像设置优先。

'; + echo '
'; + } + } +} diff --git a/wpavatar.php b/wpavatar.php index 819a6d6..2d5a0d6 100644 --- a/wpavatar.php +++ b/wpavatar.php @@ -1,7 +1,7 @@ callbacks as $priority => $callbacks) { - foreach ($callbacks as $callback_key => $callback_data) { - if (is_array($callback_data['function']) && - is_object($callback_data['function'][0]) && - get_class($callback_data['function'][0]) === 'WenPai\\ChinaYes\\Service\\Super') { - - $method_name = $callback_data['function'][1]; - remove_filter($filter_name, [$callback_data['function'][0], $method_name], $priority); - } - } - } - } - } - - // 重新添加 WPAvatar 的过滤器,使用更高的优先级 - if (wpavatar_get_option('wpavatar_enable_cravatar', true)) { - // 移除原有优先级的过滤器 - remove_filter('get_avatar_url', ['WPAvatar\\Cravatar', 'get_avatar_url'], 999); - remove_filter('um_user_avatar_url_filter', ['WPAvatar\\Cravatar', 'replace_avatar_url'], 1); - remove_filter('bp_gravatar_url', ['WPAvatar\\Cravatar', 'replace_avatar_url'], 1); - - // 使用更高优先级重新添加 - add_filter('get_avatar_url', ['WPAvatar\\Cravatar', 'get_avatar_url'], 9999, 2); - add_filter('um_user_avatar_url_filter', ['WPAvatar\\Cravatar', 'replace_avatar_url'], 9999); - add_filter('bp_gravatar_url', ['WPAvatar\\Cravatar', 'replace_avatar_url'], 9999); - add_filter('user_profile_picture_description', ['WPAvatar\\Cravatar', 'modify_profile_picture_description'], 9999); - } - - // 添加管理界面通知 - add_action('admin_notices', function() { - $screen = get_current_screen(); - if ($screen && $screen->id === 'settings_page_wpavatar-settings') { - echo '
'; - echo '

检测到文派叶子(WPCY.COM)插件,WPAvatar 生态组件兼容性补丁已生效,确保文派头像设置优先。

'; - echo '
'; - } - }); - } - }, 5); - } -});