我和 ChatGPT4 把友情链接改成了“朋友圈“

今天看到了 段先生 的文章,他用Freshrss的API在个人网站上面,实现了“朋友圈”。
我也想弄一个

我和ChatGPT4在他的基础上新增了1个功能2个版本:

  • 新增加载更多 按钮:默认显示 10 篇最新的文章,每次点击“加载更多”按钮时,都会通过 AJAX 请求加载更多文章,并在当前文章列表后追加新加载的文章。同时,如果还有更多文章可加载,新的“加载更多”按钮也会被添加到页面上。
  • 版本一:手动加载,手动点击加载更多 按钮

版本 2:自动加载,滑到底部加载更多最新文章,就像跟刷朋友圈一样地爽

大家可选择不同的版本进行使用,Enjoy ! ☀️

实现思路

通过 FreshRSS 的 API 获取订阅源的文章,并在 WordPress 中展示这些文章。

流程

安装Freshrss —— 设置Freshrss API访问权限和密码 —— 添加rss.php —— 编辑主题funtions.php文件 —— 添加自定义CSS —— 添加自动加载按钮 —— 订阅好友的 RSS

具体步骤

通过Docker 安装部署 Freshrss

新建docker compose.yml文件,并且输入以下代码
因为新版的docker已经去掉了version: “3”,所以在此也去掉了

# ~/freshrss/docker-compose.yml

services:

freshrss-db:

image: postgres:latest

container_name: freshrss-db

hostname: freshrss-db

restart: unless-stopped

volumes:

- ./freshrss-db:/var/lib/postgresql/data

environment:

POSTGRES_USER: freshrss

POSTGRES_PASSWORD: df6Qi5SnPQUdScsagzB

POSTGRES_DB: freshrss

freshrss-app:

image: freshrss/freshrss:latest

container_name: freshrss-app

hostname: freshrss-app

restart: unless-stopped

ports:

- 34211:80

depends_on:

- freshrss-db

volumes:

- ./data:/var/www/FreshRSS/data

- ./extensions:/var/www/FreshRSS/extensions

environment:

CRON_MIN: "*/45"

TZ: Asia/Shanghai

volumes:

freshrss-db: null

cd 到 yml 文件目录,输入安装命令docker compose up -d 即可安装成功

Freshrss 设置

允许api访问

按需设置清理策略、自动刷新间隔(可选,你也可保持默认)

设置 api密码

访问api地址

api 地址如下

一般常用的,都是用htps://xxx/api/greader.php 这个api地址,记住它!
到此,Freshrss的安装和设置相关工作已经结束了!

新建rss.php

在网站根目录新建rss.php文件,并且填入以下代码,按需修改成自己的域名。
*标记红色的都是需要你自己改

