适用对象:OneNav / 一为导航 系列主题(包括子主题 onenavsub) 问题场景:/hotnews/ 今日热榜页面上 20 张卡片通通显示空白,并提示「服务状态不可用」一、先弄明白空白的根源
进入热榜页面按 F12 打开 Network 面板,点击右上角的刷新按钮,你会发现卡片发出的请求指向:
//ionews.top/api/get.php?rule_id=100000&key=xxxx返回的结果是:
{"state":0,"title":"iotheme","subtitle":"续期",
"data":[{"title":"服务状态不可用!","hot":"¥98"}]}答案一目了然:这些卡片调用的是 ioTheme 的付费热榜接口,而你的订阅已过期。
主题中的每张热榜卡片都有一个「类型」字段,总共四种:
| 类型 | 走的通道 | 费用 |
|---|---|---|
api | ionews.top 付费热榜接口 | 收费,订阅一到期就空白 |
weixin | 同上(微信公众号榜单) | 收费 |
json | 通过站内 admin-ajax.php 由服务端抓取自定义数据源 | 免费 |
rss | 同上,解析 RSS/XML 格式 | 免费 |
因此「不付费也能正常使用」的思路就是:把卡片类型从
api 改成 json,然后配置一组免费数据源。主题本身已经预留了这条免费路径,只是默认情况下所有卡片都绑定在 api 上。免费通道的优势:
- 由服务端抓取数据,不存在浏览器跨域问题,也不用担心目标站需要登录态;
- 内置 60 分钟缓存(transient),避免每次刷新页面都去请求源站;
- 后台提供可视化配置,完全不需要改代码。
二、挑选一个免费的热榜接口
我亲自测试了一圈,先把结论摆在前面,帮你避开坑:
| 候选 | 实测结果 | 备注 |
|---|---|---|
| uapis.cn 聚合接口 | ✅ 值得用 | 免费、免 key、覆盖 20+ 平台、数据结构完全一致 |
| DailyHotApi 公共镜像 | ⚠️ 不稳定 | 结构相同,但实测 weibo/zhihu 直接报 500,baidu 返回的是空的缓存数据 |
| 微博/知乎官方接口 | ❌ | 微博 403、知乎 401,都需要签名或登录态 |
| 自行抓取各平台 HTML | ❌ | 主题只支持 JSON 和 XML,无法解析网页 |
推荐使用的接口格式如下(把
TYPE 替换成平台名):https://uapis.cn/api/v1/misc/hotboard?type=weibo返回结构是固定的:
{
"type": "weibo",
"update_time": "2026-10-06T10:36:05.868Z",
"list": [
{"index":1, "title":"热搜词", "url":"https://s.weibo.com/...", "hot_value":"1435288", "extra":{}}
]
}可用的
TYPE 列表(每一个我都实际跑通过):baidu 36kr juejin bilibili xiaohongshu history sspai weibo zhihu huxiu
smzdm qq-news douyin kuaishou ithome toutiao tieba hupu v2ex acfun
csdn sina thepaper weread nodeseek hellogithub coolapk 51cto jianshu ifanr如果你想用别的免费源也可以,只要满足「返回 JSON 且内部含对象数组」这个条件,下面讲的节点配置方法同样适用。
三、后台配置(关键步骤)
第 1 步:新建数据源
进入后台 → 设置 → ◉ 自定义热榜 → 在「JSON数据源」里添加一条,各字段填写方式:
| 后台字段 | 填写内容 | 本例取值 |
|---|---|---|
| 名称 | 卡片标题(会覆盖卡片原本的名称) | 微博热搜榜 |
| 小标题 | 卡片标题旁边的小字,没有热度就留空 | 热度 |
| 地址 | 接口 URL | https://uapis.cn/api/v1/misc/hotboard?type=weibo |
| 数据节点 | 数组所在的层级路径,可以用 . 分层 | list |
| 标题节点 | 每条数据里的标题字段 | title |
| 链接节点 | 每条数据里的链接字段 | url |
| 热度节点(可留空) | 热度/阅读量对应字段 | hot_value |
| 链接补全 | 链接不完整时用 %s% 占位符补全 | 留空 |
| 缓存时间 | 单位是分钟,默认 60 | 60 |
保存就完成了,请求头、请求数据都不用碰。
第 2 步:将卡片切换到 JSON
进入后台 → 主题设置 → 今日热榜 → 今日热榜页列表,对每张卡片修改两个地方:
- 类型:
API改为JSON - 热榜ID:填入该源在「自定义热榜 → JSON数据源」中的序号(从 1 开始,按排列顺序)
⚠️ 序号对应卡片顺序。主题通过下标 $rule_id - 1 去读取源,所以: 数据源的排列顺序必须和卡片顺序严格一一对应;一旦在中间删除某条源,后面所有卡片都会错位。 调整完顺序后记得清除缓存(或者等 60 分钟自动失效)。最多支持 30 张卡,20 张已经足够日常使用。
四、最容易踩的 4 个坑(均为实测结果)
1. 部分平台根本没有链接字段
有些类型返回的
"url": "" 是空字符串,即使配置了链接节点也没意义,点进去是空链接。两种应对方式:- 更换数据源:换成同类中带链接的平台(我自己就把「吾爱破解」换成了「稀土掘金」);
- 用链接补全来兜底:例如「历史上的今天」没有链接,我把链接节点填
title,链接补全填https://www.baidu.com/s?wd=%s%,点标题就会直接用百度搜索这条历史事件,用起来反而更方便。
2. 部分平台没有热度值
实测不带热度的类型(
hot_value 全为空字符串)有:36kr、smzdm、qq-news、ithome、toutiao、v2ex、thepaper、51cto、jianshu、ifanr、coolapk这些卡片对应的热度节点要直接留空。留空时主题会返回
type:"",卡片右侧就不会渲染热度这一列;反过来说,如果填了节点但取到的值是空的,右侧会出现一块空白区域,非常影响观感。
3. 「名称」会覆盖卡片标题
主题 JS 里的逻辑是
$title.text(response.title) —— 页面上真正显示的标题来自数据源中的「名称」。 所以:源的名称必须与卡片名保持一致,否则你单独改卡片名不会起作用。4. 微信、API 两种类型不要指望
api 和 weixin 都依赖 ionews 的付费接口,订阅不续就永远显示「服务状态不可用」。 不想付费就直接改用 json / rss。五、验证与排错
配置完成后先别急着看页面,直接测接口是最快的(把
N 替换成对应热榜ID):https://你的站点/wp-admin/admin-ajax.php?action=get_hot_data&type=json&id=1成功的样子(
state:1 且 data 为数组):{"state":1,"title":"微博热搜榜","subtitle":"热度","type":"hot",
"data":[{"index":1,"title":"...","link":"...","hot":"..."}]}常见错误对照:
| 返回内容 | 成因 | 修复方法 |
|---|---|---|
state:0, code:202, data:"没有获取到内容。" | 节点路径写错了 / 源返回的不是 JSON | 核对「数据节点」,用浏览器直接访问接口 URL 查看结构 |
state:0, code:0, data:7 | 连不上目标服务器(域名失效/拼错) | 更换数据源 |
state:0, code:0, data:3 | 地址为空或格式不合法 | 检查「地址」字段 |
state:1 但标题是空的 | 「标题节点」配置有误 | 对照 JSON 中的实际字段名 |
| 页面内容还是旧的 | 缓存 / CDN | 等 60 分钟,或按 Ctrl+F5,或到后台清缓存 |
如果发现页面发出的请求仍然指向
ionews.top,那就是卡片类型没有改成 JSON(或 CDN 缓存了旧版 HTML)。 数一下页面源码中 data-api_type="json" 出现的次数即可确认。六、偷懒方案:批量写入(可选)
20 张卡一张张手动改实在太累,可以写个一次性脚本直接写入选项。下面这份是可以直接运行的版本 (7.3 / 8.2 语法都验证过),整体思路是「先探测 → 再写入 → 自动验证 → 删除文件」四个步骤:
使用方法:把代码保存为
热榜-fix.php,放到 wp-content/themes/你的主题/ 目录里,然后访问:热榜-fix.php?key=你的随机串&step=probe ← 只检测,不改动任何数据
热榜-fix.php?key=你的随机串&step=run ← 检测 + 写入 + 端到端验证
热榜-fix.php?key=你的随机串&step=run&self=1 ← 写入后自动删除本文件';
/**
* OneNav 热榜免费源批量配置脚本
*
* 放到:wp-content/themes/你的主题目录/
* 用法:
* 检测(不改动): 热榜-fix.php?key=xxx&step=probe
* 写入配置: 热榜-fix.php?key=xxx&step=run
* 写入后自毁: 热榜-fix.php?key=xxx&step=run&self=1
*
* ⚠️ 用完必须删除本文件
*/
/* 1) 换成你自己的随机串(别用原文,也别外传) */
$KEY = 'put-your-own-random-string-here';
/* 2) 主题目录 → 站点根目录,层级不对就自己调 */
require dirname(__FILE__) . '/../../../wp-load.php';
if (!isset($_GET['key']) || !hash_equals($KEY, (string) $_GET['key'])) {
http_response_code(403);
exit('403');
}
/* 兜底:确保主题的解析函数已加载 */
if (!function_exists('io_get_free_hot_data') || !function_exists('get_json_hot_data')) {
require get_theme_file_path('/inc/hot-search.php');
}
if (!function_exists('io_get_free_hot_data') || !function_exists('get_json_hot_data')) {
exit('主题热榜函数加载失败');
}
@set_time_limit(600);
header('Content-Type: text/html; charset=utf-8;');
$UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36';
/**
* 3) 卡片方案:一行一张卡,顺序 = 页面卡片顺序 = 热榜ID(从 1 开始)
* n 卡片标题(会覆盖页面上的名字)
* t 接口的平台 type
* hot 热度节点,该平台没有热度就填 ''
* link 链接节点,没链接就填 'title' 配合 lr 兜底
* lr 链接补全模板(%s% 会被 link 的值替换),没有就填 ''
* keep true=保留原卡片名与图标,false=用上面的 n 改名并换默认图标
*/
$PLAN = array(
array('n' => '百度热点', 't' => 'baidu', 'hot' => 'hot_value', 'link' => 'url', 'lr' => '', 'keep' => true),
array('n' => '36氪人气榜', 't' => '36kr', 'hot' => '', 'link' => 'url', 'lr' => '', 'keep' => true),
array('n' => '微博热搜榜', 't' => 'weibo', 'hot' => 'hot_value', 'link' => 'url', 'lr' => '', 'keep' => true),
array('n' => '知乎热榜', 't' => 'zhihu', 'hot' => 'hot_value', 'link' => 'url', 'lr' => '', 'keep' => true),
array('n' => '历史上的今天', 't' => 'history', 'hot' => '', 'link' => 'title', 'lr' => 'https://www.baidu.com/s?wd=%s%', 'keep' => true),
// ... 按需继续加,最多 30 行
);
/* ========== 以下不用改 ========== */
function hnf_sources($plan)
{
$out = array();
foreach ($plan as $p) {
$out[] = array(
'name' => $p['n'],
'subtitle' => $p['hot'] ? '热度' : '',
'url' => 'https://uapis.cn/api/v1/misc/hotboard?type=' . $p['t'],
'datas' => 'list',
'title' => 'title',
'link' => $p['link'],
'hot' => $p['hot'],
'link_regular' => $p['lr'],
'cache' => 60,
'request_type' => 'get',
);
}
return $out;
}
/* 用主题自己的解析管线试跑,保证写进去一定能跑通 */
function hnf_probe($src, $ua)
{
$r = wp_remote_get($src['url'], array('timeout' => 20, 'redirection' => 5, 'headers' => array('User-Agent' => $ua)));
if (is_wp_error($r)) {
return array(false, 0, $r->get_error_message());
}
if ((int) wp_remote_retrieve_response_code($r) !== 200) {
return array(false, 0, 'HTTP ' . wp_remote_retrieve_response_code($r));
}
$json = json_decode(wp_remote_retrieve_body($r), true);
if (!is_array($json)) {
return array(false, 0, '返回不是 JSON');
}
$rows = io_get_free_hot_data($json, $src['datas']);
if (!is_array($rows) || !$rows) {
return array(false, 0, '数据节点 ' . $src['datas'] . ' 取不到');
}
$res = get_json_hot_data($rows, $src);
if (empty($res['state']) || empty($res['data'])) {
return array(false, 0, '格式化为空');
}
return array(true, count($res['data']), $res['data'][0]['title']);
}
$step = isset($_GET['step']) ? (string) $_GET['step'] : 'probe';
$sources = hnf_sources($PLAN);
echo '热榜免费源配置
';
/* ---- 步骤1:探测 ---- */
echo '步骤1 探测(走主题自己的解析代码)
';
';
echo ''; # 卡片 类型 状态 条数 首条
foreach ($PLAN as $i => $p) {
list($ok, $num, $msg) = hnf_probe($sources[$i], $UA);
printf(
'', %d %s %s %s %s %s
$i + 1,
htmlspecialchars($p['n'], ENT_QUOTES, 'UTF-8'),
htmlspecialchars($p['t'], ENT_QUOTES, 'UTF-8'),
$ok ? '可用' : '' . htmlspecialchars($msg, ENT_QUOTES, 'UTF-8') . '',
$ok ? $num : '-',
htmlspecialchars(mb_substr((string) $msg, 0, 40, 'UTF-8'), ENT_QUOTES, 'UTF-8')
);
}
echo '
if ($step === 'probe') {
echo '仅检测,未改动。确认后访问:
热榜-fix.php?key=' . htmlspecialchars($KEY, ENT_QUOTES, 'UTF-8')
. '&step=run
exit;
}
/* ---- 步骤2:写入 ---- */
$theme = get_option('io_get_option');
if (!is_array($theme)) {
$theme = array();
}
$cards = (isset($theme['hot_home_list']) && is_array($theme['hot_home_list'])) ? $theme['hot_home_list'] : array();
if (!$cards && function_exists('all_topnew_list')) {
$cards = all_topnew_list();
}
/* 备份原配置(改坏了照它还原) */
echo '原配置备份(先复制保存):
. htmlspecialchars(wp_json_encode($cards, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT), ENT_QUOTES, 'UTF-8')
. '';
/* 写 JSON 源 */
$hot = get_option('io_hot_search_list');
if (!is_array($hot)) {
$hot = array();
}
$hot['json_list'] = $sources;
if (!isset($hot['rss_list']) || !is_array($hot['rss_list'])) {
$hot['rss_list'] = array();
}
update_option('io_hot_search_list', $hot);
/* 写卡片:类型→json,热榜ID→序号 */
$ico = get_theme_file_uri('/assets/images/hot_ico.png');
$n = 0;
foreach ($cards as $i => $card) {
if (!isset($PLAN[$i])) {
break;
}
$card['hot_type'] = 'json';
$card['rule_id'] = (string) ($i + 1);
if (empty($PLAN[$i]['keep'])) {
$card['name'] = $PLAN[$i]['n'];
相关站点
© 版权声明


How To Cook - 开源免费菜谱浏览站
新发现导航 - 精品分类网址导航大全
当佰网 - 文章资料与软件下载资源站
网址收藏夹