1. 为什么要在子主题里接统一 API 通道
做 WordPress 子主题开发的人,迟早会遇到一个绕不开的问题:主题里想加一点 AI 能力,比如自动生成文章摘要、给评论区做语义审核、或者在后台写个辅助写作的小工具,结果发现每个功能都要单独配一套 Key、单独写一套请求逻辑。父主题升级一次,自己塞进去的代码就可能被覆盖;换个模型供应商,又得把散落在各处的 endpoint 和鉴权头全部改一遍。
我试过最笨的办法,就是把 Key 硬编码在functions.php里,结果一次误提交到公开仓库,只能连夜轮换。后来改成在子主题里做一层薄封装,把所有 AI 请求收敛到一个统一入口,Key 只存一份,模型名和接口地址走常量配置。这样父主题怎么升级都不影响,子主题只负责“接线”。
这篇就围绕这个思路展开:在 WordPress 子主题的functions.php里接入 TaoToken 的统一 Key/API 通道,配好style.css的头部注释骨架,最后在后台验证子主题是否真正启用、API 调用是否真的通。适合已经会写基础子主题、但还没把 AI 请求工程化的开发者。全程给可复制的代码,不讲空泛概念。
TaoToken 在这里扮演的角色,是一个统一的模型调用入口:你拿到一个 Key,就能通过兼容 OpenAI 风格的接口去请求不同模型,不用为每个供应商单独维护一套鉴权逻辑。对 WordPress 这种插件生态复杂、代码容易分散的环境来说,收敛入口这件事本身就值回票价。
2. 前置准备:子主题骨架与 TaoToken Key
2.1 子主题目录与最小文件集
先在wp-content/themes/下建一个子主题目录,比如叫mytheme-child。最小文件集只有两个:style.css和functions.php。style.css不是用来写样式的重点,它的头部注释才是 WordPress 识别子主题的关键;functions.php则是我们接入 API 通道的主战场。
目录结构大概是这样:
wp-content/themes/mytheme-child/ ├── style.css └── functions.php父主题假设叫mytheme,实际替换成你自己的主题目录名即可。注意子主题目录名和Template字段必须和父主题目录名完全一致,大小写敏感,这是最常见的“子主题不生效”原因之一。
2.2 拿 TaoToken Key 与确认接口地址
到 TaoToken 控制台创建一个 API Key,建议单独建一个给 WordPress 用的 Key,方便后续按站点轮换或吊销。控制台入口在这里:
API Keys 管理:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite
接口基地址用https://taotoken.net/api,请求路径按兼容风格拼,比如对话补全走/v1/chat/completions。Key 不要写死在代码里,后面我们会用wp-config.php常量或者环境变量注入。文档入口:
接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite
如果你只是想先在后台点几下验证模型通不通,可以先用模型对话页面试一条请求,确认 Key 有效再写代码:
模型对话:https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite
3. 可复制配置:style.css 头部与 functions.php 骨架
3.1 style.css 头部注释骨架
子主题的style.css头部必须包含Template字段,否则 WordPress 不会把它识别为子主题。下面这段直接复制,把mytheme换成你的父主题目录名:
/* Theme Name: MyTheme Child Theme URI: https://example.com/mytheme-child Description: MyTheme 子主题,接入 TaoToken 统一 API 通道。 Author: Your Name Author URI: https://example.com Template: mytheme Version: 1.0.0 Text Domain: mytheme-child */ /* 子主题样式从这里开始写,父主题样式通过下面的 enqueue 引入 */Template这一行是命门。写错一个字母,后台“外观”里就看不到这个子主题。Text Domain建议和目录名保持一致,方便后续做国际化。
3.2 functions.php:常量与请求封装
下面这段是核心骨架。它做了三件事:定义 API 常量和 Key 读取逻辑、封装一个统一的请求函数、提供一个带缓存的调用示例。Key 从wp-config.php常量读取,代码里不出现明文。
<?php /** * MyTheme Child functions.php * 接入 TaoToken 统一 API 通道 */ if ( ! defined( 'ABSPATH' ) ) { exit; } // 1. API 常量:基地址与默认模型 if ( ! defined( 'TAOTOKEN_API_BASE' ) ) { define( 'TAOTOKEN_API_BASE', 'https://taotoken.net/api' ); } if ( ! defined( 'TAOTOKEN_DEFAULT_MODEL' ) ) { define( 'TAOTOKEN_DEFAULT_MODEL', 'gpt-4o-mini' ); } // 2. 读取 Key:优先 wp-config.php 常量,其次环境变量 function mytheme_child_get_api_key() { if ( defined( 'TAOTOKEN_API_KEY' ) && TAOTOKEN_API_KEY ) { return TAOTOKEN_API_KEY; } $env = getenv( 'TAOTOKEN_API_KEY' ); return $env ? $env : ''; } // 3. 统一请求封装 function mytheme_child_taotoken_chat( $messages, $model = '', $timeout = 30 ) { $key = mytheme_child_get_api_key(); if ( empty( $key ) ) { return new WP_Error( 'no_key', 'TaoToken API Key 未配置' ); } $model = $model ? $model : TAOTOKEN_DEFAULT_MODEL; $url = TAOTOKEN_API_BASE . '/v1/chat/completions'; $response = wp_remote_post( $url, array( 'timeout' => $timeout, 'headers' => array( 'Authorization' => 'Bearer ' . $key, 'Content-Type' => 'application/json', ), 'body' => wp_json_encode( array( 'model' => $model, 'messages' => $messages, ) ), ) ); if ( is_wp_error( $response ) ) { return $response; } $code = wp_remote_retrieve_response_code( $response ); $body = wp_remote_retrieve_body( $response ); $data = json_decode( $body, true ); if ( 200 !== $code ) { $msg = isset( $data['error']['message'] ) ? $data['error']['message'] : $body; return new WP_Error( 'api_error', $msg, array( 'status' => $code ) ); } if ( isset( $data['choices'][0]['message']['content'] ) ) { return $data['choices'][0]['message']['content']; } return new WP_Error( 'bad_response', '响应结构异常' ); }3.3 在 wp-config.php 注入 Key
打开站点根目录的wp-config.php,在/* That's all, stop editing! */之前加一行:
define( 'TAOTOKEN_API_KEY', '你的_TaoToken_Key' );这样 Key 不进主题代码,换 Key 只改一处,也不会随主题导出泄露。生产环境更推荐用环境变量,mytheme_child_get_api_key()已经做了兼容。
3.4 加一个带缓存的调用示例
直接每次请求都打 API 既慢又费额度,用transient做一层缓存:
function mytheme_child_generate_summary( $post_id ) { $cache_key = 'mytheme_child_summary_' . $post_id; $cached = get_transient( $cache_key ); if ( false !== $cached ) { return $cached; } $content = get_post_field( 'post_content', $post_id ); if ( empty( $content ) ) { return ''; } $messages = array( array( 'role' => 'system', 'content' => '你是摘要助手,输出不超过 80 字。' ), array( 'role' => 'user', 'content' => wp_strip_all_tags( $content ) ), ); $result = mytheme_child_taotoken_chat( $messages ); if ( is_wp_error( $result ) ) { return ''; } set_transient( $cache_key, $result, 12 * HOUR_IN_SECONDS ); return $result; }缓存时间按内容更新频率调,文章类 12 小时通常够用。发布新文章时记得清掉对应 transient,避免摘要不更新。
4. 验证:子主题启用与 API 调用是否生效
4.1 后台确认子主题已启用
进入 WordPress 后台,打开“外观 → 主题”,应该能看到MyTheme Child。如果没出现,九成是style.css的Template字段和父主题目录名不一致,或者style.css头部注释格式被破坏(比如注释块没闭合)。启用后,前台页面样式应继承父主题,说明子主题生效。
4.2 用一段临时钩子验证 API 连通
在functions.php里临时加一段,只在管理员访问后台时触发一次请求,把结果写进错误日志:
add_action( 'admin_init', function () { if ( ! current_user_can( 'manage_options' ) ) { return; } if ( get_transient( 'mytheme_child_api_probe' ) ) { return; } $result = mytheme_child_taotoken_chat( array( array( 'role' => 'user', 'content' => '只回复两个字:连通' ), ) ); if ( is_wp_error( $result ) ) { error_log( '[TaoToken] 失败: ' . $result->get_error_message() ); } else { error_log( '[TaoToken] 成功: ' . $result ); } set_transient( 'mytheme_child_api_probe', 1, 300 ); } );打开wp-content/debug.log(需在wp-config.php开启WP_DEBUG_LOG),看到[TaoToken] 成功: 连通就说明通道打通。验证完把这段钩子删掉,别留在生产环境。
4.3 用 WP-CLI 快速验证
如果你有 WP-CLI,可以跳过临时钩子,直接跑:
wp eval 'var_dump( mytheme_child_taotoken_chat( array( array( "role" => "user", "content" => "ping" ) ) ) );'返回字符串就是通,返回WP_Error对象就按下一节的排查表逐项对。
5. 本篇常见错排查
5.1 子主题不显示 / 启用后样式丢失
先查style.css的Template值。父主题目录叫mytheme,这里就必须是mytheme,不能写成主题名MyTheme。样式丢失通常是没在子主题里 enqueue 父主题样式,补一段:
add_action( 'wp_enqueue_scripts', function () { wp_enqueue_style( 'mytheme-parent', get_template_directory_uri() . '/style.css' ); wp_enqueue_style( 'mytheme-child', get_stylesheet_uri(), array( 'mytheme-parent' ) ); } );5.2 请求返回 401 / 403
401 基本是 Key 问题:TAOTOKEN_API_KEY没定义、值带空格、或者 Key 已被吊销。403 常见于请求头缺失Authorization,检查wp_remote_post的headers是否被其他插件过滤掉。可以用wp_remote_retrieve_response_code()打印状态码定位。
5.3 请求超时或返回 502
WordPress 默认超时偏短,长文本请求容易超时。把封装函数里的timeout调到 60,并确认服务器到taotoken.net的出网正常。502 多为上游瞬时问题,加重试逻辑:
$result = mytheme_child_taotoken_chat( $messages ); if ( is_wp_error( $result ) ) { sleep( 1 ); $result = mytheme_child_taotoken_chat( $messages ); }5.4 响应结构异常 / 解析失败
不同模型的返回字段可能略有差异,但兼容风格下choices[0].message.content是通用路径。如果拿到空内容,先error_log( $body )看原始返回,确认是不是命中了限流或内容策略。别直接假设是代码问题。
5.5 缓存导致结果不更新
transient没清,改了文章摘要还是旧的。发布/更新文章时挂一个清理钩子:
add_action( 'save_post', function ( $post_id ) { delete_transient( 'mytheme_child_summary_' . $post_id ); } );6. 长期编码与 Agent 场景的接入建议
如果你不只是想在主题里做几个小功能,而是打算把 WordPress 当成一个长期运行的 AI 应用底座,比如自动写稿、批量生成 SEO 描述、或者接一个后台 Agent 做内容运营,那 Key 的管理方式要提前规划。单站点单 Key 够用,多站点或团队协作就该考虑用 Coding Plan 这类按项目组织的方案,把额度、模型和调用方分开管理,避免一个站点跑飞影响全部。
Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite
回到代码层面,子主题这层封装的价值在于:父主题升级不丢逻辑,Key 集中一处,模型切换只改常量。后面无论你是接 Claude Code 做本地开发辅助,还是把请求搬到定时任务里跑,入口都是同一个mytheme_child_taotoken_chat()。先把这层骨架搭稳,再往上叠功能,比一开始就到处散落请求要省心得多。