解决因为 SSL 导致的 WordPress 后台无限 Redirect 的问题

silver mercedes benz emblem on blue surface

在使用 CapRover 并配置域名为 HTTPs 域名时,在你访问管理后台时,可能会导致触发Chrome 自己的无限 Redirect 的问题。

之所以出现这个问题,是因为 CapRover 的架构导致的:CapRover 在最外层是一个 Nginx,SSL 证书也是在这一层完成的。而 CapRover 的默认配置,在将请求向后转发时,透传的域名会是不含 HTTPs 的协议标识的,导致 WordPress 认为发来的请求是非加密的。

d2b5ca33bd970f64a6301fa75ae2eb22 18

而 WordPress 识别到你的请求未加密,就会返回 302 让你进入 HTTPS的链接。但新的请求并不会带上 HTTPs 的标识,导致进入无限循环。

解决这个问题的一个简单处理的方式是 — 在你的 wp-config.php 中加入如下代码,来告诉 WordPress,这个请求已经是 HTTPs 保护的了,你直接处理就好。

/* for ssl in docker */

define('FORCE_SSL_LOGIN',true);

define('FORCE_SSL_ADMIN',true);

$_SERVER['HTTPS'] = 'on';
Code language: PHP (php)

插件多次加载导致的 WordPres 后台加载缓慢

turned-on monitor

WordPress Jetpack 的一个陈年 Bug – 在 wp-Options 中生成大量的数据 中,我提到,问题的根源并不是数据库,虽然在数据库中产生了大量的数据,但并没有真正意义上拖慢系统的进程, 那到底是什么拖慢了进程?

1fp2qm

随着对系统的深入排查,我发现一个异常的事情,在进入管理后台时,出现了插件更新插件列表的情况。这个并不多见。因为管理后台的进入不应该涉及到对于插件列表的更新。此外,我发现这个查询的 SQL 巨长,且包含了大量的查询。

d2b5ca33bd970f64a6301fa75ae2eb22 32

于是评估,这个可能才是导致系统缓慢的真正原因。熟悉 WordPress 的读者一定知道, WordPress 对于插件的加载,是通过在数据库中存储了一组插件路径,每次启动时通过这组插件路径来加载插件。这样对于 WordPress 来说,可以快速加载插件。

但在这次的异常场景中,同一个内容的插件被加载了多次,就算这个插件比较小,可能依然会导致计算时间。此外,WordPress 引入插件后,会加载对应的 Hook 、 Filter 和 Action,则可能导致同一个 Action 被频繁触发,造成额外的计算量。从而使得虽然数据库查询时间不长,但整体耗时却巨长无比。

而这个问题的处理倒是也比较简单:

  1. 对 active_plugins 进行备份,避免修改跪了。
  2. 对于 active_plugins 进行清空,此时 WordPress 会彻底不加载任何插件。
  3. 仿照之前的列表,启用所有的插件。

通过对于active_plugins的清理,将启动速度成功降低至 2 秒左右,将系统性能提升了 80 %。

d2b5ca33bd970f64a6301fa75ae2eb22 36

WordPress Jetpack 的一个陈年 Bug – 在 wp-Options 中生成大量的数据

silver mercedes benz emblem on blue surface

最近在处理一个 WordPress 系统访问下降的问题时,发现了一个奇怪的现象:一个只有很少的页面的网站,数据库备份竟然足足有 9.5 GB。我当时的第一反应是:数据库性能极差导致的站点性能不好。

d2b5ca33bd970f64a6301fa75ae2eb22 29

不过,到数据库打开后发现, 虽然有大量的条目生成,但因为no autoload,所以其实并不会被自动加载到缓存中,从而也不会让网站的性能有太多的下降。

d2b5ca33bd970f64a6301fa75ae2eb22 31

想想也合理,数据库中包含了数十万条记录,如果都加载到内存里,可能 PHP 默认的 1024MB 的运行内存直接被打爆了,所以问题不在此。

不过,虽然问题的核心不是它,但如此海量的脏数据对于系统依然是无价值和无意义的,于是乎我便将这些脏数据删除,数据库的大小从 9.52 GB 骤降至 34.8 MB,进入到一个正常的数据库大小区间了。

删除脏数据的命令如下:

DELETE FROM wp_options WHERE option_name LIKE '%jpsq_sync-%'
Code language: JavaScript (javascript)

相关链接

  • https://wordpress.org/support/topic/wordpress-database-error-commands-out-of-syn/
  • https://wordpress.org/support/topic/jpsq_sync-table-constantly-generated-to-the-db/
  • https://gist.github.com/bhubbard/894040fec6421f891f1f88f2c6428ef0

WordPress 出现 RedisException: OOM command not allowed when used memory > maxmemory 的报错怎么处理?

