WordPress SEO 优化记录:JSON-LD 修正与性能

前言:为什么要把优化过程写成一份记录

本站(511遇见)近期做了一轮较为完整的 SEO 与前端性能梳理,覆盖了元信息、结构化数据、样式加载、图片加载、主题函数文件清理等多个方面。过程中既有确实生效的改动,也有走了弯路、改出问题又回退的项目。

把全过程如实记录下来,一是给自己留一份可回查的维护档案,二是其中几个坑(尤其是脚本 defer 与 global-styles 注销)在网上很少见到完整说明,希望本文档能给使用 Aldehyde 主题或类似老站的朋友省下一些时间。

一、修订清单总览

序号 项目 处置 收益
1 首页 title / description / 首页简介 已改 小
2 语言标记统一为 zh-CN 已改 无(仅字面统一)
3 JSON-LD 结构化数据五项修正 已改 纠正一处真实错误
4 注销古腾堡(Gutenberg)区块样式 已改 全站每页省约 12KB
5 菜单两处硬伤修正 已改 语义正确性
6 首屏轮播图加载优化 已改 改善 LCP
7 functions.php 整理 + 修复 4 个 bug 已改 可维护性 + 修复无效代码
8 脚本 defer、移除 jquery-migrate 已放弃 —

二、元信息:title、description 与首页简介

1. title 调整

原首页标题把站点名放在最前面,例如"511遇见 - 易语言Lua……"。问题在于:几乎没有人会搜索"511遇见"这个品牌词,标题最靠前的位置是权重最高的位置,放一个没人搜的词属于浪费。

改为关键词前置:

  1. <title>易语言Lua教程_多线程自动化与WordPress建站 - 511遇见</title>

这里有个流传很广的说法是"标题里的下划线不利于分词"。这个说法只在英文语境下成立:英文靠空格和标点断词,red_shoes 会被当成一个连体词。中文分词走的是词典,不依赖标点,所以下划线、竖线在中文标题里差别可以忽略,不必为此反复修改。

2. description 调整

需要明确一点:meta description 不是排名因素,Google 已明确说明它不参与排序,只影响搜索结果页的点击率。原来的版本堆了 8 个主题方向、约 92 字,容易被截断。现调整为约 76 字,保留核心方向并加入"图色识别""源码下载"这类更具体的词。

3. 首页正文

首页正文从约 90 字扩充到约 190 字,仅增加一个段落,不新增任何板块模块。原因很简单:首页顶部已有 7 大分类导航、底部已有教程分类模块,再加一排"板块导语"等于把同一件事讲第三遍,视觉上只会更臃肿。

判断标准可以复用:如果一段内容的链接在导航或底部已经点得到,它就不该再出现在正文里。

三、语言标记统一

改动前源码里存在三个值:<html lang="zh-Hans">、og:locale 为 zh_CN、JSON-LD 的 inLanguage 为 zh-CN。

实际上后两者是同一个东西(大小写不敏感),真正不同的只有 zh-Hans(纯简体,不带地区)与 zh-CN(简体/中国)。两者都完全合法,搜索引擎对简体中文的识别结果一致,此项没有排名收益,只做字面统一。

主题使用 language_attributes() 输出该属性,且 AIOSEO 会通过同一钩子追加 prefix="og: ...",因此不能直接硬编码覆盖,要用过滤器只替换 lang 的值:

  1. /**
  2.  * 统一全站语言标记为 zh-CN
  3.  * 只替换 lang="..." 的值,dir、prefix 等属性原样保留
  4.  * 优先级 999 确保在 AIOSEO 之后执行
  5.  */
  6. add_filter( 'language_attributes', function ( $output ) {
  7. 	return preg_replace( '/lang="[^"]*"/', 'lang="zh-CN"', $output );
  8. }, 999 );

四、JSON-LD 结构化数据五项修正

1. 删除首页单条面包屑

首页的 BreadcrumbList 只有"首页"一项,而页面上并没有可见的面包屑导航。Google 要求结构化数据必须与页面可见内容一致,声明了一个页面上看不到的东西属于无效噪音,删掉最干净。

2. 清理 WebPage 对面包屑的引用

删除 BreadcrumbList 后,如果不同时清掉 WebPage 节点里的 "breadcrumb":{"@id":"...#breadcrumblist"},该引用会指向一个不存在的 @id,富媒体测试会报"引用未定义"。这两步必须配套。

