普通视图
typecho插件-MemosSync,Memos 同步插件
这款插件是我找deepseek写的,主要功能是把typecho发布的内容自动同步到Memos上。应该是绝大部分博主都用不上,各取所需吧!也是想说,AI成熟了,我们每位都是程序员,都可以让AI写出自己想要的功能的代码!
一直以来,除老张博客外,还有一个后花园,老张随笔。老张随笔就是每天记一些点滴,发一点牢骚!字数都是在一两百字,到目前为止,也记录了近一千五百篇日志了。老张随笔最初选用的是较轻量的Typecho程序,后来Memos在博客圈流行的时候,老张随笔便换成了Memos程序,这样能更好的和五木大佬开发的哔哔广场融合。Typecho数据导入到Memos数据库中也非常的简单,这篇《简单几步,Typecho博客文章轻松导入到Memos》教程,便可以教大家很方便的把Typecho的文章导入到Memos中。Memos也使用了两三年吧,但是由于作者的任性更新,版本一直还停留在0.18.1上。加之大家对Memos热度的减少,现在玩Memos的人很少了,原来五木大佬的哔哔广场,每天都好几十条哔文,现在基本上很少有人发了。种种原因,老张随笔又换回了Typecho程序,但是老张又舍不得Memos,所以在Typecho上发布一篇文章后,便手动复制到Memos上,也算是做为备份吧!每天手动甚是麻烦,便有了这款Typecho插件-MemosSync,Memos同步插件。
插件功能特点:
-
✅ 文章发布时自动同步到Memos
-
✅ 支持将文章分类作为Memos标签
-
✅ 可配置可见性(公开/受保护/私有)
-
✅ 完整的错误处理,不影响文章发布
-
✅ 后台配置界面
安装和使用说明
1.安装插件
将下面的文件上传到 /usr/plugins/MemosSync/ 目录
在Typecho后台启用插件
2.配置插件:
进入插件设置页面
填写Memos地址(例如:https://memos.example.com)
输入Access Token(在Memos设置中生成)
选择可见性设置
启用同步功能
3.获取Access Token:
登录您的Memos实例
进入设置 → 权限 → Access Tokens
生成新的Token并复制到插件设置中
注意事项
-
确保您的Typecho服务器可以访问Memos实例
-
如果同步失败,会在Typecho日志中记录错误信息
-
标签会自动过滤特殊字符,只保留字母、数字、中文和下划线
插件结构
/usr/plugins/MemosSync/
├── Plugin.php ├── config.xml └── form.php
1. config.xml
<?xml version="1.0" encoding="UTF-8"?>
<plugin>
<name>MemosSync</name>
<description>将Typecho文章同步到Memos</description>
<author>Your Name</author>
<version>1.0.0</version>
<module>MemosSync</module>
</plugin>
2. form.php
<?php if(!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
<h2>Memos 同步设置</h2>
<div class="typecho-page-title">
<h2>Memos 配置</h2>
</div>
<div class="typecho-option">
<label class="typecho-label" for="memos_url">Memos 地址</label>
<input type="text" class="text" name="memos_url" id="memos_url" value="<?php $this->options->memos_url(); ?>" />
<p class="description">请输入完整的Memos地址,例如:https://memos.example.com</p>
</div>
<div class="typecho-option">
<label class="typecho-label" for="memos_token">Access Token</label>
<input type="text" class="text" name="memos_token" id="memos_token" value="<?php $this->options->memos_token(); ?>" />
<p class="description">在Memos设置中生成的Access Token</p>
</div>
<div class="typecho-option">
<label class="typecho-label" for="memos_visibility">可见性</label>
<select name="memos_visibility" id="memos_visibility">
<option value="PUBLIC" <?php if($this->options->memos_visibility == 'PUBLIC') echo 'selected'; ?>>公开</option>
<option value="PROTECTED" <?php if($this->options->memos_visibility == 'PROTECTED') echo 'selected'; ?>>受保护</option>
<option value="PRIVATE" <?php if($this->options->memos_visibility == 'PRIVATE') echo 'selected'; ?>>私有</option>
</select>
<p class="description">选择同步到Memos的可见性设置</p>
</div>
<div class="typecho-option">
<label class="typecho-label">
<input type="checkbox" name="memos_enable_sync" value="1" <?php if($this->options->memos_enable_sync == '1') echo 'checked'; ?> />
启用同步功能
</label>
<p class="description">启用后,发布文章时会自动同步到Memos</p>
</div>
<div class="typecho-option">
<label class="typecho-label">
<input type="checkbox" name="memos_include_tags" value="1" <?php if($this->options->memos_include_tags == '1') echo 'checked'; ?> />
包含分类作为标签
</label>
<p class="description">将文章分类作为Memos的标签</p>
</div>
3. Plugin.php
<?php
/**
* MemosSync - Typecho文章同步到Memos插件
*
* @package MemosSync
* @author Your Name
* @version 1.0.0
* @link https://yourblog.com
*/
class MemosSync_Plugin implements Typecho_Plugin_Interface
{
/**
* 激活插件
*/
public static function activate()
{
Typecho_Plugin::factory('Widget_Contents_Post_Edit')->finishPublish = array('MemosSync_Plugin', 'syncToMemos');
Typecho_Plugin::factory('Widget_Contents_Post_Edit')->finishSave = array('MemosSync_Plugin', 'syncToMemos');
return _t('插件已激活,请配置Memos设置');
}
/**
* 禁用插件
*/
public static function deactivate()
{
return _t('插件已禁用');
}
/**
* 插件配置面板
*/
public static function config(Typecho_Widget_Helper_Form $form)
{
require_once 'form.php';
}
/**
* 个人用户的配置面板
*/
public static function personalConfig(Typecho_Widget_Helper_Form $form) {}
/**
* 同步到Memos
*/
public static function syncToMemos($contents, $post)
{
// 获取插件配置
$options = Typecho_Widget::widget('Widget_Options');
$memosUrl = $options->plugin('MemosSync')->memos_url;
$memosToken = $options->plugin('MemosSync')->memos_token;
$memosVisibility = $options->plugin('MemosSync')->memos_visibility;
$enableSync = $options->plugin('MemosSync')->memos_enable_sync;
$includeTags = $options->plugin('MemosSync')->memos_include_tags;
// 检查是否启用同步
if (!$enableSync) {
return;
}
// 验证必要配置
if (empty($memosUrl) || empty($memosToken)) {
return;
}
try {
// 准备请求数据
$apiUrl = rtrim($memosUrl, '/') . '/api/v1/memos';
$content = $contents['text'];
// 如果启用了标签功能,获取分类作为标签
$tags = array();
if ($includeTags && isset($contents['category'])) {
$category = $contents['category'];
if (is_array($category)) {
$tags = $category;
} else {
$tags = array($category);
}
}
// 构建内容,包含标签
$memoContent = $content;
if (!empty($tags)) {
$tagString = '';
foreach ($tags as $tag) {
$tagString .= ' #' . self::formatTag($tag);
}
$memoContent .= "\n\n" . $tagString;
}
// 准备请求数据
$postData = array(
'content' => $memoContent,
'visibility' => $memosVisibility
);
// 发送请求到Memos
$http = Typecho_Http_Client::get();
if ($http) {
$http->setHeader('Authorization', 'Bearer ' . $memosToken)
->setHeader('Content-Type', 'application/json')
->setData(json_encode($postData))
->setTimeout(30)
->send($apiUrl);
$response = $http->getResponseBody();
$status = $http->getResponseStatus();
if ($status != 200) {
throw new Exception('Memos API 返回错误: ' . $status . ' - ' . $response);
}
}
} catch (Exception $e) {
// 记录错误日志,但不影响文章发布
Typecho_Log::write('MemosSync Error: ' . $e->getMessage(), Typecho_Log::WARN);
}
}
/**
* 格式化标签
*/
private static function formatTag($tag)
{
// 移除特殊字符,只保留字母、数字、中文、下划线
$tag = preg_replace('/[^\p{L}\p{N}_]/u', '', $tag);
return $tag;
}
}
【去过】页面上线
最终效果见这里。
我这个人既不喜欢旅游,也不喜欢摄影,没出过国也没在国内溜达过几个地方,但这并不妨碍我也有一颗上线足迹地图的心。无奈谷歌地图连不上,百度地图不想连,OSM(OpenStreetMap)既连不上也连不明白,就搁置了。
直到上周,@Dayu上线了他的地图插件,试用之后发现表现形式与期待值有差距,想在帖子下面留言发建议的时候,发现了明明同学的另一份方案。虽然主要是js实现的,只需要知道leaflet这个开源库的名字,我就知道以Wordpress的海量扩展,这回成了!
找到了一个插件和插件的插件,配置之后,算是达到了心目中的效果。
插件使用比较复杂,这里记录一下,给自己个备忘,能帮到人更好。
插件Leaflet Map的配置
插件地址:Leaflet Map。
逐一说明一下后台的配置项:
Default Latitude:
地图默认纬度
Default Longitude:
地图默认经度
Default Zoom:
地图默认缩放比
Default Height:
默认高度
Default Width:
默认宽度
上面五个值可以以短代码参数的形式加到leaflet-map中,如果不加则使用后台的默认参。
Fit Bounds:
是否令地图随标记点的范围进行缩放。如果为true,那么地图会自动计算当前所有Marker的中心位置,以及包括所有Marker点的合适的缩放比。可以用默认值,也可以在map中单独设置。
Show Zoom Controls:
是否显示缩放按钮
Scroll Wheel Zoom:
是否允许滚轮缩放
这项设置之后,在地图上并不是直接用滚轮缩放,而是需要用Ctrl,感觉不便所以我自己没加。
Double Click Zoom:
是否允许双击放大
注意如果不显示缩放按钮的话,放大之后就回不来了。
Default Min/Max Zoom:
最小和最大放大倍数。最终的放大倍数不仅跟这个后台设定项有关,也跟使用的地图瓦片API有关。
Default Tiling Service:
有两个选项,“I will provide my own map tile URL”和MapQuest。MapQuest我考察了一番,感觉太难看,没继续尝试。所以重点说第一个选项,自定义tile URL。
先解释一下什么是tile URL。本插件所依赖的地图服务,叫做Map Tile Server(地图瓦片服务)。它分成Raster、Vector和Static三种形式。本插件使用的是Raster形式,而Dayu和明明同学用的都是Vector形式。Vector的参数更加丰富,Raster配置起来更简便。
※※※Map Tile URL※※※:
重中之重!!因为默认的OSM服务访问不了,所以这里必须填一个自定义的。
明明同学找的cartocdn就挺好用的。他使用的light_nolabels是不带标签的版本,换成light_all就是带标签的版本。至于他为什么用不带标签的,自己悟。
https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png
http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png
这里的{z}{x}{y}都不要动,第一个{s}是指地址里的subdomain,也就是接下来的配置项【Map Tile URL Subdomains】。
有的API是需要API Key的。这样的API都有说明文档,把Key按照人家给的例子粘贴进来即可。
cartocdn对我来说有点太素了,于是周末花了一天时间寻找能用的瓦片服务,结果惨不忍睹,汇报一下成果:
maptiler.com:要注册、被墙。
opentopomap.org:免注册、丑。
stadiamaps.com:要注册、比较流畅、免费用户限流严重
tomtom.com:要注册、慢、地图不详细
here.com:要注册、中文地名乱七八糟
geoapify.com:要注册、速度尚可、账号登录验证需要梯子,服务本身不需要。
至于为啥不找国内的地图服务,是我不想吗?本插件所支持的是Raster服务,也叫zxy服务,客户端GET的结果必须是一张PNG/JPG/WEBP图片。国产的高德和天地图我也试了,根本不是一样的格式。甚至有种说法,说国内不允许提供这种服务。
然后呢,这服务也可以自己搭建,数据和教程也都有,但总觉得这种行为像为了吃顿酱肘子先花一年时间晒酱油,没必要。
兜兜转转一圈,还是要回到cartocdn。什么功不唐捐,屁咧!
Map Tile URL Subdomains:
具体填什么要看API的文档说明,像openstreetmap和cartocdn都是abcde或a,b,c,d,e。有的API前面没有前缀那就不填。
Detect Retina:
是否检测高清设备。如果上面的瓦片服务中支持@2x,那么选中这项以后,如果leaflet发现使用者用的是高清屏幕,就会自动使用高清地图。窃以为意义不大。
Tile Size:
一般情况下服务本身已经设好了,留空即可。
Tile Id:
Access Token:
用Mapbox的服务才有用。但是我的Mapbox没配明白,只有一个默认的卫星地图能用,这两项也没用上。
Zoom Offset:
好像是在zoom的时候自动加减一下这个值,没理解意义。
No Wrap (tiles):
地图是否与经线对齐。(这有啥用?)
JavaScript URL、CSS URL:
css和js的位置,默认即可。
Default Attribution:
地图做成后,右下角的一串版权信息。尊重服务商要求即可。
再往后没用上。
插件装好后,其实已经可以编辑地图了。但因为还有个插件的插件,所以怎么用放后面再说。
插件Extensions for Leaflet Map的配置
插件地址:Extensions for Leaflet Map。
跟主插件正相反,这个插件的后台,大多数时间在说怎么用。
Marker Clustering–When you mouse over a cluster it shows the bounds of its markers.
聚合显示时,默认会将聚合的标记点连接起来形成一个多边形。我嫌不好看,勾掉了。
When you click a cluster we zoom to its bounds.
点击聚合点时,直接缩放到所有聚合点的范围。
增加一个leaflet map
语法和关键字很多,但能用上的不多。通常只需要地图、标记点、地形json文件。
leaflet-map:
主插件的主函数,用于插入一张leaflet-map。参数就是配置页面的那些,没什么特别的。
leaflet-marker:
标记一个地点。参数比较多,挑有用的说。
– lat,lng / address:用于定位标记的位置。lat是纬度,lng是经度。经纬度可以从OpenStreetMap.org上查。国产地图查到的经纬度与OSM查到的有一些偏差,注意要保持一致。而address的数据库偏差非常大,不建议。
– iconUrl:标记用图标。可以是网址,也可以是相对路径,甚至base64代码。如果不设,使用默认的蓝色pin图标。
– title:鼠标移动到标记点上时显示的提示信息。这个与点击标记后显示的内容是两码事。
– iconanchor:图标的锚点偏移。这个参数有点意思,它表示的是你图标的“尖”所在的位置。以默认图标为例,规格是19*25,“尖”在最下方,所以iconanchor就应该是宽的一半和全部的高,也就是10,25。这个参默认项是0,0。每个标记都要自己手动加,相当烦。不过也能够理解,一旦有人用的是左箭头呢?
– opacity:图标的透明度。
– 【leaflet-marker】【/leaflet-marker】之间,放置弹出的html内容。放啥都行,也可以定义css。
另外还有一些参数,我都没用上官网说明文档里都有。
leaflet-geojson:
地理信息的json文件。中国的地理信息文件可以在阿里云下载,或者直接引用。建议下载后到mapshaper进行优化后上传,在本地使用。这里非常感谢明明桑,一个优化工具解决了困扰我许久的问题。
– src:地理信息源文件的路径,可以是相对路径或网址。
– color:leaflet提供的属性,边框颜色。
– weight;leaflet提供的属性,边框宽度。
– opacity:leaflet提供的属性,边框透明度。默认的3px蓝色实在是有点虎。缺点是每个marker都需要单独设置。
– fill:leaflet提供的属性,布尔型,是否填充。默认true
– fillColor:leaflet提供的属性,填充颜色,不设则默认使用color
– fillOpacity:leaflet提供的属性,填充颜色的透明度,默认0.2
想一个省一个省点亮的,就下载省级json,想像我这样一个市一个市点亮的,就下载市级json,一次勾一个边即可。话说,我一直认为用省划分习俗非常不科学,甚至用市来划分都不科学。毕竟有粤南粤北、胶东鲁西南,还有江苏十三太保这样的众所周知的文化差异。我甚至觉得应该精确到县。毕竟我们旁边就有一个散装的地级市,我认识一堆人,他们分别来自鲅鱼圈、熊岳、盖州、老边、大石桥,就没有一个称自己是营口人的。但是真正实装以后才发现,县级太困难了,我甚至都没在普兰店歇过脚,自己家都没搞定。
markerclustergroup:聚合分组方法,这是“扩展的扩展”的功能,也是安装它的主要目地。cluster是指将临近的点进行聚合,group是通过关键字对追加的点进行分组。只聚合可以用cluster,只分组可以用leaflet-optiongroup。
– feat:适配项目。可以是【leaflet-marker】中的title或者iconUrl中的一个。参数以部分匹配的方式,对title或者iconUrl形成过滤,然后在右上角形成组别。
– strings:分组过滤用的字符串,用半角逗号间隔。
– groups:分组后显示的字符串。
– position :分组显示位置
– collapsed :分组是否折叠
多说无益,直接举例
【leaflet-map fitbounds】//用fitbounds,就不用关心点的位置和缩放了 【fullscreen】//增加一个全屏按钮 【leaflet-marker lat=38.87430121 lng=121.55204380 iconUrl="/path_to/marker-blue.png" iconanchor="15,40" 】<b>辽师附中</b><i>2012 /04 /<a href="/2012/04/ancient-school-motto.html" target="_blank" rel="noopener">沙河口黑石礁尖山街</a> /街拍 </i><img src="/path_to/imag0114.jpg" alt="imag0114" />【/leaflet-marker】 【leaflet-marker lat=38.88611421 lng=121.63731716 iconUrl="/path_to/marker-blue.png" iconanchor="15,40" opacity=0.5】<b>西岗中学</b><i>2003 /05 /<a href="/2023/06/post-truth-and-something-before-my-graduation.html" target="_blank" rel="noopener">西岗八一三环街</a> /其他 </i><img src="/path_to/vlcsnap-2023-05-21-17h15m27s675.jpg" alt="vlcsnap-2023-05-21-17h15m27s675" />【/leaflet-marker】 【leaflet-marker lat=38.88890 lng=121.70665 iconUrl="/path_to/marker-yellow.png" iconanchor="15,40" 】<b>棒棰岛</b><i>1993 /08 /中山老虎滩迎宾路 /海滩 </i>【/leaflet-marker】 【leaflet-marker lat=38.93471 lng=121.19765 iconUrl="/path_to/marker-yellow.png" iconanchor="15,40" 】<b>北海王家村</b><i>2018 /08 /旅顺北海王家村 /海滩 </i>【/leaflet-marker】 【leaflet-marker lat=38.98562089 lng=121.65895298 iconUrl="/path_to/marker-yellow.png" iconanchor="15,40" 】<b>蟹子湾</b><i>2015 /04 /<a href="/2015/04/chemical-factories-stories.html" target="_blank" rel="noopener">甘井子甘井子海茂路</a> /海滩 </i><img src="/path_to/BF59AEE251904BC4.jpg" alt="BF59AEE251904BC4" />【/leaflet-marker】 【markerclustergroup feat="iconUrl" strings="blue, yellow" groups="学校, 海滩" collapsed=true】 【leaflet-geojson src="/path_to/dalian.json" color="#FF8888" weight=2 fillOpacity=0.3】//加入大连地图 【zoomhomemap】//调整缩放比[fullscreen ] [markerclustergroup feat=iconUrl strings=blue, yellow groups=学校, 浴场 collapsed=true ] [zoomhomemap ]
就到这。总之有现成儿的我才不会亲自动手呢。
相关推荐:
- 火神杯的bug[64%]
- NDSL恶魔城苍月十字架地图[64%]
- 每夫吐槽(112)[64%]
- 迄今为止的修改s[30%]
- 此插件甚得吾心[30%]
如何在本地调试WordPress时忽略对wordpress.org的网络连接请求
本地调试WordPress时,为了保证代码的正确性,插件和主题作者往往会打开wp-config.php里的WP_DEBUG开关。如果您不知道这个开关,就不要往下看了。
define('WP_DEBUG', true);
这样PHP运行时的错误和警告就会以醒目的字体直接打印到网页上。
![]()
但是这样会带来一个程序员的日经问题:是我的BUG我改,不是我的BUG莫挨老子!
按说WP这种成熟的产品是不会让用户看到警告和错误的。但是,由于众所周知的原因,WP内核、主题和插件升级所需要的WordPress的官网wordpress.org时灵时不灵,连不上的时候就会显示大面积的警告信息。
安装完成以后,后台这种需要连接到wordpress.org的地方大抵有4种:core update、theme update、 plugin update和translation api,出现在后台Dashboard、 Plugin、 Theme、 和Settings页面。其中Dashboard会调用前三种Update,Settings四种都会调用。
这些信息不仅是影响对于出错代码的判断(比如图中提示的“Cannot modify header information”,其实根本就不是本地header的问题),还会直接影响页面元素的渲染和操作。
那就必须要干掉它!
再次更新,
define('WP_HTTP_BLOCK_EXTERNAL', true);
这个宏屁用没用,还是得用我下面的方法。
开整。
//下面的action钩子调用的早,所以在加载主题或插件的时候就要直接remove掉,否则没机会了。
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
remove_action('admin_init', '_maybe_update_core');
remove_action('admin_init', '_maybe_update_plugins');
remove_action('admin_init', '_maybe_update_themes');
remove_action('init', 'wp_schedule_update_checks');
//translations_api默认会返回false,之后会访问wordpress.org,返回空数组之后就不访问了。
//Since 4.0.0
add_filter('translations_api', '__return_empty_array');
}
//调试者作为admin,默认是有各种update权限的。这里令各种内部调用user_has_cap询问4种权限的结果强行置为false。
function _debug_ignore_wp_request ($allcaps, $caps, $args){
$server_caps = array('install_languages', 'update_themes', 'update_plugins', 'update_core', 'install_themes', 'install_plugins');
foreach ($caps as $cap) {
if ( in_array($cap, $server_caps)) {
$allcaps[$cap] = false;
}
}
return $allcaps;
}
function my_admin_init {
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
//下面的钩子很多不能移除得太早。
//宁杀错不放过。
remove_action('upgrader_process_complete', 'wp_update_plugins');
remove_action('upgrader_process_complete', 'wp_update_themes');
remove_action('load-plugins.php', 'wp_plugin_update_rows', 20);
remove_action('load-themes.php', 'wp_theme_update_rows', 20);
remove_action('load-plugins.php', 'wp_update_plugins');
remove_action('load-themes.php', 'wp_update_themes');
wp_unschedule_hook('wp_version_check');
wp_unschedule_hook('wp_update_plugins');
wp_unschedule_hook('wp_update_themes');
remove_action('wp_version_check', 'wp_version_check');
remove_action('load-plugins.php', 'wp_update_plugins');
remove_action('load-update.php', 'wp_update_plugins');
remove_action('load-update-core.php', 'wp_update_plugins');
remove_action('wp_update_plugins', 'wp_update_plugins');
remove_action('load-themes.php', 'wp_update_themes');
remove_action('load-update.php', 'wp_update_themes');
remove_action('load-update-core.php', 'wp_update_themes');
remove_action('wp_update_themes', 'wp_update_themes');
remove_action('update_option_WPLANG', 'wp_clean_update_cache', 10, 0);
remove_action('wp_maybe_auto_update', 'wp_maybe_auto_update');
add_filter('user_has_cap', '_debug_ignore_wp_request', 10, 3);
}
}
add_action('admin_init','my_admin_init');
完事。这个世界清净了。
- (1):农历每年冬至所在的月固定为十一月。如果两个冬至间有13次朔望,则该年产生闰月。13个月中,第一个没有二十四节气里的偶数节气的月份就是闰月。因为十一月是起调点,所以农历十二月和正月是不会出现闰月的,正月初一和第一个节气春分受的影响也很小。我数学不好,但查表得到的结果,从1950年到2069的120年间,闰年就是双春,双春就是闰年,一一对应,无一例外。闰月是典型的用太阳历调整月历的规则,所以农历是阴阳历而不是纯阴(月)历。