a computer screen with a bunch of text on it

早晨起来,想登录博客,记录下自己的灵感,突然发现死活登录不上 WordPress 后台。

登录到 VPS 后台,发现没有出现我之前常出的问题 — 硬盘满了。于是再次回到网页端登录,仔细研究后发现,我的登录应该是成功的,但登录完成后,又重新跳转回来,根据这个情况,我猜测可能是登录态出现了问题。

于是尝试切换到 Safari 、Chrome 的无痕模式登录,依然没有解决问题。因此可以排除掉客户端的问题导致的。

找到问题

接下来就是查看服务端问题。登录到服务器上,找到 WordPress 的日志,查看最近的几条日志,突然在众多 Notice 当中,看到了一个 Exception:

RedisException: OOM command not allowed when used memory > 'maxmemory'
Code language: JavaScript (javascript)

看到这个报错,突然明白了问题在哪了。

我的 WordPress 使用 Redis 作为缓存,而我过去一直配置的缓存空间是 128M,看报错,显然是因为 Redis 使用的内存空间大于 128M,而我过去没有配置逐出机制(默认是 noeviction),导致直接 OOM 爆掉了。

而我的登录态也使用了 Redis,没办法在缓存当中塞入新的 Key,自然登录也就失败了。

解决问题

找到问题之后,下一步便是解决问题。

解决问题并不复杂,为 Redis 调整内存空间大小,并配置逐出机制,就可以解决这个问题。

maxmemory 221000000
maxmemory-policy allkeys-lru

将 Redis 逐出机制设置为 allkeys-lru ,并将内存设置为 200M 后,重启 Redis ,果然我的 WordPress 可以正常登录了。

参考

allkeys-lru 表示对移除最近使用最少的 (least recently used)Key。

更多算法可以参考 Key Evicution

为你的 WordPress 站点配置 Telegram Instant View

telegram

Telegram 内置了一个非常好用的阅读功能 —— Instant View。Instant View 可以实现在 Telegram 内部重新对网站内容进行排版,从而为读者提供更好的阅读体验。

作为一个网站主,如果你希望对你的网站提供相应的支持,则可以自行在 Instant View 的网站添加你自己的网站进行适配。

为 WordPress 添加 Instant View 适配

访问 Instant View 官网,并使用你自己的 Telegram 账号登录

d2b5ca33bd970f64a6301fa75ae2eb22 8
Instant View 官网

登录成功后,点击右侧的 My Templates,进入到 Templates 管理页面。

d2b5ca33bd970f64a6301fa75ae2eb22 9

并在 Templates 管理页面中间的输入框中输入你网站任一文章的地址,并回车,你会自动进入到规则的适配页面。

d2b5ca33bd970f64a6301fa75ae2eb22 10
规则适配页面

随后,在页面中输入你的站点的规则,这里我们可以使用其他开发者写好的规则。将规则粘贴在页面中

# Use Instant View version 2.0
~version: "2.0"

# Use this template only blog article pages
?exists: /html/head/meta[@property="article:published_time"]

# Get article text in <article> 
body:     //article

# Get title from <h1>

title:    $body//h1[1]
subtitle: $title/next-sibling::h2
author_url: //span[has-class("author")]//@href

# Get article cover image
cover: //img[has-class("wp-post-image")]

# Convert all iframe elements to inline element
@inline: $body//iframe[starts-with(@src, "/media/")]

# Remote header and footer
@remove: //article/header
@remove: //article/footer

# Replace p to figure
@replace_tag(<figure>): $body//p[.//img]

# Youtube Embedded Fix
@replace_tag(<figure>): $body//p[.//iframe]
Code language: PHP (php)

粘贴并保存后,会自动在最右侧页面生成预览的效果。

d2b5ca33bd970f64a6301fa75ae2eb22 11
加入规则适配后的效果

当你的规则适配效果无误后,接下来只需要点击右上叫的 Mark as Checked ,来标记该页面已经检查完车。

d2b5ca33bd970f64a6301fa75ae2eb22 12
标记为检查成功

测试完成第一个后, 接下来你只需要在你的博客当中挑选出 10 篇文章,进行文章的验证即可。

d2b5ca33bd970f64a6301fa75ae2eb22 4
验证至少 10 个页面才行

根据 Telegram Instant View 的规则,你需要验证满 10 篇文章,才能提交你的模板给官方人员审核。

d2b5ca33bd970f64a6301fa75ae2eb22 5

提交后,你会见到这样的提示,接下来只需要等待你的模板通过测试即可。

d2b5ca33bd970f64a6301fa75ae2eb22 6
提交成功

预览效果

