解决因为 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)

在 WordPress 的 Docker 镜像上加装 Redis 拓展,以支持 Redis 缓存

docker

从 LAMP 到 Docker based PaaS 工具 当中,我提到我现在使用的是 Docker Based PaaS 产品来托管站点。本站目前其实就是跑在 Docker 上的。

使用默认的 WordPress 镜像时,我发现一个问题:没有支持 Redis 拓展!我使用 Redis 来缓存 Query,提升访问的性能。如果缺失了 Redis 拓展,就会减少一部分缓存的能力。于是开始研究如何在官方的 WordPress 镜像上加入 Redis 拓展。

根据 WordPress 镜像的官方说明,我们可以 docker-php-ext-* 命令来配置镜像,安装必要的拓展,来满足我们日常使用的需求,并给出了官方的参考。

不过,我在验证 Redis 拓展时,使用 docker-php-ext-* 命令没有配置成功,好在可以使用 pecl 来安装。于是,我便将 Dockerfile 修改成如下内容,来完成对于 Redis 拓展的安装。

FROM wordpress:latest
RUN pecl install -o -f redis && rm -rf /tmp/pear && docker-php-ext-enable redis

修改好 Dockerfile ,然后重新启动,一切都好了~

d2b5ca33bd970f64a6301fa75ae2eb22 4

插件多次加载导致的 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

写博客, 工具重要么?

person typing on laptop computer

我写了快 10 年的博客,近 1000 篇,勉强算得上是个老人了,今天看到 Pin 的文章提到《只要用得習慣的都是好工具?》,刚好聊聊我自己的看法。

我从一开始使用 WordPress 写博客,再到后面折腾 Ghost、Typecho、EMlog、B3log、Hexo、Hugo 等一系列博客程序,一直到后来坚持在 WordPress 这个平台上持续写作。确实是有我自己的考量的。

对于我来说,确实不太需要工具来帮助我更好的产生一篇博客 —— 因为我满脑子都是灵感。但另一方面,我也认可工具是非常重要的 —— 就像我为什么现在坚持使用 WordPress 。

WordPress 作为动态程序,可以让我无时无刻的在任何一台电脑上写作 —— 我不只在 macOS 上写博客,还会在手机上写。而这些是 Hexo、Hugo 之类的产品无法做到的。

动态博客的 WordPress 释放了我写作的生产力,让我可以源源不断的产生灵感、记下灵感,并转变成文章。

另一方面,WordPress 的丰富的插件系统,也让我能够更好的写作:如果你细心,可能会注意到,今年我的博客几乎都有了题图 —— 主要得益于一个 WordPress 插件 Instant Images,让我可以直接在 WordPress 中搜索无版权图片作为头图。再配合上 USS Upyun 这个插件,来将我的图片放在对象存储上。

d2b5ca33bd970f64a6301fa75ae2eb22 6

当贴图变得简单了以后,自然也就愿意在文章当中给我的读者以更加丰富的形式。

你说工具不重要么?我不这么觉得。

当你不知道你想要什么的时候,工具或许是不重要,因为反正你没明确方向,效率并不重要。但当你明确了你想要什么的时候,工具就变得十分重要了。

为你的 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

什么是我眼中好的开发者产品的文档?(一)

b29692084bbb

我自己作为开发者使用过很多的开发产品,也看过不少的文档。最近频繁受邀针对不同的产品的文档提出建议,单独写这样一篇文章来说明一下我觉得什么是好的文档。一方面,可以帮助更多的开发者产品变得更好,另一方面,也可以用于自省,我自己在设计产品时是否会有类似的问题。

不过也需要注意,这篇文档仅涉及 「Guide」和「API Documentation」的部分,对于更多的 Changelog、Example、Tools 、 SDK 则没有涉及,这部分留待后续再写。

本文当中参考了包括:Notion 开发者文档微信小程序开发者文档声网 Agora 开发者文档WordPress 开发者文档飞书开发者文档等开发者产品。

