WordPress 站点优化实战:WebP、缓存与内部链接结构排查

前言:一次完整的站点优化,到底改了什么

很多人做站点优化,习惯一个一个插件地试:装个缓存插件、开个图片压缩、再改改标题标签。改完感觉"好像快了",但说不清到底哪一项起了作用,也说不清哪些改动其实互相打架。

这篇文章记录一次完整的优化过程,涉及四个方向:图片格式、缓存插件冲突、CSS 字号陷阱、内部链接结构。重点不在于"我改了什么",而在于每一步怎么判断、怎么验证——这些判断方法可以直接复用到你自己的站点上。

文中的域名、路径均已脱敏处理(统一为 www.example.com 和 static/),不影响理解。

一、WebP:两种方案,差别比想象中大

1.1 为什么要上 WebP

同样的图片,WebP 的体积优势非常明显:

原格式 转 WebP 后 典型场景
PNG 小 50%~70% logo、截图
JPG 小 25%~35% 文章配图、照片

图片通常占页面总重量的 60%~75%。图片小一半,页面加载时间大致也砍半。

1.2 方案 A:改 URL(插件常用做法)

缓存插件在生成 HTML 缓存时,直接把 <img src="photo.jpg"> 改写成 <img src="photo.jpg.webp">。

问题在于:它不检查这个 .webp 文件是否真的存在。

如果某张图转换失败(超时、损坏、新上传还没转),URL 照样被加上 .webp 后缀——结果就是这张图直接 404,永久裂图。

1.3 方案 B:内部重写(推荐)

Apache 的 .htaccess 可以在服务器内部完成替换,URL 一个字都不用改:

<IfModule mod_rewrite.c>
  RewriteEngine On

  # 只在浏览器声明支持 WebP 时处理
  RewriteCond %{HTTP_ACCEPT} image/webp

  # 关键:检查 .webp 文件是否真的存在
  RewriteCond %{REQUEST_FILENAME}.webp -f

  # 内部重写,浏览器地址栏不变
  RewriteRule ^(.+)\.(jpe?g|png)$ $1.$2.webp [T=image/webp,L]
</IfModule>

<IfModule mod_headers.c>
  # 同一 URL 有两种响应,必须声明按 Accept 区分缓存
  <FilesMatch "\.(jpe?g|png)$">
    Header append Vary Accept
  </FilesMatch>
</IfModule>

核心是这一行 RewriteCond %{REQUEST_FILENAME}.webp -f——文件不存在就自动跳过,回退原图,永远不会裂图。

1.4 两种方案对比

对比项 方案 A(改 URL) 方案 B(内部重写)
HTML 里的 URL 变成 .jpg.webp 始终 .jpg
文件不存在时 404 裂图 自动回退原图
覆盖范围 只改 HTML 里的 img 所有图片,含 CSS 背景图
已有文章 需重新生成 一个字不用改
将来想关掉 重新生成全站缓存 删条规则即可

对已有大量文章的站点,方案 B 的价值尤其明显——几千篇文章里的 img 标签一个都不用动。

二、排查实录:同一张图为什么时有时无

2.1 现象

配好之后发现一个奇怪现象:无痕模式下看是 photo.jpg,硬刷新后却变成 photo.jpg.webp。反复清缓存十几次,问题依旧。

2.2 第一步:先划清责任边界

这条铁律能省掉大量时间:

如果 HTML 里的 URL 出现了 .webp 后缀,那必然是"改 URL"方案在起作用;内部重写是服务器行为,URL 永远不会变。

看到 URL 变了,就不用再去查 .htaccess 了——方向直接锁定到缓存插件。

2.3 第二步:测试工具可能是干扰源

这是最容易踩的坑。用 curl 测试时,默认发出的 Accept 头不含 image/webp:

# 第一次测:看起来没问题
curl -s https://www.example.com/demo.html | grep photo
# 输出:src=".../photo.jpg"

# 加上浏览器的 Accept 头再测
curl -s -H "Accept: text/html,image/webp,*/*" \
  https://www.example.com/demo.html | grep photo
# 输出:src=".../photo.jpg.webp"

同一个地址,两次结果完全不同。测试工具本身的行为差异,会让你误判为"缓存没清干净"。

2.4 第三步:清缓存没用,是因为它本来就该生成两份

缓存插件开启 WebP 后,会生成两套 HTML 缓存:

cache/demo.html        ← 给不支持 WebP 的浏览器(URL 是 .jpg)
cache/demo-webp.html   ← 给支持 WebP 的浏览器(URL 是 .jpg.webp)

