' . esc_html($subtitle) . ''; } endif; if (!function_exists('aksrt_get_single_title_html')) : /** * Title + optional subtitle for single headers. */ function aksrt_get_single_title_html($post_id = null): string { $post_id = $post_id ? (int) $post_id : (int) get_the_ID(); $title = get_the_title($post_id); $sub = function_exists('aksrt_get_the_subtitle') ? aksrt_get_the_subtitle(true, '', $post_id) : ''; return esc_html($title) . $sub; } endif; if (!function_exists('aksrt_get_posts_meta_items_html')) : /** * Zibll-like post meta pills: comment + views + likes. * * @param int|null $post_id Post ID. */ function aksrt_get_posts_meta_items_html($post_id = null): string { $post = get_post($post_id); if (!($post instanceof WP_Post)) { return ''; } $post_id = (int) $post->ID; $html = ''; $comments_closed = function_exists('aksrt_are_comments_closed') ? aksrt_are_comments_closed() : (!comments_open($post_id)); if (comments_open($post_id) && !$comments_closed) { $href = is_single($post_id) ? 'javascript:(typeof scrollTopTo===\'function\'?scrollTopTo(\'#comments\'):void(0));' : get_comments_link($post_id); $count = (int) get_comments_number($post_id); $html .= '' . ' ' . esc_html((string) $count) . ''; } $views = function_exists('aksrt_get_post_views') ? (int) aksrt_get_post_views($post_id) : 0; $views_label = function_exists('aksrt_format_number') ? aksrt_format_number($views) : number_format_i18n($views); $html .= ' ' . esc_html((string) $views_label) . ''; $like_on = true; if (class_exists('\AKSRT\Settings\Settings')) { $page = \AKSRT\Settings\Settings::get_post_page_settings(); $like_on = !isset($page['like_enabled']) || !empty($page['like_enabled']); } if ($like_on && $post->post_type === 'post') { $likes = function_exists('aksrt_get_post_likes') ? (int) aksrt_get_post_likes($post_id) : 0; $html .= ' ' . esc_html((string) $likes) . ''; } return $html; } endif; if (!function_exists('aksrt_get_single_meta_box')) : /** * Zibll zib_get_single_meta_box equivalent. * * @param string $class Extra class on wrapper. * @param string $direction Unused (kept for API parity). * @param int|null $post_id Post ID. */ function aksrt_get_single_meta_box(string $class = 'abs-right', string $direction = 'down', $post_id = null): string { if (!is_single() && !is_singular()) { return ''; } $post_id = $post_id ? (int) $post_id : (int) get_the_ID(); $meta = function_exists('aksrt_get_posts_meta_items_html') ? aksrt_get_posts_meta_items_html($post_id) : ''; $more = ''; $edit_link = ''; if (current_user_can('manage_options')) { // Site administrators retain the native editor for full post maintenance. $edit_link = get_edit_post_link($post_id); } elseif (class_exists('\AKSRT\Core\FrontSubmit') && function_exists('aksrt_find_template_page')) { $front_submit = \AKSRT\Core\FrontSubmit::get_instance(); $submit_page = aksrt_find_template_page('templates/pages/page-submit.php'); if ($submit_page instanceof WP_Post && $front_submit->can_edit_post($post_id)) { // Do not fall back to /wp-admin or a guessed submit URL. A normal // author sees this action only when the configured frontend editor exists. $edit_link = function_exists('aksrt_get_new_post_url') ? aksrt_get_new_post_url($post_id) : ''; } } $permalink = get_permalink($post_id); $login_url = function_exists('aksrt_get_login_url') ? aksrt_get_login_url() : wp_login_url($permalink ?: home_url('/')); $more .= '
'; $more .= ''; $more .= '
'; return '
' . $meta . '
' . $more . '
'; } endif; if (!function_exists('aksrt_get_post_status_badge')) : /** * Non-publish status badge (text badge, Zibll-compatible classes). */ function aksrt_get_post_status_badge($post = null): string { $post = get_post($post); if (!($post instanceof WP_Post)) { return ''; } $map = [ 'draft' => ['label' => __('草稿', 'aksrt'), 'class' => 'jb-yellow'], 'pending' => ['label' => __('待审核', 'aksrt'), 'class' => 'jb-red'], 'private' => ['label' => __('私密', 'aksrt'), 'class' => 'b-black opacity8'], 'future' => ['label' => __('定时发布', 'aksrt'), 'class' => 'c-blue'], 'trash' => ['label' => __('回收站', 'aksrt'), 'class' => 'jb-red'], ]; $status = $post->post_status; if (!isset($map[$status])) { return ''; } return '' . esc_html($map[$status]['label']) . ''; } endif; if (!function_exists('aksrt_get_colored_term_tags')) : /** * Colored but-links for terms. * * @param WP_Term[] $terms Terms. * @param string $class Base class. * @param string $before Prefix HTML inside link. * @param string[] $palette Color classes. */ function aksrt_get_colored_term_tags(array $terms, string $class = 'but ml6 radius', string $before = '', array $palette = []): string { if ($palette === []) { $palette = ['c-blue', 'c-yellow', 'c-green', 'c-purple', 'c-red']; } $html = ''; $i = 0; foreach ($terms as $term) { if (!($term instanceof WP_Term)) { continue; } $color = $palette[$i % count($palette)]; $i++; $url = get_term_link($term); if (is_wp_error($url)) { continue; } $html .= '' . $before . esc_html($term->name) . ''; } return $html; } endif; if (!function_exists('aksrt_get_single_article_tags_html')) : /** * Categories → tags. */ function aksrt_get_single_article_tags_html(int $post_id): string { $cats = get_the_category($post_id) ?: []; $cat_html = aksrt_get_colored_term_tags( $cats, 'but ml6 radius', ' ', ['c-blue', 'c-yellow', 'c-green', 'c-purple', 'c-red'] ); $tags_html = ''; $tags = get_the_tags($post_id) ?: []; if (!empty($tags) && is_array($tags)) { // Sort by count desc like Zibll. usort($tags, static function ($a, $b) { return (int) $b->count <=> (int) $a->count; }); foreach ($tags as $tag) { if (!($tag instanceof WP_Term)) { continue; } $tags_html .= '# ' . esc_html($tag->name) . ''; } } $top = $cat_html; if ($top === '' && $tags_html === '') { return ''; } return '
' . $top . ($tags_html !== '' ? '
' . $tags_html : '') . '
'; } endif; if (!function_exists('aksrt_get_post_allow_view_data')) : /** * Category/post reading permission gate (Zibll zib_get_post_allow_view_data subset). * * Supported term meta keys (first match wins, walks parents): * - term meta `post_cat_config` array with `allow_view` = signin|login|roles * - term meta `aksrt_allow_view` string * - post meta `_aksrt_allow_view` string (public|login|signin|roles) * * @return array{allow:bool,type:string,not_html:string,allow_reason:string,html:string} */ function aksrt_get_post_allow_view_data($post = null): array { static $cache = []; $data = [ 'allow' => true, 'type' => '', 'not_html' => '', 'allow_reason' => '', 'html' => '', ]; $post = get_post($post); if (!($post instanceof WP_Post) || $post->post_type !== 'post') { return $data; } if (isset($cache[$post->ID])) { return $cache[$post->ID]; } if (current_user_can('manage_options')) { $data['allow_reason'] = __('您是管理员,可查看所有内容', 'aksrt'); $cache[$post->ID] = $data; return $data; } // Post-level override. $post_allow = sanitize_key((string) get_post_meta($post->ID, '_aksrt_allow_view', true)); if ($post_allow !== '' && $post_allow !== 'public') { $resolved = aksrt_resolve_allow_view_rule($post_allow, [], $post); $cache[$post->ID] = $resolved; return $resolved; } $cats = get_the_category($post->ID); if (empty($cats)) { $cache[$post->ID] = $data; return $data; } foreach ($cats as $cat) { if (!($cat instanceof WP_Term)) { continue; } $rule = aksrt_get_term_allow_view_rule((int) $cat->term_id); if ($rule['type'] === '' || $rule['type'] === 'public') { continue; } $resolved = aksrt_resolve_allow_view_rule($rule['type'], $rule['roles'], $post); if (!$resolved['allow']) { $cache[$post->ID] = $resolved; return $resolved; } } $cache[$post->ID] = $data; return $data; } endif; if (!function_exists('aksrt_get_term_allow_view_rule')) : /** * Walk category ancestors for allow_view config. * * @return array{type:string,roles:array} */ function aksrt_get_term_allow_view_rule(int $term_id): array { static $term_cache = []; if (isset($term_cache[$term_id])) { return $term_cache[$term_id]; } $empty = ['type' => '', 'roles' => []]; $chain = array_merge([$term_id], get_ancestors($term_id, 'category')); foreach ($chain as $id) { $id = (int) $id; $config = get_term_meta($id, 'post_cat_config', true); if (is_array($config) && !empty($config['allow_view'])) { $rule = [ 'type' => sanitize_key((string) $config['allow_view']), 'roles' => is_array($config['allow_view_roles'] ?? null) ? $config['allow_view_roles'] : [], ]; $term_cache[$term_id] = $rule; return $rule; } $flat = sanitize_key((string) get_term_meta($id, 'aksrt_allow_view', true)); if ($flat !== '' && $flat !== 'public') { $rule = ['type' => $flat, 'roles' => []]; $term_cache[$term_id] = $rule; return $rule; } } $term_cache[$term_id] = $empty; return $empty; } endif; if (!function_exists('aksrt_resolve_allow_view_rule')) : /** * @param array $roles Role constraints for type=roles. * @return array{allow:bool,type:string,not_html:string,allow_reason:string,html:string} */ function aksrt_resolve_allow_view_rule(string $type, array $roles, WP_Post $post): array { $type = sanitize_key($type); if (in_array($type, ['login', 'signin'], true)) { $type = 'signin'; } $data = [ 'allow' => true, 'type' => $type, 'not_html' => '', 'allow_reason' => '', 'html' => '', ]; $user_id = get_current_user_id(); $login_url = function_exists('aksrt_get_login_url') ? aksrt_get_login_url() : wp_login_url(get_permalink($post)); if ($type === 'signin') { $data['html'] = '

' . esc_html__('登录后可查看', 'aksrt') . '

'; if ($user_id <= 0) { $data['allow'] = false; $data['not_html'] = aksrt_get_allow_view_deny_shell( __('内容已隐藏,请登录后查看', 'aksrt'), '

' . esc_html__('登录后继续查看', 'aksrt') . '

' . '

' . esc_html__('登录', 'aksrt') . '

' ); } else { $data['allow_reason'] = __('您已登录,可查看此内容', 'aksrt'); } return $data; } if ($type === 'roles') { $need_vip = isset($roles['vip']) ? (int) $roles['vip'] : 0; $need_level = isset($roles['level']) ? (int) $roles['level'] : 0; $need_auth = !empty($roles['auth']); $badges = ''; if ($need_vip > 0) { $badges .= '' . esc_html(sprintf(__('VIP%d 及以上', 'aksrt'), $need_vip)) . ''; } if ($need_level > 0) { $badges .= '' . esc_html(sprintf(__('等级 %d 及以上', 'aksrt'), $need_level)) . ''; } if ($need_auth) { $badges .= '' . esc_html__('认证用户', 'aksrt') . ''; } $data['html'] = '

' . esc_html__('以下用户组可查看', 'aksrt') . '

' . $badges . '
'; $ok = false; if ($user_id > 0) { if ($need_vip > 0 && function_exists('aksrt_get_user_vip_level') && aksrt_get_user_vip_level($user_id) >= $need_vip) { $ok = true; } if (!$ok && $need_level > 0) { $user_level = class_exists('\AKSRT\User\Level') ? \AKSRT\User\Level::get_level($user_id) : 0; if ($user_level >= $need_level) { $ok = true; } } if (!$ok && $need_auth) { $verify = class_exists('\\AKSRT\\User\\AuthApply') && \AKSRT\User\AuthApply::is_verified($user_id) ? 'verified' : ''; if (in_array($verify, ['verified', '1', 'yes'], true)) { $ok = true; } } // If no specific role constraints, any logged-in user passes. if (!$ok && $need_vip <= 0 && $need_level <= 0 && !$need_auth) { $ok = true; } } if (!$ok) { $data['allow'] = false; $body = $data['html']; if ($user_id <= 0) { $body .= '

' . esc_html__('登录', 'aksrt') . '

'; } $data['not_html'] = aksrt_get_allow_view_deny_shell(__('内容已隐藏', 'aksrt'), $body); } else { $data['allow_reason'] = __('您满足查看条件', 'aksrt'); } return $data; } // Unknown type → allow. $data['type'] = ''; return $data; } endif; if (!function_exists('aksrt_get_allow_view_deny_shell')) : function aksrt_get_allow_view_deny_shell(string $title, string $body_html): string { return '
' . '
' . '

' . '

' . esc_html($title) . '

' . $body_html . '
'; } endif; if (!function_exists('aksrt_single_content_allow_view')) : /** * the_content filter — hide body when category/post allow_view denies. */ function aksrt_single_content_allow_view($content) { if (is_admin() || !is_singular('post') || !in_the_loop() || !is_main_query()) { return $content; } $data = aksrt_get_post_allow_view_data(get_post()); if (!empty($data['allow'])) { return $content; } return (string) ($data['not_html'] ?? ''); } endif; // Register gate once helpers load. add_filter('the_content', 'aksrt_single_content_allow_view', 8); if (!function_exists('aksrt_render_related_graphic_card')) : /** * Minimal Zibll style-3 related thumb card. */ function aksrt_render_related_graphic_card(WP_Post $post): string { $subtitle = class_exists('\AKSRT\Core\PostMetaBox') ? (string) \AKSRT\Core\PostMetaBox::get_meta_value($post->ID, 'subtitle', '') : ''; $title = get_the_title($post) . $subtitle; $url = get_permalink($post); $media = aksrt_renderer_resolve_images($post->ID, aksrt_renderer_config(['type' => 'card'])); $thumb = (string) $media['primary']; $time = human_time_diff((int) get_the_time('U', $post), (int) current_time('timestamp')); $views = function_exists('aksrt_get_post_views') ? (int) aksrt_get_post_views($post->ID) : 0; $views_label = function_exists('aksrt_format_number') ? aksrt_format_number($views) : number_format_i18n($views); $img_attrs = aksrt_get_lazy_attr('lazy_cover', (string) $thumb, 'fit-cover', aksrt_get_lazy_thumb('lg')); $html = ''; return $html; } endif;