API Documentation vs Guide

其实不少的产品文档写的都是 API Reference ,而不是 Guide,二者在实际的使用意义上是有所不同的。

  • Guide 帮助开发者快速上手一件事,从 0 开始,完成一件事。这是「用户视角」
  • API Reference 则是告诉开发者你能使用我的产品做什么事情。这是「平台视角」

一个好的文档应该是二者兼备的,这样才能一方面降低开发者的进入门槛(Guide 负责),另一方面, 可以让开发者可以知晓能力的范畴,帮助开发者尽可能拓展的应用边界,创造出美好的体验和新的世界。

一个好的 Guide 应该是什么样的?

这里我们以 Notion 的文档为例:

1. 一个好的 Guide 应该尽可能的显眼 & 好找

作为一个新的开发者,进入一个新的开发者平台时时迷茫的:“我应该做什么?”、“我应该看什么?“

这时一个明确的「Guide」、「Get started」可以帮助我们快速找到一个开始的锚点,这个锚点会成为开发者在这个平台中开始进行的下一步。

d2b5ca33bd970f64a6301fa75ae2eb22 11
Notion 开发者文档首页中 Guides 的入口
d2b5ca33bd970f64a6301fa75ae2eb22 12
微信小程序开发者文档中的指南的入口

2. 一个好的 Guide 应该有明确的步骤描述 & TOC

开发者在进入一个新的平台时,需要的是「快速跑完流程,以熟悉平台的各项基本功能」,而不是需要了解到所有的能力(如果开发者已经非常熟悉你的产品,其实根本不会看 Guide,直接去对应的 API Documentation 查看实现了)。

一个明确的步骤描述和 TOC 可以帮助开发者降低心理压力,并让用户找到自己所在的位置,进行下一步的推进。步骤的名称也非常的重要,一个清晰明确的步骤,可以帮助开发者快速明确自己要做什么事情,不会产生疑惑。

d2b5ca33bd970f64a6301fa75ae2eb22 13
Notion 文档当中对于步骤描述
d2b5ca33bd970f64a6301fa75ae2eb22 16
声网文档中关于步骤的描述

此外,也需要注意,步骤不建议太多,可以移除掉那些非核心的步骤,重要的是帮助用户跑通开发流程

3. 一个好的 Guide 应该是场景相关的

开发者在使用产品进行产品开发时,会有明确的预期,我要做什么事情。但产品需求和平台的能力是不同的。我们很难将产品需求和平台能力直接挂钩,这时就需要开发者盲人摸象般在整个平台上搜索和查看,找到适合自己的文档。这个时候,如果有一个场景相关的 Guide,可以帮助开发者快速找到适合自己的场景,并进行文档的细分。

在这些文档中,你的目的是帮助开发者快速了解在你平台上某个方向的能力、核心概念和如何组合你所提供的能力,帮助开发者快速实现自己的业务诉求。

d2b5ca33bd970f64a6301fa75ae2eb22 15
Notion 文档中的场景化文档
d2b5ca33bd970f64a6301fa75ae2eb22 18
微信开发者平台的场景化介绍

一个好的 API Documentation 应该是什么样的?

如果说 Guide 是开发者进入一个平台的时候最基础的教程文档。API Documentation 则是一个开发平台中最为核心的部分了,开发者每天都需要与 API Documentation 打交道,以完成一项工作,如果 API Documentation 做的不好,那对于开发者来说,简直就是一个灾难。

1. 一个好的 API Documentation 应该是组织合理的

API Documentation 当中往往包含了大量的信息,那么合理的拆分不同的 API 的模块,可以帮助开发者无需遍历所有的 API ,而是直接按照模块逐级查找自己所需的 API 即可,可以有效的提升查找的效率。

d2b5ca33bd970f64a6301fa75ae2eb22 19
Notion 文档当中按照业务模块拆分的 API Documentation

