巧用ChatGPT改造代码 让PIX主题片刻支持外部链接转化为卡片(三)
本文是《技术相关(共37篇)》目录的第 37 篇。阅读本文前,建议先阅读本文前3篇文章:
本篇为以下文章的再升级版本,主要升级以下2个部分:
1、建立自己的获取任意网页的站标API接口,不再借助第三方https://favicon.im等网站进行解析,避免因第三方网站访问不畅拖慢本站速度。本站采用修改以下源码https://github.com/7xs/getFavicon进行搭建。
2、建立自己的获取微信公众号平台任意文章的公众号图标、公众号名称和文章标题API接口。本站采用修改以下源码https://github.com/jiaopianjun/wxCrawler进行搭建。获取微信公众号平台任意文章的公众号图标为独立功能,不使用第1条获取。需要注意的是,千万不要用此条进行微信公众号文章爬取,否则有封号的危险。
先看演示效果:
改造过程如下:
一、将以下压缩包解压缩至网站根目录下,即与wp-config.php同级目录。
二、强烈建议提前备份pix/inc/pix-type.php文件,然后进行修改。依然从大概第65行// 获取卡片信息开始,至//音乐编辑前结束。
// 获取卡片信息
class CardFetcher
{
private static $instance;
private $redis;
private function __construct() {
$this->redis = new Redis();
$this->redis->connect('127.0.0.1', 6379);
}
public static function getInstance()
{
if (!self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
// 获取缓存的 logo
public function getCachedLogo($url)
{
$redisKey = 'logo_'. md5($url);
$logoFromRedis = $this->redis->hGet('logos', $redisKey);
if ($logoFromRedis) {
return $logoFromRedis;
}
return null;
}
// 缓存 logo
public function cacheLogo($url, $logo)
{
$redisKey = 'logo_'. md5($url);
$this->redis->hSet('logos', $redisKey, $logo);
$this->redis->expire('logos', 86400);
}
// 获取缓存的元数据
public function getCachedMetadata($url)
{
$redisKey = 'metadata_'. md5($url);
$metadataFromRedis = $this->redis->hGet('metadatas', $redisKey);
if ($metadataFromRedis) {
return json_decode($metadataFromRedis, true);
}
return null;
}
// 缓存元数据
public function cacheMetadata($url, $metadata)
{
$redisKey = 'metadata_'. md5($url);
$this->redis->hSet('metadatas', $redisKey, json_encode($metadata));
$this->redis->expire('metadatas', 86400);
}
}
// 引入 simple_html_dom.php 文件
require_once 'simple_html_dom.php';
function extractMetaFromHtml($html)
{
$dom = str_get_html($html);
$title = '';
$description = '';
// 获取标题
if ($dom->find('title', 0)) {
$title = trim($dom->find('title', 0)->plaintext);
}
if (empty($title)) {
if ($dom->find('h1', 0)) {
$title = trim($dom->find('h1', 0)->plaintext);
}
}
if (empty($title)) {
foreach ($dom->find('meta') as $meta) {
if ($meta->property === 'og:title' && $meta->content) {
$title = trim($meta->content);
break;
}
}
}
// 获取描述
foreach ($dom->find('meta') as $meta) {
if ($meta->name === 'description' && $meta->content) {
$description = trim($meta->content);
break;
}
}
if (empty($description)) {
foreach ($dom->find('meta') as $meta) {
if ($meta->property === 'og:description' && $meta->content) {
$description = trim($meta->content);
break;
}
}
}
if (empty($description)) {
$bodyContent = $dom->find('body', 0)->plaintext;
$words = preg_split('/\s+/', strip_tags($bodyContent));
$description = implode(' ', array_slice($words, 0, 30));
}
return ['title' => $title, 'description' => $description, 'image' => null];
}
function get_external_link_metadata_with_cache($url)
{
// 设置主流常见的 USERAGENT
$userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36';
$cacheKey = 'external_link_metadata_'. md5($url);
$cachedMeta = CardFetcher::getInstance()->getCachedMetadata($cacheKey);
if ($cachedMeta) {
return $cachedMeta;
}
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_USERAGENT, $userAgent);
curl_setopt($ch, CURLOPT_TIMEOUT, 5); // 设置超时时间为 5 秒
$html = curl_exec($ch);
if ($html === false) {
error_log("Curl error for URL $url: ". curl_error($ch));
// 如果获取外部链接内容失败,尝试从缓存中获取默认值或者返回空值
return ['title' => '', 'description' => '', 'image' => null];
}
$responseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($responseCode === 200 &&!empty($html)) {
$meta = extractMetaFromHtml($html);
CardFetcher::getInstance()->cacheMetadata($cacheKey, $meta);
return $meta;
} else {
return ['title' => '', 'description' => '', 'image' => null];
}
}
function get_external_link_logo($url)
{
$parsedUrl = parse_url($url);
if (!$parsedUrl ||!isset($parsedUrl['host'])) {
return null;
}
$domain = $parsedUrl['host'];
// 判断是否为微信公众平台文章网址
if (strpos($url, 'https://mp.weixin.qq.com/s/') === 0) {
// 提取文章ID部分用于文件名
$articleId = substr($url, strlen('https://mp.weixin.qq.com/s/'));
$cacheFilePath = '/第一步解压缩你的API物理路径/api/getmpwechat/cache/'. $articleId. '.json';
// 检查缓存文件是否存在
if (file_exists($cacheFilePath)) {
$jsonContent = file_get_contents($cacheFilePath);
$data = json_decode($jsonContent, true);
// 恢复转义后的网址(如果有转义处理的话,这里假设转义函数为 `urldecode`,实际可能需要根据具体转义方式调整)
if (isset($data['url'])) {
$data['url'] = urldecode($data['url']);
}
return $data['headImgUrl'];
} else {
// 如果缓存文件不存在,先进行解析并创建缓存文件
$parseUrl = "https://你的网站域名/api/getmpwechat/crawler.php?url=". $url;
// 这里可以添加代码使用curl或者其他方式去请求这个解析接口,获取并解析返回的内容,然后创建缓存文件
// 以下是示例代码,假设返回的是JSON格式数据,实际可能需要根据接口返回格式调整
$ch = curl_init($parseUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
// 创建缓存文件
file_put_contents($cacheFilePath, json_encode($data));
return $data['headImgUrl'];
}
}
// 非微信公众平台文章网址,使用原来的方式获取站标
return "https://你的网站域名/api/getfavicon/{$domain}";
}
function get_card_by_url($data)
{
$parsedUrl = parse_url($data);
$pid = null;
if (filter_var($data, FILTER_VALIDATE_URL)) {
if ($parsedUrl['host'] == $_SERVER['HTTP_HOST']) {
if ($post = get_page_by_path($parsedUrl['path'])) {
$pid = $post->ID;
}
} else {
$pid = $data;
}
} else {
$pid = intval($data);
}
if ($pid) {
$meta = [];
if (filter_var($pid, FILTER_VALIDATE_URL)) {
$meta['url'] = $pid;
// 判断是否为微信公众平台文章网址
if (strpos($pid, 'https://mp.weixin.qq.com/s/') === 0) {
// 提取文章ID部分用于文件名
$articleId = substr($pid, strlen('https://mp.weixin.qq.com/s/'));
$cacheFilePath = '/第一步解压缩你的API物理路径/api/getmpwechat/cache/'. $articleId. '.json';
// 检查缓存文件是否存在
if (file_exists($cacheFilePath)) {
$jsonContent = file_get_contents($cacheFilePath);
$data = json_decode($jsonContent, true);
// 恢复转义后的网址(假设转义函数为urldecode,实际可能需根据具体转义方式调整)
if (isset($data['url'])) {
$data['url'] = urldecode($data['url']);
}
$meta['title'] = '微信公众平台 - '. $data['author'];
$meta['description'] = isset($data['title'])? $data['title'] : (isset($data['msg_title'])? $data['msg_title'] : '');
$meta['image'] = get_external_link_logo($pid);
} else {
// 如果缓存文件不存在,先进行解析并创建缓存文件
$parseUrl = "https://你的网站域名/api/getmpwechat/crawler.php?url=". $pid;
$ch = curl_init($parseUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
// 创建缓存文件
file_put_contents($cacheFilePath, json_encode($data));
$meta['title'] = '微信公众平台 - '. $data['author'];
$meta['description'] = isset($data['title'])? $data['title'] : (isset($data['msg_title'])? $data['msg_title'] : '');
$meta['image'] = get_external_link_logo($pid);
}
} else {
$externalMeta = get_external_link_metadata_with_cache($pid);
$meta['title'] = $externalMeta['title'];
$meta['description'] = $externalMeta['description'];
$meta['image'] = get_external_link_logo($pid);
}
} else {
$type = get_post_type($pid);
$meta['title'] = get_the_title($pid);
$meta['url'] = get_permalink($pid);
$meta['description'] = get_the_excerpt($pid);
$metaImageUrl = get_the_post_thumbnail_url($pid, 'medium');
if ($metaImageUrl) {
$meta['image'] = $metaImageUrl;
} else {
$meta['image'] = get_external_link_logo($meta['url']);
}
if ($type == 'moment') {
$meta['title'] = '片刻';
$momentImg = THEME_URL. '/img/banner.jpg';
$lists = get_post_meta($pid, 'moment_ga', true);
if (is_array($lists) &&!empty($lists)) {
$momentImg = $lists[0]['thum'];
}
$meta['image'] = $momentImg;
}
}
$meta['pid'] = $pid;
return $meta;
} else {
return false;
}
}
// 卡片编辑
function card_type_box()
{
$output = '<div class="add_card_box">
<div class="edit_card_box">
<div class="tips"># 输入本站网址或外部网址,自动生成链接卡片</div>
<div class="tips">
<span>本站网址支持文章、片刻、页面内链及外链网址</span><br>
<span>淘宝示例:https://item.taobao.com/item.htm?id=******<br>京东示例:https://item.jd.com/******.html<br>拼多多示例:https://mobile.yangkeduo.com/goods1.html?goods_id=******<br>微信公众平台文章示例:https://mp.weixin.qq.com/s/******</span></div>
<div class="edit_content">
<input type="text" placeholder="本站网址或外部网址" name="moment_card_link" id="moment_card_link" required="required">
<a class="push_card">生成卡片</a>
</div>
</div>
<div class="show_card"><div class="card_sortble" uk-sortable="handle:.moment_card_item"></div></div>
</div>';
echo $output;
exit();
}
add_action('wp_ajax_nopriv_card_type_box', 'card_type_box');
add_action('wp_ajax_card_type_box', 'card_type_box');
function get_moment_card()
{
try {
$cardUrl = esc_url($_POST['card_url']);
$arr = get_card_by_url($cardUrl);
$html = '';
if (is_array($arr)) {
$html = '<div class="moment_card_item" pid="'. $arr['pid']. '">
<a>
<div class="left"><img src="'. $arr['image']. '"></div>
<div class="right"><h4>'. $arr['title']. '</h4><div class="content">'. $arr['description']. '</div></div>
<span class="de_card"><i class="ri-close-line"></i></span>
</a>
</div>';
$res = ['html' => $html, 'state' => '1'];
} else {
$html = '未知错误';
$res = ['html' => $html, 'state' => '0'];
}
echo json_encode($res);
exit();
} catch (Exception $e) {
$html = '未知错误';
$res = ['html' => $html, 'state' => '0'];
echo json_encode($res);
exit();
}
}
add_action('wp_ajax_nopriv_get_moment_card', 'get_moment_card');
add_action('wp_ajax_get_moment_card', 'get_moment_card');
function get_m_card()
{
try {
global $post;
$pid = $post->ID;
$lists = get_post_meta($pid, 'moment_card', true);
$html = '';
if (is_array($lists) &&!empty($lists)) {
foreach ($lists as $index => $list) {
$cardInfo = get_card_by_url($list);
if ($cardInfo) {
$html.= '<div class="moment_card_item loop_card_item" pid="'. $cardInfo['pid']. '">
<a href="'. $cardInfo['url']. '" target="_blank">
<div class="left"><img src="'. $cardInfo['image']. '"></div>
<div class="right"><h4>'. $cardInfo['title']. '</h4><div class="content">'. $cardInfo['description']. '</div></div>
</a>
</div>';
}
}
return '<div class="card_list">
<div class="list_inner">'. $html. '</div>
</div>';
}
} catch (Exception $e) {
return false;
}
}
上面有5个地方需要修改称自己的,我已经标记出来了。搜索“你的网站域名”有3个,修改成你的网站地址;搜索“/第一步解压缩你的API物理路径/”,修改成你的真实网站物理目录地址,如/wwwroot/www.xxx.com/,这个需要你自己确定一下每个站都不一样。
沉沦
感觉这个主题的代码少不了,功能有点多
似水流年
已经添加不少功能了,我感觉比着原版就是PRO版本了。😎
obaby
代码好长。
似水流年
这个代码等于是把前两篇1和2的都包括了。
刘郎
js代码多了这样会不会拖垮网站速度呢😂
似水流年
我觉得还能接受。😹