在审核期间,你可以在编辑器页面右上角点击「View in Telegram」来查看预览的效果。包括你也可以复制里面的 rhash 的值,使用这个值来生成 Instant View 的链接分享给别人。不过,最方便的当然还是等官方审核通过以后再用。

d2b5ca33bd970f64a6301fa75ae2eb22 13
预览效果。

总结

Telegram Instant View 的开发不困难,掌握了一定的 HTML 、XPath 的基础,就可以开发完成,简单的几步,就可以让你的网站在 Telegram 当中拥有一个不错的预览效果,这个时间值得去花。

从企业视角,为什么要选择 WordPress?

silver mercedes benz emblem on blue surface

WordPress 在国内日渐式微,从过去的全民博客用 WordPress, 到后来的很少人会使用 WordPress 做博客,再到现在只有一小撮人还在使用 WordPress,伴随着 PHP 的衰落和 Golang 等新语言的兴起,WordPress 不再是国人的选择。过去曾经有一段时间,大家很喜欢用 WordPress 做电子商城,不过随着时间的流逝和国内外电商贸易环境差异的变化,使用 WordPress 开发电子商城也不再是一个选择。如今的企业,不再愿意选择 WordPress 来完成自己的业务。

不过,从我自己的视角来看,我们看待任何一个工具的时候,不能看他是否还流行,而是要看他是否还能解决我们所面临的问题。

WordPress 的优势是什么?

WordPress 最大的优势主要是三点:

  1. 插件市场足够丰富带来的更少的开发工作量:但凡提到 WordPress ,你就不能不提 WordPress 的插件市场。WordPress 海量的插件市场可以帮助你更好的完成你的工作。对于一些传统模式下需要自己开发的功能,你可以选择直接安装 WordPress 来完成工作。
  2. 服务端渲染带来的 SEO 友好:现代 SPA 也有服务端渲染的能力,不过对于开发者来说,则需要单独假设一套服务端渲染的服务来完成这部分工作。或者提前预生成所有的页面。对于页面较小的站点,预生成比较靠谱。但对于数据量极大的站点,预生成也是一个较为痛苦的过程。WordPress 因为更加的传统,所以一直采用的是服务端渲染的模式。服务端渲染在针对 SEO 进行优化时,可以获得更好的优化能力(毕竟有些时候 Spider 不一定会等你的页面在前端渲染完成)。
  3. 极强的编辑性带来的人力释放:WordPress 不仅仅是我们看到的给用户的这一套 UI,还包含了一个强大的用户后台。强大体现在 Editor (Gutenberg)、全站编辑(WordPress 5.9 开始提供的新能力)。这些能力可以让 WordPress 从一个只能用固定模板的网站,变成了提供了一定的自由度,可以通过拖拽来生成一个页面的能力。对于一些比较极致追求拖拽的人,还会使用 Elementor (不过不太好做性能优化,如非必要,不上 Elementor)。这个能力带来的时候可以释放开发团队的人力,在构建好最基础的 Block 之后,交由运营人员来完成后续的管理和维护。

WordPress 的劣势是什么?

但同样的,没有什么东西是只有好处没有坏处的, WordPress 的坏处同样明显。

  1. 使用 PHP 编写,国内维护人员难招:WordPress 所依赖的 PHP 生态式微,则相应的,从事 WordPress 开发的人也渐渐变得更少。对于企业来说,难以找到合适的人是一个很大的问题。
  2. 目标太大,容易被安全攻击:WordPress 作为全球使用量排行第一的 CMS(内容管理系统),盯着它的黑客也多。虽然对于 WordPress 本体的安全攻击很快就会被修复。但针对普通插件的攻击则不那么容易防范。如果选择不当,很有可能把自己变成黑客的肉鸡。

总结

技术领域没有银弹。WordPress 同样也不是那个银弹。在合适的场景下, WordPress 便能放大自己的价值。而如果不合适,同样也无法放大 WordPress 的存在价值。

在 WordPress 中实现同一个 CSS 类在不同页面展示不同的效果

programming language

在使用 WordPress 开发时,某些时候你会遇到在同一个类在不同页面的时候,希望有不同表现的诉求。在这种情况下,一个比较简单 or 比较 Tricky 的技巧是通过 Body 层的类选择器来实现。

在 WordPress 进行渲染时,会自动在页面的 <body> 上加入 postid-[id] 的类,对比本文就是 postid-5888

d2b5ca33bd970f64a6301fa75ae2eb22 29
比如本文的 class

类似的,如果是一个 Page,也会生成 page-id-[id] 的类。

d2b5ca33bd970f64a6301fa75ae2eb22 30
页面生成的类是 page-id-[id],和 post 规则不完全相同