3. 修正 WebSite.name(这是唯一一处真实错误)

AIOSEO 把首页的 SEO 标题当成了网站名,输出为:

  1. "name": "易语言Lua教程_多线程自动化与WordPress建站 - 511遇见"

而 WebSite.name 应该是网站名本身,即"511遇见"。这个字段会影响知识面板与 sitelinks 展示的站点名称,属于填错,不是"可以更好"。

4. 补 SearchAction

这是 sitelinks searchbox(搜索品牌词时结果下方的站内搜索框)的必要条件。注意 urlTemplate 里的 {search_term_string} 必须与 query-input 的 name 完全一致,改变量名会导致搜索框不生效。

5. 补 Organization 的 sameAs

填写社交账号地址,帮助搜索引擎建立实体关联。该字段只接受 URL,微信公众号 ID 这类非网址的值无法填入。

完整代码(仅首页生效):

  1. add_filter( 'aioseo_schema_output', function ( $graphs ) {
  2.  
  3. 	if ( ! is_front_page() ) {
  4. 		return $graphs;
  5. 	}
  6.  
  7. 	foreach ( $graphs as $key => $graph ) {
  8.  
  9. 		if ( empty( $graph['@type'] ) ) {
  10. 			continue;
  11. 		}
  12.  
  13. 		// 1) 删除首页单条面包屑
  14. 		if ( 'BreadcrumbList' === $graph['@type'] ) {
  15. 			unset( $graphs[ $key ] );
  16. 			continue;
  17. 		}
  18.  
  19. 		// 2) 清掉 WebPage 对已删面包屑的引用
  20. 		if ( 'WebPage' === $graph['@type'] ) {
  21. 			unset( $graphs[ $key ]['breadcrumb'] );
  22. 			continue;
  23. 		}
  24.  
  25. 		// 3) + 4) 修正 WebSite:改 name,补 SearchAction
  26. 		if ( 'WebSite' === $graph['@type'] ) {
  27. 			$graphs[ $key ]['name'] = '511遇见';
  28. 			$graphs[ $key ]['potentialAction'] = array(
  29. 				'@type'       => 'SearchAction',
  30. 				'target'      => array(
  31. 					'@type'       => 'EntryPoint',
  32. 					'urlTemplate' => home_url( '/?s={search_term_string}' ),
  33. 				),
  34. 				'query-input' => 'required name=search_term_string',
  35. 			);
  36. 		}
  37.  
  38. 		// 5) Organization 补 sameAs
  39. 		if ( 'Organization' === $graph['@type'] ) {
  40. 			$graphs[ $key ]['sameAs'] = array(
  41. 				'https://space.bilibili.com/508420984',
  42. 			);
  43. 			continue;
  44. 		}
  45. 	}
  46.  
  47. 	return array_values( $graphs );
  48.  
  49. }, 999 );

五、注销古腾堡区块样式(省 12KB)

什么是古腾堡

古腾堡(Gutenberg)是 WordPress 2018 年起主推的区块编辑器。为了渲染按钮、分栏、引用等区块,WP 会自动向每个页面输出一份约 12KB 的样式表。

如果站点的文章全部用经典编辑器或手写 HTML 编写,这份样式表就是纯空转。判断方法(phpMyAdmin 执行):

  1. SELECT COUNT(*) FROM wp_posts
  2. WHERE post_status='publish'
  3. AND post_content LIKE '%<!-- wp:%';

本站返回 0,说明全站无区块内容,可以安全注销。

正确的注销方式

  1. add_action( 'wp_enqueue_scripts', function () {
  2.  
  3. 	if ( is_admin() ) {
  4. 		return;
  5. 	}
  6.  
  7. 	// A. 常规移除
  8. 	wp_dequeue_style( 'wp-block-library' );
  9. 	wp_dequeue_style( 'classic-theme-styles' );
  10. 	wp_dequeue_style( 'global-styles' );
  11.  
  12. 	// B. 摘掉核心挂载(含 wp_footer 上那个)
  13. 	remove_action( 'wp_enqueue_scripts', 'wp_enqueue_global_styles' );
  14. 	remove_action( 'wp_footer', 'wp_enqueue_global_styles', 1 );
  15.  
  16. 	// C. 兜底
  17. 	if ( isset( wp_styles()->registered['global-styles'] ) ) {
  18. 		wp_styles()->add_data( 'global-styles', 'after', '' );
  19. 	}
  20.  
  21. }, 999 );

