Commit Graph
100 Commits
Author SHA1 Message Date
kate522 3481620ed0 feat(payment): 通用卡密兑换弹窗并修正核销订单实付与订单名称
- /user/balance/ 余额卡片入口改为通用「卡密兑换」弹窗:请求不带类型,
  后端按卡密自动识别余额/会员/积分;卡号输入恒展示且选填
- 后台「余额充值 → 卡密充值」语义更新为「卡密兑换」,开关更名
  「启用卡密兑换功能」(设置键不变),双源 schema 同步并重建 SPA
- 删除死代码:credits-vip.php 死文件、credits-balance.php 内联积分
  兑换块、/pay/card-pass/options 路由与 rest_options、labels 数组、
  asset_points_card_description/password_only 死字段及内联块专属 CSS
- 卡密核销订单实付恒 0:create_redeem_order 源头写 0,UserOrders
  对 card_pass 订单视图层归零覆盖历史行(不迁移数据)
- 订单名称按 note.meta 生成:卡密兑换-余额充值X / 卡密兑换-积分充值X /
  购入[会员档位名]X天(永久)
- 新增契约 card-pass-universal-redeem.test.cjs,收紧 user-assets-layout
  契约(禁 .uc-card-pass 根类回潮)
2026-09-17 19:04:47 +08:00
kate522 ba8d4b1b90 卡密充值与兑换接入统一订单号与支付流水号
此前卡密核销虽已建订单,但订单号硬编码 CARD{卡ID}、渠道交易号硬编码
card_pass_{卡ID},均不受后台前缀控制;且核销产生的资金流水没有挂到
订单上(order_number 为 NULL),订单详情页的「支付流水号」恒为「—」。

ChargeCard:
- 新增 allocate_redeem_order_number():走 OrderRepository 统一分配器,
  消费后台「订单前缀」(payment_order_prefix)。
- 新增 card_pass_transaction_number():BusinessNumber::candidate(flow_prefix),
  消费后台「流水号前缀」(payment_flow_prefix)。
- 两条兑换路径(redeem_asset_card / redeem_vip_card)替换硬编码取号;
  create_redeem_order 接收调用方传入的交易号。
- 账本重放(replayed)时回取已落库订单号,不再把本次新分配的号回给前端。

FinancialFlowService:
- record_card_pass_payment():会员卡(0 元、无账本参与)直接落一条
  与订单关联、零分录的 order_payment 流水;record() 新增
  allow_empty_entries 通道(prepare_entries 拒绝 delta=0,占位分录不可行)。
- record_order_event() 新增凭证结算模式:豁免「金额必须 > 0」与
  「资产类订单不得记现金流水」两条门槛(卡密核销既无第三方现金流入,
  订单还可能为 0 元或以积分计价)。
- attach_order_to_ledger_flow():账本提交后把流水补挂到订单上,
  event_type 归一为 order_payment,使「支付流水号」可反查。
- is_successful_order_payment() 认可 card_pass 凭证结算;
  is_external_recharge() 把 card_pass 与 balance/points 一并列为平台内部
  结算方式,不再为卡密充值伪造现金出账分录(现金在售卡时已确认)。

关键取舍:随机订单号不得进入 LedgerCommand 的 metadata —— payload_hash
覆盖 metadata,会破坏账本幂等重放(实测撞 uniq_operation_key 后报
aksrt_ledger_idempotency_conflict),因此订单关联改在账本提交后补挂。

测试:新增 tests/admin/card-pass-order-numbers.test.cjs 钉住上述约束;
容器内三类卡密实测通过(订单号/渠道交易号/支付流水号三项均带后台前缀,
流水行分别携带 balance:in / points:in / 零分录),重放幂等恢复正常。
2026-09-17 14:15:55 +08:00
kate522 c1c21faf7e fix(payment): 生成数量限定为 1-1000 整数并移除 spinner 死属性
生成数量不再受 step 网格约束,只要求「正整数且不超过 1000」即 (0, 1000]。

- 删除 spinner() 产出的 data-min / data-max / data-step:这三个属性在本
  项目全仓**没有任何消费方**(逐文件检索确认),属死代码;原生 min/max/step
  又会让条件显隐行触发 HTML5 校验并静默阻止提交(上一轮已定案)。参数随之
  收敛:spinner(string $name, int $value, string $unit),3 处调用点同步。
- 保留 step="any":省掉它 type="number" 会退回默认 step=1 的整数网格,把
  非整数输入判为非法,同样触发隐藏行的静默拒绝。
- 生成数量的范围收敛为 handle_add() 里的单一区间判定
  `$auto_num < 1 || $auto_num > 1000`,一次覆盖 非数字 / 0 / 负数 / 超上限,
  不再依赖下层静默夹取,也不另设分支;字段说明补上「1 - 1000 的整数」。

验证:
- 容器内真实 HTTP 边界:0 / -5 / 1001 / abc 全部拒绝,1000 / 1 / 3.9 通过
  (3.9 按整数截断)。其中 1000 这个上边界用「type=vip + 空时长」探到 ——
  数量校验通过后即报「请填写兑换会员参数」,零副作用,未真的生成 1000 张。
  正向生成 3 张后已清理,表回到原始 10 条。
- 渲染出的表单内原生约束属性 0 个、data-* 0 个;4 个 number 输入全部 step="any"。
- 契约测试:把「spinner 输出 data-*」的断言反转为「不得出现」,新增签名与
  调用点实参断言、(0,1000] 区间断言、字段说明断言;整文件属性扫描前先剥
  PHP 注释,否则文档注释里的 type="number" 字面量会污染计数。
- 负向对照:重新加回 data-min / 退回 !$auto_num / 签名加回 step 参数,
  三例均精确落到对应用例(各 5 pass / 1 fail),还原后字节一致、6/6 通过。
- tests/admin 四套件 24 pass / 0 fail;php -l 通过;两副本 SHA256 一致。
2026-09-17 13:38:40 +08:00
kate522 481f40378a fix(payment): 修复添加卡密页「确认提交」按钮静默失效
数字输入(auto_num / auto_price / auto_rand_number_limit /
auto_rand_password_limit)此前被平铺成原生 HTML5 约束属性
(min/max/step),叠加两个问题后表现为按钮点了毫无反应:

1) 数值彼此不自洽:参考主题 CSF spinner 的 default=20 / min=1 /
   step=10 合法格点是 1,11,21…,默认值 20 当场就非法;
   auto_rand_number_limit 同理(默认 20、格点 1,6,11…)。