因此,如果你需要某个页面的元素样式和其他页面元素样式不同,但页面结构保持一致,一个比较好的方式是通过这些页面类选择器来实现。以你要自定义 btn 样式为例。则可以这样实现:

// 标准页面的样式
.btn{
   // your styles
}

// 在文章 ID 为 5888 的文章上的样式
.postid-5888 .btn{
  // your styles
}
// 在页面 ID 为 84 的文章上的样式
.page-id-84 .btn{
  // your styles
}

Code language: JavaScript (javascript)

总结

借助上面的方式可以实现同一个类在不同的页面展示不同的样式。但我个人觉得,这样的实现方式可能对于 Debug 不太方便,尽可能少用。但如果你需要用的话,那一定要注意好组织代码,避免后续维护成本提升。

此外,除了通过修改 style.css 来实现,你可以考虑将 Page 单独的样式梳理在一个 page.css 中进行维护,从而降低维护难度和成本。
WordPress 当中也有一些插件来实现某个页面自定义的 CSS 能力,将这些样式放在插件中来实现也是一个不错的选择:Post/Page specific custom CSS

Reference

WordPress Contact Form 7 的正确用法

grayscale photo of person using MacBook

Contact Form 7在实际使用过程中,有些人为了简化表单的设计和使用,会选择直接在多个地方使用同一个表单,并通过页面选择器来实现不同的样式(常见于基于 Elementor 构建的页面)。

但这样会造成长期的可维护性问题:

  1. 每个页面单独写样式选择器来控制样式,且在样式命名方面没有习惯的话, 会导致页面的样式混乱,修改成本较高。
  2. 不同的页面的样式采用了相同的类名,在进行样式修改时,交接性极差。

如果想要解决这个问题,有两个方式:

  1. 规范页面样式类规范:不同风格和样式的按钮采用不同的类名,如(.blueBtn.yellowBtn);
  2. 多处使用的表单,采用复制的方式,而不是使用同一个表单:Contact Form 7 提供了 Duplicate 功能,可以非常方便的复制一个表单,并根据表单的位置来命名。降低配置表单的成本。
d2b5ca33bd970f64a6301fa75ae2eb22 14
Duplicate 一个表单

OneInStack 下部署 WordPress Multisite 的 Nginx 转发规则

silver mercedes benz emblem on blue surface

在 OneIn Stack 下如果需要配置一套 WordPress MU 的话,需要配置 Nginx 相应的转发规则。具体的规则如下:

 if (!-e $request_filename) {            
 	rewrite /wp-admin$ $scheme://$host$uri/ permanent;            
 	rewrite ^(/[^/]+)?(/wp-.*) $2 last;            
 	rewrite ^/[^/]+(/.*.php)$ $1 last;    
 }    
 location / {        
 	try_files $uri $uri/ /index.php?$args;    
 }
Code language: PHP (php)

将上述规则放置在 /usr/local/nginx/conf/rewrite/wordpressmu.conf ,并在创建 VHost 时选择对应的主机即可。

如何处理 Gutenberg 开发过程中的 Minified React error?

silver mercedes benz emblem on blue surface

在开发 Gutenberg 插件时,经常会出现下面这样的提示:

Uncaught Error: Minified React error #231; visit https://reactjs.org/docs/error-decoder.html?invariant=231&args[]=onClick&args[]=object for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
Code language: PHP (php)

上述提示表示当前的编辑器中出现了一个错误,但由于 React 的 Minified 设置,这些错误没有办法被打印出来。

在这种情况下, React 接管了默认的报错,让应用不至于崩溃,但另一方面,也让我们失去了处理这些问题的可能。因此,在本地的开发环境,最好还是将这个功能给关掉。

如何关闭默认的错误处理?

wp-config.php 文件中添加如下代码即可。

define('SCRIPT_DEBUG', true);
Code language: JavaScript (javascript)

在开发 Gutenberg 插件时,如何处理防抖?

silver mercedes benz emblem on blue surface

在开发 Gutenberg 插件时,如果你需要对编辑器的内容进行处理,则需要为其加入防抖措施,避免你的函数被频繁调用。

思路

由于编辑器需要高频处理,因此需要采用防抖策略,避免将多次输入视为不同的事件。这里可以使用 WordPress 提供的 useDebounce 来实现控制。需要注意的是,WordPress 自动的 Debounce 函数传入的参数应当采用 useCallback 来进行包裹。

参考代码

import {subscribe} from "@wordpress/data";
import {useDebounce} from  "@wordpress/compose"
import {useCallback} from "@wordpress/element";

const debounced = useDebounce(
        useCallback(() => {
            // do some thing
        }),500
    );
subscribe(debounced);
Code language: JavaScript (javascript)

使用 Github Action 发布 WordPress 插件

black and white penguin toy

WordPress 官网的插件系统采用的是 SVN 来进行管理,如果你希望将自己的插件发布至 WordPress 官网,就必须在本地安装 SVN,不太利于项目的管理。此外,WordPress 官网提供的是一个发布系统,而非版本控制系统(只是将 SVN 用作插件管理,并不是真打算让你每一个变更都提交),因此,你还是需要使用另外的版本控制系统(比如 Git)来管理你的代码。

为了简化发布,你可以采用 GitHub Action 来完成你的插件自动发布,这样你就可以使用 Git 来开发和管理你的插件,并让 Github Action 自动进行插件的发布。

具体操作

1. 配置 Action Secrets

因为你需要使用版本控制来进行发布,以及可能存在的协作开发的场景,处于安全的考虑,你应该将你的 SVN 的信息放置在 Action Secrets 当中。

d2b5ca33bd970f64a6301fa75ae2eb22 34

在仓库当中找到 Secrets – Actions ,新建两个 Secrets:SVN_USERNAMESVN_PASSWORD,配置上你的 SVN 账号信息,稍后将会使用你的这个账号信息来进行插件的发布

2. 创建一个 .distignore 文件

.distignore 文件可以帮助你实现忽略不需要发布到 WordPress 插件系统的文件,这样就让你的插件目录变得更加干净一些。在你的仓库根目录创建一个 .distignore 文件,并填写具体要忽略的文件,即可实现部分发布至 WordPress 插件目录。

以下是我的 Example

node_modules/
.github/
.git/
.distignore
.gitignore
package.json
package-lock.json
yarn.lock

3. 创建 Action 文件

在你的项目的 .github/workflows/ 中创建一个 publish.yml文件,并在其中添加如下代码即可。

name: Publish to WordPress Plugin Directory
on:
  push:
    tags:
    - "*"
jobs:
  tag:
    name: New tag
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@master
    - name: Build # 如果没有 NPM 相关构建工作,可以去除这一步。
      run: |
        npm install
        npm run build
    - name: WordPress Plugin Deploy
      uses: 10up/action-wordpress-plugin-deploy@stable
      env:
        SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }}
        SVN_USERNAME: ${{ secrets.SVN_USERNAME }}
        SLUG: wpstoreapp-spellcheck
Code language: PHP (php)

4. 发布版本

接下来只需要执行如下操作,既可以发布版本

git add .
git commit -m 'feat: release new version'
git tag 1.0.0
git push && git push origin 1.0.0
Code language: JavaScript (javascript)

上述代码中的 1.0.0 即为具体的版本号,可以根据你的诉求进行修改。

总结

在完成了配置后,后续你的插件发布就变得十分简单了:修改本地的 readme.txt 中的版本号,加入 changelog,并修改插件文件头中的版本,即可提交一个 commit ,添加对应的版本的 tag,然后 Push 到 Github 上,由 Github 来进行插件的发布。

而如果你是以公司/团队的形式来管理插件,也可以用类似的方式,这样虽然每个人都不掌握 SVN 的账号密码,但却可以完成插件的发布,十分方便。

针对 WordPress 开发配置 Sublime Text 4

029a1f00793d00a4a88e458d5cdfebb0

最近在开发两个自己用的 WordPress 的插件,所以就把 Sublime Text 配置成了适合 WordPress 的开发的状态。以下是我的一些记录。

加入代理

因为 Package Control 在境内访问不是那么的流畅,所以,针对 Package Control 进行相应的 Proxy 配置,你只需要找到相应的配置界面,在其中加入 Proxy 配置即可。

d2b5ca33bd970f64a6301fa75ae2eb22 16
{
  "http_proxy": "http://127.0.0.1:7890",
  "https_proxy": "http://127.0.0.1:7890"
}
Code language: JSON / JSON with Comments (json)

代码格式化

Sublime 自带 Reindent

Sublime Text 4 自带缩进格式化的工具,因此,可以不需要安装第三方插件来实现。

在 Sublime Text 4 的 Line — Reindent 当中可以完成相应的操作。

d2b5ca33bd970f64a6301fa75ae2eb22 17

为了更好的使用这个功能,我自己添加了一些配置来简化这个功能的使用:

  1. 安装 Package​Resource​Viewer 用于修改系统配置。
  2. 使用 Package Resource Viewer: Open Resource 命令,打开 Default 包中的 Context.sublime-menu文件,
  3. 在其中添加一行代码 { "command": "reindent","caption":"格式化选中部分" },即可实现在上下文菜单中加入自动的格式化能力。效果见下图
d2b5ca33bd970f64a6301fa75ae2eb22 18

代码辅助编写

Tabnine

