- Split PayIncome into shell + PayIncomeList flat sibling trait - Add policy callout, per-currency stats, status views, filter card - Show source post/order/buyer, base amount x ratio, expected settle time - Confirm single/batch settlement, selection count, double-submit guard - Redirect back preserving filters; report settled/failed counts - Revenue: add get_status_counts(), share admin_list_where(), drop dead settle() Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
389 lines
22 KiB
PHP
389 lines
22 KiB
PHP
<?php
|
||
/**
|
||
* 创作分成:列表视图(策略提示 + 统计 + 状态视图 + 筛选 + 分成表 + 分页)。
|
||
*
|
||
* 作为 flat sibling trait 被 PayIncome 使用(PSR-4:trait 必须与宿主类同目录)。
|
||
*
|
||
* @package AKSRT
|
||
*/
|
||
|
||
namespace AKSRT\Admin\Native;
|
||
|
||
use AKSRT\Payment\Revenue;
|
||
|
||
defined('ABSPATH') || exit;
|
||
|
||
trait PayIncomeList {
|
||
|
||
private function render_income_list_page(): void {
|
||
NativeUi::header(
|
||
__('创作分成', 'aksrt'),
|
||
__('作者从付费内容订单获得的分成记录。待结算记录到期后自动结算,也可在这里提前手动结算。', 'aksrt'),
|
||
'dashicons-chart-pie',
|
||
[[
|
||
'label' => __('分成配置', 'aksrt'),
|
||
'url' => admin_url('admin.php?page=aksrt-settings#/payment/revenue'),
|
||
'icon' => 'dashicons-admin-generic',
|
||
]]
|
||
);
|
||
$this->render_flash();
|
||
|
||
$policy = $this->revenue_policy();
|
||
$filters = $this->list_filters();
|
||
$query_args = $this->list_query_args($filters);
|
||
$per_page = AdminListPagination::DEFAULT_PER_PAGE;
|
||
$page_num = max(1, (int) ($_GET['paged'] ?? 1));
|
||
$svc = Revenue::get_instance();
|
||
|
||
$this->render_policy_callout($policy);
|
||
$this->render_income_stats($svc->get_stats($filters['user_id']), $filters['user_id']);
|
||
|
||
// 状态计数同时给出状态视图的数字与当前视图的总数,查询前就能夹取页码。
|
||
$repo_args = $this->list_repository_args($filters);
|
||
$counts = $svc->get_status_counts($repo_args);
|
||
$total = $filters['status'] !== '' ? (int) ($counts[$filters['status']] ?? 0) : array_sum($counts);
|
||
$pages = max(1, (int) ceil($total / $per_page));
|
||
|
||
// 页码越界(手工改 URL、或筛选后总数变小)会让 offset 落到数据之外:表格空掉
|
||
// 且分页条不输出,只能手改 URL 退出。先夹到最后一页再查。
|
||
if ($page_num > $pages) {
|
||
$page_num = $pages;
|
||
}
|
||
|
||
$result = $svc->get_list($repo_args + [
|
||
'status' => $filters['status'],
|
||
'limit' => $per_page,
|
||
'offset' => ($page_num - 1) * $per_page,
|
||
]);
|
||
$items = (array) ($result['items'] ?? []);
|
||
$this->prime_list_caches($items);
|
||
|
||
$this->render_status_views($filters, $query_args, $counts);
|
||
$this->render_filter_card($filters);
|
||
|
||
$can_settle = $policy['enabled'];
|
||
$has_pending = $can_settle && in_array('pending', array_column($items, 'status'), true);
|
||
|
||
NativeUi::table_card_open(__('分成记录', 'aksrt'), $has_pending ? $this->batch_form_html() : '');
|
||
echo '<table class="wp-list-table widefat striped aksrt-income-table">';
|
||
echo '<caption class="screen-reader-text">' . esc_html__('分成记录', 'aksrt') . '</caption><thead><tr>';
|
||
echo '<td class="manage-column column-cb check-column">';
|
||
if ($has_pending) {
|
||
echo '<input type="checkbox" data-aksrt-income-check-all aria-label="' . esc_attr__('全选本页待结算记录', 'aksrt') . '" />';
|
||
}
|
||
echo '</td>';
|
||
foreach ([
|
||
'record' => __('记录 / 产生时间', 'aksrt'),
|
||
'author' => __('作者', 'aksrt'),
|
||
'source' => __('来源文章 / 订单', 'aksrt'),
|
||
'base' => __('订单金额 × 比例', 'aksrt'),
|
||
'amount' => __('分成', 'aksrt'),
|
||
'status' => __('状态', 'aksrt'),
|
||
'actions' => __('操作', 'aksrt'),
|
||
] as $key => $label) {
|
||
echo '<th scope="col" class="column-' . esc_attr($key) . '">' . esc_html($label) . '</th>';
|
||
}
|
||
echo '</tr></thead><tbody>';
|
||
|
||
if (!$items) {
|
||
$filtered = array_diff_key($query_args, ['status' => true]) !== [];
|
||
echo NativeUi::empty_row(8, __('暂无分成记录', 'aksrt'), $filtered // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||
? __('没有符合当前筛选条件的记录,请调整或重置筛选。', 'aksrt')
|
||
: __('付费内容订单支付成功后,作者分成会出现在这里。', 'aksrt'));
|
||
}
|
||
foreach ($items as $row) {
|
||
$this->render_income_row($row, $can_settle, $policy['cycle_days']);
|
||
}
|
||
|
||
echo '</tbody></table>';
|
||
NativeUi::table_wrap_close();
|
||
AdminListPagination::render(self::PAGE_SLUG, $total, $page_num, $per_page, $query_args);
|
||
NativeUi::card_close();
|
||
}
|
||
|
||
private function render_income_row(array $row, bool $can_settle, int $cycle_days): void {
|
||
$id = (int) ($row['id'] ?? 0);
|
||
$status = (string) ($row['status'] ?? '');
|
||
$is_points = (string) ($row['currency'] ?? '') === 'points';
|
||
$post_id = (int) ($row['post_id'] ?? 0);
|
||
$buyer_id = (int) ($row['buyer_id'] ?? 0);
|
||
$order_number = (string) ($row['order_number'] ?? '');
|
||
$pending = $status === 'pending';
|
||
|
||
echo '<tr>';
|
||
echo '<th scope="row" class="check-column">';
|
||
if ($pending && $can_settle) {
|
||
echo '<input type="checkbox" form="aksrt-income-batch" name="revenue_ids[]" value="' . esc_attr((string) $id) . '" data-aksrt-income-check aria-label="'
|
||
. esc_attr(sprintf(__('选择分成记录 #%d', 'aksrt'), $id)) . '" />';
|
||
}
|
||
echo '</th>';
|
||
|
||
echo '<td class="column-record"><span class="aksrt-income-id">#' . esc_html((string) $id) . '</span>'
|
||
. '<div class="aksrt-income-sub">' . esc_html((string) ($row['created_at'] ?? '')) . '</div></td>';
|
||
echo '<td class="column-author">' . NativeUi::user_cell((int) ($row['author_id'] ?? 0)) . '</td>';
|
||
|
||
$title = $post_id > 0 ? (string) get_the_title($post_id) : '';
|
||
$post_html = $post_id > 0
|
||
? '<a class="aksrt-income-post" href="' . esc_url((string) get_edit_post_link($post_id)) . '">' . esc_html($title !== '' ? $title : '#' . $post_id) . '</a>'
|
||
: '<span class="aksrt-native-muted">—</span>';
|
||
$buyer = $buyer_id > 0 ? get_userdata($buyer_id) : false;
|
||
$order_url = admin_url('admin.php?page=aksrt_orders&order=' . rawurlencode($order_number));
|
||
echo '<td class="column-source">' . $post_html // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped above.
|
||
. '<div class="aksrt-income-sub"><a class="aksrt-income-order" href="' . esc_url($order_url) . '">' . esc_html($order_number) . '</a>'
|
||
. ($buyer ? ' · ' . esc_html(sprintf(__('买家 %s', 'aksrt'), $buyer->display_name)) : '')
|
||
. '</div></td>';
|
||
|
||
echo '<td class="column-base">' . esc_html($this->format_amount($row['original_amount'] ?? 0, $is_points))
|
||
. '<div class="aksrt-income-sub">' . esc_html(sprintf(
|
||
/* translators: 1 share ratio 2 author level label */
|
||
__('比例 %1$d%% · %2$s', 'aksrt'),
|
||
(int) ($row['share_ratio'] ?? 0),
|
||
$this->author_level_label((int) ($row['author_level'] ?? 0))
|
||
)) . '</div></td>';
|
||
echo '<td class="column-amount"><strong class="aksrt-native-amount' . ($pending ? '' : ' is-positive') . '">'
|
||
. esc_html($this->format_amount($row['amount'] ?? 0, $is_points)) . '</strong>'
|
||
. '<div class="aksrt-income-sub">' . esc_html($is_points ? __('积分钱包', 'aksrt') : __('余额钱包', 'aksrt')) . '</div></td>';
|
||
|
||
echo '<td class="column-status">' . NativeUi::status_badge($status, $this->status_badge_map())
|
||
. $this->status_hint($row, $cycle_days) . '</td>';
|
||
|
||
echo '<td class="column-actions">';
|
||
if ($pending && $can_settle) {
|
||
echo $this->settle_form_html($id); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||
} else {
|
||
echo '<span class="aksrt-native-muted">—</span>';
|
||
}
|
||
echo '</td></tr>';
|
||
}
|
||
|
||
/** 已结算显示结算时间;待结算显示预计自动结算时间(产生时间 + 结算周期,站点时区)。 */
|
||
private function status_hint(array $row, int $cycle_days): string {
|
||
if (($row['status'] ?? '') === 'settled') {
|
||
$at = (string) ($row['settled_at'] ?? '');
|
||
return $at !== '' ? '<div class="aksrt-income-sub">' . esc_html(sprintf(__('%s 结算', 'aksrt'), $at)) . '</div>' : '';
|
||
}
|
||
$created = (string) ($row['created_at'] ?? '');
|
||
if ($created === '') {
|
||
return '';
|
||
}
|
||
try {
|
||
$due = (new \DateTimeImmutable($created, wp_timezone()))->modify('+' . $cycle_days . ' days');
|
||
} catch (\Exception $e) {
|
||
return '';
|
||
}
|
||
$text = $due <= new \DateTimeImmutable('now', wp_timezone())
|
||
? __('已到期,等待自动结算', 'aksrt')
|
||
/* translators: %s expected settle time */
|
||
: sprintf(__('预计 %s 自动结算', 'aksrt'), $due->format('m-d H:i'));
|
||
return '<div class="aksrt-income-sub">' . esc_html($text) . '</div>';
|
||
}
|
||
|
||
private function author_level_label(int $level): string {
|
||
return $level > 0
|
||
/* translators: %d VIP level */
|
||
? sprintf(__('VIP%d 作者', 'aksrt'), $level)
|
||
: __('普通作者', 'aksrt');
|
||
}
|
||
|
||
/** @param array{enabled:bool,cycle_days:int} $policy */
|
||
private function render_policy_callout(array $policy): void {
|
||
if (!$policy['enabled']) {
|
||
echo '<div class="aksrt-native-callout is-warning">' . esc_html__('创作分成功能未启用:不会产生新的分成记录,已有的待结算记录也无法结算。', 'aksrt')
|
||
. ' <a href="' . esc_url(admin_url('admin.php?page=aksrt-settings#/payment/revenue')) . '">' . esc_html__('前往启用', 'aksrt') . '</a></div>';
|
||
return;
|
||
}
|
||
echo '<div class="aksrt-native-callout">' . esc_html(sprintf(
|
||
/* translators: %d settlement cycle days */
|
||
__('结算周期 %d 天:分成产生满周期后由系统每小时自动结算到作者钱包。手动结算会立即入账,不可撤销。', 'aksrt'),
|
||
$policy['cycle_days']
|
||
)) . '</div>';
|
||
}
|
||
|
||
/** 现金与积分分开统计,不跨单位相加;按用户筛选时统计跟随该用户。 */
|
||
private function render_income_stats(array $stats, int $user_id): void {
|
||
$cash = (array) ($stats['cash'] ?? []);
|
||
$points = (array) ($stats['points'] ?? []);
|
||
$scope = $user_id > 0
|
||
/* translators: %d user ID */
|
||
? sprintf(__('用户 #%d', 'aksrt'), $user_id)
|
||
: __('全站', 'aksrt');
|
||
$count_hint = static function (array $bucket) use ($scope): string {
|
||
/* translators: 1 scope 2 record count */
|
||
return sprintf(__('%1$s · %2$s 条记录', 'aksrt'), $scope, number_format_i18n((int) ($bucket['count'] ?? 0)));
|
||
};
|
||
$pending_url = $this->page_url(array_filter(['status' => 'pending', 'user_id' => $user_id ?: null]));
|
||
$settled_url = $this->page_url(array_filter(['status' => 'settled', 'user_id' => $user_id ?: null]));
|
||
|
||
NativeUi::stats([
|
||
['label' => __('现金待结算', 'aksrt'), 'value' => $this->format_amount($cash['pending'] ?? '0', false), 'url' => add_query_arg('currency', 'cny', $pending_url), 'icon' => 'dashicons-clock', 'tone' => 'warning'],
|
||
['label' => __('现金已结算', 'aksrt'), 'value' => $this->format_amount($cash['settled'] ?? '0', false), 'url' => add_query_arg('currency', 'cny', $settled_url), 'icon' => 'dashicons-yes-alt', 'tone' => 'success'],
|
||
['label' => __('现金分成合计', 'aksrt'), 'value' => $this->format_amount($cash['total'] ?? '0', false), 'hint' => $count_hint($cash), 'icon' => 'dashicons-chart-area', 'tone' => 'info'],
|
||
['label' => __('积分待结算', 'aksrt'), 'value' => $this->format_amount($points['pending'] ?? 0, true), 'url' => add_query_arg('currency', 'points', $pending_url), 'icon' => 'dashicons-clock', 'tone' => 'warning'],
|
||
['label' => __('积分已结算', 'aksrt'), 'value' => $this->format_amount($points['settled'] ?? 0, true), 'url' => add_query_arg('currency', 'points', $settled_url), 'icon' => 'dashicons-yes-alt', 'tone' => 'success'],
|
||
['label' => __('积分分成合计', 'aksrt'), 'value' => $this->format_amount($points['total'] ?? 0, true), 'hint' => $count_hint($points), 'icon' => 'dashicons-star-filled', 'tone' => 'info'],
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* @param array<string, mixed> $filters
|
||
* @param array<string, string|int> $query_args
|
||
* @param array<string, int> $counts
|
||
*/
|
||
private function render_status_views(array $filters, array $query_args, array $counts): void {
|
||
$base = array_diff_key($query_args, ['status' => true]);
|
||
$views = ['' => [__('全部', 'aksrt'), array_sum($counts)]];
|
||
foreach ($this->status_labels() as $key => $label) {
|
||
$views[$key] = [$label, (int) ($counts[$key] ?? 0)];
|
||
}
|
||
|
||
echo '<nav class="aksrt-native-tabs aksrt-income-views" aria-label="' . esc_attr__('按结算状态查看', 'aksrt') . '">';
|
||
foreach ($views as $key => [$label, $count]) {
|
||
$url = $this->page_url($base + ($key !== '' ? ['status' => $key] : []));
|
||
$active = $filters['status'] === $key;
|
||
echo '<a class="aksrt-native-tabs__link' . ($active ? ' is-active' : '') . '" href="' . esc_url($url) . '"' . ($active ? ' aria-current="page"' : '') . '>'
|
||
. esc_html($label) . ' <span class="count">' . esc_html(number_format_i18n($count)) . '</span></a>';
|
||
}
|
||
echo '</nav>';
|
||
}
|
||
|
||
/** @param array<string, mixed> $filters */
|
||
private function render_filter_card(array $filters): void {
|
||
NativeUi::card_open('', '', false, 'aksrt-income-filter-card');
|
||
echo '<form method="get" class="aksrt-income-filters" role="search">';
|
||
echo '<input type="hidden" name="page" value="' . esc_attr(self::PAGE_SLUG) . '" />';
|
||
if ($filters['status'] !== '') {
|
||
echo '<input type="hidden" name="status" value="' . esc_attr($filters['status']) . '" />';
|
||
}
|
||
|
||
echo '<label class="aksrt-income-filters__search"><span class="screen-reader-text">' . esc_html__('订单号', 'aksrt') . '</span>'
|
||
. '<input type="search" name="order_number" value="' . esc_attr($filters['order_number']) . '" placeholder="' . esc_attr__('搜索订单号', 'aksrt') . '" /></label>';
|
||
echo $this->filter_select('currency', __('分成币种', 'aksrt'), $this->currency_options(), $filters['currency']); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||
echo $this->filter_select('order_status', __('订单状态', 'aksrt'), $this->order_status_options(), $filters['order_status']); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||
echo '<span class="aksrt-income-filters__range">'
|
||
. '<label><span class="screen-reader-text">' . esc_html__('开始日期', 'aksrt') . '</span><input type="date" name="date_from" value="' . esc_attr($filters['date_from']) . '" /></label>'
|
||
. '<span aria-hidden="true">–</span>'
|
||
. '<label><span class="screen-reader-text">' . esc_html__('结束日期', 'aksrt') . '</span><input type="date" name="date_to" value="' . esc_attr($filters['date_to']) . '" /></label>'
|
||
. '</span>';
|
||
foreach (['user_id' => __('作者 ID', 'aksrt'), 'post_id' => __('文章 ID', 'aksrt')] as $name => $label) {
|
||
echo '<label><span class="screen-reader-text">' . esc_html($label) . '</span><input type="number" min="1" name="' . esc_attr($name) . '" class="aksrt-income-filters__id" value="'
|
||
. esc_attr($filters[$name] > 0 ? (string) $filters[$name] : '') . '" placeholder="' . esc_attr($label) . '" /></label>';
|
||
}
|
||
echo '<span class="aksrt-income-filters__submit"><button type="submit" class="button button-primary">' . esc_html__('筛选', 'aksrt') . '</button>';
|
||
if (array_diff_key($this->list_query_args($filters), ['status' => true]) !== []) {
|
||
$reset = $this->page_url($filters['status'] !== '' ? ['status' => $filters['status']] : []);
|
||
echo '<a class="button" href="' . esc_url($reset) . '">' . esc_html__('重置', 'aksrt') . '</a>';
|
||
}
|
||
echo '</span></form>';
|
||
NativeUi::card_close();
|
||
}
|
||
|
||
/** @param array<string, string> $options */
|
||
private function filter_select(string $name, string $label, array $options, string $current): string {
|
||
$html = '<label><span class="screen-reader-text">' . esc_html($label) . '</span><select name="' . esc_attr($name) . '">';
|
||
foreach ($options as $value => $text) {
|
||
$html .= '<option value="' . esc_attr((string) $value) . '"' . selected($current, (string) $value, false) . '>' . esc_html($text) . '</option>';
|
||
}
|
||
return $html . '</select></label>';
|
||
}
|
||
|
||
/** @return array<string, string> */
|
||
private function currency_options(): array {
|
||
return [
|
||
'' => __('全部币种', 'aksrt'),
|
||
'cny' => __('现金(CNY)', 'aksrt'),
|
||
'points' => __('积分', 'aksrt'),
|
||
];
|
||
}
|
||
|
||
/** @return array<string, string> */
|
||
private function order_status_options(): array {
|
||
return ['' => __('全部订单状态', 'aksrt')] + \AKSRT\Core\DomainModel::order_status_labels();
|
||
}
|
||
|
||
/** 批量结算表单只放提交按钮;表格里的复选框通过 form="aksrt-income-batch" 关联进来。 */
|
||
private function batch_form_html(): string {
|
||
return '<form id="aksrt-income-batch" class="aksrt-native-bulk aksrt-income-batch" method="post" action="' . esc_url(admin_url('admin-post.php')) . '"'
|
||
. ' data-aksrt-confirm="' . esc_attr__('确认立即结算选中的 {count} 条分成?金额会转入作者钱包,不可撤销。', 'aksrt') . '">'
|
||
. '<input type="hidden" name="action" value="aksrt_pay_batch_settle_income" />'
|
||
. $this->operation_key_field()
|
||
. wp_nonce_field('aksrt_pay_batch_settle_income', '_wpnonce', true, false)
|
||
. '<span class="aksrt-income-batch__count" data-aksrt-income-selected aria-live="polite">' . esc_html__('未选择记录', 'aksrt') . '</span>'
|
||
. '<button type="submit" class="button button-primary" disabled data-aksrt-income-batch-submit>' . esc_html__('结算选中', 'aksrt') . '</button>'
|
||
. '</form>';
|
||
}
|
||
|
||
private function settle_form_html(int $id): string {
|
||
return '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '" class="aksrt-income-action"'
|
||
. ' data-aksrt-confirm="' . esc_attr(sprintf(__('确认立即结算分成记录 #%d?金额会转入作者钱包,不可撤销。', 'aksrt'), $id)) . '">'
|
||
. '<input type="hidden" name="action" value="aksrt_pay_settle_income" />'
|
||
. '<input type="hidden" name="revenue_id" value="' . esc_attr((string) $id) . '" />'
|
||
. $this->operation_key_field()
|
||
. wp_nonce_field('aksrt_pay_settle_income_' . $id, '_wpnonce', true, false)
|
||
. '<button type="submit" class="button button-small">' . esc_html__('立即结算', 'aksrt') . '</button></form>';
|
||
}
|
||
|
||
/**
|
||
* 从请求读取并校验筛选条件;非法值一律视为未筛选。
|
||
*
|
||
* @return array{status:string,order_number:string,currency:string,order_status:string,user_id:int,post_id:int,date_from:string,date_to:string}
|
||
*/
|
||
private function list_filters(): array {
|
||
$read = static function (string $key): string {
|
||
return isset($_GET[$key]) ? sanitize_text_field((string) wp_unslash($_GET[$key])) : '';
|
||
};
|
||
$date = static function (string $value): string {
|
||
return preg_match('/^\d{4}-\d{2}-\d{2}$/', $value) ? $value : '';
|
||
};
|
||
|
||
$status = sanitize_key($read('status'));
|
||
$currency = sanitize_key($read('currency'));
|
||
$order_status = sanitize_key($read('order_status'));
|
||
|
||
return [
|
||
'status' => isset($this->status_labels()[$status]) ? $status : '',
|
||
'order_number' => $read('order_number'),
|
||
'currency' => $currency !== '' && isset($this->currency_options()[$currency]) ? $currency : '',
|
||
'order_status' => $order_status !== '' && isset($this->order_status_options()[$order_status]) ? $order_status : '',
|
||
'user_id' => max(0, (int) $read('user_id')),
|
||
'post_id' => max(0, (int) $read('post_id')),
|
||
'date_from' => $date($read('date_from')),
|
||
'date_to' => $date($read('date_to')),
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 当前筛选的 URL 参数(不含 paged):状态视图、翻页与重置链接共用同一份,避免漂移。
|
||
*
|
||
* @param array<string, mixed> $filters
|
||
* @return array<string, string|int>
|
||
*/
|
||
private function list_query_args(array $filters): array {
|
||
return array_filter($filters, static function ($value): bool {
|
||
return $value !== '' && $value !== 0;
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 筛选条件 → Revenue 查询参数(不含状态与分页,由调用方按需追加)。
|
||
*
|
||
* @param array<string, mixed> $filters
|
||
* @return array<string, mixed>
|
||
*/
|
||
private function list_repository_args(array $filters): array {
|
||
return array_diff_key($filters, ['status' => true]);
|
||
}
|
||
|
||
/** 一次性预取本页作者、买家与来源文章,避免逐行查询。 */
|
||
private function prime_list_caches(array $items): void {
|
||
$user_ids = array_merge(array_column($items, 'author_id'), array_column($items, 'buyer_id'));
|
||
$user_ids = array_values(array_unique(array_filter(array_map('intval', $user_ids))));
|
||
$post_ids = array_values(array_unique(array_filter(array_map('intval', array_column($items, 'post_id')))));
|
||
if ($user_ids !== []) {
|
||
cache_users($user_ids);
|
||
}
|
||
if ($post_ids !== []) {
|
||
_prime_post_caches($post_ids, false, false);
|
||
}
|
||
}
|
||
}
|