写作增强:选了翻译服务商之后再显示对应的 API 输入框,不要四个密钥框全都摆着 #26

Closed
opened 2026-10-27 11:57:58 +00:00 by laoyang · 2 comments
Owner

现象 / 诉求

「主题设置 → 写作增强」里,翻译服务商(w_provider)是一个下拉框,选项有 MyMemory / 百度翻译 / 有道翻译。
但下拉框下面的 4 个密钥框一直全部显示:

  • 百度 APPID(w_baidu_appid)
  • 百度密钥(w_baidu_key)
  • 有道应用 ID(w_youdao_appid)
  • 有道应用密钥(w_youdao_key)

用户原话:

写作增强部分,选择接口之后,再出现各个 api 的输入框吧,例如选择百度,才出现百度的 api 输入框。

也就是:下拉框选了谁,才出现谁的那一组输入框。选 MyMemory 时四个框都不该出现(它不需要密钥)。

现状核实(已查过源码,不是猜测)

位置 现状
inc/theme-options.php:1366-1378 w_provider select,std = mymemory,选项来自 yang_writing_providers()
inc/theme-options.php:1394-1405 百度 APPID,type => text,无条件渲染
inc/theme-options.php:1419-1425 百度密钥,type => password,无条件渲染
inc/theme-options.php:1427-1433 有道应用 ID,无条件渲染
inc/theme-options.php:1435-1443 有道应用密钥,无条件渲染

同一文件里另有 7 处写了 'requires' => 'xxx'(a_auto_enable、a_lightbox_enable、a_highlight_enable),
但 requires 这个键框架根本没读过 —— inc/options-framework/js/options-custom.js(230 行)里
全部是手写的 jQuery('#section-xxx').fadeToggle(400) 硬编码,一条通用条件逻辑都没有。

所以本次不能靠加 'requires' => 'w_provider' 解决,必须写真正的显隐逻辑。
更麻烦的是:那 7 处历史的 requires 是死键,看起来生效全靠有人另外写了一行 JS。
这块要顺手在工单里说清,避免下一个人再被误导。

涉及的坑(先写在单里,实现时必须避开)

  1. info 类型不生成 .section 包裹。w_provider_help(type => info)渲染出来是
    div.section-info 而不是 div.section,所以显隐选择器不能统一写 .section,
    要按 id 精确取(这正是 w_provider_help 当初特意给了 id 的原因)。
  2. 按服务商分组。百度两个框、有道两个框,各自成组;MyMemory 一组都没有。
    将来加服务商(DeepL / 腾讯 / 阿里)时不要每加一个就改一次 JS 分支,
    应该由 yang_writing_providers() 的 key 驱动,一组一个 data-provider 属性。
  3. JS 必须放在后台设置页,且 wp_enqueue 要在 admin_enqueue_scripts 钩子里。
    现在 options-custom.js 是框架自带文件,不要直接改它(下次升级框架会覆盖)——
    主题要加自己的 assets/js/writing-admin.js,或者走 inc/theme-writing.php 里的输出。
  4. 首次进入页面(未交互)就要正确显隐,不能等 change 事件才生效。
  5. 保存后刷新还要正确,即 JS 初始化必须读当前 select 的 value,而不是读 PHP 那边默认值。

验收标准

  • 服务商选 MyMemory → 百度和有道的 4 个输入框都不可见
  • 服务商选 百度翻译 → 只出现「百度 APPID」「百度密钥」2 个框;有道 2 个框不可见
  • 服务商选 有道翻译 → 只出现「有道应用 ID」「有道应用密钥」2 个框;百度 2 个框不可见
  • 切换服务商时是即时显隐(不用保存、不用刷新)
  • 页面初次加载时显隐就是对的(不依赖用户先动一下下拉框)
  • 保存并刷新后仍然正确
  • 隐藏不等于清空:从百度切到有得再切回百度,之前填的百度 APPID 还在(值不丢、不被清空)
  • 「服务商账号填写说明」这块 info 的显隐也要跟着走(选 MyMemory 时它里面讲的都是百度/有道,不该显示)
  • 已有的密钥不回显逻辑不受影响(w_baidu_key / w_youdao_key 仍然是 std => ''、留空 = 不修改)
  • 显隐用 CSS 类控制而不是 display:none 内联,配合 aria-hidden / 避免焦点落到隐藏框里

附带(建议同单处理,不单独开工单)

现有 7 处 'requires' 是死键。建议在本次一并核实「哪些真生效、哪些是摆设」,
把不生效的删掉或补上 JS,并在 inc/theme-options.php 顶部加一行说明:
requires 不会被框架消费,条件显示一律靠 JS。

备注

  • 服务器 IP 目前被防火墙封禁(ping 通但 22/80/443 全 DROP),本地改码与测试不受影响,
    线上真实几何测量与部署需等解封,届时会在本单追加评论。

为什么单独建单

在途 10 张单里没有一张涉及主题设置后台表单的条件显示:最新的是 #25(写作增强四引擎自动生成,已发布 3.2.57)、#21~#24(侧栏挂件)、#15~#18(归档短代码)、#16(评论语言选项)。本单是后台 UI 的显隐交互,可独立验收,与原 #25 是同一功能块但完全不同的改动面。

## 现象 / 诉求 「主题设置 → 写作增强」里,**翻译服务商**(`w_provider`)是一个下拉框,选项有 MyMemory / 百度翻译 / 有道翻译。 但下拉框下面的 **4 个密钥框一直全部显示**: - 百度 APPID(`w_baidu_appid`) - 百度密钥(`w_baidu_key`) - 有道应用 ID(`w_youdao_appid`) - 有道应用密钥(`w_youdao_key`) 用户原话: > 写作增强部分,选择接口之后,再出现各个 api 的输入框吧,例如选择百度,才出现百度的 api 输入框。 也就是:**下拉框选了谁,才出现谁的那一组输入框**。选 MyMemory 时四个框都不该出现(它不需要密钥)。 ## 现状核实(已查过源码,不是猜测) | 位置 | 现状 | |---|---| | `inc/theme-options.php:1366-1378` | `w_provider` select,std = `mymemory`,选项来自 `yang_writing_providers()` | | `inc/theme-options.php:1394-1405` | 百度 APPID,`type => text`,**无条件渲染** | | `inc/theme-options.php:1419-1425` | 百度密钥,`type => password`,**无条件渲染** | | `inc/theme-options.php:1427-1433` | 有道应用 ID,无条件渲染 | | `inc/theme-options.php:1435-1443` | 有道应用密钥,无条件渲染 | 同一文件里另有 7 处写了 `'requires' => 'xxx'`(`a_auto_enable`、`a_lightbox_enable`、`a_highlight_enable`), 但 **`requires` 这个键框架根本没读过** —— `inc/options-framework/js/options-custom.js`(230 行)里 全部是手写的 `jQuery('#section-xxx').fadeToggle(400)` 硬编码,一条通用条件逻辑都没有。 > 所以本次不能靠加 `'requires' => 'w_provider'` 解决,必须写真正的显隐逻辑。 > 更麻烦的是:那 7 处历史的 `requires` 是**死键**,看起来生效全靠有人另外写了一行 JS。 > 这块要顺手在工单里说清,避免下一个人再被误导。 ## 涉及的坑(先写在单里,实现时必须避开) 1. **`info` 类型不生成 `.section` 包裹**。`w_provider_help`(`type => info`)渲染出来是 `div.section-info` 而不是 `div.section`,所以显隐选择器不能统一写 `.section`, 要按 id 精确取(这正是 `w_provider_help` 当初特意给了 id 的原因)。 2. **按服务商分组**。百度两个框、有道两个框,各自成组;MyMemory 一组都没有。 将来加服务商(DeepL / 腾讯 / 阿里)时不要每加一个就改一次 JS 分支, 应该由 `yang_writing_providers()` 的 key 驱动,一组一个 `data-provider` 属性。 3. **JS 必须放在后台设置页**,且 `wp_enqueue` 要在 `admin_enqueue_scripts` 钩子里。 现在 `options-custom.js` 是框架自带文件,**不要直接改它**(下次升级框架会覆盖)—— 主题要加自己的 `assets/js/writing-admin.js`,或者走 `inc/theme-writing.php` 里的输出。 4. **首次进入页面(未交互)就要正确显隐**,不能等 `change` 事件才生效。 5. **保存后刷新还要正确**,即 JS 初始化必须读**当前 select 的 value**,而不是读 PHP 那边默认值。 ## 验收标准 - [ ] 服务商选 **MyMemory** → 百度和有道的 4 个输入框都不可见 - [ ] 服务商选 **百度翻译** → 只出现「百度 APPID」「百度密钥」2 个框;有道 2 个框不可见 - [ ] 服务商选 **有道翻译** → 只出现「有道应用 ID」「有道应用密钥」2 个框;百度 2 个框不可见 - [ ] 切换服务商时是**即时**显隐(不用保存、不用刷新) - [ ] 页面**初次加载**时显隐就是对的(不依赖用户先动一下下拉框) - [ ] 保存并刷新后仍然正确 - [ ] **隐藏不等于清空**:从百度切到有得再切回百度,之前填的百度 APPID 还在(值不丢、不被清空) - [ ] 「服务商账号填写说明」这块 `info` 的显隐也要跟着走(选 MyMemory 时它里面讲的都是百度/有道,不该显示) - [ ] 已有的密钥不回显逻辑不受影响(`w_baidu_key` / `w_youdao_key` 仍然是 `std => ''`、留空 = 不修改) - [ ] 显隐用 CSS 类控制而不是 `display:none` 内联,配合 `aria-hidden` / 避免焦点落到隐藏框里 ## 附带(建议同单处理,不单独开工单) 现有 7 处 `'requires'` 是死键。建议在本次一并核实「哪些真生效、哪些是摆设」, 把**不生效的删掉或补上 JS**,并在 `inc/theme-options.php` 顶部加一行说明: `requires` 不会被框架消费,条件显示一律靠 JS。 ## 备注 - 服务器 IP 目前被防火墙封禁(ping 通但 22/80/443 全 DROP),本地改码与测试不受影响, **线上真实几何测量与部署需等解封**,届时会在本单追加评论。 --- ### 为什么单独建单 在途 10 张单里没有一张涉及主题设置后台表单的条件显示:最新的是 #25(写作增强四引擎自动生成,已发布 3.2.57)、#21~#24(侧栏挂件)、#15~#18(归档短代码)、#16(评论语言选项)。本单是后台 UI 的显隐交互,可独立验收,与原 #25 是同一功能块但完全不同的改动面。
Author
Owner

