ID; } if ($subject instanceof WP_Post) { return (int) $subject->post_author; } if ($subject instanceof WP_Comment) { return (int) $subject->user_id; } if (is_object($subject) && isset($subject->user_id)) { return (int) $subject->user_id; } if (is_numeric($subject)) { return max(0, (int) $subject); } if (is_string($subject) && is_email($subject)) { $user = get_user_by('email', $subject); return $user instanceof WP_User ? (int) $user->ID : 0; } return 0; } } if (!function_exists('aksrt_resolve_avatar_email')) { /** * Resolve an email address from an avatar subject. * * @param mixed $subject User ID, WP_User, comment, post, or email. */ function aksrt_resolve_avatar_email($subject): string { if ($subject instanceof WP_User) { return sanitize_email((string) $subject->user_email); } if ($subject instanceof WP_Comment && is_email((string) $subject->comment_author_email)) { return sanitize_email((string) $subject->comment_author_email); } if (is_object($subject) && isset($subject->comment_author_email) && is_email((string) $subject->comment_author_email)) { return sanitize_email((string) $subject->comment_author_email); } if (is_string($subject) && is_email($subject)) { return sanitize_email($subject); } $user_id = aksrt_resolve_avatar_user_id($subject); $user = $user_id > 0 ? get_userdata($user_id) : false; return $user instanceof WP_User ? sanitize_email((string) $user->user_email) : ''; } } if (!function_exists('aksrt_get_user_feature_settings')) { /** * Return the canonical user media and signature settings. * * @return array{avatar_upload_s:bool,avatar_external:string,avatar_default_img:string,user_cover_upload_s:bool,user_cover_img:string,user_desc_std:string} */ function aksrt_get_user_feature_settings(): array { if (class_exists('\AKSRT\Settings\Settings')) { return \AKSRT\Settings\Settings::get_user_feature_settings(); } return [ 'avatar_upload_s' => true, 'avatar_external' => '', 'avatar_default_img' => get_theme_file_uri('assets/img/avatar-default.png'), 'user_cover_upload_s' => true, 'user_cover_img' => get_theme_file_uri('assets/img/user_t.jpg'), 'user_desc_std' => '这家伙很懒,什么都没有写...', ]; } } if (!function_exists('aksrt_get_default_avatar_url')) { /** * Return the bundled avatar used when a user has no custom image. */ function aksrt_get_default_avatar_url(): string { $settings = aksrt_get_user_feature_settings(); return (string) apply_filters( 'aksrt_default_avatar_url', (string) $settings['avatar_default_img'] ); } } if (!function_exists('aksrt_get_external_avatar_url')) { /** * Return the configured external avatar for a subject. * * @param mixed $subject User subject. */ function aksrt_get_external_avatar_url($subject, int $size = 96): string { $settings = aksrt_get_user_feature_settings(); $hosts = [ 'gravatar' => 'https://www.gravatar.com/avatar/', 'weavatar' => 'https://weavatar.com/avatar/', 'cravatar' => 'https://cn.cravatar.com/avatar/', 'geekzu' => 'https://sdn.geekzu.org/avatar/', 'loli' => 'https://gravatar.loli.net/avatar/', 'sep' => 'https://cdn.sep.cc/avatar/', 'v2ex' => 'https://cdn.v2ex.com/gravatar/', ]; $host = $hosts[(string) $settings['avatar_external']] ?? ''; $email = aksrt_resolve_avatar_email($subject); if ($host === '' || $email === '') { return ''; } $size = max(1, min(2048, $size)); return add_query_arg([ 's' => $size, 'd' => aksrt_get_default_avatar_url(), ], $host . hash('sha256', strtolower(trim($email)))); } } if (!function_exists('aksrt_get_custom_avatar_url')) { /** * Return the locally uploaded avatar URL. */ function aksrt_get_custom_avatar_url(int $user_id, int $size = 96): string { if ($user_id <= 0) { return ''; } $attachment_id = (int) get_user_meta($user_id, 'aksrt_avatar_attachment_id', true); if ($attachment_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)) { return ''; } $image = wp_get_attachment_image_url($attachment_id, [$size, $size]); return is_string($image) ? $image : ''; } } if (!function_exists('aksrt_get_avatar_url')) { /** * Resolve the canonical avatar URL used by all AKSRT frontend surfaces. * * @param mixed $subject User subject accepted by get_avatar_url(). * @param array|int $args WordPress avatar args or a numeric size. */ function aksrt_get_avatar_url($subject, $args = []): string { if (is_numeric($args)) { $args = ['size' => (int) $args]; } $args = is_array($args) ? $args : []; $size = max(16, min(512, (int) ($args['size'] ?? 96))); $user_id = aksrt_resolve_avatar_user_id($subject); $custom = aksrt_get_custom_avatar_url($user_id, $size); if ($custom !== '') { return $custom; } $external = aksrt_get_external_avatar_url($subject, $size); if ($external !== '') { return $external; } return aksrt_get_default_avatar_url(); } } if (!function_exists('aksrt_get_avatar_html')) { /** * Render a canonical avatar image. * * @param mixed $subject User subject. * @param int $size Pixel size. * @param array $attrs Additional safe image attributes. */ function aksrt_get_avatar_html($subject, int $size = 96, array $attrs = []): string { $size = max(16, min(512, $size)); $url = aksrt_get_avatar_url($subject, ['size' => $size]); if ($url === '') { return ''; } $defaults = [ 'class' => 'avatar avatar-' . $size . ' photo', 'alt' => '', 'width' => (string) $size, 'height' => (string) $size, ]; $attrs = array_merge($defaults, $attrs); unset($attrs['loading']); $class = (string) ($attrs['class'] ?? $defaults['class']); unset($attrs['class']); $html_attrs = ''; foreach ($attrs as $name => $value) { $name = sanitize_key((string) $name); if ($name === '' || $value === false || $value === null) { continue; } $html_attrs .= ' ' . $name . '="' . esc_attr((string) $value) . '"'; } return ''; } } add_filter('get_avatar_data', static function (array $args, $subject): array { $args['url'] = aksrt_get_avatar_url($subject, ['size' => (int) ($args['size'] ?? 96)]); $args['found_avatar'] = true; return $args; }, 20, 2); if (!function_exists('aksrt_get_avatar_box')) { /** * legacy parity: 头像框(span.avatar-img + VIP 角标 + 可选主页链接)。 * * @param mixed $id_or_email 用户 ID / WP_User / 邮箱。 * @param string $class 外层 span 类(avatar-img avatar-lg 等)。 * @param bool $link 是否包一层用户主页链接。 * @param bool $vip 是否叠加 VIP 角标图。 */ function aksrt_get_avatar_box($id_or_email, string $class = 'avatar-img', bool $link = true, bool $vip = true): string { $user_id = aksrt_resolve_avatar_user_id($id_or_email); $subject = $user_id > 0 ? $user_id : $id_or_email; $img = aksrt_get_avatar_html($subject, 80, ['class' => 'avatar']); $badge = ''; if ($vip && $user_id > 0) { // 禁封角标覆盖 VIP 角标位(参考主题 user_avatar_badge 过滤器覆盖语义)。 $ban_badge = function_exists('aksrt_get_user_ban_avatar_badge') ? aksrt_get_user_ban_avatar_badge($user_id) : ''; if ($ban_badge !== '') { $badge = $ban_badge; } elseif (function_exists('aksrt_get_user_vip_level') && aksrt_get_user_vip_level($user_id) > 0) { $icon_url = ''; if (class_exists('\AKSRT\Settings\Settings')) { $vip_settings = \AKSRT\Settings\Settings::get_payment_vip_settings(); $level = aksrt_get_user_vip_level($user_id); $icon_url = esc_url((string) ($vip_settings['levels'][$level]['img_icon'] ?? '')); } if ($icon_url !== '') { $badge_text = function_exists('aksrt_get_vip_badge_text') ? aksrt_get_vip_badge_text($user_id) : 'VIP'; $badge = '' . esc_attr($badge_text) . ''; } } } $html = '' . $img . $badge . ''; if ($link && $user_id > 0) { $home = function_exists('aksrt_get_user_home_url') ? aksrt_get_user_home_url($user_id) : get_author_posts_url($user_id); $html = '' . $html . ''; } return $html; } } add_action('user_edit_form_tag', static function (): void { echo ' enctype="multipart/form-data"'; }); if (!function_exists('aksrt_is_avatar_upload_enabled')) { /** * Whether local avatar uploads are enabled by attachment policy. */ function aksrt_is_avatar_upload_enabled(): bool { $settings = aksrt_get_user_feature_settings(); return !empty($settings['avatar_upload_s']); } } if (!function_exists('aksrt_is_user_cover_upload_enabled')) { function aksrt_is_user_cover_upload_enabled(): bool { $settings = aksrt_get_user_feature_settings(); return !empty($settings['user_cover_upload_s']); } } if (!function_exists('aksrt_get_user_cover_url')) { function aksrt_get_user_cover_url(int $user_id): string { $custom = $user_id > 0 ? esc_url_raw((string) get_user_meta($user_id, 'aksrt_background_image', true)) : ''; if ($custom !== '') { return $custom; } $settings = aksrt_get_user_feature_settings(); return (string) $settings['user_cover_img']; } } if (!function_exists('aksrt_get_user_description')) { function aksrt_get_user_description(int $user_id): string { $description = $user_id > 0 ? trim((string) get_user_meta($user_id, 'description', true)) : ''; if ($description !== '') { return $description; } $settings = aksrt_get_user_feature_settings(); return (string) $settings['user_desc_std']; } } if (!function_exists('aksrt_delete_owned_avatar_attachment')) { /** * Delete an avatar attachment only when it belongs to the target user. */ function aksrt_delete_owned_avatar_attachment(int $attachment_id, int $user_id): bool { $attachment = $attachment_id > 0 ? get_post($attachment_id) : null; if (!$attachment instanceof WP_Post || $attachment->post_type !== 'attachment' || (int) $attachment->post_author !== $user_id) { return false; } return (bool) wp_delete_attachment($attachment_id, true); } }