重要提醒:本站 dashicons.min.css 不能注销,菜单图标插件 menu-icons 依赖它,动了会导致导航图标消失。如果日后改用区块编辑器写文章,必须删除本段代码,否则按钮、分栏、引用块会丢失样式。

六、菜单与内链的两处硬伤

1. "关于遇见"指向归档页

菜单文字是"关于遇见",点进去却是 WordPress 的按月归档列表,访客预期与实际严重不符。处理方式有两个:改菜单文字为"文章归档"(零风险),或真的新建一个关于我们页面。本站选择了前者,因为后者属于内容工作。

2. Ngnix 拼写错误

正确写法是 Nginx。此处只改菜单显示的文字,不要改分类别名(slug)。本站该分类地址为 /front-end/ans,slug 不美观但已被收录,一旦修改会产生 404,需要额外配置 301 重定向。搜索引擎不靠 slug 判断内容,为此改 slug 属于负收益。

七、首屏图片加载与 LCP

LCP(Largest Contentful Paint)指"最大那块内容出现在屏幕上的时间",是 Core Web Vitals 三项指标之一,及格线为 2.5 秒。本站首页最大的内容就是轮播第一张图。

本站轮播共 10 张图,处理方式为:首图立即加载并高优先级,其余 9 张滚动到才加载。

  1. <!-- 首图 -->
    
  2. <img src="/pagephoto/banner/dmyj.jpg" alt="易语言图色自动化教程"
    
  3.      width="960" height="595" loading="eager" fetchpriority="high">
    
  4.  
  5. <!-- 其余 9 张 -->
    
  6. <img src="..." loading="lazy" decoding="async">

所有图片都写了 width 和 height。这一步非常关键,它让浏览器在图片下载完成前就能算出占位比例,避免图片突然加载时把下方内容挤走——这正是 CLS(布局偏移)的主要来源。

关于 preload:本站未采用

常见的优化建议是在 <head> 里加一行 <link rel="preload" as="image">,让浏览器更早发现这张图。但本站已启用 WebP 转换,服务器上实际存在 .jpg 与 .jpg.webp 两种返回情况。

此时 preload 写死 .jpg 就可能出问题:浏览器预加载了一个地址,<img> 实际请求的却是另一个,同一张图下载两遍,非但不快反而多耗带宽。因此本站放弃此项,只保留 loading="eager" 与 fetchpriority="high"——这两个属性跟随标签本身,不管最终加载哪种格式都自动正确。

八、functions.php 整理与 4 个 bug 修复

主题 functions.php 经过多年累积已超过 1000 行,格式与注释混乱。本次做了分区整理(共 27 个区块)与注释补齐,不改动任何一行代码的执行逻辑,并修复了 4 个实际存在的问题。

bug 1:禁用修订版本的写法从未生效

  1. // 原写法(无效)
  2. remove_action( 'pre_post_update' , 'wp_save_post_revision' );
  3.  
  4. // 修复后(生效)
  5. add_filter( 'wp_revisions_to_keep', '__return_zero' );

wp_save_post_revision 并未挂在 pre_post_update 上,那行代码从未起过作用,数据库里一直在堆积修订记录。改用官方过滤器后真正生效。本站累计修订记录为 258 条,量很小,历史数据未做清理。

bug 2:移除资源版本号属于负收益

原文件里有移除 CSS / JS 链接 ?ver= 的代码。移除版本号唯一的好处是让 CDN 缓存更久,本站未使用 CDN,这个好处不存在;副作用却是实打实的:去掉版本号后浏览器无法区分新旧文件,改了 main.css 之后老访客仍加载缓存里的旧版,表现为"我明明改了,前台就是不变",排查极其费时。已停用,原代码保留为注释。

bug 3:标签云取色写法错误

  1. // 原写法
  2. $color = $colors[ dechex( rand( 0, 7 ) ) ];
  3.  
  4. // 修复后
  5. $color = $colors[ rand( 0, count( $colors ) - 1 ) ];

dechex() 返回的是字符串,拿字符串当数组下标是错误写法,只是 PHP 恰好会把纯数字字符串转成整数才没报错。一旦配色数量超过 10 个,dechex 会返回字母,立刻取不到值。

bug 4:取图函数未判空

  1. // 修复:在循环外调用时 $post 为 null,PHP 8 下会抛 Warning
  2. if ( empty( $post->post_content ) ) {
  3. 	return '';
  4. }