2) 这些行是条件显隐的(field_row 输出 <tr data-dep>,不满足依赖时
   display:none)。提交时浏览器仍会校验隐藏控件,而隐藏控件无法聚焦
   去弹提示气泡,于是 Chrome 只往控制台丢一句
   "An invalid form control ... is not focusable" 便静默拒绝提交——
   不跳转、不报错、无 notice,用户看到的就是按钮坏了。

处置:数字输入改用 data-min/data-max/data-step + step="any"
(与参考主题 CSF_Field_spinner::render() 语义一致),不再写任何原生
约束属性;auto_price 一并去掉 min="0",面额下限改由服务端夹取兜底
(max(0.0, ...)),避免「去掉客户端下限」变成放行负面额。

验证:
- 无头 Chrome 探针:btn.click() 触发的 submit 事件 0 → 1,
  参与校验控件 23 个、无效 3 个 → 0 个;
- 服务端扫描页面 25 个 input:带原生约束的 0 个;
- 服务端面额夹取:-5 拒绝、0.001 拒绝、12.5 正常生成 1 张;
- 新增 tests/admin/charge-cards-form-constraints.test.cjs(4 例),
  并做负向对照(重引入 min/step 后 2 pass / 2 fail);
- tests/admin 四个套件合计 22 pass / 0 fail。
2026-09-17 13:19:05 +08:00
kate522 52d790c654 fix(payment): 卡密管理每页默认 20 条,撤掉工具栏「每页显示」控件
- DEFAULT_PER_PAGE 由 30 改为 20。
- 删除 per_page_selector() 及其表单样式(.aksrt-perpage-form / .order-header-right),
  工具栏恢复为「过滤链接 + 搜索表单」两段式。
  ice_perpage 仍作为 URL 参数被尊重,只是不再提供界面入口。
- 保留上一提交的分页健壮性修复:页码夹取到 [1, total_pages]、翻页链接用显式基准 URL、
  越界页码回退并重查、禁用按钮 pointer-events:none。
- 契约测试同步改写:断言默认值为 20,并显式禁止「每页显示」控件回归。

验证:默认态渲染为「每页 20 共10」,页面内不存在 aksrt-perpage-form;
ice_perpage=5 仍能翻到第 2 页且链接携带该参数;paged=2 越界仍回退到第 1 页的 10 行;
node --test 三套 18/18;php -l 通过;无头 Chrome 截图确认工具栏无多余控件。
2026-09-17 13:03:05 +08:00
kate522 0e7b888277 fix(payment): 修复卡密管理分页:页码夹取、显式基准 URL、补齐每页条数入口
- render_pagenavi():页码先夹到 [1, total_pages],禁用状态由 $on_first / $on_last
  一次导出。旧写法是一串 if/elseif,页码越界时三个分支一个都不命中,
  上一页与下一页同时停在 '#':既不打 disabled 也点不动。
- 翻页链接改用显式基准 URL(page_url + 当前筛选参数),不再依赖
  add_query_arg() 默认取 $_SERVER['REQUEST_URI'] 的行为;
  status / type / other / s / orderby / desc / ice_perpage 随链接带走。
- render_list():页码越界(手改 URL、或筛选后总数变小)时回退到最后一页重查,
  消除「空白表格 + 一个分页控件都没有」的死胡同。
- 新增「每页显示」选择器(ice_perpage)。该参数此前只有服务端读取、界面上没有
  任何入口能改,条数小于默认每页条数时永远只有一页,分页条恒为 disabled。
- 禁用按钮加 pointer-events:none,避免点空还滚回页首。
- 新增 tests/admin/charge-cards-pagination.test.cjs(6 条契约)。

验证:容器内真实渲染 7 组 URL(默认 / 每页 5 / 第 2 页 / paged=2 越界 /
paged=99 越界 / 带 status 筛选 / 非预设每页 7),无头 Chrome 截图核对版式;
node --test 三套 18/18 通过;负向对照(还原旧写法)按要求失败 2 条;php -l 通过。
2026-09-17 12:45:22 +08:00
kate522 1e5286d36b fix(payment): 导入提示的条目列表改用 <ul> 承载,圆点不再越出文字边界
四条导入提示里的 <li> 原先裸挂在 <div class="aksrt-submsg"> 下,没有列表容器:
list-style-position 默认 outside,圆点画在内容盒左侧的 padding 区里,而 <li>
自身没有 padding,于是圆点溢出到提示块的文字边界之外(真实后台 CSS 下实测 −8px,
视觉上紧贴提示块左侧色条)。

改动:
- 四条提示的 <li> 各用一个 <ul class="aksrt-submsg-list"> 包起来(同时修掉
  <li> 缺少列表父元素的非法标记)。
- .aksrt-submsg-list 显式声明 margin / padding-left / list-style,不依赖 UA
  或后台对 ul 的默认值,避免别处的重置再次把圆点挤出去。
- 新增契约用例:提示内的 <li> 必须在 <ul class="aksrt-submsg-list"> 中、标签成对、
  每条提示只有一个列表容器,且该类的 CSS 必须带 padding-left 与 list-style。

实测(真实 Chrome + 真实后台 common/forms/list-tables CSS):圆点左缘由
「文字边界 −8px(溢出)」变为「文字边界 +12px(界内)」,条目文字缩进 20px。
2026-09-17 12:28:09 +08:00
kate522 d787f3ff97 fix(payment): 导入提示不再使用 WP notice 类,避免被 common.js 搬到页面顶部
真因:wp-admin/js/common.js 在 DOM 就绪时执行
  $('div.updated, div.error, div.notice').not('.inline, .below-h2').insertAfter($headerEnd)
它会把页面上所有「非 inline」的 notice 搬到 .wp-header-end(不存在时取 .wrap 内首个
h1/h2)之后。提示块原先输出 class="aksrt-submsg notice notice-warning",被判定为
notice,于是在求值之后被整块搬到页头:既脱离「添加方式—卡密数据」之间的字段区,
又因为搬迁发生在 evalDeps 之后,行内显隐逻辑无从纠正。

这也是同一现象反复出现的真因:四条提示都可见时会被整体搬到页面最上方;给提示块
补上初始隐藏后看起来像「提示不见了」;改为全文档求值后则表现为「提示显示在页面
最顶部」。此前的 foster-parenting 判断有误——服务端输出的表格结构始终合法。