它靠请求的 Accept 头决定给哪一份。清一次缓存,它重新生成两份——清多少次都是两套。这不是"缓存脏了",是设计如此。

2.5 解决

在缓存插件的"缓存行为"设置里,找到 WebP 相关选项并取消勾选,然后清空一次缓存。(不同版本文案不同,常见的是"创建一个缓存版本以支持 WebP"。)

验证:两种 Accept 头请求,HTML 里的 URL 应该都变成 .jpg,同时服务器响应仍是 Content-Type: image/webp。

三、CSS 字号陷阱:一句 62.5% 让全站缩水

3.1 现象

首页主标题和简介段落特别小,比正文还小,怎么调都不对。

3.2 根因

主题样式表里有这么一句:

html {
    font-size: 62.5%;  /* = 10px,不是默认的 16px */
}

这是个老式 hack,目的是让 1em = 10px 方便计算。但它坑了 Bootstrap——Bootstrap 所有尺寸单位都是 rem,设计时假设 1rem = 16px。现在 1rem 只有 10px,于是:

元素 Bootstrap 原值 实际值
h1 2.5rem = 40px 25px
.lead 1.25rem = 20px 12.5px

.lead 本该是醒目的导语段落,结果只有 12.5px,比 16px 的正文还小。

3.3 解决:用 px 显式复位

/* 绕开 rem,用 px 显式指定 */
.home-h1 {
    font-size: 34px;
    line-height: 1.4;
    font-weight: 600;
}
.home-intro {
    font-size: 16px;   /* 覆盖被缩水的 .lead */
    line-height: 1.9;
    max-width: 920px;  /* 防止宽屏一行拉太长 */
}

@media (max-width: 768px) {
    .home-h1 { font-size: 24px; }
    .home-intro { font-size: 14px; }
}

为什么不直接改 html 的 62.5%?因为全站所有用 rem 的地方(栅格、间距、字号)会同时放大 60%,等于整站排版推倒重来。定点用 px 只影响目标元素,其他页面纹丝不动。

四、标题截断:PHP 按宽度,CSS 按像素

4.1 问题:截断了还留一大块空白

用 mb_strimwidth($title, 0, 38, '') 截断标题,结果末尾空出好几个字的距离。

原因在于它的计数规则是宽度单位,不是字符数:

中文/全角 = 2 个宽度单位
英文/数字 = 1 个宽度单位

所以同样设 38:

  • 纯中文标题 → 只显示 19 个字
  • 纯英文标题 → 显示 38 个字母
  • 中英混排 → 长度飘忽不定

中文标题按 2 倍计费,"买"到的字符数只有一半——这就是留白的真相,不是数字设小了。

4.2 解决:交给 CSS 按像素截断

PHP 是"猜"宽度,CSS 是"量"像素。浏览器按真实可用空间计算,标题会一直延伸,直到贴住日期才截断。

/* PHP 输出完整标题,不截断 */
<?php echo esc_html( get_the_title() ); ?>
/* CSS 负责截断 */
.post-list li {
    display: flex;
    align-items: baseline;
}
.post-list li a.title {
    flex: 1 1 auto;
    min-width: 0;              /* 关键:允许收缩 */
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}
.post-list li time {
    flex: 0 0 auto;
    margin-left: 8px;
}

效果对比:

PHP 截断:WordPress 站点 SEO 自查与权……      10/11   ← 提前截断留白
CSS 截断:WordPress 站点 SEO 自查与权重恢复…  10/11   ← 填满才截断

额外好处:Chrome / Edge / 手机表现一致,窗口缩放自动重算,天然适配移动端。

4.3 关于省略号

这里的 text-overflow: ellipsis 和 PHP 版的 '…' 参数不是一回事:

对比项 PHP 版省略号 CSS 版省略号
何时出现 到 38 宽度就截 真的装不下才出现
是否占预算 占 1 个宽度单位 不占
留白 中英混排常留一大块 填满才截断

CSS 版没有"预算"概念,排不满就一个点都不出现。保留它比硬切要好看得多。

五、内部链接结构:真正影响权重的部分

5.1 一个容易被忽略的事实

搜索引擎排名的是页面,不是站点。它不会想"这个站是主站所以排前面",只判断"这个 query 下哪个页面最该排第一"。

所以"主站权重输给子站"这个说法并不精确。真实发生的是:你的某个子站页面,在搜索结果里挤掉了主站的同类页面。

5.2 问题结构

假设主站有 1900 篇文章,子站不到 100 篇,而主站每个页面的导航栏里都有子站链接:

主站 1900 篇 ──每篇投一票──> 子站的少数几个页面

你在用 1900 篇文章,去养一个只有 100 篇的站。子站那一篇收到的内部链接支持,可能比主站任何一篇都高——所以它在具体 query 上赢了。

这跟搜索引擎"聪不聪明"无关,链接投票是所有搜索引擎的通用机制。

5.3 解决

  • 把子站链接从全站导航撤下,只保留首页一个入口——这一步收回 1900 票,是整套动作里最关键的一步
  • 子站的 header 和 footer 反向链回主站
  • 子站文章正文里,在相关内容处插入主站内链(正文语境内链的权重远高于导航和页脚)

5.4 关于 nofollow 的取舍

如果想保留用户通路但切断权重传递,给链接加 rel="nofollow" 即可——用户照常点击、蜘蛛照常抓取,只是不传递权重。

自家站点之间加 nofollow 听起来奇怪,但如果你的目标就是"不再给子站加权",这个做法完全合理。

六、结构化数据:别重复输出

常见错误:插件已经输出了结构化数据,又在主题 header 里手写一段。

结果是同一个页面出现两个 Organization、两个 WebSite。搜索引擎遇到同类实体会困惑:到底哪个是你?严重时两个都忽略,反而把插件那份正确的也带下水。

判断方法:

curl -s https://www.example.com/ | grep '"@type"'

看输出里有几个 Organization / WebSite。如果各有两个,删掉手工那段,统一交给插件。

用 wp_json_encode() 而不是手写 JSON 字符串,可以让 PHP 保证语法永远正确——手写时只要站名里出现引号或换行,整个 JSON 就废了,而且不报错,只是被搜索引擎静默忽略。

七、几个值得记下的排查工具

# 看响应头(验证 WebP、缓存头、X-Robots-Tag)
curl -s -D - -o nul -H "Referer: https://www.example.com/" \
  -H "Accept: image/webp,*/*" https://www.example.com/static/photo.jpg

# 模拟浏览器 Accept(避免测试工具本身造成误判)
curl -s -H "Accept: text/html,image/webp,*/*" https://www.example.com/demo.html

# 统计图片总体积(PowerShell)
$p = "D:\webroot\static"
$jpg = (Get-ChildItem $p -Recurse -Include *.jpg,*.png | Measure-Object -Sum Length).Sum
$webp = (Get-ChildItem $p -Recurse -Include *.webp | Measure-Object -Sum Length).Sum
"节省比例: {0:P1}" -f (1 - $webp/$jpg)

Windows 下注意:PowerShell 里的 curl 是 Invoke-WebRequest 的别名,参数完全不通用,要写成 curl.exe。

八、诚实地说:各项改动的价值排序

项目 价值
撤掉全站子站链接 ★★★★★ 决定性
canonical 各自自引用 ★★★★ 防重复内容
正文内链 ★★★ 长期有价值
子站反向链接 ★★ 聊胜于无
WebP ★ SEO 边际改善
结构化数据 ★ 不传递权重

关于 WebP 的 SEO 价值,说句实在话:它通过 Core Web Vitals 的 LCP 指标和百度的闪电算法起作用,但权重很低,大概在 5%~10% 的边际改善量级。

排名的决定性因素永远是:内容质量 + 外链权威 >>> 页面速度 >>> 是否用 WebP。

WebP 真正的价值在带宽成本和用户体验——尤其没用 CDN 的站点,省下的流量是实实在在的。排名提升是附带的,别指望靠它翻盘。

九、两条方法论

9.1 先划责任边界,再动手改

"URL 变了必然是改 URL 方案在起作用"——这类边界判断能一秒排除错误方向。每次排查前先问一句:这个现象的成因,可能落在哪几个模块里?

9.2 测试工具本身可能是干扰源

curl 默认不带 image/webp 的 Accept 头,导致你看到的"现象"和浏览器完全不同。当你发现"改了没效果"时,先怀疑测试方式,再怀疑改动本身。

结语

这一整套改下来,真正起决定作用的只有一件事:撤掉那个全站子站链接。其余都是顺手清理。

而 WebP 这套方案最值钱的地方在于——它用内部重写实现,几千篇文章的 img 标签一个字没改,且不依赖任何插件。CMS 换不换都在,哪天想关掉删条规则就行。

优化之后就是等。搜索引擎需要时间重新计算链接结构,通常两周左右能在站长平台看到索引量的变化。


发布日期:

所属分类: WordPress 主题 标签:  



下一篇:

没有了,已经是最新文章