我相信,一个传统的WordPress主题应该能够像静态网站或无头网络应用一样有效地工作。绝大多数的WordPress网站都是用一个好的老式的WordPress主题建立的。他们中的大多数甚至有很好的缓存层,和依赖性优化,使这些网站运行得相当快。但是作为开发者,我们已经完成了为我们的网站创造更好结果的方法。使用无头的WordPress让许多网站有更快的加载速度,更好的用户互动,以及页面之间的无缝过渡。
问题是什么?维护。让我向你展示另一种可能性吧!
让我们首先定义一下我所说的 "传统 "WordPress、"无头 "WordPress,然后是 "近乎无头 "WordPress。
传统的WordPress网站
传统上,一个WordPress网站是用PHP来渲染页面上呈现的HTML标记的。每次点击一个链接,浏览器就会向服务器发送另一个请求,PHP就会渲染被点击的网站的HTML标记。
这是大多数网站使用的方法。它是最容易维护的,在技术上的复杂性最低,而且有合适的服务器端缓存工具,它可以表现得相当好。问题是,由于它是一个传统的网站,它感觉就像一个传统的网站。转场、效果和其他时尚、现代的功能往往在这种类型的网站中更难建立和维护。
优点
- 该网站易于维护。
- 技术相对简单。
- 与WordPress插件有很大的兼容性。
缺点
- 你的网站可能会觉得有点过时,因为社会期望在浏览器中获得类似应用程序的体验。
- 由于网站没有使用JavaScript框架来控制网站的行为,因此JavaScript的编写和维护往往会有点困难。
- 传统的网站往往比无头和接近无头的网站运行速度慢。
无头的WordPress网站
无头WordPress网站使用现代JavaScript和某种服务器端RESTful服务,如WordPress REST API或GraphQL。服务器不是在PHP中建立和渲染HTML,而是发送最小的HTML和一个大的JavaScript文件,可以处理渲染网站上的任何页面。这种方法加载页面的速度要快得多,并提供了在页面之间创建非常酷的过渡的机会,以及其他有趣的事情。
不管你怎么想,大多数无头的WordPress网站都需要一个开发人员来对网站进行任何重大改变。想安装一个表单插件?对不起,你可能需要一个开发人员来设置它。想安装一个新的SEO插件?不,需要一个开发人员来改变应用程序。想使用那个花哨的块吗?太糟糕了 - 你首先需要一个开发人员。
优点
- 网站本身会有现代感,而且速度快。
- 它很容易与WordPress之外的其他RESTful服务集成。
- 整个网站是用JavaScript建立的,这使它更容易建立复杂的网站。
缺点
- 你必须重新发明很多WordPress插件为你做的开箱即用的事情。
- 这种设置很难维护。
- 与其他选择相比,主机是复杂的,而且可能变得昂贵。
参见"WordPress和Jamstack",以深入比较WordPress和静态主机之间的差异。
我喜欢无头的WordPress所能创造的结果。我不喜欢维护。我想要的是一个网络应用程序,让我的网站有快速的加载速度,页面之间的过渡,以及整体上像应用程序的感觉。但我也希望能够自由使用使WordPress如此受欢迎的插件生态系统。我想要的是无头的东西。几乎是无头的。
我找不到任何符合这种描述的东西,所以我建了一个。从那时起,我已经建立了一些使用这种方法的网站,并建立了必要的JavaScript库,使其他人更容易创建他们自己的近乎无头的WordPress主题。
介绍近乎无头的WordPress
近乎无头的WordPress是一种网络开发方法,它为你提供了许多类似于无头方法的应用程序的好处,以及使用传统WordPress主题时的开发便利性。它通过一个小的JavaScript应用来实现这一点,该应用将处理路由并呈现你的网站,就像一个无头应用一样,但有一个后备功能,可以用一个正常的WordPress请求来加载完全相同的页面。你可以选择使用回退方法加载哪些页面,并且可以在JavaScript或PHP中注入逻辑,以确定是否应该像这样加载页面。
你可以在我建立的演示网站上看到这个方法的作用,以展示这个方法可以做什么。
例如,实施这种方法的网站之一使用了一个叫做LifterLMS的学习管理系统来在线销售WordPress课程。这个插件有内置的电子商务功能,并设置了托管和放置付费墙后面的课程内容所需的界面。这个网站使用了很多LifterLMS的内置功能来工作--其中的一个重要部分是结账车。我没有重新构建整个页面以在我的应用程序中工作,而是简单地将其设置为使用回退方法加载。正因为如此,这个页面像任何旧的WordPress主题一样工作,并且完全按照预期的结果工作--所有这些都不需要我重新建立任何东西。
优点
- 在设置时,这很容易维护。
- 托管和典型的WordPress主题一样简单。
- 网站感觉就像无头网站一样现代和快速。
缺点
- 你总是要考虑两种不同的方法来呈现你的网站。
- 对这种方法有效的JavaScript库的选择有限。
- 这个应用程序与WordPress紧密相连,所以使用第三方REST APIs比无头网站更困难。
它是如何工作的
要使某样东西接近无头化,它需要能够做几件事,包括
- 使用WordPress请求加载一个页面。
- 使用JavaScript加载一个页面。
- 允许页面是相同的,无论它们是如何呈现的。
- 提供一种方法来知道何时使用JavaScript或PHP加载页面,以及
- 确保所有路由的页面100%相同,无论它是用JavaScript还是PHP渲染的。
这使网站能够利用渐进式增强。由于该页面可以使用或不使用JavaScript,你可以根据提出的请求,使用最合理的版本。有一个受信任的机器人在抓取你的网站吗?向他们发送非JavaScript版本以确保兼容性。有一个结账页面没有达到预期的效果?现在强迫它在没有应用程序的情况下加载,也许以后会修复它。
为了完成这些项目,我发布了一个名为Nicholas的开源库,其中包括一个预制的模板。
保持干燥
在构建一个几乎无头的应用程序时,我想克服的最大问题是保持页面在PHP和JavaScript中的呈现方式的一致性。我不希望在两个不同的地方建立和维护我的标记--我希望尽可能多的标记有一个单一的来源。这立即限制了我可以实际使用的JavaScript库(对不起,React!)。经过一些研究和大量的实验,我最终使用了AlpineJS。这个库使我的代码保持合理的干燥。有一些部分绝对要为每个人重新编写(例如循环),但大多数重要的标记块都可以重复使用。
一个用PHP渲染的帖子模板可能看起来像这样的东西:
<?php
if ( have_posts() ) {
while ( have_posts() ) {
the_post();
if ( is_singular() ) {
echo nicholas()->templates()->get_template( 'index', 'post', [
'content' => Nicholas::get_buffer( 'the_content' ),
'title' => Nicholas::get_buffer( 'the_title' ),
] );
}
}
}
?>
同样的帖子模板用JavaScript渲染,使用Alpine:
<template x-for="(post, index) in $store.posts" :key="index">
<?= nicholas()->templates()->get_template( 'index', 'post' ) ?>
</template>
两者都使用相同的PHP模板,所以实际循环内的所有代码都是DRY的:
$title = $template->get_param( 'title', '' );
// Get the title that was passed into this template, fallback to empty string.
$content = $template->get_param( 'content', '' ); // Get the cotent passed into this template, fallback to empty string.
?>
<article x-data="theme.Post(index)">
<!-- This will use the alpine directive to render the title, or if it's in compatibility mode PHP will fill in the title directly -->
<h1 x-html="title"><?= $title ?></h1>
<!-- This will use the Alpine directive to render the post content, or if it's in compatibility mode, PHP will fill in the content directly -->
<div class="content" x-html="content"><?= $content ?></div>
</article>
相关的:这种Alpine.js方法在精神上与Jonathan Land的《如何在WordPress主题中构建Vue组件》中涉及的Vue.js方法相似。
检测一个页面何时应该在兼容模式下运行
"兼容模式 "允许你强制任何请求在没有运行无头版网站的JavaScript的情况下加载。当一个页面被设置为使用兼容模式加载时,该页面将只使用PHP加载,而应用程序脚本永远不会被排队。这使得那些不能按预期工作的 "问题页面 "可以在不需要重新编写的情况下运行。
有几种不同的方法可以强迫一个页面在兼容模式下运行--有些需要代码,有些不需要。尼古拉斯为任何帖子类型添加了一个开关,使其有可能强制帖子以兼容模式加载。

同时,你可以手动添加任何URL,强制它在Nicholas设置中以兼容模式加载。

这些都是一个很好的开始,但我发现,我通常可以根据一个帖子中存储的块来自动检测一个页面何时需要以兼容模式加载。例如,假设你的网站上安装了Ninja Forms,你想使用他们提供的验证JavaScript,而不是重新制作你自己的。在这种情况下,你必须在任何有Ninja Form的页面上强制执行兼容模式。你可以在需要时手动添加每个URL,或者你可以使用查询来获取页面上有Ninja Forms块的所有内容。就像这样。
add_filter( 'nicholas/compatibility_mode_urls', function ( $urls ) {
// Filter Ninja Forms Blocks
$filtered_urls = Nicholas::get_urls_for_query( [
'post_type' => 'any',
's' => 'wp:ninja-forms/form', // Find Ninja Forms Blocks
] );
return array_merge( $urls, $filtered_urls );
} );
这将自动把任何带有Ninja Forms块的页面添加到将使用兼容模式加载的URL列表中。这只是使用WP_Query 参数,所以你可以在这里传递任何你想要的东西来决定哪些内容应该被添加到列表中。
扩展应用程序
在引擎盖下,Nicholas使用一个轻量级的路由器,可以使用中间件模式进行扩展,就像Express应用程序处理中间件一样。当一个被点击的页面被路由时,系统会运行每个中间件项目,并最终路由该页面。默认情况下,路由器什么都不做;然而,它带有几个预制的中间件,允许你以你认为合适的方式组装路由器。
一个基本的例子是这样的:
// Import WordPress-specific middleware
import {
updateAdminBar,
validateAdminPage,
validateCompatibilityMode
} from 'nicholas-wp/middlewares'
// Import generic middleware
import {
addRouteActions,
handleClickMiddleware,
setupRouter,
validateMiddleware
} from "nicholas-router";
// Do these actions, in this order, when a page is routed.
addRouteActions(
// First, validate the URL
validateMiddleware,
// Validate this page is not an admin page
validateAdminPage,
// Validate this page doesn't require compatibility mode
validateCompatibilityMode,
// Then, we Update the Alpine store
updateStore,
// Maybe fetch comments, if enabled
fetchComments,
// Update the history
updateHistory,
// Maybe update the admin bar
updateAdminBar
)
// Set up the router. This also uses a middleware pattern.
setupRouter(
// Setup event listener for clicks
handleClickMiddleware
)
从这里,你可以扩展一个页面被路由时的情况。也许你想扫描页面的代码来突出显示,或者你想改变<head> 标签的内容来匹配新路由的页面。甚至可能引入一个缓存层。不管你需要做什么,添加所需的动作就像使用addRouteAction 或setupRouter 一样简单。