改动:
- submessage_row() 只输出自有类名 aksrt-submsg,不再复用 .notice / .notice-warning。
- 外观(底色 #fef8ee + 左侧 4px #f0b849 色条)改由 .aksrt-submsg 自带,与参考主题
  CSF content 字段的做法一致;元素内联样式只保留初始隐藏状态。
- 新增契约用例:提示块不得带 notice;.aksrt-submsg 必须自带 background 与 border-left;
  并确认页面级错误通知仍正常使用 notice(不误伤其它通知输出)。
2026-09-17 12:19:25 +08:00
kate522 45c7a4a59c fix(payment): 添加卡密页导入提示移至卡密数据上方并修正脱离表单后不显示
- 四条导入提示与「单密码模式」开关收拢到「卡密数据」行正上方:切换卡密类型/
  添加方式时,命中的那一条紧邻示例数据与输入框,便于对照填写。原先单密码模式
  开关夹在两条提示之间、提示又落在自动生成字段之后的位置不再使用。
- evalDeps() 与 change 监听不再限定在 .aksrt-cardpass-form 子树内,改为全文档
  查找 [data-dep]。提示块一旦被移出表单子树,限域查找会漏过它,其内联
  display:none 无人清除,表现为「切换到导入卡密后提示不显示」。
- 契约测试同步收紧:断言必须为全文档选择器,并显式禁止回退为限域写法。
2026-09-17 12:03:13 +08:00
kate522 670e271ff6 fix(payment): 添加卡密页提示块自带依赖状态,脱离所在行也不再铺开
用户复报「四条导入提示仍然全部铺开」。其 DevTools 实测给出关键判据:
同一页面上 formClass=1 / submsg=4 / depRows=17 与线上一致,但四条提示的
父级 <tr> 为 null、computed display 为 block —— 也就是说提示块虽在 DOM 中,
却不在任何表格行内。此时依赖状态只挂在 <tr> 上,隐藏与切换都无处落地,
于是四条提示永久可见、切换卡密类型/添加方式也没有反应。

修复:把 data-dep 与初始隐藏状态同时挂到内层提示块上,求值器改为
「谁带 data-dep 就管谁」,行与提示块各自落自己的 display。

变更(src/Admin/Native/PayChargeCards.php):
- submessage_row():<tr> 与内层 <div class="aksrt-submsg"> 共用同一份
  data-dep;初始隐藏状态合并进提示块原有的 margin/padding 内联样式,
  不产生重复的 style 属性。原「只给 <tr> 加 style」的写法保留给行本身。
- evalDeps():选择器由 '.aksrt-cardpass-form tr[data-dep]' 放宽为
  '.aksrt-cardpass-form [data-dep]',并改用 el.style.display 落值。

测试(tests/admin/charge-cards-dependency.test.cjs):
- DOM 桩按真实结构为每条提示建「行 + 提示块」两个元素,新增用例
  「提示块与所在行同层落 display」断言两层始终同状态(默认 8 个元素全隐藏、
  命中依赖时仅该提示的两层可见、切回默认两层同时收起)。
- 契约用例新增三条静态断言:提示块必须自带 data-dep、必须自带初始隐藏状态、
  求值选择器必须同时覆盖行与提示块。
- 负向验证:把提示块的 data-dep 去掉后跑测试 → pass 5 / fail 1,护栏生效。

验证:
- node --test 两个 admin 契约测试 10/10 通过;php -l 无语法错误;
- 线上抓取:tr_total=19 / tr_with_dep=17 / div_with_dep=4 / display_none=18;
  四条提示的 div 均带 data-dep="…" 与 display:none。
- 真实浏览器模拟「提示块被搬出所在行」(foster-parent 到 <table> 之前)后:
  默认态四条全部 none;切到「会员兑换 + 导入卡密」时,只有已脱离行的
  「导入会员兑换卡密」变为可见(ownStyle 中的 display:none 被移除),
  其余三条维持 none;切回默认四条全部收 none。
2026-09-17 11:41:05 +08:00
kate522 5243bbf0d4 fix(payment): 添加卡密页清理依赖求值死代码并锁定显隐契约
render_add_form() 渲染 19 行表单,其中 17 行带 data-dep;4 条导入提示
(导入卡密 / 导入会员兑换卡密 / 自定义卡密导入 / 自定义卡密导入-单密码模式)
的显隐依赖已由服务端预隐藏与服务端默认值修正落地,本次仅做收尾。

变更:
- 删除行内脚本 IIFE 末尾的 evalDeps() 死调用。该调用位于表单之前的
  解析期(脚本在表单前输出),此刻 document 中尚无任何 tr[data-dep],
  属于必然空操作;初始求值统一交由 DOMContentLoaded 分支处理。
- 补充注释说明「脚本在表单前输出 → 解析期取不到行 → 必须等 DOM 就绪」,
  避免后人误加回解析期调用。
- .gitignore 追加 /tests/admin/charge-cards-dependency.test.cjs 白名单。

新增契约测试 tests/admin/charge-cards-dependency.test.cjs(5 用例,全过):
从源码抽取 field_row/submessage_row 的 data-dep,用 Node vm 加载真实行内
脚本并以最小 DOM 桩驱动,断言:
1) 依赖键须在 is_known_dep_key 与 default_form_value 成对登记;
2) 服务端预判与前端求值使用同一组操作符且覆盖表单实际用到的全部操作符;
3) 两类行渲染均接入服务端预隐藏,避免首帧铺开;
4) 行内脚本不再保留解析期空操作求值;
5) 导入提示跟随「卡密类型 × 添加方式」切换(balance/credits/vip/custom
   及单密码模式矩阵),且不同时铺开、切回 auto 全部收起。

负向验证:将 balance,credits 篡改为 balance,credits,vip 后测试转为
pass 4 / fail 1,护栏确实生效。

验证:node --test 两个 admin 契约测试 9/9 通过;php -l 无语法错误;
dev 与运行副本内容一致(行尾归一后逐字节相同)。
2026-09-17 11:03:34 +08:00
kate522 1cbc0c6ed8 fix(payment): 排序箭头改为基线锚定,修正表头箭头相对文字偏下
.orderby-but 从「无尺寸 inline 宿主 + 依赖绝对定位静态位置 + 固定
translateY(-3px)/6px」改为「零尺寸 inline-block 宿主 + bottom 锚定 + translateY(50%)」。

原理:空 inline-block 的基线即其下边缘,会与同行文字基线对齐,于是箭头盒可用 bottom
精确锚定到「基线以上 N em」;translateY(50%) 抵消箭头自身高度,使盒中心恒等于 bottom 值,
与 dashicons 盒高无关。两枚箭头中心分别落在基线以上 .725em / .075em,对称于文字视觉中心。

