Home >CMS Tutorial >WordPress >Advanced OOP for WordPress: Customizing REST API Endpoints

Advanced OOP for WordPress: Customizing REST API Endpoints

William Shakespeare
William ShakespeareOriginal
2025-02-09 13:12:14550browse

Advanced OOP for WordPress: Customizing REST API Endpoints

(This article was originally published by Torque Magazine and reprinted with permission.)

In recent years, the author has written a lot of articles on object-oriented PHP and WordPress REST APIs in Torque magazine, which also involves using Composer for dependency management and automatic loading, as well as unit testing. The core point of all articles is: By applying established software development best practices to WordPress development, we can create better plugins.

This is the first in a series of articles that will integrate these concepts in a practical, functional example. I'll walk through how to create a WordPress plugin to modify the functionality of the WordPress REST API endpoint to better optimize searches. The plugin is available on GitHub. You may need to browse the commit log to understand my build process.

In this series, I will cover how to build plugins and classes using modern object-oriented PHP, and how to make it testable, and how to write automated tests for it. I'll cover the differences between unit testing, integration testing, and acceptance testing and show you how to write and automate each type of test. This article first introduces how to use an object-oriented method to modify the WordPress REST API using filters.

Key Points

  • Enhance WordPress REST API endpoints with object-oriented PHP for better search capabilities and integrate with advanced search tools such as ElasticSearch.
  • Modify the REST API endpoint parameters and WP_Query interaction to bypass the limitations of default WordPress searches and improve the response quality of complex queries.
  • Use unit testing, integration testing and acceptance testing for robust and easy-to-maintain code to ensure that each component runs correctly in the WordPress ecosystem.
  • Use dependency injection and PHP Traits to cleanly manage class dependencies, enabling easier maintenance and testing code.
  • Customize REST API endpoint mode to include additional parameters such as post_type, allowing for more flexible and powerful search capabilities.
  • Dynamically adjust the WP_Query parameters through specific REST API requests, and use filters to effectively refine search results and endpoint behavior.

Improving WordPress search with REST API

Usually use plugins like SearchWP or Relevansi, or integration with ElasticSearch (a technology that uses a completely different stack from WordPress) to improve WordPress search. These types of plugins provide better search results and are often used with a multifaceted search interface, which is very useful for e-commerce applications.

Search through WordPress REST API inherits all these same problems and the same solutions. In this post, I will first introduce how search works and its limitations. We will then look at how to modify searches and integrate with SearchWP using two different methods.

The built-in search functionality of WordPress usually requires improvement using external services. While this article is about an object-oriented approach to modifying how WordPress REST API post routing works, the actual example would be to improve search.

When WordPress is used as a backend for decoupling front-ends (such as native mobile applications or web applications, which may be built using Vue, React, or Angular), it is important to do high-quality search through the REST API. The code presented in this article will help you if your application users need to find the right product variant or search for content based on complex algorithms based on multiple taxonomy and you are writing custom code instead of just installing plugins .

Search posts using WordPress REST API

If you want to search for all posts with a post type of “product” on one site, use the search term “Taco Shirts” and you will make a request to the /wp/v2/product?s=Taco Shirt endpoint. If you want to improve the quality of your results, the solutions listed above will help.

As mentioned above, WP_Query (thing used by the post endpoint of the WordPress REST API) is not a good search tool. More specifically, WP_Query may be less likely than dedicated search tools that tend to be built using NoSQL databases due to its dependency on MySQL.

First, let's see how to bypass WP_Query's interaction with WordPress database when making REST API requests.

This is a strategy used by many search plugins to replace their own search system results (which are generated by default for WP_Query). The search system can use the same database. It can also connect to other databases, possibly via API requests, such as to ElasticSearch or Apache Solr servers.

If you look at WordPress core code, you will find that the filter "posts_pre_query" runs before the WP_Query query database, but after the SQL query is ready. This filter returns null by default. If the value is null, WordPress continues its default behavior: query the WordPress database and return the result as a simple array of WP_Post objects.

On the other hand, if the return value of this filter is an array (that would like to contain a WP_Post object), the default behavior of WordPress is not used.

Let's see how to use posts_pre_query to return a simulated WP_Post. This strategy is very useful for testing, but a more complex version of the same schema can be used to integrate a separate database with your WordPress site:

<code class="language-php">// ... (代码示例与原文相同) ...</code>

In this example, we are using mock data, but we can use SearchWP's query class or anything else. Another thing to note about this code is that it will run on any WP_Query, not just the WP_Query object created by the WordPress REST API. Let's modify it so that we don't use filters unless it's a WordPress REST API request:

<code class="language-php">// ... (代码示例与原文相同) ...</code>

Modify WordPress REST API endpoint parameters

We just looked at how to change the search results generated for WordPress REST API requests. This allows us to optimize the query for better search results, but it may expose the need for different patterns of the endpoint.

For example, if you want to allow searches for product endpoints optionally allow other post types to be included in the search, I introduced another solution to the same problem last year.

