Files
wordpress-kratos-yang/inc/options-framework/css/optionsframework.css
T
laoyang 0a5486e195 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,未被覆盖
2026-10-27 16:05:43 +08:00

541 lines
14 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#optionsframework {
max-width: 855px;
background: #fff;
}
#optionsframework h3 {
margin: 0;
padding: 12px 10px;
border-bottom: 1px solid #ddd;
background-color: #f1f1f1;
cursor: default;
}
#optionsframework p {
margin-bottom: 0;
padding-bottom: 10px;
}
#optionsframework .section {
padding: 10px 10px 0;
}
#optionsframework .group {
padding-bottom: 40px;
}
#optionsframework .section .controls {
float: left;
padding-right: 2%;
width: 54%;
min-width: 350px;
}
#optionsframework .section .explain {
float: left;
max-width: 38%;
color: #777;
font-size: 12px;
line-height: 16px;
}
#optionsframework .section-checkbox .controls {
width: 98%;
}
#optionsframework .section-checkbox .explain {
max-width: 94%;
}
#optionsframework .controls input[type="text"],
#optionsframework .controls input[type="password"] {
width: 100%;
}
#optionsframework .controls input[type="text"].wp-color-picker {
width: 65px;
}
#optionsframework .controls select,
#optionsframework .controls textarea {
margin-bottom: 10px;
width: 100%;
}
#optionsframework .section-radio label,
#optionsframework .section-multicheck label {
float: left;
margin-bottom: 5px;
max-width: 90%;
line-height: 16px;
}
#optionsframework input.checkbox,
#optionsframework input.of-radio {
float: left;
clear: both;
margin: 0 10px 5px 0;
}
#optionsframework .section-typography .controls {
float: none;
width: auto;
}
#optionsframework .section-typography .explain {
float: none;
width: auto;
}
#optionsframework .controls .of-typography-size {
float: left;
width: 80px;
}
#optionsframework .controls .of-typography-unit {
float: left;
margin-left: 5px;
width: 50px;
}
#optionsframework .controls .of-typography-face {
float: left;
margin-left: 5px;
width: 100px;
}
#optionsframework .controls .of-typography-style {
float: left;
margin-right: 5px;
margin-left: 5px;
width: 80px;
}
#optionsframework .section-typography .wp-picker-container {
margin-top: 2px;
}
#optionsframework .of-background-properties {
clear: both;
margin-top: 18px;
}
#optionsframework .controls .of-background-repeat {
float: left;
margin-right: 5px;
width: 125px;
}
#optionsframework .controls .of-background-position {
float: left;
margin-right: 5px;
width: 125px;
}
#optionsframework .controls .of-background-attachment {
float: left;
margin-right: 5px;
width: 125px;
}
#optionsframework .section-background .wp-picker-container {
margin-bottom: 10px;
}
#optionsframework .controls .of-radio-img-img {
float: left;
display: none;
margin: 0 5px 10px 0;
border: 3px solid #f9f9f9;
cursor: pointer;
}
#optionsframework .controls .of-radio-img-selected {
border: 3px solid #ccc;
}
#optionsframework .controls .of-radio-img-img:hover {
opacity: 0.8;
}
#optionsframework .controls .of-border-width {
float: left;
width: 80px;
}
#optionsframework .controls .of-border-style {
float: left;
width: 120px;
}
#optionsframework .hide {
display: none;
}
#optionsframework .of-option-image {
margin: 3px 0 18px 0;
max-width: 340px;
}
#optionsframework .mini .controls select,
#optionsframework .section .mini .controls {
width: 140px;
}
#optionsframework .mini .controls input,
#optionsframework .mini .controls {
width: 140px;
min-width: 140px;
}
#optionsframework .mini .explain {
max-width: 74%;
}
#optionsframework .section-info {
padding-bottom: 7px;
}
#optionsframework .controls input.upload {
width: 80%;
}
#optionsframework .screenshot {
position: relative;
float: left;
margin-top: 3px;
margin-left: 1px;
width: 344px;
}
#optionsframework .screenshot img {
float: left;
margin-bottom: 10px;
padding: 4px;
max-width: 334px;
border-color: #ccc #eee #eee #ccc;
border-style: solid;
border-width: 1px;
background: #fafafa;
}
#optionsframework .screenshot .remove-image {
position: absolute;
bottom: 4px;
left: -4px;
float: left;
display: block;
padding: 0;
width: 16px;
height: 16px;
border: medium none;
background: url("../images/ico-delete.png") no-repeat;
text-indent: -9999px;
}
#optionsframework .screenshot .no_image .file_link {
margin-left: 20px;
}
#optionsframework .screenshot .no_image .remove-button {
bottom: 0px;
}
#optionsframework .reset-button {
float: left;
cursor: pointer;
}
#optionsframework-submit {
padding: 7px 10px;
border-top: 1px solid #ddd;
background-color: #f1f1f1;
}
#optionsframework .button-primary {
float: right;
}
#optionsframework .section:after {
display: table;
content: "";
}
#optionsframework .section:after {
clear: both;
}
#optionsframework .about-content {
padding: 10px 20px;
}
#optionsframework .about-content img {
width: 100%;
height: auto;
}
#optionsframework .about-content h4 {
margin-top: 20px;
margin-bottom: 16px;
padding-bottom: 0.3em;
border-bottom: 1px solid #eaecef;
font-weight: 600;
font-size: 18px;
line-height: 1.25;
}
#optionsframework .about-content ul {
padding-left: 0;
list-style: none;
font-size: 15px;
}
#optionsframework .about-content ul li {
line-height: 25px;
}
#optionsframework .about-content .notices {
color: #727777;
font-size: 14px;
}
#optionsframework .about-content .tips {
color: #333333;
text-align: center;
font-size: 16px;
}
#optionsframework .about-content .tips b {
margin-left: 3px;
}
/* ── 多选复选框组(multicheck)────────────────────────────────
框架原本没有这个类型的渲染分支,所以也没有配套样式。
不加样式的话,9 个纪念日会挤成一行流水文字,看不出是一个可勾选的清单。
这里做成两列表格状,并把说明文字压到第二行、颜色调淡,
让「名称」是视觉主体、「日期说明」是补充信息。 */
#optionsframework .of-multicheck {
margin: 0;
padding: 2px 0 0;
border: 0;
}
#optionsframework .of-multicheck-item {
display: flex;
align-items: flex-start;
gap: 8px;
padding: 9px 12px;
margin: 0 0 2px;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.15s ease;
}
#optionsframework .of-multicheck-item:hover {
background-color: #f3f5f7;
}
#optionsframework .of-multicheck-item input[type="checkbox"] {
margin: 3px 0 0;
flex: 0 0 auto;
}
/* 名称与说明两行文字共用的竖排容器 */
#optionsframework .of-multicheck-text {
display: flex;
flex-direction: column;
flex: 1 1 auto;
}
#optionsframework .of-multicheck-label {
font-size: 14px;
color: #23282d;
line-height: 1.5;
}
#optionsframework .of-multicheck-note {
font-size: 12px;
color: #727777;
line-height: 1.5;
margin-top: 3px;
}
/* ══════════════════════════════════════════════════════════════
3.2.24 设置页布局重排
用户反馈:"主题设置的样式不好看,把标签页按钮放左侧、上下排列,
功能项放在右侧,重新设置好看一点。"
实现:≥960px 时把 nav-tab-wrapper 浮到左侧成一列竖排导航,
内容区(含保存提示条)整体右移;窄屏回退 WP 默认的横向标签,
不在手机后台做特殊布局。切标签的 JS(options-custom.js)不动,
它只认 .nav-tab / .nav-tab-active / .group 这几个类。
══════════════════════════════════════════════════════════════ */
@media screen and (min-width: 960px) {
#optionsframework-wrap {
max-width: 1180px;
}
/* 浮动布局的收尾:否则 wrap 高度塌到标签列或面板较短的那个 */
#optionsframework-wrap::after {
display: table;
clear: both;
content: "";
}
/* ── 左侧标签列 ── */
#optionsframework-wrap h2.nav-tab-wrapper {
float: left;
box-sizing: border-box;
width: 190px;
margin: 0 20px 20px 0;
padding: 8px;
border: 1px solid #dcdcde;
border-radius: 6px;
background: #fff;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04);
}
#optionsframework-wrap .nav-tab-wrapper .nav-tab {
float: none;
display: block;
width: 100%;
box-sizing: border-box;
margin: 0 0 2px;
padding: 9px 12px;
border: 0;
border-left: 3px solid transparent;
border-radius: 4px;
background: none;
color: #50575e;
line-height: 1.5;
cursor: pointer;
}
#optionsframework-wrap .nav-tab-wrapper .nav-tab:last-child {
margin-bottom: 0;
}
#optionsframework-wrap .nav-tab-wrapper .nav-tab:hover {
border-left-color: transparent;
background: #f0f0f1;
color: #1d2327;
}
#optionsframework-wrap .nav-tab-wrapper .nav-tab-active,
#optionsframework-wrap .nav-tab-wrapper .nav-tab-active:hover {
border-left-color: #00a2ff;
background: #e8f5ff;
color: #0089db;
font-weight: 600;
}
/* ── 右侧内容区:面板 + 保存提示条都要让开左侧一列 ── */
#optionsframework-wrap > #optionsframework-metabox,
#optionsframework-wrap > .notice,
#optionsframework-wrap > .updated,
#optionsframework-wrap > .error {
margin-left: 210px;
}
/* ══════════════════════════════════════════════════════════
3.2.33 两栏顶边对齐
用户反馈:"左侧标签栏和右侧设置框两个也不一样高,有一个高度差,
看着很别扭。" —— 实际量下来不是高度,是**顶边**:左栏白卡片
top=53,右栏白卡片 top=63,差 10px,左边高、右边低。
病因在 WordPress 自己的后台样式:
#wpbody-content .metabox-holder { padding-top: 10px }
这条是给「一路往下排的 metabox」留顶部间距用的。3.2.24 把标签列
float 到左边、变成两栏并排之后,这 10px 就没人跟它配对了 ——
左栏(h2.nav-tab-wrapper)不带这层 padding,右栏带,于是错开。
修法:两栏并排时把那 10px 清零。**只在 ≥960px 里清** ——
窄屏仍是标签横排在上一路往下,那 10px 是该留的间距。
⚠️ 不能用 padding-top: 10px 补给左栏来"凑齐":那会让左栏白卡片
内部多出一段看不见的空白,标签整体下移 10px,与页面标题之间
出现空隙,问题只是从「两栏错位」变成「左栏内部偏下」。
══════════════════════════════════════════════════════════ */
#optionsframework-wrap > #optionsframework-metabox {
padding-top: 0;
}
#optionsframework-metabox #optionsframework {
border-radius: 6px;
}
}
/* ── 区块内部(宽窄屏都生效)────────────────────────────────
1. 分组标题:原来 `#optionsframework h3` 是给面板顶部那条用的
灰底横条,选择器太宽把每个分组标题也罩了进去,整页一排灰条。
这里把分组标题单独重排:去灰底、加重字重、压淡下边线。 */
#optionsframework .group > h3 {
margin: 0;
padding: 15px 18px 13px;
border-bottom: 1px solid #f0f0f1;
background: none;
font-size: 15px;
font-weight: 600;
color: #1d2327;
}
/* 2. 区块间距与分隔:原来 10px 的内边距太挤,项与项之间没有分界。
* 3.2.26 调整:16/8 → 14/12,并清掉 h4 标题的 WP 默认 margin(见下)
*
* 3.2.28:这里补上了 `display: flow-root` —— 本次真正的根因修复。
*
* 3.2.24 把标签列改成 float:left(宽 190px;标签多了以后整列约 400px 高),
* 而框架原本给 .section 留了 ::after{clear:both} 来清除内部浮动的
* .controls / .explain。问题在于 clear 的作用范围以**最近的 BFC** 为界:
* .section 只是普通块盒、不建 BFC,于是它末尾那个清除元素被要求避开
* **左侧整个浮动标签列**,把第一个配置项的下边界一直撑到标签列底部
* (实测 section 高 405px,而内容只占 43px)。
*
* 这也解释了 3.2.26 只收编 h4 的 margin 为什么完全无效 —— 多出来的不是
* 间距,是 section 自身的高度;空白也只出现在第一个配置项之后,因为后面
* 的 section 起点已经越过标签列底部,clear 不再起作用。
*
* 修法:让 .section 建立自己的 BFC,内部的清除就只在自身范围内生效。
* 不能用 overflow:hidden —— 那会把颜色选择器的弹出层裁掉。
* 原有的 ::after{clear:both}(见上面 .section:after)保留,
* 作为极老浏览器不支持 flow-root 时的兜底。 */
#optionsframework .section {
display: flow-root;
padding: 14px 18px 12px;
border-bottom: 1px solid #f6f7f7;
}
/* 3.2.26:配置项标题(h4.heading)继承 WP 后台 common.css 的
* 上下 margin ≈17px,与 section 的 padding 叠加后,相邻两个配置项
* 之间多出约 34px 的空隙(上下各 17px)。标题的内距统一由本条控制:
* 上边距清零(section 的 padding-top 负责),下边距 10px 压住控件。 */
#optionsframework .section > .heading {
margin: 0 0 10px;
}
/* 条件字段(如「自动插入位置」只在目录位置=正文中间时才有意义)
*
* 用 !important 的 display:none 而不是 jQuery 的 show()/hide(),原因见
* js/options-custom.js 里 yq_toggle_toc_anchor():.section 的 display 是
* flow-root,jQuery 会把行内 display 写成 block,等于回退 3.2.28 的修复。
* 这里只隐藏,不改变其它布局属性。 */
#optionsframework .section.yq-cond-hide {
display: none !important;
}
/* info 类型的条件隐藏
*
* info 不生成 .section 包裹层(框架对它走另一条分支),它自己是
* div.section-info。上面那条选择器要求同时有 .section 类,命不中它,
* 所以单独补一条 —— 否则「写作增强」里那段服务商申请说明永远显示,
* 即使「自动生成英文别名」没勾。 */
#optionsframework .section-info.yq-cond-hide {
display: none !important;
}
/* 3. 提交栏:与分组标题同一套留白 */
#optionsframework-submit {
padding: 12px 18px;
}