WP Search Analytics:站内搜索关键词统计与分析插件
本文对应插件版本 v1.4.0(2026-08 更新)。相较最初发布的 v1.0.1,插件新增了最新搜索记录、IP 归属地、搜索结果自定义 HTML 注入、独立设置页与更新日志页,并对后台 UI 做了两轮重构。文末附「与旧版文章的差异对照」,老读者可直接跳到第八节。
一、插件简介
WP Search Analytics 是一款专为 WordPress 网站设计的搜索关键词统计与分析插件。它能帮助网站管理员深入了解访客的搜索行为,通过直观的数据可视化、详细的搜索词记录和强大的分析功能,轻松掌握用户最关心的内容,从而优化网站内容策略,提升用户体验。
插件基于 WordPress 标准开发规范构建,轻量、高效,与绝大多数主题和插件兼容,无需修改主题文件即可自动追踪所有原生搜索请求。
从 v1.1.0 开始,插件不再只是“统计工具”,而是加入了运营干预能力:当访客搜不到内容时,可以自动在搜索结果页下方插入你预设的 HTML(推荐文章、客服入口、引导表单等),把无效搜索转化为有效停留。



二、主要功能
1. 全面的搜索数据统计
- 总搜索次数:记录全站所有搜索请求的总次数。
- 唯一搜索词:按关键词哈希去重统计,反映用户需求的广度。
- 今日搜索量:实时展示当天的搜索活跃度,方便监控突发流量。
- 今日独立 IP 数:判断搜索量是“多人少搜”还是“一人狂搜”。
- 今日无结果搜索数:直接暴露内容缺口,是选题的第一手素材。
2. 趋势图表分析
- 可视化趋势图:使用 Chart.js 绘制搜索量随时间变化的折线图(indigo 配色,带面积填充)。
- 多时间维度:支持按 7天 / 30天 / 90天 / 1年 快速切换,服务端对天数做白名单校验(仅接受 7/30/90/365)。
3. 热门搜索词排行(独立页面)
自 v1.3.0 起,热门搜索词从仪表盘中分离为独立页面 搜索分析 → 热门搜索:
- 按搜索次数排序,默认展示前 100 个关键词。
- 排名徽章:Top 3 使用金/银/铜渐变背景 + 阴影,其余为统一灰色。
- 动画进度条:以第一名为基准计算百分比,进度条带 shimmer 光效。
- 平均结果数:展示该关键词历次搜索的平均命中数量。
- 状态标签:平均结果 > 0 显示“有结果”,否则显示“无结果”(带圆点指示器)。
- 最后搜索时间:相对时间显示(如“3 小时前”),鼠标悬停显示完整时间。
- 关键词筛选:输入框带 350ms 防抖,AJAX 实时过滤。
- 一键刷新:按钮图标旋转动画,重新拉取数据。
4. 最新搜索记录(独立页面)
自 v1.2.0 起新增 搜索分析 → 最新搜索 页面,默认展示最近 50 条明细记录:
| 列 | 说明 |
|---|---|
| # | 序号 |
| 搜索关键词 | indigo 浅色 pill 标签 |
| 搜索时间 | 相对时间 + 时钟图标,hover 显示完整时间戳 |
| IP 地址 | 等宽 code 样式 |
| 归属地 | 国家 + 省份 + 城市,琥珀色渐变标签 + 定位图标 |
| 浏览器 / 系统 | 彩色徽章,Chrome 蓝、Firefox 橙、Safari 蓝、Edge 绿、Opera 红等 |
| 结果数 | 0 为红色 pill,非 0 为绿色 pill |
筛选范围覆盖关键词、IP、国家、省份、城市五个字段,输入任意片段即可定位。
5. 搜索结果自定义 HTML 注入
这是 v1.1.0 引入的核心运营功能,在 搜索分析 → 设置 中配置:
- 启用开关:默认关闭。
- 结果数量阈值:当
found_posts <= 阈值时触发注入。设为0表示仅在完全无结果时显示;设为3则结果少于等于 3 条时也会显示。 - 自定义 HTML 内容:支持任意 HTML 标签,输出时包裹在
<div class="wpsa-custom-html">中,便于主题自定义样式。
注入采用三重钩子保障,兼容各种主题写法:
loop_end—— 有结果时在循环结束后输出;loop_no_results—— 无结果时输出(WordPress 6.2+);wp_footer—— 兜底输出,确保前两个钩子都未触发时内容仍能显示。
内部通过 $_html_injected 标志位保证同一次请求只输出一次,不会重复。
6. IP 归属地识别
- 通过
ip-api.com免费接口查询,请求参数已指定lang=zh-CN,返回中文地名。 - 结果写入
transient缓存,有效期 7 天,同一 IP 不重复请求。 - 私有/保留地址(内网 IP、127.0.0.1 等)直接标记为「本地网络」,不发起外部请求。
- 支持在设置页一键关闭;关闭后不再查询新 IP,已有数据保留。
- IP 获取顺序为
HTTP_CLIENT_IP→HTTP_X_FORWARDED_FOR(取最左侧原始客户端)→REMOTE_ADDR,并用filter_var做合法性校验。
7. 数据管理工具
- 导出 CSV:一键导出全部关键词统计(关键词、搜索次数、平均结果数、最后搜索时间)。文件带 UTF-8 BOM,Excel 打开不乱码,文件名自动附加日期。
- 清理数据:可自定义天数(如 90 天)删除旧记录,主表与日汇总表同步清理;输入
0则TRUNCATE两张表清空全部数据。操作前有 JS 二次确认。
8. 仪表盘小工具与更新日志
- 后台仪表盘小工具:在 WordPress 首页概览「总搜索 / 唯一词 / 今日」三项核心指标,并提供「查看完整报告 →」跳转链接。
- 更新日志页面:
搜索分析 → 更新日志,内置从 1.0.1 到 1.4.0 的完整版本记录,升级后无需查文档即可知道改了什么。
三、后台菜单与配置项
1. 菜单结构
激活后,后台左侧出现顶级菜单「搜索分析」(dashicons-search 图标,位置 30),包含 5 个子页面:
| 子页面 | slug | 说明 |
|---|---|---|
| 仪表盘 | wpsa-dashboard |
核心指标卡片 + 趋势图 + 快捷入口 |
| 热门搜索 | wpsa-popular |
关键词排行榜(Top 100) |
| 最新搜索 | wpsa-latest-searches |
最近 50 条明细记录 |
| 设置 | wpsa-settings |
自定义 HTML、IP 归属地、数据清理、CSV 导出 |
| 更新日志 | wpsa-changelog |
版本变更记录 |
全部页面均要求 manage_options 权限。
2. 配置项一览
所有设置存储在单个 option wpsa_settings(数组形式):
| 配置键 | 类型 | 默认值 | 说明 |
|---|---|---|---|
enable_custom_html |
int (0/1) | 0 |
是否启用搜索结果自定义内容注入 |
result_threshold |
int | 0 |
结果数 ≤ 该值时注入,0 = 仅无结果时 |
custom_html |
string | '' |
注入的 HTML 内容 |
enable_ip_geolocation |
int (0/1) | 1 |
是否启用 IP 归属地查询 |
另有独立 option wpsa_version 记录当前已安装版本号,用于升级时触发数据库迁移。
四、技术架构概览
1. 文件目录结构
wp-search-analytics/
├── wp-search-analytics.php # 主插件文件(常量、激活钩子、类加载、版本迁移)
├── uninstall.php # 卸载时删表 + 清理 option 与 transient
├── readme.txt # WordPress 标准 readme
├── includes/
│ ├── class-database.php # 数据库操作(建表、迁移、写入、统计查询、清理、导出)
│ ├── class-search-tracker.php # 搜索追踪 + IP 归属地 + 自定义 HTML 注入
│ ├── class-admin.php # 菜单、资源加载、页面渲染、设置/清理/导出处理
│ └── class-ajax-handler.php # AJAX 接口(趋势、热门词、最新记录)
├── templates/
│ ├── admin-page.php # 仪表盘模板
│ ├── popular-searches.php # 热门搜索词页面模板(服务端渲染)
│ └── latest-searches.php # 最新搜索记录页面模板(服务端渲染)
└── assets/
├── css/
│ └── admin.css # 后台样式(约 890 行,CSS 变量配色体系)
└── js/
└── admin.js # 后台脚本(Chart.js 图表 + 两个页面的筛选/刷新)
可选:将 chart.min.js 放入 assets/js/ 目录,插件会自动优先加载本地版本,不再请求 CDN。
2. 核心类设计
| 类名 | 职责 | 关键方法 |
|---|---|---|
WPSA_Database |
数据库操作 | create_tables()、maybe_migrate()、table_exists()、insert_search()、get_total_searches()、get_unique_terms_count()、get_today_searches()、get_today_unique_ips()、get_today_no_result_searches()、get_trend_data()、get_popular_terms()、get_latest_searches()、clean_old_data()、export_all_data() |
WPSA_Search_Tracker |
搜索追踪与前台注入 | track_on_wp()、track_ajax_search()、get_user_ip()、get_ip_location()、maybe_inject_custom_html()、inject_custom_html()、inject_custom_html_footer() |
WPSA_Admin |
后台界面与工具 | add_admin_menu()、enqueue_assets()、add_dashboard_widget()、render_dashboard()、render_popular()、render_latest_searches()、render_settings()、render_changelog()、handle_save_settings()、handle_clean_old_data()、handle_export_csv() |
WPSA_Ajax_Handler |
AJAX 接口 | get_trend_data()、get_popular_terms()、get_latest_searches() |
3. 数据库设计
采用两张表,以平衡实时写入和查询性能。
主表 wp_search_analytics
存储每一条搜索记录,用于明细查询和统计。
| 字段 | 类型 | 说明 |
|---|---|---|
id |
BIGINT | 自增主键 |
search_term |
VARCHAR(255) | 用户输入的关键词(超长自动截断) |
search_term_hash |
VARCHAR(64) | 关键词 SHA-256 哈希,用于去重统计 |
result_count |
INT | 搜索结果数量(0 表示无结果) |
user_id |
BIGINT | 用户 ID(0 为访客) |
user_ip |
VARCHAR(45) | 用户 IP,兼容 IPv6 |
ip_country |
VARCHAR(100) | v1.1.0 新增 国家 |
ip_region |
VARCHAR(100) | v1.1.0 新增 省/州 |
ip_city |
VARCHAR(100) | v1.1.0 新增 城市 |
user_agent |
TEXT | 浏览器 UA |
referer |
VARCHAR(500) | 来源页面 |
search_date |
DATETIME | 搜索时间(WordPress 时区) |
索引:search_term_hash、search_date、result_count。
汇总表 wp_search_analytics_daily
按「关键词 + 日期」聚合。
| 字段 | 类型 | 说明 |
|---|---|---|
id |
BIGINT | 自增主键 |
search_term |
VARCHAR(255) | 关键词原文 |
search_term_hash |
VARCHAR(64) | 哈希 |
search_date |
DATE | 统计日期 |
total_searches |
INT | 当日搜索次数 |
total_results |
INT | 当日结果总数(用于算平均) |
last_search_time |
DATETIME | 当日最后一次搜索时间 |
唯一索引:(search_term_hash, search_date)。写入采用 INSERT ... ON DUPLICATE KEY UPDATE 原子操作,高并发下不会出现竞态导致的计数丢失。
数据库迁移
dbDelta() 在部分环境下不会为已存在的表补充新列,因此 v1.3.1 起增加了 maybe_migrate():通过 DESCRIBE 读取现有列,逐一比对 ip_country、ip_region、ip_city,缺失则 ALTER TABLE ADD COLUMN。
迁移触发时机有两处:插件激活时,以及每次 plugins_loaded 时对比 wpsa_version 与 WPSA_VERSION,版本落后即自动执行。也就是说,通过 FTP 直接覆盖文件升级也能正确迁移,无需重新激活插件。
4. 关键钩子与流程
搜索追踪
- 原生搜索:监听
wp钩子,判断is_search() && ! is_admin(),取get_search_query( false )与$wp_query->found_posts,随后采集 IP、归属地、UA、referer 一并写库。 - AJAX 搜索:主题若使用 AJAX 搜索,可调用
wpsa_track_ajax_search接口(同时注册了wp_ajax_与wp_ajax_nopriv_),POST 传search_term、result_count、nonce。
前台 AJAX 上报示例:
jQuery.post( ajaxurl, {
action: 'wpsa_track_ajax_search',
search_term: '关键词',
result_count: 12,
nonce: wpsa_nonce // 由 wp_create_nonce('wpsa_nonce') 生成
} );
注意:前台页面需自行用 wp_localize_script() 输出 wpsa_nonce,插件本身只在后台注入 wpsa_ajax 对象。
管理界面数据加载
v1.3.2 起改为 PHP 服务端渲染优先:热门搜索、最新搜索两个页面在 PHP 渲染阶段就把数据写进表格,页面加载完即可见数据,不再出现 AJAX 失败导致的“正在加载…”卡死。AJAX 仅用于后续的筛选与刷新。
模板底部还内嵌了一段回退脚本:
<script type="text/javascript">
if ( typeof wpsa_ajax === 'undefined' ) {
var wpsa_ajax = {
ajax_url: '<?php echo admin_url( 'admin-ajax.php' ); ?>',
nonce: '<?php echo wp_create_nonce( 'wpsa_nonce' ); ?>'
};
}
</script>
用于兜底 wp_localize_script() 在某些环境下失效的情况。admin.js 开头也会检查 wpsa_ajax 是否存在,不存在则打印警告并安全退出,不会抛异常。
AJAX 接口一览
| action | 权限 | 参数 | 说明 |
|---|---|---|---|
wpsa_get_trend_data |
manage_options |
days(7/30/90/365)、nonce |
趋势数据 |
wpsa_get_popular_terms |
manage_options |
limit、search、nonce |
热门关键词 |
wpsa_get_latest_searches |
manage_options |
limit(1-100)、search、nonce |
最新记录 |
wpsa_track_ajax_search |
公开(需 nonce) | search_term、result_count、nonce |
前台搜索上报 |
表单类操作走 admin-post.php:wpsa_save_settings、wpsa_clean_old_data、wpsa_export_csv,各自使用独立 nonce(wpsa_settings_nonce、wpsa_clean_nonce、wpsa_export_nonce)。
5. 资源加载策略
这一块在 v1.3.0 / v1.3.1 连续修过两个坑,值得单独说明:
- 按页面加载:只在
wpsa-*五个页面和 WordPress 首页仪表盘(index.php)加载 CSS/JS,不污染其他后台页面。 - 通过
$_GET['page']判断而非$hook:因为菜单标题是中文,$hook会带上编码后的乱码字符串,早期版本据此判断导致子页面样式完全不加载。 - Chart.js 按需加载:仅仪表盘页面加载 Chart.js。其他页面的
admin.js只依赖 jQuery——早期把 Chart.js 写成硬依赖,CDN 一旦被墙,热门搜索/最新搜索页面的 JS 直接不执行。 - 本地优先:若存在
assets/js/chart.min.js则加载本地文件,否则回退到cdn.jsdelivr.net。
6. 安全与性能
- 权限控制:所有后台功能与管理类 AJAX 均校验
manage_options。 - Nonce 校验:所有 AJAX 与表单提交均带 nonce,防 CSRF。
- SQL 注入防护:全部动态查询使用
$wpdb->prepare(),LIKE 查询经$wpdb->esc_like()转义。 - 输出转义:模板中用户数据统一
esc_html()/esc_attr()处理。 - 表存在性检查:所有统计方法先调
table_exists(),表不存在返回 0 或空数组,避免建表失败时后台白屏报错。 - 哈希索引:以
search_term_hash做去重依据,规避长文本字段索引的性能问题。 - 归属地缓存:
transient缓存 7 天,同一 IP 只查一次外部接口。 - 时区统一:所有时间写入与比较均使用
current_time(),跟随 WordPress 后台设定的时区,不受服务器时区影响。
7. 兼容性与依赖
- WordPress:5.0 及以上(
loop_no_results钩子需 6.2+,无该钩子时由wp_footer兜底),已测试至 6.5。 - PHP:7.4 及以上(代码使用了
??运算符)。 - JavaScript:Chart.js v4.4.0(本地或 CDN)+ jQuery(WordPress 内置)。
- 数据库:MySQL 5.7+ / MariaDB 10.2+,需支持
INSERT ... ON DUPLICATE KEY UPDATE。 - 界面语言:后台文案为简体中文,已包裹
__()/_e(),Text Domain 为wp-search-analytics。
五、数据流程图

