feat(forum,admin): plate follow-pay MVP, sales column, order type tabs
Wire paid plate follow (admin meta + points/balance purchase + AJAX), re-check plate gate on topics, post list sales column, and order type subtabs; update gap matrix and admin IA map.
This commit is contained in:
1 parent
bccb14a487
commit
cf6ad0e972
12 files changed
+672
-12
No files matched your search
@@ -89,8 +89,10 @@ class AKSRT_Plate_Meta_Box {
|
||||
$wp_roles = $this->wp_role_options();
|
||||
$icon = (string) get_post_meta($plate_id, '_aksrt_icon', true);
|
||||
$sort_order = (int) get_post_meta($plate_id, '_aksrt_sort_order', true);
|
||||
$follow_pay = $this->get_follow_pay_meta($plate_id);
|
||||
|
||||
$this->render_access_fields($allow_view, $add_limit, $view_roles, $add_roles, $wp_roles);
|
||||
$this->render_follow_pay_fields($follow_pay);
|
||||
$this->render_display_fields($icon, $sort_order);
|
||||
$this->render_moderator_fields($moderator_ids, $roles_map, $author_id);
|
||||
$this->render_applications($applications);
|
||||
@@ -151,6 +153,42 @@ class AKSRT_Plate_Meta_Box {
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{enabled:bool,modo:string,price:float,points:int,vip_price:string} $follow_pay
|
||||
*/
|
||||
private function render_follow_pay_fields(array $follow_pay): void {
|
||||
?>
|
||||
<p>
|
||||
<label>
|
||||
<input type="checkbox" name="aksrt_plate_follow_pay_enabled" value="1" <?php checked(!empty($follow_pay['enabled'])); ?>>
|
||||
<strong><?php esc_html_e('付费关注', 'aksrt'); ?></strong>
|
||||
</label>
|
||||
<span class="description" style="display:block;"><?php esc_html_e('开启后,未关注用户需支付才能关注(与「关注可见」配合使用)。', 'aksrt'); ?></span>
|
||||
</p>
|
||||
<p>
|
||||
<label for="aksrt_plate_follow_pay_modo"><strong><?php esc_html_e('关注支付方式', 'aksrt'); ?></strong></label>
|
||||
<select id="aksrt_plate_follow_pay_modo" name="aksrt_plate_follow_pay_modo" class="widefat">
|
||||
<option value="money" <?php selected(($follow_pay['modo'] ?? 'money'), 'money'); ?>><?php esc_html_e('现金(余额)', 'aksrt'); ?></option>
|
||||
<option value="points" <?php selected(($follow_pay['modo'] ?? ''), 'points'); ?>><?php esc_html_e('积分', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label for="aksrt_plate_follow_pay_price"><strong><?php esc_html_e('现金价格(元)', 'aksrt'); ?></strong></label>
|
||||
<input type="number" step="0.01" min="0" class="widefat" name="aksrt_plate_follow_pay_price" id="aksrt_plate_follow_pay_price" value="<?php echo esc_attr((string) ($follow_pay['price'] ?? 0)); ?>">
|
||||
</p>
|
||||
<p>
|
||||
<label for="aksrt_plate_follow_pay_points"><strong><?php esc_html_e('积分价格', 'aksrt'); ?></strong></label>
|
||||
<input type="number" step="1" min="0" class="widefat" name="aksrt_plate_follow_pay_points" id="aksrt_plate_follow_pay_points" value="<?php echo esc_attr((string) (int) ($follow_pay['points'] ?? 0)); ?>">
|
||||
</p>
|
||||
<p>
|
||||
<label for="aksrt_plate_follow_pay_vip_price"><strong><?php esc_html_e('VIP 价格(可选)', 'aksrt'); ?></strong></label>
|
||||
<input type="number" step="0.01" min="0" class="widefat" name="aksrt_plate_follow_pay_vip_price" id="aksrt_plate_follow_pay_vip_price" value="<?php echo esc_attr((string) ($follow_pay['vip_price'] ?? '')); ?>" placeholder="<?php esc_attr_e('留空=不设 VIP 价;0=VIP 免费', 'aksrt'); ?>">
|
||||
<span class="description"><?php esc_html_e('现金模式用元;积分模式填积分数。', 'aksrt'); ?></span>
|
||||
</p>
|
||||
<hr>
|
||||
<?php
|
||||
}
|
||||
|
||||
private function render_display_fields(string $icon, int $sort_order): void {
|
||||
?>
|
||||
<p>
|
||||
@@ -280,6 +318,7 @@ class AKSRT_Plate_Meta_Box {
|
||||
}
|
||||
|
||||
$this->save_access_meta($post_id);
|
||||
$this->save_follow_pay_meta($post_id);
|
||||
$this->save_display_meta($post_id);
|
||||
$this->save_moderators($post_id, (int) $post->post_author);
|
||||
$this->save_applications();
|
||||
@@ -325,6 +364,70 @@ class AKSRT_Plate_Meta_Box {
|
||||
}
|
||||
}
|
||||
|
||||
private function save_follow_pay_meta(int $post_id): void {
|
||||
$enabled = !empty($_POST['aksrt_plate_follow_pay_enabled']);
|
||||
$modo = isset($_POST['aksrt_plate_follow_pay_modo'])
|
||||
? sanitize_key((string) wp_unslash($_POST['aksrt_plate_follow_pay_modo']))
|
||||
: 'money';
|
||||
if (!in_array($modo, ['money', 'points'], true)) {
|
||||
$modo = 'money';
|
||||
}
|
||||
$price = isset($_POST['aksrt_plate_follow_pay_price']) ? max(0, (float) wp_unslash($_POST['aksrt_plate_follow_pay_price'])) : 0;
|
||||
$points = isset($_POST['aksrt_plate_follow_pay_points']) ? max(0, (int) wp_unslash($_POST['aksrt_plate_follow_pay_points'])) : 0;
|
||||
|
||||
// Invalid price while enabled → force off (normalize, no migration).
|
||||
if ($enabled) {
|
||||
if ($modo === 'points' && $points <= 0) {
|
||||
$enabled = false;
|
||||
}
|
||||
if ($modo === 'money' && $price <= 0) {
|
||||
$enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$enabled) {
|
||||
delete_post_meta($post_id, '_aksrt_follow_pay');
|
||||
delete_post_meta($post_id, '_aksrt_follow_pay_modo');
|
||||
delete_post_meta($post_id, '_aksrt_follow_pay_price');
|
||||
delete_post_meta($post_id, '_aksrt_follow_pay_points');
|
||||
delete_post_meta($post_id, '_aksrt_follow_pay_vip_price');
|
||||
return;
|
||||
}
|
||||
|
||||
update_post_meta($post_id, '_aksrt_follow_pay', 1);
|
||||
update_post_meta($post_id, '_aksrt_follow_pay_modo', $modo);
|
||||
update_post_meta($post_id, '_aksrt_follow_pay_price', $price);
|
||||
update_post_meta($post_id, '_aksrt_follow_pay_points', $points);
|
||||
|
||||
if (isset($_POST['aksrt_plate_follow_pay_vip_price']) && (string) wp_unslash($_POST['aksrt_plate_follow_pay_vip_price']) !== '') {
|
||||
$vip = max(0, (float) wp_unslash($_POST['aksrt_plate_follow_pay_vip_price']));
|
||||
update_post_meta($post_id, '_aksrt_follow_pay_vip_price', $vip);
|
||||
} else {
|
||||
delete_post_meta($post_id, '_aksrt_follow_pay_vip_price');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{enabled:bool,modo:string,price:float,points:int,vip_price:string}
|
||||
*/
|
||||
private function get_follow_pay_meta(int $plate_id): array {
|
||||
$enabled = (int) get_post_meta($plate_id, '_aksrt_follow_pay', true) === 1;
|
||||
$modo = sanitize_key((string) (get_post_meta($plate_id, '_aksrt_follow_pay_modo', true) ?: 'money'));
|
||||
if (!in_array($modo, ['money', 'points'], true)) {
|
||||
$modo = 'money';
|
||||
}
|
||||
$vip_raw = get_post_meta($plate_id, '_aksrt_follow_pay_vip_price', true);
|
||||
$vip_set = ($vip_raw !== '' && $vip_raw !== null && $vip_raw !== false);
|
||||
|
||||
return [
|
||||
'enabled' => $enabled,
|
||||
'modo' => $modo,
|
||||
'price' => (float) get_post_meta($plate_id, '_aksrt_follow_pay_price', true),
|
||||
'points' => (int) get_post_meta($plate_id, '_aksrt_follow_pay_points', true),
|
||||
'vip_price' => $vip_set ? (string) (float) $vip_raw : '',
|
||||
];
|
||||
}
|
||||
|
||||
private function save_moderators(int $post_id, int $author_id): void {
|
||||
$role_posted = isset($_POST['aksrt_plate_mod_role']) && is_array($_POST['aksrt_plate_mod_role'])
|
||||
? wp_unslash($_POST['aksrt_plate_mod_role'])
|
||||
|
||||
Reference in new issue
Block a user