3.2.57 新增「写作增强」:发布时自动生成别名/标签/分类/摘要 #25

需求(工单 #25):写文章时自动生成别名(翻译)、自动生成标签、
自动选择分类、自动生成摘要,问主题能不能做、是否必须用插件。
结论:主题自己就能做,不依赖任何插件。

新增 inc/theme-writing.php(四个独立引擎 + 设置读写 + 密钥处理):

- 触发点:transition_post_status,且要求
  new_status === publish && old_status !== publish
  ⇒ 只在「第一次点发布」时动手,自动保存不触发,已发布的文章一概不碰。
- 幂等锁 _yang_writing_done:同一篇只做一次,避免反复覆写。

四道「不覆盖」守卫(用户逐条确认的决策):
- 摘要:只在 post_excerpt 为空时才写。
- 分类:只在文章还挂默认分类(未分类)时才动。
- 别名:只在「空」或「不是纯 ASCII」时才生成。判据不是"空"而是
  "不是纯 ASCII" —— 中文标题下 WP 生成的是 %e4%bf%a1... 这种编码串,
  它非空但不可用。已有英文别名的 966 篇一概不动(别名=URL,改了
  就是成批 404)。
- 标签:wp_set_post_tags(..., true) 追加,绝不删除手工标签。

修一个真实产品 bug:3.2.56 及以前 apply() 里写的是
list($suggest, $_) = yang_writing_make_tags(...),$new 被整个丢掉;
接着又拿 $suggest 去 get_term_by 二次分类 —— 而 $suggest 里每个词
都来自词典、必然全部命中 ⇒「新建」分支永远进不去 ⇒ 这条功能在真实
发布流程里一次都没生效过。改为 list($exist_hits, $new_cands),
两段分别复核后合并。

标签两级策略(新博客也能用):先匹配已有标签池,匹配不到才新建,
每篇新增数量受 w_tag_new_limit 约束(默认 3,设 0 = 永不新建)。

中文分词(服务器无 scws/jieba):先按虚词与标点切短语,再在短语
内部取 2~6 字 n-gram。不切句直接取窗口会产出「星等换算与赤」
这类跨词碎片,且字面上"出现 ≥2 次"能通过所有频次闸门 —— 这是
n-gram 的固有缺陷,只能靠切分规避,调阈值无效。
虚词表统一由 yang_writing_seps() 提供(闸门④ 复用同一函数)。

翻译:默认 MyMemory(免注册),可选百度/有道。任何失败都返回空串
跳过该项,绝不阻塞发布。

密钥:存独立选项 yang_writing_secrets,不进 kratos;password 类型 +
std 空串;页面只显示末 4 位;留空提交 = 不修改。

设置页:新增「写作增强」独立 heading 标签页,四个开关默认全关
(升级不改变现有行为)。framework 里 'requires' 这个键根本没被读取,
条件显示改用 options-custom.js 显式逻辑;info 类型不生成 .section
包裹层,补一条 .section-info 规则才能藏住服务商申请说明。

验证(发布前):
- 写作端到端 71 条、后台渲染 21 条、密钥路径 9 条,合计 101 条全过
- 反证 22 组(W1~W16 端到端 / A1~A6 后台)× R1~R14 发布包注入,
  全部让失败数从 0 增加
- 测试自身不污染:每节差分回滚 + 总闸门,标签库稳定 703 / 967 篇
- 发布走 theme-update/,主题目录仍是 3.2.56,未被覆盖
This commit is contained in:
2026-10-27 16:05:43 +08:00
parent b7dcdc1602
commit 0a5486e195
6 changed files with 1653 additions and 3 deletions
@@ -128,6 +128,43 @@ jQuery(document).ready(function ($) {
jQuery(document).on('change', '#toc_inline, #toc_float', yq_toggle_toc_fields)
yq_toggle_toc_fields()
// 写作增强:翻译服务商的四个凭据 + 说明,只在「自动生成英文别名」勾选时才有意义。
//
// 为什么用 requires 之外的方式:`requires` 这个键在框架里**根本没被读取**
// (grep 整个 options-framework 目录零命中,条件显示全靠本文件里这些
// 硬编码的 jQuery)。所以主题里其它 19 处 'requires' 其实都是死代码,
// 这里不再往那个坑里加,直接写显式逻辑。
//
// 为什么连说明文字一起藏:用户没勾别名生成时,那段「去百度申请 APPID」
// 只会是噪声。
//
// ⚠️ 用 delegation + toggleClass('yq-cond-hide'),不直接绑 input.hide():
// 原因与上面的自动目录一致(.section 的 display 是 flow-root,
// jQuery 会把行内 display 写成 block,回退 3.2.28 的布局修复)。
// info 那块没有 .section 类,靠 CSS 里补的 .section-info 规则命中。
function yq_toggle_writing_slug_fields () {
var on = jQuery('#w_on_slug').is(':checked')
jQuery('#section-w_provider').toggleClass('yq-cond-hide', !on)
jQuery('#section-w_baidu_appid').toggleClass('yq-cond-hide', !on)
jQuery('#section-w_baidu_key').toggleClass('yq-cond-hide', !on)
jQuery('#section-w_youdao_appid').toggleClass('yq-cond-hide', !on)
jQuery('#section-w_youdao_key').toggleClass('yq-cond-hide', !on)
jQuery('#section-w_timeout').toggleClass('yq-cond-hide', !on)
jQuery('#w_provider_help').toggleClass('yq-cond-hide', !on)
}
jQuery(document).on('change', '#w_on_slug', yq_toggle_writing_slug_fields)
yq_toggle_writing_slug_fields()
// 写作增强:「每篇最多新增几个标签」只在「自动生成标签」勾选时才有意义。
function yq_toggle_writing_tag_fields () {
var on = jQuery('#w_on_tag').is(':checked')
jQuery('#section-w_tag_new_limit').toggleClass('yq-cond-hide', !on)
}
jQuery(document).on('change', '#w_on_tag', yq_toggle_writing_tag_fields)
yq_toggle_writing_tag_fields()
// Loads the color pickers
$('.of-color').wpColorPicker()