Horizontal focus

We are about to look at how to modify allowed endpoint parameters and how to use them to create WP_Query parameters. These are two separate concerns, and the single responsibility principle states that we need to create a class for each concern. But these two classes will have shared concerns.

For example, if we want to allow querying by different post types, we need to know which public post types are, and what their slug and rest_base parameters are. All this information is available from the function get_post_types.

The output of this function is not exactly what we need. So let's design a class to format the data according to the requirements I just listed and provide us with a helper way to access it.

Think of it as a common shape for all post type data we need to use in available containers:

<code class="language-php">// ... (代码示例与原文相同) ...</code>

Note that instead of calling get_post_types() in the class, we use it as a dependency, injected through the constructor. Therefore, this class can be tested without loading WordPress.

This is why I describe this kind as "unit-testable". It doesn't rely on any other API, and we don't worry about side effects. We can test it as a separate, isolated unit. Separate the focus and isolate its functionality into small parts, and once we have unit test coverage, we can make the code easy to maintain. I'll cover how to test this type of class in my next post.

Remember that this class does depend on WP_Post_Type. My unit tests will not define the class because only integration tests can use WordPress or any other external dependencies. This class is used only to represent data, not to perform any action. Therefore, we can say that its use will not have any side effects. So I'd love to use mocks in unit tests instead of real WP_Post_Type.

Speaking of dependency injection, classes that require objects of this new class, we want to follow the same pattern. Instead of instantiating PreparedPostTypes in the class that requires them, we pass in an instance. This means that classes using PreparedPostTypes and PreparedPostType are kept isolated and can be tested separately.

It can also cause code reuse because we have to make dependency injection possible and set a property for this object. We can use cut and paste, or we can use PHP Trait, a more advanced and extensible method for copying methods and properties between classes.

This is a Trait that establishes a pattern for injecting PreparedPostTypes objects into other classes:

<code class="language-php">// ... (代码示例与原文相同) ...</code>

One of our concerns is that we need to know some information about the post type in multiple places. For example, post type slug. This is slightly different from the previous cross-cutting concern. The last problem we solved involves dynamic data. Now we just need to change the strings we use in multiple places in one place.

A class with class constants simply solved this problem for us:

<code class="language-php">// ... (代码示例与原文相同) ...</code>

Now we can make these strings consistent throughout the code. This seems to be an unnecessary step. But my sample code works for post post type. If you want to change the post type you are using, this class needs to be changed without changing anything else. This is following Tom McFarlin's preferred definition of the single responsibility principle when he wrote "A class should have only one reason to change."

Modify REST API endpoint mode

Now we need to modify the pattern of the post type endpoint. By doing so, WordPress will communicate to the REST API endpoint that the post type parameter is allowed and that new endpoint parameters are allowed when parsing the request.

This is our class to add the post_type property. Please note that it uses the trait UsesPreparedPostTypes we just discussed:

<code class="language-php">// ... (代码示例与原文相同) ...</code>

In the settings of this property, we tell WordPress that this property is an array property, and we use the "enum" index of the array to specify the allowed values.

In "enum", we enumerate allowed values. In this case, the PreparedPostTypes class provides an array of allowed values, as this is a previously solved cross-cutting concern.

Note that this class is not coupled to any post type or even this specific use case. We will soon go back to what hooks to use to make this class work for specific post types.

Modify REST API WP_Query parameter

The previous section describes how to make the new endpoint property post_type available. This does not actually change the WP_Query parameter generated by the WordPress REST API. We already have everything we need except the last filter.

Post type is a WP_Query parameter that the core code specifically does not allow changes to the REST API request. We have a dynamically named filter—rest_{$post_type}_query—can override any WP_Query parameter.

This is our class, which injects our post_type parameters, which were not allowed before:

<code class="language-php">// ... (代码示例与原文相同) ...</code>

Most of it is just to verify that we should make changes and then use the get_param method of WP_Rest_Request to get the value from the request. Most of it is automatic because we modify the pattern first to match.

Modify the WP_Query object requested by WordPress REST API

I have already covered how to do this in the first part of this article. This is a class that implements the same pattern:

<code class="language-php">// ... (代码示例与原文相同) ...</code>

I hope you notice that this code is closely related to WordPress and is not testable. It uses WP_Post from WordPress, which is checking constants for WordPress and interacting with WordPress's plugin API. We can simulate WP_Post, and we can set constants ourselves. But the plugin's API - this is an important feature that needs to be tested. In my next few posts, I'll cover how to refactor this class so that we can use unit tests to cover everything except the effect of removing that filter, and use integration tests to check that effect.

I chose to use a static method for two reasons. First, it makes it easy to add and remove it in multiple locations. For example, in the ModifyQuery class, I only hook this filter if needed:

<code class="language-php">// ... (代码示例与原文相同) ...</code>

Also, it is easy to create recursive loops when using this filter. It's great to be able to remove it as easily as in this example code.

