普通视图

发现新文章,点击刷新页面。
昨天以前WordPress 果酱

WPJAM Basic - 样式定制:一键自定义 WordPress 前后台和登录页面

2025年5月6日 23:28

继续 #WPJAM Basic# 插件的详细介绍,前面介绍了「优化设置」还没有看的同学,可以先看一下,今天接着介绍「样式定制」的功能,「样式定制」也是 WPJAM Basic 最早开发的功能,开发这个功能主要是为了方便自定义网站。

简单说就是「样式定制」功能让用户可以在 WordPress 前后台和登录这三个主要不同的界面的头部(head)和底部(footer)插入一些定制代码,实现对网站页面样式和前端功能进行快速的定制。

因为是给三个主要不同的界面实现定制,那我们也分三个部分来讲解吧:

前台定制

前台定制的功能管的就是前台的页面了,通过前台 Head 代码前台 Footer 代码来定制前台的样式和功能。

这个功能对于有时候网站需要验证的时候有用,比如验证百度站长的时候,百度站长会给你两种选择:

  1. 让你在根目录上传一个 txt 文件
  2. 在头部的 Head 代码总加一段代码

如果不方便上传 txt 验证文件时候,直接把代码复制到这里的头部 Head 代码即可,即使方便的上传验证文件时候,把代码贴到这里也是更方便。

如果你的主题不支持暗黑模式,也可以通过把下面代码贴到这里的前台 Head 代码,也可以实现博客暗黑模式:

<style type="text/css">
@media (prefers-color-scheme: dark) {
html, img {filter: invert(1) hue-rotate(180deg);}
html, iframe {filter: invert(1) hue-rotate(180deg);}
img {opacity: .75;}
}
</style>

此外我在新版还增加了「文章页代码」选项,本来该功能是扩展,现在我把功能增加到「样式定制」功能中,因为这里使用起来比较顺手,不过做成了开关,开启可以单独设置每篇文章 head 和 Footer 代码。

先说下该功能的主要用途,主要是因为如果某些文章的展示的时候需要引入一些的 JS 和 CSS 来实现特殊的页面效果,怎么处理好呢?如果直接内容编辑框中插入,首先不是特别方便和友好,也可能由于安全或者其他的原因而造成插入失败。

「文章页代码」功能就是为该需求实现的,它可以让大家在文章编辑页面插入文章头部代码和底部代码:

另外他还可以让大家选择是否支持在文章列表页设置,有三个选项:支持,不支持,只允许,如果可以设置,在后台的文章列表页面中就有「文章页代码」按钮,如下图所示:

点击「文章页代码」按钮,就可以通过弹窗的方式来设置文章详情页的头部和底部代码:

后台定制

如上图所示,后台定制多了两个个功能,一个就是可以上传一个 40x40 大小的图片替换后台左上角的 WordPress 图标,另外一个是「后台右下角显示内存使用和 SQL 数量」,开启之后,在后台右下角显示:

其他和「前台定制」一样,也是通过后台 Head 代码后台 Footer 代码来定制后台的样式或者功能。

登录界面

登录界面也有两个额外的功能,首选是可以设置「登录之后跳转的页面」,比如可以设置网站首页,后台文章列表页面等等,另外一个是可以「屏蔽登录界面语言切换器」,这个不必多言。

其他一样可以设置 Head 和 Footer 代码,通过这两个值,可以做出自定义的登录界面。如果你懂 CSS,我们就可以自定登陆界面的 logo,甚至通过只用 CSS 就能做出非常漂亮的 WordPress 登录界面

关于样式定制,目前就提供了这些选项,基本满足简单定制的需求,该功能虽然偏向程序员使用,但是只要懂一些 CSS 和 JS,还是可以定制出很不错的 WordPress 后台,登录界面和前台的样式和交互。

WPJAM Basic - 优化设置:一键优化和增强 WordPress 功能

2025年5月6日 22:42

#WPJAM Basic# 插件的「优化设置」是 WPJAM Basic 插件的开端,可以说是我爱水煮鱼博客多年使用 WordPress 的经验而整理的优化插件。

我们 WordPress JAM 为了在定制开发的时候方便,就把各种用不上的功能,或者可能影响性能的功能,都提供开关,只需要一键搞定。

经过几年的发展,优化设置的功能分成功能屏蔽和增强优化两大块:

功能屏蔽

上图可以很清楚看到,功能屏蔽就是让你屏蔽 WordPress 中一些用不上的功能,我把功能屏蔽分成六大块:

常规功能

屏蔽文章修订功能,精简文章表数据。

WordPress 的文章版本修订功能是通过在 wp_posts 表中增加一条记录来实现的,这样如果修改了几次,就会有好几个修订版本,插入好几条记录。

如果经常修改文章或者博客有多个作者的话,每篇文章记录在 posts 表中都会有多条记录,文章一多,wp_posts 表的数据就会急剧上升,数据表的增大,最后自然影响了查询,肯定会变慢。所以建议屏蔽文章修订功能,提高数据库效率。

彻底关闭Trackback,防止垃圾留言。

Trackbacks 是被设计出来用于博客间交流,但实际上这样的应用很少,反而被 Spammer 滥用,并且各种防垃圾评论插件比如 Akismet 也经常漏掉,可以说防不胜防,Trackback 真的让人不慎其烦,建议彻底关闭 WordPress 的 Trackback。

关闭XML-RPC功能,只在后台发布文章。

XML-RPC协议用于客户端发布文章,如果只是在 WordPress 后台发布,可以关闭 XML-RPC 功能,提供 WordPress 的安全性。

关闭自动更新功能,通过手动或SSH方式更新。

WordPress 的更新服务器在国外,并且没有在国内开启加速服务,所以 WordPress 在后台检查更新的时候,可能因为各种原因无法顺畅连接上,然后一直卡着,造成 WordPress 后台有时很慢很慢。建议关闭 WordPress 后台和自动更新功能,通过手动或者SSH方式更新WordPress。

屏蔽站点Feed,防止文章被快速被采集。

WordPress Feed 主要用于阅读器使用,但是现在使用阅读器的用户越来越少,而 Feed 更多成为了一些垃圾站快速全文采集的方式,造成不必要的资源消耗,建议关闭站点 Feed。

屏蔽站点管理员邮箱定期验证功能。

WordPress 会在每六个月管理员再次登录之后,会看到站点管理员的邮箱地址验证界面,这是担心管理员的邮箱不再使用,引起一些安全的问题,让管理员再次确认,如果不会这方面的问题,觉得没有必要,可以屏蔽邮箱验证。

转换功能

屏蔽Emoji转换成图片功能,直接使用Emoji。

WordPress 使用图片来渲染Emoji表情文字,但是渲染图片经常打不开,并且现在主流浏览器都已经支持Emoji文字,并且现在绝大部分服务器的 MySQL 数据库(5.5版本之后)都支持 utf8mb4 编码格式,所以无需将 Emoji 转换成 HTML 实体进行存储了,直接存储速度更快,节省了实体转换的时间消耗。建议屏蔽 Emoji 功能。

屏蔽字符转换成格式化的HTML实体功能。

WordPress会将一些纯文本字符转换成格式化的 HTML 实体,但是这些转换并不适合中文环境,所以我们最好去掉这些字符转换,也能节约这些转换所消耗的时间。

屏蔽WordPress大小写修正,自行决定如何书写。

WordPress 默认会把 Wordpress 这样的写法转换成 WordPress,就是中间的 P 会变成大写。如果熟悉 WordPress 的用户,都会正确 WordPress 模式书写,所以从效率优先考虑,没有必要浪费时间在这个转换上面,一样一键移除。

后台功能

后台功能移除为欧洲通用数据保护条例生成的页面。

GDPR 是欧洲的通用数据保护条例,它制定了非常严格的隐私条例,WordPress为了适应该法律,在后台设置很多隐私功能,如果只是在国内运营博客,可以移除后台隐私相关的页面。

移除仪表盘的「WordPress 活动及新闻」。

WordPress 后台仪表盘页面会有「WordPress 活动及新闻」功能,但是大部分都是英文文章,如果你不想出现,可以一键移除。

移除后台界面右上角的帮助和选项。

WordPress 后台很多页面右上角,比如后台文章列表页面,都会有「显示选项」和「帮助」这两个按钮,一个是用来显示和设置该页面的选项,一个是用来获取该页面的帮助信息:

此图片的alt属性为空;文件名为1646055773-image.png

首先这两个按钮都在右上角,很多用户都不会特别注意,以至于自己操作了都忘记了,并且帮助文档对用户也帮助不大,建议两个都移除。

页面功能

页面功能移除页面头部版本号和服务发现标签代码。

WordPress 会在页面的头部输出版权信息和其他服务发现代码,版权信息代码会让用户知道你的目前运行的 WordPress 的版本,而服务发现代码则可以说明你的博客支持哪些服务。

这些代码在前台反而会引起一些安全的问题,最好一键去掉。

移除工具栏和后台个人资料中工具栏相关选项。

一般不建议在网站前台显示 WordPress 工具栏,所以可以一键移除。

嵌入功能

嵌入功能禁用Auto Embeds功能,加快页面解析速度。

Auto Embeds协议让你插入一个视频网站或者图片分享网站的链接,这个链接里面含有的视频或者图片就自动显示出来,但是该功能支持的网站都是国外的,如果运营的是中文博客,建议禁用 Auto Embeds 功能,加快页面解析速度。

屏蔽嵌入其他WordPress文章的Embed功能。

文章Embed功能让你可以在WordPress站点用嵌入的方式插入本站或者其他站点的WordPress文章。如果你不需要,可以屏蔽文章Embed功能。

古腾堡编辑器

屏蔽Gutenberg编辑器,换回经典编辑器。

WordPress 5.0 发布带来的 Gutenberg 编辑器,也叫区块编辑器,这个编辑器很酷,但是很多人不习惯,还是喜欢原来简简单单的编辑,name可以屏蔽 Gutenberg。

屏蔽小工具区块编辑器模式,切换回经典模式。

同样主题的小工具功能,新版 WordPress 也同样使用区块编辑器模式,你如果习惯了原来的经典模式,也可以一键屏蔽,切换回经典模式。

增强优化

增强优化主要将 WordPress 一些资源加速优化,并且添加一些常用的小功能,目前有以下的功能:

前端公共库

我们常用的 JS 库,比如 jQuery / Underscore 这些,网上都有提供免费的公共库,这里提供几个常用的前端公共库,可以根据自己的喜欢选择。

Google 字体加速服务

Google 字体很好用,很方便,WordPress 很多主题也使用了 Google 字体,但是 Google 在线字体在国内的速度不是很快,甚至有时候还无法打开,这也是 WordPress 有时候在国内速度不够快的原因。

WPJAM Basic 可以让选择第三方 Google 字体字体加速服务,也可以自定义输入加速服务地址:

详细介绍:使用 Google 字体加速服务,加快 WordPress 打开速度

Gravatar 加速服务

Gravatar 部分 CDN 服务器在国内访问困难,出现头像无法显示的问题,而 WordPress 后台或者评论页有时候默认加载 Gravatar 头像图片的,这样就可能造成页面卡死的情况。

WPJAM Basic 可以让选择第三方 Gravatar 镜像加速服务,也可以自定义输入加速服务地址:

详细介绍:使用 Gravatar 加速服务,加快 WordPress 打开速度

Frame 嵌入

WPJAM Basic 可以让你直接在后台设置 Frame 嵌入,避免点击劫持,增强网站的安全性:

详细介绍:如何防止 WordPress 页面被 Frame 嵌入

分类链接简化

去掉 category 的分类目录和 WordPress 的页面的 URL,这两种页面的页面rewrite 规则是不是一样的,那么我们可以直接使用页面的 rewrite 规则来处理了。

WPJAM Basic 还额外增加一个选项,如果博客自定义了其他的自定义分类模式,可以选择设置哪个分类模式应用该功能:

详细介绍:去掉 WordPress 分类目录 URL 中的 category 最佳方法

图片时间戳

如果长期上传的图片名字都是 1.jpg 的话,那么上传一张图,会造成数据库进行几十到上百次的 SQL 查询,应该在上传的时候把图片的名字更改了,给图片的名字加多一个时间戳,这样就能几乎保证图片名字不可能重复了:

详细介绍:如果经常在 WordPress 上传同名的图片,最好开启这个选项

之前还有一些优化增强功能,我因为各种原因去除或者移到别的插件。

  • 搜索结果快速跳转:提高搜索效率,当搜索结果只有一篇时直接重定向到文章该功能已经移到搜索优化插件。
  • 禁止admin用户名:使用admin作为用户名是最大的安全漏洞,建议禁止使用 admin 用户名尝试登录 WordPress,提高网站的安全性。很多人因为用户名是 admin,又开启这个功能,然后站点登录不了,然后说 WPJAM Basic 的问题,忍疼删除该功能,大家记得不要设置 admin 的用户名。
  • 前台不加载语言包:WordPress加载语言包是需要花费 0.1-0.5 秒不等的时间,如果对性能要求极致,可以前台不加载语言包,但是要把主题文件中的描述改成中文。很多人设置了该功能,前台出现英文,说WPJAM Basic 乱改,所以继续忍疼删除该功能。
  • 媒体文件默认链接到:无/媒体文件/附件页面,该功能已经迁移到图片集插件。

CloudFlare CDNJS:免费加速你的前端资源

2025年4月28日 14:18

我们前面介绍了 CloudFlare 的 R2 服务:Cloudflare R2 对象存储白嫖指南:10G存储+免流量费,打造免费图床,其实 CloudFlare 还有另外一个我们使用比较多的服务,就是 CDNJS 服务。

什么是 CDNJS?

CDNJS 是 Cloudflare 维护的一个免费开源 CDN 服务,专门托管热门的前端库(如 jQuery、React、Vue、Font Awesome 等),开发者只需通过简单的链接引用,就能让全球用户快速加载这些资源,无需自己部署服务器。

它有如下的核心优势:

✅ ​全球加速:依托 Cloudflare 的全球 CDN 网络,资源加载更快。
✅ ​自动同步:与 npm/GitHub 同步,确保使用最新版本。
​完全免费:零成本使用,无需担心带宽费用。
✅ ​广泛兼容:支持传统 JS、ES Modules、WASM 等多种格式。

CDNJS 的发展历程

CDNJS 最初是由 ​Thomas Davis​(前端开发者,当时就职于 Twitter)于 ​2011 年 创建,并联合开源社区共同维护,初期只是托管几十个热门库。

当初发起这个库的最大原因就是为了解决开发者直接托管第三方库(如 jQuery)的痛点:

  • 带宽成本高:小团队或个人开发者自建 CDN 成本高昂。
  • 更新延迟:手动下载和部署库版本效率低下。
  • 全球化需求:当时已有的 CDN(如 Google Hosted Libraries)覆盖节点有限。

2014 年接手 CDNJS 的服务器和网络基础设施,并提供了企业级基础设施和全球 CDN 节点支持。

2016 年引入自动化 npm/GitHub 同步,大幅提升效率。

2020 年开始支持现代 Web 技术(如 WASM、ES Modules)。

为什么需要 CDNJS?

自托管 vs. CDNJS

对比项自托管CDNJS
加载速度依赖自身服务器带宽全球 CDN 加速
维护成本需手动更新版本自动同步最新版
缓存命中率仅限自身用户全球共享缓存,命中率更高
可用性服务器宕机=资源不可用高可用性,99.99% SLA

适用场景

  • 个人博客、小型网站(节省带宽成本)
  • 企业级应用(提升全球访问速度)
  • WordPress 等 CMS(优化前端性能)

如何使用 CDNJS

在 HTML 中直接引用 CDNJS 链接即可:

<!-- 加载 jQuery -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>

<!-- 加载 Font Awesome CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" />

如要增强安全性,可以使用 ​SRI(Subresource Integrity)​ 防止资源被篡改:

<script 
  src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"
  integrity="sha256-kmHvs0M+1Qz9wuZOJ8E6OE2bM4S4n2GeXJ6X5+5ow="
  crossorigin="anonymous"></script>

由于 CloudFlare 在国内没有加速节点,国内访问可能会有些慢,所以推荐一些国内的 cdnjs 的镜像服务:

服务商特点延迟(国内/国外)
CloudFlare
https://cdnjs.cloudflare.com
✅ 全球加速
⚠️ 国内速度较慢
528 ms / 4 ms
又拍云 CDN
https://s4.zstatic.net
✅ 镜像自 Cloudflare CDNJS
✅ 库齐全,国内速度快
30 ms / 8 ms
字节跳动 CDN
https://cdn.bytedance.com
✅ 速度快企业级稳定性
⚠️ 但库较少,仅 JS 无 CSS 库
27 ms / 216 ms
360 前端静态资源库
https://lib.baomitu.com
⚠️ 更新不太及时
⚠️ 库较少
13 ms / 3 ms
SM.MS
https://cdnjs.loli.net/ajax/libs
✅ 镜像自 Cloudflare CDNJS
⚠️ 个人开发者
160 ms / 8 ms
7ED
https://use.sevencdn.com
✅ 镜像自 Cloudflare CDNJS
⚠️ 个人开发者
33 ms / 180 ms

如果你使用的是 WordPress 博客,那么 #WPJAM Basic# 插件也提供了一个前端公共库,让你一键切换,在「WPJAM」-「优化设置」-「增强优化」:

目前已经内置了下面这几家:

cdnjs.cloudflare.com
s4.zstatic.net
cdnjs.snrat.com
lib.baomitu.com
cdnjs.loli.net
use.sevencdn.com

根据上面的推荐,国内最佳可能是 s4.zstatic.net,具体还是需要你自己切换和体验。

CDNJS 总结

CDNJS 是前端开发者的利器,能显著提升资源加载速度并降低维护成本。

  • 全球用户 → 直接使用 cdnjs.cloudflare.com
  • 国内优化 → 切换至 s4.zstatic.net
  • WordPress → 通过 WPJAM Basic 插件一键配置

Cloudflare R2 对象存储白嫖指南:10G存储+免流量费,打造免费图床

2025年4月25日 10:15

网站的图片和静态资源使用 CDN 加速是常见的操作,并且很多许多对象存储的服务商都提供了「免费」的额度,看起来很爽,但是万一被刷之后就很不爽了:

那么有没有一款不怕被刷的对象存储呢?答案是有的,还是你熟悉的赛博善人 CLoudFlare R2对象存储

CLoudFlare R2

R2 是 Cloudflare 推出的对象存储服务,主打零出口费用(也就是免流量费)和与 Amazon S3 兼容的 API,适合存储大量数据且需频繁访问的场景,完美解决传统图床的痛点:

  • ✅ ​不怕被刷流量:下载请求1000万次/月免费,超限后仅$0.36/千万次
  • ✅ ​全球加速:虽不及国内CDN,但实测白天可达50MB/s(速度测试截图)
  • ✅ ​完全兼容S3 API:适配所有主流图床工具(如PicGo、WordPress插件)

更重要的是并且 R2 的免费额度非常的大,以下是R2的核心定价和免费额度:​

罗列了个表格:

类别内容免费额度超出部分费用
💾 存储存储空间10GB/月 免费
可存5万张2MB图片
每增加 1GB 收费 $0.015 美元(约 $15/TB)
🔄 A 类操作上传、列出100 万次/月 免费
每天3.3万次
每增加 100 万次 收费 $4.50 美元
🔁 B 类操作下载、读取1000 万次/月 免费
每天33万次
每增加 1000 万次 收费 $0.36 美元
⏬ 出口流量访问数据时的流量全免无任何费用

出口费用全免!当然有些人还是会说下载、读取次数被刷怎么办?1000万次才收费0.36美元,真的会有人去刷 CF 的 R2 吗?

为了防止“被刷”(抬杠),我们稍后介绍下强制缓存、速率控制的设置方法(进一步规避被刷风险)。

实战步骤:从创建到防刷

下面我们就一步一步教大家如何开启 CloudFlare R2 服务:

1. 创建 R2 存储桶

官方网址:https://www.cloudflare.com/zh-cn/

打开并注册 CF 账户(不是,你不会还没有CF账户吧?😁)进入「R2 对象存储」:

添加支付信息,这里需要一张外币卡 或者 Paypal

完成之后,就可以「创建存储桶」

点击「创建存储桶」:

  • 存储桶名称:自己填写
  • 位置:亚太地区 或 北美洲西部 (实际速度差不多)
  • 默认存储类:标准(不能选不频繁访问,没有免费额度)

这样就创建完成了!这时候就可以直接在页面上上传和删除等操作。

添加你的图床域名,当然主域名要先托管到CF,也可以按需开启 R2.dev 子域名

​按需设置CORS 策略等:

2. 创建 R2 API

按照下面的路径进行操作,账户API、用户API均可:

「R2对象存储」-「API」-「管理API令牌」-「创建API令牌」

其中权限选择「管理员读和写」,对象读和写也可以,不过要指定桶。

创建好后会出现API密钥等信息,请保存好,以后一些插件、软件都会用到

关键防护配置

虽然 R2 基本不怕被刷,但是如果你还有这方面的担忧,可以通过下面三步操作基本杜绝这方面的问题:

1. 设置图片缓存规则

设置这个主要是为了进一步防止被刷下载次数(虽然也基本没人去刷CF的R2),先点进去域名:

然后选择「规则」-「页面规则」-「创建页面规则」:

其中:

  • URL:https://img.ssqq.de/*​ 要带https,后面 /*
  • 浏览器缓存 TTL:1天
  • 边缘缓存TTL:1个月(也可以适当降低,如果你经常更换图片的话)
  • 缓存级别:缓存所有内容
  • 源服务器缓存控制:添加但不开启!

这样缓存规则就设置完毕了!

2. 设置速率限制

还通过设置速率限制防止恶意请求:

选择「安全性」-「WAF」-「速率限制规则」-「创建规则」:

​其中:

  • 规则名称:随意
  • 字段:URL路径、包含、/​
  • 当速率超过...:100​,10秒钟
  • 然后采取措施…:阻止

这里重点是【当速率超过...】这个选项,推荐100甚至更多一点,不建议填写太低,很容易误伤;意思是同一个 IP 10 秒内请求超过多少张图片,就触发操作(按照你站点图片情况设置)

3. 设置图片防盗链

这个可以按需添加,主要是防止别的网站盗用你的图床的图片,在别的网址引用图床链接就会提示错误,但是直接请求的方式就还是能打开!

选择「安全性」-「WAF」-「自定义规则」:

  • 主机名:等于,img.ssqq.de (图床域名)
  • And:右边添加一个 And
  • 引用方:不等于,www.xiaoge.org(你的博客域名)
  • 然后采取措施...:阻止

工具链推荐

CloudFlare 的 R2 是兼容 Amazon S3 对象存储的,所以有很多配合的软件可以使用,例如:

PHP 8 重大变更:is_callable() 不再支持类名+非静态方法检查,强制返回 false!

2025年4月18日 00:10

最近在 PHP 8 环境下,发现 #WPJAM Basic# 的一个严重问题:就是后台文章和分类列表的一些操作无效了,点击保存按钮没有任何反应。经过深入调试,发现问题根源在于 PHP 8 对is_callable()函数的行为进行了重大调整。

技术细节

在 PHP 8 之前,is_callable() 函数在检查类名与非静态方法的组合时会返回 true,即使这种调用方式在实际执行时可能会导致问题。PHP 8 对此进行了更严格的检查,以提前发现潜在的错误调用方式,因此 is_callable() 在检查一个类名与非静态方法时将返回失败(应当检查一个类的实例)。

具体看下面这个例子就大概能够明白了:

class Test{
    public function method1() { }
    public static function method2() { }
}

// PHP 8 之前
var_dump(is_callable(['Test', 'method1']));	// bool(true)
var_dump(is_callable(['Test', 'method2']));	// bool(true)

// PHP 8 之后
var_dump(is_callable(['Test', 'method1']));	// bool(false)
var_dump(is_callable(['Test', 'method2']));	// bool(true)
var_dump(is_callable([new Test, 'method1']));	// bool(true)

变更原因

PHP 8 的这一变更是为了更严格地执行面向对象编程规范:

  1. 静态与非静态方法调用的区分:非静态方法需要类的实例才能调用,而静态方法可以直接通过类名调用。
  2. 提前错误检测:在 PHP 7 及以下版本,虽然 is_callable() 会返回 true,但实际以静态方式调用非静态方法时会产生警告。PHP 8 通过 is_callable() 提前返回 false 来更早发现问题。
  3. 代码质量提升:强制开发者明确方法调用的上下文,避免模糊的调用方式。

解决方案

既然知道这个原因,那就是代码要根据上下文来写了。所以如果要检查某个对象的非静态方法是否可调用,应该使用一个对象实例而不是类名。

此外,其实很多时候我们只需要检查类的方法是否存在,而不关心其可调用性(例如访问控制),那么可以简单使用 method_exists() 进行判断就好了:

if (method_exists('Test', 'method1')) {
    // Do something
}

WordPress 6.8 发布,速度更快、防护更强、使用更顺手!

2025年4月16日 16:50

WordPress 6.8 正式版发布了,按照 WordPress 官方说法,这是一个精雕细琢的版本,对日常使用的工具进行了全面的打磨和升级,让你的网站运行更快、防护更强、使用更顺手

样式手册全面优化

样式手册(Style Book)采用结构化布局设计,界面更加清爽直观,通过清晰的标签,让管理员可以轻松管理全站的颜色、字体等样式设置。

特别值得一提的是,现在样式手册还兼容经典主题,只要主题包含 editor-styles.css 文件或 theme.json 配置文件,就能在「外观」>「设计」中使用这一功能,在编辑 CSS 或使用定制器时,所有样式更改都能实时预览,让设计过程更加直观高效。

编辑器改进

数据视图(Data Views)的选项展示更加清晰明了,现在可以轻松地从查询循环中排除置顶文章。此外,编辑器还包含了70多处细节优化,从内容排版到最终发布,整个创作流程都变得更加流畅自然。


极速预加载技术

WordPress 6.8 引入了极速预加载技术(Speculative Loading),它能够在用户鼠标悬停或点击链接时,会自动预加载下一页内容,使页面跳转几乎达到瞬时完成的效果。开发者还可以通过插件或自定义代码来调整预加载策略,最后这项功能仅在现代浏览器中生效,对老旧浏览器则完全无影响。

更强的哈希算法

WordPress 6.8采用了更强大的bcrypt哈希算法,这种算法算法需要消耗大量计算资源才能破解,使得密码保护更加牢不可破。此外所有安全升级都是自动完成的,管理员无需进行任何额外操作,系统就会自动将现有密码迁移到新的加密方式。

性能提升

在无障碍体验方面,WordPress 6.8 做了 100 多项修复和增强,涵盖 WordPress 体验的方方面面,修复了所有内置的主题,改进了导航菜单管理、自定义工具,并简化了标签功能等,并且针对区块编辑器的块、数据视图及其整体用户体验也进行了 70 多项改进。

在性能方面,WordPress 6.8 也做了一系列的修复和增强,提升了从编辑到浏览的各项功能,除了前面预测加载之外,还特别优化了区块编辑器、块类型注册和查询缓存,朝着任何交互的等待时间都不会超过 50 毫秒这个目前前进。

数据库查询性能也得到显著提升,特别是优化了WP_Query类的缓存键生成机制,有效降低了高并发访问时的服务器负载,让网站在流量激增时也能保持稳定运行。

WPJAM Basic 昨天也更新到了 6.7.6 版本,我也会很快同步更新到 6.8 版本,并且我会根据 WordPress 6.8 持续更新,注重兼容性和性能优化,如有使用问题,也欢迎反馈到知识星球。

手把手教你使用 netcup 服务器的 SCP 面板一键重装系统

2025年4月24日 22:50

🪧 先打个小广告,我和 VERKY 创建了「VPS 交流/分享/评测的微信群」,欢迎大家加入,可以先加 VERKY 个人号(微信号:PSD404),再拉你入群,与 300+ VPS 玩家共同探讨!

前面我们介绍了「高性能/高性价比欧洲服务器首选:netcup(网杯) 介绍 | 附免税注册与优惠码」,很群里面购买了的小伙伴需要更换操作系统或恢复初始状态,就在问 netcup 如何重装系统?

其实 netcup 可以通过 ​SCP(Server Control Panel)面板 快速重装系统,今天就整理了一篇详细的图文教程,手把手教你使用 netcup 的 SCP 面板重装系统。

开始之前提醒大家,重装系统会清空全部数据!​所以重装前请备份重要文件,确保 VPS 没有运行关键服务,避免影响业务。

1️⃣ 登录 netcup 的 SCPSCP地址:https://www.servercontrolpanel.de,也可以在 netcup 的 ccp 后台直接跳转。

nc-reinstall-1.png

输入你的 ​服务器IP 和 ​SCP密码 登录,首次购买后,SCP 密码会通过邮件发送至你的注册邮箱。

2️⃣ 选择镜像,点击「Media」菜单,然后选「Image」:

nc-reinstall-2.png
nc-reinstall-3.png

3️⃣ 设置分区,其中 Partition layout 选 one big partition with os as root partition.(一个大分区,作为系统根分区),然后其他都不用改,直接点击下一步。

nc-reinstall-4.png

4️⃣ 确认并开始重装,系统会要求再次输入 ​SCP 密码 确认操作。

nc-reinstall-5.png

5️⃣ 等待完成,这时候请不要关闭界面!重装过程通常需要 ​5-15 分钟,完成后,页面会显示 ​新的 root 密码,记得复制并保存好。

nc-reinstall-6.png

至此使用 netcup 的 SCP 面板重装系统就完成了。🎉

🪧 最后再次提醒一下:

📌 我和 VERKY 创建了「VPS 交流/分享/评测的微信群」,欢迎大家加入,可以先加 VERKY 个人号(微信号:PSD404),再拉你入群,与 300+ VPS 玩家共同探讨!

如有其他问题,欢迎在评论区留言~ 💬

WordPress 官方推出了 AI 建站工具,让你分分钟就打造美观网站

2025年4月15日 11:56

WordPress 在其官方托管 SasS 平台正式推出了一款全新的 AI 驱动网站构建器,这款工具可以在几分钟内为用户创建出功能齐全、外观美观的 WordPress 网站。用户只需通过聊天机器人输入相关提示,便可生成包括文本、布局和图像等在内的网站内容。

WordPress 官方推出的这款 AI 网站构建器操作异常简便,对技术背景几乎没有任何要求,用户可以告诉 AI 自己需要建立个人网站还是商业网站,并描述希望的页面元素,如标题外观、配色方案等,AI 系统便会根据这些指令自动生成网站的基本框架。

越具体的初始提示将带来更理想的结果,在生成网站时,聊天机器人会询问一些关键信息,例如公司名称和位置。生成完成后,网站将包含 AI 生成的标题、图片和文本。

这一功能特别适用于企业家、自由职业者、博主等需要快速建立专业网络形象的群体,值得注意的是,虽然这款 AI 网站构建器功能强大,但目前仍主要适用于生成简单的页面。对于需要更复杂集成的网站,如电子商务商店等,暂时还无法直接通过该工具创建。

为了让用户充分试用这一新功能,WordPress.com 也为用户提供了 30 次免费提示额度,对于开发者,还可以将 AI 生成的网页切换回手动编辑的模式,自己再次修改。

一旦网站构建完成,用户可以将其转移到 WordPress.com 的托管服务上,继续手动编辑或重新返回 AI 构建器进行调整。而使用 WordPress.com 的托管计划,费用起价为每月18美元。另外需要注意的是,这个工具目前仅适用于新创建的站点,已经存在的网站则无法使用。

不过这项服务目前仅限于 WordPress 官方运营的 SaaS 平台 WordPress.com,对于自己托管的 WordPress 独立站点,暂时还没有提供相应的插件。不知道 WordPress 官方之后是否将其开源。

地址:https://wordpress.com/ai-website-builder/

VPS 新手必看:拿到服务器后这 3 项关键优化建议你要去做!

2025年4月11日 19:13

VERKY 和我创建了「VPS 交流/分享/评测的微信群」(还没加入的同学,可以先加 VERKY 个人号(微信号:PSD404),再拉你入群)之后,碰到群里面问的最多的一个问题就是:VPS 用不用做一些「优化」。

刚拿到 VPS 时,很多人会纠结是否需要优化。虽然不优化也能用,但简单的几步设置就能显著提升安全性、网络速度和稳定性。本文分享 ​3 个最实用的 VPS 优化操作,涵盖 ​SSH 安全加固、IPv4/IPv6 优化、BBR 加速,适合新手快速上手。

⚠️ ​重要提醒:所有操作前请​备份数据,避免误操作导致数据丢失。

1. 安全加固:修改默认 SSH 端口

建议程度:⭐️⭐️⭐️⭐️⭐️

为什么要改 SSH 端口?

  • 默认 ​SSH 端口 22 是黑客扫描的主要目标,如果再加上你的密码较弱,服务器可能被暴力破解。
  • 修改为 ​高位端口(如 50000+)​ 能减少 90% 以上的恶意扫描攻击。

那么如何修改 SSH 端口?首先可以通过纯命令行手动修改​

1. 编辑 SSH 配置文件:

sudo nano /etc/ssh/sshd_config

2. 找到 #Port 22,去掉 # 并修改端口(如 Port 54321)。

3. 重启 SSH 服务生效:

sudo systemctl restart sshd

​4. 测试新端口能否连接

如果命令行队你有难度,也可以试试在宝塔和 1Panel 等这些主流面板去修改:

宝塔面板安全 → SSH 端口修改

1Panel安全 → SSH 设置

修改后请一定要记住 SSH 端口哈,当然不想修改的也可以通过安装 Fail2ban ​等工具,达到避免暴力破解的目的,这里暂不做介绍,感兴趣的可以去了解下。当然使用密钥登录更安全,进阶用户可以自己去试试。

2. 网络优化:强制 IPv4 优先访问

建议程度:⭐️⭐️⭐️

为什么 IPv4 优先?

  • 部分 VPS 的 ​IPv6 路由较差,并且优化线路可能只优化了 v4,所以 IPv6 可能导致访问延迟高、丢包严重。
  • ​目前在跨国和跨运营商的骨干网络当中通常 IPv4 更稳定,而 IPv6 可能绕路,也可能会因为地区或运营商的问题,增加网络延迟或丢包情况。

如何设置 IPv4 优先?

1. 先测试当前优先协议:

curl ip.p3terx.com

如果返回 IPv6 地址,说明当前 IPv6 优先。

2. 修改 /etc/gai.conf 强制 IPv4 优先:还是免责申明的那句话,动手前请先备份❗️❗️❗️(我已经打了三个感叹号❗️造成了问题,可别找我 😂)

sudo cp /etc/gai.conf /etc/gai.conf.bak  # 先备份
sudo nano /etc/gai.conf

取消注释或添加以下行(确保 IPV4 优先)

sudo precedence ::ffff:0:0/96  100

设置后一般立马生效,可以再执行一下上面的 CURL 命令验证下优先。

3. 如需回滚备份

sudo cp /etc/gai.conf.bak /etc/gai.conf

⚠️ ​注意事项

  • 某些云服务商可能需要额外配置,建议先咨询厂商。
  • 如果 IPv6 在你的网络环境下更快,可以跳过此优化。

3. 性能调优:一键开启 BBR+FQ 网络加速

建议程度:⭐️⭐️⭐️⭐️

BBR 和 FQ 是什么?为什么能加速?

BBR(Bottleneck Bandwidth and Round-trip propagation time)​ 是 Google 开发的 TCP 拥塞控制算法,通过动态调整发包速率(基于带宽和延迟),提高带宽利用率,尤其适合高延迟、跨国网络(如国外 VPS)。BBR 可提升 ​20%~50% 传输速度,减少缓冲和卡顿。

FQ(Fair Queueing,公平队列)​ 是一种网络流量调度算法,用于管理数据包的传输顺序,确保不同网络连接能 ​公平共享带宽,避免单一连接占用过多资源,从而提高网络稳定性和响应速度。

BBR+FQ 是非常经典的优化组合,相比默认的 CUBIC,能够提高吞吐量和减少数据包排队时间,以达到降低些许延迟,提升访问速度的目的。

TCP加速 一键安装管理脚本

wget -O tcpx.sh "https://github.com/ylx2016/Linux-NetSpeed/raw/master/tcpx.sh" && chmod +x tcpx.sh && ./tcpx.sh

选择11项,BBR+FQ​加速即可:

加群,获取更多优化技巧

最后如果你对 VPS 还有什么优化的建议,欢迎加入我们 ​「VPS 交流/分享/评测的微信群」(添加微信 ​PSD404,备注「优化」入群),与 300+ VPS 玩家共同探讨! 🚀

📌 ​提示:优化效果因服务商和网络环境而异,建议先测试再部署到生产服务器。

DMIT LAX.EB 大杯补货!美西3网优化CMIN2+9929 年付49.9美元起!

2025年4月3日 22:49

大妈(DMIT) EB 系列终于返厂了,这次补货的是大杯和超大杯!

套餐详情

LAX.EB.CORONA

  • CPU:1核(EPYC 9654)
  • 内存:1GB
  • 硬盘:20GB SSD
  • 流量:2000GB /月流量(2Gbps)
  • 回程:三网优化(9929&cmin2)
  • IP:1 IPv4 & 1 IPv6 /64
  • 价格:49.9美元/年
  • 购买链接https://www.dmit.io/aff.php?aff=9154&pid=218

LAX.EB.FONTANA

  • CPU:2核(EPYC 9654)
  • 内存:2GB
  • 硬盘:40GB SSD
  • 流量:4000GB /月流量(4Gbps)
  • 回程:三网优化(9929&cmin2)
  • IP:1 IPv4 & 1 IPv6 /64
  • 价格:100.00美元/年
  • 购买链接https://www.dmit.io/aff.php?aff=9154&pid=219

每15天可以免费更换1次ip,国内优化直连保障

性能测试

测试 IP:154.17.226.2

全国TCPing:三网回程优化,一片绿(晚间测试)。

探针表现:三网平稳,高峰期无波澜。

基础信息

--------------------------------------系统基础信息--------------------------------------
 CPU 型号            : AMD EPYC 9654 96-Core Processor @ 2396.398 MHz
 CPU 数量            : 1 Virtual CPU(s)
 CPU 缓存            : 512 KB
 AES-NI              : ✔️ Enabled
 VM-x/AMD-V/Hyper-V  : ✔️ Enabled
 内存                : 283.62 MB / 958.71 MB
 气球驱动            : ✔️ Enabled
 虚拟内存 Swap       : 0.00 MB / 1024.00 MB
 硬盘空间            : 3.69 GB / 19.60 GB
 启动盘路径          : /dev/vda1
 系统                : debian 12.9 [x86_64] 
 内核                : 6.1.0-21-amd64
 系统在线时间        : 0 days, 00 hours, 34 minutes
 时区                : UTC
 负载                : 0.17 / 0.10 / 0.03
 虚拟化架构          : KVM
 NAT类型             : Full Cone
 TCP加速方式         : bbr
 IPV4 ASN            : AS906 DMIT
 IPV4 Location       : Los Angeles / California / United States
 IPV6 ASN            : AS906 DMIT
 IPV6 Location       : Los Angeles / California / United States
 IPv6 子网掩码       : /64

CPU / 内存 / 硬盘

--------------------------------CPU测试-通过sysbench测试--------------------------------
1 线程测试(单核)得分:   4364.81
--------------------------------内存测试-通过sysbench测试---------------------------------
单线程顺序写速度: 30915.78 MB/s(32.42K IOPS, 5s)
单线程顺序读速度: 46886.73 MB/s(49.16K IOPS, 5s)
-----------------------------------硬盘测试-通过fio测试-----------------------------------
测试路径      块大小   读测试(IOPS)            写测试(IOPS)            总和(IOPS)
/root         4k       62.55 MB/s(15.6k)       62.66 MB/s(15.7k)       125.21 MB/s(31.3k)      
/root         64k      1.07 GB/s(16.6k)        1.07 GB/s(16.7k)        2.14 GB/s(33.4k)  
/root         512k     1.02 GB/s(1995)         1.08 GB/s(2101)         2.10 GB/s(4096)   
/root         1m       1.01 GB/s(989)          1.08 GB/s(1055)         2.09 GB/s(2044) 

CPU性能不错,磁盘 IO 为 nvme 水准。

Geekbench 5 Benchmark Test:
---------------------------------
Test            | Value                         
                |                               
Single Core     | 1551                          
Multi Core      | 1539                          
Full Test       | https://browser.geekbench.com/v5/cpu/23265464

Geekbench 6 Benchmark Test:
---------------------------------
Test            | Value                         
                |                               
Single Core     | 1585                          
Multi Core      | 938                           
Full Test       | https://browser.geekbench.com/v6/cpu/9953190

流媒体

-------------------------------------跨国流媒体解锁--------------------------------------
IPV4:
============[ 跨国平台 ]============
Dazn                      Banned
Disney+                   NO (forbidden-location)
Netflix                   Restricted (Originals Only)
Netflix CDN               US
YouTube Region            YES (Region: US)
YouTube CDN               LAX
Amazon Prime Video        YES (Region: US)
Paramount+                YES
TVBAnywhere+              YES (Region: US)
IQiYi                     YES (Region: US)
Viu.com                   YES
Spotify Registration      NO
Steam Store               YES (Community Available) (Region: US)
ChatGPT                   YES (Region: US)
Sora                      YES (Region: US)
Gemini                    YES (Region: USA)
MetaAI                    YES (Region: US)
Wikipedia Editability     NO
Reddit                    NO
TikTok                    YES (Region: US)
Bing Region               YES (Risky) (Region: US)
Instagram Licensed Audio  YES
KOCOWA                    YES
SonyLiv                   NO (Proxy Detected) (Region: US)
OneTrust                  YES (Region: US CALIFORNIA)
GoogleSearch              YES

三网回程

-------------------------------------三网回程线路检测-------------------------------------
北京电信 219.141.140.10  移动CMIN2  [精品线路] 
北京联通 202.106.195.68  联通9929   [优质线路] 联通4837   [普通线路] 
北京移动 221.179.155.161 移动CMIN2  [精品线路] 
上海电信 202.96.209.133  移动CMIN2  [精品线路] 
上海联通 210.22.97.1     联通9929   [优质线路] 联通4837   [普通线路] 
上海移动 211.136.112.200 移动CMIN2  [精品线路] 
广州电信 58.60.188.222   移动CMIN2  [精品线路] 
广州联通 210.21.196.6    联通9929   [优质线路] 
广州移动 120.196.165.24  移动CMIN2  [精品线路] 
成都电信 61.139.2.69     移动CMIN2  [精品线路] 
成都联通 119.6.6.6       联通9929   [优质线路] 
成都移动 211.137.96.205  移动CMIN2  [精品线路]
-------------------------------------三网回程路由检测-------------------------------------
[NextTrace API] preferred API IP - [2606:4700:3030::6815:1001] - 37.39ms - Misaka.LAX
广州电信 - ICMP v4 - traceroute to 58.60.188.222, 30 hops max, 52 byte packets
0.67 ms      AS906      [DMIT-BB]          Anycast, Anycast, DMIT.com 
0.43 ms      AS906      [DMIT-BB]          美国, 加利福尼亚, 洛杉矶, DMIT.com 
0.52 ms      AS906      [DMIT-BB]          美国, 加利福尼亚, 洛杉矶, DMIT.com 
126.18 ms    AS58807    [CMIN2-NET]        美国, 加利福尼亚, 洛杉矶, cmi.chinamobile.com  移动
125.91 ms    AS58807    [CMIN2-NET]        中国, 上海, cmi.chinamobile.com  移动
127.35 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
126.89 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
128.02 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com 
159.81 ms    AS9808     [CMNET]            中国, 广东, 广州, chinamobileltd.com  移动
158.14 ms    AS9808     [CMNET]            中国, 广东, 广州, chinamobileltd.com  移动
*
*
156.80 ms    AS134774   [CHINANET-GD]      中国, 广东, 深圳, chinatelecom.cn  电信
*
161.27 ms    AS4134                        中国, 广东, 深圳, www.chinatelecom.com.cn  电信
广州联通 - ICMP v4 - traceroute to 210.21.196.6, 30 hops max, 52 byte packets
0.24 ms      AS906      [DMIT-BB]          Anycast, Anycast, DMIT.com 
0.84 ms      AS906      [DMIT-BB]          美国, 加利福尼亚, 洛杉矶, DMIT.com 
*
212.91 ms    AS10099    [CUG-BACKBONE]     中国, 上海, chinaunicomglobal.com  联通
212.91 ms    AS9929     [CNC-BACKBONE]     中国, 上海, chinaunicom.cn  联通 CUII
237.90 ms    AS9929     [CNC-BACKBONE]     中国, 广东, 广州, chinaunicom.cn  联通 CUII
230.85 ms    *          [CNC-BACKBONE]     中国, 广东, 广州
*
*
167.05 ms    AS17816    [APNIC-AP]         中国, 广东, 深圳, chinaunicom.cn  联通
185.31 ms    AS17623    [APNIC-AP]         中国, 广东, 深圳, chinaunicom.cn  联通
168.44 ms    AS17623                       中国, 广东, 深圳, chinaunicom.cn  联通
广州移动 - ICMP v4 - traceroute to 120.196.165.24, 30 hops max, 52 byte packets
0.14 ms      AS906      [DMIT-BB]          Anycast, Anycast, DMIT.com 
0.38 ms      AS906      [DMIT-BB]          美国, 加利福尼亚, 洛杉矶, DMIT.com 
0.48 ms      AS906      [DMIT-BB]          美国, 加利福尼亚, 洛杉矶, DMIT.com 
126.23 ms    AS58807    [CMIN2-NET]        美国, 加利福尼亚, 洛杉矶, cmi.chinamobile.com  移动
125.95 ms    AS58807    [CMIN2-NET]        中国, 上海, cmi.chinamobile.com  移动
126.23 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
126.25 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
126.54 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
149.94 ms    AS9808     [CMNET]            中国, 北京, chinamobileltd.com  移动
150.51 ms    AS9808     [CMNET]            中国, 北京, chinamobileltd.com  移动
*
152.03 ms    AS56040    [APNIC-AP]         中国, 广东, 深圳, gd.10086.cn  移动

测速

--------------------------------------就近节点测速--------------------------------------
位置            上传速度        下载速度        延迟            丢包率          
Speedtest.net   2080.22 Mbps    1647.83 Mbps    0.41 ms         0.0%            
洛杉矶          934.76 Mbps     917.49 Mbps     1.14 ms         0.0%            
法兰克福        1205.28 Mbps    426.70 Mbps     144.68 ms       0.0%            
联通上海5G      1294.88 Mbps    735.21 Mbps     147.12 ms       0.0%            
联通Beijing     562.31 Mbps     1483.30 Mbps    149.84 ms       Not available.  
电信浙江        534.67 Mbps     1125.47 Mbps    137.94 ms       Not available.  
电信浙江        521.65 Mbps     800.87 Mbps     143.74 ms       Not available.  
移动Fujian      461.81 Mbps     1253.97 Mbps    159.31 ms       Not available.

简单总结

  • 性能:DMIT 升级过一次配置,CPU 性能非常不错,磁盘 IO 也是 nvme 水准;
  • 线路:电信 9929/cmin2 负载、联通 9929、移动 cmin2;无晚高峰波动,电信回程没有 CN2GIA 稍稍遗憾,奈何流量给的太多了;
  • 灵度:DMIT 是 2017 成立的大厂了和瓦工一类的,灵度无需担心;
  • 价格:性价比非常不错的三网优化回程(小小可惜的是小杯29.9、39.9没有补货)。

最后做个表格简单汇总下:

套餐CPU内存硬盘月流量回程IP
LAX.EB.CORONA
49.9 美元/年
1核
EPYC 9654
1GB20GB
SSD
2T
2Gbps
三网优化
9929&cmin2
1 IPv4
1 IPv6 /64
LAX.EB.FONTANA
100.00 美元/年
2核
EPYC 9654
2GB40GB
SSD
4T
4Gbps
三网优化
9929&cmin2
1 IPv4
1 IPv6 /64

购买链接:

LAX.EB.CORONAhttps://www.dmit.io/aff.php?aff=9154&pid=218

LAX.EB.FONTANAhttps://www.dmit.io/aff.php?aff=9154&pid=219

原来 explode 还有第三个参数,竟然这么好用!

2025年4月2日 18:25

explode 是 PHP 一个常见的字符串处理函数,主要用于将字符串按照指定的分隔符拆分成数组。比如下面的代码就是通过英文逗号将字符串转换为数组。

$str	= "apple,banana,orange";
$fruits	= explode(",", $str);

// 结果:
// Array
// (
//     [0] => apple
//     [1] => banana
//     [2] => orange
// )

我相信大部分人(主要是我)都是这么用这个函数,但是绝大部分都不知道,explode 这个 PHP 函数还有第三个参数:$limit,这是一个可选参数,限制返回数组的最大元素数量。

我标题里面说这么好用,好用在哪里呢?🧐

🙋‍♀️🌰 我有个字符串,比如 args=type=select&name=gravatar,这个字符串其实是两部分,第一部分是 args 是 key,第二部分(type=select&name=gravatar),它其实是个 query_string,我的目的到时候通过 WordPress 函数 wp_parse_args 函数是将其解析成数组的。

如果直接使用 explode 分割字符串拆成数组的话:

$str	= "args=type=select&name=gravatar";
$arr	= explode("=", $str);

// 结果:
// Array
// (
//     [0] => args
//     [1] => type
//     [2] => select&name
//     [3] => gravatar
// )

这是我又要使用 implode 函数将除了第一个元素之外,其他元素拼成字符串。

有点烦躁。😒

这是第三个参数就派上用场了,设置为 2,看看结果

$str	= "args=type=select&name=gravatar";
$arr	= explode("=", $str, 2);

// 结果:
// Array
// (
//     [0] => args
//     [1] => type=select&name=gravatar
// )

是不是就是我需要的结果!🥳

最后我们在看看第三个参数 $limit 的用法:

  1. 如果设置了 limit 参数并且是正数,则返回的数组包含最多 limit 个元素,而最后那个元素将包含 str 的剩余部分
  2. 如果 limit 参数是负数,则返回除了最后的 -limit 个元素外的所有元素。
  3. 如果 limit 是 0,则会被当做 1。

好了,以后不要傻傻自己使用 implode 函数拼贴回去了,记得 explode  还有第三个参数的,而且非常好用。

使用 OPCache 字节码缓存让 WordPress PHP 执行效率提升 300%

2025年3月31日 22:17

前面我们介绍了使用 Memcached 内存缓存来实现 WordPress 站点秒开,其实 WordPress 加速还有个一个大招就是使用 OPcache 字节码缓存来提升 PHP 的执行效率,经测试最高可达提升 300%。

这么强吗?那今天就介绍一下 OPCache!

OPCache 是什么?

OPCache 是 PHP 的官方推出的字节码缓存器(Zend OPcache),通过将 PHP 脚本预编译的字节码存储在共享内存中来提升 PHP 的性能,在 PHP 5.5.0 及后续版本中已经绑定了 OPcache 扩展,

 缓存预编译字节码的好处就是避免重复解析和编译脚本,省去了每次加载和解析 PHP 脚本的开销,那么这一过程是如何实现的呢?

缓存字节码:PHP 脚本首次被执行的时候,Zend 引擎会将代码转换为 ​抽象语法树(AST)​,再编译为 ​字节码(opcodes)​,OPCache 扩展会拦截这一过程,将字节码存储在共享内存中,后续请求直接调用内存中的字节码,跳过重复编译的过程。

内存共享机制:OPCache 使用共享内存(mmap 或 shm)存储字节码,所有 PHP 进程(如 PHP-FPM 子进程)共享同一份缓存,降低了内存的占用,相比其他方案,OPCache 与 PHP 内核深度集成,效率更高。

所以 OPCache 在下面几个关键点提升了性能:

  • CPU 节省:避免重复编译,降低 CPU 负载(尤其是 WordPress 这类动态脚本)。
  • I/O 优化:减少磁盘读取 .php 文件的次数(对机械硬盘效果显著)。
  • 内存效率:字节码比原始 PHP 代码更紧凑,共享内存减少整体内存占用。

所以对于 WordPress 来说,就特别需要 OPCache 了,因为 WordPress 每个页面请求都会加载大量 PHP 文件(主题、插件、核心),这样未优化的 WordPress 在流量高峰时容易因 PHP 编译拖慢响应。

如何启用 OPCache

PHP PHP 5.5.0 及后续版本默认包含 OPCache,OPcache 只能编译为共享扩展,如果你使用 --disable-all 参数 禁用了默认扩展的构建, 那么必须使用 --enable-opcache 选项来开启 OPcache。

编译之后,就可以使用 zend_extension 指令来将 OPcache 扩展加载到 PHP 中。在非 Windows 平台使用 zend_extension=/full/path/to/opcache.so, Windows 平台使用 zend_extension=C:\path\to\php_opcache.dll

汇总一下在 php.ini 中添加下面代码:

zend_extension=opcache.so ; Linux
zend_extension=opcache.dll ; Windows
opcache.enable=1

针对 WordPress,可以加入这些专属优化配置:

[opcache]
opcache.enable=1
opcache.memory_consumption=256      ; WordPress 建议 ≥128MB
opcache.max_accelerated_files=10000 ; 覆盖 WordPress 核心 + 插件文件数
opcache.interned_strings_buffer=16  ; WordPress 大量重复字符串(如钩子名)
opcache.validate_timestamps=0       ; 生产环境关闭自动检查
opcache.revalidate_freq=0           ; 与 validate_timestamps=0 配合
opcache.save_comments=1             ; WordPress 依赖注释(如钩子文档)
opcache.enable_file_override=1      ; 覆盖 include/require 优化

安装好时候,如何检测验证安装成功了呢?

简单可以通过通过 phpinfo() 或命令行 php -v 查看是否加载。也可以在后台 「WPJAM」主菜单下「系统信息」子菜单中的「服务器」标签中「PHP 扩展」看到:OPCache:

当然最重要是「OPCache」标签页:

WPJAM Basic - 系统信息 - OPCache

这里也会罗列出 OPCache 的一些状态,比如已用内存和剩余内存,以及他们之间百分率,命中率和未命中率,以及他们之间百分率等等数据,还有相关的饼图。

生产环境一般建议关闭 validate_timestamps,避免频繁检查文件修改,文件有更新的时候通过手动重启 OPCache 或 PHP-FPM 来更新代码,也可以在上图中点击「刷新缓存」即可。

下面是一个简单 WordPress 站点在开启 OPCache 前后的性能对比:

场景未启用 OPCache启用 OPCache优化幅度
首页加载时间800ms300ms↓62.5%
后台管理页面1200ms500ms↓58.3%
并发请求(100 QPS)CPU 90%CPU 45%↓50%

所以可以看到启用 OPCache 最高接近 300% 的提升。

简单总结

PHP 代码使用 OPCache 之后,可以提高代码的执行效率,特别是 WordPress 这类文件比较多的 CMS 系统,所以在使用 Memcached 内存缓存来实现 WordPress 站点秒开之后,记得一定要开启 OPCache 来提速,另外 #WPJAM Basic# 也在 WordPress 集成了 OPCache 状态页面,可以看到 PHP 使用 OPCache 的状态。

高性能/高性价比欧洲服务器首选:netcup(网杯) 介绍 | 附免税注册与优惠码

2025年3月29日 23:04

netcup,中文一般翻译为「网杯」,平常大家也简单称呼它为 NC,它是一家总部位于德国的托管服务提供商,成立于 2001 年,专注于提供高性能、高性价比的虚拟主机、VPS、专用服务器和域名注册等服务。

netcup 产品特点

  • 高性价比:4C8G256G 的 VPS 产品,只需要 5.75 欧/月付起,活动时候还有硬盘翻倍。
  • 性能强劲Root Server 系列产品 CPU 均为 AMD EPYC 9634,磁盘也是优秀的SSD水准。
  • 量大管饱:主流产品都提供了 2.5G 网口,且不限流量(当然用量多了会临时限速200m/300m)。
  • 产品稳定:NC 以高可靠性和稳定著称,提供 DDOS 防御、多线冗余设计,节点故障自动迁移等。

netcup 注意事项

  • 机房:NC 机房以欧洲市场为主,主要为德国纽伦堡奥地利维也纳美东马纳萨斯荷兰阿姆斯特丹,路线均无国内优化,平均延迟 220+!(国内使用要套 CF 缓解,或使用优化路线、CDN 进行反代加速)
  • 合约:欧洲人比较重视合约,产品要提前31天取消,也就是月合约的就要至少使用的 2 个月,年合约也要在到期前 31 天取消,不然就要再续一年(当然产品也提供了满意度退款的选项)。
  • 注册:账户注册需要购买服务,支付方式为 PayPal账户外币信用卡(visa/万事达);

如果以上不是问题,NC 无疑是你高性能服务器的不二之选

netcup 产品详细介绍

netcup 的产品主要有以下这三个系列:

产品线代表配置价格起点适合场景性能亮点
Root Server VDS4C8G256GB
AMD EPYC 9634
€8.24/月起高负载业务独占CPU/GB6单核1800分
vServer VPS2C2G64GB
无限流量(1Gbps)
€3.35/月起中大型项目可阶段性100%占用CPU
1o 等廉价VPS1C1G30G
1Gbps不限流量
€10.08/年监控/面板/轻量应用年付性价比之王

我们下面一一做下详细介绍:

Root Server (VDS):专用虚拟服务器

nc-2.png

链接:https://www.netcup.com/de/server/root-server?ref=217135

Root Server (VDS) 是 NC 家的明星产品,CPU 均为 AMD EPYC 9634(可以长期高占用),GB6 单核分数1800 分左右、SSD 磁盘也属于优秀水准:

nc-16.png

vServer (VPS):虚拟服务器

nc-3.png

链接:https://www.netcup.com/de/server/vps?ref=217135

vServer (VPS) 就是常见的 VPS,VPS1000 以上套餐 CPU 均为 AMD EPYC系列 性能也挺不错,4C8G256G 每月5.75欧起,磁盘也同为 SSD 阵列(稍稍弱于RS系列)

NC 的 VPS 产品,实际也几乎不管你的 CPU 高占用(当然不要1天内,十几二十小时都100%的那种)

1o 等廉价VPS

nc-4.png

链接:https://www.netcup.com/de/server/guenstige-vserver-angebote?ref=217135

1C1G30G 无限流量(1Gbps),只需要10.08欧元/年,很适合部署一些对延迟要求不高的小服务~(类似探针、青龙面板、刮削服务器、服务主控等等,也有大佬拿去做博客)

类似产品:CCS 10刀/年的 1C1G20G 不限流量,CPU 性能和nc 1o机差不多,但 CPU 长期占用30%以上就会被停机…

注册 netcup

官网地址https://www.netcup.com/?ref=217135

注册时不要使用任何代理工具(可能会造成审核不通过),留意上方是否含税,含税请手动切换为 OtherAndere 国家;

nc-6.png

新用户可以使用5欧元的无门槛优惠券,通过以下链接就会自动使用:

https://www.netcup.com/en/checkout/cart?gutschein=36nc17428085140

nc-5.png

这样就使用了优惠券,之后按需选购服务器,以 RS1000 为例:

nc-7.png
nc-8.png
nc-9.png

无论选择年合约,还是月合约,付款周期都是1个月(且需要提前31天取消):

  • 年合约:如1月1日购买,10月31日前取消,服务器次年1月1日到期,11月后取消就要再续一年;
  • 月合约:如1月1日购买,1月31日前取消,服务器3月1日到期,2月后取消,4月1日到期。

确认无误后添加购物车:

nc-10.png

这里就会显示你的产品和优惠券,如果优惠券无显示-5欧元,可以手动输入兑换:

新用户5欧元优惠券:36nc17428085140

确认后结算,填写你的信息:

nc-11.png

人工审核通过后,你会收到 账号信息(CCP)邮箱验证 共2封邮件:

nc-12.png

打开并登录CCP:https://www.customercontrolpanel.de

nc-13.png

登录后填入另一封邮件的验证码,验证邮箱

nc-14.png

验证方式记得选择Prepayment(预支付),用PayPal 或银行卡支付订单;

右边的Verification(实名),会进行扫码实名认证,并需要人工审核(不容易通过)!

nc-15.png

收到SCP(服务器台)账户邮件,就完成注册啦!下方也有你的服务器ip、密码等信息~

最后再提示下新用户使用下面的链接注册可以获取5欧元的无门槛优惠券

https://www.netcup.com/en/checkout/cart?gutschein=36nc17428085140

前端真麻烦,概念真多,今天碰到了函数节流(Throttle)和函数防抖(Debounce)

2025年3月28日 15:06

前面我在 WordPress 后台集成了标签选择器(tag-input)和多选选择器(mu-select),其中「Tag-input」有个功能是:按退格键(Backspace)不仅可以删除输入的文字,也可以删除前面的标签(为了防止误删,需要快速按两次)。

「为了防止误删,需要快速按两次」这个是怎么实现的,我搜索了一圈和问了 DeepSeek,原来有个牛逼的技术叫做 Debounce,中文翻译成函数防抖,和它一起出现的还有个概念叫做 Throttle,中文翻译是函数节流。

于是各种搜索和 DeepSeek 问,把这两个概念理解的七七七八八,简单整理一篇文章,防止以后快速能用上。先来 DeepSeek 最这个的一句话总结:

函数节流(Throttle)和函数防抖(Debounce)是控制函数执行频率的两种常用技术,它们的核心目标都是优化高频事件触发时的性能,但实现方式和适用场景有所不同。

函数节流(Throttle)​

函数节流的核心是固定时间间隔内只执行一次函数,即使事件被频繁触发,函数也会按照设定的时间间隔规律性执行。

实现原理

  • 记录上一次执行的时间戳,每次触发时判断当前时间与上次执行的时间差。
  • 如果时间差大于等于设定的间隔,则执行函数并更新上次执行时间;否则忽略本次触发。

应用场景

  • 高频事件需定期响应:如滚动(scroll)、窗口调整(resize)、鼠标移动(mousemove)。
  • 防止重复操作:如游戏中的射击按钮(限制点击频率)、表单提交按钮(避免重复提交)。

代码示例

这里仅做演示,一般 LodashUnderScore 已经带了 throttle 函数。

function throttle(func, wait){
	let lastTime	= 0;
	return function(...args){
		const now	= Date.now();
		if(now - lastTime >= wait){
			func.apply(this, args);
			lastTime	= now;
		}
	};
}

函数防抖(Debounce)​

函数防抖的核心是等待事件停止触发后,延迟执行函数。如果事件在等待期间被再次触发,则重新计时。

实现原理

  • 每次触发时清除之前的定时器,并重新设置一个定时器。
  • 只有在事件停止触发超过设定时间后,函数才会执行。

应用场景

  • 输入结束后执行:如搜索框联想建议(用户停止输入后发送请求)。
  • 避免重复触发:如窗口调整结束后的布局计算(resize结束)、表单提交按钮防抖(防止多次提交)。

代码示例

这里仅做演示,一般 LodashUnderScore 已经带了 debounce 函数。

function debounce(func, wait, immediate=false){
	let timeout;
	return function(...args){
		const context	= this;
		const later		= ()=> {
			timeout	= null;
			if(!immediate){
				func.apply(context, args);
			}
		};
		const callNow	= immediate && !timeout;
		clearTimeout(timeout);
		timeout	= setTimeout(later, wait);
		if(callNow){
			func.apply(context, args);
		}
	};
}

核心区别

特性节流(Throttle)​防抖(Debounce)​
执行时机固定间隔执行一次事件停止触发后延迟执行
适用场景需定期响应的连续事件(如滚动、拖拽)只需最终结果的场景(如输入验证、搜索)
高频触发结果规律性执行(如每 100ms 一次)仅执行最后一次触发

如何选择?

  • 需要即时反馈:用节流(如拖拽、滚动时更新元素位置),结合 leadingtrailing 选项
  • 只需最终结果:用防抖(如搜索建议、输入验证),结合 immediate 选项。

通过合理使用这两种技术,可以有效优化性能并提升用户体验。

在 WordPress 后台集成了标签选择器(tag-input)和多选选择器(mu-select)

2025年3月28日 00:04

使用过 #WPJAM Basic# 的同学都知道,WPJAM Basic 集成了多个字段组件,这些组件都是后台定义一下,然后前段就能够渲染,并且提交的时候也会根据类型进行验证和处理,反正就是我通过前后端双修的模式将字段设置这块做到了最简洁了。😁

比如多个输入框(类型:mu-text),在「CDN 加速」里的「扩展名」字段:

甚至可以无限重复的一组字段(类型:mu-fields),在「缩略图设置」里面的:「未设置缩略图是,获取特色图片顺序」字段:

还有设置多个图片(类型:mu-img),还是在「缩略图设置」里面的「默认缩略图」字段:

这些字段都是后端配置的,自动渲染生成的,不用再多写一行前段 JS 代码:

「扩展名」字段:

[
	'exts'	=> [
		'type'		=> 'mu-text',
		'button_text'	=> '添加扩展名',
		'direction'	=> 'row',
		'sortable'	=> false,
		'description'	=> '镜像到云存储的静态文件扩展名'
	]
]

「获取顺序」字段:

[
	'post_thumbnail_orders'	=> [
		'title'		=> '文章缩略图',
		'type'		=> 'mu-fields',
		'group'		=> true,
		'max_items'	=> 5,
		'before'	=> '首先使用文章特色图片,如未设置,将按照下面的顺序获取:<br />',
		'fields'	=> [
			'type'	=> ['type'=>'select',	'options'=>[
				''			=> '请选择来源',
				'first'		=> '第一张图',
				'post_meta'	=> [
					'label'		=> '自定义字段',
					'fields'	=> ['post_meta'=>['type'=>'text',	'class'=>'all-options',	'placeholder'=>'请输入自定义字段的 meta_key']]
				],
				'term'		=>[
					'label'		=> '分类缩略图',
					'show_if'	=> ['term_thumbnail_type', 'IN', ['img','image']],
					'fields'	=> ['taxonomy'=>['options'=>[''=>'请选择分类模式']+$tax_options]]
				]
			]]
		]
	]
]

「默认缩略图」字段:

[
	'default'	=> [
		'title'		=> '默认缩略图',
		'type'		=> 'mu-img',
		'item_type'	=>'url'
	]
]

就是这样配置一下就好,剩下的程序会自动处理,厉害吧!这就是我前后端兼修的能力。😂

但是还是有些地方需要一些主键,比如在列表筛选的时候,用到上面这些多输入框的时候,界面就有点挤了,所以就有了「标签选择器」和「多选选择器」这两个字段组件。

「标签选择器」这个其实和上面的多输入框很类似,只是它每输入一个之后,就变成类似标签的样式:

支持自动完成,拖动排序,删除,按退格键(Backspace)不仅可以删除输入的文字,也可以删除前面的标签(为了防止误删,需要快速按两次)。这个可能更多的是样式的改进,但是更重要的是界面的节省。

使用也很简单,首先它的类型是:tag-inpug

[
	'tags'	=> [
		'type'			=> 'tag-input',
		'data_type'		=> 'taxonomy',	// 数据类型
		'taxonomy'		=> 'post_tag',	// 文章标签
		'min_items'		=> 2,	// 至少 2 个
		'max_items'		=> 3,	// 最多 3 个
		'unique_items'	=> true // 不能重复,已选择的项目不会再次出现
	]
]

有时候被选择的项目数量是有限的,比如分类,但是要多选,如果使用 select 的话,只能单选,当然 select 有个 multiple 属性,但是显示的效果是这样的:

通过按着 CTRL 或者 Shift 然后点击进行多选,怎么用,怎么难受,并且高度太高,不好排版,如果强制设置为一行,都不知道选择了什么。

所以我们做了「多选选择器」这个组件,它默认显示选中的选项,通过逗号分割开:

点击「下拉选择框」(其实这个是个按钮,通过 CSS 改造和下拉选择框很类似)就可以看到所有选项,并且所有选项前面都有个复选框:

勾选之后,就会显示到上面「下拉选择框」中,并且同样也支持设置至少和最多的数量,选好之后点击人地方,这个下拉复选框就隐藏了,这样就能大大节省界面:

使用也很简单,首先它的类型是:mu-select,其实把上面标签选择器的代码复制下来,改下类型就好了

[
	'tags'	=> [
		'type'			=> 'mu-select',
		'data_type'		=> 'taxonomy',	// 数据类型
		'taxonomy'		=> 'category',	// 文章分类
		'min_items'		=> 2,	// 至少 2 个
		'max_items'		=> 3,	// 最多 3 个
	]
]

如果你基于 WPJAM Basic 进行二次开发,那么这两个字段组件可以帮到你很多。为了写这两个字段,我相当于又重修了一下 JavaScript 这门语言,还好现在有 DeepSeek,很多模棱两可的东西,都可以问题,然后也可以让它给到一些演示代码,然后在改就简单了很多。😁

在 WordPress 中如何优雅的使用全局变量

2025年3月29日 22:15

程序写多了,都会认同这条规则:在 WordPress 中,都尽量不要使用全局变量,其实任何 PHP 程序中都是这样的。为什么?先从简单介绍下全局变量开始。

什么是全局变量

全局变量是在 PHP 脚本的任何作用域中都可以访问的变量,主要包括以下几种形式:

超全局变量 (Superglobals)

PHP 预定义的全局数组,​无需使用 global 声明即可在任何作用域访问:

  • $_GET:HTTP GET 请求参数
  • $_POST:HTTP POST 请求参数
  • $_REQUEST:GET/POST/COOKIE 的合并数据
  • $_SESSION:会话数据
  • $_COOKIE:客户端 Cookie 数据
  • $_SERVER:服务器和执行环境信息
  • $_FILES:上传文件信息
  • $_ENV:环境变量
  • $GLOBALS:所有全局变量的引用集合

使用 global 关键字

在函数或方法内部通过 global 关键字访问全局变量:

$globalVar = 10;

function test() {
    global $globalVar;
    echo $globalVar; // 输出 10
}

$GLOBALS 数组

直接通过 $GLOBALS 访问全局变量:

$globalVar = 10;

function test() {
    echo $GLOBALS['globalVar']; // 输出 10
}

使用全局变量的问题

代码可维护性差

  • 隐式依赖:函数内部依赖全局变量会导致代码逻辑不透明,难以追踪数据来源。
  • 耦合度高:修改全局变量可能影响多个地方,引发难以调试的副作用。

作用域污染

  • 命名冲突:全局变量可能与其他变量或库中的变量同名,导致意外覆盖。
  • 生命周期不可控:全局变量在脚本结束前一直存在,可能占用不必要的内存。

并发和线程安全问题

  • 在并发环境(如多线程或异步任务)中,全局变量可能被多个线程同时修改,导致数据不一致。

测试困难

  • 全局状态使得单元测试难以隔离,测试用例之间可能互相影响。

安全隐患

  • 超全局变量(如 $_GET$_POST)未过滤时可能引发安全漏洞(如 SQL 注入、XSS)。

全局变量虽然方便,但过度使用会导致代码质量下降。应该遵循“最小作用域原则”和“单一职责原则”,能显著提升代码的可维护性和安全性。

在 WordPress 中正确使用全局变量

但是我们在代码中还是要使用一些全局变量,或者类似全局变量的变量,比如我在小程序中记录当前登录的用户的 openid:$weapp_openid。那么怎么办呢?

先上代码:

function wpjam_var($name, ...$args){
	static $vars;

	$vars	??= wpjam_parse_user_agent();	// 当前用户访问的环境信息

	if($args && (!isset($vars[$name]) || !is_closure($args[0]))){
		$value	= maybe_closure($args[0], $name);

		if(is_wp_error($value) || is_null($value)){
			return $value;
		}

		$vars[$name]	= $value;
	}

	return $vars[$name] ?? null;
}

我创建一个 wpjam_var 函数,这个函数创建一个静态变量 $vars,它是一个数组,所有全局要使用的变量都存到该数组中。

$weixin_openid	= '通过小程序插件获取';

// 存储变量
wpjam_var('weapp_openid', $weixin_openid);

然后在之后 $weapp_openid 可以通过以下方法获取:

// 获取变量
wpjam_var('weapp_openid');

它还支持闭包函数,比如我们可以将获取 $weapp_openid 包装成一个函数:

function weapp_get_current_openid(){
	return wpjam_var('weapp_openid', function(){
		$access_token	= wpjam_get_parameter('access_token');

		if(!$access_token){
			return new WP_Error('illegal_access_token', 'Access Token 为空!');
		}

		return WEAPP::get_openid_by_access_token($access_token);
	});
}

这样在之后的地方都可以使用 weapp_get_current_openid 获取 $weapp_openid。它的具体如何获取和实现,

最后再总结一下 wpjam_var 函数,它的第一个参数 $name 很简单,变量的名称,第二个参数分三种情况:

  1. 如果没有设置,就返回该变量的值,没有设置则为 null
  2. 如果是简单的值(非闭包),则设置并返回该值。
  3. 如果是闭包函数,如设置 $name 的变量,则返回它的值,如果未设置,通过调用闭包函数获得值,然后设置并返回。

wpjam_var 函数的好处

1. 作用域隔离,避免污染

  • 数据封闭性
    示例中的 $weapp_openid 通过 wpjam_var 存储,​仅限函数内部访问,外部无法直接修改,彻底规避全局变量的命名冲突和意外覆盖。
  • 安全访问
    所有操作必须通过 wpjam_var 函数(如 weapp_get_current_openid()),​天然实现私有性,避免全局污染。敏感数据(如 access_token)的获取逻辑封装在闭包内,防止外部直接暴露。

2. 性能优化(延迟初始化)​

  • 按需加载
    示例中 $weapp_openid 的闭包函数可能涉及数据库查询,首次调用时执行一次并缓存结果,后续直接复用,避免重复计算。
  • 内存级访问速度
    静态变量存储在内存中,访问速度远超全局变量或文件读取。同一请求中多次调用 weapp_get_current_openid() 时,​性能提升显著​(如减少冗余 API 调用)。

3. 灵活的数据管理

  • 动态惰性计算
    通过闭包(如示例中的匿名函数)实现“按需生成数据”,仅在未缓存时触发逻辑,资源利用率更高。
  • 错误隔离与健壮性
    检测 WP_Error 或 null(如 access_token 为空时返回错误),​避免污染缓存,确保后续逻辑仅处理有效数据。

4. 可维护性与扩展性

  • 逻辑集中管理
    weapp_get_current_openid() 作为唯一入口,​集中维护 openid 的获取规则,修改生成逻辑(如更换认证方式)只需调整闭包,无需全局搜索。
  • 易于扩展功能
    支持快速添加类型检查、日志记录或缓存失效机制(如 reset 参数),​无需改动外部调用代码,扩展成本低。
  • 代码清晰度
    数据定义($weapp_openid)与业务逻辑(闭包)分离,​提升可读性,降低维护难度。

5. 安全性提升

  • 输入验证与过滤
    示例中闭包内对 access_token 做非空校验,​拦截非法输入​(如空值或无效格式),防止无效请求进入下游逻辑。
  • 风险隔离
    敏感操作(如 get_openid_by_access_token())封装在闭包中,​统一实施安全策略​(如加密、超时控制),避免全局变量直接暴露的风险。

6. 适用场景

  • 高频请求数据
    如示例中的 openid,适用于同一请求内多次访问的场景(如用户信息、权限校验)。
  • 动态配置管理
    根据环境加载不同配置(如开发/生产环境参数),通过闭包实现按需加载。
  • 共享资源访问
    替代单例模式,简化数据库连接池等共享资源的管理。

上面这段话,是 deepseek 帮我总结的,果然比我吹的好,但是也说明这个函数实现的好,哈哈!在最新版的 #WPJAM Basic# 即可直接使用。

CloudCone - 中盘 VPS 清仓促销活动 14美元/年起!

2025年3月21日 23:47

CloudCone 上线了中盘 VPS 清仓活动,近期有入门美国VPS或是 存储需求的倒是不错的选择~

他家所有的机器和 RN(RackNerd)的DC02地区的VPS都在MC机房,在普通路线VPS里面表现比较稳定。

清仓套餐详情

特惠商品,售完即止!

名称配置流量价格位置链接
CS-Q1-25-VPS-12核/1G/60G2T/月14 美元/年美国 洛杉矶https://app.cloudcone.com.cn/vps/378/create?ref=11351&token=cs-q1-25-vps-1
CS-Q1-25-VPS-23核/2G/120G3T/月24 美元/年美国 洛杉矶https://app.cloudcone.com.cn/vps/379/create?ref=11351&token=cs-q1-25-vps-2
CS-Q1-25-VPS-36核/4G/240G4T/月44 美元/年美国 洛杉矶https://app.cloudcone.com.cn/vps/380/create?ref=11351&token=cs-q1-25-vps-3

简单测试

这次 CloudCone - 中盘 VPS 清仓使用都是 SSD 缓存硬盘,而不是纯 SSD 硬盘。

SSD缓存硬盘 是通过 SSD 固态阵列对 HDD 机械硬盘进行加速的技术;与纯 SSD 硬盘相比,其 IO 性能稍逊一筹,但结合了机械硬盘的大容量优势,以下是性能对比:

纯SSD硬盘:

------------------磁盘dd读写测试--感谢lemonbench开源--------------------
 -> 磁盘IO测试中 (4K Block/1M Block, Direct Mode)
 测试操作               写速度                                  读速度
 100MB-4K Block         18.5 MB/s (4509 IOPS, 5.68s)            48.9 MB/s (11933 IOPS, 2.15s)
 1GB-1M Block           497 MB/s (474 IOPS, 2.11s)              2.3 GB/s (2195 IOPS, 0.46s)
---------------------磁盘fio读写测试--感谢yabs开源----------------------
Block Size | 4k            (IOPS) | 64k           (IOPS)
  ------   | ---            ----  | ----           ---- 
Read       | 125.94 MB/s  (31.4k) | 430.73 MB/s   (6.7k)
Write      | 126.28 MB/s  (31.5k) | 433.00 MB/s   (6.7k)
Total      | 252.22 MB/s  (63.0k) | 863.73 MB/s  (13.4k)
           |                      |                     
Block Size | 512k          (IOPS) | 1m            (IOPS)
  ------   | ---            ----  | ----           ---- 
Read       | 746.93 MB/s   (1.4k) | 973.88 MB/s    (951)
Write      | 786.62 MB/s   (1.5k) | 1.03 GB/s     (1.0k)
Total      | 1.53 GB/s     (2.9k) | 2.01 GB/s     (1.9k)

SSD缓存硬盘:

------------------磁盘dd读写测试--感谢lemonbench开源--------------------
 -> 磁盘IO测试中 (4K Block/1M Block, Direct Mode)
 测试操作		写速度					读速度
 100MB-4K Block		14.6 MB/s (3568 IOPS, 7.17s)		41.3 MB/s (10078 IOPS, 2.54s)
 1GB-1M Block		462 MB/s (441 IOPS, 2.27s)		2.8 GB/s (2708 IOPS, 0.37s)
---------------------磁盘fio读写测试--感谢yabs开源----------------------
Block Size | 4k            (IOPS) | 64k           (IOPS)
  ------   | ---            ----  | ----           ---- 
Read       | 17.05 MB/s    (4.2k) | 338.89 MB/s   (5.2k)
Write      | 17.05 MB/s    (4.2k) | 340.67 MB/s   (5.3k)
Total      | 34.11 MB/s    (8.5k) | 679.56 MB/s  (10.6k)
           |                      |                     
Block Size | 512k          (IOPS) | 1m            (IOPS)
  ------   | ---            ----  | ----           ---- 
Read       | 341.56 MB/s    (667) | 295.25 MB/s    (288)
Write      | 359.70 MB/s    (702) | 314.91 MB/s    (307)
Total      | 701.27 MB/s   (1.3k) | 610.16 MB/s    (595)

IO 逊色纯固态阵列硬盘,但优于机械盘,但是提供了大容量。

磁盘外的测评可看之前的文章:CloudCone 7 周年促销,推出多款高性价比 VPS

配置链接
2核/1G/60Ghttps://app.cloudcone.com.cn/vps/378/create?ref=11351&token=cs-q1-25-vps-1
3核/2G/120Ghttps://app.cloudcone.com.cn/vps/379/create?ref=11351&token=cs-q1-25-vps-2
6核/4G/240Ghttps://app.cloudcone.com.cn/vps/380/create?ref=11351&token=cs-q1-25-vps-3

从 Division by zero 到 set_error_handler

2025年3月20日 17:16

最近做了个简单的表格应用,其中有个功能是支持公式运算,如下图,毛利率这列是其他两列相除算出来的:

Division by zero

做完,客户还没用一天,就碰到问题了,因为有时候公式中的被除数是 0,这时候 log 中一堆 「Division by zero」的 Warning,影响查看其他的 log 的查看。

刚开始我想到的办法是在填充公式变量的时候,判断一下被除数是零就抛出「除零错误」,不去真正计算就好了,确实可以解决问题。嘻嘻,我还是挺聪明的。😎

但是很快又碰到新的问题了,因为有这样的公式:$a / ($b + $c) ,然后 ($b + $c) 的结果为 0。😂

如果继续按照原来的做法,我要根据运算的优先级,来判断被除数是 0,如果公式一复杂,那么什么时候是个头啊。🤦🤦‍♂️🤦‍♀️🤕

Warning 还是异常

先搜索了一圈 Division by zero,然后在 PHP 文档,看到 PHP 就已经有一个预定义的异常 DivisionByZeroError

但是为啥我的代码能够执行成功,只是在 log 中出现一堆 「Division by zero」的 Warning,那就继续看文档:

在 PHP 7 中使用算术运算符 / 不会抛出异常,而在 PHP 8 中会抛出异常,可惜客户的系统还在使用 PHP 7.4。

直接问 DeepSeek 我该怎么办?它给了我四个方法:

1. 手动检查并抛出异常

我这个又不是简单的被除数,真的是。🙄

2. 使用 set_error_handler 捕获警告

貌似这个可以。😘

3. 封装除法操作类

我是算术公式,这个不合适。🤪

4. 升级 PHP 8

我能升级就不会问你了。🤬

看来使用方案二了!

使用 set_error_handler 捕获警告

就是通过 set_error_handler 函数将警告转换成异常抛出。

set_error_handler(function($no, $str){
	if(str_contains($str , 'Division by zero')){
		throw new DivisionByZeroError($str); 
	}

	throw new ErrorException($str , $no);

	return true;
});

如果警告信息的字符串里面有 Division by zero,就抛出 DivisionByZeroError 异常,其他情况抛出 ErrorException

然后原来的执行表达式运算的代码改成 try - catch 结构:

try{
	// 原来执行运算表达式代码
}catch(DivisionByZeroError $e){
	return $if_error ?? '!除零错误';
}catch(throwable $e){
	return $if_error ?? '!计算错误';
}

完美解决!🍾🥂🎆🎇🎊

还没开心 5 分钟,很快就来了但是。😞😮‍💨

如果这样自定义错误处理程序,那么之后的代码的警告都被他接管了,然后直接抛出异常。这 🙄🫤

继续查 PHP 文档,问 DeepSeek,原来 set_error_handler 有返回值的,如果之前有定义的错误处理程序,则返回之前定义的错误处理程序,如果没有定义或者是内置的错误处理程序,则返回 null。

这样的话,那就好处理,给 try - catch 结构加上 finally,最终的代码如下:

$handler	= set_error_handler(function($no, $str){
	if(str_contains($str , 'Division by zero')){
		throw new DivisionByZeroError($str); 
	}

	throw new ErrorException($str , $no);

	return true;
});

try{
	// 原来执行运算表达式代码
}catch(DivisionByZeroError $e){
	return $if_error ?? '!除零错误';
}catch(throwable $e){
	return $if_error ?? '!计算错误';
}finally{
	if($handler){ // 之前有定义的错误处理程序
		set_error_handler($handler);
	}else{ // 恢复到内置的错误处理程序
		restore_error_handler();
	}
}

搞定,收工,记录一下!📝 🐂🍺

同台服务器上多个 WordPress 站点如何使用同个 Memcached?

2025年3月19日 23:31

前面我们介绍了「使用 Memcached 内存缓存来实现 WordPress 站点秒开」,很多用户都开始使用 Memcached 来提高 WordPress 站点速度,但是使用的时候碰到第一个或者说最多的问题就是,同台服务器上多个 WordPress 网站怎么同时使用 Memcached?

站点间数据互串

如果同时将 #WPJAM Basic# 插件 template 目录下的 object-cache.php 文件复制到同个服务器上多个 WordPress 站点的 wp-content 目录下来同时开启 Memcached 缓存,可能会出现这样的问题:

访问一个网站会跳转到另外一个网站,也就是说数据会串了。

这是怎么回事呢?这是因为 object-cache.php 默认是使用 WordPress 的表前缀($table_prefix区分不同站点在内存中的缓存的

如果你在同个服务器多个 WordPress 网站的表前缀都相同,都是默认的 wp_,那么 object-cache.php 就无法区分是哪个站点了。

那么怎么解决呢?

怎么同时使用 Memcached

定位了问题,那么就非常好解决,有两个解决方法:

1. 修改表前缀,让不同的 WordPress 博客使用不同的表前缀。我开发了一个 WordPress 数据库表前缀修改器,一键生成修改数据库表前缀所需的SQL,让你在 WordPress 修改表前缀之后能够更加方便全站修改。

2. 如果修改表前缀不方便,我还提供了 WP_CACHE_KEY_SALT 这个缓存 key 盐值的常量,你只需要在不同站点的 wp-config.php 文件定义不同的 WP_CACHE_KEY_SALT 值即可

比如两个站点分别定义为:

define('WP_CACHE_KEY_SALT', 'site1');
define('WP_CACHE_KEY_SALT', 'site2');

如果设置了还不行,可能你的 object-cache.php 不是最新版,那就下载一下最新版的 WPJAM Basic 插件,然后将 wpjam-basic/template/ 目录下的 object-cache.php 文件复制到 wp-content 目录下。

如何设置 Memcache 服务器地址

此外还有一些用户服务器的设置,他们的 Memcached 的服务器地址不是默认的 127.0.0.1,或者它们使用的云服务器的 Memcached 服务,很多聪明的同学会自己修改 object-cache.php 中的 Memcached 服务器地址。

其实不用那么麻烦 #WPJAM Basic# 提供的 object-cache.php 支持自定义服务器地址的, 只要在 wp-config.php 文件填下如下代码,将相应的服务器地址和端口改成自己的即可:

global $memcached_servers;

$memcached_servers	= [
	[
		'127.0.0.1', // Memcached 服务器地址
		11211        // Memcached 服务器端口
	]
];

最后,关于在 WordPress 中使用 Memcached:

1. 使用 Memcached 内存缓存来实现 WordPress 站点秒开

2. Memcached 和 Redis 有什么区别,做缓存 WordPress 用哪个好?

3. WordPress 是如何缓存的?对象缓存(Object Cache)详细介绍和使用!


WPJAM Basic 插件已经集成了 Memcached,下载 WPJAM Basic 之后,将 wpjam-basic/template/ 目录下的 object-cache.php 文件复制到 wp-content 目录下即可。

preg_replace_callback 如果正则有问题,竟然不是返回原字符串,而是返回 null

2025年3月19日 00:00

#WPJAM Basic# 有个功能,就是在 WordPress 后台文章列表添加上文章特色图片,并且支持点击设置:

这个功能因为 WordPress 没有好的 Hook 使用,我是通过对最终生成的 HTML 实现正则替换实现的。

这个功能本来挺好的,然后有个用户说使用 WPJAM Basic 之后,说后台文章列表空白,经过我仔细的 Debug,原来他使用的标签太多了,使得 HTML 过于复杂,正则回溯次说过多,发生错误了。

原本我以为正则错就错了呗,最多就是正则替换不成功,功能没有,为啥还给我整成空白的呢?我仔细查了下 PHP 官方文档,原来 preg_replace_callback 函数的返回是这样的:

如果 subject 是一个数组, preg_replace_callback() 返回一个数组,其他情况返回字符串。错误发生时返回 null

厄,错误发生时返回 null,第一次知道,一下子无言以对,原来之前正则都是成功了,我都没有去处理错误的情况,真的是。

然后 preg_replace 也是一样的情况,错误发生时返回 null

所以我写了一个函数 wpjam_preg_replace,同时实现  preg_replace_callbackpreg_replace 的正则替换功能(它们的参数差不多,一个是回调,一个是替换的字符串),如果发生错误时,不是返回 null,而是返回原始 $subject

function wpjam_preg_replace($pattern, $replace, $subject, $limit=-1, &$count=null, $flags=0){
	if(is_closure($replace)){
		$result	= preg_replace_callback($pattern, $replace, $subject, $limit, $count, $flags);
	}else{
		$result	= preg_replace($pattern, $replace, $subject, $limit, $count);
	}

	if(is_null($result)){
		trigger_error(preg_last_error_msg());
		return $subject;
	}

	return $result;
}

如果发生了错误,并且在 log 中打印出具体的错误信息,方便查看原因,看看能不能优化正则什么的。这里有个限制,preg_replace_callback 的回调函数只能是闭包,因为同时要支持两个函数的原因,使用闭包比较容易判断。

有了这个函数之后,即使发生正则错误,至少还能显示页面,这也算是一种防御性编程(防御性编程是一种编程实践,旨在编写代码以抵御或处理潜在的错误和异常情况,以提高代码的健壮性和可靠性)。😆

「果酱粉丝专属福利」恒创科技香港大宽带云服务器,仅 237.6元 / 年

2025年3月14日 23:11

上次我们在「WordPress果酱」公众号说搞了个 VPS 交流/分享/评测的微信群,很快就有 200 多人入群了。还没有入群的同学,大家可以加 VERKY 个人号(微信号:PSD404),再拉你入群,超过 200 人群无法扫群二维码啦。🙂

近来好几个群友来问有无性价比香港机器推荐,最近似乎没有特别优惠的,而国内大厂的又要么没货、要么限速严重。这时候突然想到之前推过一期的恒创,也是一家十来载的老牌云厂商,用过 WordPress 的小伙伴应该多少有听说过。

大宽带云服务器

这次推荐的是他们的大宽带云服务器,下面是他们的官网套餐:

henghost-wpjam-1.png

四款服务器都是香港 50m/100m 独享大带宽服务器,最低配置的一款目前官网价格是 1C1G15G(500G/月)298元/年起!(原价75折)

比起之前首发时候的限量促销价格高了一些,这怎么能忍?在和恒创运营人员几番“友好”的交流后,终于py到了一波优惠,原价的 6 折,比促销价还低 15%:

通过下面活动链接,使用专属优惠码:wpjam,可以享受原价6折优惠(官网活动是75折):

https://www.henghost.com/hostsdfsdf.php?6690872a032cbflU6eOB

四款大宽带云服务器均可享6折优惠

  • 1C1G15G 50M独享 (流量500G/月) 237.6元/年
  • 1C2G20G 50M独享 (流量1T/月) 357.6元/年
  • 2C2G30G 100M独享 (流量2T/月) 477.6元/年
  • 2C4G50G 100M独享 (流量3T/月) 638.4元/年

直接标注到图上,这样大家看得更加清楚一些:😁

henghost-wpjam-2.png

所有套餐均为 三网优化线路独享50/100m带宽续费同价

恒创服务器真机测试

测试机器:1C1G15G 50M独享款

测试IP:154.197.26.254(实际机器也是同个ip段)

全国Tcping:三网直连,平均延迟40~50ms

henghost-wpjam-4.png

探针表现:联通表现非常不错,电信和移动些许波动

hc-3w.png
hc-dx.png
hc-lt.png
hc-yd.png

基础信息:ASN号:AS133199 为自家持有

--------------------------------------系统基础信息--------------------------------------
 CPU 型号            : Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50GHz
 CPU 数量            : 1 Virtual CPU(s)
 CPU 缓存            : L1: 64 KB / L2: 256 KB / L3: 30 MB
 GPU 型号            : GD 5446
 GPU 状态            : 0.000000
 AES-NI              : ✔️ Enabled
 VM-x/AMD-V/Hyper-V  : ✔️ Enabled
 内存                : 250.46 MB / 961.00 MB
 气球驱动            : ✔️ Enabled
 虚拟内存 Swap       : [ no swap partition or swap file detected ]
 硬盘空间            : 2.02 GB / 14.94 GB
 启动盘路径          : /dev/vda1
 系统                : debian 12.0 [x86_64] 
 内核                : 6.1.0-10-amd64
 系统在线时间        : 0 days, 00 hours, 03 minutes
 时区                : CST
 负载                : 2.13 / 1.27 / 0.50
 虚拟化架构          : KVM
 NAT类型             : Port Restricted Cone
 TCP加速方式         : cubic
 IPV4 ASN            : AS133199 SonderCloud Limited
 IPV4 Location       : Hong Kong / Hong Kong / Hong Kong

CPU、内存、磁盘:CPU常规E5性能表现一般,磁盘 IO SSD 水平还不错

--------------------------------CPU测试-通过sysbench测试--------------------------------
1 线程测试(单核)得分:    725.48
--------------------------------内存测试-通过sysbench测试---------------------------------
单线程顺序写速度: 10315.43 MB/s(10.82K IOPS, 5s)
单线程顺序读速度: 15571.92 MB/s(16.33K IOPS, 5s)
-----------------------------------硬盘测试-通过fio测试-----------------------------------
测试路径      块大小   读测试(IOPS)            写测试(IOPS)            总和(IOPS)
/root         4k       10.29 MB/s(2571)        10.32 MB/s(2580)        20.61 MB/s(5151)  
/root         64k      162.10 MB/s(2532)       162.96 MB/s(2546)       325.06 MB/s(5078) 
/root         512k     214.95 MB/s(419)        226.37 MB/s(442)        441.32 MB/s(861)  
/root         1m       199.35 MB/s(194)        212.62 MB/s(207)        411.97 MB/s(401)
Geekbench 5 Benchmark Test:
---------------------------------
Test            | Value                         
                |                               
Single Core     | 516                           
Multi Core      | 499                           
Full Test       | <https://browser.geekbench.com/v5/cpu/23403101>

流媒体解锁

-------------------------------------跨国流媒体解锁--------------------------------------
IPV4:
============[ 跨国平台 ]============
Apple                     YES (Region: HKG)
BingSearch                YES (Region: HK)
Claude                    YES
Dazn                      Banned
Disney+                   NO (forbidden-location)
Gemini                    NO
GoogleSearch              YES
Google Play Store         YES (Region: HK)
IQiYi                     YES (Region: HK)
Instagram Licensed Audio  YES
KOCOWA                    NO
MetaAI                    NO (AbraGeoBlocked)
Netflix                   Restricted (Originals Only)
Netflix CDN               HK
OneTrust                  YES (Region: HK)
ChatGPT                   YES (Only Available with Mobile APP)
Paramount+                YES
Amazon Prime Video        YES (Region: HK)
Reddit                    NO
SonyLiv                   YES (Region: HK)
Sora                      Banned (VPN Blocked)
Spotify Registration      NO
Steam Store               YES (Community Available) (Region: HK)
TVBAnywhere+              YES (Region: HK)
TikTok                    NO
Viu.com                   YES
Wikipedia Editability     YES
YouTube Region            YES (Region: HK)
YouTube CDN               HKG

回程测试:香港直连,商家宣称三网4837回程(但出于安全考虑隐藏了路由),实际测试延迟表现还不错!

-------------------------------------三网回程线路检测-------------------------------------
北京电信 219.141.140.10  检测不到回程路由节点的IP地址
北京联通 202.106.195.68  检测不到回程路由节点的IP地址
北京移动 221.179.155.161 检测不到回程路由节点的IP地址
上海电信 202.96.209.133  检测不到回程路由节点的IP地址
上海联通 210.22.97.1     检测不到回程路由节点的IP地址
上海移动 211.136.112.200 检测不到回程路由节点的IP地址
广州电信 58.60.188.222   检测不到回程路由节点的IP地址
广州联通 210.21.196.6    检测不到回程路由节点的IP地址
广州移动 120.196.165.24  检测不到回程路由节点的IP地址
成都电信 61.139.2.69     检测不到回程路由节点的IP地址
成都联通 119.6.6.6       检测不到回程路由节点的IP地址
成都移动 211.137.96.205  检测不到回程路由节点的IP地址
-------------------------------------三网回程路由检测-------------------------------------
[NextTrace API] preferred API IP - 172.67.69.163 - 50.05ms - Misaka.HKG
广州电信 - ICMP v4 - traceroute to 58.60.188.222, 30 hops max, 52 byte packets
*
*
*
40.08 ms     AS4134                        中国, 广东, 深圳, www.chinatelecom.com.cn  电信
广州联通 - ICMP v4 - traceroute to 210.21.196.6, 30 hops max, 52 byte packets
*
*
*
12.02 ms     AS17623                       中国, 广东, 深圳, chinaunicom.cn  联通
广州移动 - ICMP v4 - traceroute to 120.196.165.24, 30 hops max, 52 byte packets
*
*
*
16.90 ms      AS56040    [APNIC-AP]         中国, 广东, 深圳, gd.10086.cn  移动

三网测速:晚高峰测速结果

——————————————————————————— HyperSpeed —————————————————————————————
         bash <(wget -qO- <https://bench.im/hyperspeed>)
         项目修改自: <https://github.com/zq/superspeed/>
   脚本更新: 2023/4/13 | 组件更新: 2023/11/1 | 组件版本: 0.17.0
————————————————————————————————————————————————————————————————————
  测速类型:    1. 三网测速    2. 取消测速    0. 港澳台日韩
               3. 电信节点    4. 联通节点    5. 移动节点
               6. 教育网IPv4  7. 教育网IPv6  8. 三网IPv6
  请选择测速类型(默认: 1): 1
  启用八线程测速[y/N](默认: N): n
————————————————————————————————————————————————————————————————————
测速服务器信息   ↑     上传/Mbps ↓     下载/Mbps ↕ 延迟/ms ϟ 抖动/ms
————————————————————————————————————————————————————————————————————
电信|上海        ↑     47.6 正常 ↓     47.4 正常 ↕    27.7 ϟ     2.9
电信|江苏镇江5G  ↑     47.9 正常 ↓     47.5 正常 ↕    40.1 ϟ     3.9
电信|江苏南京5G  ↑     47.5 正常 ↓     47.3 正常 ↕    42.3 ϟ     6.1
移动|浙江杭州5G  ↑     47.9 正常 ↓     45.6 正常 ↕    31.7 ϟ     2.7
移动|四川成都    ↑     48.4 正常 ↓     45.0 正常 ↕    53.4 ϟ     5.1
联通|天津        ↑     47.3 正常 ↓     47.5 正常 ↕    37.5 ϟ     5.6

全球持续PING:晚间测试,除江苏出现了7~13%的丢包,其他国家地区表现都挺不错

恒创服务器小结

  • 性能:CPU性能常规E5表现一般,硬盘为SSD水平还不错;
  • 线路:香港三网直连,宣称联通4837回程(但隐藏了路由),延迟实测较低,晚间电信移动些许波动;
  • 价格:对于香港三网回程优化的机器,价格还是非常不错的(美西优化的价格,香港直连的体验);
  • 灵度:恒创也是十多年的老牌主机商了,还是有一定信誉和口碑的,同时提供了3天无理由退款、云服务器产品附带免费快照备份功能;有性价比港机需求,可以上车体验~

最后所有套餐均为三网优化线路独享50/100m带宽续费同价,在购买界面输入果酱粉丝专属优惠吗,可以享受 6 折优惠:

最后如果想要加入我们「VPS 交流/分享/评测的微信群」的同学,大家可以先加 VERKY 个人号(微信号:PSD404),再拉你入群。

微信公众号竟然防爬了,那就升级一下同步公众号文章到博客的 WordPress 插件「WPJAM GrabMP」

2025年3月13日 23:07

微信公众号竟然升级系统,给他的公众号文章页面加上了防爬功能,现在如果没有做任何处理直接使用 wp_remote_get 获取自己公众号的文章页,得到是如下的页面:

我简单试了一下,给 wp_remote_get 加上 User-Agent

$mp_html	= wpjam_remote_request($mp_url, ['headers' => ['User-Agent' => $user_agent ?: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36',]]);

然后就可以了,微信这防爬是典型的简单的防一下,意思到了就好。😂

为了防止微信对 User-Agent 有要求,我给「WPJAM GrabMP」加上「User Agent」选项,让使用者也可以自定义,不过他有个默认值,就是上面这个,最新的 Chrome 浏览器的 User Agent:

最后还是简单介绍一下「WPJAM GrabMP」插件:

怎么快速同步自己公众号文章到 WordPress 博客,还有公众号文章里的图片因为微信防盗链,要一张一张下载然后再上传到 WordPress 媒体库,非常很麻烦,所以我写了一个插件「WPJAM GrabMP」来实现一键同步公众号文章到 WordPress 博客:

1. 安装之后,在 WordPree 文章管理菜单下面出现一个抓取图文的子菜单:

2. 点击之后,就可以进入公众号图文抓取界面:

3. 首先输入公众号图文的链接,User Agent 使用默认就好,如果抓取不成功,可以试试一些其他的 User Agent,然后选择文章状态选择「保存我草稿,修改后发布」还是「无需修改,立即发布」。

选择保存为草稿,则点击「一键抓取」按钮之后,就会进入抓取的文章的编辑页面,看看有什么问题,比如抓取下来的图文格式会不会太乱等等,可以自己去编辑修正一下,然后再发布,甚至还选择定时发布。

选择立即发布,则点击「一键抓取」按钮之后,就会直接发布,然后跳转到前台的文章详情页面,直接可以看到前台显示的效果了,当然看到显示效果不好,也可以回到后台,文章编辑页面再次修改。

4. 接着就是外部图片的处理,勾选「将公众号图文中的图片保存到媒体库」之后,系统就会在抓取图文的时候,自动将公众号图文的图片全部抓取到 WordPress 本地媒体库。

如果你博客开启了 CDN 功能,图片也会自动镜像到云存储,然后自动加速,没有开启 CDN 也没有问题,至少媒体库也有了图片。😄

另外公众号图文中的图片默认是640宽显示的,然后你觉这样图片太小了,还可以选择抓取原图,方便对图片有更高追求的同学。

5. 最后点击「一键抓取」按钮就会自动生成一篇文章,插件会自动抓取公众号文章的标题,摘要,然后把头图作为文章的特色图片,内容部分,该插件做了些处理,将视频转成 qqv shortcode。

这样一篇公众号的文章就同步到 WordPress 博客了,对了,该插件需要你先安装 WPJAM Basic 插件和微信机器人高级版才行。

对了,这次更新也要更新一下微信机器人高级版

如何构建安全的 WordPress 5:禁用搜索结果动态标题,防止 SEO 垃圾攻击

2025年4月8日 23:05

继续「如何构建安全的 WordPress」系列文章,这是 WordPress 搜索安全相关的第二篇,前面我们介绍了「限制搜索频率,防止搜索滥用攻击」,今天讲讲 WordPress 搜索第二个重大的安全隐患, SEO 垃圾攻击(SEO Spam)

SEO 垃圾攻击

什么是SEO 垃圾攻击(SEO Spam)

SEO 垃圾攻击(SEO Spam)​,也称为 ​搜索引擎投毒(Search Engine Poisoning)​,是指黑客或黑产通过操纵搜索引擎优化(SEO)技术,向目标网站注入垃圾内容或篡改网页元素(如标题、关键词、链接等),使其在搜索引擎结果中显示恶意或无关信息,从而误导用户或提升黑产网站的排名。如下(我做个演示):

图片

它还有一下几个行业通用术语

  • SEO Spam / SEO Poisoning:通过操纵页面元素(如标题、描述)提升黑产网站在搜索引擎中的可见性。
  • Title Tag Hijacking:直接劫持标题标签内容,属于 ​On-Page SEO 攻击 的一种。
  • Search Index Pollution:污染搜索引擎索引的恶意行为(Google 官方文档曾用此术语描述类似攻击)。

攻击者通过构造恶意搜索请求(如 ?s=黑产关键词+域名),利用 WordPress 默认的搜索结果页动态标题机制(例如 wp_title() 函数),将恶意内容注入到 <title> 标签中。这属于 ​注入攻击(Injection Attack)​ 的子类,但更贴近 ​SEO 滥用 场景。

为什么 WordPress 经常被这类攻击呢?因为WordPress 默认将搜索关键词动态插入标题(例如 搜索:{关键词} - 网站名),而黑产通过自动化工具高频请求含恶意关键词的搜索页(如 ?s=赌博网站),导致这些关键词被收录到搜索引擎索引中,甚至排名靠前。

这类攻击造成的损害也是很大的,一旦你的网站有这类情况,可能会被搜索引擎误判为关联黑产内容,导致网站降权或标记为恶意。万一用户通过搜索敏感词进入站点,可能触发安全平台(如 Google Safe Browsing)的警告。

静态化搜索结果标题

那么怎么办呢?其实很简单,禁用 WordPress 搜索结果动态标题,静态化搜索结果标题,​比如只显示「搜索结果」这四个字:

图片

WPJAM 搜索优化插件 已经集成了该功能,如下图所示,「搜索增强」的第三个选项「搜索结果页面标题不显示关键字,只显示「搜索结果」四个字」勾选上即可:

WPJAM 搜索优化插件 已经集上面所有的功能和相关代码,直接启用即可,点击查看 WPJAM 搜索优化插件 的详细介绍,Modular 主题也集成了,我会在介绍 WordPress 安全这系列文章的时候,将这些安全相关代码也整合到 Modular 主题中,争取打造最安全的 WordPress 主题。

Memcached 和 Redis 有什么区别,做缓存 WordPress 用哪个好?

2025年3月11日 23:51

前面介绍了使用 Memcached 内存缓存来实现 WordPress 站点秒开,但是很多人问到了 Redis,就是做缓存 Redis 和 Memcached 有什么区别,用哪个更好?今天就给大家做一个简单介绍。

Memcached 和 Redis 有什么区别

首先从模型上看,Memcached 是一个分布式内存缓存系统,专注于简单的键-值对存储,设计简单易用,它不支持复杂数据类型,而 Redis 是一个内存数据结构存储,支持更多的数据结构(如列表、集合、排序集合、哈希等),不仅仅是简单的键-值对。

所以 Memcached 是为简单的读写操作优化的,适合需要快速缓存大量数据的场景,而 Redis 提供了丰富的数据操作功能,对复杂数据操作优化良好,同时也提供了高性能的读写速度,并且 Redis 支持数据持久化,可以将内存数据保存到磁盘,Memcached 没有持久性功能,所有数据都存储在内存中,服务器重启时数据就会丢失,作为缓存这个问题不大。

此外,它们还有一点比较大的区别,就是 Memcached 支持多线程,所以支持高并发访问,而 Redis 一般使用单线程模型,虽然通过 I/O 多路复用技术提供高吞吐量,这样就比较在秒杀等场景下使用,不需要考虑并发的问题,因为单线程。

简单做个功能特性对比表格:

特性MemcachedRedis
数据结构仅支持键值对(String)支持 String、List、Hash、Set 等
持久化不支持支持 RDB 快照和 AOF 日志
线程模型多线程(高并发读优)单线程(避免锁竞争,顺序执行)
内存管理预分配固定内存,LRU 淘汰支持内存淘汰策略,可配置虚拟内存
集群模式依赖客户端分片(如 Twemproxy)原生 Cluster 模式支持
适用场景简单键值缓存(如会话、HTML片段)缓存、消息队列、实时统计等复杂场景

Redis 的作者的建议

Redis 的作者 Salvatore Sanfilippo 曾经对这两种基于内存的数据存储系统进行过比较:

  1. Redis 支持服务器端的数据操作:Redis 相比 Memcached 来说,拥有更多的数据结构和并支持更丰富的数据操作,通常在 Memcached 里,你需要将数据拿到客户端来进行类似的修改再 set 回去。这大大增加了网络 IO 的次数和数据体积。在 Redis 中,这些复杂的操作通常和一般的 GET/SET 一样高效。所以,如果需要缓存能够支持更复杂的结构和操作,那么 Redis 会是不错的选择。
  2. 内存使用效率对比:使用简单的 key-value 存储的话,Memcached 的内存利用率更高,而如果 Redis 采用 hash 结构来做 key-value 存储,由于其组合式的压缩,其内存利用率会高于 Memcached。
  3. 性能对比:由于 Redis 只使用单核,而 Memcached 可以使用多核,所以平均每一个核上 Redis 在存储小数据时比 Memcached 性能更高。而在 100k 以上的数据中,Memcached 性能要高于 Redis,虽然 Redis 最近也在存储大数据的性能上进行优化,但是比起 Memcached,还是稍有逊色。

总结一下:Memcached 是解决简单缓存问题的可靠选择,而 Redis 通过提供更丰富的功能和各种各样的特性而优于 Memcached,这些特性对于解决复杂的场景更有优势。

WordPress 使用哪个做缓存好?

如果单纯作为内存缓存来使用,两者其实没有什么区别,那么为什么 WPJAM Basic 为什么使用 Memcached 呢?

这里有一份 4 核 CPU / 8G 内存的服务器上的测试数据:

操作Memcached QPSRedis QPS
GET 请求120,000+100,000+
SET 请求90,000+80,000+

可以看出在 WordPress 这样简单的键-值缓存,并且需要处理大量简单数据,Memcached 是一个更好的选择。

此外我们一开始就选择了 Memcached 做 WordPress 的内存缓存的存储介质,并且在使用 Memcached 做内存缓存过程中,针对出现的各种的问题,我也做了很多的优化,比如我们在后台「WPJAM」菜单下的「系统信息」中展示「Memcached」的各种信息。

Memcached 命中率

当然如果你已经使用了 Redis 做内存缓存或者更熟悉 Redis,WordPress 官方插件库也有很多第三方提供了 Redis 的 object-cache.php,和使用 Memcached 一样,只需要将对应的 object-cache.php 上传到 wp-content 目录即可。

此外也有小伙伴问,WPJAM Basic 会不会集成 Redis,让大家自己选,这个可以明确的说,目前作为简单缓存功能,Memcached 已经足够好用,不会再花时间集成 Redis。

最后还有个问题,Memcached 和 Redis 可以一起用吗?如果作为缓存,WordPress 只能选择一个,因为你上传谁的 object-cache.php,就是用谁得了。

但是不等于使用 Memcached 作为缓存,就不能使用 Redis 了,比如我们之前就利用 Redis 的一些特性做过一些开发,比如因为 Redis 单线程天然串行排队的特性,我们在花生小店秒杀的功能中就是使用 Redis 进行处理的,还有一些简单的消息队列的功能处理,也是基于 Redis 进行开发的。

简单总结

所以最后总结说一下,如果简单的 key-value 的内存缓存,建议使用 Memcached,WordPress 绝大部分站点也是使用 Memcached 进行缓存的,此外 WPJAM Basic 也对此优化得比较完善。

如果要进行复杂的程序开发,比如上面说的电商的秒杀功能 ,消息队列系统等,那么 Redis 才是发挥其长处的地方。

搬瓦工推出和 NodeSeek 合作的美西 VPS,三网优化 / 1C1G20G1T / 36.36 美元/年

2025年3月7日 23:22

搬瓦工这次挺狠,推出和 NodeSeek 合作的第二款VPS,三网优化且有路线保障;明显狙击 DMIT,同时也背刺了自家前些时候的 DC99 产品。

套餐详情

NODESEEK-BIGGERBOX-PRO

  • CPU:1核(AMD)
  • 内存:1G
  • 硬盘:20G
  • 流量:1000GB /月流量(2.5Gbps)
  • 线路:电信CN2GIA+联通移动CMIN2 回程(三网优化)
  • 价格:36.36美元/年(优惠后)

限量供应,30天内可退款,即使IP被墙了!购买地址:

https://bandwagonhost.com/aff.php?aff=76910&pid=156

如果连不上,可能是主站点 DNS 被污染,可以试下:

https://bwh81.net/aff.php?aff=76910&pid=156

购买的时候可以用优惠码:BWHCGLUKKB(优惠6.77%)

测试

测试 IP:144.34.228.10

全国TCPing,一片绿~ 联通从上海回程,高几十 ms:

探针表现:三网优化回程,延迟情况不错;联通走cmin2(移动的优化路线)经上海回程延迟会高几十。

1741340061864_d.png
Clipboard - 2025-03-07 17.34.36.png
Clipboard - 2025-03-07 17.35.07.png
Clipboard - 2025-03-07 17.35.19.png

IP质量报告:解锁是优化路线里,优秀的水平了~

YABS 脚本测试结果

root@secure-poke-2:~# curl -sL https://yabs.sh | bash -s -- -r5
# ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## #
#              Yet-Another-Bench-Script              #
#                     v2025-01-01                    #
# https://github.com/masonr/yet-another-bench-script #
# ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## #
 
Fri 07 Mar 2025 04:23:16 AM EST
 
Basic System Information:
---------------------------------
Uptime     : 0 days, 0 hours, 11 minutes
Processor  : AMD EPYC-Genoa Processor
CPU cores  : 1 @ 2794.748 MHz
AES-NI     : ✔ Enabled
VM-x/AMD-V : ❌ Disabled
RAM        : 1.0 GiB
Swap       : 545.0 MiB
Disk       : 20.6 GiB
Distro     : Debian GNU/Linux 11 (bullseye)
Kernel     : 5.10.0-8-amd64
VM Type    : KVM
IPv4/IPv6  : ✔ Online / ❌ Offline
 
IPv4 Network Information:
---------------------------------
ISP        : IT7 Networks Inc
ASN        : AS25820 IT7 Networks Inc
Host       : Cluster Logic Inc
Location   : Los Angeles, California (CA)
Country    : United States
 
fio Disk Speed Tests (Mixed R/W 50/50) (Partition /dev/sda2):
---------------------------------
Block Size | 4k            (IOPS) | 64k           (IOPS)
  ------   | ---            ----  | ----           ---- 
Read       | 164.54 MB/s  (41.1k) | 653.43 MB/s  (10.2k)
Write      | 164.98 MB/s  (41.2k) | 656.87 MB/s  (10.2k)
Total      | 329.53 MB/s  (82.3k) | 1.31 GB/s    (20.4k)
           |                      |                     
Block Size | 512k          (IOPS) | 1m            (IOPS)
  ------   | ---            ----  | ----           ---- 
Read       | 891.69 MB/s   (1.7k) | 1.15 GB/s     (1.1k)
Write      | 939.07 MB/s   (1.8k) | 1.22 GB/s     (1.1k)
Total      | 1.83 GB/s     (3.5k) | 2.38 GB/s     (2.3k)
 
iperf3 Network Speed Tests (IPv4):
---------------------------------
Provider        | Location (Link)           | Send Speed      | Recv Speed      | Ping           
-----           | -----                     | ----            | ----            | ----           
Clouvider       | London, UK (10G)          | 1.17 Gbits/sec  | 1.36 Gbits/sec  | 130 ms         
Leaseweb        | Singapore, SG (10G)       | 850 Mbits/sec   | 1.04 Gbits/sec  | 178 ms         
Leaseweb        | NYC, NY, US (10G)         | 2.32 Gbits/sec  | 2.85 Gbits/sec  | 69.2 ms        
 
Geekbench 5 Benchmark Test:
---------------------------------
Test            | Value                         
                |                               
Single Core     | 1015                          
Multi Core      | 1012                          
Full Test       | https://browser.geekbench.com/v5/cpu/23388307
 
YABS completed in 3 min 57 sec

融合怪脚本测试结果

-------------------------------------VPS融合怪测试-------------------------------------
版本:v0.1.15
测评频道: https://t.me/vps_reviews
Go项目地址:https://github.com/oneclickvirt/ecs
Shell项目地址:https://github.com/spiritLHLS/ecs
--------------------------------------系统基础信息--------------------------------------
 CPU 型号            : AMD EPYC-Genoa Processor @2794.748 MHz
 CPU 数量            : 1 Virtual CPU(s)
 CPU 缓存            : L1: 64 KB / L2: 1 MB / L3: 32 MB
 GPU 型号            : GD 5446
 GPU 状态            : 0.000000
 AES-NI              : ✔️ Enabled
 VM-x/AMD-V/Hyper-V  : ✔️ Enabled
 内存                : 258.03 MB / 1.01 GB
 气球驱动            : ✔️ Enabled
 虚拟内存 Swap       : 0.00 MB / 545.00 MB
 硬盘空间            : 1.71 GB / 20.58 GB
 启动盘路径          : /dev/sda2
 系统                : debian 11.0 [x86_64] 
 内核                : 5.10.0-8-amd64
 系统在线时间        : 0 days, 00 hours, 05 minutes
 时区                : EST
 负载                : 0.13 / 0.11 / 0.06
 虚拟化架构          : KVM
 NAT类型             : Full Cone
 TCP加速方式         : bbr
 IPV4 ASN            : AS25820 It7 Networks INC
 IPV4 Location       : Los Angeles / California / United States
--------------------------------CPU测试-通过sysbench测试--------------------------------
1 线程测试(单核)得分:   1623.81
--------------------------------内存测试-通过sysbench测试---------------------------------
单线程顺序写速度: 19594.80 MB/s(20.55K IOPS, 5s)
单线程顺序读速度: 44908.52 MB/s(47.09K IOPS, 5s)
-----------------------------------硬盘测试-通过fio测试-----------------------------------
测试路径      块大小   读测试(IOPS)            写测试(IOPS)            总和(IOPS)
/root         4k       158.79 MB/s(39.7k)      159.21 MB/s(39.8k)      317.99 MB/s(79.5k)      
/root         64k      664.01 MB/s(10.4k)      667.51 MB/s(10.4k)      1.33 GB/s(20.8k)        
/root         512k     778.83 MB/s(1521)       820.22 MB/s(1601)       1.60 GB/s(3122)         
/root         1m       1.23 GB/s(1199)         1.31 GB/s(1279)         2.54 GB/s(2478)         
-------------------------------------跨国流媒体解锁--------------------------------------
IPV4:
============[ 跨国平台 ]============
Apple                     YES (Region: USA) [Native]
BingSearch                YES (Region: US)
Claude                    YES [Native]
Dazn                      Banned
Disney+                   NO (forbidden-location)
Gemini                    YES (Region: USA) [Native]
GoogleSearch              YES
Google Play Store         YES (Region: US) [Native]
IQiYi                     YES (Region: US) [Native]
Instagram Licensed Audio  YES [Native]
KOCOWA                    YES [Native]
MetaAI                    YES (Region: US) [Native]
Netflix                   Restricted (Originals Only)
Netflix CDN               US
OneTrust                  YES (Region: US CALIFORNIA) [Via DNS]
ChatGPT                   YES (Region: US) [Native]
Paramount+                YES [Native]
Amazon Prime Video        YES (Region: US) [Native]
Reddit                    NO
SonyLiv                   YES (Region: US) [Native]
Sora                      YES (Region: US)
Spotify Registration      YES (Region: US) [Native]
Steam Store               YES (Community Available) (Region: US)
TVBAnywhere+              YES (Region: US) [Native]
TikTok                    YES (Region: US) [Native]
Viu.com                   YES [Native]
Wikipedia Editability     NO
YouTube Region            YES (Region: US) [Native]
YouTube CDN               LAX
-------------------------------------三网回程线路检测-------------------------------------
北京电信 219.141.140.10  电信CN2GIA [精品线路] 
北京联通 202.106.195.68  移动CMIN2  [精品线路] 
北京移动 221.179.155.161 移动CMIN2  [精品线路] 
上海电信 202.96.209.133  电信CN2GIA [精品线路] 
上海联通 210.22.97.1     移动CMIN2  [精品线路] 
上海移动 211.136.112.200 移动CMIN2  [精品线路] 
广州电信 58.60.188.222   电信CN2GIA [精品线路] 
广州联通 210.21.196.6    移动CMIN2  [精品线路] 
广州移动 120.196.165.24  移动CMIN2  [精品线路] 
成都电信 61.139.2.69     电信CN2GIA [精品线路] 
成都联通 119.6.6.6       移动CMIN2  [精品线路] 联通4837   [普通线路] 
成都移动 211.137.96.205  移动CMIN2  [精品线路] 
-------------------------------------三网回程路由检测-------------------------------------
[NextTrace API] preferred API IP - 104.26.12.151 - 32.66ms - Misaka.LAX
广州电信 - ICMP v4 - traceroute to 58.60.188.222, 30 hops max, 52 byte packets
21.09 ms     AS25820                       美国, 加利福尼亚, 洛杉矶, it7.net 
0.44 ms      AS25820                       美国, 加利福尼亚州, 洛杉矶, it7.net 
*
151.30 ms    *          [CN2-Global]       中国, 香港, chinatelecom.cn  电信
150.80 ms    *          [CN2-Global]       中国, 广东, 广州, chinatelecom.cn  电信
152.61 ms    *          [CN2-BackBone]     中国, 广东, 广州, chinatelecom.cn  电信
157.00 ms    *          [CN2-BackBone]     中国, 广东, 广州, chinatelecom.cn  电信
183.58 ms    AS4134                        中国, 广东, 佛山市, www.chinatelecom.com.cn  电信
*
154.21 ms    AS4134                        中国, 广东, 深圳, www.chinatelecom.com.cn  电信
广州联通 - ICMP v4 - traceroute to 210.21.196.6, 30 hops max, 52 byte packets
28.55 ms     AS25820                       美国, 加利福尼亚, 洛杉矶, it7.net 
0.59 ms      AS25820                       美国, 加利福尼亚州, 洛杉矶, it7.net 
*
126.39 ms    AS58807    [CMIN2-NET]        美国, 加利福尼亚, 洛杉矶, cmi.chinamobile.com  移动
126.15 ms    AS58807    [CMIN2-NET]        中国, 上海, cmi.chinamobile.com  移动
126.40 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
126.22 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
128.55 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
154.82 ms    AS9808     [CMNET]            中国, 广东, 广州, chinamobileltd.com  移动
185.00 ms    AS9808     [CMNET]            中国, 广东, 广州, chinamobileltd.com  移动
*
*
199.35 ms    AS17816    [UNICOM-GD]        中国, 广东, 深圳, chinaunicom.cn  联通
178.32 ms    AS17623    [APNIC-AP]         中国, 广东, 深圳, chinaunicom.cn  联通
195.77 ms    AS17623                       中国, 广东, 深圳, chinaunicom.cn  联通
广州移动 - ICMP v4 - traceroute to 120.196.165.24, 30 hops max, 52 byte packets
50.36 ms     AS25820                       美国, 加利福尼亚, 洛杉矶, it7.net 
0.43 ms      AS25820                       美国, 加利福尼亚州, 洛杉矶, it7.net 
*
126.49 ms    AS58807    [CMIN2-NET]        美国, 加利福尼亚, 洛杉矶, cmi.chinamobile.com  移动
126.17 ms    AS58807    [CMIN2-NET]        中国, 上海, cmi.chinamobile.com  移动
126.25 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
126.31 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
127.86 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com 
151.49 ms    AS9808     [CMNET]            中国, 北京, chinamobileltd.com  移动
209.56 ms    AS9808     [CMNET]            中国, 北京, chinamobileltd.com  移动
204.45 ms    AS9808     [CMNET]            中国, 北京, chinamobileltd.com  移动
211.46 ms    AS56040    [APNIC-AP]         中国, 广东, 深圳, gd.10086.cn  移动
--------------------------------------就近节点测速--------------------------------------
位置            上传速度        下载速度        延迟            丢包率          
Speedtest.net	 9381.26 Mbps	 8126.19 Mbps	 0.51	  0.0%
日本东京	 770.51 Mbps	 4510.01 Mbps	 114.53	  0.0%
联通上海5G	 2051.16 Mbps	 2402.26 Mbps	 174.38	  0.0%
电信浙江	 645.55 Mbps	 3296.00 Mbps	 135.75	  NULL
电信Zhenjiang5G	 672.50 Mbps	 6649.51 Mbps	 136.01	  NULL
移动Chengdu	 1386.67 Mbps	 534.93 Mbps	 169.68	  NULL
----------------------------------------------------------------------------------
花费          : 1 分 45 秒
时间          : Fri Mar 7 04:19:32 EST 2025
----------------------------------------------------------------------------------

简评

  • 性能:瓦工终于升级AMD CPU,性能非常不错,磁盘io也是nvme水准;
  • 线路:三网优化回程(电信CN2GIA、联通移动CMIN2),无晚高峰波动的美西优化线路;
  • 灵度:知道美西优化路线的基本都知道搬瓦工,灵度无需担心;
  • 价格:36.36美元/年的价格,明显狙击DMIT36.9(500G),联通稍差于dmit,但1T流量2.5G口子,价格太卷了!非常有性价比的美西三网优化路线VPS,有需要可以上车(同时提供了30天退款保障)。

如何构建安全的 WordPress 2:隐藏登录失败时「未知用户名」和「密码不正确」错误信息

2025年3月3日 23:12

之前我们开启了如何构建安全的 WordPress 系列文章,并开启了第一篇:防止用户名暴露,我们通过 5 个地方的功能和代码,让 WordPress 登录名不会出现在任何页面上或者源代码中。

除此之外,其实还有一个地方还有可能让攻击者猜测到用户名是否正确,这个就是在登录界面,如果工具者使用暴力破解的方式尝试使用用户名的时候,WordPress 默认的错误信息,可以让攻击者获得正确的用户名。

默认情况下,在登录 WordPress 的时候,如果输入的用户名不存在,WordPress 会报「未知用户名」的错误:

「未知用户名」

如果用户名正确,密码错误的话,WordPress 会报「密码不正确」的错误:

「密码不正确」

这些错误提示信息可以让让攻击者知道快速定位用户名,确定了用户名,继续暴力破解获得密码就更加方便。

所以这些错误信息最好统一改成:「用户名或者密码错误」的错误信息,让攻击者猜去吧。

add_filter('wp_login_errors', function($errors){
	$error_code	= $errors->get_error_code();

	if(in_array($error_code, ['invalid_username', 'invalid_email', 'incorrect_password'])){
		$errors->remove($error_code);
		$errors->add($error_code, '用户名或者密码错误。');
	}

	return $errors;
});

还是那句话,安全是最重要的,所以一定要重视,除了防止用户名暴露,隐藏可以让攻击者确定用户名的错误信息是非常好的安全措施。

WPJAM 用户管理插件 已经集上面所有的功能和相关代码,直接启用即可,点击查看 WPJAM 用户管理插件的详细介绍,Modular 主题也集成了,我会在介绍 WordPress 安全这系列文章的时候,将这些安全相关代码也整合到 Modular 主题中,争取打造最安全的 WordPress 主题。

在 DeepSeek 的帮助下,我又给 WPJAM Basic 增加了几个函数!

2025年2月26日 23:21

对于程序员来说,写代码其实不难,反而最难的是给函数命名,这是困扰程序员最大的问题,很多程序员开玩笑说:编程5分钟,命名2小时。😂

比如之前网上就有一张图,反应了程序员编程的时候,具体在干嘛:

让 DeepSeek 给函数命名

首先我们先明确一下:什么样的函数名是一个好的名字呢?

好的函数命名应当简洁、清晰且易于理解,能够在不查看具体实现的情况下直观地反映出其功能和用途。

但实际上找到这样的命名并不容易,需要充分考虑变量、函数和类的功能、用途以及上下文环境,因此程序员需要花费大量时间思考如何为代码中的各个元素命名,以提高代码的可读性和可维护性。

那么如果我们让 DeepSeek 在我们给函数命名的时候,给我我们一些建议,是不是可以解决我们这个困扰呢? 或者说打开我们的思路呢?我们说干就干,首先是提示词,经过调试,下面是我的函数命名的提示词是:

我将发给你一段程序代码,你根据这段代码帮我提炼出函数的名称,函数名称的风格为下划线风格,然后函数应用于 WordPress,需要参考 WordPress 函数命名风格,并简单解释下为什么这么命名,如果可以请提供多一些选项以供选择,谢谢。

正好最近在发布 #WPJAM Basic# 新版的时候,为了方便,又增加了几个函数,比如下面,判断变量是不是闭包函数:

return $object instanceof Closure;

再来一个,如果变量回调函数,那就调用回调函数,否则就还是返回变量本生:

return $value && is_callable($value) ? $value(...$args) : $value;

如果自己也有想法,可以再在和他沟通一下:😄

WPJAM Basic 新增函数

所最后在 DeepSeek 的帮助下,WPJAM Basic 新版增加下面几个函数:

1. maybe_callback

如果变量是回调函数,则调用回调函数,否则返回变量本身:

if(!function_exists('maybe_callback')){
	function maybe_callback($value, ...$args){
		return $value && is_callable($value) ? $value(...$args) : $value;
	}
}

2. maybe_closure

类似于 maybe_callback,但是它判断是闭包函数才调用,其他一样:

if(!function_exists('maybe_closure')){
	function maybe_closure($value, ...$args){
		return $value && is_closure($value) ? $value(...$args) : $value;
	}
}

3. is_closure

怎么判断闭包函数呢?就有这个函数了:

if(!function_exists('is_closure')){
	function is_closure($object){
		return $object instanceof Closure;
	}
}

4. wpjam_pick

从对象或者数组中,根据 $keys 获取一个关联数组,类似 JS 工具库 underscore 或者 loadsh 的 _.pick 函数,如果是从数组中获取,其实和 WordPress 内置的 wp_array_slice_assoc 一样,只是命名这个更加简洁。

function wpjam_pick($arr, $keys){
	return is_object($arr) ? wpjam_array($keys, fn($i, $k)=> isset($arr->$k) ? [$k, $arr->$k] : null) : wp_array_slice_assoc($arr, $keys);
}

等我发布新版,就可以使用了!

怎么用好 DeepSeek?这里有 60 多款集成 DeepSeek 的应用!

2025年2月21日 23:38

大家对 DeepSeek 的理解就是对话,问它一个问题,它解答你,然后呢?很多人就没有然后了,其实已经很多第三方应用集成了 DeepSeek,用好这些集成 DeepSeek 第三方,拓展自己使用 AI 场景,提高工作和学习的效率。

为了方便在公众号展示,我在文章中使用图片展示了,下载链接统一在文章末尾展示,你也可以直接拉到末尾复制链接去下载。

使用这些第三方应用,需要用到 DeepSeek 的 API key,登录 DeepSeek 开放平台获取即可,一般充值 10 员就可以用很久。

应用推荐

浏览器插件

即时通讯插件

AI Agent 框架

RAG 框架

编程插件

统一获取地址:https://github.com/deepseek-ai/awesome-deepseek-integration

微信「AI 搜索」的快速回答和深度思考分别用的是什么模型?有什么区别?

2025年2月19日 23:46

前些天,微信搜一搜上线「AI 搜索」功能,并且接入 DeepSeek 模型!这些天基本已经成为了我手机上 AI 工具的首选了,毕竟能在微信上解决问题,又合并要多下载一个 APP 呢?

在使用的时候,大家肯定都发现了,微信的 AI 搜索功能提供了两个模式「快速回答」和「深度思考」:

我一开始以为快速回答是使用腾讯自家的「混元」模型,而深度思考则使用 DeepSeek-R1 模型,事实是这样吗?然后使用他们又有什么不同呢?

我就把这个问题直接扔给微信的「AI 搜索」:

微信搜一搜的Al搜索的快速回答和深度思考,分别用的是什么模型,有什么区别?

先用快速回答看看:

确实比较简单,但是好像没有详细回答到我们的问题,没有我们要的点,那就切换到深度思考模式吧,答案立刻就变得非常长了,首先是它的思考过程:

从微信「AI 搜素」深度思考的回答来看:快速回答和深度思考两种模式均基于DeepSeek-R1模型

然后它从「模型与功能定位」、「技术差异」、「用户体验」和「应用场景」四个方面对两种模式的区别做了详细的介绍:

最后总结是两者共享同一模型(DeepSeek-R1,为啥自家的混元模型不用呢???),他们之间最大的区别:快速回答追求效率,深度思考侧重深度。

最后的最后,你用上了微信的「AI 搜索」功能了吗?我现在是期望桌面客户端也赶快上线,这样我就可以在写代码的时候也可以快速用上了。

微信上线「AI 搜索」功能,并且接入 DeepSeek 模型!

2025年2月19日 23:46

腾讯元宝在接入 DeepSeek-R1 满血版之后,微信也开始接入 AI 大模型了,在搜索界面提供了「AI 搜索」的入口 ,本来微信就是最适合 AI 的场景,本身他就是一个聊天工具,接入一个 AI 助理水到渠成的事情。

不过微信还是比较谨慎,首先该功能还是在灰度测试中,可能部分幸运的用户才能看到,另外微信只在搜索中接入,并且在点击搜索框之后,才出现「AI 搜索」按钮:

点击该按钮进入「AI搜索」界面:

默认是「快速回复」,估计是使用腾讯自研的混元模型,然后可以切换到 DeepSeep 的「深度思考-R1」模型:

我简单问了下:

再多问一句,它也和 DeepSeep 一样,服务繁忙,请稍后再试!😅 看来刚开放,用的人太多了,看看明天上班之后能否恢复过来。😁

DeepSeek 在自然语言处理上的优势能提升微信搜索的精准度,并且结合公众号内容可以提供相比起其他平台更有竞争力的个性化答案,此外 DeepSeek 的开源属性与微信生态契合,期待微信的可以提供一些基于此提供一些开放接口,未来也可拓展智能客服等场景。

需要别人登录你的 WordPress,再也不需要给账号密码了,现在可以给「一次登录链接」了!

2025年2月16日 20:18

前面我们介绍「为什么你的 WordPress 站点老是被黑?」的时候,说到大胡子和我卖 Modular 主题,我们的售后是很负责的,😎 会在用户允许的情况下,进入后台帮忙解决,这时候我们需要对方提供一下后台的账号密码,然后就接触到了很多简单到令人发指的密码,所以网站就被黑了。

说到要求对方提供账号密码这个事情,有用户提出,其实给人账号密码也很不安全,最好是创建一个新的管理员账号,这样就不会不小心暴露自己常用密码。

一次登录链接

但是创建一个新的管理员账号也是麻烦,用完又要删除或者去修改密码。那么有没有更好的方法呢?今天想到一个好方法,就是给某个用户创建「一次登录链接」,只能使用一次,这样就不用担心「售后」的时间。✌️

我就把该功能增加到「用户管理」功能,默认是开启的:

然后在用户列表就会有「生成链接」的操作,我把原来的「生成重置密码链接」一起合并进来:

点击之后,链接类型选择「一次登录」,链接有效期默认是 3 个小时,意思是 3 个小时内该链接点击都可以登录,过了就不行。

然后复制该链接,发送给帮你解决问题的好人,就可以了。

WPJAM「用户管理」

这次一次登录链接功能,我集成到了 WPJAM 这个「用户管理」插件中,它是 WordPress 果酱知识星球福利插件,加入「WordPress果酱」知识星球(长按下图二维码)即可下载:

腾讯元宝接入 DeepSeek-R1 满血版,并且支持联网搜索!

2025年2月13日 23:03

最近 DeepSeek 老是服务器繁忙,这之前也分享了三个替代方法。现在也有新的方法了,腾讯元宝也接入 DeepSeek-R1 满血版,并且支持联网搜索。

打开腾讯元宝的网页:https://yuanbao.tencent.com/

大模型选择 DeepSeek R1,还可以开启联网搜索,试一下:「国内最强的 WordPress 个人开发者是?」

他引用了 5 篇资料作为参考,我点击了一下,前面三篇公众号文章,其中第一篇是本公众号的文章「给大家装个大的:我做的 WordPress 项目」,看来在自己公众号吹下牛,还是有好处的。

最后他的回复:

看来还是非常准确的,至少我是这样认为的。😁

除了网页版之后,腾讯元宝的 APP 也支持 DeepSeek,在应用搜索搜索「腾讯元宝」即可获取。

为何 DeepSeek 没有别人用得好,因为他们有官方提示库!

2025年2月13日 22:34

最近大家在使用 DeepSeek 的时候,感觉没有自己用起来有点不太对,怎么说呢,网上的人怎么用起来那么好,自己用就感觉没有那么好,是姿势不对,还是缺少点什么?

其实就是没有让 DeepSeek 完全了解到你的需求,就像人和人之间沟通交流一样,首先要理解别人的需求,才能够做出正确的回应,AI 再聪明,首先也得要知道你的需求。

那么如何让 AI 读懂用户的需求呢,这就需要说到提示词,简单的说,提示词就是事先给定 AI 规则和框架,让 DeepSeek 按照指定的逻辑进行推理,然后给出答案。

那么接下来的问题就变成了怎么写 DeepSeek 的提示词呢?其实完全不用担心,DeepSeek 官方提供了一个提示词库,先仔细学习一下,照着写一些,慢慢你就能成为 DeepSeek 使用大师了。

直接来,DeepSeek 官方提示词网址是:

https://api-docs.deepseek.com/zh-cn/prompt-library/

目前官方提示词库一共有 13 个:

非常好,特别前面三个就是代码相关的,特别符合程序员使用。简单点,我们就先看看「代码解释」这个提示词怎么写,点开之后:

其实非常简单,就是一句话「请解释下面这段代码的逻辑,并说明完成了什么功能:」,然后附上代码即可。

那么就来试试,我把 #WPJAM Basic# 里面的 wpjam_compare 函数的代码提供给他,让它解释一下:

这段 PHP 代码定义了一个名为 wpjam_compare 的函数,用于比较两个值 $value 和 $value2,并根据指定的比较运算符 $compare 返回比较结果。函数还支持严格模式($strict),并且在某些情况下可以处理数组和字符串的比较。

代码逻辑解析

  1. 参数处理
    • 函数接受三个参数:$value(要比较的值)、$compare(比较运算符),以及可变参数 $args(用于传递额外的参数)。
    • 如果 $compare 是一个数组,或者 $args 为空,那么函数会将 $compare 赋值给 $value2,并将 $compare 和 $strict 分别设置为空字符串和 false
    • 否则,$value2 会被赋值为 $args[0]$strict 会被赋值为 $args[1](如果存在),否则为 false
  2. 比较运算符处理
    • 如果 $compare 不为空,函数会将其转换为大写,并检查是否存在对应的反义词(如 != 的反义词是 =)。
    • 如果存在反义词,函数会递归调用自身,并使用反义词进行比较,然后返回取反的结果。
  3. 默认比较运算符
    • 如果 $compare 为空,函数会根据 $value2 的类型(数组或非数组)来设置默认的比较运算符 IN 或 =
  4. 特殊比较运算符处理
    • 如果比较运算符是 IN 或 BETWEEN,函数会对 $value2 进行处理:
      • 对于 IN,如果 $value2 是数组且只有一个元素,函数会将 $value2 转换为该元素,并将比较运算符改为 =
      • 对于 BETWEEN$value2 应该是一个包含两个元素的数组,表示范围。
  5. 比较操作
    • 根据 $compare 的值,函数会执行不同的比较操作:
      • =:使用 == 或 ===(取决于 $strict)进行比较。
      • > 和 <:分别使用 > 和 < 进行比较。
      • IN:如果 $value 是数组,函数会检查数组中的所有元素是否都在 $value2 中;否则,检查 $value 是否在 $value2 中。
      • BETWEEN:检查 $value 是否在 $value2 指定的范围内。
  6. 返回值
    • 函数根据比较结果返回 true 或 false

功能总结

wpjam_compare 函数的主要功能是比较两个值 $value 和 $value2,并根据指定的比较运算符 $compare 返回比较结果。函数支持多种比较运算符(如 =><INBETWEEN 等),并且可以处理数组和字符串的比较。此外,函数还支持严格模式($strict),在严格模式下使用 === 进行比较。

这个函数可以用于复杂的条件判断场景,特别是在需要处理多种比较运算符和数组的情况下。

完全没有问题,比我自己讲解得更清楚。😁

非常重要的是,DeepSeek 官方提示库最后一个提示词是「模型提示词生成」,可以指导用户生成自己所需的提示词:

怎么使用,由于 DeepSeek 经常服务器繁忙,今天演示比较困难。😅

之后我再给大家演示怎么生成自己所需要的提示词工具。大家有什么已经生成好的提示词也可以留言分享给大家。最后再说下 DeepSeek 官方提示库的地址:

https://api-docs.deepseek.com/zh-cn/prompt-library/

为什么你的 WordPress 站点老是被黑?根本就没啥复杂的原因,就是因为……

2025年2月5日 23:21

因为你的 WordPress 密码太简单了,坏人根本都不用什么牛逼工具或者利用什么 0day 漏洞,只要简单撞下库就能破解!

为什么这么说呢?

因为大胡子和我卖 Modular 主题,我们的售后是很负责的,除了在群里回答问题之外,一些用户复杂的问题,在说不清楚的情况下,我们会在用户允许的情况下,进入后台帮忙解决,甚至他们站点被黑了也会找我们帮忙解决,这时候我们需要对方提供一下后台的账号密码,然后就接触到了很多简单到令人发指的密码。😅

这些密码简单到什么程度,请看下面截图:

所以根本不用在讲什么大道理,这么多赤裸裸和血淋淋的事实,大家应该明白为什么 WordPress 会被黑吧。如果你的密码还是那么简单,快去改一下密码,不然下次被黑可能就是你了。😂

并且 WordPress 后台也会提示你的密码是否足够复杂了,如果是 123456 这种,就会显示非常弱:

如果是累下面这种 WordPress 自动生成的,则会显示强:

建议大家都一定要设置成「强」的密码!

最后大家来看看我们的 Modular 主题,我们售后很负责的。另外你有没有朋友,使用很简单密码的那种,来分享你朋友简单的密码。😁

使用 DeepSeek 写代码也是一把好手,我简单通过两次问答就实现链式调用的支持

2025年2月4日 22:43

今天发现 WPJAM_Field 这个字段处理类中好几个方法都是传递 $value 进去,处理之后再返回 $value,这个感觉上很类似 JavaScript 工具库 underscore 的链式调用,所以打算实现一下链式调用,我自己是试了几次实现感觉都很麻烦,于是直接让 DeepSeek 来帮我实现,为了方便提问,我也把把相关代码省略了一下:

假设我有个这样一个 PHP Class,它的几个方法比如 validate prepare unpackpack 等,都是传入一个 $value,处理之后返回 $value,参考如下,具体处理代码我省略了:

class WPJAM_Field{
	public function validate($value, $for=''){
		// 省略具体的处理代码

		return $value;
	}

	public function pack($value){
		// 省略具体的处理代码

		return $value;
	}

	public function unpack($data){
		// 省略具体的处理代码

		return $value;
	}

	public function prepare($args){
		// 省略具体的处理代码

		return $value;
	}

	// 其他方法
}

现在我不能改动这些方法,因为其他地方已经使用了,但是我想实现链式调用,有没有方法?

我开启了深度思考,DeepSeek 太牛逼了,把各种情况都给考虑了一遍,他首先去理解链式调用的关键点,然后怎么实现,自己尝试想到的每种方法,可能的问题等,最后得出最佳解:

嗯,用户有一个PHP类WPJAM_Field,里面有几个方法比如validate、prepare、unpack和pack,这些方法都接收一个值,处理之后返回。现在用户想实现链式调用,但不能修改现有方法,因为其他地方已经在使用了。这需要找到一个解决方案,既能保持原有方法的兼容性,又能添加链式调用的支持。

首先,链式调用的关键点是每个方法返回对象实例本身,也就是$this。这样每次调用方法后可以继续调用其他方法。但用户现有的方法都是返回处理后的$value,而不是对象实例,所以直接修改这些方法的返回值会破坏现有代码。因此,不能直接在这些方法中添加return $this。

那该怎么办呢?可能需要创建一个新的类,或者使用某种包装器,将原有类的方法进行封装,使得每次调用后返回实例本身,同时保留原有的处理逻辑。或者,是否可以在现有类中添加新的方法,比如链式调用的版本,例如在方法名后面加上Chainable,比如validateChainable,然后在这些新方法中调用原有方法处理值,并将处理后的值存储起来,同时返回$this。

或者,是否可以使用__call魔术方法来拦截方法调用,并在调用原有方法之后返回$this?但这样的话,如何处理$value的传递呢?因为每个方法处理的是传入的$value,并返回处理后的值。如果链式调用需要每个方法处理同一个值,并将处理后的值传递给下一个方法,那么可能需要维护一个中间值,比如在类中添加一个属性,比如$currentValue,然后在每个链式方法中更新这个值。

例如,用户可能需要这样调用:

$field = new WPJAM_Field();

$result = $field->validate('input')->pack()->get();

这时候,每个方法需要处理当前的$currentValue,并将结果保存回$currentValue,然后返回$this。但原有的方法都是接收外部传入的$value,并返回处理后的值。所以,如果要在链式调用中使用这些方法,可能需要将这些方法包装成处理内部保存的值。

那么可能的步骤是:

1. 在WPJAM_Field类中添加一个属性,比如protected $chainableValue,用来保存链式调用过程中处理的值。

2. 创建新的方法,比如validateChain、packChain等,这些方法会使用$this->chainableValue作为输入,调用原有的validate、pack等方法,然后将结果保存回$this->chainableValue,并返回$this以支持链式调用。

3. 添加一个方法,比如getValue(),用于在链式调用结束后获取处理后的值。

但是这样需要用户改变调用方式,使用新的方法名,这可能不太方便,或者需要用户适应新的方法名。或者是否可以使用魔术方法或者某种方式,使得用户仍然可以调用原有的方法名,但自动处理链式调用的逻辑?

另一个思路是创建一个装饰器类,包装原有的WPJAM_Field实例,在装饰器中维护当前处理的值,并将每个方法调用转换为对装饰器内部值的处理,并返回装饰器实例本身。例如:

class WPJAM_FieldChainable {

protected $field;

protected $currentValue;

public function __construct(WPJAM_Field $field, $initialValue) {

$this->field = $field;

$this->currentValue = $initialValue;

}

public function validate($for = '') {

$this->currentValue = $this->field->validate($this->currentValue, $for);

return $this;

}

public function pack() {

$this->currentValue = $this->field->pack($this->currentValue);

return $this;

}

// 其他方法类似...

public function get() {

return $this->currentValue;

}

}

然后用户可以这样使用:

$originalField = new WPJAM_Field();

$chainable = new WPJAM_FieldChainable($originalField, $initialValue);

$result = $chainable->validate()->pack()->get();

这样,用户不需要修改原有的WPJAM_Field类,而是通过装饰器来实现链式调用。不过,这需要用户创建一个新的对象,并且初始值需要传入。这可能是一个可行的办法,但用户可能需要调整他们的代码结构,或者提供一个更便捷的方式来创建链式调用的实例。

或者,是否可以在WPJAM_Field类中添加一个方法,比如chain($value),该方法返回一个链式调用的包装器实例,例如:

class WPJAM_Field {

// 原有方法...

public function chain($value) {

return new WPJAM_FieldChainable($this, $value);

}

}

这样用户就可以这样调用:

$field = new WPJAM_Field();

$result = $field->chain($input)->validate()->pack()->get();

这可能是一个比较方便的方式,用户只需要添加chain方法,并且其他方法不需要改动。而WPJAM_FieldChainable类负责处理链式调用,每次调用方法后返回自身,并更新内部的值。

不过,这样需要在WPJAM_Field类中添加chain方法,而用户可能不希望修改原有类,或者用户可能无法修改该类?如果用户不能修改该类,那么可能需要使用装饰器模式,不修改原有类,而是在外部创建一个包装类。

或者,用户是否可以扩展原有的类,创建一个子类,添加链式调用的方法?例如:

class WPJAM_ChainableField extends WPJAM_Field {

protected $chainValue;

public function chain($value) {

$this->chainValue = $value;

return $this;

}

public function validate($for = '') {

$this->chainValue = parent::validate($this->chainValue, $for);

return $this;

}

public function pack() {

$this->chainValue = parent::pack($this->chainValue);

return $this;

}

// 其他方法重写...

public function get() {

return $this->chainValue;

}

}

但这样需要覆盖原有的方法,将它们的返回值改为$this,这可能会影响原有代码中调用这些方法的方式。例如,原来的代码可能期望调用validate()返回处理后的值,而子类中的validate()返回$this,这会破坏原有功能。所以这可能不可行。

因此,回到最初的思路,用户不能修改原有方法,所以必须找到一种不改变原有方法返回值的方法。可能的解决方案是使用一个包装类,将每个方法的调用转换为对内部值的处理,并维护该值,同时返回实例本身。

因此,最终的解决方案可能是创建一个新的类,例如WPJAM_FieldChain,该类包含一个WPJAM_Field的实例和一个当前值。然后,这个新类有与原有类相同的方法名,但每个方法都接受较少的参数(例如不需要传递$value,因为值保存在内部),处理内部值,并返回$this。用户需要将原有类的实例传递给这个新类的构造函数,或者新类内部创建原有类的实例。

例如:

class WPJAM_FieldChain {

protected $field;

protected $value;

public function __construct(WPJAM_Field $field, $initialValue) {

$this->field = $field;

$this->value = $initialValue;

}

public function validate($for = '') {

$this->value = $this->field->validate($this->value, $for);

return $this;

}

public function pack() {

$this->value = $this->field->pack($this->value);

return $this;

}

public function unpack($data) {

// 注意:原方法可能需要参数,比如unpack的参数是$data,但这里可能不需要,或者如何处理?

// 比如,可能这个方法的链式调用需要不同的处理方式?

// 这里可能需要重新考虑参数的问题。

// 原方法unpack的参数是$data,返回$value。但在链式调用中,可能需要将$data作为初始值?

// 或者unpack可能不适用于链式调用?

// 这可能是一个问题,因为原方法的参数可能不同,比如unpack需要$data,而其他方法需要不同的参数。

// 所以,可能需要处理各个方法的参数差异。

// 例如,对于unpack,可能在链式调用中,用户需要传递参数,比如:

$this->value = $this->field->unpack($data);

return $this;

}

public function prepare($args) {

// 原prepare方法接受$args,并返回$value,这里如何处理?

$this->value = $this->field->prepare($args);

return $this;

}

public function get() {

return $this->value;

}

}

然后用户的使用方式可能如下:

$originalField = new WPJAM_Field();

$chain = new WPJAM_FieldChain($originalField, $initialValue);

$result = $chain->validate()->pack()->get();

但是,这样的问题在于,每个方法可能需要不同的参数。例如,validate方法可能需要$for参数,而prepare需要$args参数。因此,在链式调用的每个方法中,需要允许用户传递这些参数。例如,调用$chain->validate('some_for'),这时候在WPJAM_FieldChain的validate方法中,需要接受$for参数,并将其传递给原field的validate方法。

因此,上面的例子中的validate方法应该接受$for参数,例如:

public function validate($for = '') {

$this->value = $this->field->validate($this->value, $for);

return $this;

}

这样,用户可以在链式调用时传递必要的参数,例如:

$chain->validate('for_something')->pack();

对于其他方法,如unpack,可能需要不同的参数。例如,原unpack方法接收$data参数,但在链式调用中,可能需要将$data作为初始值,或者如何处理?例如,假设原unpack方法是从$data中提取某个值,那么在链式调用中,可能需要调用unpack并将结果保存到当前值中:

public function unpack($data) {

$this->value = $this->field->unpack($data);

return $this;

}

但这样,unpack的参数是外部传入的$data,而不是处理当前的值。这可能与链式调用的预期不同。例如,其他方法如validate和pack都是处理当前的值,而unpack则是处理传入的$data,并替换当前的值。这可能符合用户的需求,但需要明确。

例如,用户可能希望链式调用是这样的:

$chain->unpack($data)->validate()->pack();

这时候,unpack处理传入的$data,得到value,保存到链中的当前值,然后validate处理该值,接着pack处理后的结果。

这可能符合预期,所以在这种情况下,unpack的参数是外部的$data,而其他方法处理当前值。因此,在链式调用中,unpack可能用于设置初始值,或者根据具体情况处理。

同样,prepare方法可能需要参数,例如:

public function prepare($args) {

$this->value = $this->field->prepare($args);

return $this;

}

但原prepare方法接收$args参数,并返回处理后的value。这可能意味着,在链式调用中,prepare的参数是某个$args,处理后的结果成为当前值。例如,用户可能需要:

$chain->prepare(['some' => 'args'])->validate()->pack();

这样,prepare处理传入的$args,并将结果作为当前值,之后继续处理。

这样看来,这个解决方案是可行的。用户需要创建一个新的链式调用包装类,该类接受原始Field实例和初始值,然后每个方法调用将处理当前值(可能需要其他参数),并返回自身,最后通过get方法获取结果。

但用户可能需要不同的初始值传递方式。例如,用户可能不想在构造函数中传入初始值,而是通过某个方法设置初始值。例如:

$chain->setValue($initialValue)->validate()->pack();

但为了简化,可能在构造函数中传入初始值比较方便。

总结解决方案:

1. 创建一个新的包装类,例如WPJAM_FieldChain,内部持有WPJAM_Field的实例和当前处理的值。

2. 该包装类为每个需要链式调用的方法创建对应的方法,这些方法接受相应的参数,调用原始类的方法处理当前值(或传入的参数),然后保存结果到当前值,并返回$this。

3. 添加一个get方法,用于获取最终处理后的值。

这样,用户在不修改原有类的情况下,可以通过这个包装类实现链式调用。例如:

$originalField = new WPJAM_Field();

$chain = new WPJAM_FieldChain($originalField, $initialValue);

$result = $chain->validate('for')->pack()->get();

或者,如果用户希望更简洁,可以在原有类中添加一个方法返回包装类的实例:

class WPJAM_Field {

// 原有方法...

public function chain($value) {

return new WPJAM_FieldChain($this, $value);

}

}

这样用户可以直接:

$result = $field->chain($value)->validate()->pack()->get();

当然,这需要用户能修改原有类,添加chain方法。如果用户不能修改原有类,则需要手动创建包装类的实例。

因此,最终的解决方案是使用装饰器模式或包装类,将原有类的方法包装成链式调用的形式,维护处理过程中的值,并在每个方法调用后返回实例本身,从而支持链式调用。

DeepSeek 给出了答案:

为了实现链式调用而不修改原有的 WPJAM_Field 类,可以采用 装饰器模式 创建一个新的类,该类包装原类的实例并维护处理过程中的值。以下是具体实现步骤:

1. 创建链式调用的装饰器类

class WPJAM_FieldChain {
    protected $field;
    protected $value;

    public function __construct(WPJAM_Field $field, $initialValue) {
        $this->field = $field;
        $this->value = $initialValue;
    }

    public function validate($for = '') {
        $this->value = $this->field->validate($this->value, $for);
        return $this; // 返回自身以支持链式
    }

    public function pack() {
        $this->value = $this->field->pack($this->value);
        return $this;
    }

    public function unpack($data) {
        $this->value = $this->field->unpack($data);
        return $this;
    }

    public function prepare($args) {
        $this->value = $this->field->prepare($args);
        return $this;
    }

    // 其他需要链式的方法...

    public function get() {
        return $this->value; // 获取最终结果
    }
}

2. 使用示例

// 原类实例
$originalField = new WPJAM_Field();

// 创建链式实例,传入初始值
$chain = new WPJAM_FieldChain($originalField, $initialValue);

// 链式调用
$result = $chain->validate('for_something')
               ->pack()
               ->get();

// 或者处理其他逻辑
$processed = $chain->unpack($data)
                  ->prepare(['arg' => 'value'])
                  ->validate()
                  ->get();

3. 可选优化:添加 chain 方法到原类(若允许修改)

如果允许在 WPJAM_Field 中添加方法,可以简化链式对象的创建:

class WPJAM_Field {
    // 原有方法...

    public function chain($value) {
        return new WPJAM_FieldChain($this, $value);
    }
}

// 使用方式
$result = $originalField->chain($input)
                       ->validate()
                       ->pack()
                       ->get();

方案优势

  • 无侵入性:无需修改原类代码,完全兼容已有逻辑。
  • 灵活处理参数:每个链式方法可接受原方法所需参数,透明传递。
  • 维护状态:内部维护 value 状态,链式调用自然传递处理结果。

此方案通过包装类巧妙地将原有方法转换为链式操作,兼顾了兼容性和扩展性。


太牛逼了,完全实现了我的想法,唯一一点缺陷是就是如果我有新方法需要链式调用,那么装饰器类也要新增一次,并且 WPJAM_FieldChain 这个类的名字貌似只是给 WPJAM_Field 使用,缺乏通用性,那就让 DeepSeek 再优化一下:

非常棒,但是还有 2 点小问题,如果 WPJAM_Field 有新方法需要链式调用,那么装饰器类也要新增一次,能否使用 __call 魔术方法?并且 WPJAM_FieldChain 这个类的名字貌似只是给 WPJAM_Field 使用,缺乏通用性。但是这个链式调用应该都通用的,可以改成 WPJAM_Chainable 这个名字是否合适?

和前面一样一定认真阅读它的深度思考过程,相比具体的代码实现,它的思考过程对我们编程能力和解决问题能力提高帮助更大,这里我就不再复制过来,因为太长了,并且还是深深震撼了我,我直接给出他的答案:

解决方案:利用 __call 提升灵活性和通用性

针对原有方案的改进需求,我们可以通过以下方式实现更灵活、更通用的链式调用:

1. 使用 __call 魔术方法自动代理方法调用

通过 __call 方法动态转发调用到原对象,自动处理参数和返回值,无需为每个方法编写重复代码。

class WPJAM_Chainable {
    protected $object;  // 原对象(如 WPJAM_Field)
    protected $value;   // 当前处理的值

    public function __construct($object, $initialValue) {
        $this->object = $object;
        $this->value = $initialValue;
    }

    public function __call($method, $args) {
        if (method_exists($this->object, $method)) {
            // 通过反射检查方法是否需要 $value 作为第一个参数
            $reflectionMethod = new \ReflectionMethod($this->object, $method);
            $parameters = $reflectionMethod->getParameters();

            // 如果方法的第一个参数名为 "value",自动插入当前值
            if (!empty($parameters) && $parameters[0]->getName() === 'value') {
                array_unshift($args, $this->value);
            }

            // 调用原方法并更新值
            $this->value = call_user_func_array([$this->object, $method], $args);
            return $this; // 链式返回
        }

        throw new \BadMethodCallException("Method {$method} does not exist.");
    }

    public function get() {
        return $this->value; // 获取最终结果
    }
}

2. 增强通用性:类名和参数约定

  • 类名优化:将 WPJAM_FieldChain 改为通用的 WPJAM_Chainable,表明它是一个通用的链式调用包装器。
  • 参数约定:约定原对象的方法若需要处理当前值,则其第一个参数必须命名为 $value(如 validate($value, ...)),否则直接透传用户参数(如 unpack($data))。

3. 使用方法

基本调用

$field = new WPJAM_Field();
$chain = new WPJAM_Chainable($field, $initialValue);

$result = $chain->validate('for_something')  // 自动插入 $value 作为第一个参数
               ->pack()                      // 自动插入 $value
               ->unpack($externalData)       // 直接透传 $externalData
               ->get();

可选优化:添加 chain 快捷方法(若允许修改原类)

class WPJAM_Field {
    // 原有方法...

    public function chain($value) {
        return new WPJAM_Chainable($this, $value);
    }
}

// 使用方式
$result = $field->chain($input)
               ->validate('for_something')
               ->pack()
               ->get();

方案优势

  1. 无需手动同步方法
    通过 __call 动态代理,原类新增方法时,只要符合参数约定(如第一个参数为 $value),链式调用自动生效,无需修改 WPJAM_Chainable
  2. 通用性设计
    • 类名 WPJAM_Chainable 表明其通用性,可复用于任何需要链式调用的类。
    • 通过反射和参数约定,灵活适配不同方法签名。
  3. 兼容性保障
    • 完全无需修改原类代码,无侵入式扩展。
    • 对 unpack($data) 等特殊方法,直接透传用户参数,兼容性强。

注意事项

  • 参数命名约定:需确保原类中需要处理当前值的方法,其第一个参数命名为 $value
  • 返回值约定:原方法必须返回处理后的值,以便链式传递。
  • 异常处理:通过 BadMethodCallException 明确提示不存在的方法调用。

此方案通过动态代理和约定优于配置的原则,实现了高度灵活和通用的链式调用,兼顾了代码简洁性和扩展性。


牛逼🐂🍺,厉害厉害,下一版本中,WPJAM Basic 我就加入这个 WPJAM_Chainable 的 class。感觉以后些任何功能都可以让 DeepSeek 来帮忙写了,比自己写的还考虑的周全完善。自己把握一下方向就好了,嘻嘻!大家 DeepSeek 也赶快用起来吧!

如果基于 DeepSeek 开发 WordPress 的插件,它自己会选择什么功能?

2025年1月30日 21:54

今年最火的就是 DeepSeek 了,各种新闻,把英伟达的股票都干没了10 几个点。我也在想做一个基于 DeepSeep 的 WordPress 插件,但是做什么方向的的功能呢?要不这个功能也让 DeepSeek 帮我们也想想?

DeepSeek 的使用和 ChatGPT 之类其他的 AI 工具是有区别,他是基于推理型的大模型,而不是指令型的大模式,所以使用 DeepSeek 根本不需要提示词,直接就好了。

所以我的问题就直接把自己的目的告诉,我想写个 DeepSeek 的插件,需要给些功能灵感:

我想基于 DeepSeek 写个 WordPress 插件,在方向上,基于你对自己理解,你觉得可以做那些功能呢,你可以给我一些灵感吗?

然后我 开启了深度思考模式,DeepSeek 给出了它对这个问题的推理过程:

然后他给出了自己的建议,它还非常贴心的分成几个小标题,一共提供内容生产力、智能交互增强、数据智能分析和效率增强功能四大方向,每个方向还提供了2 个小功能,大家看看这些功能建议如何,并且它还非常贴心的提供技术实现要点,以及如何赚钱,也就是商业化建议

基于 DeepSeek 的能力和 WordPress 生态需求,以下是几个值得探索的插件开发方向,按优先级排序并附具体实现思路:


一、内容生产力工具(核心场景)

  1. AI 文章助手
    • 自动草稿生成:根据用户输入关键词自动生成结构化大纲(支持Markdown)
    • 智能续写/改写:通过浮动工具栏实现选中内容的优化/扩写/简写
    • SEO 增强:实时分析内容并推荐关键词密度、生成meta描述
    • 技术实现:结合Gutenberg编辑器API + 内容缓存机制降低API调用成本
  2. 多模态内容生成
    • 基于文本描述自动生成特色图片(需集成DeepSeek-Visual)
    • 智能生成文章配图说明文字(ALT文本优化)
    • 自动创建信息图描述文本

二、智能交互增强

  1. 对话式知识库
    • 将网站文档/产品目录转化为可对话的知识库
    • 实现路径:定期爬取指定页面内容构建向量数据库
    • 示例场景:客户服务机器人、产品FAQ交互
  2. 实时评论互动
    • 智能回复用户评论(可设置白名单词库限制)
    • 情感分析自动标记高风险评论
    • 支持预设行业话术模板(电商/教育等)

三、数据智能分析

  1. 流量内容洞察
    • 结合GA数据生成自然语言分析报告
    • 自动识别高跳出率页面的内容问题
    • 预测内容生命周期并提供更新建议
  2. 竞品内容监测
    • 定期抓取竞品RSS进行摘要对比
    • 生成差异化创作建议(需配置代理抓取)

四、效率增强功能

  1. 智能翻译工作流
    • 一键生成多语言版本并保持SEO结构
    • 支持术语表维护和翻译风格预设
    • 实现:WPML兼容 + 增量翻译缓存
  2. 自动化运营
    • 定期自动生成节日营销文案
    • 社交媒体帖子自动生成与排期
    • 结合Zapier实现跨平台自动化

技术实现要点

  1. 性能优化
    • 实现内容缓存池(基于文章ID的版本控制)
    • 支持异步队列处理长文本任务
    • 本地语义相似度计算减少API调用
  2. 安全合规
    • 内容审核过滤层(可对接DeepSeek审核API)
    • 用户数据脱敏处理
    • GDPR兼容设计(数据暂存策略)
  3. 扩展架构
    • 提供webhook接入点
    • 开发REST API扩展模块
    • 支持与WooCommerce等流行插件的数据打通

商业化建议

  • 分层定价策略
    • 免费版:基础内容生成(限次/水印)
    • 专业版:高级分析+多语言(订阅制)
    • 企业版:私有化部署+定制模型
  • 流量变现
    • 内置AI写作模版市场
    • 对接第三方云服务返佣
    • 提供A/B测试数据服务

建议初期聚焦内容生成核心场景,采用「AI功能+SEO工具」组合拳切入市场,后续通过用户行为数据分析逐步扩展智能运营功能。可参考Jarvis(Conversion.ai)的增长路径,但需注意WordPress生态的特殊性,强化与经典插件(Yoast SEO、Elementor)的兼容性。


大家觉得如何?希望首先实现哪个方向的插件?可以给我留言,我争取2 月份就先做个简单的插件出来给大家用用。😁

DMIT 多款美西 3 网优化的 VPS 补货了,年付仅需 39.9 美元起!

2025年1月29日 23:46

还是先简单介绍下 DMIT,DMIT 成立于2017,是一家海外 VPS 的厂商,主营中国香港、美国洛杉矶、日本东京等地区的 VPS,拥有对国内访问友好(CN2 GIA+CMIN2)的优化路线,稳定不掉速,并且基本也不超售,是著名VPS厂商搬瓦工(Bandwagonhost)的上游之一。

DMIT 39.9

为了方便大家理解,先对线路的名称做下说明:😄

  • CN2GIA 是指中国电信的高端优化路线
  • CMIN2 是指中国移动的高端优化路线

下面是这次 DMIT 这次的优惠的套餐:

LAX.EB.WEE(3网CMI2)推荐

  • 1vCPU(EPYC 9654)
  • 1GB RAM
  • 20GB SSD
  • 1000GB /月流量(1Gbps)
  • 1 IPv4 & 1 IPv6 /64
  • 39.9美元/年

测试 IP:154.17.226.2

购买链接:https://www.dmit.io/aff.php?aff=9154&pid=188

LAX.EB.CORONA(3网CMI2)

  • 1vCPU(EPYC 9654)
  • 1GB RAM
  • 20GB SSD
  • 2000GB /月流量(2Gbps)
  • 1 IPv4 & 1 IPv6 /64
  • 49.9美元/年

测试 IP:154.17.226.2

购买链接:https://www.dmit.io/aff.php?aff=9154&pid=218

LAX.Pro.MALIBU(3网CN2GIA)

  • 1vCPU(EPYC 9654)
  • 1GB RAM
  • 20GB SSD
  • 1000GB /月流量(1Gbps)
  • 1 IPv4 & 1 IPv6 /64
  • 49.9美元/年

测试 IP:154.17.2.12

购买链接:https://www.dmit.io/aff.php?aff=9154&pid=186

DMIT 测评

我们对 LAX.EB.WEE(3网CMI2)做了下基本的测试,首先是 全国 TCPing(测试IP:154.17.226.2),可以说是一片绿油油(晚间测试):

探针表现也非常稳定,三网平稳,高峰期无波澜,全天候 PING 值基本没啥变动(如果是普通路线的话,晚高峰期会 Ping 值高,降速严重)。

再看下 IP 质量报告:

YABS

# ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## #
#              Yet-Another-Bench-Script              #
#                     v2025-01-01                    #
# https://github.com/masonr/yet-another-bench-script #
# ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## #
 
Wed Jan 15 08:57:41 PM UTC 2025
 
Basic System Information:
---------------------------------
Uptime     : 0 days, 0 hours, 48 minutes
Processor  : AMD EPYC 9654 96-Core Processor
CPU cores  : 1 @ 2396.398 MHz
AES-NI     : ✔ Enabled
VM-x/AMD-V : ✔ Enabled
RAM        : 958.7 MiB
Swap       : 1024.0 MiB
Disk       : 19.6 GiB
Distro     : Debian GNU/Linux 12 (bookworm)
Kernel     : 6.1.0-21-amd64
VM Type    : KVM
IPv4/IPv6  : ✔ Online / ✔ Online
 
IPv6 Network Information:
---------------------------------
ISP        : DMIT Cloud Services
ASN        : AS906 DMIT Cloud Services
Host       : DMIT Cloud Services
Location   : Los Angeles, California (CA)
Country    : United States
 
fio Disk Speed Tests (Mixed R/W 50/50) (Partition /dev/vda1):
---------------------------------
Block Size | 4k            (IOPS) | 64k           (IOPS)
  ------   | ---            ----  | ----           ---- 
Read       | 62.54 MB/s   (15.6k) | 1.07 GB/s    (16.7k)
Write      | 62.65 MB/s   (15.6k) | 1.07 GB/s    (16.8k)
Total      | 125.19 MB/s  (31.2k) | 2.15 GB/s    (33.6k)
           |                      |                     
Block Size | 512k          (IOPS) | 1m            (IOPS)
  ------   | ---            ----  | ----           ---- 
Read       | 1.02 GB/s     (1.9k) | 1.01 GB/s      (987)
Write      | 1.07 GB/s     (2.1k) | 1.07 GB/s     (1.0k)
Total      | 2.09 GB/s     (4.0k) | 2.08 GB/s     (2.0k)
 
iperf3 Network Speed Tests (IPv4):
---------------------------------
Provider        | Location (Link)           | Send Speed      | Recv Speed      | Ping           
-----           | -----                     | ----            | ----            | ----           
Clouvider       | London, UK (10G)          | 674 Mbits/sec   | 543 Mbits/sec   | 129 ms         
Leaseweb        | Singapore, SG (10G)       | 697 Mbits/sec   | 642 Mbits/sec   | 166 ms         
Leaseweb        | NYC, NY, US (10G)         | 984 Mbits/sec   | 748 Mbits/sec   | 63.2 ms        
 
iperf3 Network Speed Tests (IPv6):
---------------------------------
Provider        | Location (Link)           | Send Speed      | Recv Speed      | Ping           
-----           | -----                     | ----            | ----            | ----           
Clouvider       | London, UK (10G)          | 713 Mbits/sec   | 601 Mbits/sec   | 129 ms         
Leaseweb        | Singapore, SG (10G)       | 745 Mbits/sec   | 705 Mbits/sec   | 166 ms         
Leaseweb        | NYC, NY, US (10G)         | 987 Mbits/sec   | 697 Mbits/sec   | 63.0 ms        
 
Geekbench 5 Benchmark Test:
---------------------------------
Test            | Value                         
                |                               
Single Core     | 1551                          
Multi Core      | 1539                          
Full Test       | https://browser.geekbench.com/v5/cpu/23265464
 
Geekbench 6 Benchmark Test:
---------------------------------
Test            | Value                         
                |                               
Single Core     | 1585                          
Multi Core      | 938                           
Full Test       | https://browser.geekbench.com/v6/cpu/9953190
 
YABS completed in 17 min 56 sec

融合怪

-------------------------------------VPS融合怪测试-------------------------------------
版本:v0.1.4
测评频道: https://t.me/vps_reviews
Go项目地址:https://github.com/oneclickvirt/ecs
Shell项目地址:https://github.com/spiritLHLS/ecs
--------------------------------------系统基础信息--------------------------------------
 CPU 型号            : AMD EPYC 9654 96-Core Processor @ 2396.398 MHz
 CPU 数量            : 1 Virtual CPU(s)
 CPU 缓存            : 512 KB
 AES-NI              : ✔️ Enabled
 VM-x/AMD-V/Hyper-V  : ✔️ Enabled
 内存                : 283.62 MB / 958.71 MB
 气球驱动            : ✔️ Enabled
 虚拟内存 Swap       : 0.00 MB / 1024.00 MB
 硬盘空间            : 3.69 GB / 19.60 GB
 启动盘路径          : /dev/vda1
 系统                : debian 12.9 [x86_64] 
 内核                : 6.1.0-21-amd64
 系统在线时间        : 0 days, 00 hours, 34 minutes
 时区                : UTC
 负载                : 0.17 / 0.10 / 0.03
 虚拟化架构          : KVM
 NAT类型             : Full Cone
 TCP加速方式         : bbr
 IPV4 ASN            : AS906 DMIT
 IPV4 Location       : Los Angeles / California / United States
 IPV6 ASN            : AS906 DMIT
 IPV6 Location       : Los Angeles / California / United States
 IPv6 子网掩码       : /64
--------------------------------CPU测试-通过sysbench测试--------------------------------
1 线程测试(单核)得分:   4364.81
--------------------------------内存测试-通过sysbench测试---------------------------------
单线程顺序写速度: 30915.78 MB/s(32.42K IOPS, 5s)
单线程顺序读速度: 46886.73 MB/s(49.16K IOPS, 5s)
-----------------------------------硬盘测试-通过fio测试-----------------------------------
测试路径      块大小   读测试(IOPS)            写测试(IOPS)            总和(IOPS)
/root         4k       62.55 MB/s(15.6k)       62.66 MB/s(15.7k)       125.21 MB/s(31.3k)      
/root         64k      1.07 GB/s(16.6k)        1.07 GB/s(16.7k)        2.14 GB/s(33.4k)        
/root         512k     1.02 GB/s(1995)         1.08 GB/s(2101)         2.10 GB/s(4096)         
/root         1m       1.01 GB/s(989)          1.08 GB/s(1055)         2.09 GB/s(2044)         
-------------------------------------跨国流媒体解锁--------------------------------------
IPV4:
============[ 跨国平台 ]============
Dazn                      Banned
Disney+                   NO (forbidden-location)
Netflix                   Restricted (Originals Only)
Netflix CDN               US
YouTube Region            YES (Region: US)
YouTube CDN               LAX
Amazon Prime Video        YES (Region: US)
Paramount+                YES
TVBAnywhere+              YES (Region: US)
IQiYi                     YES (Region: US)
Viu.com                   YES
Spotify Registration      NO
Steam Store               YES (Community Available) (Region: US)
ChatGPT                   YES (Region: US)
Sora                      YES (Region: US)
Gemini                    YES (Region: USA)
MetaAI                    YES (Region: US)
Wikipedia Editability     NO
Reddit                    NO
TikTok                    YES (Region: US)
Bing Region               YES (Risky) (Region: US)
Instagram Licensed Audio  YES
KOCOWA                    YES
SonyLiv                   NO (Proxy Detected) (Region: US)
OneTrust                  YES (Region: US CALIFORNIA)
GoogleSearch              YES
-------------------------------------三网回程线路检测-------------------------------------
北京电信 219.141.140.10  移动CMIN2  [精品线路] 
北京联通 202.106.195.68  移动CMIN2  [精品线路] 联通4837   [普通线路] 
北京移动 221.179.155.161 移动CMIN2  [精品线路] 
上海电信 202.96.209.133  移动CMIN2  [精品线路] 电信163    [普通线路] 
上海联通 210.22.97.1     移动CMIN2  [精品线路] 
上海移动 211.136.112.200 移动CMIN2  [精品线路] 
广州电信 58.60.188.222   移动CMIN2  [精品线路] 电信163    [普通线路] 
广州联通 210.21.196.6    移动CMIN2  [精品线路] 联通4837   [普通线路] 
广州移动 120.196.165.24  移动CMIN2  [精品线路] 
成都电信 61.139.2.69     移动CMIN2  [精品线路] 
成都联通 119.6.6.6       移动CMIN2  [精品线路] 联通4837   [普通线路] 
成都移动 211.137.96.205  移动CMIN2  [精品线路] 
-------------------------------------三网回程路由检测-------------------------------------
[NextTrace API] preferred API IP - 104.21.48.1 - 51.02ms - Misaka.LAX
广州电信 - ICMP v4 - traceroute to 58.60.188.222, 30 hops max, 52 byte packets
0.24 ms      AS906      [DMIT-BB]          Anycast, Anycast, DMIT.com 
0.64 ms      AS906      [DMIT-BB]          美国, 加利福尼亚, 洛杉矶, DMIT.com 
0.78 ms      AS906      [DMIT-BB]          美国, 加利福尼亚, 洛杉矶, DMIT.com 
126.91 ms    AS58807    [CMIN2-NET]        美国, 加利福尼亚, 洛杉矶, cmi.chinamobile.com  移动
126.17 ms    AS58807    [CMIN2-NET]        中国, 上海, cmi.chinamobile.com  移动
127.55 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
127.09 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
128.02 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com 
167.80 ms    AS9808     [CMNET]            中国, 广东, 广州, chinamobileltd.com  移动
158.20 ms    AS9808     [CMNET]            中国, 广东, 广州, chinamobileltd.com  移动
*
207.43 ms    AS4134     [CHINANET-BB]      中国, 广东, 广州, www.chinatelecom.com.cn  电信
156.82 ms    AS134774   [CHINANET-GD]      中国, 广东, 深圳, chinatelecom.cn  电信
*
161.06 ms    AS4134                        中国, 广东, 深圳, www.chinatelecom.com.cn  电信
广州联通 - ICMP v4 - traceroute to 210.21.196.6, 30 hops max, 52 byte packets
0.22 ms      AS906      [DMIT-BB]          Anycast, Anycast, DMIT.com 
0.48 ms      AS906      [DMIT-BB]          美国, 加利福尼亚, 洛杉矶, DMIT.com 
0.84 ms      AS906      [DMIT-BB]          美国, 加利福尼亚, 洛杉矶, DMIT.com 
126.73 ms    AS58807    [CMIN2-NET]        美国, 加利福尼亚, 洛杉矶, cmi.chinamobile.com  移动
126.09 ms    AS58807    [CMIN2-NET]        中国, 上海, cmi.chinamobile.com  移动
126.20 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
126.14 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
126.98 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
154.14 ms    AS9808     [CMNET]            中国, 广东, 广州, chinamobileltd.com  移动
153.71 ms    AS9808     [CMNET]            中国, 广东, 广州, chinamobileltd.com  移动
269.49 ms    AS4837     [CU169-BACKBONE]   中国, 广东, 广州, chinaunicom.cn 
*
167.66 ms    AS17816    [APNIC-AP]         中国, 广东, 深圳, chinaunicom.cn  联通
181.77 ms    AS17623    [APNIC-AP]         中国, 广东, 深圳, chinaunicom.cn  联通
168.55 ms    AS17623                       中国, 广东, 深圳, chinaunicom.cn  联通
广州移动 - ICMP v4 - traceroute to 120.196.165.24, 30 hops max, 52 byte packets
0.23 ms      AS906      [DMIT-BB]          Anycast, Anycast, DMIT.com 
2.24 ms      AS906      [DMIT-BB]          美国, 加利福尼亚, 洛杉矶, DMIT.com 
0.64 ms      AS906      [DMIT-BB]          美国, 加利福尼亚, 洛杉矶, DMIT.com 
126.17 ms    AS58807    [CMIN2-NET]        美国, 加利福尼亚, 洛杉矶, cmi.chinamobile.com  移动
126.09 ms    AS58807    [CMIN2-NET]        中国, 上海, cmi.chinamobile.com  移动
126.11 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
126.24 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
126.56 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
148.94 ms    AS9808     [CMNET]            中国, 北京, chinamobileltd.com  移动
150.48 ms    AS9808     [CMNET]            中国, 北京, chinamobileltd.com  移动
*
152.08 ms    AS56040    [APNIC-AP]         中国, 广东, 深圳, gd.10086.cn  移动
--------------------------------------就近节点测速--------------------------------------
位置            上传速度        下载速度        延迟            丢包率          
Speedtest.net   1041.71 Mbps    998.97 Mbps     0.33 ms         0.0%            
洛杉矶          1047.87 Mbps    1001.83 Mbps    0.67 ms         0.0%            
法兰克福        556.37 Mbps     885.65 Mbps     148.49 ms       0.0%            
联通上海5G      723.41 Mbps     375.84 Mbps     151.79 ms       2.2%            
联通Wu Xi       808.67 Mbps     803.87 Mbps     149.33 ms       0.0%            
电信浙江        594.87 Mbps     604.07 Mbps     147.60 ms       0.0%
电信浙江        597.95 Mbps     618.77 Mbps     134.21 ms       0.0% 
移动Beijing     903.87 Mbps     388.01 Mbps     149.03 ms       0.0%            
----------------------------------------------------------------------------------
花费          : 8 分 31 秒
时间          : Wed Jan 15 20:52:03 UTC 2025
----------------------------------------------------------------------------------

DMIT 总结

  • 性能:DMIT升级过一次配置,CPU性能非常不错,磁盘 IO 也是 nvme 水准;
  • 线路:三网 CMIN2 回程(移动高端优化线路),无晚高峰波动,稍逊于电信 CN2GIA,奈何 CMIN2 给的太多了(流量);
  • 灵度:DMIT 是2017 成立的大厂了和瓦工一类的,灵度无需担心;
  • 价格:39.9 美元/年的价格,1T 的三网 CMIN2 回程,价格相当不错!
  • 直达链接:https://www.dmit.io/aff.php?aff=9154&pid=188

WordPress 是如何缓存的?对象缓存(Object Cache)详细介绍和使用!

2025年1月20日 23:43

任何技术要彻底了解它是怎么工作的,则要去了解它的机制和原理,WordPress 优化也是一样,如果要深度理解如何优化 WordPress,那么就要去了解 WordPress 对象缓存的原理和机制。

所以那么今天就来详细讲解一下 WordPress 缓存的底层原理对象缓存(Object Cache),以及在开发的时候如何使用它对 WordPress 进行加速。

WordPress 对象缓存和服务器设置

WordPress 对象缓存(英文名是:Object Cache)就是 WordPress 的缓存机制,它的主要功能是把数据库查询结果或者复杂运算的结果按照 Key-Value 这样的方式存储到对象里面,此外 WordPress 还支持按照 Group 来按组划分,以避免缓存内容的冲突。下次进行同样操作的时候,可以让直接从这个对象中取出数据,不用重复到数据库中或者其他外部获取数据。

WordPress 对象缓存和服务器设置关系很大,如果系统开启了 #Memcached# 内存缓存,则这个对象是直接存入到内存,在数据未过期之前,以后再次读取这个数据都是直接从内存中读取的,这样效率和速度都非常快的。

如果服务器不支持内存缓存的话,则只能保证在当前页面(PHP同个进程下)下同样的查询或者操作不再重复从数据库中读取了。

WordPress 对象缓存的函数

WordPress 对象缓存技术使用是非常简单的,其核心就是掌握下面下面这四个函数:

  • 添加数据到缓存中:
    wp_cache_add($key, $data, $group='', $expire=0)
  • 设置数据到缓存中:
    wp_cache_set($key, $data, $group='', $expire=0)
  • 获取缓存中的数据:
    wp_cache_get($key, $group='', $force=false, &$found=null)
  • 删除缓存中的数据:
    wp_cache_delete($key, $group='')

这四个函数会涉及到参数我罗列到一起简单讲下,下面知道个大概,可以收藏,方便使用的时候回来查看,重点还是后面的应用:

参数解释
$key数据在缓存中的健名
$data要缓存的数据,获取和删除函数无需用这个参数
$group缓存要添加到的组
$expire过期时间,可选参数,获取和删除函数无需用这个参数
如果是默认缓存,这个参数没用,如果是内存缓存,是设置缓存的时间。
单位是秒,默认为0(0 的意思就是永远,不会自动过期)
$force这个是获取缓存函数独有的函数,设置为 true 则强制使用持久缓存更新本地缓存
$found这个也是获取缓存函数独有的函数,它是一个引用参数,用于存储是否在缓存中找到 key,可以用于消除返回 false 的歧义

使用 WordPress 对象缓存

下面以我以 WordPress 相关文章为例,讲讲如何使用 WordPress 对象缓存。

我们知道 WordPress 相关文章插件是通过 tag 和分类来获取相关文章,文章使用相同的 tag 和分类越多,则认为为相关性越强,这样就需要进行多个表联合查询来获取相关文章,连表查询效率一般是比较差的。比如下面是一个比较通用的从数据库中查找相关文章的函数:

function wpjam_get_related_posts($post_id){
	global $wpdb;

	$term_ids   = wp_get_post_terms($post_id, ['category', 'post_tag'], ['fields' => 'ids']);
	$terms_ids  = implode(',', $term_ids);

	$related_posts = $wpdb->get_results("
		SELECT object_id, COUNT(*) as count
		FROM $wpdb->term_relationships
		WHERE term_taxonomy_id IN ($terms_string) AND object_id != $post_id
		GROUP BY object_id
		ORDER BY count DESC
		LIMIT 10"
	);

	foreach($related_posts as &$post){
		$post = get_post($post->object_id);
	}

	return $related_posts;
}

上面的函数,首先获取文章的标签和分类,然后基于使用相同的标签和分类的数量,通过 SQL 获取相似度最高的 10 篇文章的 ID,然后再相应获取对应的文章(这里为了简化,一般应该要根据文章 ID 批量文章,防止同时多条 SQL 请求)。

但是另外一方面,一篇文章,如果它的标签和分类没有修改的话,那么它的相关文章在一段时间内是不会变动的,所以相关文章的功能就非常适合使用 WordPress 对象缓存进行缓存加速加速。

我们就可以使用 wp_cache_set 函数就是把把相关文章的数据写入缓存的例子,使用当前 post_id 作为 key,related_posts 作为 group,缓存时间为一个小时,即 3600 秒。

$related_posts_data = wpjam_get_related_posts($post->ID);
wp_cache_set($post->ID,$related_posts_data,'related_posts',3600);

把数据存到缓存对象之后,在显示相关文章的时候,就可以使用 wp_cache_get 调用这个对象缓存来使用。

一般的流程是这样的,首先检查下是否已经有相应的缓存,如果你要的信息没有在缓存中,或者已经过期,wp_cache_get() 会返回 false,这时,你就要去数据库中重新获取这些信息,否则就返回在缓存中的信息。

$related_posts_data = wp_cache_get($post->ID,'related_posts');

if(false === $related_posts_data){
	$related_posts_data = wpjam_get_related_posts($post->ID);
	wp_cache_set($post->ID,$related_posts_data,'related_posts',3600);
}

因为设置了一个小时,相关文章的数据就失效,再次显示的时候会重新请求,,如果你在后台更改了设置,需要立即清理缓存,可以通过相关的 Hook 使用 wp_cache_delete 进行清理:

wp_cacache_delete($post->ID,'related_posts');

这里只是简单删除一下,更详细怎么使用 Hook 的例子,可以去 #WPJAM Basic# 的相关文章扩展中查看详情。

WPJAM 终极方法

通过上面的例子,看到使用 object_cache 都是首先要使用 wp_cache_get 函数去获取,如果不存在,再使用 wp_cache_set 函数去存储,有没有更加方便的方法呢?

有的,#WPJAM Basic# 提供了一个 wpjam_cache 的方法,可以将这个过程合并了,比如上面的例子,可以通过下面的代码实现:

$related_posts_data = wpjam_cache($post->ID,'related_posts', fn()=> wpjam_get_related_posts($post->ID), 3600);

它有四个参数,前面两个和 wp_cache_get() 函数一样,第三个参数是一个回调函数,它会在对象缓存不存在的时候被调用,获取数据并存到缓存中,从而实现自动实现缓存的过程,第四个是缓存时长。可以说除了第三个参数之外,其他参数和 wp_cache_xxx 函数的参数基本一致,使用也更加简洁,是一种高阶函数的写法。

总结

WordPress 对象缓存(Object Cache)是 WordPress 缓存机制,是深入了解对 WordPress 优化的基础,如果要熟悉 WordPress 开发和应用,都要有掌握好他。此外,WPJAM Basic 集成的 wpjam_cache 函数进一步提高使用效率,只需一步就实现 WordPress 对象缓存。


WPJAM Basic 插件已经集成了 Memcached,下载 WPJAM Basic 之后,将 wpjam-basic/template/ 目录下的 object-cache.php 文件复制到 wp-content 目录下即可。

「用户管理」:一键实现用户名称优化,用户安全增强,自定义头像等多项功能 WordPress 插件

2025年1月4日 19:22

这是基于 WPJAM Basic 的超强的 WordPress 用户管理的插件,有多强大呢,首先看后台的设置界面:

可以说它把 WordPress 相关的用户管理功能都集成了,简单数一数就实现了十多个 WordPress 用户相关功能:

  1. 屏蔽个性化设置
  2. 屏蔽姓氏和名字设置
  3. 取消显示名称设置
  4. 开启别名设置
  5. 隐藏用户登录名
  6. 开启登录次数限制
  7. 用户最后登录时间
  8. 取消「应用程序密码」
  9. 按注册时间排序
  10. 以此身份登陆
  11. 生成密码重置链接
  12. 自定义用户头像
  13. 默认用户头像

下面我们分成五大模块分别来介绍 WPJAM 的「用户管理插件」具体实现了那些功能:

屏蔽个性化设置

WordPress后台个人资料用户可以设置「可视化编辑器」,「语法高亮」,「配色方案」,「键盘快捷键」,「工具栏」,「语言」等这些个性化选项,如下图:

这些选项 WordPress 都是存储到 usermeta 表里面,如果 WordPress 有大量的用户,每个用户会占用7个选项,那么 usermeta 表很快就会爆炸。

比如我运营的 WordPress 站点,有几十万用户,usermeta 表的数据如果不清理的话,已经千万级了,查点东西都慢的要死,如果你和我有一样的困扰,那就可以在插件中勾选实现屏蔽用户的个性化设置,直接采用使用系统全局的默认值。然后还可以根据自己的需求删除这些选项。

用户名称优化

在默认情况下,WordPress 后台个人资料页面中,关于用户的姓名相关的设置是这样的:

是不是有点繁琐,并且很多字段也是存到 usermeta 表中的,我个人觉得关于用户昵称的设置,尽量简洁就好,所以名字和姓氏一般就不需要用户输入,公开显示的名字直接为昵称就好了,所以插件首先提供了下面两个选项:

  • 屏蔽姓名设置:屏蔽了姓氏和名字设置,简化后台个人资料界面设置。
  • 显示名称设置:取消显示名称选择器,直接使用昵称作为显示名称。

另外插件还支持开启了别名设置,是的,我们不仅仅做减法,偶尔也做下加法,这里可以让用户可以编辑自己的别名(user_nicename),这样只要不使用和登录名相同的别名,作者文章链接就不会暴露用户名,当然没有设置别名,插件还是有安全选项来实现防止用户名暴露。

所以优化之后最终的用户界面非常简洁,如下所示:

安全增强

WordPres 用户安全增强体现在两个地方,首先是隐藏登录名,不要让攻击者猜到用户名,然后是开启登录限制,防止密码被暴力破解,插件也提供这两方面的选项:

首先说一下如何隐藏登录名,如果用户没有修改过别名(user_nicename),那么他的别名和登录名(user_login)是一样的,然后作者文章链接或者其他地方就会暴露登录名,为了进一步防止登录名暴露,我们提供了隐藏登录名的选项:

勾选「防止登录名暴露」之后,如果用户的 user_nicenameuser_login 是一样的情况下:

1. 作者文章链接使用 author_id 代替 user_nicename,并且原来的作者链接直接设置为 404 页面,防止用户名暴露

2. user_login 不出现在 body_classcomment_class 中。

3. 隐藏登录失败时候未知用户名和密码不正确的错误信息,这两种情况都显示「用户名或者密码错误」,让攻击者猜去。😁

4. 取消作者相关的 sitemap 以及 REST API 中可以查看所有发布过文章的用户信息列表的中的登录名。

如果真的被攻击者猜到了登录名,那么我们还可以开启登录限制,限制登录失败次数,这样就可以防止密码被暴力破解了,进一步做到安全。

功能增强

除了安全增强之外,我们还增加了一个小功能和屏蔽一个功能,分别是记录用户最后登录时间和取消「应用程序密码」功能:

首先新增记录用户最后登录时间,用户登录之后,在后台用户列表就会显示该用户的最后登录时间,并且支持按照用户最后登录时间进行排序。

默认情况下在后台个人资料页面可以设置「应用程序密码」:

应用程序密码允许通过非交互式系统(例如 XML-RPC 或 REST API)进行身份验证,而无需提供您的实际密码。应用密码可以随时撤销。它们不能用于通过传统方式登录您的网站。

很多人看到这个其实是稀里糊涂,简单说他就是用于 APP 或者小程序通过接口来登录的,但是基本上来说,我们用不到这个功能,所以默认建议屏蔽它。

后台用户列表

对于管理员经常使用的用户列表,也新增一些功能和操作:

首先用户可以除了可以按照上面提示按照最后登录事件排序之外,也可以按照用户注册时间排序,只要你勾选了用户列表里的第一个选项,此外在用户列表页面新增两个操作「以此身份登陆」和「生成密码重置链接」:

如果你是 WordPress 开发者,「以此身份登陆」这个功能特别实用,在用户列表界面,管理员可以轻松以用户的身份登录后台,这样用户说他碰到什么问题,就可以直接登录他的账号去看了,而不是问他要账号密码,这个多难为情啊。😳

WordPress 原来「发送密码重置邮件」这个功能是直接发送密码重置邮件给用户,用户在邮箱里面直接点击操作,改成「生成密码重置链接」,则管理员直接获取密码重置链接,可以通过微信或者其他的社交媒体工具发给用户。

头像设置

在后台个人资料页,用户可以自定义自己的头像。

如果用户没有设置头像,管理员可以设置默认头像,然后随机给用户使用:

最后用户头像还多加一个选项,就是如果用户已经在 Gravatar 里面设置了头像怎么办?有两个选项,从默认中随机选一个,继续使用 Gravatar 的设置。

总结

通过上面的介绍,是不是非常强大,目前我所有用户相关的功能整合到 WPJAM-User 的插件中,只需后台简单的勾选就可以实现绝大部分用户安全和管理相关的功能。


「WordPress果酱」知识星球福利插件基于 WPJAM Basic 开发,加入「WordPress果酱」知识星球,即可下载:

插件 简介
抓取公众号图文

支持一键同步微信公众号文章到 WordPress 博客,并支持一键将文章中所有图片都下载到 WordPress 媒体库。

搜索优化

WordPress 最强的搜索优化插件,支持限制每个 IP 每分钟搜索次数,达到上限之后屏蔽搜索时长,还可以限制搜索关键词的长度,搜索结果页面限制只显示「搜索结果」,还有以下搜索功能增强:

1. 只搜索文章标题,不搜索文章内容和摘要。
2. 当搜索关键词为空时重定向到首页,只有一篇文章时重定向到文章
3. 后台文章列表支持搜索ID。
4. 支持搜索自定义字段。

编辑器优化

一键增强 WordPress 经典 TinyMCE 编辑器:

1. 增加下划线,背景颜色,两端对齐,字体和大小设置,以及内容分页按钮。
2. 新增插入表格功能。
3. 直接插入屏幕截图。

标题设置

一键设置 WordPress 所有页面的页面标题,通过规则方式让博主可以自定义 WordPres 首页,分类,文章类型,文章详情都所有页面的页面标题。

登录优化

一键优化 WordPress 登录注册界面,并支持第三方账号登录和绑定,目前已经支持微信公众号(所有类型),微信小程序,手机号码第三方平台。

内容模板

实现在内容中插入一段共用的内容模板,通过短代码(shortcode)的方式来实现的,支持统一修改,目前支持普通的内容模板,表格内容模板和卡片内容模板三种类型。

用户管理

最强 WordPress 一键用户管理插件,一键实现以下12个功能:

1. 屏蔽个性化设置
2. 屏蔽姓氏和名字设置
3. 取消显示名称设置
4. 开启别名设置
5. 隐藏用户登录名
6. 开启登录次数限制
7. 用户最后登录时间
8. 按注册时间排序
9. 以此身份登陆
10. 生成密码重置链接
11. 自定义用户头像
12. 默认用户头像

分类管理

这是一个全能的 WordPress 分类管理插件:

1. 层式管理分类
2. 限制分类层级
3. 分类拖动排序
4. 使用数字固定链接
5. 首页文章支持分类过滤
6. 后台文章列表支持分类筛选过滤
7. 后台文章列表支持分类多重筛选

评论增强

这是一个 WordPress 评论增强插件,支持评论置顶,评论点赞和按照点赞数排序。

图片集

1. 给媒体创建个分类「图片集 | collection」
2. 图片分类限制为二级
3. 取消图片编辑入口
4. 附件页面直接图片链接。

配置器

全自动 WordPress 配置器,不用一行代码就可以开发。
支持自定义文章类型,自定义字段,自定义分类,分类选项,全局选项。

Script Loader

通过恢复 WordPress 联合加载方式来优化 WordPress 后台脚本加载。

外部链接

将文章或评论中的外部链接加上安全提示的中间页。
让用户确认之后再跳转,并还支持添加 nofollow rel 属性。

话题标签

文章中插入 #话题标签#。
如果是内部链接,直接跳转,
标签或者分类,则自动转换成标签或分类链接,
否则跳转到搜索链接。

格式文章

在 WordPress 实现真正的文章格式

草稿分享

一键生成草稿临时分享链接
并可设置分享链接的有效期

文章专题

设置文章专题,并在文章末尾显示一个文章专题列表。

文章隐藏

设置文章在列表⻚不显示,并且可以根据不同平台进行设置

Meta Data

可视化管理 WordPress Meta 数据,支持所有内置的 Meta 数据:
Post Meta,Term Meta,User Meta 和 Comment Meta。

站点选项

查看和管理所有非 WordPress 系统自动生成的站点选项。
如果你觉得某个选项无用,可以直接删除它。

后台论坛

WordPress 后台论坛,支持创建帖子,分组,消息。

微信小程序

微信小程序 WordPress 基础插件,包含基础类库和管理。

微信群二维码

轮询显示微信群二维码,突破微信群100人限制。

文章置顶

支持置顶文章排序和分类文章置顶的 WordPress 插件

静态文件

一键合并 WordPress 插件和主题的 JS 和 CSS 文件,加快页面加载速度

Debug

一键检测 WordPress 运行效率。

腾讯元宝接入 DeepSeek-R1 满血版,并且支持联网搜索!

2025年2月13日 23:03

最近 DeepSeek 老是服务器繁忙,这之前也分享了三个替代方法。现在也有新的方法了,腾讯元宝也接入 DeepSeek-R1 满血版,并且支持联网搜索。

打开腾讯元宝的网页:https://yuanbao.tencent.com/

大模型选择 DeepSeek R1,还可以开启联网搜索,试一下:「国内最强的 WordPress 个人开发者是?」

他引用了 5 篇资料作为参考,我点击了一下,前面三篇公众号文章,其中第一篇是本公众号的文章「给大家装个大的:我做的 WordPress 项目」,看来在自己公众号吹下牛,还是有好处的。

最后他的回复:

看来还是非常准确的,至少我是这样认为的。😁

除了网页版之后,腾讯元宝的 APP 也支持 DeepSeek,在应用搜索搜索「腾讯元宝」即可获取。

为何 DeepSeek 没有别人用得好,因为他们有官方提示库!

2025年2月13日 22:34

最近大家在使用 DeepSeek 的时候,感觉没有自己用起来有点不太对,怎么说呢,网上的人怎么用起来那么好,自己用就感觉没有那么好,是姿势不对,还是缺少点什么?

其实就是没有让 DeepSeek 完全了解到你的需求,就像人和人之间沟通交流一样,首先要理解别人的需求,才能够做出正确的回应,AI 再聪明,首先也得要知道你的需求。

那么如何让 AI 读懂用户的需求呢,这就需要说到提示词,简单的说,提示词就是事先给定 AI 规则和框架,让 DeepSeek 按照指定的逻辑进行推理,然后给出答案。

那么接下来的问题就变成了怎么写 DeepSeek 的提示词呢?其实完全不用担心,DeepSeek 官方提供了一个提示词库,先仔细学习一下,照着写一些,慢慢你就能成为 DeepSeek 使用大师了。

直接来,DeepSeek 官方提示词网址是:

https://api-docs.deepseek.com/zh-cn/prompt-library/

目前官方提示词库一共有 13 个:

非常好,特别前面三个就是代码相关的,特别符合程序员使用。简单点,我们就先看看「代码解释」这个提示词怎么写,点开之后:

其实非常简单,就是一句话「请解释下面这段代码的逻辑,并说明完成了什么功能:」,然后附上代码即可。

那么就来试试,我把 #WPJAM Basic# 里面的 wpjam_compare 函数的代码提供给他,让它解释一下:

这段 PHP 代码定义了一个名为 wpjam_compare 的函数,用于比较两个值 $value 和 $value2,并根据指定的比较运算符 $compare 返回比较结果。函数还支持严格模式($strict),并且在某些情况下可以处理数组和字符串的比较。

代码逻辑解析

  1. 参数处理
    • 函数接受三个参数:$value(要比较的值)、$compare(比较运算符),以及可变参数 $args(用于传递额外的参数)。
    • 如果 $compare 是一个数组,或者 $args 为空,那么函数会将 $compare 赋值给 $value2,并将 $compare 和 $strict 分别设置为空字符串和 false
    • 否则,$value2 会被赋值为 $args[0]$strict 会被赋值为 $args[1](如果存在),否则为 false
  2. 比较运算符处理
    • 如果 $compare 不为空,函数会将其转换为大写,并检查是否存在对应的反义词(如 != 的反义词是 =)。
    • 如果存在反义词,函数会递归调用自身,并使用反义词进行比较,然后返回取反的结果。
  3. 默认比较运算符
    • 如果 $compare 为空,函数会根据 $value2 的类型(数组或非数组)来设置默认的比较运算符 IN 或 =
  4. 特殊比较运算符处理
    • 如果比较运算符是 IN 或 BETWEEN,函数会对 $value2 进行处理:
      • 对于 IN,如果 $value2 是数组且只有一个元素,函数会将 $value2 转换为该元素,并将比较运算符改为 =
      • 对于 BETWEEN$value2 应该是一个包含两个元素的数组,表示范围。
  5. 比较操作
    • 根据 $compare 的值,函数会执行不同的比较操作:
      • =:使用 == 或 ===(取决于 $strict)进行比较。
      • > 和 <:分别使用 > 和 < 进行比较。
      • IN:如果 $value 是数组,函数会检查数组中的所有元素是否都在 $value2 中;否则,检查 $value 是否在 $value2 中。
      • BETWEEN:检查 $value 是否在 $value2 指定的范围内。
  6. 返回值
    • 函数根据比较结果返回 true 或 false

功能总结

wpjam_compare 函数的主要功能是比较两个值 $value 和 $value2,并根据指定的比较运算符 $compare 返回比较结果。函数支持多种比较运算符(如 =><INBETWEEN 等),并且可以处理数组和字符串的比较。此外,函数还支持严格模式($strict),在严格模式下使用 === 进行比较。

这个函数可以用于复杂的条件判断场景,特别是在需要处理多种比较运算符和数组的情况下。

完全没有问题,比我自己讲解得更清楚。😁

非常重要的是,DeepSeek 官方提示库最后一个提示词是「模型提示词生成」,可以指导用户生成自己所需的提示词:

怎么使用,由于 DeepSeek 经常服务器繁忙,今天演示比较困难。😅

之后我再给大家演示怎么生成自己所需要的提示词工具。大家有什么已经生成好的提示词也可以留言分享给大家。最后再说下 DeepSeek 官方提示库的地址:

https://api-docs.deepseek.com/zh-cn/prompt-library/

需要别人登录你的 WordPress,再也不需要给账号密码了,现在可以给「一次登录链接」了!

2025年2月10日 23:22

前面我们介绍「为什么你的 WordPress 站点老是被黑?」的时候,说到大胡子和我卖 Modular 主题,我们的售后是很负责的,😎 会在用户允许的情况下,进入后台帮忙解决,这时候我们需要对方提供一下后台的账号密码,然后就接触到了很多简单到令人发指的密码,所以网站就被黑了。

说到要求对方提供账号密码这个事情,有用户提出,其实给人账号密码也很不安全,最好是创建一个新的管理员账号,这样就不会不小心暴露自己常用密码。

一次登录链接

但是创建一个新的管理员账号也是麻烦,用完又要删除或者去修改密码。那么有没有更好的方法呢?今天想到一个好方法,就是给某个用户创建「一次登录链接」,只能使用一次,这样就不用担心「售后」的时间。✌️

我就把该功能增加到「用户管理」功能,默认是开启的:

然后在用户列表就会有「生成链接」的操作,我把原来的「生成重置密码链接」一起合并进来:

点击之后,链接类型选择「一次登录」,链接有效期默认是 3 个小时,意思是 3 个小时内该链接点击都可以登录,过了就不行。

然后复制该链接,发送给帮你解决问题的好人,就可以了。

WPJAM「用户管理」

这次一次登录链接功能,我集成到了 WPJAM 这个「用户管理」插件中,它是 WordPress 果酱知识星球福利插件,加入「WordPress果酱」知识星球(长按下图二维码)即可下载:

为什么你的 WordPress 站点老是被黑?根本就没啥复杂的原因,就是因为……

2025年2月5日 23:21

因为你的 WordPress 密码太简单了,坏人根本都不用什么牛逼工具或者利用什么 0day 漏洞,只要简单撞下库就能破解!

为什么这么说呢?

因为大胡子和我卖 Modular 主题,我们的售后是很负责的,除了在群里回答问题之外,一些用户复杂的问题,在说不清楚的情况下,我们会在用户允许的情况下,进入后台帮忙解决,甚至他们站点被黑了也会找我们帮忙解决,这时候我们需要对方提供一下后台的账号密码,然后就接触到了很多简单到令人发指的密码。😅

这些密码简单到什么程度,请看下面截图:

所以根本不用在讲什么大道理,这么多赤裸裸和血淋淋的事实,大家应该明白为什么 WordPress 会被黑吧。如果你的密码还是那么简单,快去改一下密码,不然下次被黑可能就是你了。😂

并且 WordPress 后台也会提示你的密码是否足够复杂了,如果是 123456 这种,就会显示非常弱:

如果是累下面这种 WordPress 自动生成的,则会显示强:

建议大家都一定要设置成「强」的密码!

最后大家来看看我们的 Modular 主题,我们售后很负责的。另外你有没有朋友,使用很简单密码的那种,来分享你朋友简单的密码。😁

使用 DeepSeek 写代码也是一把好手,我简单通过两次问答就实现链式调用的支持

2025年2月4日 22:43

今天发现 WPJAM_Field 这个字段处理类中好几个方法都是传递 $value 进去,处理之后再返回 $value,这个感觉上很类似 JavaScript 工具库 underscore 的链式调用,所以打算实现一下链式调用,我自己是试了几次实现感觉都很麻烦,于是直接让 DeepSeek 来帮我实现,为了方便提问,我也把把相关代码省略了一下:

假设我有个这样一个 PHP Class,它的几个方法比如 validate prepare unpackpack 等,都是传入一个 $value,处理之后返回 $value,参考如下,具体处理代码我省略了:

class WPJAM_Field{
	public function validate($value, $for=''){
		// 省略具体的处理代码

		return $value;
	}

	public function pack($value){
		// 省略具体的处理代码

		return $value;
	}

	public function unpack($data){
		// 省略具体的处理代码

		return $value;
	}

	public function prepare($args){
		// 省略具体的处理代码

		return $value;
	}

	// 其他方法
}

现在我不能改动这些方法,因为其他地方已经使用了,但是我想实现链式调用,有没有方法?

我开启了深度思考,DeepSeek 太牛逼了,把各种情况都给考虑了一遍,他首先去理解链式调用的关键点,然后怎么实现,自己尝试想到的每种方法,可能的问题等,最后得出最佳解:

嗯,用户有一个PHP类WPJAM_Field,里面有几个方法比如validate、prepare、unpack和pack,这些方法都接收一个值,处理之后返回。现在用户想实现链式调用,但不能修改现有方法,因为其他地方已经在使用了。这需要找到一个解决方案,既能保持原有方法的兼容性,又能添加链式调用的支持。

首先,链式调用的关键点是每个方法返回对象实例本身,也就是$this。这样每次调用方法后可以继续调用其他方法。但用户现有的方法都是返回处理后的$value,而不是对象实例,所以直接修改这些方法的返回值会破坏现有代码。因此,不能直接在这些方法中添加return $this。

那该怎么办呢?可能需要创建一个新的类,或者使用某种包装器,将原有类的方法进行封装,使得每次调用后返回实例本身,同时保留原有的处理逻辑。或者,是否可以在现有类中添加新的方法,比如链式调用的版本,例如在方法名后面加上Chainable,比如validateChainable,然后在这些新方法中调用原有方法处理值,并将处理后的值存储起来,同时返回$this。

或者,是否可以使用__call魔术方法来拦截方法调用,并在调用原有方法之后返回$this?但这样的话,如何处理$value的传递呢?因为每个方法处理的是传入的$value,并返回处理后的值。如果链式调用需要每个方法处理同一个值,并将处理后的值传递给下一个方法,那么可能需要维护一个中间值,比如在类中添加一个属性,比如$currentValue,然后在每个链式方法中更新这个值。

例如,用户可能需要这样调用:

$field = new WPJAM_Field();

$result = $field->validate('input')->pack()->get();

这时候,每个方法需要处理当前的$currentValue,并将结果保存回$currentValue,然后返回$this。但原有的方法都是接收外部传入的$value,并返回处理后的值。所以,如果要在链式调用中使用这些方法,可能需要将这些方法包装成处理内部保存的值。

那么可能的步骤是:

1. 在WPJAM_Field类中添加一个属性,比如protected $chainableValue,用来保存链式调用过程中处理的值。

2. 创建新的方法,比如validateChain、packChain等,这些方法会使用$this->chainableValue作为输入,调用原有的validate、pack等方法,然后将结果保存回$this->chainableValue,并返回$this以支持链式调用。

3. 添加一个方法,比如getValue(),用于在链式调用结束后获取处理后的值。

但是这样需要用户改变调用方式,使用新的方法名,这可能不太方便,或者需要用户适应新的方法名。或者是否可以使用魔术方法或者某种方式,使得用户仍然可以调用原有的方法名,但自动处理链式调用的逻辑?

另一个思路是创建一个装饰器类,包装原有的WPJAM_Field实例,在装饰器中维护当前处理的值,并将每个方法调用转换为对装饰器内部值的处理,并返回装饰器实例本身。例如:

class WPJAM_FieldChainable {

protected $field;

protected $currentValue;

public function __construct(WPJAM_Field $field, $initialValue) {

$this->field = $field;

$this->currentValue = $initialValue;

}

public function validate($for = '') {

$this->currentValue = $this->field->validate($this->currentValue, $for);

return $this;

}

public function pack() {

$this->currentValue = $this->field->pack($this->currentValue);

return $this;

}

// 其他方法类似...

public function get() {

return $this->currentValue;

}

}

然后用户可以这样使用:

$originalField = new WPJAM_Field();

$chainable = new WPJAM_FieldChainable($originalField, $initialValue);

$result = $chainable->validate()->pack()->get();

这样,用户不需要修改原有的WPJAM_Field类,而是通过装饰器来实现链式调用。不过,这需要用户创建一个新的对象,并且初始值需要传入。这可能是一个可行的办法,但用户可能需要调整他们的代码结构,或者提供一个更便捷的方式来创建链式调用的实例。

或者,是否可以在WPJAM_Field类中添加一个方法,比如chain($value),该方法返回一个链式调用的包装器实例,例如:

class WPJAM_Field {

// 原有方法...

public function chain($value) {

return new WPJAM_FieldChainable($this, $value);

}

}

这样用户就可以这样调用:

$field = new WPJAM_Field();

$result = $field->chain($input)->validate()->pack()->get();

这可能是一个比较方便的方式,用户只需要添加chain方法,并且其他方法不需要改动。而WPJAM_FieldChainable类负责处理链式调用,每次调用方法后返回自身,并更新内部的值。

不过,这样需要在WPJAM_Field类中添加chain方法,而用户可能不希望修改原有类,或者用户可能无法修改该类?如果用户不能修改该类,那么可能需要使用装饰器模式,不修改原有类,而是在外部创建一个包装类。

或者,用户是否可以扩展原有的类,创建一个子类,添加链式调用的方法?例如:

class WPJAM_ChainableField extends WPJAM_Field {

protected $chainValue;

public function chain($value) {

$this->chainValue = $value;

return $this;

}

public function validate($for = '') {

$this->chainValue = parent::validate($this->chainValue, $for);

return $this;

}

public function pack() {

$this->chainValue = parent::pack($this->chainValue);

return $this;

}

// 其他方法重写...

public function get() {

return $this->chainValue;

}

}

但这样需要覆盖原有的方法,将它们的返回值改为$this,这可能会影响原有代码中调用这些方法的方式。例如,原来的代码可能期望调用validate()返回处理后的值,而子类中的validate()返回$this,这会破坏原有功能。所以这可能不可行。

因此,回到最初的思路,用户不能修改原有方法,所以必须找到一种不改变原有方法返回值的方法。可能的解决方案是使用一个包装类,将每个方法的调用转换为对内部值的处理,并维护该值,同时返回实例本身。

因此,最终的解决方案可能是创建一个新的类,例如WPJAM_FieldChain,该类包含一个WPJAM_Field的实例和一个当前值。然后,这个新类有与原有类相同的方法名,但每个方法都接受较少的参数(例如不需要传递$value,因为值保存在内部),处理内部值,并返回$this。用户需要将原有类的实例传递给这个新类的构造函数,或者新类内部创建原有类的实例。

例如:

class WPJAM_FieldChain {

protected $field;

protected $value;

public function __construct(WPJAM_Field $field, $initialValue) {

$this->field = $field;

$this->value = $initialValue;

}

public function validate($for = '') {

$this->value = $this->field->validate($this->value, $for);

return $this;

}

public function pack() {

$this->value = $this->field->pack($this->value);

return $this;

}

public function unpack($data) {

// 注意:原方法可能需要参数,比如unpack的参数是$data,但这里可能不需要,或者如何处理?

// 比如,可能这个方法的链式调用需要不同的处理方式?

// 这里可能需要重新考虑参数的问题。

// 原方法unpack的参数是$data,返回$value。但在链式调用中,可能需要将$data作为初始值?

// 或者unpack可能不适用于链式调用?

// 这可能是一个问题,因为原方法的参数可能不同,比如unpack需要$data,而其他方法需要不同的参数。

// 所以,可能需要处理各个方法的参数差异。

// 例如,对于unpack,可能在链式调用中,用户需要传递参数,比如:

$this->value = $this->field->unpack($data);

return $this;

}

public function prepare($args) {

// 原prepare方法接受$args,并返回$value,这里如何处理?

$this->value = $this->field->prepare($args);

return $this;

}

public function get() {

return $this->value;

}

}

然后用户的使用方式可能如下:

$originalField = new WPJAM_Field();

$chain = new WPJAM_FieldChain($originalField, $initialValue);

$result = $chain->validate()->pack()->get();

但是,这样的问题在于,每个方法可能需要不同的参数。例如,validate方法可能需要$for参数,而prepare需要$args参数。因此,在链式调用的每个方法中,需要允许用户传递这些参数。例如,调用$chain->validate('some_for'),这时候在WPJAM_FieldChain的validate方法中,需要接受$for参数,并将其传递给原field的validate方法。

因此,上面的例子中的validate方法应该接受$for参数,例如:

public function validate($for = '') {

$this->value = $this->field->validate($this->value, $for);

return $this;

}

这样,用户可以在链式调用时传递必要的参数,例如:

$chain->validate('for_something')->pack();

对于其他方法,如unpack,可能需要不同的参数。例如,原unpack方法接收$data参数,但在链式调用中,可能需要将$data作为初始值,或者如何处理?例如,假设原unpack方法是从$data中提取某个值,那么在链式调用中,可能需要调用unpack并将结果保存到当前值中:

public function unpack($data) {

$this->value = $this->field->unpack($data);

return $this;

}

但这样,unpack的参数是外部传入的$data,而不是处理当前的值。这可能与链式调用的预期不同。例如,其他方法如validate和pack都是处理当前的值,而unpack则是处理传入的$data,并替换当前的值。这可能符合用户的需求,但需要明确。

例如,用户可能希望链式调用是这样的:

$chain->unpack($data)->validate()->pack();

这时候,unpack处理传入的$data,得到value,保存到链中的当前值,然后validate处理该值,接着pack处理后的结果。

这可能符合预期,所以在这种情况下,unpack的参数是外部的$data,而其他方法处理当前值。因此,在链式调用中,unpack可能用于设置初始值,或者根据具体情况处理。

同样,prepare方法可能需要参数,例如:

public function prepare($args) {

$this->value = $this->field->prepare($args);

return $this;

}

但原prepare方法接收$args参数,并返回处理后的value。这可能意味着,在链式调用中,prepare的参数是某个$args,处理后的结果成为当前值。例如,用户可能需要:

$chain->prepare(['some' => 'args'])->validate()->pack();

这样,prepare处理传入的$args,并将结果作为当前值,之后继续处理。

这样看来,这个解决方案是可行的。用户需要创建一个新的链式调用包装类,该类接受原始Field实例和初始值,然后每个方法调用将处理当前值(可能需要其他参数),并返回自身,最后通过get方法获取结果。

但用户可能需要不同的初始值传递方式。例如,用户可能不想在构造函数中传入初始值,而是通过某个方法设置初始值。例如:

$chain->setValue($initialValue)->validate()->pack();

但为了简化,可能在构造函数中传入初始值比较方便。

总结解决方案:

1. 创建一个新的包装类,例如WPJAM_FieldChain,内部持有WPJAM_Field的实例和当前处理的值。

2. 该包装类为每个需要链式调用的方法创建对应的方法,这些方法接受相应的参数,调用原始类的方法处理当前值(或传入的参数),然后保存结果到当前值,并返回$this。

3. 添加一个get方法,用于获取最终处理后的值。

这样,用户在不修改原有类的情况下,可以通过这个包装类实现链式调用。例如:

$originalField = new WPJAM_Field();

$chain = new WPJAM_FieldChain($originalField, $initialValue);

$result = $chain->validate('for')->pack()->get();

或者,如果用户希望更简洁,可以在原有类中添加一个方法返回包装类的实例:

class WPJAM_Field {

// 原有方法...

public function chain($value) {

return new WPJAM_FieldChain($this, $value);

}

}

这样用户可以直接:

$result = $field->chain($value)->validate()->pack()->get();

当然,这需要用户能修改原有类,添加chain方法。如果用户不能修改原有类,则需要手动创建包装类的实例。

因此,最终的解决方案是使用装饰器模式或包装类,将原有类的方法包装成链式调用的形式,维护处理过程中的值,并在每个方法调用后返回实例本身,从而支持链式调用。

DeepSeek 给出了答案:

为了实现链式调用而不修改原有的 WPJAM_Field 类,可以采用 装饰器模式 创建一个新的类,该类包装原类的实例并维护处理过程中的值。以下是具体实现步骤:

1. 创建链式调用的装饰器类

class WPJAM_FieldChain {
    protected $field;
    protected $value;

    public function __construct(WPJAM_Field $field, $initialValue) {
        $this->field = $field;
        $this->value = $initialValue;
    }

    public function validate($for = '') {
        $this->value = $this->field->validate($this->value, $for);
        return $this; // 返回自身以支持链式
    }

    public function pack() {
        $this->value = $this->field->pack($this->value);
        return $this;
    }

    public function unpack($data) {
        $this->value = $this->field->unpack($data);
        return $this;
    }

    public function prepare($args) {
        $this->value = $this->field->prepare($args);
        return $this;
    }

    // 其他需要链式的方法...

    public function get() {
        return $this->value; // 获取最终结果
    }
}

2. 使用示例

// 原类实例
$originalField = new WPJAM_Field();

// 创建链式实例,传入初始值
$chain = new WPJAM_FieldChain($originalField, $initialValue);

// 链式调用
$result = $chain->validate('for_something')
               ->pack()
               ->get();

// 或者处理其他逻辑
$processed = $chain->unpack($data)
                  ->prepare(['arg' => 'value'])
                  ->validate()
                  ->get();

3. 可选优化:添加 chain 方法到原类(若允许修改)

如果允许在 WPJAM_Field 中添加方法,可以简化链式对象的创建:

class WPJAM_Field {
    // 原有方法...

    public function chain($value) {
        return new WPJAM_FieldChain($this, $value);
    }
}

// 使用方式
$result = $originalField->chain($input)
                       ->validate()
                       ->pack()
                       ->get();

方案优势

  • 无侵入性:无需修改原类代码,完全兼容已有逻辑。
  • 灵活处理参数:每个链式方法可接受原方法所需参数,透明传递。
  • 维护状态:内部维护 value 状态,链式调用自然传递处理结果。

此方案通过包装类巧妙地将原有方法转换为链式操作,兼顾了兼容性和扩展性。


太牛逼了,完全实现了我的想法,唯一一点缺陷是就是如果我有新方法需要链式调用,那么装饰器类也要新增一次,并且 WPJAM_FieldChain 这个类的名字貌似只是给 WPJAM_Field 使用,缺乏通用性,那就让 DeepSeek 再优化一下:

非常棒,但是还有 2 点小问题,如果 WPJAM_Field 有新方法需要链式调用,那么装饰器类也要新增一次,能否使用 __call 魔术方法?并且 WPJAM_FieldChain 这个类的名字貌似只是给 WPJAM_Field 使用,缺乏通用性。但是这个链式调用应该都通用的,可以改成 WPJAM_Chainable 这个名字是否合适?

和前面一样一定认真阅读它的深度思考过程,相比具体的代码实现,它的思考过程对我们编程能力和解决问题能力提高帮助更大,这里我就不再复制过来,因为太长了,并且还是深深震撼了我,我直接给出他的答案:

解决方案:利用 __call 提升灵活性和通用性

针对原有方案的改进需求,我们可以通过以下方式实现更灵活、更通用的链式调用:

1. 使用 __call 魔术方法自动代理方法调用

通过 __call 方法动态转发调用到原对象,自动处理参数和返回值,无需为每个方法编写重复代码。

class WPJAM_Chainable {
    protected $object;  // 原对象(如 WPJAM_Field)
    protected $value;   // 当前处理的值

    public function __construct($object, $initialValue) {
        $this->object = $object;
        $this->value = $initialValue;
    }

    public function __call($method, $args) {
        if (method_exists($this->object, $method)) {
            // 通过反射检查方法是否需要 $value 作为第一个参数
            $reflectionMethod = new \ReflectionMethod($this->object, $method);
            $parameters = $reflectionMethod->getParameters();

            // 如果方法的第一个参数名为 "value",自动插入当前值
            if (!empty($parameters) && $parameters[0]->getName() === 'value') {
                array_unshift($args, $this->value);
            }

            // 调用原方法并更新值
            $this->value = call_user_func_array([$this->object, $method], $args);
            return $this; // 链式返回
        }

        throw new \BadMethodCallException("Method {$method} does not exist.");
    }

    public function get() {
        return $this->value; // 获取最终结果
    }
}

2. 增强通用性:类名和参数约定

  • 类名优化:将 WPJAM_FieldChain 改为通用的 WPJAM_Chainable,表明它是一个通用的链式调用包装器。
  • 参数约定:约定原对象的方法若需要处理当前值,则其第一个参数必须命名为 $value(如 validate($value, ...)),否则直接透传用户参数(如 unpack($data))。

3. 使用方法

基本调用

$field = new WPJAM_Field();
$chain = new WPJAM_Chainable($field, $initialValue);

$result = $chain->validate('for_something')  // 自动插入 $value 作为第一个参数
               ->pack()                      // 自动插入 $value
               ->unpack($externalData)       // 直接透传 $externalData
               ->get();

可选优化:添加 chain 快捷方法(若允许修改原类)

class WPJAM_Field {
    // 原有方法...

    public function chain($value) {
        return new WPJAM_Chainable($this, $value);
    }
}

// 使用方式
$result = $field->chain($input)
               ->validate('for_something')
               ->pack()
               ->get();

方案优势

  1. 无需手动同步方法
    通过 __call 动态代理,原类新增方法时,只要符合参数约定(如第一个参数为 $value),链式调用自动生效,无需修改 WPJAM_Chainable
  2. 通用性设计
    • 类名 WPJAM_Chainable 表明其通用性,可复用于任何需要链式调用的类。
    • 通过反射和参数约定,灵活适配不同方法签名。
  3. 兼容性保障
    • 完全无需修改原类代码,无侵入式扩展。
    • 对 unpack($data) 等特殊方法,直接透传用户参数,兼容性强。

注意事项

  • 参数命名约定:需确保原类中需要处理当前值的方法,其第一个参数命名为 $value
  • 返回值约定:原方法必须返回处理后的值,以便链式传递。
  • 异常处理:通过 BadMethodCallException 明确提示不存在的方法调用。

此方案通过动态代理和约定优于配置的原则,实现了高度灵活和通用的链式调用,兼顾了代码简洁性和扩展性。


牛逼🐂🍺,厉害厉害,下一版本中,WPJAM Basic 我就加入这个 WPJAM_Chainable 的 class。感觉以后些任何功能都可以让 DeepSeek 来帮忙写了,比自己写的还考虑的周全完善。自己把握一下方向就好了,嘻嘻!大家 DeepSeek 也赶快用起来吧!

如果基于 DeepSeek 开发 WordPress 的插件,它自己会选择什么功能?

2025年1月30日 21:54

今年最火的就是 DeepSeek 了,各种新闻,把英伟达的股票都干没了10 几个点。我也在想做一个基于 DeepSeep 的 WordPress 插件,但是做什么方向的的功能呢?要不这个功能也让 DeepSeek 帮我们也想想?

DeepSeek 的使用和 ChatGPT 之类其他的 AI 工具是有区别,他是基于推理型的大模型,而不是指令型的大模式,所以使用 DeepSeek 根本不需要提示词,直接就好了。

所以我的问题就直接把自己的目的告诉,我想写个 DeepSeek 的插件,需要给些功能灵感:

我想基于 DeepSeek 写个 WordPress 插件,在方向上,基于你对自己理解,你觉得可以做那些功能呢,你可以给我一些灵感吗?

然后我 开启了深度思考模式,DeepSeek 给出了它对这个问题的推理过程:

然后他给出了自己的建议,它还非常贴心的分成几个小标题,一共提供内容生产力、智能交互增强、数据智能分析和效率增强功能四大方向,每个方向还提供了2 个小功能,大家看看这些功能建议如何,并且它还非常贴心的提供技术实现要点,以及如何赚钱,也就是商业化建议

基于 DeepSeek 的能力和 WordPress 生态需求,以下是几个值得探索的插件开发方向,按优先级排序并附具体实现思路:


一、内容生产力工具(核心场景)

  1. AI 文章助手
    • 自动草稿生成:根据用户输入关键词自动生成结构化大纲(支持Markdown)
    • 智能续写/改写:通过浮动工具栏实现选中内容的优化/扩写/简写
    • SEO 增强:实时分析内容并推荐关键词密度、生成meta描述
    • 技术实现:结合Gutenberg编辑器API + 内容缓存机制降低API调用成本
  2. 多模态内容生成
    • 基于文本描述自动生成特色图片(需集成DeepSeek-Visual)
    • 智能生成文章配图说明文字(ALT文本优化)
    • 自动创建信息图描述文本

二、智能交互增强

  1. 对话式知识库
    • 将网站文档/产品目录转化为可对话的知识库
    • 实现路径:定期爬取指定页面内容构建向量数据库
    • 示例场景:客户服务机器人、产品FAQ交互
  2. 实时评论互动
    • 智能回复用户评论(可设置白名单词库限制)
    • 情感分析自动标记高风险评论
    • 支持预设行业话术模板(电商/教育等)

三、数据智能分析

  1. 流量内容洞察
    • 结合GA数据生成自然语言分析报告
    • 自动识别高跳出率页面的内容问题
    • 预测内容生命周期并提供更新建议
  2. 竞品内容监测
    • 定期抓取竞品RSS进行摘要对比
    • 生成差异化创作建议(需配置代理抓取)

四、效率增强功能

  1. 智能翻译工作流
    • 一键生成多语言版本并保持SEO结构
    • 支持术语表维护和翻译风格预设
    • 实现:WPML兼容 + 增量翻译缓存
  2. 自动化运营
    • 定期自动生成节日营销文案
    • 社交媒体帖子自动生成与排期
    • 结合Zapier实现跨平台自动化

技术实现要点

  1. 性能优化
    • 实现内容缓存池(基于文章ID的版本控制)
    • 支持异步队列处理长文本任务
    • 本地语义相似度计算减少API调用
  2. 安全合规
    • 内容审核过滤层(可对接DeepSeek审核API)
    • 用户数据脱敏处理
    • GDPR兼容设计(数据暂存策略)
  3. 扩展架构
    • 提供webhook接入点
    • 开发REST API扩展模块
    • 支持与WooCommerce等流行插件的数据打通

商业化建议

  • 分层定价策略
    • 免费版:基础内容生成(限次/水印)
    • 专业版:高级分析+多语言(订阅制)
    • 企业版:私有化部署+定制模型
  • 流量变现
    • 内置AI写作模版市场
    • 对接第三方云服务返佣
    • 提供A/B测试数据服务

建议初期聚焦内容生成核心场景,采用「AI功能+SEO工具」组合拳切入市场,后续通过用户行为数据分析逐步扩展智能运营功能。可参考Jarvis(Conversion.ai)的增长路径,但需注意WordPress生态的特殊性,强化与经典插件(Yoast SEO、Elementor)的兼容性。


大家觉得如何?希望首先实现哪个方向的插件?可以给我留言,我争取2 月份就先做个简单的插件出来给大家用用。😁

WordPress 是如何缓存的?对象缓存(Object Cache)详细介绍和使用!

2025年1月20日 23:43

任何技术要彻底了解它是怎么工作的,则要去了解它的机制和原理,WordPress 优化也是一样,如果要深度理解如何优化 WordPress,那么就要去了解 WordPress 对象缓存的原理和机制。

所以那么今天就来详细讲解一下 WordPress 缓存的底层原理对象缓存(Object Cache),以及在开发的时候如何使用它对 WordPress 进行加速。

WordPress 对象缓存和服务器设置

WordPress 对象缓存(英文名是:Object Cache)就是 WordPress 的缓存机制,它的主要功能是把数据库查询结果或者复杂运算的结果按照 Key-Value 这样的方式存储到对象里面,此外 WordPress 还支持按照 Group 来按组划分,以避免缓存内容的冲突。下次进行同样操作的时候,可以让直接从这个对象中取出数据,不用重复到数据库中或者其他外部获取数据。

WordPress 对象缓存和服务器设置关系很大,如果系统开启了 #Memcached# 内存缓存,则这个对象是直接存入到内存,在数据未过期之前,以后再次读取这个数据都是直接从内存中读取的,这样效率和速度都非常快的。

如果服务器不支持内存缓存的话,则只能保证在当前页面(PHP同个进程下)下同样的查询或者操作不再重复从数据库中读取了。

WordPress 对象缓存的函数

WordPress 对象缓存技术使用是非常简单的,其核心就是掌握下面下面这四个函数:

  • 添加数据到缓存中:
    wp_cache_add($key, $data, $group='', $expire=0)
  • 设置数据到缓存中:
    wp_cache_set($key, $data, $group='', $expire=0)
  • 获取缓存中的数据:
    wp_cache_get($key, $group='', $force=false, &$found=null)
  • 删除缓存中的数据:
    wp_cache_delete($key, $group='')

这四个函数会涉及到参数我罗列到一起简单讲下,下面知道个大概,可以收藏,方便使用的时候回来查看,重点还是后面的应用:

参数解释
$key数据在缓存中的健名
$data要缓存的数据,获取和删除函数无需用这个参数
$group缓存要添加到的组
$expire过期时间,可选参数,获取和删除函数无需用这个参数
如果是默认缓存,这个参数没用,如果是内存缓存,是设置缓存的时间。
单位是秒,默认为0(0 的意思就是永远,不会自动过期)
$force这个是获取缓存函数独有的函数,设置为 true 则强制使用持久缓存更新本地缓存
$found这个也是获取缓存函数独有的函数,它是一个引用参数,用于存储是否在缓存中找到 key,可以用于消除返回 false 的歧义

使用 WordPress 对象缓存

下面以我以 WordPress 相关文章为例,讲讲如何使用 WordPress 对象缓存。

我们知道 WordPress 相关文章插件是通过 tag 和分类来获取相关文章,文章使用相同的 tag 和分类越多,则认为为相关性越强,这样就需要进行多个表联合查询来获取相关文章,连表查询效率一般是比较差的。比如下面是一个比较通用的从数据库中查找相关文章的函数:

function wpjam_get_related_posts($post_id){
	global $wpdb;

	$term_ids   = wp_get_post_terms($post_id, ['category', 'post_tag'], ['fields' => 'ids']);
	$terms_ids  = implode(',', $term_ids);

	$related_posts = $wpdb->get_results("
		SELECT object_id, COUNT(*) as count
		FROM $wpdb->term_relationships
		WHERE term_taxonomy_id IN ($terms_string) AND object_id != $post_id
		GROUP BY object_id
		ORDER BY count DESC
		LIMIT 10"
	);

	foreach($related_posts as &$post){
		$post = get_post($post->object_id);
	}

	return $related_posts;
}

上面的函数,首先获取文章的标签和分类,然后基于使用相同的标签和分类的数量,通过 SQL 获取相似度最高的 10 篇文章的 ID,然后再相应获取对应的文章(这里为了简化,一般应该要根据文章 ID 批量文章,防止同时多条 SQL 请求)。

但是另外一方面,一篇文章,如果它的标签和分类没有修改的话,那么它的相关文章在一段时间内是不会变动的,所以相关文章的功能就非常适合使用 WordPress 对象缓存进行缓存加速加速。

我们就可以使用 wp_cache_set 函数就是把把相关文章的数据写入缓存的例子,使用当前 post_id 作为 key,related_posts 作为 group,缓存时间为一个小时,即 3600 秒。

$related_posts_data = wpjam_get_related_posts($post->ID);
wp_cache_set($post->ID,$related_posts_data,'related_posts',3600);

把数据存到缓存对象之后,在显示相关文章的时候,就可以使用 wp_cache_get 调用这个对象缓存来使用。

一般的流程是这样的,首先检查下是否已经有相应的缓存,如果你要的信息没有在缓存中,或者已经过期,wp_cache_get() 会返回 false,这时,你就要去数据库中重新获取这些信息,否则就返回在缓存中的信息。

$related_posts_data = wp_cache_get($post->ID,'related_posts');

if(false === $related_posts_data){
	$related_posts_data = wpjam_get_related_posts($post->ID);
	wp_cache_set($post->ID,$related_posts_data,'related_posts',3600);
}

因为设置了一个小时,相关文章的数据就失效,再次显示的时候会重新请求,,如果你在后台更改了设置,需要立即清理缓存,可以通过相关的 Hook 使用 wp_cache_delete 进行清理:

wp_cacache_delete($post->ID,'related_posts');

这里只是简单删除一下,更详细怎么使用 Hook 的例子,可以去 #WPJAM Basic# 的相关文章扩展中查看详情。

WPJAM 终极方法

通过上面的例子,看到使用 object_cache 都是首先要使用 wp_cache_get 函数去获取,如果不存在,再使用 wp_cache_set 函数去存储,有没有更加方便的方法呢?

有的,#WPJAM Basic# 提供了一个 wpjam_cache 的方法,可以将这个过程合并了,比如上面的例子,可以通过下面的代码实现:

$related_posts_data = wpjam_cache($post->ID,'related_posts', fn()=> wpjam_get_related_posts($post->ID), 3600);

它有四个参数,前面两个和 wp_cache_get() 函数一样,第三个参数是一个回调函数,它会在对象缓存不存在的时候被调用,获取数据并存到缓存中,从而实现自动实现缓存的过程,第四个是缓存时长。可以说除了第三个参数之外,其他参数和 wp_cache_xxx 函数的参数基本一致,使用也更加简洁,是一种高阶函数的写法。

总结

WordPress 对象缓存(Object Cache)是 WordPress 缓存机制,是深入了解对 WordPress 优化的基础,如果要熟悉 WordPress 开发和应用,都要有掌握好他。此外,WPJAM Basic 集成的 wpjam_cache 函数进一步提高使用效率,只需一步就实现 WordPress 对象缓存。


WPJAM Basic 插件已经集成了 Memcached,下载 WPJAM Basic 之后,将 wpjam-basic/template/ 目录下的 object-cache.php 文件复制到 wp-content 目录下即可。

DMIT 多款美西 3 网优化的 VPS 补货了,年付仅需 39.9 美元起!

2025年1月16日 22:59

还是先简单介绍下 DMIT,DMIT 成立于2017,是一家海外 VPS 的厂商,主营中国香港、美国洛杉矶、日本东京等地区的 VPS,拥有对国内访问友好(CN2 GIA+CMIN2)的优化路线,稳定不掉速,并且基本也不超售,是著名VPS厂商搬瓦工(Bandwagonhost)的上游之一。

DMIT 39.9

为了方便大家理解,先对线路的名称做下说明:😄

  • CN2GIA 是指中国电信的高端优化路线
  • CMIN2 是指中国移动的高端优化路线

下面是这次 DMIT 这次的优惠的套餐:

LAX.EB.WEE(3网CMI2)推荐

  • 1vCPU(EPYC 9654)
  • 1GB RAM
  • 20GB SSD
  • 1000GB /月流量(1Gbps)
  • 1 IPv4 & 1 IPv6 /64
  • 39.9美元/年

测试 IP:154.17.226.2

购买链接:https://www.dmit.io/aff.php?aff=9154&pid=188

LAX.EB.CORONA(3网CMI2)

  • 1vCPU(EPYC 9654)
  • 1GB RAM
  • 20GB SSD
  • 2000GB /月流量(2Gbps)
  • 1 IPv4 & 1 IPv6 /64
  • 49.9美元/年

测试 IP:154.17.226.2

购买链接:https://www.dmit.io/aff.php?aff=9154&pid=218

LAX.Pro.MALIBU(3网CN2GIA)

  • 1vCPU(EPYC 9654)
  • 1GB RAM
  • 20GB SSD
  • 1000GB /月流量(1Gbps)
  • 1 IPv4 & 1 IPv6 /64
  • 49.9美元/年

测试 IP:154.17.2.12

购买链接:https://www.dmit.io/aff.php?aff=9154&pid=186

DMIT 测评

我们对 LAX.EB.WEE(3网CMI2)做了下基本的测试,首先是 全国 TCPing(测试IP:154.17.226.2),可以说是一片绿油油(晚间测试):

探针表现也非常稳定,三网平稳,高峰期无波澜,全天候 PING 值基本没啥变动(如果是普通路线的话,晚高峰期会 Ping 值高,降速严重)。

再看下 IP 质量报告:

YABS

# ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## #
#              Yet-Another-Bench-Script              #
#                     v2025-01-01                    #
# https://github.com/masonr/yet-another-bench-script #
# ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## #
 
Wed Jan 15 08:57:41 PM UTC 2025
 
Basic System Information:
---------------------------------
Uptime     : 0 days, 0 hours, 48 minutes
Processor  : AMD EPYC 9654 96-Core Processor
CPU cores  : 1 @ 2396.398 MHz
AES-NI     : ✔ Enabled
VM-x/AMD-V : ✔ Enabled
RAM        : 958.7 MiB
Swap       : 1024.0 MiB
Disk       : 19.6 GiB
Distro     : Debian GNU/Linux 12 (bookworm)
Kernel     : 6.1.0-21-amd64
VM Type    : KVM
IPv4/IPv6  : ✔ Online / ✔ Online
 
IPv6 Network Information:
---------------------------------
ISP        : DMIT Cloud Services
ASN        : AS906 DMIT Cloud Services
Host       : DMIT Cloud Services
Location   : Los Angeles, California (CA)
Country    : United States
 
fio Disk Speed Tests (Mixed R/W 50/50) (Partition /dev/vda1):
---------------------------------
Block Size | 4k            (IOPS) | 64k           (IOPS)
  ------   | ---            ----  | ----           ---- 
Read       | 62.54 MB/s   (15.6k) | 1.07 GB/s    (16.7k)
Write      | 62.65 MB/s   (15.6k) | 1.07 GB/s    (16.8k)
Total      | 125.19 MB/s  (31.2k) | 2.15 GB/s    (33.6k)
           |                      |                     
Block Size | 512k          (IOPS) | 1m            (IOPS)
  ------   | ---            ----  | ----           ---- 
Read       | 1.02 GB/s     (1.9k) | 1.01 GB/s      (987)
Write      | 1.07 GB/s     (2.1k) | 1.07 GB/s     (1.0k)
Total      | 2.09 GB/s     (4.0k) | 2.08 GB/s     (2.0k)
 
iperf3 Network Speed Tests (IPv4):
---------------------------------
Provider        | Location (Link)           | Send Speed      | Recv Speed      | Ping           
-----           | -----                     | ----            | ----            | ----           
Clouvider       | London, UK (10G)          | 674 Mbits/sec   | 543 Mbits/sec   | 129 ms         
Leaseweb        | Singapore, SG (10G)       | 697 Mbits/sec   | 642 Mbits/sec   | 166 ms         
Leaseweb        | NYC, NY, US (10G)         | 984 Mbits/sec   | 748 Mbits/sec   | 63.2 ms        
 
iperf3 Network Speed Tests (IPv6):
---------------------------------
Provider        | Location (Link)           | Send Speed      | Recv Speed      | Ping           
-----           | -----                     | ----            | ----            | ----           
Clouvider       | London, UK (10G)          | 713 Mbits/sec   | 601 Mbits/sec   | 129 ms         
Leaseweb        | Singapore, SG (10G)       | 745 Mbits/sec   | 705 Mbits/sec   | 166 ms         
Leaseweb        | NYC, NY, US (10G)         | 987 Mbits/sec   | 697 Mbits/sec   | 63.0 ms        
 
Geekbench 5 Benchmark Test:
---------------------------------
Test            | Value                         
                |                               
Single Core     | 1551                          
Multi Core      | 1539                          
Full Test       | https://browser.geekbench.com/v5/cpu/23265464
 
Geekbench 6 Benchmark Test:
---------------------------------
Test            | Value                         
                |                               
Single Core     | 1585                          
Multi Core      | 938                           
Full Test       | https://browser.geekbench.com/v6/cpu/9953190
 
YABS completed in 17 min 56 sec

融合怪

-------------------------------------VPS融合怪测试-------------------------------------
版本:v0.1.4
测评频道: https://t.me/vps_reviews
Go项目地址:https://github.com/oneclickvirt/ecs
Shell项目地址:https://github.com/spiritLHLS/ecs
--------------------------------------系统基础信息--------------------------------------
 CPU 型号            : AMD EPYC 9654 96-Core Processor @ 2396.398 MHz
 CPU 数量            : 1 Virtual CPU(s)
 CPU 缓存            : 512 KB
 AES-NI              : ✔️ Enabled
 VM-x/AMD-V/Hyper-V  : ✔️ Enabled
 内存                : 283.62 MB / 958.71 MB
 气球驱动            : ✔️ Enabled
 虚拟内存 Swap       : 0.00 MB / 1024.00 MB
 硬盘空间            : 3.69 GB / 19.60 GB
 启动盘路径          : /dev/vda1
 系统                : debian 12.9 [x86_64] 
 内核                : 6.1.0-21-amd64
 系统在线时间        : 0 days, 00 hours, 34 minutes
 时区                : UTC
 负载                : 0.17 / 0.10 / 0.03
 虚拟化架构          : KVM
 NAT类型             : Full Cone
 TCP加速方式         : bbr
 IPV4 ASN            : AS906 DMIT
 IPV4 Location       : Los Angeles / California / United States
 IPV6 ASN            : AS906 DMIT
 IPV6 Location       : Los Angeles / California / United States
 IPv6 子网掩码       : /64
--------------------------------CPU测试-通过sysbench测试--------------------------------
1 线程测试(单核)得分:   4364.81
--------------------------------内存测试-通过sysbench测试---------------------------------
单线程顺序写速度: 30915.78 MB/s(32.42K IOPS, 5s)
单线程顺序读速度: 46886.73 MB/s(49.16K IOPS, 5s)
-----------------------------------硬盘测试-通过fio测试-----------------------------------
测试路径      块大小   读测试(IOPS)            写测试(IOPS)            总和(IOPS)
/root         4k       62.55 MB/s(15.6k)       62.66 MB/s(15.7k)       125.21 MB/s(31.3k)      
/root         64k      1.07 GB/s(16.6k)        1.07 GB/s(16.7k)        2.14 GB/s(33.4k)        
/root         512k     1.02 GB/s(1995)         1.08 GB/s(2101)         2.10 GB/s(4096)         
/root         1m       1.01 GB/s(989)          1.08 GB/s(1055)         2.09 GB/s(2044)         
-------------------------------------跨国流媒体解锁--------------------------------------
IPV4:
============[ 跨国平台 ]============
Dazn                      Banned
Disney+                   NO (forbidden-location)
Netflix                   Restricted (Originals Only)
Netflix CDN               US
YouTube Region            YES (Region: US)
YouTube CDN               LAX
Amazon Prime Video        YES (Region: US)
Paramount+                YES
TVBAnywhere+              YES (Region: US)
IQiYi                     YES (Region: US)
Viu.com                   YES
Spotify Registration      NO
Steam Store               YES (Community Available) (Region: US)
ChatGPT                   YES (Region: US)
Sora                      YES (Region: US)
Gemini                    YES (Region: USA)
MetaAI                    YES (Region: US)
Wikipedia Editability     NO
Reddit                    NO
TikTok                    YES (Region: US)
Bing Region               YES (Risky) (Region: US)
Instagram Licensed Audio  YES
KOCOWA                    YES
SonyLiv                   NO (Proxy Detected) (Region: US)
OneTrust                  YES (Region: US CALIFORNIA)
GoogleSearch              YES
-------------------------------------三网回程线路检测-------------------------------------
北京电信 219.141.140.10  移动CMIN2  [精品线路] 
北京联通 202.106.195.68  移动CMIN2  [精品线路] 联通4837   [普通线路] 
北京移动 221.179.155.161 移动CMIN2  [精品线路] 
上海电信 202.96.209.133  移动CMIN2  [精品线路] 电信163    [普通线路] 
上海联通 210.22.97.1     移动CMIN2  [精品线路] 
上海移动 211.136.112.200 移动CMIN2  [精品线路] 
广州电信 58.60.188.222   移动CMIN2  [精品线路] 电信163    [普通线路] 
广州联通 210.21.196.6    移动CMIN2  [精品线路] 联通4837   [普通线路] 
广州移动 120.196.165.24  移动CMIN2  [精品线路] 
成都电信 61.139.2.69     移动CMIN2  [精品线路] 
成都联通 119.6.6.6       移动CMIN2  [精品线路] 联通4837   [普通线路] 
成都移动 211.137.96.205  移动CMIN2  [精品线路] 
-------------------------------------三网回程路由检测-------------------------------------
[NextTrace API] preferred API IP - 104.21.48.1 - 51.02ms - Misaka.LAX
广州电信 - ICMP v4 - traceroute to 58.60.188.222, 30 hops max, 52 byte packets
0.24 ms      AS906      [DMIT-BB]          Anycast, Anycast, DMIT.com 
0.64 ms      AS906      [DMIT-BB]          美国, 加利福尼亚, 洛杉矶, DMIT.com 
0.78 ms      AS906      [DMIT-BB]          美国, 加利福尼亚, 洛杉矶, DMIT.com 
126.91 ms    AS58807    [CMIN2-NET]        美国, 加利福尼亚, 洛杉矶, cmi.chinamobile.com  移动
126.17 ms    AS58807    [CMIN2-NET]        中国, 上海, cmi.chinamobile.com  移动
127.55 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
127.09 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
128.02 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com 
167.80 ms    AS9808     [CMNET]            中国, 广东, 广州, chinamobileltd.com  移动
158.20 ms    AS9808     [CMNET]            中国, 广东, 广州, chinamobileltd.com  移动
*
207.43 ms    AS4134     [CHINANET-BB]      中国, 广东, 广州, www.chinatelecom.com.cn  电信
156.82 ms    AS134774   [CHINANET-GD]      中国, 广东, 深圳, chinatelecom.cn  电信
*
161.06 ms    AS4134                        中国, 广东, 深圳, www.chinatelecom.com.cn  电信
广州联通 - ICMP v4 - traceroute to 210.21.196.6, 30 hops max, 52 byte packets
0.22 ms      AS906      [DMIT-BB]          Anycast, Anycast, DMIT.com 
0.48 ms      AS906      [DMIT-BB]          美国, 加利福尼亚, 洛杉矶, DMIT.com 
0.84 ms      AS906      [DMIT-BB]          美国, 加利福尼亚, 洛杉矶, DMIT.com 
126.73 ms    AS58807    [CMIN2-NET]        美国, 加利福尼亚, 洛杉矶, cmi.chinamobile.com  移动
126.09 ms    AS58807    [CMIN2-NET]        中国, 上海, cmi.chinamobile.com  移动
126.20 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
126.14 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
126.98 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
154.14 ms    AS9808     [CMNET]            中国, 广东, 广州, chinamobileltd.com  移动
153.71 ms    AS9808     [CMNET]            中国, 广东, 广州, chinamobileltd.com  移动
269.49 ms    AS4837     [CU169-BACKBONE]   中国, 广东, 广州, chinaunicom.cn 
*
167.66 ms    AS17816    [APNIC-AP]         中国, 广东, 深圳, chinaunicom.cn  联通
181.77 ms    AS17623    [APNIC-AP]         中国, 广东, 深圳, chinaunicom.cn  联通
168.55 ms    AS17623                       中国, 广东, 深圳, chinaunicom.cn  联通
广州移动 - ICMP v4 - traceroute to 120.196.165.24, 30 hops max, 52 byte packets
0.23 ms      AS906      [DMIT-BB]          Anycast, Anycast, DMIT.com 
2.24 ms      AS906      [DMIT-BB]          美国, 加利福尼亚, 洛杉矶, DMIT.com 
0.64 ms      AS906      [DMIT-BB]          美国, 加利福尼亚, 洛杉矶, DMIT.com 
126.17 ms    AS58807    [CMIN2-NET]        美国, 加利福尼亚, 洛杉矶, cmi.chinamobile.com  移动
126.09 ms    AS58807    [CMIN2-NET]        中国, 上海, cmi.chinamobile.com  移动
126.11 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
126.24 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
126.56 ms    AS9808     [CMNET]            中国, 上海, chinamobileltd.com  移动
148.94 ms    AS9808     [CMNET]            中国, 北京, chinamobileltd.com  移动
150.48 ms    AS9808     [CMNET]            中国, 北京, chinamobileltd.com  移动
*
152.08 ms    AS56040    [APNIC-AP]         中国, 广东, 深圳, gd.10086.cn  移动
--------------------------------------就近节点测速--------------------------------------
位置            上传速度        下载速度        延迟            丢包率          
Speedtest.net   1041.71 Mbps    998.97 Mbps     0.33 ms         0.0%            
洛杉矶          1047.87 Mbps    1001.83 Mbps    0.67 ms         0.0%            
法兰克福        556.37 Mbps     885.65 Mbps     148.49 ms       0.0%            
联通上海5G      723.41 Mbps     375.84 Mbps     151.79 ms       2.2%            
联通Wu Xi       808.67 Mbps     803.87 Mbps     149.33 ms       0.0%            
电信浙江        594.87 Mbps     604.07 Mbps     147.60 ms       0.0%
电信浙江        597.95 Mbps     618.77 Mbps     134.21 ms       0.0% 
移动Beijing     903.87 Mbps     388.01 Mbps     149.03 ms       0.0%            
----------------------------------------------------------------------------------
花费          : 8 分 31 秒
时间          : Wed Jan 15 20:52:03 UTC 2025
----------------------------------------------------------------------------------

DMIT 总结

  • 性能:DMIT升级过一次配置,CPU性能非常不错,磁盘 IO 也是 nvme 水准;
  • 线路:三网 CMIN2 回程(移动高端优化线路),无晚高峰波动,稍逊于电信 CN2GIA,奈何 CMIN2 给的太多了(流量);
  • 灵度:DMIT 是2017 成立的大厂了和瓦工一类的,灵度无需担心;
  • 价格:39.9 美元/年的价格,1T 的三网 CMIN2 回程,价格相当不错!
  • 直达链接:https://www.dmit.io/aff.php?aff=9154&pid=188

「用户管理」:一键实现用户名称优化,用户安全增强,自定义头像等多项功能 WordPress 插件

2025年1月4日 19:22

这是基于 WPJAM Basic 的超强的 WordPress 用户管理的插件,有多强大呢,首先看后台的设置界面:

可以说它把 WordPress 相关的用户管理功能都集成了,简单数一数就实现了十多个 WordPress 用户相关功能:

  1. 屏蔽个性化设置
  2. 屏蔽姓氏和名字设置
  3. 取消显示名称设置
  4. 开启别名设置
  5. 隐藏用户登录名
  6. 开启登录次数限制
  7. 用户最后登录时间
  8. 取消「应用程序密码」
  9. 按注册时间排序
  10. 以此身份登陆
  11. 生成密码重置链接
  12. 自定义用户头像
  13. 默认用户头像

下面我们分成五大模块分别来介绍 WPJAM 的「用户管理插件」具体实现了那些功能:

屏蔽个性化设置

WordPress后台个人资料用户可以设置「可视化编辑器」,「语法高亮」,「配色方案」,「键盘快捷键」,「工具栏」,「语言」等这些个性化选项,如下图:

这些选项 WordPress 都是存储到 usermeta 表里面,如果 WordPress 有大量的用户,每个用户会占用7个选项,那么 usermeta 表很快就会爆炸。

比如我运营的 WordPress 站点,有几十万用户,usermeta 表的数据如果不清理的话,已经千万级了,查点东西都慢的要死,如果你和我有一样的困扰,那就可以在插件中勾选实现屏蔽用户的个性化设置,直接采用使用系统全局的默认值。然后还可以根据自己的需求删除这些选项。

用户名称优化

在默认情况下,WordPress 后台个人资料页面中,关于用户的姓名相关的设置是这样的:

是不是有点繁琐,并且很多字段也是存到 usermeta 表中的,我个人觉得关于用户昵称的设置,尽量简洁就好,所以名字和姓氏一般就不需要用户输入,公开显示的名字直接为昵称就好了,所以插件首先提供了下面两个选项:

  • 屏蔽姓名设置:屏蔽了姓氏和名字设置,简化后台个人资料界面设置。
  • 显示名称设置:取消显示名称选择器,直接使用昵称作为显示名称。

另外插件还支持开启了别名设置,是的,我们不仅仅做减法,偶尔也做下加法,这里可以让用户可以编辑自己的别名(user_nicename),这样只要不使用和登录名相同的别名,作者文章链接就不会暴露用户名,当然没有设置别名,插件还是有安全选项来实现防止用户名暴露。

所以优化之后最终的用户界面非常简洁,如下所示:

安全增强

WordPres 用户安全增强体现在两个地方,首先是隐藏登录名,不要让攻击者猜到用户名,然后是开启登录限制,防止密码被暴力破解,插件也提供这两方面的选项:

首先说一下如何隐藏登录名,如果用户没有修改过别名(user_nicename),那么他的别名和登录名(user_login)是一样的,然后作者文章链接或者其他地方就会暴露登录名,为了进一步防止登录名暴露,我们提供了隐藏登录名的选项:

勾选「防止登录名暴露」之后,如果用户的 user_nicenameuser_login 是一样的情况下:

1. 作者文章链接使用 author_id 代替 user_nicename,并且原来的作者链接直接设置为 404 页面,防止用户名暴露

2. user_login 不出现在 body_classcomment_class 中。

3. 隐藏登录失败时候未知用户名和密码不正确的错误信息,这两种情况都显示「用户名或者密码错误」,让攻击者猜去。😁

4. 取消作者相关的 sitemap 以及 REST API 中可以查看所有发布过文章的用户信息列表的中的登录名。

如果真的被攻击者猜到了登录名,那么我们还可以开启登录限制,限制登录失败次数,这样就可以防止密码被暴力破解了,进一步做到安全。

功能增强

除了安全增强之外,我们还增加了一个小功能和屏蔽一个功能,分别是记录用户最后登录时间和取消「应用程序密码」功能:

首先新增记录用户最后登录时间,用户登录之后,在后台用户列表就会显示该用户的最后登录时间,并且支持按照用户最后登录时间进行排序。

默认情况下在后台个人资料页面可以设置「应用程序密码」:

应用程序密码允许通过非交互式系统(例如 XML-RPC 或 REST API)进行身份验证,而无需提供您的实际密码。应用密码可以随时撤销。它们不能用于通过传统方式登录您的网站。

很多人看到这个其实是稀里糊涂,简单说他就是用于 APP 或者小程序通过接口来登录的,但是基本上来说,我们用不到这个功能,所以默认建议屏蔽它。

后台用户列表

对于管理员经常使用的用户列表,也新增一些功能和操作:

首先用户可以除了可以按照上面提示按照最后登录事件排序之外,也可以按照用户注册时间排序,只要你勾选了用户列表里的第一个选项,此外在用户列表页面新增两个操作「以此身份登陆」和「生成密码重置链接」:

如果你是 WordPress 开发者,「以此身份登陆」这个功能特别实用,在用户列表界面,管理员可以轻松以用户的身份登录后台,这样用户说他碰到什么问题,就可以直接登录他的账号去看了,而不是问他要账号密码,这个多难为情啊。😳

WordPress 原来「发送密码重置邮件」这个功能是直接发送密码重置邮件给用户,用户在邮箱里面直接点击操作,改成「生成密码重置链接」,则管理员直接获取密码重置链接,可以通过微信或者其他的社交媒体工具发给用户。

头像设置

在后台个人资料页,用户可以自定义自己的头像。

如果用户没有设置头像,管理员可以设置默认头像,然后随机给用户使用:

最后用户头像还多加一个选项,就是如果用户已经在 Gravatar 里面设置了头像怎么办?有两个选项,从默认中随机选一个,继续使用 Gravatar 的设置。

总结

通过上面的介绍,是不是非常强大,目前我所有用户相关的功能整合到 WPJAM-User 的插件中,只需后台简单的勾选就可以实现绝大部分用户安全和管理相关的功能。


「WordPress果酱」知识星球福利插件基于 WPJAM Basic 开发,加入「WordPress果酱」知识星球,即可下载:

插件 简介
抓取公众号图文

支持一键同步微信公众号文章到 WordPress 博客,并支持一键将文章中所有图片都下载到 WordPress 媒体库。

搜索优化

WordPress 最强的搜索优化插件,支持限制每个 IP 每分钟搜索次数,达到上限之后屏蔽搜索时长,还可以限制搜索关键词的长度,搜索结果页面限制只显示「搜索结果」,还有以下搜索功能增强:

1. 只搜索文章标题,不搜索文章内容和摘要。
2. 当搜索关键词为空时重定向到首页,只有一篇文章时重定向到文章
3. 后台文章列表支持搜索ID。
4. 支持搜索自定义字段。

编辑器优化

一键增强 WordPress 经典 TinyMCE 编辑器:

1. 增加下划线,背景颜色,两端对齐,字体和大小设置,以及内容分页按钮。
2. 新增插入表格功能。
3. 直接插入屏幕截图。

标题设置

一键设置 WordPress 所有页面的页面标题,通过规则方式让博主可以自定义 WordPres 首页,分类,文章类型,文章详情都所有页面的页面标题。

登录优化

一键优化 WordPress 登录注册界面,并支持第三方账号登录和绑定,目前已经支持微信公众号(所有类型),微信小程序,手机号码第三方平台。

内容模板

实现在内容中插入一段共用的内容模板,通过短代码(shortcode)的方式来实现的,支持统一修改,目前支持普通的内容模板,表格内容模板和卡片内容模板三种类型。

用户管理

最强 WordPress 一键用户管理插件,一键实现以下12个功能:

1. 屏蔽个性化设置
2. 屏蔽姓氏和名字设置
3. 取消显示名称设置
4. 开启别名设置
5. 隐藏用户登录名
6. 开启登录次数限制
7. 用户最后登录时间
8. 按注册时间排序
9. 以此身份登陆
10. 生成密码重置链接
11. 自定义用户头像
12. 默认用户头像

分类管理

这是一个全能的 WordPress 分类管理插件:

1. 层式管理分类
2. 限制分类层级
3. 分类拖动排序
4. 使用数字固定链接
5. 首页文章支持分类过滤
6. 后台文章列表支持分类筛选过滤
7. 后台文章列表支持分类多重筛选

评论增强

这是一个 WordPress 评论增强插件,支持评论置顶,评论点赞和按照点赞数排序。

图片集

1. 给媒体创建个分类「图片集 | collection」
2. 图片分类限制为二级
3. 取消图片编辑入口
4. 附件页面直接图片链接。

配置器

全自动 WordPress 配置器,不用一行代码就可以开发。
支持自定义文章类型,自定义字段,自定义分类,分类选项,全局选项。

Script Loader

通过恢复 WordPress 联合加载方式来优化 WordPress 后台脚本加载。

外部链接

将文章或评论中的外部链接加上安全提示的中间页。
让用户确认之后再跳转,并还支持添加 nofollow rel 属性。

话题标签

文章中插入 #话题标签#。
如果是内部链接,直接跳转,
标签或者分类,则自动转换成标签或分类链接,
否则跳转到搜索链接。

格式文章

在 WordPress 实现真正的文章格式

草稿分享

一键生成草稿临时分享链接
并可设置分享链接的有效期

文章专题

设置文章专题,并在文章末尾显示一个文章专题列表。

文章隐藏

设置文章在列表⻚不显示,并且可以根据不同平台进行设置

Meta Data

可视化管理 WordPress Meta 数据,支持所有内置的 Meta 数据:
Post Meta,Term Meta,User Meta 和 Comment Meta。

站点选项

查看和管理所有非 WordPress 系统自动生成的站点选项。
如果你觉得某个选项无用,可以直接删除它。

后台论坛

WordPress 后台论坛,支持创建帖子,分组,消息。

微信小程序

微信小程序 WordPress 基础插件,包含基础类库和管理。

微信群二维码

轮询显示微信群二维码,突破微信群100人限制。

文章置顶

支持置顶文章排序和分类文章置顶的 WordPress 插件

静态文件

一键合并 WordPress 插件和主题的 JS 和 CSS 文件,加快页面加载速度

Debug

一键检测 WordPress 运行效率。

做公众号,学会排版,写一篇很「美」的文章!

2024年12月26日 23:37

继续我们「做公众号」系列的文章,今天讲讲如何学会给文章排版写一篇很「美」的文章!如果你是第一次看到这篇文章,这是这个系列之前的两篇文章:

我们这些略懂一些 SEO 的草根站长(😳)都知道,一篇文章的内核都是内容,写的好的内容,读起来如沐春风,非常舒服,但是承载内容的页面的如果没有布局和排版,广告位横飞,混乱不堪,使得明明很好的内容,变得一点阅读的兴趣都没有。

对于做公众号的人来说也是一样的,学会排版也是非常重要的一个技能,一些公众号文章,排版清晰,文字间距适当,读起来毫无压力。而一些公众号的文章,文字密密麻麻,也没有任何段落章节划分,完全没有读下去的勇气。😅

如果你已经阅读过我「做公众号」系列的文章,你一定对我这两篇文章的排版还算是不错吧,段落章节都非常清晰,图片和字体都做了一些小的设计,我今天就讲解一下我是如何给公众号排版的。

文字

一篇文章,最重要的是文字,使用什么字体,行距多少合适呢?都会对阅读造成非常大的影响。

如果你仔细看,就会发现我文章的文字都比较细,这个主要是为了方便阅读,现在手机的分辨率都很高,对于细的字体也会渲染得不错,使用比较细的字体让文章整体效果看起来会清爽很多。

下面就是我使用的字体列表:

body{ font-family: Roboto, Oxygen, Ubuntu, Cantarell, PingFangSC-light, PingFangTC-light, "Open Sans", "Helvetica Neue", "sans-serif"; }

除此之外,我还把字体颜色设置纯黑色,因为字体比较细,所以看起来不会那么黑,然后行距设置为 1.6,字体设置为 16px,这样一眼看上去就非常清晰:

body{ color: #000000; font-size: 16px; line-height: 1.6; }

作为对比,如果行距设置为 1,字体设置为 14px 的,会显示成什么样呢?不多打一段文字了,就拿这段文字来设置了,大家看看,是不是立刻看起来密密麻麻的感觉,阅读感明显就差了不止一个档次吧!

通过对比,是不是很明显感觉到不同文字的样式对阅读影响非常大。😁

一级子标题

接着我觉得一篇文章最重要的是标题,我们写技术类文章,喜欢通过子标题将文章划分得更加清晰,用户也能够首先通过一二级子标题大概知道文章的脉络和重点。

当然除了技术类文章,其他类型的文章也可以通过这类子标题划分的模式让用户清晰知道自己读到那里,对于作者,也能让自己将文章写得更有逻辑和条理。

如上所示,我是给一级子标题颜色设置成青蓝色,并且加上大概 10 像素颜色淡一些的线,同时这条线向上推了一些,放到标题后面形成阴影的感觉,然后二级子标题的颜色设置成草绿色,阴影的感觉同样处理,如下所示:

二级子标题

之前我试过子标题下面加一条线,但是感觉不是那么好看,经过各种测试和比较,终于改成现在这个样子,感觉明显一下高级多了。😄

大家觉得呢?

此外一般来说文章有一二级子标题就已经足够了,如果文章有三级子标题,当然也可以按照同样的方式设置,颜色根据自己喜好选择即可。

图片

图片算是第三重要吧,我目前只是做了简单的一些设置,效果先看上面两种子标题样式比较的图片,我把文章中的图片都设置了 6px 半径的阴影效果,这样图片有点发光的效果,比较好看。😊

你觉得呢?

因为我写技术文章比较多,很多截图,有些截图,可能边缘是白色,可能会和内容混了,这个阴影效果处理的方式也可以明显把这种截图明显区别开。

当然图片还有一些相册,多张图片的样式等,可能需要处理,我暂时还没有用到,如果之后我要处理了,我也会再加上去。

表格

除了「文字」、「标题」和「图片」这三大件之外,技术类的文章可能还会比较多用到表格,我针对微信公众号,也特别优化了一下表格的显示,算是一个 bonus 的功能吧:

插件简介
标题设置一键设置 WordPress 所有页面的页面标题。
通过规则方式让博主可以自定义 WordPres 首页,分类,文章类型,文章详情都所有页面的页面标题。
登录优化一键优化 WordPress 登录注册界面。
并支持第三方账号登录和绑定,目前已经支持微信公众号(所有类型),微信小程序,手机号码第三方平台。
内容模板实现在内容中插入一段共用的内容模板。
通过短代码(shortcode)的方式来实现的,支持统一修改,目前支持普通的内容模板,表格内容模板和卡片内容模板三种类型。

如上所示,如果没有回车,都会一行显示,除了第一列之外,其他列支持滚动,这样在手机上看的时候,在保持表格优雅的同时,让用户不仅能够快速预览表格内容,也可以看完表格内容。

代码

最后技术性的文章的怎么可能少的了代码呢,所以代码样式是非常重要的,我也是做了一些优化,如上面文字样式代码的样式效果,怎么样?我再去搞一段 PHP 代码给大家演示一下:

add_action('plugins_loaded', function(){	// 所有插件都已经加载
	if(!did_action('wpjam_loaded')){		// 确保已加载 WPJAM Basic 插件
		return;
	}

	$fields	= [
		'seo_title'			=> ['title'=>'SEO标题',	'type'=>'text',	'class'=>'large-text',	'placeholder'=>'不填则使用标题'],
		'seo_description'	=> ['title'=>'SEO描述',	'type'=>'textarea'],
		'seo_keywords'		=> ['title'=>'SEO关键字','type'=>'text',	'class'=>'large-text']
	];

	wpjam_register_post_option('seo', [
		'title'			=> 'SEO设置',	// 自定义选项标题
		'context'		=> 'side',		// 显示在文章编辑页的侧边
		'list_table'	=> true,		// 后台文章列表页也支持弹窗设置
		'page_title'	=> 'SEO设置',	// 文章列表点击弹窗的标题
		'fields'		=> $fields
	]);
});

怎么样,效果很不错吧。你对写一篇很「美」的文章有什么看法,欢迎在公众号的留言来发表你的看法。

哦,对了,我是把这些样式都写在了「我爱水煮鱼」博客主题中,写公众号的时候,在 WordPress 后台写好,然后直接一键复制到公众号即可,非常快捷,并且样式也全带过去了。当然了,你也可以在公众号后台,把自己常用的样式保存为模板,下次直接直接使用模板来写文章,也是可以的。😄

最后再说一句:「我爱水煮鱼」博客主题我放在了「WordPress 果酱」的知识星球,你加入之后即可获取。

企业建站,就用 WordPress Modular 主题!

2024年12月25日 23:08

企业建站其实可以一个一个模块「组装」起来的,这样企业站点的需求就变成了不同模块的定制

Modular 主题提供几十个我们这些年理解的企业站点所需的模块,那么在大部分情况下,通过一个主题就能类似于淘宝店铺装修那样,就能够很快构建成一个完全不同风格的企业站点了。

所以企业建站首先需要的是一款深度自定义与模块化设计的 WordPress 企业主题

Modular 主题除了 WPJAM Basic 插件之外,还集成两个独立的插件:

首先是页面模块装修插件,通过它无需再写一行代码,只需要在后台设置装修页面:无需再写一行代码即可一键模块化装修 WordPress 页面

然后是完全自定义的表单插件,可以在后台自定义表单的字段,就可以生成自己所需的表单,用户提交之后,后台可以自动收集:整波大的, Modular 主题集成了我们压箱底的表单插件!

东西好不好,还是要用户说了算:

无需 Element Pro 就可以实现装修效果,并且页面还能秒开,这样的 WordPress 主题见过吗?

总结一下,可以说 Modular 主题完全是为了企业建站而生的

如果你是一家企业的 IT 负责人,通过这个主题,自己设计一下图片就能快速完成企业交给你的任务,再加上 WordPress 本身的易用性,这款主题可以说让你每天的「摸鱼」时间成倍增加。😁

如果你是一个平时接接单给企业做个小网站的自由职业者,这款主题可以让你快速赚到钱,你完全不用操心代码的事情只需要沟通清楚企业的需求,找到对应的模块搭建进去即可,让你只需要800块钱的成本就能够构建5000-10000的企业站点

最后的最后,Modular(模块化)主题是一个付费的主题,基于 WPJAM Basic 插件构建,原价2680 元,现在只需 688 元就能构建一个完全个性化的企业站点,购买请点击链接:https://wpjam.com/go/modular

做公众号,首先要学会涨粉!

2024年12月17日 22:57

之前我们开启了「做公众号」系列文章的第一篇:「做公众号,能发家致富?

因为谈到赚钱,大家都很感兴趣,毕竟现在做站普遍都很难的情况下,如果能够有一个不错的赚钱的自媒体平台,自然还是很不错的。😊

但是要在公众号赚钱,首先要有 500 粉丝,因为开通流量主首先就要有 500 粉丝:

那么怎么涨粉呢?今天我们就「做公众号」的第二篇:「做公众号,首先要学会涨粉」!

网上会有很多人会教你很多涨粉的经验,甚至还有卖课教大家涨粉的。其实我觉得大道至简,公众号涨粉只有两点:好的内容实用工具,然后一点点吸粉的小技巧

利他内容

好的内容,或者说是利他的内容,比如我这个「WordPress 果酱」公众号,我就会提供站长如何赚钱的内容,和我自己做站长和做公众号的经验,这样的内容对于站长来说是非常有用的,比如我这篇文章「做公众号,能发家致富?」就涨了几百个粉丝,如果多几篇这样的文章,可以只花了 2 天时间就达到了开通流量主的门槛。

换句话说,如果你写的内容帮助到了别人,那么你的目标用户自然就会关注你的公众号,也会转发你的内容,然后让更多人看到并关注你的公众号,这样达到 500 粉丝很快就会实现,甚至更多粉丝也不是太难的问题。

可能现在有些用户说,刚开始做公众号能有几个阅读,其实完全不用担心,现在微信的推荐机制,让一些好的内容也能得到推荐的机会,这样你不用担心目标用户看不到,你要做的就是坚持,坚持一段时间之后,微信会有所表示的,只要你的内容够好,相信我,1-2 个星期之后,就会有效果。

吸粉小技巧

除了坚持分享好的内容之后,还需要学会一些吸粉的小技巧,简单说就给用户一个必须关注你的理由,比如说很多公众号都会必须要发送某些关键字才能获取资料和链接,这样可以更加明显提高粉丝的关注率。

举个例子,我之前写了我一本 WordPress 优化相关的电子书,我就让用户必须回复某个关键字到公众号才能获取,当时我也是一天就获得 300 多粉丝。

另外在文章中需要用户关注公众号的地方,不要吝啬插入公众号卡片,如下所示,这样也能够明显提高关注率:

相信我,你多做一步,你的粉丝就少做一步,关注你公众号就轻松一点,人数就多一点,很多道理就是这么简单。

实用工具 

这是我总结出来目前依旧非常有效的涨粉方法,我们上家在的公司,我们公众号做到 200 多万粉丝,老板在给人分享的时候,侃侃而谈自己管理和内容做得多好,但是他从来没有提到的一点,就是我们做了很多非常实用的涨粉工具。😁 

可以说这是我们不传之秘,😎 这也是我不太去参加外面各种分享会的原因,因为真正成功的理由,大部分分享会都不会说,分享会分享都会是「大而空」的东西。😂

比如我这篇文章「给你的微信昵称加上上标电话号码 ℡¹³⁸¹²³⁴⁵⁶⁷⁸」之前发过,当时得到了微信的推荐,然后一天就新增了1万5千多粉丝,减掉取消关注,还有1万3千多净增长,之后几天还有几千粉丝增长,最后一篇文章就让我获得差不多共有2万多粉丝的增长

这个增长数据,我相信很多人都有点不信,现在很多做公众号的人都说只要不掉粉就好了,怎么可能还有日净增长 1 万多粉丝呢。但是确实是这样,上图是微信订阅号助手的截图。如果你要说我 P 图,那我也无话可说了。

因为我的功能都是做在公众号自定义回复中,和上面给用户一个必须关注理由一样,用户必须要关注之后,才能使用工具:

据我统计,这些实用的工具,一般来说 30 个阅读可以获得一个粉丝,如果 10 万+的阅读,差不多有 3000 以上的粉丝增长。而我之前

现在微信的推荐机制,让每个人都能获得 10 万+阅读的机会,但是大部分公众号的情况都是只涨阅读,不涨粉丝,如果你没有办法将微信推荐流量转化为粉丝,你公众号的阅读数的提升只能期待下次微信的推荐。

而如果你能够提供一些实用的工具,粉丝也得到了增长,这样即使微信不推荐了,你的文章还是有不错的阅读,这也是我们做公众号,首先要涨粉的另一个重要的原因,虽然微信的推荐机制,但是他本身粉丝订阅机制对阅读还是长期有效的。

公众号涨粉总结

这是我「做公众号」第二篇,主要讲我公众号涨粉的方法,简单说就是两点:好的内容实用工具,然后一点点吸粉的小技巧,希望能够帮到在做公众号不知道如何涨粉的各位。😁 大家有什么好的涨粉的工具

最后也希望大家能够关注我公众号「WordPress果酱」,大家对于做公众号有什么问题和看法,也可以给我留言。

「搜索优化」:防止搜索攻击,限制搜索频率,增强搜索能力,WordPress 一键式搜索优化增强插件

2024年12月13日 23:49

在 WordPress 进行搜索是一个常见的操作,而 WordPress 搜索的底层其实就是使用 MySQL like 语法去检索文章的标题摘要内容查出相关的文章。

一般情况 WordPress 这样搜索没有什么大的问题,可能中文分词会存在一些语义理解的小问题,但是通过多次修改关键字多搜索几次总能找到想要的文章。

WordPress 搜索存在的问题

如果碰到攻击,WordPress 的搜索就有很大的问题,因为 WordPress 搜索的链接是 https://blog.wpjam.com/?s=关键词,攻击者只要使用脚本不停的切换关键字,就会造成系统不停去数据库搜索查询,缓存都救不了!

而这样 MySQL Like 查询相对来说是比较耗时的,这就存在被攻击的漏洞,并且攻击时使用的关键字都是随机的,生成的缓存键都是不同,这时候缓存都救不了。

另外 WordPress 只是简单使用 MySQL like 语法去检索文章的标题,摘要和内容来查出相关的文章,没有别的选项,能不能只搜索标题?能不能搜索ID,甚至搜索自定义字段等。

WordPress 最强的搜索优化插件

WPJAM 的「搜索优化」插件就能为了这些功能而实现的,在碰到搜索攻击的时候,可以去限制甚至关闭 WordPress 的搜索,然后一方面,它还提供很多的选项增强 WordPress 的搜索功能。

「搜索优化」插件安装之后,在「WPJAM」菜单的「文章设置」子菜单下就有「搜索优化」标签页,点击进入即可设置搜索优化的功能:

搜索范围

首先该插件可以设置搜索范围:

可以设置文章类型支持在那些文章类型中搜索,如果不设置,WordPress 会使用默认的方式。

其次可以设置哪些用户可以进行搜索,这里有三个选项,默认「所有用户都可以搜索」,然后也可以设置「仅限登录用户搜索」,甚至还可以「关闭站点搜索功能」,这个功能在站点受到攻击的时候,可能会帮到你。

搜索限制

第二大的功能是对搜索功能进行限制:

做站点最重要的就是安全,如上图所示,首先支持限制每个 IP 每分钟搜索多少次,达到上限之后屏蔽多少分钟。在遭受搜索攻击的时候,甚至可以直接关闭搜索,最后还可以设置管理员搜索功能不受影响。

下图就是用户搜索达到上限之后,用户再次搜索之后页面显示的效果:

微信公众号的搜索也可以搜索限制,只要使用#微信机器人#的自定义回复,插件就会自动检测每个公众号用户的搜索次数:

#果酱小程序#也支持搜索限制,达到搜索上限之后,同样会报错:

嗯,「WPJAM」出品的插件很多功能有关联,但也不影响单独使用,非常方便。

此外还可以设置「搜索关键词最大长度」,太长的关键字其实搜索不出什么东西,并且还增加系统的搜索负担,所以可以选择直接屏蔽了事。这个长度的规则还是:一个汉字算两个,一个英文单词算两个,空格不算,所以大家设置的时候注意下,别搞错了。

此外为了防止不怀好意的人来瞎搞,还可以设置「不允许搜索禁用词」。禁用词是在「设置」-「讨论」-「禁止使用的评论关键字」中设置的。

当然了,最后不要限制都把自己给限制了,所以最后还有个选项,可以开启:「站点管理员搜索功能不受上面这些条件限制」。

搜索增强

我们在给一些客户做定制开发的时候,也会经常碰到一些搜索的优化,比如能不能只针对文章标题进行搜索,能不能搜索自定义字段等等,这些功能「搜索优化」插件都实现了:

首先是重定向功能,开始的时候,就会:当关键词为空时重定向到首页,只有一篇文章时重定向到文章。这个功能原本是集成在 #WPJAM Basic# 中,我写了「搜索优化」插件之后,就整和到一起了,做强做大 WPJAM「搜索优化」插件。😁

接着是我命名为「标签搜索功能」,当关键词和分类/标签/自定义分类相同时,直接展示对应的文章。

搜索结果页面标题不显示关键字,只显示「搜索结果」四个字」,这个功能大家第一眼看可能感觉没啥,其实这个功能非常重要的,这里要特别讲解一下,为什么要做这个呢?

这是因为一些 WordPress 的站点的搜索结果页面被黑产会刷了,他们把自己的网站名字和域名刷到搜索结果的页面标题上:

图片

当然上面限制了搜索关键字长度之后,在一定程度上也限制了刷搜索结果的可能性,但是要继续杜绝这种事情,通过把搜索结果页面的标题只显示「搜索结果」则可以完全的防止住,因为无论搜索搜什么,都是显示「搜索结果」这四个字:

图片


只搜索文章标题,不搜索文章内容和摘要」:字面意思,懂的吧?😂

后台文章列表支持ID搜索,如123,多个ID用「,」分隔开,如12,34,56,这个在后台要定位某篇文章 ID 的时候特别有用。

支持搜索自定义字段,功能要别注意一下,开启之后搜索效率会明显下降,然后这个功能勾选之后,还可以选择是在所有自定义字段中搜索还是在指定的自定义字段(输入 meta_key )中搜索。

WPJAM「搜索优化」

WPJAM 这个「搜索优化」是不是很强大,关于 WordPress 搜索相关的功能,我都会整合到这个插件中。

它是 WordPress 果酱知识星球福利插件,加入「WordPress果酱」知识星球(长按下图二维码)即可下载:


「WordPress果酱」知识星球福利插件基于 WPJAM Basic 开发,加入「WordPress果酱」知识星球,即可下载:

插件 简介
抓取公众号图文

支持一键同步微信公众号文章到 WordPress 博客,并支持一键将文章中所有图片都下载到 WordPress 媒体库。

搜索优化

WordPress 最强的搜索优化插件,支持限制每个 IP 每分钟搜索次数,达到上限之后屏蔽搜索时长,还可以限制搜索关键词的长度,搜索结果页面限制只显示「搜索结果」,还有以下搜索功能增强:

1. 只搜索文章标题,不搜索文章内容和摘要。
2. 当搜索关键词为空时重定向到首页,只有一篇文章时重定向到文章
3. 后台文章列表支持搜索ID。
4. 支持搜索自定义字段。

编辑器优化

一键增强 WordPress 经典 TinyMCE 编辑器:

1. 增加下划线,背景颜色,两端对齐,字体和大小设置,以及内容分页按钮。
2. 新增插入表格功能。
3. 直接插入屏幕截图。

标题设置

一键设置 WordPress 所有页面的页面标题,通过规则方式让博主可以自定义 WordPres 首页,分类,文章类型,文章详情都所有页面的页面标题。

登录优化

一键优化 WordPress 登录注册界面,并支持第三方账号登录和绑定,目前已经支持微信公众号(所有类型),微信小程序,手机号码第三方平台。

内容模板

实现在内容中插入一段共用的内容模板,通过短代码(shortcode)的方式来实现的,支持统一修改,目前支持普通的内容模板,表格内容模板和卡片内容模板三种类型。

用户管理

最强 WordPress 一键用户管理插件,一键实现以下12个功能:

1. 屏蔽个性化设置
2. 屏蔽姓氏和名字设置
3. 取消显示名称设置
4. 开启别名设置
5. 隐藏用户登录名
6. 开启登录次数限制
7. 用户最后登录时间
8. 按注册时间排序
9. 以此身份登陆
10. 生成密码重置链接
11. 自定义用户头像
12. 默认用户头像

分类管理

这是一个全能的 WordPress 分类管理插件:

1. 层式管理分类
2. 限制分类层级
3. 分类拖动排序
4. 使用数字固定链接
5. 首页文章支持分类过滤
6. 后台文章列表支持分类筛选过滤
7. 后台文章列表支持分类多重筛选

评论增强

这是一个 WordPress 评论增强插件,支持评论置顶,评论点赞和按照点赞数排序。

图片集

1. 给媒体创建个分类「图片集 | collection」
2. 图片分类限制为二级
3. 取消图片编辑入口
4. 附件页面直接图片链接。

配置器

全自动 WordPress 配置器,不用一行代码就可以开发。
支持自定义文章类型,自定义字段,自定义分类,分类选项,全局选项。

Script Loader

通过恢复 WordPress 联合加载方式来优化 WordPress 后台脚本加载。

外部链接

将文章或评论中的外部链接加上安全提示的中间页。
让用户确认之后再跳转,并还支持添加 nofollow rel 属性。

话题标签

文章中插入 #话题标签#。
如果是内部链接,直接跳转,
标签或者分类,则自动转换成标签或分类链接,
否则跳转到搜索链接。

格式文章

在 WordPress 实现真正的文章格式

草稿分享

一键生成草稿临时分享链接
并可设置分享链接的有效期

文章专题

设置文章专题,并在文章末尾显示一个文章专题列表。

文章隐藏

设置文章在列表⻚不显示,并且可以根据不同平台进行设置

Meta Data

可视化管理 WordPress Meta 数据,支持所有内置的 Meta 数据:
Post Meta,Term Meta,User Meta 和 Comment Meta。

站点选项

查看和管理所有非 WordPress 系统自动生成的站点选项。
如果你觉得某个选项无用,可以直接删除它。

后台论坛

WordPress 后台论坛,支持创建帖子,分组,消息。

微信小程序

微信小程序 WordPress 基础插件,包含基础类库和管理。

微信群二维码

轮询显示微信群二维码,突破微信群100人限制。

文章置顶

支持置顶文章排序和分类文章置顶的 WordPress 插件

静态文件

一键合并 WordPress 插件和主题的 JS 和 CSS 文件,加快页面加载速度

Debug

一键检测 WordPress 运行效率。

做公众号,能发家致富?

2024年12月17日 22:54

关注我博客和公众号的朋友,我现在除了更新博客之外,主要就是更新公众号了,因为公众号没有留言功能,之前主要聊一些技术和工具的东西,而要讨论一些主观性的东西,如果没有用户的互动,总觉得少了一些什么。

终于现在公众号有了留言功能,那就首先开启一些主观性的话题,争取长期和大家做一些探讨,如果你有什么好的看法,可以给我留言也可以来投稿,今天开启就第一个话题「做公众号」,开始第一篇:做公众号,能发家致富吗?

首先直接给出结论:肯定可以的。但是,重点还是后面这个但是,这个但是就是这接下来这三个问题:1. 怎么理解公众号,2. 怎么运营公众号,3. 怎么靠公众号赚钱。

流量主广告

这三个问题,首先我们从怎么靠公众号赚钱开始讲起,简单说,公众号赚钱主要靠两种,一是流量主广告,二是商单。

对于公众号还没有做大,或者还有很强的个人 IP 的公众号来说,商单基本不太可能会有,如果有,也是风险很高的单子,因为很多虚假广告,你可能不一定会分辨,如果接了甚至可能会把号都封了,所以对于绝大部分的用户来说,做公众号主要并且首先靠流量主广告的收入了。

微信的流量主的广告位有以下5种方式:

图片

我们一般指的是前面两种:公众号底部广告和文中广告,互选广告相当于有人让你直接帮忙写一篇软文或者帮忙转发一篇软文,这个价格比较高,但是机会也很难得到。

视频后广告这个如果我们做的是图文,那么基本可以忽略不计,返佣广告指的是在文章中推荐京东或者拼多多等商家的商品,用户购买了给号主返佣,我试过一两次,卖出去2-3本书,基本可以忽略不计。🥹

所以对于公众号号主来说,最重要的还是公众号底部广告和文中广告,这个只要公众号写了文章有人看,有流量就有收入,下图是我公众号8 月份初7天的底部广告的收入:

图片

这几天没有获得微信推荐,流量不是特别高,但是基本上也有 30-50 一天,如果获得微信推荐,那么微信流量主收入可能高的可怕:

图片

今年 4 月份有文章被微信推荐了,有几十万的流量,一天就有 1000 多的广告收入。

具体到单篇文章,上个月也有篇文章被微信推荐了:

图片

95%的流量都是来自微信的推荐,文章总阅读数达到了50 多万,这样的文章有多少广告收入呢?

图片

接近 1500 元的广告收入

eCPM = 3

根据阅读和收入算下来,差多就是 1000 阅读有 3 块多的收入,所以一般来说 1 万阅读就有 30-40 块钱钱的收入,10 万阅读就有 300,每天都有10 万阅读的话,那么基本一个月可以有近 1 万左右的收入。

当然可能因为号的属性不同,收入也会有所不同,我听过最离谱的是,1000阅读达到20元。啧啧啧。😋

哈哈,这么说起来貌似靠公众号流量主的广告收入能赚到不错的收入的,那接下去的问题,就变成了怎么把公众号的阅读数做到10万+呢?

去中心化自媒体

首先要明白一个概念「去中心化自媒体」,什么意思呢?其实就是粉丝推送的概念,就是你公众号的粉丝始终会收到你推送的内容,微信公众号之前就是最好的去中心化的媒体平台,你的粉丝永远是你的粉丝。

其他所有平台都是中心化的媒体平台,中心化平台永远是给平台打工,比如无论你的百家号有多少粉丝,但是百度百家号的流量分发机制始终把握在平台的手里,而微信公众号的粉丝是会给你文章真正带来流量的,会给你的电商小程序真正带来转化的。

不过最近微信订阅号也进行了一些改版,已经不是完全「去中心化自媒体了」,订阅号的列表页,加入了快讯,加入了推荐等,相对之前并不是所有的粉丝都会看到你的公众号推送,微信也开始把控流量了。

但是相比其他平台还是粉丝的权重还是相对高的,拥有一个百万大号始终是比几千几万粉丝的公众号获得流量大,另外微信也加入一些推荐机制,一些小号也能获得推荐,比如我前面那篇文章,就获得 50 万的流量,获得 1500 左右的广告收入。

从这个概念上理解,做好微信运营除了写好的内容之外,还是要做好粉丝的增长,因为首先微信需要 500 :

图片

所以「WordPress果酱」这个公众号,我一直在想办法涨粉,那么怎么涨粉呢?哈哈,这个又是另外一个问题,我之前公司在运营200多万粉丝的公众号的时候是非常轻松的,所以在写好文章的同时,可能还要学会涨粉的技巧,这个具体怎么做,我会在之后讲讲怎么涨粉和写公众号内容。

记得关注,不要错过哦,我之前那篇 50 万阅读的文章,让我天就长了 1 万 3 千多粉丝。我之后也介绍我是怎么做到的。😎

图片

当然我们不可能立刻要求做到10万➕的阅读,其实只要保持2-5万阅读的公众号就已经是非常优质的公众号,这时候广告商单完全可以给到你非常不错的收入,我这个目前阅读数在1K不到-1万跳到的号,我都接到了5条广告商单了,每篇收2000,合计都有10000的收入。😊

个人 IP

所以做公众号绝对是自媒体行业的最好选择,没有之一!好几个听我劝的朋友,已经开始赚钱了。

当然我个人更加看重的是公众号给我带来IP或者说品牌效应,之前大家是通过我的博客,现在大家是通过「WordPress果酱」这个公众号知道我,知道我还在分享 WordPress 建站,知道我还在努力做技术,也愿意将一些项目分享给我,所以做公众号分享自己和自己的技术,绝对是一本万利的事情。😁

最后回到标题,做公众号能发财吗?有人确实发财了,有人赚到不错的零花钱,有人夸大了自己的影响力,结果都算是好的,只要你能够坚持下来。

你呢?除了用 WordPress 做站,开始做公众号了吗?一起留言说说你的看法。这就是公众号可以留言的好处。😁

还没升级到 PHP 8.4,也可以提前在 WordPress 中使用 PHP 8.4 引入的数组函数

2024年12月2日 23:17

PHP 升级到了 8.4,个人觉得对我们写代码帮助最大的就是 PHP 8.4 引入的 array_find()array_find_key()array_any() 和 array_all() 这 4 个 array_*() 数组函数。

其实这四个函数在 JavaScript 的 Array 的实例方法中就有了,只是他的命名方式和 PHP 有点不一样,就他是用 every 和 some 而不是 all 和 any,我之前写代码的时候,也有一些地方需要使用到这四个数组函数,所以我基于 JavaScript 的方式在 #WPJAM Basic# 中集成了这四个方法。

在 PHP 8.4 发布之后我基于 PHP 8.4 命名方式做了一些优化,使得大家在没有升级到 PHP 8.4,也可以提前在 WordPress 中使用 PHP 8.4 引入的数组函数。

array_find()

array_find() 是返回数组中第一个满足回调函数的元素,如果没有则返回 null,根据这个特性,我们很容易就是先这个函数:

if(!function_exists('array_find')){
	function array_find($arr, $callback){
		foreach($arr as $k => $v){
			if($callback($v, $k)){
				return $v;
			}
		}
	}
}

比如我在字段处理中,如果字段没有定义类型,我根据它是否有其他属性来给他设置类型的代码,如果没有 array_find,我们一般这么写:

if(!empty($field['options'])){
	$field['type']	= 'select';
}elseif(!empty($field['label'])){
	$field['type']	= 'checkbox';
}elseif(!empty($field['fields'])){
	$field['type']	= 'fieldset';
}else{
	$field['type']	= 'text';
}

有了 array_find,一行搞定了:

$field['type']	= array_find(['options'=>'select', 'label'=>'checkbox', 'fields'=>'fieldset'], fn($v, $k)=> !empty($field[$k])) ?: 'text';

array_find_key()

array_find_key()array_find() 很像,只是它返回数组中第一个满足回调函数的元素的健名:

if(!function_exists('array_find_key')){
	function array_find_key($arr, $callback){
		foreach($arr as $k => $v){
			if($callback($v, $k)){
				return $k;
			}
		}
	}
}

相比 array_find() 函数的定义,唯一的区别,它 return 的是 key 而不是 value。

上面的获取字段的类型的代码,也可以使用 array_find_key() 来实现,大家看看区别:

$field['type']	= array_find_key(['select'=>'options', 'checkbox'=>'label', 'fieldset'=>'fields'], fn($v, $k)=> !empty($field[$v])) ?: 'text';

array_all()

array_all() 判断数组中的每个元素是否都满足回调函数,意思是将每个元素传递给回调函数,都要返回 true

if(!function_exists('array_all')){
	function array_all($arr, $callback){
		foreach($arr as $k => $v){
			if(!$callback($v, $k)){
				return false;
			}
		}

		return true;
	}
}

比如我写的 SMTP 发信扩展里面就有判断代码,需要「发信地址」,「邮箱账号」和「邮箱密码」这三个选项都设置了之后才生效:

if(array_all(['host', 'user', 'pass'], fn($k)=> WPJAM_SMTP::get_setting($k))){
	// 执行代码
}

array_any()

array_any() 也是判断数组的元素是否满足满足回调函数,但是 array_any() 只需要一个满足即可,而 array_all() 一样则是需要全部都满足:

if(!function_exists('array_any')){
	function array_any($arr, $callback){
		foreach($arr as $k => $v){
			if($callback($v, $k)){
				return true;
			}
		}

		return false;
	}
}

上面例子中,发信设置扩展需要「发信地址」,「邮箱账号」和「邮箱密码」这三个选项都要设置,换成 array_any() 的思维,则只要一个没有设置就返回:

if(array_any(['host', 'user', 'pass'], fn($k)=> !WPJAM_SMTP::get_setting($k))){
	return;	// 返回,不生效
}

大家对比一下两个例子的代码,使用相类似的例子,通过不同的写法,也是一种更加清晰的区分函数的方式。😄

标题说了,还没升级到 PHP 8.4,也可以提前在 WordPress 中使用 PHP 8.4 引入的数组函数,意思只要你更新 WPJAM Basic 到最新版就能使用了,所以记得更新,有什么问题,记得给我留言。

PHP 8.4 正式版发布,一文快速预览新功能

2024年11月23日 23:50

PHP 8.4 在 11 月 21 号就发布了,它包含了许多新功能,对于 WordPress 用户来说,了解 PHP 新版的功能也是一个简单必要的工作,并且  8.4 版是 PHP 在 2024 年的年度的一个主要的版本更新,所以我们就简单快速过一遍 PHP 8.4 的新功能。😄

属性挂钩

对象属性现在可以其 get 和 set 操作中关联相关的附加逻辑。根据用法,这可能会也可能不会使属性变为虚拟属性,即该属性根本没有实际的存储值。

<?php
class Person
{
    // “虚拟”属性,可能无法明确设置。
    public string $fullName {
        get => $this->firstName . ' ' . $this->lastName;
    }

    // 所有的写入操作都会经过这个挂钩,结果就是写入的内容。
    // 读取访问正常。
    public string $firstName {
        set => ucfirst(strtolower($value));
    }

    // 所有的写入操作都会经过这个挂钩,它必须写入支持值本身。
    // 读取访问正常。
    public string $lastName {
        set {
            if (strlen($value) < 2) {
                throw new \InvalidArgumentException('Too short');
            }
            $this->lastName = $value;
        }
    }
}

$p = new Person();

$p->firstName = 'peter';
print $p->firstName; // 打印“Peter”
$p->lastName = 'Peterson';
print $p->fullName; // 打印“Peter Peterson”

不对称属性可见性

现在可以将对象属性的 set 可见性和 get 可见性分开控制。

<?php
class Example
{
    // 第一个可见性修饰符控制 get 可见性,第二个修饰符控制 set 可见性。
    // The get-visibility must not be narrower than set-visibility.
    public protected(set) string $name;

    public function __construct(string $name)
    {
        $this->name = $name;
    }
}

惰性对象

现在可以创建对象,将初始化延迟到访问时。库和框架可以利用这些惰性对象来延迟获取初始化所需的数据或依赖项。

<?php
class Example
{
    public function __construct(private int $data)
    {
    }

    // ...
}

$initializer = static function (Example $ghost): void {
    // 获取数据或者依赖项
    $data = ...;
    // 初始化
    $ghost->__construct($data);
};

$reflector = new ReflectionClass(Example::class);
$object = $reflector->newLazyGhost($initializer);

#[\Deprecated] 属性

新的 #[\Deprecated] 属性使 PHP 的现有弃用机制可用于用户定义的函数、方法和类常量。

class PhpVersion
{
    #[\Deprecated(
        message: "use PhpVersion::getVersion() instead",
        since: "8.4",
    )]
    public function getPhpVersion(): string
    {
        return $this->getVersion();
    }

    public function getVersion(): string
    {
        return '8.4';
    }
}

$phpVersion = new PhpVersion();
// Deprecated: Method PhpVersion::getPhpVersion() is deprecated since 8.4, use PhpVersion::getVersion() instead
echo $phpVersion->getPhpVersion();

新的 ext-dom 功能和 HTML5 支持

新的 DOM API 包括符合标准的支持,用于解析 HTML5 文档,修复了 DOM 功能行为中的几个长期存在的规范性错误,并添加了几个函数,使处理文档更加方便。

新的 DOM API 可以在 Dom 命名空间中使用。使用新的 DOM API 可以使用 Dom\HTMLDocument 和 Dom\XMLDocument 类创建文档。

$dom = Dom\HTMLDocument::createFromString(
    <<<HTML
        <main>
            <article>PHP 8.4 is a feature-rich release!</article>
            <article class="featured">PHP 8.4 adds new DOM classes that are spec-compliant, keeping the old ones for compatibility.</article>
        </main>
        HTML,
    LIBXML_NOERROR,
);

$node = $dom->querySelector('main > article:last-child');
var_dump($node->classList->contains("featured")); // bool(true)

BCMath 的对象 API 

新的 BcMath\Number 对象使在处理任意精度数字时可以使用面向对象的方式和标准的数学运算符。

这些对象是不可变的,并实现了 Stringable 接口,因此可以在字符串上下文中使用,如 echo $num

use BcMath\Number;

$num1 = new Number('0.12345');
$num2 = new Number('2');
$result = $num1 + $num2;

echo $result; // '2.12345'
var_dump($num1 > $num2); // false

新的 array_*() 函数

新增函数 array_find()array_find_key()array_any() 和 array_all()

$animal = array_find(
    ['dog', 'cat', 'cow', 'duck', 'goose'],
    static fn (string $value): bool => str_starts_with($value, 'c'),
);

var_dump($animal); // string(3) "cat"

PDO 驱动程序特定子类

新的 Pdo\DblibPdo\FirebirdPdo\MySqlPdo\OdbcPdo\Pgsql 和 Pdo\Sqlite 的子类可用。

$connection = PDO::connect(
    'sqlite:foo.db',
    $username,
    $password,
); // object(Pdo\Sqlite)

$connection->createFunction(
    'prepend_php',
    static fn ($string) => "PHP {$string}",
); // Does not exist on a mismatching driver.

$connection->query('SELECT prepend_php(version) FROM php');

new MyClass()->method() 不需要括号

现在可以在不使用括号包裹 new 表达式的情况下访问新实例化对象的属性和方法。

$connection = PDO::connect(
    'sqlite:foo.db',
    $username,
    $password,
); // object(Pdo\Sqlite)

$connection->createFunction(
    'prepend_php',
    static fn ($string) => "PHP {$string}",
); // Does not exist on a mismatching driver.

$connection->query('SELECT prepend_php(version) FROM php');

新的类、接口和函数

新的 延迟对象。
基于 IR 框架的新 JIT 实现。
新增 request_parse_body() 函数。
新增 bcceil()、bcdivmod()、bcfloor() 和 bcround() 函数。
新增 RoundingMode 枚举用于 round(),包括 4 个新的舍入模式 TowardsZero、AwayFromZero、NegativeInfinity 和 PositiveInfinity。
新增 DateTime::createFromTimestamp()、DateTime::getMicrosecond()、DateTime::setMicrosecond()、DateTimeImmutable::createFromTimestamp()、DateTimeImmutable::getMicrosecond() 和 DateTimeImmutable::setMicrosecond() 方法。
新增 mb_trim()、mb_ltrim()、mb_rtrim()、mb_ucfirst() 和 mb_lcfirst() 函数。
新增 pcntl_getcpu()、pcntl_getcpuaffinity()、pcntl_getqos_class()、pcntl_setns() 和 pcntl_waitid() 函数。
新增 ReflectionClassConstant::isDeprecated()、ReflectionGenerator::isClosed() 和 ReflectionProperty::isDynamic() 方法。
新增 http_get_last_response_headers()、http_clear_last_response_headers() 和 fpow() 函数。
新增 XMLReader::fromStream()、XMLReader::fromUri()、XMLReader::fromString()、XMLWriter::toStream()、XMLWriter::toUri() 和 XMLWriter::toMemory() 方法。
新增 grapheme_str_split() 函数。

弃用和向后不兼容

IMAP、OCI8、PDO_OCI 和 pspell 扩展已从 PHP 中分离并移至 PECL。
隐式可空参数类型现已弃用。
使用 _ 作为类名现已弃用。
将零的负数次幂现已弃用。
向 round() 传递无效模式将抛出 ValueError。
来自扩展 date、intl、pdo、reflection、spl、sqlite、xmlreader 的类常量现在是有类型的。
GMP 类现已是 final 类。
已删除 MYSQLI_SET_CHARSET_DIR、MYSQLI_STMT_ATTR_PREFETCH_ROWS、MYSQLI_CURSOR_TYPE_FOR_UPDATE、MYSQLI_CURSOR_TYPE_SCROLLABLE 和 MYSQLI_TYPE_INTERVAL 常量。
已弃用 mysqli_ping()、mysqli_kill()、mysqli_refresh() 函数,mysqli::ping()、mysqli::kill()、mysqli::refresh() 方法,以及 MYSQLI_REFRESH_* 常量。
stream_bucket_make_writeable() 和 stream_bucket_new() 现在返回 StreamBucket 实例而不是 stdClass。
exit() 行为变更。
E_STRICT 常量已弃用。

所以你打算升级吗?我打算先把 WPJAM 所有插件的最低版本的要求从 7.4 先升级到 8.0 了,不过现在我已经开始修复一些插件在 PHP 8 版本的兼容问题了。

网站速度很慢?使用 WordPress 短时缓存(Transients)来优化数据库查询和 HTTP 响应!

2024年11月18日 22:40

每个人都想要一个速度很快的网站,网站速度越快,用户停留和点击页面或购买产品的时间就越长,加快网站速度的方法之一是开启缓存,而缓存背后的逻辑就是存储信息,更具体一点说,就是找到一个比连接数据库更快的存储信息的地方。

在 WordPress 中,如果一些复杂的 SQL 查询或者耗时的 HTTP 请求,其实它们的结果在一定时间内是不变的,那么为了网站速度,如果把这些操作的结果缓存起来,这样下次进行同样的 SQL 查询和 HTTP 请求的时候,就可以直接从缓存中获取数据,从而可以显著加快网站的速度,当然一些复杂计算的结果也可以通过该方法进行缓存。

 WordPress Transients

那么在 WordPress 中如何快速缓存 SQL 查询和 HTTP 响应呢?这个时候就要用到 WordPress 的短时缓存(Transients)功能。

什么是短时缓存(Transients)

我们知道 WordPress 缓存有多种类型,比如对象缓存、浏览器缓存、页面缓存甚至数据库缓存,每种类型都有其用途和设置步骤,比如需要安装插件和更改服务器配置以启用对象缓存等。

那么今天介绍的 Transients API,是 WordPress 用于在页面加载期间临时存储 WordPress 中的信息,Transients 本身是“短暂的”或“临时的”意思,那么 Transients API 可以理解为临时缓存或者短暂缓存的意思,我这里将它翻译成短时缓存,它是 WordPress 用来缓存一些复杂的 SQL 查询和运算结果的最简单的方法。

它给这些需要缓存的数据一个过期时间,并且时间一到就会自动删除,所以在制作 WordPress 插件的时候,需要存储一些有一定生命周期的数据的时候,Transients API 就是最好的选择。

简单说,Transients 是一种非常强大的工具,它不仅可以用来避免对页面内容进行不必要的数据库请求,还可以加快生成复杂标记的速度并加快耗时的第三方 API 请求。 

Transients 相关函数

首先说下,Transients 的存储,如果服务器开启了 #Memcached#,那么缓存的数据就会存在 Memcached 的内存中,如果没有开启的话,则存储到 WordPress 数据库的 Options 表中

所以它接口函数和 WordPress 的 Option API get_option, add_option, update_option, delete_option))基本一样,唯一区别就是 Transients API 有一个过期时间,并且它没有 add 方法,统一合并成 set 了,所以 WordPress Transients API 有以下三个函数:

// 保存一个数据到短时缓存中
set_transient( string $transient, mixed $value, int $expiration )

// 从短时缓存中获取一个数据
get_transient( string $transient )

// 从短时缓存中删除一个数据
delete_transient( string $transient )

函数的使用过非常简单,这里不做详细解释,简单注意下两点:

  1. 如果使用获取短时缓存函数 get_transient 去获取数据,已经过期或者不存在的情况下是返回 false 的。
  2. 完全不用担心 Transients API 会将数据库的 Options 表塞满数据,因为临时变量一旦过期,下次获取的时候就会自动被删除,并且上面也说了如果服务器开启了 #Memcached#,那么缓存的数据就会存在 Memcached 的内存中。

一个应用 Transients 的例子

🙋‍♀️🌰 假设你要获取博客的浏览最高的 10 篇文章,文章的浏览数据一般是存在 PostMeta 表中,所以这样的数据库查询会用到 Posts 表和 PostMeta 表进行联表查询,如果文章数量比较多的情况下,这样的查询一般是比较慢的。

而事情的另一面,博客浏览最高的 10 篇文章一般来说在一段时间(比如:12小时)之内很可能是不变的,所以这个功能最适合使用 Transients API 进行缓存了:

$top_10_posts = get_transient('top_10_posts');

if(false === $top_10_posts){ // 临时变量过期了或者根本就没有创建

	// 通过 SQL 查询获取流量最高的 10 篇文章,
	$top_10_posts = wpjam_get_top_viewd_posts(10);

	// 把临时变量存到数据库中,时间为 12 个小时
	set_transient('top_10_posts', $top_10_posts, HOUR_IN_SECONDS*12);
}

我们首先使用 get_transient('top_10_posts') 函数从缓存中看看有没有缓存,如果没有,该函数是返回 false 的。

程序获取缓存结果为 false 的时候,就通过 wpjam_get_top_viewd_posts 这个带有复杂 SQL 的函数获取文章,然后通过函数 set_transient('top_10_posts', $top_10_posts, HOUR_IN_SECONDS*12) 存到缓存中,并且过期时间设置为 12 小时。

这样下次再去获取浏览最高的文章,直接从缓存中返回了,就不用担心不用担心数据库查询过慢的问题了。

使用 Hook 删除短时缓存

如果由于某种原因某篇流行文章删除,这个时候可能流量最高的文章都可能发生变化,我们就可以使用 delete_transient 函数把这个临时变量删除了,这样我们可以使用 WordPress 的删除文章的 Hook delete_post 进行操作:

add_action('delete_post', fn() => delete_transient('top_10_posts'));

如果你想有新文章发布了,虽然这时候一般不会影响浏览最高的文章列表,但是如果想,也可以把缓存清理了,这时候用到是 publish_post Hook:

add_action('publish_post', fn() => delete_transient('top_10_posts'));

WPJAM 终极方法

虽然 Transients API 的使用非常简单,它主要逻辑就是首先使用 get_transient() 函数获取缓存,=如果没有,再通过函数 set_transient() 将数据存到缓存中。

但是这里都有要写个判断,并且缓存的名称也要重复写两次,对于我这么懒的程序是不可能接受的,另外它的逻辑感觉上在破坏了程序的主逻辑,所以我在 #WPJAM Basic# 中集成了 wpjam_transient 函数,它通过回调的方式,让只需一步就实现 WordPress 短时缓存:

首先我们实现看看我的 wpjam_transient 函数的实现:

function wpjam_transient($name, $callback, $expire=86400){
	$data	= get_transient($name);

	if($data === false){
		$data	= $callback();

		if(!is_wp_error($data)){
			set_transient($name, $data, $expire);
		} 
	}

	return $data;
}

可以看到 wpjam_transient 函数把获取和设置短时缓存的函数都内置到了函数中,你只需要关注你程序的主逻辑,所以上面的缓存的浏览最高的 10 篇文章的代码可以简化为 1 行代码:

wpjam_transient('top_10_posts', fn()=> wpjam_get_top_viewd_posts(10), HOUR_IN_SECONDS*12);

是不是非常简洁。🤭

总结

WordPress 短时缓存(Transients API)是 WordPress 用于在页面加载期间临时存储 WordPress 中的信息,该功能用的好,特别是用于缓存复杂的 SQL 查询,耗时 HTTP 请求,以及复杂计算的结果等,对于站点有明显的提高,#WPJAM Basic# 集成的 wpjam_transient 函数进一步提高使用效率,只需一步就实现 WordPress 短时缓存。

RackNerd 和 CloudCone 黑五、双11 低价 VPS 推荐

2024年11月10日 23:42

RackNerd 和 CloudCone 是老牌低价 VPS厂商中比较有代表性的;近期,这两家公司针对双十一和黑色星期五推出了优惠套餐,年付低至 10.29 美元;在海外低价 VPS 中,稳定性表现都还不错,有需求的小伙伴可以了解一下。

RackNerd 优惠套餐

CPU/内存/硬盘流量/月价格/年链接
1C/1G/20G4TB10.29 美元https://my.racknerd.com/aff.php?aff=11321&a=add&pid=810
1C/1G/14G2TB11.11 美元https://my.racknerd.com/aff.php?aff=11321&a=add&pid=875
1C/2G/25G3TB17.98 美元https://my.racknerd.com/aff.php?aff=11321&a=add&pid=876
2C/3G/40G5TB25.98 美元https://my.racknerd.com/aff.php?aff=11321&a=add&pid=877
3C/3G/40G6TB36.88 美元https://my.racknerd.com/aff.php?aff=11321&a=add&pid=878

其中年付10.29美元款为特别优惠款,比 11.11 美元款配置还更高。

机房测试 IP

洛杉矶DC02(Multacom机房)的需要17.98美元以上套餐才有,建议优先 洛杉矶DC02 机房,其次圣何塞,(当然也可以结合机房测试ip的延迟、速度进行选择)。

Cloudcone 优惠套餐

CPU/内存/硬盘流量/月价格/年链接
2C/1G/14G3TB13.99 美元https://app.cloudcone.com.cn/vps/282/create?ref=11351&token=pre-bf-24-ssd-vps-1
5C/2G/27G4TB21.21 美元https://app.cloudcone.com.cn/vps/283/create?ref=11351&token=pre-bf-24-ssd-vps-2
8C/4G/55G5TB38.50 美元https://app.cloudcone.com.cn/vps/284/create?ref=11351&token=pre-bf-24-ssd-vps-3

机房测试ip

附言和总结

Cloudcone 和 RackNerd 的洛杉矶 DC02 产品均位于相同的机房(Multacom 机房);具体表现可参考之前的测试结果:「RackNerd 这款老牌低价的国外VPS,真的值得入手吗?

线路上相较于普通的美国 VPS,洛杉矶 DC02 还是要好上一些,肯定不如CN2线路(毕竟价格摆在这里);两家稳定性表现都还不错,可根据需求进行选择。

在 WordPress 中如何设置背景色透明度?

2024年10月29日 23:55

最近开始写一些 WordPress 专业的知识,阅读数奇低,然后我发一些微信昵称技巧,又说我天天发这些小学生爱玩的玩意,写点文章真不容易。

那我两天发点专业的东西,两天发点小学生的东西,剩下三天我看着办,这样总行吧?

哈哈,那就天就发布一点点专业的东西,就是我们做网页开发的时候的时候如何设置透明背景。

为什么背景要设置透明度?

首先说下为什么背景要设置透明度,比如最近我给公司实现做的表格应用的时候,有个单元格条件样式的功能:

就是类似于 Excel 的条件格式化的功能,让数据根据不同的值显示不同的样式,如上图所示,可以设置,加粗,文本颜色,和填充颜色,其中填充就是设置单元格的背景颜色 :

由于我们的表格每一行本身就有间隔背景色(或者说斑马色),如果我们设置的单元格背景没有透明度的话,就会看不到间隔色,看数据不太方便,另外也会比较显眼,抢过了主体文本的颜色

也有人可能喜欢这种比较强烈的配色方式,不过不管了,我觉这个例子就是想给大家说下,我做了一个表格应用,可以自定义单元格样式,嘻嘻,另外也是为了点下今天的主体,怎么设置背景透明度。

如何设置背景透明度?

首先这个是 CSS 的活,我们都知道设置背景色的 CSS 代码:

// 使用 RGB
.background {
  background-color: rgb(255, 0, 0); /* 红色背景 */
}

// 使用 HSL
.background {
  background-color: hsl(120, 100%, 50%); /* 绿色背景 */
}

// 使用 HEX 6位16进制颜色代码
.background {
  background-color: #0000FF; /* 蓝色色背景 */
}

// 使用 HEX 3位16进制颜色代码
.background {
  background-color: #00F; /* 蓝色色背景 */
}

上面展示了 RGB 和 HSL 以及 HEX 16 进制三种设置背景的方法,但是这样设置都是不透明的。

那么如何设置透明度呢?其实也非常简单,只要给上面的颜色加上透明度的 Alpha 通道即可:

// 使用 RGBA
.background {
  background-color: rgba(255, 0, 0, 0.5); /* 红色背景 50% 透明度*/
}

// 使用 HSLA
.background {
  background-color: hsla(120, 100%, 50%, 0.3); /* 绿色背景  50% 透明度*/
}

// 使用 HEX 8位16进制颜色代码
.background {
  background-color: #0000FF80; /* 蓝色色背景 50% 透明度*/
}

// 使用 HEX 4位16进制颜色代码
.background {
  background-color: #00F8; /* 蓝色色背景 50% 透明度*/
}

其中 RGB 和 HSL 两种方法则在起方法名后面加上 A 即可,然后取值范围从 0(完全透明)到 1(完全不透明)。

16 进制的方法则有点复杂,使用16进制颜色代码设置背景透明度可以通过使用8位(#RRGGBBAA)或4位(#RGBA)的16进制格式来实现,其中最后两位(AA)或最后一位(A)代表透明度(Alpha)。透明度的值范围从00(完全透明)到FF(完全不透明)。

所以上面的例子中 0000FF 是蓝色,80(即128/255)表示大约50%的透明度。另外需要特别注意一下虽然现代浏览器普遍都支持16进制颜色透明度代码,但在某些旧版本的浏览器中可能不会正常工作,因此,如果你需要兼容,建议还是使用 rgba()hsla() 函数。

另外使用 opacity 定义透明度,但是他是使得整个元素透明度都下降,包括它的背景、文本和边框等,这个时候要注意你是要整体还仅仅是背景了。

.background {
  background-color: #0000FF; /* 蓝色色背景 */
  opacity: 0.5; /* 整个元素50% 透明度 */
}

在 WordPress 中如何设置支持透明度的颜色字段

我们知道有个 wp-color-picker 组件,可以让我们在设置输入字段的时候,可以直接选择颜色(在 WPJAM Basic 添加字段的时候,将 type 设置为 color 即可):

但是他无法设置透明度,Sergio 就更新了一下 wp-color-picker 组件,发不了 wp-color-picker-alpha 组件,支持通过拖拉即可设置透明度,如下图所示:

哈哈,WPJAM Basic 最新版也支持了该功能,在设置添加字段的时候,将 type 设置为 color 之外,还需要加上 data-alpha-enabled 属性,并将其设置为 true,比如我上面设置背景色的代码:

$fields	= [
	'background-color'	=> ['type'=>'color',	'button_text'=>'填充颜色',	'data-alpha-enabled'=>true]
];

我和大胡子做的模块化主题「Modular」也很快会加上该功能:

WordPress「站点选项」插件:一键查看和管理站点全局选项

2024年10月27日 23:42

前面我写了 WordPress 中如何设置全局选项?一文详解 WordPress 的 Option 功能,为了方便 WordPress 所有站点选项的管理和设置,我做了一个 WordPress「站点选项」插件,可以查看和管理所有 WordPress 站点的全局选项,特别是选项不再使用了,可以通过该插件直接删除它。

为什么开发这个插件?

我们知道绝大部分的插件和主题都会有选项设置,这些选项设置就会在 WordPress Option 表里面插入一些数据,如果这些插件或者主题不用的话,这些加入到 Option 表里面的数据一般都还会留在那里。

其实这些站点选项数据留在那里,问题也不大,不过总有一些有洁癖的同学,想清理一下,比如我,所以就开发了这个「站点选项」WordPress 插件。

查看和管理站点选项

安装好之后,在 WPJAM 菜单下会多出一个「站点选项」的子菜单,点击进去,即可查看站点上所有的全局选项:

对于这些选项数据,如果觉得没有任何用了,比如是插件停用之后的残留,就可以删除他们,不过删除前还是要再次确保不再使用。

除了删除之外,我们还可以进行「编辑」和「重命名」等操作,但是进行这些操作之前,还是要确认该操作不会造成任何问题。

另外对于如果数值是数组的选项,在列表是解析出来显示的:

但是在编辑的时候,在编辑的时候,显示的是序列化的:

所以编辑的时候,也要注意,不要搞错了,这时候建议的通过「替换」进行操作:

最后WordPress 选项「Option」的自动加载的功能,该功能是在 WordPress 的加载的时候,开启的「自动加载的选项就会一次全部加载,这样下次再使用该选项的时候,就无需再从数据库中获取。

所以该插件也可以加上一个设置「自动加载」的功能,可以开启或者关闭某个选项的「自动加载」功能,如下图所示,在列表页最后一列自动加载的开关点击一下即可切换:

总之,WordPress 「站点选项」是一个非常方便的后台数据管理 WordPress 插件,可以让你一键查看和管理站点的全局选项,但是操作之前还是要确保你对这些的操作已经足够了解,是自己真正需要的。😄

WordPress 「站点选项」插件

WordPress 「站点选项」插件是 WordPress 果酱知识星球福利插件,加入「WordPress果酱」知识星球(长按下图二维码)即可下载:


「WordPress果酱」知识星球福利插件基于 WPJAM Basic 开发,加入「WordPress果酱」知识星球,即可下载:

插件 简介
抓取公众号图文

支持一键同步微信公众号文章到 WordPress 博客,并支持一键将文章中所有图片都下载到 WordPress 媒体库。

搜索优化

WordPress 最强的搜索优化插件,支持限制每个 IP 每分钟搜索次数,达到上限之后屏蔽搜索时长,还可以限制搜索关键词的长度,搜索结果页面限制只显示「搜索结果」,还有以下搜索功能增强:

1. 只搜索文章标题,不搜索文章内容和摘要。
2. 当搜索关键词为空时重定向到首页,只有一篇文章时重定向到文章
3. 后台文章列表支持搜索ID。
4. 支持搜索自定义字段。

编辑器优化

一键增强 WordPress 经典 TinyMCE 编辑器:

1. 增加下划线,背景颜色,两端对齐,字体和大小设置,以及内容分页按钮。
2. 新增插入表格功能。
3. 直接插入屏幕截图。

标题设置

一键设置 WordPress 所有页面的页面标题,通过规则方式让博主可以自定义 WordPres 首页,分类,文章类型,文章详情都所有页面的页面标题。

登录优化

一键优化 WordPress 登录注册界面,并支持第三方账号登录和绑定,目前已经支持微信公众号(所有类型),微信小程序,手机号码第三方平台。

内容模板

实现在内容中插入一段共用的内容模板,通过短代码(shortcode)的方式来实现的,支持统一修改,目前支持普通的内容模板,表格内容模板和卡片内容模板三种类型。

用户管理

最强 WordPress 一键用户管理插件,一键实现以下12个功能:

1. 屏蔽个性化设置
2. 屏蔽姓氏和名字设置
3. 取消显示名称设置
4. 开启别名设置
5. 隐藏用户登录名
6. 开启登录次数限制
7. 用户最后登录时间
8. 按注册时间排序
9. 以此身份登陆
10. 生成密码重置链接
11. 自定义用户头像
12. 默认用户头像

分类管理

这是一个全能的 WordPress 分类管理插件:

1. 层式管理分类
2. 限制分类层级
3. 分类拖动排序
4. 使用数字固定链接
5. 首页文章支持分类过滤
6. 后台文章列表支持分类筛选过滤
7. 后台文章列表支持分类多重筛选

评论增强

这是一个 WordPress 评论增强插件,支持评论置顶,评论点赞和按照点赞数排序。

图片集

1. 给媒体创建个分类「图片集 | collection」
2. 图片分类限制为二级
3. 取消图片编辑入口
4. 附件页面直接图片链接。

配置器

全自动 WordPress 配置器,不用一行代码就可以开发。
支持自定义文章类型,自定义字段,自定义分类,分类选项,全局选项。

Script Loader

通过恢复 WordPress 联合加载方式来优化 WordPress 后台脚本加载。

外部链接

将文章或评论中的外部链接加上安全提示的中间页。
让用户确认之后再跳转,并还支持添加 nofollow rel 属性。

话题标签

文章中插入 #话题标签#。
如果是内部链接,直接跳转,
标签或者分类,则自动转换成标签或分类链接,
否则跳转到搜索链接。

格式文章

在 WordPress 实现真正的文章格式

草稿分享

一键生成草稿临时分享链接
并可设置分享链接的有效期

文章专题

设置文章专题,并在文章末尾显示一个文章专题列表。

文章隐藏

设置文章在列表⻚不显示,并且可以根据不同平台进行设置

Meta Data

可视化管理 WordPress Meta 数据,支持所有内置的 Meta 数据:
Post Meta,Term Meta,User Meta 和 Comment Meta。

站点选项

查看和管理所有非 WordPress 系统自动生成的站点选项。
如果你觉得某个选项无用,可以直接删除它。

后台论坛

WordPress 后台论坛,支持创建帖子,分组,消息。

微信小程序

微信小程序 WordPress 基础插件,包含基础类库和管理。

微信群二维码

轮询显示微信群二维码,突破微信群100人限制。

文章置顶

支持置顶文章排序和分类文章置顶的 WordPress 插件

静态文件

一键合并 WordPress 插件和主题的 JS 和 CSS 文件,加快页面加载速度

Debug

一键检测 WordPress 运行效率。

WordPress 中如何设置全局选项?一文详解 WordPress 的 Option 功能!

2024年10月24日 22:36

对于进行 WordPress 开发来说,肯定会了解到的一个开发功能就是 WordPress 设置选项的创建,访问,修改和删除,比如主题和插件的设置选项处理,那么 WordPress 具体是怎么管理全局选项的呢?

WordPress 全局选项管理的接口叫做 Option API,它是一种简单且标准化的在数据库中存储数据的方法,它使用给定的自定义名称将数据存储到 wp_options 表中。

WordPress 提供了 Option 的增删查改四个操作的函数,如果你安装的 WordPress 是多站点版本,那么还有对应的 _site_ 函数应用全网选项的函数,同样使用给定的自定义名称将数据存储到 wp_sitemeta 表中。

但是多站点的选项设置用到场景比较少,所以今天我们还是详细介绍一下 Option 的增删查改四个操作的函数:

增加选项|add_option

add_option( string $option, mixed $value = '', string $deprecated = '', string|bool $autoload = null ): bool

add_option 函数实现给 WordPress 增加一个选项,选项的名称通过参数 $option 指定,选项的值 $value 支持标量和非标量,如果非标量的话,则该值可以被序列化,但是无需手动对值进行序列化,该函数会在将值插入数据库之前会进行序列化操作,所以简单说,就是把各种类型值 $value 无需做任何处理,以 $option 作为名称添加到选项中。

另外第三个参数是被放弃的,不用管,如果要用到第四个参数 $autoload 的时候,三个参数的位置直接输入空字符串即可,这里简单说下一下第四个参数 $autoload,用于定义在 WordPress 启动的时候是否自动加载该选项到内存中,该参数默认值为 null,意思是它会自动根据 $value 大小来决定是否自动加载,小于 150000 字节则会自动加载,如果不管大小都要求自动加载,则可以将其设置 'on',无需自动加载,则需要将其设置为 'off'

最后如果该选项如果被成功添加,则返回 true,否则 false,额外说一下如果该选项数据库已有,则无法添加成功,如果你是想如已存在则修改,则建议用到后面介绍 update_option 函数。

add_option( 'my_option', 'my_value' );

比如上面代码就添加一个名称为 'my_option' 选项,它的值为:'my_value'

删除选项|delete_option

delete_option( string $option ): bool

delete_option 函数删除名称为 $option 的选项,删除选项函数比较简单,比如下面的代码就是删除名称为 'my_option' 选项。

delete_option( 'my_option' );

查询选项|get_option

get_option( string $option, mixed $default_value = false ): mixed

get_option 函数用于获取名称为 $option 的选项的值,除该参数之外,它还有第二个参数 $default_value,该参数默认值为 false,如果选项不存在,则返回该值。

get_option 函数返回值的类型可能会因与保存或更新选项时传递的类型不同而不同,如果选项值被序列化了,那么在返回时它将被反序列化,在这种情况下,返回的类型将会相同,比如存储一个如数组这样的非标量值,将返回相同的数组。

在大多数情况下,非字符串的标量和 null 值存储被转换并返回为字符串等效值。比如通过 add_option( 'my_option', $value ) 添加选项,然后通过 get_option( 'my_option' ) 获取选项值将会:

  • false 返回 string(0) ""
  • true 返回 string(1) "1"
  • 0 返回 string(1) "0"
  • 1 返回 string(1) "1"
  • '0' 返回 string(1) "0"
  • '1' 返回 string(1) "1"
  • null 返回 string(0) ""

如果添加是非标量的值,比如 add_option( 'my_array', array( false, 'str', null ) ), 返回的值将与原始值完全相同,因为它在保存到数据库之前已经被序列化了:

array(3) {
    [0] => bool(false)
    [1] => string(3) "str"
    [2] => NULL
}

更新选项|update_option

update_option( string $option, mixed $value, string|bool $autoload = null ): bool

update_option 函数的参数和 add_option 函数参数除了没有放弃的参数,基本都是一致的,用法也是一样的,这里就不重复了。

那么 update_option 函数和 add_option 函数的区别主要是:add_option 函数只会添加,如果已经存在,则不会覆盖,而 update_option 函数则会修改现有的选项,如果不存在,它则会调用 add_option 函数增加。

update_option( 'my_option', 'my_value' );

比如上面代码就修改名称为 'my_option' 选项的值为 'my_value',如果不存在则增加该选项,值也是为 'my_value'。

总结

关于 WordPress 全局选项,或者说站点选项的开发接口介绍,最核心的部分就是这四个函数,只要认真阅读这篇文章,那么进行开发的时候基本不会有太大的问题。

WordPress 新一代默认主题 Twenty Twenty-Five「2025」初探

2024年10月21日 23:46

WordPress 6.7 版本将推出一个新的默认主题:Twenty Twenty-Five,今天我们一起看看:

概念

Twenty Twenty-F​​ive 的设计理念可以总结为一句话:「简单的事情应该直观的,而复杂的事情应该可行的」。

所以该主题就体现了极致的灵活性和适应性,使用户能够通过多种模式和风格讲述自己的故事,有多种图案和风格可供选择,主题中融入的自然美景和历史的片段唤起了无常、时间流逝和不断进化的想法。

拼贴画形式的构图展示了 2025 年默认主题中使用的许多照片。

模式

在结构上,Twenty Twenty-Five 主体提供了一套健全的模板,为服务、关于、落地页、产品、行动呼吁、事件等多个类别设计了广泛的模式,提高了操作性并让用户快速撰写有针对性的页面。

A broad range of patterns designed for the 2025 theme in categories like services, about, landing pages, products, calls to actions, events, etc.

样式

考虑到该主题的全球使用,从设计的最初概念步骤开始,就考虑了支持多种语言的高质量和全面的字体,此外,主体还完善了一组不同的调色板,将其作为风格样式捆绑在主题中。

为 2025 年默认主题设计的八种不同的调色板。
为 2025 年默认主题设计的八种不同的字体搭配。
展示针对 2025 主题设计的不同风格变化模板的九个示例。

模板

Twenty Twenty-F​​ive 还提供了多用途的博客模板集:带有侧边栏的以文本为中心的博客模板、强调特色图片的照片博客模板以及具有多样化内容的更复杂的博客模板。

Twenty Twenty-F​​ive 并且和站点编辑器完全兼容,并使用了许多新的设计工具,例如网格块和图案/部分样式。

个人博客(默认)

为了保持简单的理念,个人博客倾向于依赖一个可以正常工作的默认模板,无论是否想写一个带有标题和特色图片的文章,并且显示文章的所有内容,而不仅仅是摘要。

两个模型:左边的模型显示带有图片、帖子标题和帖子全部内容的博客帖子,右边的模型显示单篇帖子。

照片博客(替代)

主要为摄影或作品集定制的替代“照片博客”模板,依赖于图像密集型的方法,具有可用于多种用途的有趣布局。

两个模型:左边的模型仅显示博客文章的特色图片,右边的模型显示带有全宽图像的单篇文章。

复杂博客(替代)

最后,复杂博客替代模板集更适合内容复杂度更高的网站。其中一些模板的字体范围更加多样,设计也更具个性,可以吸引不同的受众。

两个模型:左侧的模型显示了一个 3 列网格,其中的博客文章包含特色图片和文章标题,后面跟着一个 2 列网格;右侧的模型显示了一个单篇文章,其中有一个左对齐的大标题、文章元数据和一张宽图像,后面跟着文章内容,右侧有一个侧边栏。

主题随着 WordPress 6.7 一起发布。在这之前推荐我们主题:

深度自定义与模块化设计的 WordPress 企业主题来了」总结一下,可以说 Modular 主题完全是为了企业建站而生的:

如果你是一家企业的 IT 负责人,通过这个主题,自己设计一下图片,就能快速完成企业交给你的任务,再加上 WordPress 本身的易用性,这款主题可以说让你每天的「摸鱼」时间成倍增加。

如果你是一个平时接接单给企业做个小网站的自由职业者,这款主题可以让你快速赚到钱,你完全不用操心代码的事情,只需要沟通清楚企业的需求,找到对应的模块搭建进去即可,让你只需要800块钱的成本就能够构建5000-10000的企业站点。

最后的最后,Modular(模块化)主题是一个付费的主题,基于 WPJAM Basic 插件构建,原价2680 元,现在只需 688 元就能构建一个完全个性化的企业站点,购买请复制下面链接或者点击阅读原文:

https://wpjam.com/go/modular

在 PHP 和 WordPress 中如何给数组切片

2024年9月12日 16:58

从一个数组中取出一段数据,或者说切片,这是非常常见的数组操作,PHP 已经内置了了 array_slice 函数来实现这个操作,但是面对关联数组的一些基于 key 的切片操作,该函数就有点力不从心了,那么我们面对这些复杂的情况,怎么操作呢?今天就通过这篇文章详细讲解一下在 WordPress 中如何给数组切片。

还是从 array_slice 说起

array_slice 的简介就是从数组中取出一段,它是从指定偏移量开始提取特定数量的元素,具体的语法:

array_slice(array $array, int $offset, int $length, bool $preserve_keys = false)
  • $array:待切片的数组。
  • $offset:切片开始的位置,从 0 开始计数,支持负数,从末端开始算起。
  • $length:切片元素的长度。
  • $preserve_keys(可选):是否保留切片元素的键名,默认值为 false。注意无论本参数如何设置,都会保留字符串的键。

还是看具体的例子吧。

// 从数组中取出第一个元素
$slice = array_slice([1, 2, 3, 4, 5], 0, 1); // [1]

// 从数组中取出第二个和第三个元素
$slice = array_slice([1, 2, 3, 4, 5], 1, 2); // [2, 3]

如果是用负偏移量,将从数组末尾开始计数:

// 从数组中取出倒数第二个元素
$slice = array_slice([1, 2, 3, 4, 5], -2, 1); // [4]

如果不指定长度,则切片将包括从偏移量到数组末尾的所有元素:

// 从数组中取出第二个和之后所有的元素
$slice = array_slice([1, 2, 3, 4, 5], 1); // [2, 3, 4, 5]

如果将 $preserve_keys 参数设置为 true,则切片元素将保留其原始键名:

// 从数组中取出第二个元素,并保留键名
$slice = array_slice([1, 2, 3, 4, 5], 1, 1, true); // [1 => 2]

对于关联数组,则  $preserve_keys 不管参数是什么值,都会保留原始的键:

// 从关联数组中取出第二和第三个个元素,下面都是输出 ['b'=>2, 'c'=>3]
$slice = array_slice(['a'=>1, 'b'=>2, 'c'=>3, 'd'=>4, 'e'=>5], 1, 2, true);

$slice = array_slice(['a'=>1, 'b'=>2, 'c'=>3, 'd'=>4, 'e'=>5], 1, 2);

关联数组如何切片

从上面的例子可以看出 array_slice  是基于偏移量和长度进行切片的,但是对于关联数组来说,如果我们要基于数组的 key 进行切片怎么操作?

WordPress 的 wp_array_slice_assoc

WordPress 内置有个 wp_array_slice_assoc 函数,它基于一个健的列表从关联数组中取出数组,具体的语法:

wp_array_slice_assoc( array $input_array, array $keys )
  • $input_array:待切片的关联数组。
  • $keys:健的列表。
// 从数组中取出键为 c 和 b 的元素
$slice = wp_array_slice_assoc(['a'=>1, 'b'=>2, 'c'=>3, 'd'=>4, 'e'=>5], ['c', 'b', 'f']); 
// 结果为 ['c'=>3, 'b'=>2] 

取出的数组是按照 $keys 参数的顺序取出来的,上面的例子中,我故意把 c 放到 b 前面,取出的关联数组的 key 的顺序也是按照这个顺序,另外数组中不存在的 key,取出关联的数组也是不存在的,比如上面例子的 f。

WPJAM Basic 的 wpjam_slice

因为 wp_array_slice_assoc 取出的关联数组的顺序是按照输入的 $keys 参数顺序的,但是有些情况下我们要求取出的关联数组的顺序不要动,即不关系 $keys 的顺序,所以我在 #WPJAM Basic# 中加入了一个 wpjam_slice 函数,它取出的数组是不会变动的,具体的语法:

wpjam_slice( array $input_array, array $keys )
  • $input_array:待切片的关联数组。
  • $keys:健的列表。

还是看具体的例子吧:

// 从数组中取出键为 c 和 b 的元素
$slice = wpjam_slice(['a'=>1, 'b'=>2, 'c'=>3, 'd'=>4, 'e'=>5], ['c', 'b', 'f']); 
// 结果为 ['b'=>2, 'c'=>3] 

最后取出的关联数组的是按照原先的顺序,并且不存在的 key,取出关联的数组也是不存在的。

此外 $keys 参数除了数组之外,还支持字符串,通过空格或者逗号转化成数组:

// 从数组中取出键为 c 和 b 的元素,$keys 参数为逗号间隔字符串
$slice = wpjam_slice(['a'=>1, 'b'=>2, 'c'=>3, 'd'=>4, 'e'=>5], 'c,b,f']); 
// 结果也是 ['b'=>2, 'c'=>3]

// 从数组中取出键为单个元素
$slice = wpjam_slice(['a'=>1, 'b'=>2, 'c'=>3, 'd'=>4, 'e'=>5], 'c']); 
// 结果为 ['c'=>3] 

这样 WordPress 中给数组如何切片,是不是方法更多了一下,哈哈!

中文环境下,WordPress 截取个摘要,竟然有那么多问题!

2024年9月8日 23:09

我们先从 WordPress 文章摘要功能说起,大部分 WordPress 主题在首页,分类搜索等各种列表页,会只显示文章摘要,而不显示文章内容全文,所以摘要很重要,在列表页,用户是否会点击查看这篇文章,摘要会起到很重要的效果。

怎么设置文章摘要

那么怎么设置摘要呢?在使用经典编辑器的年代,摘要是非常容易设置的,就在文章内容的下面,很多人写完文章,顺手也设置了文章摘要:

但是升级到古腾堡编辑器之后,很多人就发现不知道去哪里设置摘要了,摘要设置文本框被移到编辑器右侧文章设置的很下面,很多人没有认真去看,还以为没了。😅

甚至有些人因为这个原因,从来没有去设置过文章摘要,也有人因为这个原因坚持在用经典编辑器。😅

#WPJAM Basic# 插件支持一键屏蔽古腾堡编辑器,此外 #WPJAM Basic# 还提供一个扩展「摘要快速编辑」,让你可以在文章列表快速设置文章摘要:

使用文章摘要

设置了 WordPress 摘要,那就要去用,这个一般来说都是主题开发者的工作,这里简单了解一下就好,如果你要自己修改主题,那就就要认真看下。😄

WordPress 提供了两个文章摘要的模板函数,这个知道就好,一般主题就是使用这两个函数实现的。

1. get_the_excerpt( $post = null ) ,用于获取文章的摘要,它只有一个参数,就是 $post,可以是文章对象,或者文章 ID, 也可以不传,不传则获取当前文章的摘要。

2. the_excerpt(),直接输出当前文章的摘要,该函数没有任何参数,所以模板开发很简单,直接在文章列表页使用该模板函数即可。

自动获取文章摘要

由上可知,并不是每篇文章都设置了摘要,这个时候,WordPress 默认会自动获取:

WordPress 默认会使用 wp_trim_excerpt 去获取文章内容,加上摘要长度传递给 wp_trim_words 函数处理, wp_trim_words 会基于用户所处的环境:

  • 单词之间没有空格的,比如中日韩,它就按照中文字符和英文字符都算一个字符来截取。
  • 单词之间有空格的,比如英文或其他,它就按照空格或者回车来获取单词数组,截取输入长度的单词数。

这种算法对于中文来说,非常不好,因为一个中文字符,宽度基本上是一个英文字符的两倍,如果文章中的中英文混排的话,截取出来肯定会长度不一。

所以现在很多主题会加入自动摘要截取优化的代码,但是有些主题直接使用 substr 函数来获取摘要,该函数是把中文算成 3 个字符,英文字符算 1 个字符,这个算法有点奇怪,但是如果英文不多,截取的产地还算一致,但是比较致命的是,该函数无法判断一个完整的中文字符,截取的时候,可能在中文字符中间劈开了,然后就出现乱码:😅

所以对于中文环境,最好按照「中文 2 个字节,英文 1 个字节」的方式来截取,并且中文字符会当作一个完整的字符来处理,而采用该截取算法 PHP 函数则是 mb_strimwidth

mb_strimwidth($text, 0, 240, '...', 'utf-8');

为了方便大家的设置,我在 #WPJAM Basic# 集成了自动获取文章摘要的设置,无需修改任何代码,简单选择设置一下即可,点击「WPJAM」菜单下「文章设置」子菜单下之后可以看到:

当文章未设置摘要时候,默认还是 WordPress 默认自带的截取摘要的方式,然后 WPJAM Basic 插件增加了两个选项:

  • 第一个很简单直接:直接不显示摘要。
  • 第二个选项就是前面介绍的算法,按照中文最优方式截取,并且还可以设置文章摘要的长度。
    再次提醒一下注意算法是「中文 2 个字节,英文 1 个字节」,设置长度的时候要注意下。

这个时候再看看,除了第二篇是后台设置了摘要,其他三篇摘要都基本差不多长度了,并且也没有出现乱码:

mb_strimwidth 不存在?

写到这里,你是不是觉得 WordPress 摘要的问题已经解决了?现在还存在两个问题:

1. #WPJAM Basic# 的设置不生效,还是出现上面那种乱码,或者长短不一的情况。

因为插件的优化摘要的代码和主题优化摘要的代码优先级是不一定的,可能主题占优了,那么你这个时候应该咨询主题作者,让他提供选项,然后你可以关闭主题的摘要优化功能。

2. 直接报错了:

Call to undefined function mb_strimwidth()

好吧,mb_ 打头的函数,需要 PHP 安装 mb_string 扩展,在后台「WPJAM」菜单下的「系统信息」的子菜单中,可以快速查看:

所以我又升级了一下 #WPJAM Basic# ,做了兼容,就是说现在没有装该扩展,也有该函数了:

if(!function_exists('mb_strimwidth')){
	function mb_strimwidth($str, $start, $width, $trimmarker=''){
		preg_match_all('/./us', $str, $match);

		$count	= count($match[0]);
		$start	= $start < 0 ? $count-1+$start : $start;
		$chars	= array_slice($match[0], $start);

		if($width >= array_sum(wpjam_map($chars, fn($char)=> ord($char) >=224 ? 2 : 1))){
			return implode('', $chars);
		}

		$length	= 0;
		$result	= '';
		$count	-= $start;
		$width	-= strlen($trimmarker);

		for($i=0; $i<$count; $i++){
			$char	= $chars[$i];
			$w		= ord($char) >= 224 ? 2 : 1;

			if($length + $w > $width){
				break;
			}

			$result	.= $char;
			$length	+= $w;
		}

		return $result.$trimmarker;
	}
}

这就是我最近发现大家在设置 WordPress 文章摘要中碰到的问题。好累,一个摘要的问题写了那么长。😅

还有一点,文章摘如果设置得好,结合一些 SEO 插件,比如 WPJAM Basic 的「简单SEO」扩展,摘要也可以设置成 meta description,搜索引擎收录内容之后,在搜索结果页面显示的内容也是文章的摘要。

又做了一个 WordPress 工具,可以一键生成 WordPress 数据库表前缀修改 SQL

2024年8月22日 18:56

好吧,不说理由,你就是需要修改 WordPress 的数据库表的前缀,那么所有的 WordPress 数据表的前缀都需要修改,还有 opitonsuser_meta 表里面的一些字段也要进行修改。

手工改的话,会非常累,真的会非常累,所以我就写了一个工具,可以一键把用于修改的所有数据库表前缀的 SQL 全部生成出来:

如上图,你只需要输入旧的前缀,和新的前缀,然后点生成即可,然后把生成的 SQL copy 到 MySQL 运行一遍即可,非常方便。

特别注意一下就是,在 MySQL 中运行 SQL 修改前缀之前,一定要先备份好数据库。最后工具的地址是:

https://wpjam.com/tool/prefix-changer/

另外我在「果酱站长」的首页 WordPress 分组也加入了该工具:

https://wpjam.com

欢迎收藏,下次要进行数据库前缀需要修改的时候就方便了,如果有这方面需求的朋友也可以分享给他。

❌
❌