已实现并发布 3.2.58,等你在后台升级后确认

commit 1a31e41(0a5486e..1a31e41 已推送 main)。

后台实际表现

进「主题设置 → 写作增强」:

别名生成总开关 服务商下拉框 页面上出现什么
未勾 无论选谁 整块都不出现(含「服务商账号填写说明」)
勾了 MyMemory 只有一句「MyMemory 不用填任何东西」+ 接口超时
勾了 百度翻译 「百度翻译 · 账号怎么拿」+ APPID + 密钥 + 接口超时
勾了 有道翻译 「有道翻译 · 账号怎么拿」+ 应用 ID + 应用密钥 + 接口超时

切换下拉框立刻重排,不用保存、不用刷新。

三处关键实现选择(都是踩过坑才这么写的)

1. 首帧在服务端算好,不靠 JS 兜

$yang_prov_class() 闭包按当前已保存的服务商直接打好 yq-cond-hide。
若只靠 JS,每次进设置页、每次保存后重载都会「四家全显示 → 闪一下 → 收起」。
这和 theme-avatar.php 用 admin_body_class 是同一个思路。

2. 两层条件必须在同一个函数里合成

toggleClass(cls, force) 的 force 是绝对赋值,不是取反。如果拆成
「按总开关 toggle 一次」+「按服务商 toggle 一次」两个函数,最终结果只取决于
注册顺序,跟业务无关 —— 表现就是「勾了别名生成、选了百度,百度框时有时无」。

3. 分组声明只在 PHP 一处

