友链的朋友圈 RSS的聚合页 (WordPress->PIX主题篇&本地解析版)

本文适用于友链网站内容频繁更新的情况

友链的朋友圈 RSS的聚合页 (WordPress->PIX主题篇&在线解析版)请参考如下文章:

友链的朋友圈 RSS的聚合页 (WordPress->PIX主题篇&在线解析版) 友链的朋友圈 RSS的聚合页 (WordPress->PIX主题篇&在线解析版) 本文代码基于WordPress构建,PIX主题测试,其他主题理论上通用。 友链的朋友圈 RSS的聚合页 (WordPress->PIX主题篇&本地解析版)请参考如下文章: [pix_po... 时间:2023/12/26 分类:技术相关

之所以又出了一个本地解析版,是因为在线解析版始终未能解决两个问题:第一、我有个别友链网站,明明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文件,就不会重新获取覆盖,只能手工修改。

友链的朋友圈 RSS的聚合页 (WordPress->PIX主题篇&本地解析版)-似水流年

[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文件中,重新获取一下就全部搞定了。

Comments | 6 条评论
  • 二猫

    Microsoft Edge 128 Microsoft Edge 128 Windows 10 Windows 10 1中国 中国电信 ip address 240e:3a3:4c27:5e0:*:*

    前来学习一下,看看怎么布置

  • obaby

    Google Chrome 118 Google Chrome 118 Mac OS X 10.15 Mac OS X 10.15 1中国–山东–青岛 联通 ip address 112.224.*.*

    缓存还是有必要的,直接请求问题很多,并且数据量大了请求等待时间太长。

    • 似水流年

      Microsoft Edge 120 Microsoft Edge 120 Windows 10 Windows 10 1中国–河南–漯河 联通 ip address 123.10.*.*

      是啊。看了你的网站,钟MM既能开发应用又能出书投稿,膜拜一下大神!🙏🎁

  • 网友小宋

    Microsoft Edge 120 Microsoft Edge 120 Windows 10 Windows 10 1中国–河南–漯河 联通 ip address 125.44.*.*

    有的站点rss订阅链接有问题,页面会报解析失败。建议增加忽略功能。

    • 似水流年

      Microsoft Edge 120 Microsoft Edge 120 Windows 10 Windows 10 1中国–河南–漯河 联通 ip address 123.10.*.*

      已经更新给你留言了。

消息盒子
# 您需要首次评论以获取消息 #
# 您需要首次评论以获取消息 #

只显示最新10条未读和已读信息