由于我使用的是 Sublime Text ,所以 VSCode 才有的 GitHub Copilot 自然是无法使用的,但不代表你不能使用机器来帮助你快速生成代码。这里我选择的是 Tabnine

由于我目前还没有为 Tabnine 付费,所以他只能基于我本地的代码进行学习。

文档快速生成

DoxyDoxygen

虽然是给自己用的插件,还是希望代码写的足够清晰。一个更加简单的插件,可以帮助我更好的去写批注。

在 WordPress 的插件页面添加更多的连接

turned-on monitor

WordPress 的插件页面提供了不少的 Hooks,可以帮助我们实现自定义的插件页面,让用户在启用插件后,第一时间可以看到我们为其提供的功能,从而降低用户使用的成本。

d2b5ca33bd970f64a6301fa75ae2eb22 33

以上图为例,你可以看到,我在左侧的功能区添加了「配置 Token」和「购买额度」;右侧的更多链接区提供了帮助手册和联系我们,帮助用户优化体验,更快的了解如何使用你的插件。

左侧功能区

首先,在左侧功能,WordPress 提供了两个 Filter来实现这个功能:

一个是 plugin_action_links,这个插件传入两个参数,一个是当前插件的链接构成的数组,另一个则是插件的文件路径,你可以根据传入的参数判断当前是使用哪个插件,并通过返回不同的数组,来实现不同的功能。

另外一个则是 plugin_action_links_wpstore-spellcheck/wpstore-spellcheck.php,是在上一个 filter 的基础之上,加入了插件的路径,从而让你可以无需进行判断,直接针对对应插件来完成链接的修改。

以上图效果为例,具体的代码如下

function wpstoreapp_plugin_action_link($links, $file)
{
	if($file == plugin_basename(dirname(__FILE__) . '/wpstore-spellcheck.php')){
		$links[] = '<a href="./options-writing.php">配置 Token</a>';
		$links[] = '<a href="https://api.wpstore.app/plugins/spell-check/pricing" target="_blank">购买额度</a>';
	}
	return $links;
}

add_filter('plugin_action_links', 'wpstoreapp_plugin_action_link', 10, 2);
Code language: PHP (php)

这里我选择的是第一种实现方式,主要的原因是我无法保证用户安装插件一定是采用的是 WordPress 插件目录的安装方式,因此,在这种情况下,第二种带了路径的 filter 的名字是有可能发生变化的。

右侧更多链接区

右侧更多链接区可以用来承载联系我们、帮助文档等入口,从而实现用户在使用时,可以快速找到相应的辅助资料,从而获得更好的体验。

从实现的逻辑上来看,和在左侧功能区添加链接的基本逻辑是一样的,需要判断当前插件是否是目标插件,如果是,则可以根据需要添加功能。

add_filter( 'plugin_row_meta', 'wpstoreapp_plugin_row_meta', 10, 2 );

function wpstoreapp_plugin_row_meta( $links, $file ) {
	if ( plugin_basename( __FILE__ ) == $file ) {
		$row_meta = array(
			'docs'    => '<a href="https://www.wpstore.app/?p=291">帮助手册</a>',
			'contact'    => '<a href="mailto:hi@wpstore.app">联系我们</a>'
		);

		return array_merge( $links, $row_meta );
	}
	return (array) $links;
}
Code language: PHP (php)

总结

WordPress 为我们提供了方便的 Hook,可以让我们可以自定义我们想要的功能,借助这些功能来降低你的用户的 Landing 成本,从而实现更好的服务用户,是一个不错的选择。

如何“抄”一个 WordPress 插件

silver mercedes benz emblem on blue surface

WordPress 作为 CMS 生态的第一产品,PHP 生态的护城河,可以说,只要 WordPress 不死,PHP 就还能继续活下去。而 WordPress 团队也在不断迭代项目。因此,有不少的开发者以 WordPress 开发为生。

而得益于 WordPress 基于 GPL 开发的,所以,理论上,如果你开发的插件是通过 WordPress 官方的目录分发的,你的插件是需要以 GPL 兼容的协议开源的,这也给了想要开发同款插件的开发者们提供了机会。

PHP in WordPress themes must be GPL, artwork and CSS may be but are not required.

Matt Mullenweg, https://wordpress.org/news/2009/07/themes-are-gpl-too/

不过,需要注意的是,只有 PHP 的插件源码才需要以 GPL 兼容协议开源,CSS 和图片文件不需要开源,而随着 Gutenberg 编辑器的不断推广,以后的插件可能不太好“抄”了。

在这篇文章,我们不再讨论 Gutenberg 功能的研究,只谈插件的 PHP 部分。

如何理解 WordPress 的插件开发?