字段上写 yang-prov(我参与按服务商显示)+ yang-prov-<key>(我属于哪家),
JS 只读 class 与下拉框 value 比对,零服务商知识。
如果反过来在 JS 里写 {baidu:[...], youdao:[...]},将来加一家要改两处,
而且两边不一致时不报错,只表现成「新服务商的框永远不出现」。

刻意没做的两件事

  • 不用 jQuery show()/hide():.section 的 display 是 flow-root
    (3.2.28 的 BFC 修复),jQuery 会写行内 display:block 把它回退掉。
    统一用 .yq-cond-hide { display:none !important }。
  • 隐藏不 disabled 输入框:两个密钥字段是「留空=不修改」语义,
    disabled 的字段不随表单提交,会把已保存的密钥冲掉。

测试与反证

套件 结果
_prov_cond_check.php(PHP 产品判据,真实 WP 环境) 9 / 0
_prov_js_check.js(JS 判据,抽真实函数体 + 最小 jQuery 桩) 12 / 0
回归 _writing_test.php 71 / 0
回归 _admin_writing_check.php 21 / 0
回归 _secret_path_check.php 9 / 0
_mkzip358.py 打包自检 24 / 0
_mkreadme358.py readme 四道关卡 全过(48 → 49 条版本标题)

反证 11 组全部有牙齿(证明判据不是恒绿):

  • PHP 7 组在服务器跑通:R1 去掉 yq-cond-hide、R2 闭包恒返空、R3 分组 key 写错、
    R4 首帧用 std 而非已保存值、R7 info 混用分组、R8 把 w_timeout 也分组、基线
  • JS 4 组在本地跑通:R5 belongs = true(4 条失败)、R6 .on('change','#w_on_slug')
    漏掉 #w_provider(4 条失败)、R9 两层拆成两个函数(5 条)、R10 toggleClass 写成取反(4 条)

⚠️ 这里有一次真发现:R5 / R6 两个 JS 层注入最初跑出「失败 0 条」——
9 条 PHP 判据完全没测 JS。JS 坏掉时用户切下拉框毫无反应,测试却全绿。
补了 _prov_js_check.js 12 条之后才把它们揭穿。教训:PHP 判据只能证明
「服务端首帧对」,证明不了「点了之后对」。

发布信息

项 值
版本 3.2.58
zip kratos_yang-3.2.58.zip,4818165 字节
md5 cc7a62e787bf67d54b6947db7cd0b1fa
readme readme358.html,152178 字节,49 条版本标题
下载 https://yangyq.net/theme-update/kratos_yang-3.2.58.zip

发布严格按序:传 zip → 传 readme → 验 HTTP 双向 → 最后改 update.json。

🔴 红线守住:线上 kratos_yang/style.css 仍是 3.2.57,
线上 theme-options.php 里 yang_prov_class 计数为 0。
/theme-update/ 通道已指向 3.2.58,等你在后台点升级,服务器主题目录没被动过。

请你确认的点

  1. 后台升级到 3.2.58 后,进「写作增强」看四个框是不是只有选中那家的一两个。
  2. 切换下拉框,框是不是立刻跟着换(不用保存)。
  3. 勾掉「别名生成」再勾回,整块是不是干净地跟着出现/消失。
  4. 你当前用的服务商如果是百度/有道,已保存的密钥还在不在(这一条最容易出问题,
    因为涉及「留空=不修改」的提交语义)。

都对了再关单。

## 已实现并发布 3.2.58,等你在后台升级后确认 commit `1a31e41`(`0a5486e..1a31e41` 已推送 main)。 ### 后台实际表现 进「主题设置 → 写作增强」: | 别名生成总开关 | 服务商下拉框 | 页面上出现什么 | |---|---|---| | 未勾 | 无论选谁 | 整块都不出现(含「服务商账号填写说明」) | | 勾了 | MyMemory | 只有一句「MyMemory 不用填任何东西」+ 接口超时 | | 勾了 | 百度翻译 | 「百度翻译 · 账号怎么拿」+ APPID + 密钥 + 接口超时 | | 勾了 | 有道翻译 | 「有道翻译 · 账号怎么拿」+ 应用 ID + 应用密钥 + 接口超时 | 切换下拉框**立刻**重排,不用保存、不用刷新。 ### 三处关键实现选择(都是踩过坑才这么写的) **1. 首帧在服务端算好,不靠 JS 兜** `$yang_prov_class()` 闭包按**当前已保存的**服务商直接打好 `yq-cond-hide`。 若只靠 JS,每次进设置页、每次保存后重载都会「四家全显示 → 闪一下 → 收起」。 这和 `theme-avatar.php` 用 `admin_body_class` 是同一个思路。 **2. 两层条件必须在同一个函数里合成** `toggleClass(cls, force)` 的 `force` 是**绝对赋值**,不是取反。如果拆成 「按总开关 toggle 一次」+「按服务商 toggle 一次」两个函数,最终结果只取决于 **注册顺序**,跟业务无关 —— 表现就是「勾了别名生成、选了百度,百度框时有时无」。 **3. 分组声明只在 PHP 一处** 字段上写 `yang-prov`(我参与按服务商显示)+ `yang-prov-<key>`(我属于哪家), JS 只读 class 与下拉框 value 比对,**零服务商知识**。 如果反过来在 JS 里写 `{baidu:[...], youdao:[...]}`,将来加一家要改两处, 而且两边不一致时**不报错**,只表现成「新服务商的框永远不出现」。 ### 刻意没做的两件事 - **不用 `jQuery show()/hide()`**:`.section` 的 `display` 是 `flow-root` (3.2.28 的 BFC 修复),jQuery 会写行内 `display:block` 把它回退掉。 统一用 `.yq-cond-hide { display:none !important }`。 - **隐藏不 `disabled` 输入框**:两个密钥字段是「留空=不修改」语义, `disabled` 的字段不随表单提交,会把已保存的密钥冲掉。 ### 测试与反证 | 套件 | 结果 | |---|---| | `_prov_cond_check.php`(PHP 产品判据,真实 WP 环境) | **9 / 0** | | `_prov_js_check.js`(JS 判据,抽真实函数体 + 最小 jQuery 桩) | **12 / 0** | | 回归 `_writing_test.php` | **71 / 0** | | 回归 `_admin_writing_check.php` | **21 / 0** | | 回归 `_secret_path_check.php` | **9 / 0** | | `_mkzip358.py` 打包自检 | **24 / 0** | | `_mkreadme358.py` readme 四道关卡 | 全过(48 → 49 条版本标题) | **反证 11 组全部有牙齿**(证明判据不是恒绿): - PHP 7 组在服务器跑通:R1 去掉 `yq-cond-hide`、R2 闭包恒返空、R3 分组 key 写错、 R4 首帧用 std 而非已保存值、R7 info 混用分组、R8 把 `w_timeout` 也分组、基线 - JS 4 组在本地跑通:R5 `belongs = true`(4 条失败)、R6 `.on('change','#w_on_slug')` 漏掉 `#w_provider`(4 条失败)、R9 两层拆成两个函数(5 条)、R10 `toggleClass` 写成取反(4 条) > ⚠️ **这里有一次真发现**:R5 / R6 两个 **JS 层**注入最初跑出「失败 0 条」—— > 9 条 PHP 判据**完全没测 JS**。JS 坏掉时用户切下拉框毫无反应,测试却全绿。 > 补了 `_prov_js_check.js` 12 条之后才把它们揭穿。教训:PHP 判据只能证明 > 「服务端首帧对」,证明不了「点了之后对」。 ### 发布信息 | 项 | 值 | |---|---| | 版本 | 3.2.58 | | zip | `kratos_yang-3.2.58.zip`,4818165 字节 | | md5 | `cc7a62e787bf67d54b6947db7cd0b1fa` | | readme | `readme358.html`,152178 字节,49 条版本标题 | | 下载 | https://yangyq.net/theme-update/kratos_yang-3.2.58.zip | 发布严格按序:传 zip → 传 readme → 验 HTTP 双向 → **最后**改 `update.json`。 🔴 **红线守住**:线上 `kratos_yang/style.css` 仍是 **3.2.57**, 线上 `theme-options.php` 里 `yang_prov_class` 计数为 **0**。 `/theme-update/` 通道已指向 3.2.58,**等你在后台点升级**,服务器主题目录没被动过。 ### 请你确认的点 1. 后台升级到 3.2.58 后,进「写作增强」看四个框是不是只有选中那家的一两个。 2. 切换下拉框,框是不是立刻跟着换(不用保存)。 3. 勾掉「别名生成」再勾回,整块是不是干净地跟着出现/消失。 4. 你当前用的服务商如果是百度/有道,**已保存的密钥还在不在**(这一条最容易出问题, 因为涉及「留空=不修改」的提交语义)。 都对了再关单。
Author
Owner

用户已验收通过,关闭

用户 2026-10-27 确认:「这个功能验收吧,没问题了。」

验收结论

3.2.58 在后台「主题设置 → 写作增强」的实际表现符合需求:
选了哪家服务商,就只有那家的账号输入框出现在页面上,用不上的不再摆着碍事。

本次交付汇总

项 内容
版本 3.2.58
commit 1a31e41(0a5486e..1a31e41,已推送 main)
包 kratos_yang-3.2.58.zip / 4818165 字节 / md5 cc7a62e787bf67d54b6947db7cd0b1fa
readme readme358.html / 152178 字节 / 49 条版本标题
改动文件 inc/theme-options.php、inc/options-framework/js/options-custom.js、style.css

一句话记住这版的设计

分组声明只在 PHP 一处(字段的 class 上写 yang-prov + yang-prov-<key>),
JS 零服务商知识。将来加一家服务商,只改 theme-writing.php 的清单 + 字段的
$yang_prov_class('新key'),不需要动 JS —— 这是刻意避免"两处抄一份映射表、
不一致时静默失效"的后果。

顺带记下的两条通用经验(已进项目红线)

  • #456:一个需求横跨几层,就必须每层都有判据。本轮 9 条 PHP 判据全绿,
    但两个 JS 层致命 bug 的反证仍跑出「失败 0 条」—— 因为 PHP 判据压根不执行 JS。
    只测一层而全绿比测出红更危险。
  • #457:toggleClass(cls, force) 的 force 是绝对赋值不是取反。
    多层条件拆成多个函数各 toggle 一次,结果只取决于注册顺序 ——
    表现成"时有时无"的鬼故事。

关闭。

## 用户已验收通过,关闭 用户 2026-10-27 确认:「这个功能验收吧,没问题了。」 ### 验收结论 3.2.58 在后台「主题设置 → 写作增强」的实际表现符合需求: 选了哪家服务商,就只有那家的账号输入框出现在页面上,用不上的不再摆着碍事。 ### 本次交付汇总 | 项 | 内容 | |---|---| | 版本 | 3.2.58 | | commit | `1a31e41`(`0a5486e..1a31e41`,已推送 main) | | 包 | `kratos_yang-3.2.58.zip` / 4818165 字节 / md5 `cc7a62e787bf67d54b6947db7cd0b1fa` | | readme | `readme358.html` / 152178 字节 / 49 条版本标题 | | 改动文件 | `inc/theme-options.php`、`inc/options-framework/js/options-custom.js`、`style.css` | ### 一句话记住这版的设计 分组声明**只在 PHP 一处**(字段的 `class` 上写 `yang-prov` + `yang-prov-<key>`), JS 零服务商知识。将来加一家服务商,只改 `theme-writing.php` 的清单 + 字段的 `$yang_prov_class('新key')`,**不需要动 JS** —— 这是刻意避免"两处抄一份映射表、 不一致时静默失效"的后果。 ### 顺带记下的两条通用经验(已进项目红线) - **#456**:一个需求横跨几层,就必须每层都有判据。本轮 9 条 PHP 判据全绿, 但两个 JS 层致命 bug 的反证仍跑出「失败 0 条」—— 因为 PHP 判据压根不执行 JS。 只测一层而全绿比测出红更危险。 - **#457**:`toggleClass(cls, force)` 的 `force` 是绝对赋值不是取反。 多层条件拆成多个函数各 toggle 一次,结果只取决于注册顺序 —— 表现成"时有时无"的鬼故事。 关闭。
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: laoyang/wordpress-kratos-yang#26