2. 一个好的 API Documentation 应该具备所涉及到的各项数据结构的说明

对于复杂的 API 接口来说,参数/返回值往往不仅仅是一个简单的 Integer 、String ,还会涉及到一些更加复杂的结构化数据的定义。

一种选择是将这种复杂的结构化数据抽象出来,成为一个新的类型;另一种选择是每次都解释一遍。显然,根据软件工程的 “DRY” 原则,我们应当将其抽象出来。在将对应的数据结构抽象出来后,需要注意的是,将其放在一个明确的位置进行展示和说明。原则上,这些结构的说明应该先于具体的接口说明。

d2b5ca33bd970f64a6301fa75ae2eb22 20
Notion 文档中的 Database Object 的位置说明
d2b5ca33bd970f64a6301fa75ae2eb22 21
WordPress 文档中关于返回类的定义描述
d2b5ca33bd970f64a6301fa75ae2eb22 22
WordPress 中在返回值中说明的错误类的入口

3. 一个好的 API Documentation 应该提供相应的 Sample Code

对于开发者来说,Talk is cheap, show me code。而在开发领域也是同样的。你提供的 Sample Code (甚至是在线的调用测试),都可以帮助开发者更好的理解相关的能力和开发逻辑。

所有的细节,都在 Sample Code 中一览无余。

d2b5ca33bd970f64a6301fa75ae2eb22 23
Notion API Documentation 中生成代码的部分

4. 一个好的 API Documentation 应该可以提供上下游关系

在 WordPress 文档中,有一个我非常喜欢的功能就是 Related 。Related 内部分为 Uses Used By,分别介绍了某个函数都是用了哪些函数来完成自己的功能和哪些函数使用本函数完成自己的功能。

d2b5ca33bd970f64a6301fa75ae2eb22 24
WordPress 文档中 Related 的部分说明
d2b5ca33bd970f64a6301fa75ae2eb22 28
声网文档中关于 API 上下游的描述

伴随着 Uses 还提供了这个函数的源码(不过这个对于平台类型的产品不能直接照抄),这样我可以非常清晰的参考这个函数的 Uses 和源码,以了解这个函数是如何实现自己的功能的。这样当我需要的时候,就可以非常方便的基于这个函数,改造出一个我自己使用的函数。

而 Used By ,则提供了其他的函数是如何使用这个函数的。对于一些我比较陌生的函数,可以直接参考其他函数的用法。从某种意义上来看,这是比测试用例更加全面的用法的说明,因为这是在“生产环境”下的用法。

我们在开源世界如果没有文档,会看测试用例,那么在 WordPress 当中,我会看的是 Used By。

5. 一个好的 API Documentation 可以提供用户之间的沟通渠道

我在 WordPress 开发者文档当中,还会常用到的一个功能是 —— User Contributed Notes。这个功能为开发者提供了一个基于函数的共建笔记。开发者可以自发的在其中撰写自己针对这个函数的开发经验。

d2b5ca33bd970f64a6301fa75ae2eb22 25
WordPress 文档中 User Contributed Notes

当我在不知道某个函数应该怎么使用的时候,我往往会去 User Contributed Notes 去找找看,看看别人是如何使用某一个函数的。官方的文档往往无法跳出「我有什么」的思路,而用户的共建笔记则可以共享出开发者使用某个函数的「奇技淫巧」。这些「奇技淫巧」让开发者的产品显得与众不同,也可以进一步的扩大产品的范畴。

总结

一个好的开发者产品文档是什么样的我很难定义,但至少上述的这些点,确实让我使用这些平台的产品在开发应用和业务的时候变得更加坚定。希望我的这些笔记,可以帮助到你,让你也可以涉及出一个好的开发者文档。

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 一个表单

在项目中使用 Dead Simple LESS CSS Watch Compiler 来自动生成 css 文件

9a1f326b911de6c1629837f3b57551e5 1

