First of all, don’t expect much of this blog post. It’s intended to capture some thoughts and opinions I’ve noted down while working on my first real-world React / WP REST API application. It’s not intended to be polished, professional-grade marketing copy. It also assumes you have some familiarity with React, Redux, and the WP REST API — if you don’t, the blog post may not make sense. You’ve been warned.
I pretty much love React at this point, and can’t imagine using WordPress’ theming for anything in the future. If you hire me to build a brochure website, I will probably build it in React, just because.
What I like most is that everything is so damn elegant. The component-based architecture encourages you to think about whatever you’re building in terms of reusable pieces. I suspect this naturally lends itself to Better Quality Code.
But, React is also a substantial departure from WordPress’ quick and dirty ethos. A concern of mine is long-term maintainability of a React-based website, particularly for clients who think they’re getting a WordPress website and expect to be able to hire a WordPress developer for future changes to it.
Routing is painful. I haven’t found an elegant solution to the fact that routes need to be declared in WordPress and in React.
For the project I’m on, all routes are going into React first so the application works as expected. At some point, I’ll need to figure out how equivalent routes should be sustainably registered as WordPress rewrites.
The theory is that single page applications deployed as WordPress themes can use WordPress to serve response headers, social / SEO meta, and prepare an initial payload of data using the main query, before passing on the torch to React. In practice, I’ve worked very little of this out yet.
Or, I can noop WordPress’ route handling entirely, but then I’ll lose some of the benefit of having WordPress serving the initial pageload.
Which brings me to managing application state. Once you get over the day of effort to understand how Redux works, it’s really quite elegant. It also takes about 50% more effort than I’d like to get my application data into my components.
If I may make one request, could someone please write a redux-wp library to magically generate actions and reducers from my WP REST API index?
If you’re curious what real-world WP REST API endpoint registration looks like, here’s the Controller for a Record which, in the LMS data model of students completing activities and quizzes, stores the data of a student’s answers to an activity or quiz.
Commentary on my code, in no particular order, includes:
- I’m not sure why I’m using
register_rest_field()when I’m already subclassing and have access to the schema. I should probably refactor that.
- Make sure to register your fields before your routes, if you’re using the helpers to transform schema into route args. This bit me once.
- While it’s nice I can use a filter to modify the behavior of
WP_REST_Posts_Controller->get_items(), aforementioned method is impossible to subclass.
- The REST API’s concept of context (e.g. embed vs. view vs. edit) is mostly useless in my case, because I’m always fetching the entirety of the resource. I would like for a way to easy disable the concept of context. Also, we should’ve gone with
title_renderedinstead of creating a title object on the Post resource.
arg_optionsalways feels really awkward, because registering a schema property seems like it should be equivalent to registering a query parameter or anything else. I want to be able to use
default, and others as top-level arguments to registering a schema property.
Generally, I consider the WP REST API controllers to be good, but not great, right now. I’m writing lots of tests for cases I don’t think I should need to write tests for, because the WP REST API is a bit leaky. For instance, I’d expect for my declaration of query params and schema to be the canonical truth of what the endpoint supports, which isn’t the case currently (e.g. you can deregister the
password field on a Post-derived resource, and password will still be included in the response object).
In my ideal world, to create a custom post type endpoint, I would:
- Define the shape of my resource (e.g. its schema)
- Declare which operations the resource supports (list, get, create, update, delete) through some means where I didn’t have to extend
- Declare which query params the resource supports.
- Implement permissions checks as needed.
Leave me any questions you have in the comments! Or, better yet, write about the real-world lessons you’ve learned.