<?php
/**
* 获取最新订阅文章并生成JSON文件
*/
function getAllSubscribedArticlesAndSaveToJson($user, $password)
{
$apiUrl = 'https://你部署FreshRSS的域名/p/api/greader.php';
$loginUrl = $apiUrl . '/accounts/ClientLogin?Email=' . urlencode($user) . '&Passwd=' . urlencode($password);
$loginResponse = curlRequest($loginUrl);
if (strpos($loginResponse, 'Auth=') !== false) {
$authToken = substr($loginResponse, strpos($loginResponse, 'Auth=') + 5);
$articlesUrl = $apiUrl . '/reader/api/0/stream/contents/reading-list?&n=1000';
$articlesResponse = curlRequest($articlesUrl, $authToken);
$articles = json_decode($articlesResponse, true);
if (isset($articles['items'])) {
usort($articles['items'], function ($a, $b) {
return $b['published'] - $a['published'];
});
$subscriptionsUrl = $apiUrl . '/reader/api/0/subscription/list?output=json';
$subscriptionsResponse = curlRequest($subscriptionsUrl, $authToken);
$subscriptions = json_decode($subscriptionsResponse, true);
if (isset($subscriptions['subscriptions'])) {
$subscriptionMap = array();
foreach ($subscriptions['subscriptions'] as $subscription) {
$subscriptionMap[$subscription['id']] = $subscription;
}
$formattedArticles = array();
foreach ($articles['items'] as $article) {
$desc_length = mb_strlen(strip_tags(html_entity_decode($article['summary']['content'], ENT_QUOTES, 'UTF-8')), 'UTF-8');
if ($desc_length > 20) {
$short_desc = mb_substr(strip_tags(html_entity_decode($article['summary']['content'], ENT_QUOTES, 'UTF-8')), 0, 99, 'UTF-8') . '...';
} else {
$short_desc = strip_tags(html_entity_decode($article['summary']['content'], ENT_QUOTES, 'UTF-8'));
}

$formattedArticle = array(
'site_name' => $article['origin']['title'],
'title' => $article['title'],
'link' => $article['alternate'][0]['href'],
'time' => date('Y-m-d H:i', $article['published']),
'description' => $short_desc,
);

$subscriptionId = $article['origin']['streamId'];
if (isset($subscriptionMap[$subscriptionId])) {
$subscription = $subscriptionMap[$subscriptionId];
$iconUrl = $subscription['iconUrl'];
$filename = 'https://你部署FreshRSS的域名/p/'.substr($iconUrl, strrpos($iconUrl, '/') + 1);
$formattedArticle['icon'] = $filename;
}

$formattedArticles[] = $formattedArticle;
}

saveToJsonFile($formattedArticles);
return $formattedArticles;
} else {
echo 'Error retrieving articles.';
}
} else {
echo 'Error retrieving articles.';
}
} else {
echo 'Login failed.';
}
return null;
}
function curlRequest($url, $authToken = null)
{
$ch = curl_init($url);
if ($authToken) {
$headers = array(
'Authorization: GoogleLogin auth=' . $authToken,
);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
/**
* 将数据保存到JSON文件中
*/
function saveToJsonFile($data)
{
$json = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
file_put_contents('output.json', $json);
echo '数据已保存到JSON文件中';
}

// 调用函数并提供用户名和密码
getAllSubscribedArticlesAndSaveToJson('这里输入FreshRSS的用户名', '这里输入Freshrss的api密码');

请先检测是否成功:地址栏输入 https://你的域名/rss.php,假如看到“数据已保存到JSON文件中”,就意味着成功,可进行下一步。

编辑funtions.php

在子主题的funtions.php里添加以下代码
(建议用子主题,因为当主题更新时,不怕丢失funtions.php里面的自定义代码)
(这里的代码无修修改,找funtions的自定义代码区域,粘贴进去)

function display_articles_shortcode($atts) {
    $attributes = shortcode_atts(array('offset' => 0), $atts);
    $offset = intval($attributes['offset']);

    $jsonFilePath = ABSPATH . 'output.json';
    $jsonData = file_get_contents($jsonFilePath);
    if ($jsonData === false) {
        return '<div class="error">Failed to load data from ' . htmlspecialchars($jsonFilePath) . '</div>';
    }

    $articles = json_decode($jsonData, true);
    if (json_last_error() !== JSON_ERROR_NONE) {
        return '<div class="error">Error decoding JSON data: ' . htmlspecialchars(json_last_error_msg()) . '</div>';
    }

    if (empty($articles)) {
        return '<div class="error">No articles to display.</div>';
    }

    usort($articles, function ($a, $b) {
        return strtotime($b['time']) - strtotime($a['time']);
    });

    $itemsPerPage = 10;
    $articlesToShow = array_slice($articles, $offset, $itemsPerPage);

    ob_start();
    foreach ($articlesToShow as $article) {
        ?>
        <div class="article">
            <h3>
                <img src="<?php echo htmlspecialchars($article['icon']); ?>" alt="Icon" class="icon">
                <a href="<?php echo htmlspecialchars($article['link']); ?>" rel="nofollow" target="_blank"><?php echo htmlspecialchars($article['title']); ?></a>
            </h3>
            <p>作者:<?php echo htmlspecialchars($article['site_name']); ?></p>
            <p><?php echo htmlspecialchars($article['description']); ?></p>
            <time><?php echo htmlspecialchars($article['time']); ?></time>
        </div>
        <?php
    }
    // Check if there are more articles to load
    if ($offset + $itemsPerPage < count($articles)) {
        echo '<button id="load-more" data-offset="' . ($offset + $itemsPerPage) . '">加载更多</button>';
    } else {
        echo '<div id="all-loaded">加载完毕</div>';
    }
    return ob_get_clean();
}

add_shortcode('display_articles', 'display_articles_shortcode');



function enqueue_custom_scripts() {
    wp_enqueue_script('custom-js', get_template_directory_uri() . '/js/custom.js', array('jquery'), null, true);
    wp_localize_script('custom-js', 'ajax_params', array('ajax_url' => admin_url('admin-ajax.php')));
}
add_action('wp_enqueue_scripts', 'enqueue_custom_scripts');

function load_more_articles() {
    $offset = isset($_POST['offset']) ? intval($_POST['offset']) : 0;
    echo display_articles_shortcode(array('offset' => $offset));
    wp_die();
}
add_action('wp_ajax_load_more_articles', 'load_more_articles');
add_action('wp_ajax_nopriv_load_more_articles', 'load_more_articles');

新建js文件

在主主题,是主主题,不是子主题,在主主题的根目录新建 js 文件夹,在 js 里面新增 custom.js,并且把下面代码粘贴进去
(也就是:/wp-content/themes/主主题/js/custom.js)

版本一:手动加载

custom.js

jQuery(document).ready(function($) {
$(document).on('click', '#load-more', function() {
var button = $(this);
var offset = button.data('offset');
$.ajax({
url: ajax_params.ajax_url,
type: 'POST',
data: {
'action': 'load_more_articles',
'offset': offset
},
success: function(response) {
button.replaceWith(response);
}
});
});
});

版本二:底部自动加载,就像刷朋友圈那么爽!

custom.js

jQuery(document).ready(function($) {
    // 函数用于检查是否滚动到页面底部
    function isScrolledToBottom() {
        return $(window).scrollTop() + $(window).height() >= $(document).height() - 100; // 100px提前量
    }

    // 函数用于加载更多文章
    function loadMoreArticles() {
        var button = $('#load-more');
        if (button.length) {
            var offset = button.data('offset');
            $.ajax({
                url: ajax_params.ajax_url,
                type: 'POST',
                data: {
                    'action': 'load_more_articles',
                    'offset': offset
                },
                beforeSend: function() {
                    button.text('加载中...'); // 可选:在加载时更改按钮文本
                },
                success: function(response) {
                    button.replaceWith(response);
                }
            });
        }
    }

    // 绑定滚动事件
    $(window).scroll(function() {
        if (isScrolledToBottom()) {
            loadMoreArticles(); // 当滚动到底部时,调用加载更多文章的函数
        }
    });

    // 也保留点击加载更多的功能
    $(document).on('click', '#load-more', function() {
        loadMoreArticles();
    });
});

自定义css

/* Article container */
.article {
    border: 1px solid #ccc;
    border-radius: 5px;
    padding: 15px;
    margin-bottom: 20px;
}

/* Article title */
.article h3 {
    margin-top: 0;
}

/* Article icon */
.icon {
    width: 50px;
    height: 50px;
    margin-right: 10px;
    border-radius: 50%;
}

/* Article metadata */
.article p, .article time {
    margin: 5px 0;
}

/* Article time */
.article time {
    font-style: italic;
}

/* Hover effect on article */
.article:hover {
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    transition: box-shadow 0.3s ease;
}
/* Article icon */
.icon {
    width: 1.5em; /* 使用 em 单位可以根据标题字体大小调整图标大小 */
    height: auto; /* 自动调整高度以保持宽高比 */
    margin-right: 10px;
    vertical-align: middle; /* 垂直居中对齐 */
    border-radius: 50%;
}

输入简码

在需要的地方输入 简码 即可

[display_articles]

定时刷新

定时访问刚开始创建的php文件,以更新订阅数据
以1panel为例,宝塔面板同理

用Freshrss订阅好友

用Freshrss订阅好友非常方便

See You~

参考资料:
若志:用FreshRSS 实现友圈rss订阅
段先生:跟风利用FreshRSS实现朋友圈

评论 6
      1. 动态也很好呀,我准备后面换个大点的服务器了,换成动态,静态的没有后台,更新起来不太方便

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

这些同样精彩