Another reason I chose to use a static method is that the function interacts with other APIs. It will never be truly unit-testable. This pattern, a class with static methods, makes it very easy to simulate the class in integration testing, thus minimizing the impact of lack of strong isolation in one part of this system.

Make all content work together

The code we've seen so far is very uncoupled from WordPress. There are many benefits to this. But that means it does nothing on its own. This is very good. We have only dealt with business logic requirements so far. Now we need to consider integration.

This is not difficult, just add some hooks. What hooks? The exact same two hooks as we designed for the ModifyQuery and ModifySchema classes. The desire for decoupling business logic does not mean that we cannot consider the actual reasons why we write code when designing their public interfaces. Otherwise, we will only add extra complexity to our code without reason.

Generally speaking, I try to increase software complexity only when it makes life easier. I've deviated from this path in the past. We all have it, it doesn't matter, practice forgiveness.

The methods in the class we are about to hook use exactly the same parameters and return types as the hook. Their job is to assign these values ​​to other components.

<code class="language-php">// ... (代码示例与原文相同) ...</code>

Next step: Test

This is close enough. It will work. Due to the lack of a formal system to add hooks, this is the best thing we can do for initialization. This is very good. I will cover how to create a more complex and scalable boot process in a future article on WordPress integration testing.

In this article, we examine the underlying WP_Query for creating code to modify schema, WP_Query parameter generation, and post type. I encourage you to convert this code into a plugin and use Composer for automatic loading. In my next post, we will look at unit tests to cover these classes.

(The following is the original FAQ part, and the pseudo-original creation has been made based on the original content)

FAQs about advanced OOP and custom REST API endpoints in WordPress

What is the meaning of object-oriented programming (OOP) in WordPress?

Object-oriented programming (OOP) is a programming paradigm for designing applications and software using "objects". In a WordPress environment, OOP provides a simple, efficient and robust way to develop complex applications. It allows developers to group relevant tasks into classes and objects, making the code easier to read, reuse, and maintain. OOP also enhances application security by encapsulating data and preventing direct external access.

How to customize REST API endpoints in WordPress?

The WordPress REST API provides a set of default endpoints for different types of data. However, you can customize these endpoints or create new endpoints to suit your specific needs. This can be done by using the register_rest_route() function in your plugin or theme. This function allows you to specify the route or URL of the endpoint and define the methods it should respond to (GET, POST, etc.).

What are the advantages of customizing WordPress REST API endpoints?

Custom WordPress REST API endpoints allow you to create more efficient, flexible and secure applications. You can adjust the data returned by the endpoint to reduce the amount of unnecessary data sent over the network. You can also create endpoints that perform specific tasks, such as processing form submissions or generating reports, making your application more interactive and user-friendly.

How does OOP enhance the security of WordPress applications?

OOP enhances the security of WordPress applications by encapsulating data and methods into objects. This means that the properties (data) and methods (functions) of the object are hidden from the rest of the application and are only accessible through the object's methods. This prevents unauthorized access and manipulation of data, thereby reducing the risk of security breaches.

Can OOP be used with older versions of WordPress?

Yes, you can use OOP with older versions of WordPress. However, it is important to note that newer versions of WordPress have improved OOP support and include many features to make it easier to develop using this paradigm. So while OOP can be used with older versions, it is generally recommended to use the latest version of WordPress for the best development experience.

What are the roles of classes and objects in OOP?

In OOP, a class is a blueprint or template for creating an object. It defines the properties (data) and methods (functions) that an object should have. On the other hand, an object is an instance of a class. It has its own set of properties and methods that may be different from other objects of the same class. The use of classes and objects makes the code more organized, reusable and easy to maintain.

How to create a new class in WordPress?

You can use the class keyword, followed by the class name and a set of curly braces {} to create a new class in WordPress. In parentheses, you can define the properties and methods of the class. To create an object of a class, you can use the new keyword followed by the class name.

What is the REST API in WordPress?

The REST API in WordPress is an interface that allows you to interact with your WordPress site using HTTP requests. It provides a set of endpoints for different types of data such as posts, comments, and users that you can access using standard HTTP methods such as GET, POST, PUT, and DELETE. The REST API makes it easier for you to create, read, update, and delete data from your WordPress site from an external application.

How to access REST API in WordPress?

You can access the REST API in WordPress by sending HTTP requests to the corresponding endpoint. Each endpoint corresponds to a specific type of data and supports certain HTTP methods. For example, to retrieve a post list, you can send a GET request to the /wp/v2/posts endpoint. The REST API will return data in JSON format, which you can then process and display in your application.

Can I use the REST API with a non-WordPress application?

Yes, you can use the REST API with non-WordPress applications. The REST API is platform-agnostic, which means it can be used with any application that can send HTTP requests and process JSON data. This makes it a powerful tool for integrating WordPress sites with other applications such as mobile apps, desktop apps, and other web services.

The above is the detailed content of Advanced OOP for WordPress: Customizing REST API Endpoints. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn