(本文最初由Torque Magazine发表,经许可转载。)
近年来,笔者在Torque杂志上撰写了大量关于面向对象PHP和WordPress REST API的文章,也涉及到使用Composer进行依赖管理和自动加载,以及单元测试。所有文章的核心观点是:通过将已建立的软件开发最佳实践应用到WordPress开发中,我们可以创建更好的插件。
这是一系列文章中的第一篇,它将在一个实际的、功能性的示例中整合这些概念。我将逐步讲解如何创建一个WordPress插件来修改WordPress REST API端点的功能,以便更好地优化搜索。该插件可在GitHub上找到。您可能需要浏览提交日志以了解我的构建过程。
在本系列文章中,我将介绍如何使用现代面向对象PHP构建插件和类,以及如何使其可测试,以及如何为其编写自动化测试。我将介绍单元测试、集成测试和验收测试之间的区别,并向您展示如何编写和自动化运行每种类型的测试。本文首先介绍如何使用面向对象的方法使用过滤器修改WordPress REST API。
关键要点
post_type
,从而实现更灵活和强大的搜索功能。使用REST API改进WordPress搜索
通常使用SearchWP或Relevansi之类的插件,或与ElasticSearch(一种使用与WordPress完全不同的堆栈的技术)集成(使用Jetpack或ElasticPress),来改进WordPress搜索。这些类型的插件提供更好的搜索结果,并且通常与多方面搜索界面配合使用,这对于电子商务应用程序非常有用。
通过WordPress REST API进行搜索继承了所有这些相同的问题和相同的解决方案。在这篇文章中,我将首先介绍搜索的默认工作方式以及其局限性。然后,我们将研究如何使用两种不同的方法修改搜索并与SearchWP集成。
WordPress内置的搜索功能通常需要使用外部服务来改进。虽然本文是关于修改WordPress REST API帖子路由工作方式的面向对象方法,但实际示例将是改进搜索。
当WordPress用作解耦前端(例如原生移动应用程序或Web应用程序,可能使用Vue、React或Angular构建)的后端时,通过REST API进行高质量搜索非常重要。本文介绍的代码将有助于您,如果您的应用程序用户需要查找正确的产品变体或根据基于多个分类法的复杂算法搜索内容,并且您正在编写自定义代码,而不仅仅是安装插件。
使用WordPress REST API搜索帖子
如果您想在一个站点上搜索所有帖子类型为“product”的帖子,使用搜索词“Taco Shirts”,您将向/wp/v2/product?s=Taco Shirt
端点发出请求。如果您想提高结果的质量,上面列出的解决方案将有所帮助。
如上所述,WP_Query(WordPress REST API的帖子端点使用的东西)并不是一个很好的搜索工具。更具体地说,WP_Query可能由于其对MySQL的依赖性,不如那些倾向于使用NoSQL数据库构建的专用搜索工具。
首先,让我们看看如何在进行REST API请求时绕过WP_Query与WordPress数据库的交互。
这是许多搜索插件用来替换其自身搜索系统结果(对于WP_Query默认生成的)的策略。搜索系统可以使用相同的数据库。它也可以连接到其他数据库,可能通过API请求,例如到ElasticSearch或Apache Solr服务器。
如果您查看WordPress核心代码,您会发现过滤器“posts_pre_query”在WP_Query查询数据库之前运行,但在SQL查询准备之后运行。此过滤器默认返回null。如果该值为null,WordPress将继续其默认行为:查询WordPress数据库并将结果作为简单的WP_Post对象数组返回。
另一方面,如果此过滤器的返回值是一个数组(希望包含WP_Post对象),则不使用WordPress的默认行为。
让我们看看如何使用posts_pre_query返回一个模拟WP_Post。此策略对于测试非常有用,但相同模式的更复杂版本可用于将单独的数据库与您的WordPress站点集成:
// ... (代码示例与原文相同) ...
在此示例中,我们使用的是模拟数据,但我们可以使用SearchWP的查询类或其他任何东西。关于这段代码需要注意的另一件事是,它将在任何WP_Query上运行,而不仅仅是WordPress REST API创建的WP_Query对象。让我们对其进行修改,以便除非它是WordPress REST API请求,否则我们不使用过滤器:
// ... (代码示例与原文相同) ...
修改WordPress REST API端点参数
我们刚刚研究了如何更改WordPress REST API请求的搜索结果生成方式。这允许我们优化查询以获得更好的搜索效果,但它可能会暴露出对端点不同模式的需求。
例如,如果您希望允许对产品端点的搜索可选地允许将其他帖子类型包含在搜索中,我去年介绍了另一种解决同一问题的方法。
横切关注点
我们即将研究如何修改允许的端点参数以及如何使用它们来创建WP_Query参数。这是两个单独的关注点,单一职责原则指出我们需要为每个关注点创建一个类。但是这两个类将具有共享的关注点。
例如,如果我们想允许按不同的帖子类型进行查询,我们需要知道哪些是公共帖子类型,以及它们的slug和rest_base参数是什么。所有这些信息都可以从函数get_post_types中获得。
该函数的输出并不完全是我们需要的。因此,让我们设计一个类来根据我刚才列出的需求格式化数据,并为我们提供访问它的辅助方法。
将其视为所有我们需要在可用容器中使用的帖子类型数据的通用形状:
// ... (代码示例与原文相同) ...
请注意,我们没有在类中调用get_post_types(),而是将其用作依赖项,通过构造函数注入。因此,此类可以在不加载WordPress的情况下进行测试。
这就是为什么我会将此类描述为“单元可测试”的原因。它不依赖于任何其他API,我们也不担心副作用。我们可以将其作为一个单独的、隔离的单元进行测试。将关注点分离并将其功能隔离成小的部分,一旦我们有了单元测试覆盖率,就可以使代码易于维护。我将在我的下一篇文章中介绍如何测试这种类型的类。
请记住,此类确实依赖于WP_Post_Type。我的单元测试将没有定义该类,因为只有集成测试才可以使用WordPress或任何其他外部依赖项。该类仅用于表示数据,而不是执行任何操作。因此,我们可以说它的使用不会产生任何副作用。因此,我很乐意在单元测试中使用模拟来代替真实的WP_Post_Type。
说到依赖注入,那些需要此新类的对象的类,我们想遵循相同的模式。我们不会在需要它们的类中实例化PreparedPostTypes,而是传入一个实例。这意味着使用PreparedPostTypes和PreparedPostType的类保持隔离,并且可以单独测试。
它还可以导致代码重用,因为我们必须使依赖注入成为可能,并为此对象设置一个属性。我们可以使用剪切和粘贴,或者我们可以使用PHP Trait,这是一种更高级、更可扩展的方法,用于在类之间复制方法和属性。
这是一个Trait,它建立了将PreparedPostTypes对象注入其他类的模式:
// ... (代码示例与原文相同) ...
我们的另一个关注点是,我们需要在多个地方了解帖子类型的一些信息。例如帖子类型的slug。这与之前的横切关注点略有不同。我们解决的最后一个问题涉及动态数据。现在我们只需要在一个地方更改我们在多个地方使用的字符串即可。
一个具有类常量的类为我们简单地解决了这个问题:
// ... (代码示例与原文相同) ...
现在我们可以使这些字符串在整个代码中保持一致。这似乎是不必要的步骤。但是我的示例代码适用于帖子帖子类型。如果您想更改使用的帖子类型,则此类需要更改,而无需更改其他任何内容。这是遵循Tom McFarlin在他撰写“一个类应该只有一个更改原因”时对单一职责原则的首选定义。
修改REST API端点模式
现在我们需要修改帖子类型端点的模式。通过这样做,WordPress将向REST API端点传达帖子类型参数是允许的,并且在解析请求时,允许新的端点参数。
这是我们的类,用于添加post_type属性。请注意,它使用了我们刚才讨论过的trait UsesPreparedPostTypes:
// ... (代码示例与原文相同) ...
在此属性的设置中,我们告诉WordPress此属性是一个数组属性,我们使用数组的“enum”索引指定允许的值。
在“enum”中,我们枚举允许的值。在这种情况下,PreparedPostTypes类提供了允许值的数组,因为这是一个先前解决的横切关注点。
请注意,此类没有与任何帖子类型甚至此特定用例耦合。我们将很快回到使用哪些钩子来使此类适用于特定帖子类型。
修改REST API WP_Query参数
上一节介绍了如何使新的端点属性post_type可用。这实际上并没有更改WordPress REST API生成的WP_Query参数。除了最后一个过滤器之外,我们已经拥有所需的一切。
帖子类型是核心代码专门不允许通过REST API请求更改的一个WP_Query参数。我们有一个动态命名的过滤器——rest_{$post_type}_query——可以覆盖任何WP_Query参数。
这是我们的类,它注入我们的post_type参数,这些参数以前是不允许的:
// ... (代码示例与原文相同) ...
大部分内容只是验证我们是否应该进行更改,然后使用WP_Rest_Request的get_param方法从请求中获取值。大部分是自动的,因为我们首先修改模式以匹配。
修改WordPress REST API请求的WP_Query对象
我已经在本文的第一部分介绍了如何做到这一点。这是一个实现相同模式的类:
// ... (代码示例与原文相同) ...
我希望您注意到这段代码与WordPress紧密相关,并且不可测试。它使用来自WordPress的WP_Post,它正在检查WordPress的常量,并与WordPress的插件API交互。我们可以模拟WP_Post,并且我们可以自己设置常量。但是插件的API——这是需要测试的重要功能。在我的接下来的几篇文章中,我将介绍如何重构此类,以便我们可以使用单元测试来涵盖除删除该过滤器的效果之外的所有内容,并使用集成测试来检查该效果。
我选择使用静态方法有两个原因。首先,它使在多个位置添加和删除它变得很容易。例如,在ModifyQuery类中,我只在需要时才挂钩此过滤器:
// ... (代码示例与原文相同) ...
此外,在使用此过滤器时很容易创建递归循环。能够像在此示例代码中一样轻松地删除它非常不错。
我选择使用静态方法的另一个原因是该函数与其他API交互。它永远不会真正可进行单元测试。这种模式,一个具有静态方法的类,使得在集成测试中模拟该类变得非常容易,从而最大限度地减少了在这个系统的一个部分中缺乏强隔离的影响。
使所有内容协同工作
到目前为止,我们看到的代码与WordPress非常脱钩。这有很多好处。但这意味着它本身什么也不做。这很好。我们到目前为止只处理了业务逻辑需求。现在我们需要考虑集成。
这并不难,只需要添加一些钩子即可。哪些钩子?与我们为ModifyQuery和ModifySchema类设计的完全相同的两个钩子。对解耦业务逻辑的渴望并不意味着我们在设计其公共接口时不能考虑编写代码的实际原因。否则,我们只会毫无理由地为我们的代码增加额外的复杂性。
一般来说,我尽量只在它使生活更轻松时才增加软件复杂性。我过去偏离了这条道路。我们都有过,没关系,练习宽恕。
我们即将挂钩的类中的方法与钩子使用完全相同的参数和返回类型。它们的工作是将这些值分派给其他组件。
// ... (代码示例与原文相同) ...
下一步:测试
这已经足够接近了。它会起作用。由于缺乏添加钩子的正式系统,这是我们可以为初始化做的最好的事情。这很好。我将在未来关于WordPress集成测试的文章中介绍如何创建一个更复杂和可扩展的引导过程。
在这篇文章中,我们研究了创建代码来修改模式、WP_Query参数生成和帖子类型的底层WP_Query。我鼓励您将此代码转换为插件,使用Composer进行自动加载。在我的下一篇文章中,我们将研究单元测试以涵盖这些类。
(以下为原文FAQ部分,已根据原文内容进行伪原创)
关于WordPress中高级OOP和自定义REST API端点的常见问题解答
面向对象编程(OOP)在WordPress中的意义是什么?
面向对象编程(OOP)是一种使用“对象”设计应用程序和软件的编程范式。在WordPress环境中,OOP为开发复杂的应用程序提供了一种简洁、高效和健壮的方法。它允许开发人员将相关任务分组到类和对象中,使代码更易于阅读、重用和维护。OOP还通过封装数据并防止外部直接访问来增强应用程序的安全性。
如何在WordPress中自定义REST API端点?
WordPress REST API提供了一组用于不同类型数据的默认端点。但是,您可以自定义这些端点或创建新的端点以满足您的特定需求。这可以通过在您的插件或主题中使用register_rest_route()
函数来完成。此函数允许您指定端点的路由或URL,并定义它应该响应的方法(GET、POST等)。
自定义WordPress REST API端点的优势是什么?
自定义WordPress REST API端点允许您创建更高效、更灵活和更安全的应用程序。您可以调整端点返回的数据,减少通过网络发送的不必要数据量。您还可以创建执行特定任务的端点,例如处理表单提交或生成报告,从而使您的应用程序更具交互性和用户友好性。
OOP如何增强WordPress应用程序的安全性?
OOP通过将数据和方法封装在对象中来增强WordPress应用程序的安全性。这意味着对象的属性(数据)和方法(函数)对应用程序的其余部分隐藏,并且只能通过对象的方法访问。这可以防止未经授权访问和操作数据,从而降低安全漏洞的风险。
OOP可以与旧版本的WordPress一起使用吗?
是的,您可以将OOP与旧版本的WordPress一起使用。但是,需要注意的是,较新版本的WordPress对OOP的支持有所改进,并且包含许多功能,使使用此范式进行开发更容易。因此,虽然可以使用OOP与旧版本一起使用,但通常建议使用最新版本的WordPress以获得最佳的开发体验。
类和对象在OOP中的作用是什么?
在OOP中,类是创建对象的蓝图或模板。它定义了对象应该具有的属性(数据)和方法(函数)。另一方面,对象是类的实例。它具有自己的一组属性和方法,这些属性和方法可能与同一类的其他对象不同。类和对象的使用使代码更具组织性、可重用性和易于维护性。
如何在WordPress中创建一个新类?
您可以使用class
关键字,后跟类名和一组花括号{}
来在WordPress中创建一个新类。在括号内,您可以定义类的属性和方法。要创建类的对象,您可以使用new
关键字,后跟类名。
WordPress中的REST API是什么?
WordPress中的REST API是一个接口,允许您使用HTTP请求与WordPress站点交互。它为不同类型的数据(例如帖子、评论和用户)提供了一组端点,您可以使用标准HTTP方法(如GET、POST、PUT和DELETE)来访问这些端点。REST API使您可以更轻松地从外部应用程序创建、读取、更新和删除WordPress站点中的数据。
如何在WordPress中访问REST API?
您可以通过向相应的端点发送HTTP请求来访问WordPress中的REST API。每个端点对应于特定类型的数据,并支持某些HTTP方法。例如,要检索帖子列表,您可以向/wp/v2/posts
端点发送GET请求。REST API将以JSON格式返回数据,然后您可以在应用程序中处理和显示这些数据。
我可以将REST API与非WordPress应用程序一起使用吗?
是的,您可以将REST API与非WordPress应用程序一起使用。REST API是平台无关的,这意味着它可以与任何可以发送HTTP请求和处理JSON数据的应用程序一起使用。这使其成为将WordPress站点与其他应用程序(例如移动应用程序、桌面应用程序和其他Web服务)集成的强大工具。
以上是WordPress的高级OOP:自定义REST API端点的详细内容。更多信息请关注PHP中文网其他相关文章!