旧写法的问题:绝对定位元素未指定 top/bottom 时,其位置来自静态位置(容器内容盒顶部),
该值与表头字体/行高联动;在真实后台 CJK 字体度量下整体偏下。

量测(无头 Chrome + 真实 wp-admin common.css/list-tables.css + 真实表头标记):
- 旧写法:箭头簇中心相对文字中心 +2.0px(复现用户反馈的「偏下一点」)
- 新写法:-0.09px;两箭头相对文字中心 -4.64 / +4.46,居中对称
- 表头行高两版均为 36.59px,无行高副作用

契约测试同步收紧:断言 bottom 锚定写法,并禁止回归到无 bottom 的固定像素位移。
2026-09-17 10:28:17 +08:00
kate522 537fb97f48 fix(settings): 充值套餐选项为数组时不再触发数组转字符串警告
get_payment_recharge_settings() 原先先对 pay_balance_product 做强转、再判
is_array:当该选项以数组保存时会触发 PHP "Array to string conversion" 警告,
且强转结果随即被覆盖,属无效语句。改为按类型二选一转换,输出行为不变。
2026-09-17 10:14:21 +08:00
kate522 9fffe7b590 fix(payment): 卡密管理页标题按钮单点输出并修正排序箭头下沉
- 标题右侧按钮原在页面头部与列表渲染函数各输出一次(实际渲染 3 个
  page-title-action,「添加卡密」重复出现),改为只在页面头部的 tab switch 中
  拼一次;render_list() 收为 render_list(string $s),只渲染过滤链接与表格,
  搜索词在页面头部单次解析后传入,搜索提示仍按参考主题跟在按钮之后。
- .orderby-but 恢复参考主题写法(position: relative,不设 display)。
  箭头是绝对定位元素且不写 top/left,位置取自容器的静态位置;容器一旦变成零
  高度 inline-block,基线会退化为自身下边缘并与文字基线对齐,整组箭头下沉一
  个字高。同时补回参考主题的 padding-right: 1em,并加注释锁定该约束。
- 清理死代码:行循环中 custom 分支的 $type_html 赋值总被下方类型链覆盖,已删除。
- 新增 tests/admin/charge-cards-page-contract.test.cjs(4 例)作为回归护栏,
  并按 .gitignore 既有白名单惯例放开该文件。
2026-09-17 10:14:19 +08:00
kate522 282a12a90b fix(payment): 依赖求值改按 name 属性匹配,避免选择器异常静默失效
- formVal 不再把字段名拼进 CSS 选择器:vip_exchange[time] 等含方括号的名称会令选择器抛异常并被 try/catch 吞掉,导致依赖行永久停在初始状态
- 改为 fieldsByName 按 getAttribute('name') 逐元素匹配,radio 选中态也在同一集合内判断
- evalDeps 作用域收窄为 .aksrt-cardpass-form tr[data-dep],避免误命中页面上其他表格的依赖行
2026-09-16 23:03:56 +08:00
kate522 cb84c88792 fix(payment): 修正导入提示的服务端依赖判定键缺失
- 补全 is_known_dep_key 白名单:加入 only_pass_s 与 vip_exchange[time],其默认值统一按空字符串处理
- 修复服务端 !=/checked 类依赖因默认值缺失而错判的问题:自定义卡密的两条导入提示此前会被同时判为可见,导致四条提示全部铺开
- 服务端预判与行内 JS 求值器语义现已逐条对齐,任意状态下最多显示 1 条导入提示
2026-09-16 22:46:26 +08:00
kate522 ef9409cee6 fix(payment): 添加卡密页依赖字段初始状态按默认值隐藏
- 渲染期按表单默认值预判依赖可见性(deps_visible/default_form_value),不满足项直接输出 display:none,消除导入提醒首帧全部显示的问题
- 行内 JS 在 DOMContentLoaded 兜底执行一次依赖求值,交互前后状态与服务端一致
2026-09-16 22:40:35 +08:00
kate522 678143e7b9 feat(payment): 卡密管理改为独立页面并对齐参考主题
- 移除「余额充值」设置中的充值卡(card_pass_*)配置组,PHP schema 与 SPA mirror 双轨同步
- 重写后台卡密管理页:列表过滤/排序/搜索/批量删除/同款分页/点击复制、自动生成与导入、text/xls 导出
- ChargeCard 服务新增 generate_cards/rand_number/rand_password/delete_by_ids/get_export_rows,get_list 支持参考主题排序别名与标识过滤
- 删除无消费方的 /payment/charge-cards REST 路由及 batch_create/disable 死代码,数据层零迁移
2026-09-16 22:05:37 +08:00
kate522 ba1c8c2822 style(user-center): 卡密兑换弹窗按钮右对齐 2026-09-16 21:20:23 +08:00
kate522 2ef02e2865 feat(user-center): 余额卡密兑换移入弹窗并在余额卡片增加入口
- 余额卡片右下角新增「卡密兑换」点击区(data-aksrt-card-pass-open)
- 内联 uc-card-pass 区块替换为 uc-modal 弹窗,兑换逻辑不变
- initCardPass 增加弹窗开关绑定(防重复绑定)
- 清理 :first-child > .uc-card-pass 死选择器片段
2026-09-16 21:15:04 +08:00
kate522 ff11f3b156 fix(payment): 结算货币旧小写值导致枚举校验失败无法保存
paypal_currency/stripe_currency 由自由文本改为 select 后,旧存储值(如
stripe_currency=usd 小写)不通过枚举校验,收款接口页保存被 422 拦截。
为两个货币字段增加 case_insensitive 归一化:读取时归一为选项规范写法、
写入时归一化、校验时大小写不敏感放行,匹配不到回退默认 USD。
2026-09-16 19:56:51 +08:00
kate522 14f9534651 fix(payment): 充值商品选项旧字符串值导致假条目且不可删除
- SchemaProvider 读取时 group/repeater 字段忽略非数组旧值(textarea 时代的
  字符串),回退默认数组,避免前端按字符渲染出 20+ 条假条目
