友链的朋友圈 RSS的聚合页 (WordPress->PIX主题篇&本地解析版)
本文是《技术相关(共39篇)》目录的第 16 篇。阅读本文前,建议先阅读本文前3篇文章:
本文适用于友链网站内容频繁更新的情况
友链的朋友圈 RSS的聚合页 (WordPress->PIX主题篇&在线解析版)请参考如下文章:
之所以又出了一个本地解析版,是因为在线解析版始终未能解决两个问题:第一、我有个别友链网站,明明feed地址在浏览器里能够直接访问,并且能够正常显示rss内容,但就是解析不了,导致聚合页不能显示这些友链网站。第二、虽然代码采用了异步加载及缓存机制等优化措施,但每次在线解析时间长短都与友链网站的访问速度有关,如果网络不好甚至网站打不开,要么解析时间很长,要么聚合页内无法显示站点内容,不如把各站点的feed缓存到本地服务器,到时直接在本地解析。
20240115更新代码二,与代码一区别在于代码一是根据比较远程RSS的MD5和本地的MD5值是否一致来判断远程RSS是否更新,代码二是根据比较远程RSS的内容和本地的内容是否一致来判断远程RSS是否更新,更真实一些。
说一下大致逻辑:
现在的逻辑是获取后台所有友情链接网站feed地址后直接在线解析,修改后的逻辑是不再直接在线解析,而是第一次运行首先从wordpress后台检测友链网站的RSS地址是否填写,如果没填写为空则忽略该友链网站,如果已填写不为空,只访问这些RSS地址已经填写的友链网站的feed地址,然后查看feed地址页面的源代码,并各自计算出源代码的md5值,以友情链接网站域名.md5值.xml为文件名将各自的rss的源代码内容分别保存在当前主题目录中的rsscache文件夹下,然后在本地分别直接解析这些友情链接网站域名.md5值.xml,显示效果同现有代码不变。
rsscache文件夹下这些友情链接网站域名.md5值.xml的有效保存期为8个小时,8个小时内直接本地解析rsscache下的xml文件。8个小时后,服务器自动访问这些RSS地址已经填写的友链网站的feed地址并再次计算源代码的md5值进行比较,如果md5值变化则重新下载最新XML文件,并自动删除旧文件,如果md5值没有变化则无需下载。但是,如果8个小时之内我删除了rsscache下的所有文件,都将被视作第一次运行。
对于feed地址浏览器能够访问并且能够显示rss内容但是一直无法保存的友链网站,在rsscache文件夹下自动建立对应域名.md5值.xml文件,把这些无法保存RSS的友链网站,加入忽略域名里,即便是8小时后,只要rsscache文件夹下还存在该xml文件,就不会重新获取覆盖,只能手工修改。
[reply]
代码一:
<?php
/*
Template Name: 似水流年-RSS朋友圈
*/
date_default_timezone_set('Asia/Shanghai');
get_header();
require_once(ABSPATH . WPINC . '/class-simplepie.php');
// 主内容区域
echo '<div id="primary" class="content-area">';
echo '<main id="main" class="site-main" role="main">';
echo '<p style="color: red; font-size: 14px; margin-top: 10px; margin-bottom: 20px; text-align: center; display: flex; align-items: center; justify-content: center;">以下友情链接网站最新内容每8小时获取更新一次</p>';
// 获取并显示友情链接的最新文章
$all_articles = get_cached_friend_link_rss_data();
$articles_to_show = array_slice($all_articles, 0, 50);
foreach ($articles_to_show as $article) {
display_friend_link_rss($article);
}
// 侧边栏
get_sidebar();
echo '</main><!-- #main -->';
echo '</div><!-- #primary -->';
get_footer();
//rsscache目录下忽略域名即不自动获取覆盖域名
$ignored_domains = array("www.忽略域名1.com", "忽略域名2.cn");
// 获取并缓存友情链接的最新文章数据
function get_cached_friend_link_rss_data() {
global $ignored_domains;
$all_articles = array();
// 获取所有友情链接
$args = array(
'orderby' => 'name',
'category' => 0,
'order' => 'ASC',
'hide_invisible' => 1,
'categorize' => 0,
'title_li' => '',
'echo' => 0
);
$links = get_bookmarks($args);
// 遍历每个友情链接
foreach ($links as $link) {
if ($link->link_rss && !empty($link->link_rss)) {
$domain = parse_url($link->link_url, PHP_URL_HOST);
if (!$domain) {
continue;
}
$feed_url = $link->link_rss;
$domain = parse_url($link->link_url, PHP_URL_HOST);
$cache_file = get_stylesheet_directory() . '/rsscache/' . $domain . '.' . md5($feed_url) . '.xml';
if (is_array($ignored_domains) && in_array($domain, $ignored_domains)) {
continue; // 如果域名在忽略列表中,则跳过
}
// Delete old XML files with the same domain name
$old_cache_files = glob(get_stylesheet_directory() . '/rsscache/' . $domain . '.*.xml');
foreach ($old_cache_files as $old_file) {
// 获取旧文件的域名
$old_domain = pathinfo($old_file, PATHINFO_FILENAME);
// 检查旧文件的域名是否在忽略列表中
if (is_array($ignored_domains) && in_array($old_domain, $ignored_domains)) {
continue; // 如果域名在忽略列表中,则跳过删除
}
// 继续删除非忽略域名的旧文件
if ($old_file !== $cache_file) {
unlink($old_file);
}
}
if ((!file_exists($cache_file) || (is_array($ignored_domains) && in_array($domain, $ignored_domains))) || (time() - filemtime($cache_file) > 8 * HOUR_IN_SECONDS)) {
// 获取并保存最新的RSS内容,但只有在缓存文件不存在或域名在忽略列表中或已经过了8小时时才执行
$rss_content = get_rss_content($feed_url);
if ($rss_content) {
file_put_contents($cache_file, $rss_content);
}
}
$rss_items = get_rss_items($cache_file);
foreach ($rss_items as $item) {
$item_data = array(
'link_name' => $link->link_name,
'link_logo' => $link->link_image,
'link_url' => $link->link_url,
'item_title' => $item->get_title(),
'item_link' => $item->get_permalink(),
'item_date' => $item->get_date('Y-m-d H:i:s'),
'item_author' => $item->get_author()->get_name(),
'item_excerpt' => $item->get_description(),
'item_content' => $item->get_content()
);
$all_articles[] = $item_data;
}
}
}
// 根据更新时间降序排列所有文章数据
usort($all_articles, function ($a, $b) {
return strtotime($b['item_date']) - strtotime($a['item_date']);
});
return $all_articles;
}
// 获取并保存最新的RSS内容
function get_rss_content($feed_url) {
$response = wp_safe_remote_get($feed_url);
if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) {
return wp_remote_retrieve_body($response);
} else {
return '无法从提供RSS的URL获取RSS内容。';
}
}
// 使用SimplePie获取RSS项
function get_rss_items($cache_file) {
$rss = new SimplePie();
$rss->set_feed_url($cache_file);
$rss->init();
$rss->handle_content_type();
$rss->set_output_encoding('UTF-8'); // 设置输出编码
return $rss->get_items();
}
// 显示友情链接的RSS内容
function display_friend_link_rss($article) {
?>
<div class="friend-link-rss" style="border: 1px dashed #ccc; background-color: #f5f5f5; padding: 10px; margin-bottom: 20px; display: flex;">
<!-- 左边占1/5 -->
<div style="width: 20%; padding-right: 10px;">
<!-- 上部分显示站标logo,大小控制在60*60 -->
<div style="display: flex; align-items: center; justify-content: center; height: 50%;">
<img src="<?php echo $article['link_logo']; ?>" alt="<?php echo $article['link_name']; ?>" style="width: 60px; height: 60px; border-radius: 50%; box-shadow: 0 0 10px 5px rgba(173, 216, 230, 0.8);">
</div>
<!-- 下部分显示网站名称,显示在左边下半部的正中间,加粗且为红色 -->
<p style="font-size: 12px; text-align: center; margin: 0; height: 50%; display: flex; align-items: center; justify-content: center; font-weight: bold; color: red;"><a href="<?php echo $article['link_url']; ?>" target="_blank"><?php echo $article['link_name']; ?></a></p>
</div>
<!-- 右边占4/5 -->
<div style="width: 80%;">
<!-- 上部分显示文章名称,点击文章名称打开新窗口跳转到文章实际地址,文字蓝色大小为16px -->
<h3 style="font-size: 16px; color: blue; margin-bottom: 5px;"><a href="<?php echo $article['item_link']; ?>" target="_blank"><?php echo $article['item_title']; ?></a></h3>
<!-- 中部分显示文章摘要显示65个文字大小为14px,如果没有摘要,取文章的前65个文字 -->
<p style="font-size: 14px; margin-bottom: 5px;"><?php echo wp_trim_words(wp_kses_post(empty($article['item_excerpt']) ? $article['item_content'] : $article['item_excerpt']), 65); ?></p>
<!-- 下部分显示作者名称和更新时间,同一行 -->
<p style="font-size: 14px; margin-bottom: 0;">作者:<?php echo $article['item_author']; ?> | 更新时间:<?php echo $article['item_date']; ?></p>
</div>
</div>
<?php
}
?>
代码二:
<?php
/*
Template Name: 似水流年-RSS朋友圈
*/
date_default_timezone_set('Asia/Shanghai');
get_header();
require_once(ABSPATH . WPINC . '/class-simplepie.php');
// 主内容区域
echo '<div id="primary" class="content-area">';
echo '<main id="main" class="site-main" role="main">';
echo '<p style="color: red; font-size: 14px; margin-top: 10px; margin-bottom: 20px; text-align: center; display: flex; align-items: center; justify-content: center;">以下友情链接网站最新内容每8小时获取更新一次</p>';
// 获取并显示友情链接的最新文章
$all_articles = get_cached_friend_link_rss_data();
$articles_to_show = array_slice($all_articles, 0, 50);
foreach ($articles_to_show as $article) {
display_friend_link_rss($article);
}
// 侧边栏
get_sidebar();
echo '</main><!-- #main -->';
echo '</div><!-- #primary -->';
get_footer();
//rsscache目录下忽略域名即不自动获取覆盖域名
$ignored_domains = array("www.忽略域名1.com", "忽略域名2.cn");
// 获取并缓存友情链接的最新文章数据
function get_cached_friend_link_rss_data() {
global $ignored_domains;
$all_articles = array();
// 获取所有友情链接
$args = array(
'orderby' => 'name',
'category' => 0,
'order' => 'ASC',
'hide_invisible' => 1,
'categorize' => 0,
'title_li' => '',
'echo' => 0
);
$links = get_bookmarks($args);
// 遍历每个友情链接
foreach ($links as $link) {
if ($link->link_rss && !empty($link->link_rss)) {
$domain = parse_url($link->link_url, PHP_URL_HOST);
if (!$domain) {
continue;
}
$feed_url = $link->link_rss;
$domain = parse_url($link->link_url, PHP_URL_HOST);
$cache_file = get_stylesheet_directory() . '/rsscache/' . $domain . '.xml'; // 移除MD5值
if (is_array($ignored_domains) && in_array($domain, $ignored_domains)) {
continue; // 如果域名在忽略列表中,则跳过
}
// 删除具有相同域名的旧XML文件
$old_cache_files = glob(get_stylesheet_directory() . '/rsscache/' . $domain . '.*.xml');
foreach ($old_cache_files as $old_file) {
// 获取旧文件的域名
$old_domain = pathinfo($old_file, PATHINFO_FILENAME);
// 检查旧文件的域名是否在忽略列表中
if (is_array($ignored_domains) && in_array($old_domain, $ignored_domains)) {
continue; // 如果域名在忽略列表中,则跳过删除
}
// 继续删除非忽略域名的旧文件
if ($old_file !== $cache_file) {
unlink($old_file);
}
}
if ((!file_exists($cache_file) || (is_array($ignored_domains) && in_array($domain, $ignored_domains))) || (time() - filemtime($cache_file) > 8 * HOUR_IN_SECONDS)) {
// 获取并保存最新的RSS内容,但只有在缓存文件不存在或域名在忽略列表中或已经过了8小时时才执行
$rss_content = get_rss_content($feed_url);
if ($rss_content) {
file_put_contents($cache_file, $rss_content);
}
}
$rss_items = get_rss_items($cache_file);
foreach ($rss_items as $item) {
$item_data = array(
'link_name' => $link->link_name,
'link_logo' => $link->link_image,
'link_url' => $link->link_url,
'item_title' => $item->get_title(),
'item_link' => $item->get_permalink(),
'item_date' => $item->get_date('Y-m-d H:i:s'),
'item_author' => $item->get_author()->get_name(),
'item_excerpt' => $item->get_description(),
'item_content' => $item->get_content()
);
$all_articles[] = $item_data;
}
}
}
// 根据更新时间降序排列所有文章数据
usort($all_articles, function ($a, $b) {
return strtotime($b['item_date']) - strtotime($a['item_date']);
});
return $all_articles;
}
// 获取并保存最新的RSS内容
function get_rss_content($feed_url) {
$response = wp_safe_remote_get($feed_url);
if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) {
return wp_remote_retrieve_body($response);
} else {
return '无法从提供RSS的URL获取RSS内容。';
}
}
// 使用SimplePie获取RSS项
function get_rss_items($cache_file) {
$rss = new SimplePie();
$rss->set_feed_url($cache_file);
$rss->init();
$rss->handle_content_type();
$rss->set_output_encoding('UTF-8'); // 设置输出编码
return $rss->get_items();
}
// 显示友情链接的RSS内容
function display_friend_link_rss($article) {
?>
<div class="friend-link-rss" style="border: 1px dashed #ccc; background-color: #f5f5f5; padding: 10px; margin-bottom: 20px; display: flex;">
<!-- 左边占1/5 -->
<div style="width: 20%; padding-right: 10px;">
<!-- 上部分显示站标logo,大小控制在60*60 -->
<div style="display: flex; align-items: center; justify-content: center; height: 50%;">
<img src="<?php echo $article['link_logo']; ?>" alt="<?php echo $article['link_name']; ?>" style="width: 60px; height: 60px; border-radius: 50%; box-shadow: 0 0 10px 5px rgba(173, 216, 230, 0.8);">
</div>
<!-- 下部分显示网站名称,显示在左边下半部的正中间,加粗且为红色 -->
<p style="font-size: 12px; text-align: center; margin: 0; height: 50%; display: flex; align-items: center; justify-content: center; font-weight: bold; color: red;"><a href="<?php echo $article['link_url']; ?>" target="_blank"><?php echo $article['link_name']; ?></a></p>
</div>
<!-- 右边占4/5 -->
<div style="width: 80%;">
<!-- 上部分显示文章名称,点击文章名称打开新窗口跳转到文章实际地址,文字蓝色大小为16px -->
<h3 style="font-size: 16px; color: blue; margin-bottom: 5px;"><a href="<?php echo $article['item_link']; ?>" target="_blank"><?php echo $article['item_title']; ?></a></h3>
<!-- 中部分显示文章摘要显示65个文字大小为14px,如果没有摘要,取文章的前65个文字 -->
<p style="font-size: 14px; margin-bottom: 5px;"><?php echo wp_trim_words(wp_kses_post(empty($article['item_excerpt']) ? $article['item_content'] : $article['item_excerpt']), 65); ?></p>
<!-- 下部分显示作者名称和更新时间,同一行 -->
<p style="font-size: 14px; margin-bottom: 0;">作者:<?php echo $article['item_author']; ?> | 更新时间:<?php echo $article['item_date']; ?></p>
</div>
</div>
<?php
}
?>
[/reply]
用此方法能够解决一部分网站无法在线解析时的问题,但是可能还是有一部分无法获取,不用着急,因为是在本地了,把不能正常获取的rss自己动手复制粘贴到对应域名的xml文件中,重新获取一下就全部搞定了。
您已阅读完《技术相关(共39篇)》目录的第 16 篇。请继续阅读本文后3篇文章:
二猫
前来学习一下,看看怎么布置
似水流年
https://my1981.cn/technology/646.html
这个是最后一版。
obaby
缓存还是有必要的,直接请求问题很多,并且数据量大了请求等待时间太长。
似水流年
是啊。看了你的网站,钟MM既能开发应用又能出书投稿,膜拜一下大神!🙏🎁
网友小宋
有的站点rss订阅链接有问题,页面会报解析失败。建议增加忽略功能。
似水流年
已经更新给你留言了。