WeChatDraft 插件
WeChatDraft 是一个 Typecho 博客插件,把文章一键同步到微信公众号草稿箱:文中图片自动上传到微信素材库、封面自动选择、链接保留原文跳转。同步后在「微信公众平台」或「订阅号助手 APP」稍作调整即可发布,填补了 Typecho 在个人公众号场景下的空白。
功能特点
- 文章一键同步:发布 Typecho 文章时自动同步到公众号草稿箱。
- 图片自动上传:正文里的远程图片自动下载并上传到微信素材库,原
src替换成微信 URL。 - 封面智能选择:支持「文章首图优先」「默认封面优先」两种策略,找不到时兜底用素材库第一张。
- 同步策略灵活:支持 opt-in(默认不同步、按需开启)和 opt-out(默认全同步、按需排除)两种模式,通过注释 / 标签 / 分类三种方式标记。
- 防盗链与代理:可配置下载图片时的 Referer、User-Agent、额外 HTTP 头、超时和 HTTP/SOCKS5 代理,应对 CDN 限制。
- 公开 API:暴露
WeChatDraft_Plugin::syncDraft()给其他插件调用(如 AiDailyPost 等)。 - 失败可追溯:所有同步过程写入
logs/wechatdraft.log,方便排查。
安装方法
- 把本插件目录复制到 Typecho 的
/usr/plugins/WeChatDraft/。 - 登录 Typecho 后台 → 控制台 → 插件管理。
- 找到 WeChatDraft,点击「启用」。
配置说明
启用后到 设置 → 插件 → WeChatDraft 页面填写:
必填项
| 配置项 | 说明 |
|---|---|
| APPID | 微信公众号 AppID。 |
| Secret | 微信公众号 AppSecret。 注意:公众号后台需要把服务器出口 IP 加到「IP 白名单」,否则 access_token 拿不到。 |
基础配置
| 配置项 | 默认 | 说明 |
|---|---|---|
| 作者 | 空 | 公众号显示的作者名(不超过 8 个汉字)。留空走文章作者的个人资料昵称。 |
| 默认同步策略 | 不勾选 | 详见下文「同步策略」。 |
| 同步关键词 | wechat | 用于注释 / 标签 / 分类的匹配关键词。改名后已有文章里的旧标记也要相应改名。 |
封面图配置
封面图的来源由两项配合决定:
| 配置项 | 默认 | 说明 |
|---|---|---|
| 默认封面图 URL | 空 | 公网可访问的图片 URL,插件自动上传到微信永久素材库。建议尺寸 900×383(2.35:1),JPG/PNG。 修改 URL 后会自动重新上传,老的素材库图片不会被删除。 |
| 封面图优先策略 | 文章首图优先 | 控制 thumb_media_id 来源顺序,两种模式都会在最终找不到时回退到素材库第一张。 |
两种策略:
| 策略 | 顺序 | 适合场景 |
|---|---|---|
| 文章首图优先(默认) | 文章正文首图 → 默认封面 URL → 素材库第一张 | 每篇文章都有配图,希望封面跟着内容走 |
| 默认封面优先 | 默认封面 URL → 文章首图 → 素材库第一张 | 想给整个公众号统一品牌封面 |
图片下载配置(应对 CDN 防盗链)
当你的图片走 CDN 且开启了防盗链 / WAF,PHP curl 直接下载会被拒绝。下面这组配置都只影响图片下载环节,不影响微信 API 调用:
| 配置项 | 默认 | 说明 |
|---|---|---|
| 下载图片时的 Referer | 站点首页 URL | 填一个被 CDN 白名单允许的来源,如 https://www.liangwei.cc/。 |
| 下载图片时的 User-Agent | WeChatDraft/1.0 | 某些 CDN 按 UA 判断浏览器,可填浏览器 UA。 |
| 额外 HTTP 头 | 空 | 每行一个 Key: Value,用于自定义鉴权头或绕过特殊 WAF 规则。 |
| 下载超时(秒) | 30 | 单张图片下载超时秒数。大图或慢网可改 60。 |
| HTTP 代理 | 空 | http://host:port 或 socks5://host:port,留空直连。 |
影响范围:正文图片上传 + 封面图下载(含「文章首图作为封面」、「默认封面图 URL」两条路径)。
使用方法
- 在 Typecho 编辑器里写好文章(标题、正文、标签、分类)。
- 决定这篇文章是否要同步到公众号(见下方「同步策略」)。
- 点「发布」,被标记同步的文章会自动进入微信公众号草稿箱。
- 打开微信公众平台或订阅号助手 APP,在草稿箱里找到草稿,调整后发布。
⚠️ 个人订阅号限制:微信不向个人订阅号开放群发 API,文章只能落入草稿箱。最后一步「发布给粉丝」必须在订阅号助手 APP 手动点击 —— 这是平台规则,任何插件都绕不过去。
同步策略
「默认同步策略」开关决定手动发文默认是发还是不发:
| 默认策略 | 默认行为 | 想要相反行为时 |
|---|---|---|
| 不勾选(默认,opt-in) | 所有手动发文不同步 | 文章里加正向标记 → 同步 |
| 勾选(opt-out) | 所有手动发文都同步 | 文章里加反向标记 → 跳过 |
三种标记方式(任一命中即触发)
假设「同步关键词」是默认的 wechat:
正文注释(最方便,写在 Markdown 任何位置)
- 正向:
<!--wechat--> - 反向:
<!--no-wechat-->
- 正向:
文章标签(在编辑页右侧标签框里加)
- 正向:标签名为
wechat - 反向:标签名为
no-wechat
- 正向:标签名为
文章分类(按分类的名字或 slug 匹配,都行)
- 正向:分类名 / slug 为
wechat - 反向:分类名 / slug 为
no-wechat
- 正向:分类名 / slug 为
「同步关键词」可以在配置页改。修改后,文章里已有的旧标签 / 注释也得相应改名。
其他插件通过 API 调用
外部插件通过 WeChatDraft_Plugin::syncDraft() 主动调用时,不经过上述判断逻辑 —— API 调用者全权决定是否要同步。
给其他插件提供的公开 API
如果你写的 Typecho 插件需要把文章同步到微信公众号草稿箱,可以直接调用本插件暴露的静态方法:
if (class_exists('WeChatDraft_Plugin')) {
$result = WeChatDraft_Plugin::syncDraft(
$title, // 文章标题(string)
$contentHtml, // 文章正文 HTML(string,非 Markdown)
$sourceUrl, // 原文链接,用于 content_source_url(string)
$authorOverride = null // 可选:覆盖默认作者名,传 null 走插件配置或用户昵称
);
// $result = ['success' => bool, 'message' => string, 'media_id' => string|null]
}特性:
- 异常一律转成返回值,不会向调用方抛出异常 —— 草稿同步失败不应该让上游业务跟着挂。
- 自动校验 AppID / Secret 配置;缺失时返回
success=false并附带提示。 - 自动处理
<img>标签:远程 URL 先下载到本地 tmp,再上传到微信素材库(兼容 CDN 链接),然后替换src为微信 URL。 - 复用本插件的
access_token缓存与thumb_media_id缓存。 - 封面图按配置的「封面图优先策略」自动选取。
调用方需要自己负责:
- 把 Markdown / Editor.md / 富文本等格式转成 HTML(微信草稿 API 只认 HTML)。
- 如果不希望微信文章页出现重复大标题,在传入前剥掉正文顶部的
<h1>(公众号标题字段是独立传的)。 - 错误处理:根据
$result['success']决定是否要重试 / 写日志。
故障排查
日志文件
所有同步过程会写入插件目录下的 wechat-draft.log,包括 access_token 请求、图片下载、素材上传、草稿提交、错误堆栈。同步出问题先翻日志。
重置封面缓存
封面 media_id 有本地缓存(cache/mediaId + cache/mediaIdSource)。如果你在公众平台手动删了图、或想强制刷新,访问:
<你的站点>/reset_mediaid老的缓存会被清掉,下一次同步会重新选封面。
常见问题
invalid ip ... not in whitelist:服务器出口 IP 不在公众号白名单。去公众平台 → 设置与开发 → 基本配置 → IP 白名单加上。- 图片下载失败(403 / 超时):CDN 防盗链或网络限制。配置上面的「下载图片时的 Referer」「User-Agent」或「代理」,再不行就开「额外 HTTP 头」加自定义鉴权。
media_id拿不到 / 素材库为空:首次使用时,要么配置「默认封面图 URL」,要么先在公众平台手动传一张图到素材库。- 草稿里图片显示不出来:通常是图片本身就没下载成功,看日志里
图片上传相关行定位。
帮助
如果在安装、配置或使用 WeChatDraft 插件过程中遇到任何问题,请查阅以下资源获取帮助:
- Typecho 官方论坛:https://forum.typecho.org/
- 项目仓库:https://github.com/nmgliangwei/WeChatDraft
- 提交 Issue:https://github.com/nmgliangwei/WeChatDraft/issues
感谢
- 特别感谢由 qiuzhangsaer 提供的基础代码,本项目在此基础上进行了功能优化和升级