- AksField group/repeater 渲染改为数组安全视图(非数组一律按空列表)
- 充值商品选项默认条数调整为 3 条(PHP 与前端 schema 同步)
2026-09-16 19:46:49 +08:00
kate522 2c139e5c20 fix(payment): 修复推广返佣与收款接口 schema 顶层常量 TDZ 报错
affiliate.js 的 rebateTypeOptions 与 gateway.js 的 currencyOptions 定义在
文件底部,而 schema 对象在模块顶层即引用,ES 模块顶层代码立即执行导致
const 声明前访问触发 ReferenceError(压缩后表现为 Cannot access 'He')。
将常量上移至 schema 对象之前。
2026-09-16 19:36:27 +08:00
kate522 a48007a44d feat(payment): 支付&付费菜单按参考主题重构并新增提现策略页
- 子菜单重组为知识付费/余额充值/VIP会员/创作分成/推广返佣/收款接口/提现策略
- 收款接口页 1:1 复刻 Zibll 双下拉结构,仅保留支付宝/微信/PayPal/Stripe/易支付
- 订单前缀/流水号前缀/提现单号前缀配置保留并移入收款接口页
- 知识付费/推广返佣按参考主题全字段复刻,余额充值并入充值卡配置
- 新增 tabbed/between_number/page_select 表单控件及后端 pages 搜索源
- 清理旧 SPA 组件、无消费者 REST 端点与废弃配置键(不写双路兼容)
- 更新存量契约测试至新 schema 文件
2026-09-16 19:18:28 +08:00
kate522 fb5cdf247d feat(user-center): 官方认证面板 1:1 复刻参考主题视觉
- 面板主体改为 Zibll 同款 colorful-bg hero 卡片(大图标/标题/状态区)
- 保留云认证 modal 流程与 data-* 功能钩子,13 个钩子一一对应
- 清理旧 uc-auth-card 面板样式与无引用的 uc-auth-upload/apply-detail 死样式
- 新增 #panel-auth 去壳样式,去除外层白卡使卡片成为唯一内容
2026-09-16 18:06:48 +08:00
kate522 098df7f921 fix(user-center): 去除余额金额显示前¥符号 2026-09-16 17:39:40 +08:00
kate522 175d32f01e fix(tests): 修复存量合约测试失败 2026-09-16 17:24:22 +08:00
kate522 56d1b2a417 fix(user-center): 防止大额资产金额断行 2026-09-16 17:23:56 +08:00
kate522 e7ffb44b45 fix(admin): 兼容提现金额历史配置 2026-09-16 14:12:40 +08:00
kate522 bcba58f227 fix(user-center): 对齐宽屏提现记录列 2026-09-16 13:31:36 +08:00
kate522 a26ef3fadd fix(user-center): 对齐窄屏提现状态标签 2026-09-16 13:20:53 +08:00
kate522 0871c8ea81 fix(user-center): 优化提现记录窄屏布局 2026-09-16 13:16:16 +08:00
kate522 3cedcd1bc2 fix(user-center): 单独弱化实际到账金额 2026-09-16 13:10:13 +08:00
kate522 d4e33706cf style(user-center): 弱化提现记录文字样式 2026-09-16 13:05:56 +08:00
kate522 2c4bd3eb2a fix(user-center): 调整提现记录金额展示 2026-09-16 13:00:27 +08:00
kate522 6bbb79213b fix(user-center): 优化提现记录弹窗分页 2026-09-16 12:53:38 +08:00
kate522 27f54c8e35 修复资产卡片底部对齐 2026-09-15 22:24:49 +08:00
kate522 7efbbeed3f 修复余额页顶部资产卡片高度 2026-09-15 20:50:21 +08:00
kate522 f00045502f 收紧顶部卡片与下方主卡片的间距 2026-09-14 12:57:57 +08:00
kate522 0a4448dd70 收紧顶部卡片与下方主卡片的间距 2026-09-14 12:53:20 +08:00
kate522 9e9918b7f3 修正“成长体系”卡片顶部字段错位问题 2026-09-14 12:48:17 +08:00
kate522 486fc34a4b 修正“成长体系”卡片顶部字段错位问题 2026-09-14 12:45:01 +08:00
kate522 1873018a2a Merge pull request 'fix(user): replicate level center page' (#33) from worktree/user-level into main
Reviewed-on: #33
2026-09-14 04:29:49 +00:00
kate522 632a7d15ba fix(user): replicate level center page 2026-09-13 21:28:10 +08:00
kate522 6f1860f5d0 Merge pull request 'fix(email): lock templates to built-in catalog' (#32) from worktree/email-config-hard-cut into main
Reviewed-on: #32
2026-09-13 12:04:57 +00:00
kate522 129eb25078 fix(email): lock templates to built-in catalog 2026-09-13 20:02:56 +08:00
kate522 3f02048bc5 test(admin): read the picker css before asserting the hidden guard 2026-09-06 16:38:42 +08:00
kate522 abf3a4ae31 fix(admin): re-assert [hidden] inside the icon modal so tabs and search switch 2026-09-06 16:37:11 +08:00
kate522 5c226237c0 fix(admin): wrap the icon picker tabs and shorten catalog group titles 2026-09-06 16:28:07 +08:00
kate522 af04fcfd3c fix(admin): bind FaIconPicker with v-model so icon clicks update the value 2026-09-06 16:10:28 +08:00
kate522 5acd1e0e25 chore(build): restore the tracked build/.gitkeep placeholder 2026-09-06 15:55:31 +08:00
kate522 26afa6ea3a revert(build): stop tracking the admin SPA build output
Tracking assets/admin/build was wrong — it is deploy-only output.
Revert to the ignored state; deploy by building on the target:
cd assets/admin && npm ci && npm run build
2026-09-06 15:53:50 +08:00
kate522 39bafb65c4 fix(icons): render FA glyphs in the SPA picker grid and harden item clicks
The server catalog ships bare glyph names, but the SPA grid preview
composed "fas home" instead of "fas fa-home" — every FA icon rendered
blank (the old curated lists carried the fa- prefix, so the regression
appeared with the catalog switch).

Item clicks move from per-element @click to a delegated panel handler
reading data-icon (immunity to DOM-replacing extensions/userscripts,
matching the PHP picker's pattern), and selecting now closes the
popover so the choice is visible in the field immediately.
2026-09-06 15:48:52 +08:00
kate522 27d8a9ea71 build(admin): track the SPA build output so git deploys carry it
assets/admin/build was gitignored, so servers deployed by git pull kept
running a stale admin bundle — the icon picker integration in the tabbar
and floating-button settings pages never reached them. Track the build
directory (rebuild with: cd assets/admin && npm run build) and commit the
current bundle containing the universal icon picker.
2026-09-06 14:35:15 +08:00
kate522 2e25894eb5 fix(navigation): stop mangling zibsvg/customsvg menu icons
aksrt_render_menu_icon() prefixed any value without an fa substring
with fa fas fa-, turning picker values like zibsvg-hot into
fa fas fa-zibsvg-hot — blank icons in the frontend nav. Sprite and
inline SVG values now flow through aksrt_icon_markup with the
menu-item-icon classes attached; FA values keep the legacy padding.
2026-09-06 14:27:49 +08:00
kate522 70cba11fb7 feat(icons): wire the universal picker into tabbar/floating settings and keep customsvg through their save paths
手机底部Tab and 右侧悬浮按钮 settings pages swap their icon text inputs
for the shared FaIconPicker (with a new IconValue preview component that
renders FA/sprite/custom SVG values in lists and previews). footer.php
tabbar/floating/sub-item icons and the VIP float render through
aksrt_icon_markup so every stored format displays; GlobalControllerPart1
and the VIP helper drop the FA-only regex gate and sanitize icon values
through aksrt_sanitize_icon_value. The picker popover tabs now wrap
instead of overflowing, and FA grid previews use style-only classes.
2026-09-06 14:27:49 +08:00
kate522 d89752d543 Merge pull request 'fix(icons): render brand icons under the fa fab double prefix and drop an empty sprite key' (#31) from worktree/icon-picker into main
Reviewed-on: #31
2026-09-06 05:35:05 +00:00
kate522 7ab5f29f87 fix(icons): render brand icons under the fa fab double prefix and drop an empty sprite key
FA5's own single-class declarations lose the cascade to the later
.fa,.far,.fas family rule, so zibll-legacy values like "fa fab fa-weixin"
rendered with the Free font and came up blank — visible in the picker's
brand tab (500px…zhihu) and on every brand icon in the SPA and frontend
social links. Re-assert .fa.fab (and .fa.far weight) in the three
stylesheets that load FA5. Also remove the empty aksrt_svgs['qqww']
sprite entry, which surfaced as a blank built-in SVG item.
2026-09-06 13:31:24 +08:00
kate522 5e2cc7b56a Merge pull request 'Worktree/icon picker' (#30) from worktree/icon-picker into main
Reviewed-on: #30
2026-09-06 05:09:54 +00:00
kate522 2e9650d15f test(widgets): contract-lock the universal icon picker
Assert the generated FA5 catalog, the REST route + sprite single
source, picker field wiring in widgets and nav menus, SVG-aware icon
sanitization on both save paths, the single aksrt-font-awesome handle
with FA5 class names, and the consolidated assets/icons layout.
2026-09-06 13:00:13 +08:00
kate522 7cd39e278a chore(assets): remove dead icon assets and consolidate icons/
Delete zero-referenced leftovers (31 img SVGs, duplicate top-level
vip badges, favicon/icon/person_background pngs, assets/fonts/,
tmp-debug/, gutenberg-extend.js and the FA eot/ttf/svg font formats)
and give icon-purpose SVGs one home in assets/icons/ (upload-add,
default favicon/logo, playing, user-certification) with every reference
updated. Icon SVG files were audited by name across PHP/CSS/JS before
deletion.
2026-09-06 13:00:13 +08:00
kate522 e4745d501e refactor(icons): converge every icon render on aksrt_icon_markup
aksrt_get_comment_icon(), aksrt_renderer_svg_icon() and the widget
renderer's private icon_markup() all delegate to the unified helper,
and the duplicated 24px empty-state SVGs in user-center/user-home now
come from one aksrt_empty_state_svgs(). Contract tests follow the
delegation (sprite <use> markup asserted in the helper).
2026-09-06 12:59:44 +08:00
kate522 d599bbccd9 fix(icons): swap FA4-only class names for FA5 equivalents
fa-clock-o/fa-folder-open-o did not exist in the bundled FA5 fonts and
rendered nothing; fa-file-text-o maps to fa-file-alt in FA5 Free (there
is no fa-file-text glyph either).
2026-09-06 12:59:31 +08:00
kate522 5b5db0f8f5 feat(admin): back the SPA icon picker with the server catalog
FaIconPicker drops its duplicated hard-coded FA subset and loads
GET /aksrt/v1/icons/catalog: full solid/regular/brands sets, the
built-in zibsvg sprite tab and an inline custom SVG tab. Props/emit
surface is unchanged; the system-notice title icon schema drift
(input vs icon) is fixed on the JS side.
2026-09-06 12:59:30 +08:00
kate522 009f9874c0 feat(widgets): render icon fields with the universal icon picker
The widget FormRenderer icon case and the nav-menu item icon field now
emit the shared picker (preview + choose/clear + editable text input,
delegated events so lazy forms and repeater rows work). Icon values are
sanitized through aksrt_sanitize_icon_value on both save paths so inline
customsvg- markup survives; the widget admin screen enqueues the picker.
2026-09-06 12:59:12 +08:00
kate522 f629a4f373 feat(icons): add the FA5 catalog, REST endpoint and unified icon helpers
Mirror the reference theme's universal picker on FA5: a generated full
catalog of the bundled FA5 Free 5.15.4 fonts (src/Icons/fa5-icons.php,
generated from the shipped CSS + SVG fonts), a zibsvg group parsed from
the runtime sprite so it cannot drift, and GET /aksrt/v1/icons/catalog.

Shared admin pieces: aksrt_icon_markup()/aksrt_sanitize_icon_value()
with an SVG allowlist, the picker field/modal assets, and one canonical
aksrt-font-awesome handle registered through aksrt_enqueue_fontawesome().
2026-09-06 12:59:03 +08:00
kate522 9496db5171 fix(single): place the video footer breadcrumb like the reference
Drop the invented .post-breadcrumbs wrapper and echo the breadcrumb
inside the reference's flex jsb at row; split .single-video .breadcrumb
out of the cover-overlay rule (-6px pull and opacity reset belong to
title-over-cover contexts only) and restore the legacy 15px footer
padding. Pin the structure in the cover contract test and rebuild the
homepage aggregates.
2026-09-06 11:26:21 +08:00
kate522 d3eef19b95 fix(single): match the reference video cover height (bare ratio)
Zibll reserves +50px only for covers whose title overlays them
(image/slide via .single-cover/.single-cover-slide); the video cover
keeps its title in the footer below and uses the bare scale height
(.dplayer-scale-height). Drop the +50px from the video box, pin the
reference height matrix in the contract test, and refresh the stale
slide-action assertion in the toast contract.
2026-09-06 11:12:13 +08:00
kate522 7c0d5945ca fix(single): stop the video cover letterboxing inside its ratio box
The player init wrote an inline object-fit:contain on the video
element, which outranked the injected stylesheet's object-fit:cover
fill contract and left black bars above/below whenever the cover box
ratio differed from the video. Drop the inline style so the
stylesheet rule is the single source of truth, and pin the
no-inline-style rule in the cover contract test.
2026-09-06 11:00:04 +08:00
kate522 6ffc5ba3d6 fix(submit): drop the redundant featured preview type badge
The reference theme renders no type badge in the featured box; the
swiper and dplayer previews are self-explanatory. Remove it from both
preview branches and delete the now-unused CSS rule.
2026-09-06 10:47:24 +08:00
kate522 b7f5523874 fix(submit): render slide cover preview as a real swiper
Replace the static first-image preview with the reference theme's
.new-swiper contract (loop + autoplay + prev/next + pagination) in both
the server-rendered box and the JS re-render, and run auto_fun for
slide covers so new_swiper initializes them.
2026-09-06 10:39:39 +08:00
kate522 d0c6c3e431 feat(submit): fold slide cover into multi-select image picker
Match the featured cover buttons row to the reference theme: drop the
dedicated slide button, let the icon-only image picker select multiple
images into a slide cover (single pick stays an image cover), and align
the loaded-state visibility matrix.
2026-09-06 10:30:27 +08:00
kate522 1a0b023658 fix(submit): raise TinyMCE fullscreen above the fixed navbar
TinyMCE's skin injects .mce-fullscreen { z-index: 100 } at editor init,
after core editor.css, so the fullscreen editor (toolbar at the viewport
top) lost to the fixed navbar (.nav-fixed .header, z-index 999). Restore
core's intended 100010 with an element+class selector that outranks the
skin regardless of injection order; it stays below the submit media
dialog (100080). Also remove the dead .mce-top-part.affix rules (no
AKSRT script drives them) and pin both in a contract test.
2026-09-06 10:10:20 +08:00
kate522 daee4cd67f feat(submit): make video cover row icon-only with hover titles
Replace the video-pic/video/clear button labels with icon-only buttons
carrying title + aria-label (设置视频封面/视频/清除), center the glyphs
via flex to fix the upward icon shift, rename the media picker title to
为视频设置封面, and drop the unused setVideoCover i18n key. Contract
test updated to pin the new markup and string set.
2026-09-06 10:10:12 +08:00
kate522 51a591e2b9 feat(submit): add video cover picker with playable video preview
Featured video preview now renders a real DPlayer (video-url/video-pic)
like the reference theme instead of a static image, so the cover video
plays on the submit page. Top-right bar gains the video-cover button
shown only when a video cover is loaded; backend honors pic_id and no
longer deletes the thumbnail before cover validation. Drop dead i18n
keys and data-can-* attributes.
2026-09-05 23:41:22 +08:00
kate522 d84d485ec7 refactor(submit): remove unused aksrt_update_post ajax endpoint
No caller anywhere: front JS updates via aksrt_submit_post (posts_id),
guests via aksrt_save_draft. Re-pin the one-captcha-admission contract
to ajax_submit_post, the only non-draft entry point.
2026-09-05 23:41:12 +08:00
kate522 5fbcfa2b49 fix data-aksrt-video 属性 2026-09-05 22:28:19 +08:00
kate522 5a61e68a8c fix(video): guard sourceless player play attempts 2026-09-05 22:04:24 +08:00
kate522 51dd38163d fix(submit): keep sidebar visible on front submit page 2026-09-05 21:50:40 +08:00
kate522 49ffdc6ab2 fix(runtime): remove obsolete jQuery compatibility assets 2026-09-05 21:31:11 +08:00
kate522 4a12de38cb fix(runtime): use compatible WordPress jQuery 2026-09-05 20:48:18 +08:00
kate522 d64c4cf1b4 fix single-post.css 2026-09-05 20:10:07 +08:00
kate522 d86147f406 fix(single): fill slide and video cover media like the image cover
Slide-mode images rendered at intrinsic ratio, top-aligned inside the
swiper chain (--pc-height:auto left .swiper-wrapper content-sized), so
the taller box showed a gap at the bottom and never center-cropped like
the image cover. The video cover had the same problem through
video-player.js (height:auto, capped at 70vh).

- aksrt_render_slider scale mode emits --pc-height/--m-height 100% so
  the wrapper/slide/img chain fills the ratio box and object-fit: cover
  center-crops inside it (same pattern as the .scale-height widgets)
- video-player.js renders the video at height:100% + object-fit:cover;
  with an undimensioned container height:100% degrades to auto,
  matching the previous behavior
- drop the dead .single-cover padding-bottom rules (every producer owns
  its height inline, and the rule squeezed the absolutely positioned
  slide inner) and the orphaned --single-cover-scale var in
  tokens.css/compat-vars.css/main.css/InlineStyleBuilder
- rebuild public bundles; extend the single-cover-height contract
2026-09-05 18:53:45 +08:00
kate522 9fa7190232 test(submit): align toast contract with unified media picker
f3fcfe45 moved featured/slide/video cover uploads into the shared
AksrtSubmitMedia picker, which owns the fixed-id load/success/danger
flow under aksrt-front-submit-editor-media-toast, and pay downloads now
only add a success confirmation with the resource-upload id. Update the
contract accordingly: drop the obsolete featured-upload/slide-upload/
video-cover ids and the image/slide/videoToastId variable assertions,
and assert instead that all three cover actions route through
AksrtSubmitMedia.open and that the picker keeps its fixed-id flow.
2026-09-05 18:22:59 +08:00
kate522 4f2d17f6ee fix(single): align slide and video cover heights with image cover
The image-mode cover reserves +50px for the title/breadcrumb overlay
(calc(scale% + 50px)), but the slide cover wrapper was given a bare
inline padding-bottom by aksrt_render_slider, permanently defeating the
.cover-slide rule, and the video cover used a bare video_scale%.

- aksrt_render_slider: add scale_extra so scale mode emits
  calc(ratio% + extra); the single cover passes 50px so all three
  modes share one height formula
- drop the unreachable static slide fallback and function_exists guard
  (the helper is unconditionally loaded by inc/bootstrap.php), the
  always-true cover_url/ep_count conditions, and the dead --scale-ratio
  and inner swiper padding emitted in scale mode
- remove the dead cover CSS cluster with no producer: .single-cover-slide
  (main.css/main.min.css/cover.css), .single-cover-slider family
  (components/base.css), .single-cover-slide-wrap and .single-cover__*
  helpers (cover.css), and initSlideCovers in misc.js
- rebuild public bundles via tools/build-public-assets.mjs
- add single-cover-height-contract test covering the shared formula
  and the dead-code removals
2026-09-05 18:22:37 +08:00
kate522 05a6b6fc54 fix 更多栏目 2026-09-05 17:32:18 +08:00
kate522 5b89fc200b fix(frontend): restore no-sidebar two-column list pairing
The homepage utility .flex { display: flex !important } out-ranked the
legacy wide-mode rule .site-layout-1 .posts-item:not(.card)
{ display: inline-flex; width: calc(50% - 16px) }, so with the sidebar
collapsed (no widgets) every list item rendered at half width stacked
into one column with an empty right half.

Zibll's .flex utility carries no !important; drop it so the wide-mode
rule wins the cascade, and regenerate the CSS bundles.

Verification: node --test tests/widget-system/*.test.cjs (242/243, the
toast-contract failure is pre-existing); rebuilt bundle contains no
display:flex!important on .flex.
2026-09-05 16:04:23 +08:00
kate522 620a625a72 Merge pull request 'fix(sidebar): collapse empty sidebar column on every scene' (#29) from worktree/sidebar-empty-collapse into main
Reviewed-on: #29
2026-09-05 07:40:57 +00:00
kate522 1839150ecb fix(sidebar): collapse empty sidebar column on every scene
Sidebar visibility had two disconnected decisions: the body site-layout-*
class (via aksrt_is_show_sidebar_filter) only checked widget activity for
singles, while the homepage aside renderer skipped the column and
sidebar.php rendered an empty one. With the toggle on and no widgets, the
homepage kept a reserved gutter and squeezed the main content aside.

- collapse every scene to no-sidebar when the sidebar widget stack is empty
- resolve home_sidebar before the page branch so a static front page is
  checked against the zones the homepage renders
- guard the homepage aside with aksrt_is_show_sidebar() alone and drop the
  duplicate aksrt_homepage_has_sidebar gate
- early-return sidebar.php instead of rendering an empty column
- drop dead code: archive helper $preferred param, wp_is_mobile fallback,
  container--no-sidebar class, unreachable front-page fallback
- update post-visual-contract to pin the single visibility decision

Verification: php -l on all changed files; node --test
tests/widget-system/*.test.cjs 242/243 (the toast-contract failure is
pre-existing and unrelated).
2026-09-05 15:40:11 +08:00
kate522 2bf9b00022 fix(widgets): close the new-swiper container in slider markup
参考 zib_new_slider 的闭合顺序补回缺失的 </div>:此前 .new-swiper
从未闭合,.zib-slider 把后续标记全部吞入,导致组合模块的 .cover-col
成为 .slider-col 的子节点——flex 容器只剩一个占满整行的子列,
PC 端呈现上下堆叠布局(该问题自首次复刻起即存在,非 CSS 所致)。

验证:run.php 136 断言(新增 slider/combo 标签配平断言);
组合模块渲染 26 开/26 闭;localhost 实测两列恢复左右布局
2026-09-05 15:00:27 +08:00
kate522 4eb2ddef66 fix(widgets): keep slider media combo PC layout flex in admin preview
后台模板预览只加载 frontend.css,不加载 main.css 的 .flex 工具类,
PC 端两列因此退化为 block 上下堆叠;在 widget 自有样式层显式声明
display:flex(移动端媒体查询的 display:block/flex 覆盖不受影响)
2026-09-05 14:30:39 +08:00
kate522 73e58517f6 Merge pull request 'Worktree/slider media combo parity' (#28) from worktree/slider-media-combo-parity into main
Reviewed-on: #28
2026-09-05 06:17:51 +00:00
kate522 bb37df19fc chore(assets): remove orphaned legacy widget form styles
widget-set.css(-min) 仅含旧版幻灯片小工具表单样式
(widget_ui_slider_* / ashu_upload_button / panel 等),
全仓无入队与引用,属死代码
2026-09-05 14:17:13 +08:00
kate522 65a69b1dec fix(widgets): align slider media combo with the Zibll reference
- 渲染器:幻灯片按参考补回 span/a 包裹、lazyload swiper-lazy 懒加载契约、
  视频背景与图层视差属性条件;组合模块补回 is_show 门控、超管缺省提示、
  widget-graphic-cover mb 类与内层样式容器、卡片列入场动画类与 lazy_cover 开关
- Schema:幻灯片/图层/卡片字段补齐 library、unit、参考描述文案与分组按钮标题
- 后台表单:分组按钮文案(添加幻灯片/添加卡片/添加图层)、行编号格式、
  视频上传不渲染图片预览(FormRenderer + admin.js)
- 契约测试:新增 slider media combo 前后台参考契约断言

验证:php -l 全部通过;run.php 133 断言;node --test 243 项(仅主干既有
toast-contract 失败);validate-widget-golden 通过
2026-09-05 14:17:03 +08:00
kate522 cf264d5e81 Merge pull request 'fix(widgets): keep widget-content an unstyled structural layer' (#27) from worktree/fix-widget-content-margin into main
Reviewed-on: #27
2026-09-05 05:28:06 +00:00
kate522 d7950730dd fix(widgets): keep widget-content an unstyled structural layer
Reference contract: widget cards carry their own 15px padding and
.widget-content is bare. The added 20px padding inset every widget
card from the content max width on the fixed homepage (the only
bundle loading sidebar.css).

- drop the root padding rule and the unreferenced --flush modifier
- drop the now-redundant user-widget padding:0 workaround
- drop the dead --card-padding-lg token
- lock the contract with negative assertions in the display test
2026-09-05 13:26:52 +08:00
kate522 274b888fd0 Merge pull request 'chore(assets): bump theme version to bust stale admin asset caches' (#26) from worktree/fix-term-aggregation-cover into main
Reviewed-on: #26
2026-09-05 04:45:36 +00:00
kate522 f0f908d9e1 chore(assets): bump theme version to bust stale admin asset caches
The terms field handlers shipped with the widget parity work, but every
asset is enqueued with the unchanged AKSRT_VERSION cache key, so
browsers kept the old admin.js without them: category checkboxes
toggled visually while chips and the hidden value never synced, and
saved term_id stayed empty (widget renders nothing). Bump the version
so all theme assets re-fetch.
2026-09-05 12:44:33 +08:00
kate522 ff7b1c547a Merge pull request 'fix(widgets): keep found rows for term aggregation post count' (#25) from worktree/fix-term-aggregation-cover into main
Reviewed-on: #25
2026-09-05 04:32:50 +00:00
kate522 0c4a0d18f4 fix(widgets): keep found rows for term aggregation post count
The aggregation card's N篇文章 meta reads found_posts, but paginate ''
disables SQL_CALC_FOUND_ROWS and found_posts comes back 0 on current
WordPress. The reference shows the term's total post count, so keep
found rows enabled for this internal query.
2026-09-05 12:32:09 +08:00