《人人都能学会的 WordPress 课程》当中,我曾经介绍过 WordPress 的插件的运行机制。如果现在用一个更加简单的说法来探讨这个问题的话,WordPress 是通过提供do_actionapply_filter这两个方法,实现了功能的可修改性。而插件则需要 add_actionadd_filter 这个方法来影响 WordPress 的运行表现

75b49d4621ffc8bf01cedf88d0855a01

当你明白这个问题之后,你就会意识到,如果我们需要解析一个插件的运行机制,来开发自己的同类型插件之时,唯一要做的其实就是找到对应的 Action 和 Filter,修改 WordPress 的运行表现。

因此,你接下来要做的事情就变得简单很多,你需要做的,仅仅是在插件的代码中搜索所有的 add_actionadd_filter,并记录下对应的 action 和 filter 的名字,在 Code Reference 当中搜索对应的 action 的应用场景和用法即可。

Tips

  1. 按照 WordPress 的开发规范,插件的目录中一定有一个和其目录名相同的 PHP 文件,这个文件是 WordPress 插件的入口文件,你只需要从这个插件看起,就能找到你想要了解的实现方式。
  2. WordPress 插件的代码都可以在 WordPress Directory 中找到,你只需要在 Development 目录中,就可以找到对应的插件的源码。
d2b5ca33bd970f64a6301fa75ae2eb22 32

如何从 WordPress 插件目录下架一个插件

silver mercedes benz emblem on blue surface

我在 WordPress 官方上架了不少的插件,但不少的插件如今我已经不再维护了。

再加上现在我开始重新调整 WPStore,因此,决定下架其中一些不再维护的插件,减少 WordPress 官方插件系统中的无用插件。

操作步骤

1. 登陆你的 WordPress.org 的账号,并找到你要下架的插件

d2b5ca33bd970f64a6301fa75ae2eb22 28

比如,我这里希望下架早年为 Payjs 写的付费阅读插件。

2. 点击 右下角的 Advanced View

d2b5ca33bd970f64a6301fa75ae2eb22 29

在 Details 页面找到 Advanced View 的连接,并点击进入 Advanced View 页面。

3. 在 THE DANGER ZONE 中关闭插件

d2b5ca33bd970f64a6301fa75ae2eb22 30

进入 Advanced View 页面之后,向下拖动,在底部的 THE DANGER ZONE 中可以找到 「Close This Plugin」,点击按钮,并在弹出的窗口中,点击确认即可。

4. 删除完成

d2b5ca33bd970f64a6301fa75ae2eb22 31

当你看到如上界面时,就说明你这个插件已经完全关闭了。

总结

其实 WordPress 并没有要求你关闭掉每一个插件,不过从插件的维护角度来看,关闭一个不再维护的插件可以减少你后续的服务的成本,也是一个不错的选择。

WordPress 官方的 Code Reference应该如何使用?

silver mercedes benz emblem on blue surface

如果你要开发 WordPress ,必然会用到 WordPress 官方的文档。而在官方文档当中,除了各种 Handbook ,最重要便是 Code Reference

在使用 Code Reference 的时候,也是存在一些技巧的。

搜索你需要的函数、Hooks、Filter、Class

访问 Code Reference 主页,可以看到有一个搜索框,在这里你可以输入你要搜索的关键词,并在下拉框中筛选出你要用的具体的函数/Hooks/Filter/Class

d2b5ca33bd970f64a6301fa75ae2eb22 20

当然,如果你在开发过程中,明确了你要查询的某个特定的函数,也有一个简单的方式来查询,只需要将下方的链接中的 FUNCTIONNAME 替换为你要查询的函数名,就可以直接跳转到对应的函数的详细界面,查看对应的函数的功能。

https://developer.wordpress.org/reference/functions/FUNCTIONNAME/
Code language: JavaScript (javascript)

如果你查询的是 Hooks、Filter 也有类似的方法,WordPress 的单个函数/Hooks/Filter 的URL非常的明确,因此,你可以在写代码的时候,随时把你需要查询的函数直接复制出来,替换浏览器地址栏中的方法名即可。

理解 Code Reference 的内容

download_url 为例,在 Code Reference 当中,大体上会分为以下几个区域

Description
Parameters
Return
Source
Related
 - Uses
 - Used By
Changelog
User Contributed Notes
 - Feedback
Code language: PHP (php)

Description

d2b5ca33bd970f64a6301fa75ae2eb22 21

这里介绍了这个函数的基本介绍,一些时候,也会在这个区域加入一些使用的 Tips。

不过这个描述并非每一个函数都会有。

Parameters

d2b5ca33bd970f64a6301fa75ae2eb22 22

参数区域说明了这个函数的入参有哪些,你可以对着入参的介绍调用函数,从而避免传入错误的参数

Return

