本文约 5,442 字,预计阅读 14 分钟。文中命令与配置均经过实测,可直接参考执行。
引言:RSS 不只是”订阅”,还是内容分发通道
很多站长觉得 RSS 已经过时。实际上它仍然在三个场景里很关键:
- 内容聚合平台(Feedly、Inoreader、各类 RSS 阅读器)的用户靠它订阅;
- 自动化分发:把 Feed 接到公众号、邮件列表、社交媒体自动推送;
- 被其他站点聚合:这是被动获得外链和内容曝光的方式(当然也有被无授权采集的风险)。
WordPress 默认就提供了完整的 Feed 能力,只是默认配置未必合适。
原理分析:四类默认 Feed 与它们的地址
| Feed 类型 | 地址 | 内容 |
|---|---|---|
| 站点文章 Feed | /feed/ |
最新文章 |
| 评论 Feed | /comments/feed/ |
最新评论 |
| 单篇文章评论 Feed | /2026/01/post/feed/ |
该文章的评论 |
| 分类/标签 Feed | /category/seo/feed/、/tag/cache/feed/ |
该分类下的文章 |
| 自定义文章类型 Feed | /case/feed/(需 has_archive) |
CPT 文章 |
| 搜索结果 Feed | /?s=关键词&feed=rss2 |
搜索结果 |
技术实现上,Feed 走的是 feed 重写规则 + do_feed_rss2(),输出的是标准 RSS 2.0 XML。核心模板函数在 wp-includes/feed-rss2.php。
关键设置:设置 → 阅读 → “Syndication feeds show the most recent”(Feed 显示最新多少篇,默认 10)和”For each article in a feed, show”(全文 or 摘要)。
保姆级实操
一、选择”全文”还是”摘要”
这是一个真实的取舍:
- 摘要(Summary):只输出
the_excerpt_rss(),能防止内容被无授权采集,但订阅体验差,用户要点进来看; - 全文(Full text):订阅体验好,Feedly 里能直接读完,容易被整篇采集。
务实建议:
- 内容站/博客:选全文。愿意用 RSS 读你的人是高价值用户,采集的损失远小于订阅的收益;
- 商业站/原创深度内容:选摘要,或者在全文末尾自动加一段带原文链接的声明(既是版权提示又是反向内链)。
给 RSS 正文末尾自动加版权+原文链接(选全文时的标配):
add_filter( 'the_content_feed', function( $content ) {
if ( is_feed() ) {
$content .= sprintf(
'<p><a href="%s">本文首发于 %s,欢迎订阅 <a href="%s">RSS</a>。</p>',
esc_url( get_permalink() ),
esc_html( get_bloginfo( 'name' ) ),
esc_url( get_feed_link() )
);
}
return $content;
});
二、给 RSS 加特色图片(默认没有)
WordPress 默认 RSS 不输出特色图,这对 Feedly、邮件推送很不利:
add_action( 'rss2_item', function() {
if ( has_post_thumbnail() ) {
$thumb_id = get_post_thumbnail_id();
$url = wp_get_attachment_image_url( $thumb_id, 'medium' );
$mime = get_post_mime_type( $thumb_id );
$size = filesize( get_attached_file( $thumb_id ) );
printf(
'<media:content url="%s" medium="image" type="%s"><media:title>%s</media:title></media:content>' . "\n",
esc_url( $url ),
esc_attr( $mime ),
esc_html( get_the_title() )
);
printf( '<enclosure url="%s" length="%d" type="%s" />' . "\n", esc_url( $url ), (int) $size, esc_attr( $mime ) );
}
});
三、RSS 里输出自定义字段
add_action( 'rss2_item', function() {
$subtitle = get_post_meta( get_the_ID(), 'subtitle', true );
if ( $subtitle ) {
printf( '<subtitle>%s</subtitle>' . "\n", esc_html( $subtitle ) );
}
});
自定义 XML 命名空间要声明:
add_action( 'rss2_ns', function() {
echo 'xmlns:media="http://search.yahoo.com/mrss/"' . "\n";
});
四、让 RSS 包含自定义文章类型
add_filter( 'request', function( $qv ) {
if ( isset( $qv['feed'] ) && ! isset( $qv['post_type'] ) ) {
$qv['post_type'] = array( 'post', 'case', 'product' );
}
return $qv;
});
五、排除某些分类不出现在 RSS
add_action( 'pre_get_posts', function( $q ) {
if ( ! is_admin() && $q->is_main_query() && $q->is_feed() ) {
$q->set( 'cat', '-42,-43' ); // 排除 ID 42 和 43 的分类
}
});
六、修改 Feed 的标题、描述和缓存时间
// 站点 Feed 标题
add_filter( 'bloginfo_rss', function( $output, $show ) {
if ( 'name' === $show ) {
return '迷忙飞 - WordPress 技术博客';
}
if ( 'description' === $show ) {
return '专注 WordPress 建站、SEO 与运维实战';
}
return $output;
}, 10, 2 );
// Feed 缓存时间(默认 43200 秒 = 12 小时,开发调试时改小)
add_filter( 'wp_feed_cache_transient_lifetime', function( $seconds ) {
return 1800; // 30 分钟
});
七、完全禁用 RSS(少数场景)
add_action( 'do_feed', 'mmf_disable_feed', 1 );
add_action( 'do_feed_rdf', 'mmf_disable_feed', 1 );
add_action( 'do_feed_rss', 'mmf_disable_feed', 1 );
add_action( 'do_feed_rss2', 'mmf_disable_feed', 1 );
add_action( 'do_feed_atom', 'mmf_disable_feed', 1 );
function mmf_disable_feed() {
wp_die( '<p>本站不提供 RSS 订阅。</p>', 'Feed 已禁用', array( 'response' => 404 ) );
}
// 移除 head 里的 feed 链接
remove_action( 'wp_head', 'feed_links', 2 );
remove_action( 'wp_head', 'feed_links_extra', 3 );
八、验证 Feed 是否合法
curl -s https://example.com/feed/ | head -40
curl -s https://example.com/feed/ | xmllint --noout - # 校验 XML 合法性
XML 报错通常是某个插件往输出里插了 HTML(比如调试信息、BOM、空白行)。
W3C Feed 校验:https://validator.w3.org/feed/
九、把 Feed 重定向到第三方(Feedburner 之类)
add_action( 'template_redirect', function() {
if ( is_feed() && ! preg_match( '/feedburner|feedvalidator/i', $_SERVER['HTTP_USER_AGENT'] ) ) {
wp_redirect( 'https://feeds.feedburner.com/yourid', 302 );
exit;
}
});
常见踩坑与失败案例
- 案例一:RSS 输出 XML 解析错误,原因是某个插件在
wp_head里输出了调试用的var_dump,或者在主题文件末尾有多余的换行/BOM。用xmllint能立刻定位到行号。 - Feed 内容不更新:WordPress 缓存了 Feed(
wp_feed_cache_transient_lifetime),或者页面缓存插件缓存了/feed/。要排除缓存:
– WP Rocket 默认不缓存 feed,宝塔静态缓存要手动排除;
– 或者调小wp_feed_cache_transient_lifetime。 - 案例二:某站 RSS 只输出 10 篇,但邮件推送服务希望拿 50 篇。改 设置 → 阅读 → “Syndication feeds show the most recent” 为 50。
- 特色图片在 Feedly 里不显示:需要
<enclosure>或<media:content>,WordPress 默认不输出,用上面代码补。 - RSS 被采集站整站抓取:可以在 Feed 里只输出摘要 + 原文链接,或者给采集 UA 返回 403。但不要因噎废食完全关闭 RSS。
the_excerpt_rss被主题覆盖:有些主题重写了摘要函数导致 RSS 输出为空。检查has_filter('the_excerpt_rss')。- HTTPS 站点 RSS 里是 HTTP 图片链接:跑一次
wp search-replace统一。
总结
WordPress 的 RSS 能力很完整(文章/评论/分类/CPT/搜索五类 Feed 默认都有),需要调整的通常只有四处:全文还是摘要(内容站选全文 + 自动加原文链接声明)、补特色图片(rss2_item 钩子里输出 <enclosure>)、包含 CPT(request 过滤器)、排除不需要的分类。调试用 xmllint 校验 XML 合法性,Feed 不更新优先查缓存(transient 和页面缓存两层)。RSS 不是过时的功能,它是成本最低的内容分发通道。
