diff --git a/inc/options-framework/autoload.php b/inc/options-framework/autoload.php index c21f2fe..bb8378b 100644 --- a/inc/options-framework/autoload.php +++ b/inc/options-framework/autoload.php @@ -71,6 +71,26 @@ if (!function_exists('kratos_option')): function kratos_option($name, $default = false) { + /* 一次性覆盖层:只影响当前这次请求。 + * + * 用在「后台点测试邮件」这一种场景:那时用户刚在表单里改了 + * SMTP 主机/账号/密码,但新值还没写进库(register_setting 的 + * sanitize 回调返回值之后才落库)。直接读库会拿到上一次的配置, + * 于是"明明填对了却发不出去"。 + * + * 为什么不用 update_option() 把新值先写进去:那个函数会再触发 + * 一次 sanitize_option_kratos 过滤器,而写入逻辑本身就在那个 + * 回调里 ⇒ 无限递归吃爆内存(3.2.11 的事故)。 + * + * 覆盖层只在本请求内有效、不落库、不触发任何过滤器, + * 所以安全。其它场景这个全局变量根本不存在,行为与原来一致。 + */ + if (isset($GLOBALS['__yang_options_override']) + && is_array($GLOBALS['__yang_options_override']) + && array_key_exists($name, $GLOBALS['__yang_options_override'])) { + return $GLOBALS['__yang_options_override'][$name]; + } + $option_name = 'kratos'; // Get option settings from database diff --git a/inc/options-framework/includes/class-options-framework-admin.php b/inc/options-framework/includes/class-options-framework-admin.php index 4aaa886..79db8a7 100644 --- a/inc/options-framework/includes/class-options-framework-admin.php +++ b/inc/options-framework/includes/class-options-framework-admin.php @@ -255,15 +255,27 @@ class Options_Framework_Admin { if ( isset( $_POST['sendmail'] ) ) { /* - * 测试发信必须先落库再发。 + * 测试发信要让「这一批新配置」立刻生效,但**绝对不能** + * 在这里调 update_option()。 * - * 这个函数是 register_setting 的回调,返回值**之后**才会被 - * update_option() 写进数据库。如果在这里直接 wp_mail(), - * 主题配置 PHPMailer 时读 kratos_option() 拿到的还是**上一次**保存的 - * 主机/账号/密码 —— 刚改完配置点测试,测的其实是旧配置, - * 用户会看到"明明填对了却发不出去"或"改了密码还能发"这种怪现象。 + * ── 为什么不调(3.2.11 的血案)────────────────────────── + * 本函数是 register_setting() 注册的 sanitize_callback, + * WP 把挂在 `sanitize_option_kratos` 这个过滤器上 + * (wp-includes/option.php:3073)。而 update_option() 内部 + * **会再跑一遍**同名过滤器 ⇒ 又调回本函数 ⇒ 本函数再 + * update_option() ⇒ 无限递归。 + * + * 递归每层都在复制 $clean 和 $_POST 派生的大数组,最终把 + * 内存吃到上限,报出来的是 + * 「Allowed memory size of 268435456 bytes exhausted + * in class-wp-block-parser.php」。报错落在区块解析器上纯属 + * 巧合 —— 那只是递归链最后执行到的一行,看它会完全找错方向。 + * + * 正确做法:不写库、不递归,只把新值放进一个一次性覆盖层, + * 让 kratos_option() 在本次请求里优先读它。写完库由 WP 自己 + * 在 validate_options 返回后完成。 */ - update_option( 'kratos', $clean ); + $GLOBALS['__yang_options_override'] = is_array( $clean ) ? $clean : array(); $this->yang_send_test_mail( $clean ); diff --git a/style.css b/style.css index 52b2e8a..bc9c7ee 100644 --- a/style.css +++ b/style.css @@ -1,7 +1,7 @@ /* Theme Name: Kratos_Yang Text Domain: kratos_Yang -Version: 3.2.11 +Version: 3.2.12 Requires PHP: 7.0 Description: 这是一个Kratos主题的分支版本,用来增加一些定制化功能。 Tags: 博客, 双栏, 响应式, 自定义背景, 自定义颜色, 自定义图标, 自定义菜单, 特色图像, 收录优化, 邮件中心, 主题选项, 小工具, 文章置顶, 无障碍友好