最近在写一个 WordPress 主题来帮助我完成从 WordPress 到微信公众号的实现。在这个过程中,我需要借助于一些 CSS 的超集,来帮助我完成样式的编写。考虑到 SCSS 的 C++ 依赖问题,我选择了 Less 来完成。但如果直接使用 lessc 的话,主要面临的问题在于无法检测文件更新,这样对于需要实时查看效果的我来说,是比较麻烦的。所以我选择使用 Dead Simple LESS CSS Watch Compiler 来完成自动监控文件变化并刷新的功能。

教程

安装

执行 npm 命令来安装 Dead Simple LESS CSS Watch Compiler

yarn global add less less-watch-compiler 

安装完成后,你就可以执行命令来监听文件的变化。

配置

这里为了方便,我在 WordPress 插件目录中初始化了 npm, 因此,可以非常方便的借助于 npm script 来完成命令的配置。

通过配置了单独的 Build 命令,实现了执行 npm run build 就会自动监听 less 文件夹下的文件,并转换成对应的 css 文件,放置在 css 目录中。

{
  "private": true,
  "scripts": {
    "build": "less-watch-compiler ./less ./css"
  },
  "devDependencies": {
    "less": "^4.1.2",
    "less-watch-compiler": "^1.16.3"
  }
}
Code language: JSON / JSON with Comments (json)

其他

如果你需要对 less 运行有更多配置的诉求,还可以创建一个 less-watch-compiler.config.json 来配置具体的执行目录。不过我对于这部分没有要求,就直接整个目录来进行配置了。

{
    "watchFolder": "<input_folder>",   
    "outputFolder": "<output_folder>",
    "mainFile": "<main-file>",   
    "includeHidden": false,
    "sourceMap": false,
    "plugins": "plugin1,plugin2",
    "lessArgs": "option1=1,option2=2",
    "runOnce": false,
    "enableJs": true
}

总结

SCSS 因为 node-scss 的编译问题被各种吐槽,虽然换成了 dart-scss ,但历史的阴影还在。选择了 less 后,通过一些配置,可以让我自己的开发变得更加简单。何乐而不为?

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)

在 Pug 中实现类似 get_sidebar() 全局方法

javascript

在开发 WordPress 主题时,我们会用到一些全局方法,来帮助我们快速加载特定的区域的代码。如果我们在设计和开发主题的时候,也可以实现类似的功能,则在开发对应的页面和应用的时候,我们就可以根据自己的需求来进行特定区域的代码的封装。这样我们在进行后续的开发的时候,就可以简化自己的代码,同时还可以按照 WordPress 的规范提前拆分代码,在实际进行项目开发的时候,提升效率。

原理

本次实现主要是基于 Pug 自带的 Mixins 机制来实现在主题中提供自定义的函数,从而实现我们想要的内容。在原理上,和 WordPress 的 get_sidebar 之类的方法不完全一样。所以,在体验上还没有做到像 WordPress 那么方便。

实现方式

1. 创建 Mixins

在项目的根目录下创建一个 mixins 目录,并在其中创建一个 includes.pug 文件和一个 getHeader.pug 文件。

includes.pug 文件中添加如下代码

include getHeader
Code language: PHP (php)

getHeader.pug 文件中添加如下代码

mixin getHeader
    p header

2. 引入 includes.pug

在你的 layouts.pug 文件中加入 includes.pug 的引入。需要注意的是,要加在 doctype 之前。

include ../mixins/includes
doctype html
html
  head
Code language: PHP (php)

3. 在需要的地方调用

当你完成上述的配置后,即可在需要的地方进行调用。

extends layout

block content
  +getHeader
  h1= title
  p hi to #{title}
Code language: PHP (php)

调用的效果如下:

d2b5ca33bd970f64a6301fa75ae2eb22 39

如果你希望实现更加强大的功能(比如参数),可以参考 Pug 官网的 Mixins 页面。

在开发 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)

针对 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

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

使用 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 的账号密码,但却可以完成插件的发布,十分方便。