九、踩坑:为什么放弃了脚本 defer

这是本次唯一一次改出问题又回退的操作,值得完整记录。

最初为了减少白屏时间,给 <head> 里的 jQuery 与 custom.js 加了 defer。改完立刻出现三条报错:

  1. Bootstrap's JavaScript requires jQuery          (external.js)
  2. jQuery(...).slicknav is not a function          (custom.js)
  3. e.indexOf is not a function                     (jquery.min.js / custom.js)

原因:WordPress 的依赖系统只保证输出顺序,不保证执行方式。本站页脚还挂着 bootstrap、slicknav 等同步脚本,它们没有被加 defer,于是执行顺序变成:

脚本 状态 执行时机
jquery.min.js defer 等 HTML 解析完
custom.js defer 同上,排在 jQuery 后
bootstrap / slicknav(页脚) 同步 解析到就立刻执行 ← 此时 jQuery 还没加载

结果就是 jQuery 被推迟了,但用它的脚本没推迟,后者先跑、直接报错。其中 slicknav 是手机端的汉堡菜单,它坏了意味着手机访问时导航可能点不开——这比省下的零点几秒重要得多。

同理,移除 jquery-migrate 也一并放弃。它只省约 10KB,而对一个拥有 10 张轮播大图的页面来说,10KB 可以忽略。

十、最终效果

使用浏览器内置的 Lighthouse(移动端模拟)实测:

指标 结果 及格线 判定
Performance 总分 94 90–100 为优秀 优秀
CLS(布局偏移) 0 < 0.1 满分
TBT(主线程阻塞) 0 ms < 200 ms 满分
LCP(最大内容绘制) 2.7 s < 2.5 s 略超
FCP(首次内容绘制) 2.3 s < 1.8 s 参考项

CLS 与 TBT 两项满分,其中 CLS 为 0 正是得益于所有图片都写了宽高属性。LCP 2.7 秒略微超标,需要说明的是:Lighthouse 默认会模拟 4G 网络与中端手机,属于限速环境,真实访客大概率跑在及格线内。该项的主要瓶颈是轮播的 10 张大图,要进一步优化得从压缩图片入手,不是再改几行代码能解决的。

另外确认了域名跳转为单跳 301:无论输入 http://511yj.com 还是 https://511yj.com,都一步直达 https://www.511yj.com,这是最优状态。

十一、关于 canonical 尾斜杠的说明

本站 canonical 与 og:url 均不带尾斜杠,而站内 logo、Organization.url 带斜杠。这类不一致会被搜索引擎归一化处理,不会产生重复内容问题,不需要专门处理。WordPress 后台"设置 → 常规"里的站点地址也无法通过加斜杠来统一(保存时会自动去除),因此保持现状即可。

十二、明确放弃的项目

为了便于日后回查,把评估后决定不做的项目一并列出:

项目 放弃原因
脚本 defer 会导致手机端菜单失效(已实测)
移除 jquery-migrate 仅省 10KB,风险大于收益
LCP 图片 preload WebP 环境下可能重复下载
WebPage 改为 CollectionPage Google 无对应富媒体结果,改了无可见变化
给列表加 ItemList 四个 Tab 中有三个默认隐藏,声明了看不见的内容反而违反一致性要求
改分类 slug、改文章 URL 会产生 404,风险远大于"可读性"收益
清理内联 CSS 核心自动内联是 WP 的既定优化行为,不是缺陷
防 iframe 改用 CSP frame-ancestors 无法通过 meta 标签设置;且 CSP 会误伤微信内置浏览器等合法场景,导致白屏
og:image:alt、插件指纹清理 收益可忽略

十三、小结

这一轮梳理下来,一个很实际的体会是:SEO 技术层的改动收益递减得非常快,而风险并不递减。

真正有确定收益的,集中在少数几项:修正填错的结构化数据字段、注销确实在空转的样式、修正菜单语义错误、给图片补齐宽高。这些做完之后,继续往下挖出来的项目,价值往往低于所花费的时间,甚至可能改出真问题(如本次的 defer)。

技术层做完后,影响更大的其实是另外两个层面:教程内容本身的质量与数量,以及外部链接与品牌。那不是改代码能解决的。优化做到一定程度就该停手,把时间花在写下一篇教程上。


发布日期:

所属分类: 网站运营 SEO 标签: