diff --git a/inc/helpers/jio-avatar.php b/inc/helpers/jio-avatar.php index 032eedac..05d82f38 100644 --- a/inc/helpers/jio-avatar.php +++ b/inc/helpers/jio-avatar.php @@ -131,7 +131,11 @@ if (!function_exists('jio_get_external_avatar_url')) { if (!function_exists('jio_get_custom_avatar_url')) { /** - * Return the locally uploaded avatar URL. + * Return the avatar that replaces the external/default one. + * + * Uploaded avatars win; the third-party avatar stored at registration or + * binding fills the gap until the user uploads their own — the reference + * seeds its equivalent from the OAuth profile only when none exists. */ function jio_get_custom_avatar_url(int $user_id, int $size = 96): string { if ($user_id <= 0) { @@ -139,17 +143,51 @@ if (!function_exists('jio_get_custom_avatar_url')) { } $attachment_id = (int) get_user_meta($user_id, 'jio_avatar_attachment_id', true); - if ($attachment_id <= 0) { + if ($attachment_id > 0) { + $attachment = get_post($attachment_id); + if ($attachment instanceof WP_Post && $attachment->post_type === 'attachment' && (int) $attachment->post_author === $user_id && wp_attachment_is_image($attachment_id)) { + $image = wp_get_attachment_image_url($attachment_id, [$size, $size]); + if (is_string($image) && $image !== '') { + return $image; + } + } + } + + return jio_get_oauth_avatar_url($user_id); + } +} + +if (!function_exists('jio_get_oauth_avatar_url')) { + /** + * Return the avatar captured from the user's third-party profile. + * + * Providers hand back CDN URLs that go stale or start blocking hotlinks; + * Baidu in particular serves `tb.himg.baidu.com` which 403s, so the host is + * rewritten the way the reference does before the URL is used. + */ + function jio_get_oauth_avatar_url(int $user_id): string { + if ($user_id <= 0) { return ''; } - $attachment = get_post($attachment_id); - if (!$attachment instanceof WP_Post || $attachment->post_type !== 'attachment' || (int) $attachment->post_author !== $user_id || !wp_attachment_is_image($attachment_id)) { + $url = trim((string) get_user_meta($user_id, 'jio_oauth_avatar', true)); + if ($url === '') { return ''; } - $image = wp_get_attachment_image_url($attachment_id, [$size, $size]); - return is_string($image) ? $image : ''; + $url = (string) str_replace('tb.himg.baidu.com', 'himg.bdimg.com', $url); + $url = esc_url_raw($url); + if (!is_http_url($url)) { + return ''; + } + + // 第三方 CDN 常回 http://,在 HTTPS 站点上会被浏览器当作混合内容拦截; + // 参考主题用去掉协议头的写法规避,这里直接对齐站点协议。 + if (is_ssl()) { + $url = (string) preg_replace('#^http://#i', 'https://', $url); + } + + return $url; } } diff --git a/src/Admin/UserControllerProfileMediaOperations.php b/src/Admin/UserControllerProfileMediaOperations.php index fb59c226..b9b7cf90 100644 --- a/src/Admin/UserControllerProfileMediaOperations.php +++ b/src/Admin/UserControllerProfileMediaOperations.php @@ -27,6 +27,8 @@ trait UserControllerProfileMediaOperations { $attachment_id = (int) get_user_meta($user_id, 'jio_avatar_attachment_id', true); delete_user_meta($user_id, 'jio_avatar_attachment_id'); + // 第三方头像会在上传头像被清除后重新顶上来,恢复默认时必须一并丢弃。 + delete_user_meta($user_id, 'jio_oauth_avatar'); $this->delete_owned_profile_attachment($attachment_id, $user_id); do_action('jio_user_avatar_changed', $user_id, 0, ''); diff --git a/src/Auth/OAuthAccountService.php b/src/Auth/OAuthAccountService.php index 74e083c8..9fcd0857 100644 --- a/src/Auth/OAuthAccountService.php +++ b/src/Auth/OAuthAccountService.php @@ -71,9 +71,7 @@ final class OAuthAccountService { $bindings[] = $provider; } update_user_meta($user_id, 'jio_oauth_bindings', array_values(array_unique($bindings))); - if (!empty($identity['avatar_url'])) { - update_user_meta($user_id, 'jio_oauth_avatar', esc_url_raw((string) $identity['avatar_url'])); - } + self::seed_avatar($user_id, $identity); return true; } finally { OAuthTransactionStore::release_lock($scope, (string) $lock); @@ -114,9 +112,27 @@ final class OAuthAccountService { $bindings[] = $provider; update_user_meta($user_id, 'jio_oauth_bindings', array_values(array_unique($bindings))); } - if (!empty($identity['avatar_url'])) { - update_user_meta($user_id, 'jio_oauth_avatar', esc_url_raw((string) $identity['avatar_url'])); + self::seed_avatar($user_id, $identity); + } + + /** + * 建档或首次绑定时以第三方头像补齐,之后不再覆盖。 + * + * 参考主题只在用户没有自定义头像时写入(`if ($args['avatar'] && !$custom_avatar)`), + * 这样用户换过的头像不会被后续第三方登录冲掉。 + */ + private static function seed_avatar(int $user_id, array $identity): void { + $avatar = trim((string) ($identity['avatar_url'] ?? '')); + if ($user_id <= 0 || $avatar === '') { + return; } + if ((int) get_user_meta($user_id, 'jio_avatar_attachment_id', true) > 0) { + return; + } + if (trim((string) get_user_meta($user_id, 'jio_oauth_avatar', true)) !== '') { + return; + } + update_user_meta($user_id, 'jio_oauth_avatar', esc_url_raw($avatar)); } private static function has_recovery_after_unbind(int $user_id, string $provider): bool { diff --git a/src/Frontend/WeChatShare.php b/src/Frontend/WeChatShare.php index 14e23205..56d3427b 100644 --- a/src/Frontend/WeChatShare.php +++ b/src/Frontend/WeChatShare.php @@ -166,10 +166,10 @@ window.WeChatShareDate = ID)) { - $pic = (string) get_user_meta((int) $author->ID, 'custom_avatar', true); - if ($pic === '') { - $pic = get_avatar_url((int) $author->ID, ['size' => 300]); - } + // 与本主题其余头像位一致:上传头像 → 第三方头像 → 外部服务。 + $pic = function_exists('jio_get_avatar_url') + ? (string) jio_get_avatar_url((int) $author->ID, ['size' => 300]) + : get_avatar_url((int) $author->ID, ['size' => 300]); } } elseif (is_category() || is_tag() || is_tax()) { $term = get_queried_object(); diff --git a/src/User/ProfileAdmin.php b/src/User/ProfileAdmin.php index eed6646d..65354764 100644 --- a/src/User/ProfileAdmin.php +++ b/src/User/ProfileAdmin.php @@ -33,6 +33,8 @@ final class ProfileAdmin { ? jio_get_user_profile_details($user_id) : ['gender' => 'secret', 'website' => '', 'qq' => '', 'wechat' => '', 'weibo' => '', 'github' => '', 'address' => '']; $avatar_url = function_exists('jio_get_custom_avatar_url') ? jio_get_custom_avatar_url($user_id, 96) : ''; + $avatar_custom = (int) get_user_meta($user_id, 'jio_avatar_attachment_id', true) > 0 + || trim((string) get_user_meta($user_id, 'jio_oauth_avatar', true)) !== ''; $cover_id = (int) get_user_meta($user_id, 'jio_background_attachment_id', true); $cover_url = esc_url_raw((string) get_user_meta($user_id, 'jio_background_image', true)); if ($cover_url === '' && $cover_id > 0) $cover_url = (string) wp_get_attachment_image_url($cover_id, 'full'); @@ -45,7 +47,7 @@ final class ProfileAdmin {