六、安装、升级与使用
1. 全新安装
- 上传:后台「插件 → 安装插件 → 上传插件」选择 zip 包,或通过 FTP 将
wp-search-analytics文件夹上传至/wp-content/plugins/。 - 激活:激活时自动建表并写入默认设置,无需手动操作。
- 验证:在前台随便搜索一个词,然后进入「搜索分析 → 最新搜索」,应能看到刚才那条记录。
2. 从旧版本升级
直接覆盖文件即可。plugins_loaded 时会比对版本号,自动执行建表与列迁移。从 1.0.x / 1.1.x 升级的用户请务必刷新一次后台,让 ip_country 等新列补齐,否则最新搜索页的归属地列会一直为空。
3. 日常使用建议
- 看内容缺口:优先关注「今日无结果搜索」和热门搜索里状态为“无结果”的关键词——这些是用户想要但你没有的内容,是最直接的选题来源。
- 配自定义 HTML:把无结果页变成引导页。示例:
<div style="padding:20px;background:#f8fafc;border-radius:8px;margin-top:20px;">
<h3>没找到想要的内容?</h3>
<p>试试这些热门文章:</p>
<ul>
<li><a href="/archives/">全部文章归档</a></li>
<li><a href="/categories/">按分类浏览</a></li>
</ul>
<p>或者 <a href="/contact/">直接联系我们</a>,告诉我们你想看什么。</p>
</div>
保存后在前台搜索一个不存在的词验证效果。
- 定期维护:建议每季度在设置页清理一次 90 天前的旧数据;清理前可先导出 CSV 存档。
- CSV 用法:导出的文件带 BOM,双击直接用 Excel 打开即可,可用于制作月度搜索报表。
七、注意事项与已知限制
这些是实际使用中容易踩的点,提前说清楚:
- 搜索分页会重复计数。追踪挂在
wp钩子上,用户翻到搜索结果第 2 页会再记一条。如果你的站点搜索结果经常分页,总搜索次数会略高于真实搜索行为数。 - 管理员和爬虫的搜索也会被记录。插件不区分角色和 UA,自己测试搜索同样入库。介意的话可以在清理时按天数处理,或后续自行加过滤。
- IP 归属地查询是同步阻塞的。首次遇到新 IP 时会发起一次 HTTP 请求(超时 3 秒),极端情况下会让搜索页响应变慢。命中缓存后无此开销。对速度敏感的站点可在设置中关闭该功能。
- ip-api.com 免费版有频率限制(约 45 次/分钟)且为 HTTP 明文接口。高流量站点建议关闭,或自行替换为付费/自建服务。
- 自定义 HTML 不做过滤,会原样输出。这是刻意设计(否则
<script>、内联样式都会被剥掉),但意味着只应由可信管理员填写。多作者站点请注意manage_options权限的分配。 - Chart.js 默认走 CDN。插件包内不含
chart.min.js,如果cdn.jsdelivr.net访问不畅,仪表盘趋势图会空白(其他页面不受影响,因为已解除硬依赖)。解决办法:下载 Chart.js v4.4.0 放到assets/js/chart.min.js,插件会自动优先使用本地文件。 - 日汇总表目前只写不读。趋势图和热门词排行仍然直接查询主表。汇总表数据是完整且准确的,为后续大数据量优化预留——数据量超过百万级时改查汇总表即可获得明显提速。
- 卸载会删除全部数据。
uninstall.php会 DROP 两张表、删除wpsa_version与wpsa_settings,并清理所有wpsa_ip_前缀的 transient。仅“停用”不会删数据,“删除”才会。重要数据请先导出。
八、与旧版文章(v1.0.1)的差异对照
如果你看过本文最初的版本,以下是这段时间的实际变化:
| 项目 | 旧文所述(v1.0.1) | 当前实际(v1.4.0) |
|---|---|---|
| 版本号 | 1.0.1 | 1.4.0 |
| 后台菜单 | 仅仪表盘 | 仪表盘 / 热门搜索 / 最新搜索 / 设置 / 更新日志 五个页面 |
| 配置项 | “无需配置,开箱即用” | 新增设置页,含 4 项配置(wpsa_settings) |
| 主表字段 | 9 个字段 | 新增 ip_country、ip_region、ip_city 三列 |
| 数据清理 | “汇总表暂不清理,未来可扩展” | 已实现主表与汇总表同步清理,并支持传 0 清空全部 |
| 明细记录 | 无 | 最新搜索页,50 条明细含 IP、归属地、浏览器、系统 |
| 运营干预 | 无 | 搜索结果自定义 HTML 注入(三重钩子) |
| 统计维度 | 3 项 | 新增今日独立 IP、今日无结果搜索 |
| 数据加载 | 全部 AJAX 异步 | 改为 PHP 服务端渲染优先,AJAX 仅负责筛选与刷新 |
| Chart.js | 全局依赖 | 仅仪表盘加载,本地文件优先、CDN 回退 |
| 数据库升级 | 依赖 dbDelta |
新增 maybe_migrate() 列级迁移 + 版本号自动检测 |
| 写入并发 | 普通更新 | 日汇总改为 INSERT ... ON DUPLICATE KEY UPDATE 原子操作 |
| 时区 | 未处理 | 统一使用 current_time(),跟随 WP 设置 |
| 卸载清理 | 仅删表 | 删表 + 删 option + 清理 IP 缓存 transient |
| UI | 基础 WP 后台样式 | 渐变 banner、玻璃质感卡片、彩色徽章、动画进度条,CSS 变量配色体系 |
九、后续规划
- 汇总表投入查询:数据量大时切换趋势图与排行榜的数据源,进一步降低查询开销。
- 异步写入:将追踪写入改为
wp_schedule_single_event,彻底消除对前台响应时间的影响。 - 扩展钩子:在
track_on_wp()中加入do_action,方便第三方插件挂接自定义逻辑。 - 隐私增强:增加 IP 匿名化选项(如只保留前三段),满足 GDPR 场景。
- 角色/爬虫过滤:可配置是否记录登录用户、指定角色或已知爬虫 UA 的搜索。
- 本地化 IP 库:内置离线 IP 库选项,摆脱对外部接口的依赖。
十、总结
WP Search Analytics 从最初的“记录 + 图表”工具,逐步演进为一套完整的站内搜索运营方案:看得见数据(明细、归属地、设备)、看得懂问题(无结果搜索、内容缺口)、能立刻干预(自定义 HTML 注入)。
v1.3.x 的几次修复解决了数据不显示这类致命问题,v1.4.0 则把后台界面推到了可以拿出手的水准。对个人博客来说它足够轻;对企业站点来说,哈希索引、原子写入、日汇总表这些设计也留足了扩容余地。
如果您有任何定制需求或建议,欢迎与我们联系,我们将持续迭代优化。