d2b5ca33bd970f64a6301fa75ae2eb22 23

返回值定义了具体的返回值,你可以根据返回值来判断具体的结果。不仅如此,点击里面的链接,可以跳转到对应的类,查看对应返回结果的类型。

Source

d2b5ca33bd970f64a6301fa75ae2eb22 24

Source 部分则给你了函数的具体的代码,对于一些你在开发过程中百思不得其解的函数,读一下这个函数的源码可能会让你茅塞顿开。

对于比较长的函数,点击 Expand 就可以展开看。如果你希望在本地看,左上角也告诉你了这个函数在具体哪个文件可以查看。你可以直接按图索骥,找到本地的对应函数来查看。

Related

d2b5ca33bd970f64a6301fa75ae2eb22 25

Related 当中分为两个区块,分别是 Uses 和 Used By ,分别介绍当前这个函数是基于哪些函数实现的(Uses)和其他哪些函数使用了当前这个函数(Used By)

有了 Uses 和 Used By,你就可以自己封装一个类似的函数,也可以看看其他的函数是如何调用当前这个函数,心中更有数。

Changelog

d2b5ca33bd970f64a6301fa75ae2eb22 26

Changelog 当中记录了这个函数的具体的变更历史,你就可以非常方便的去了解到一个函数的发展历史,可能某个功能你过去用的好好的,最近不能用了,就是因为函数发生了更新。

User Contributed Notes

d2b5ca33bd970f64a6301fa75ae2eb22 27

在 User Contributed Notes 当中,记录了别人对于这个函数使用的反馈,你可以看到其他开发者是如何使用这个函数的。当你在使用这个函数/Hook出现问题时,就可以参考一下其他人贡献的笔记,可能会更好的帮助你来理解这些 Notes。

总结

用好 WordPress 自带的 Code Reference 可以帮助大家更好的开发 WordPress 的各种功能,花点时间了解一下 Code Reference ,相信可以帮到你~

Gutenberg 编辑器带来的模式变更

silver mercedes benz emblem on blue surface

自 WordPress 5.0 开始, Gutenberg 编辑器(后文称为古腾堡编辑器)开始存在于 WordPress 当中,为普通用户所用。而得益于古腾堡编辑器带来的卓越的使用体验(用户不需要再记录晦涩难懂的短代码、无须忍受 TinyMCE 的界面),用户使用 WordPress 的方式也开始变得多种多样。

如果你还没有用过古腾堡编辑器,那你可以访问 WordPress 官方提供的在线预览工具来试用:https://wordpress.org/gutenberg/

体验的变革

古腾堡的出现,让作者可以更加接近于我一直描述的 WordPress 所能够提供的最大的价值 —— 让写作变得更加简单,易实现。不仅如此,古腾堡带来的新的编辑体验,让除了工程师、Geek 以外的人也可以很轻松的实现一个更好看、更易读、更加丰富的界面。

而从 WordPress 开发团队的态度来看,也是更加推荐作者们更多的使用古腾堡编辑器:从Twenty Nineteen 开始,古腾堡的支持就成为了默认,并不断的通过官方主题的用法,让作者们看到 WordPress 原来还可以是这样。今年的 Twenty Twenty Two 更是从写作者变为了艺术家 —— 你可以十分简单的建造一个线上的画廊。

开发模式的变更

过去,WordPress 开发整体来说,可以分为两条线:一条是主题开发,你需要与 PHP、HTML、CSS、Javascript 共同战斗;另一条线则是插件开发,你需要与PHP 为伍。

搞插件开发的,你对于前端开发不甚了解也无所谓。WordPress 提供了大量的 helper function 。比如,我在「开发一个短代码插件」中,不使用一行前端代码就实现了 TinyMCE 的功能新增。

而在新的古腾堡编辑器生态下,开发者如果希望对于古腾堡进行拓展,一方面依然可以使用之前的方式,接入各种短代码来实现各种不同的用户体验,另一方面,则可以借助与前端技术栈来实现一个更加丰富的用户体验。

你可以使用 JQuery 和 WordPress 为你绑定的全局对象来修改古腾堡编辑器实现你的目标,更是可以借助前端的开发体系,诸如 Webpack、React 来开发一个强交互,体验佳的用户体验。

WordPress 的开发不再是 PHP 工程师自己的事情,它将更多的人卷入 WordPress 的开发过程中。而对于 WordPress 开发工程师来说,则有了更高的要求,来完成插件的开发、主题的开发。

总结

自古腾堡的推出,这样的趋势就开始渐显。但直到我真正开始开发一款古腾堡插件,我才真正意识到 —— WordPress 在内容创作领域的价值,无可替代。纵然他有众多的历史包袱,但对于每一个创作者来说,他都是最好的选择。