Sådan gør du Wordpress mere spændende med Wordpress API, ACF og Express.js

Jeg har arbejdet med Wordpress, siden det er spredning som et content management system. Jeg bliver næppe ophidset, når klienter eller kolleger nævner det længere. Jeg har “fundet lyset” i mere robuste rammer og lært meget mere om de forskellige dele af brugerdefinerede webapplikationer.

Så i et forsøg på at forynge min passion for Wordpress er jeg begyndt at se på forskellige måder at implementere rammen på. En af disse måder er at adskille frontend fra back-end og undgå nogle af smertepunkterne ved at bruge Wordpress Template Tags og temasystemet. Lad os se.

Monolitiske vs. distribuerede apps

Wordpress er en monolitisk ramme, hvilket betyder, at de forskellige dele af rammen (database, filopbevaring, præsentationsstruktur og aktivfiler, forretningslogikfiler) alle er pakket sammen. Dette er en stor del af, hvorfor Wordpress er så let at komme i gang. Installer MAMP, kopier over de nyeste Wordpress-filer, opret en database, og skift wp-config.phpfilen. Klar.

Vi vil gå imod den monolitiske konvention og dele dette Wordpress-sted op i to forskellige dele: front-end og back-end, præsentation og administration.

Vi skal bruge Wordpress til datadministrationen af ​​vores app og udnytte et plugin til at hjælpe med oprettelse og styring af attributter (felter) til vores brugerdefinerede posttype. For præsentationssiden af ​​tingene vil vi helt give afkald på et tema og forbruge API-slutpunkter fra en Express.js-applikation.

Eksempel

I dette eksempel skal vi opbygge en simpel produktliste. Ideen er, at du allerede har et websted drevet af Wordpress, og gerne vil styre en liste over produkter til salg via den samme grænseflade. Men du vil oprette et helt andet websted til butikken.

Wordpress API

Siden version 4.7 udsætter Wordpress automatisk dine publicerede indlæg (og andre data) via sin REST API, præsenteret i et JSON-format. Hvis du har udviklet et websted ved hjælp af Wordpress 4.7+, skal du blot tilføje /wp-jsontil rod-URL'en og undre sig over væggen med tekst, der returneres.

Med denne API automatisk integreret i Wordpress-installationen er meget af arbejdet med en distribueret applikation allerede gjort for os. API-oprettelse kan være en vejspærring, når du kommer i gang med denne nye måde at tænke på applikationer på. Wordpress har skabt en fantastisk, grundlæggende API til at forbruge vores data, som vi foretrækker.

På dette tidspunkt ville jeg kun rodet internettet ved at skrive en vejledning i, hvordan man lokalt installerer Wordpress. Så i stedet vil jeg pege dig mod en betroet kilde om emnet.

Uanset hvilken vej du tager for at få en Wordpress-forekomst i gang, skal du være i stand til at få adgang til den via //localhosteller en anden URL. Når vi har en URL, lad os lave en hurtig test for at sikre, at vi har data, der kommer tilbage. Jeg foretrækker et værktøj som Postman, men vi holder det simpelt og besøger følgende URL i vores browser (selvfølgelig ændrer vi URL'en i overensstemmelse hermed).

//localhost/mysite/wp-json

Dette skal returnere en liste over alle tilgængelige slutpunkter til din Wordpress-installations REST API.

Men i virkeligheden postmand ...

Postbud

Postman er det eneste komplette API-udviklingsmiljø til API-udviklere, der bruges af mere end 5 millioner udviklere ... www.getpostman.com

Tilpassede posttyper

Da Wordpress begrænser os til to datatyper (indlæg og sider), bliver vi nødt til at oprette en brugerdefineret posttype til vores produkter. Dette vil skabe en klar adskillelse fra produktindlæg og andre indlæg, vi har.

Der er en række forskellige måder at oprette brugerdefinerede posttyper på. Her skal vi oprette en enkelt fil Wordpress Plugin for at registrere typen af ​​produkter.


    
function create_product_cpt() { $labels = array( 'name' => __( 'Products', 'Post Type General Name', 'products' ), 'singular_name' => __( 'Product', 'Post Type Singular Name', 'products' ), 'menu_name' => __( 'Products', 'products' ), 'name_admin_bar' => __( 'Product', 'products' ), 'archives' => __( 'Product Archives', 'products' ), 'attributes' => __( 'Product Attributes', 'products' ), 'parent_item_colon' => __( 'Parent Product:', 'products' ), 'all_items' => __( 'All Products', 'products' ), 'add_new_item' => __( 'Add New Product', 'products' ), 'add_new' => __( 'Add New', 'products' ), 'new_item' => __( 'New Product', 'products' ), 'edit_item' => __( 'Edit Product', 'products' ), 'update_item' => __( 'Update Product', 'products' ), 'view_item' => __( 'View Product', 'products' ), 'view_items' => __( 'View Products', 'products' ), 'search_items' => __( 'Search Product', 'products' ), 'not_found' => __( 'Not found', 'products' ), 'not_found_in_trash' => __( 'Not found in Trash', 'products' ), 'featured_image' => __( 'Featured Image', 'products' ), 'set_featured_image' => __( 'Set featured image', 'products' ), 'remove_featured_image' => __( 'Remove featured image', 'products' ), 'use_featured_image' => __( 'Use as featured image', 'products' ), 'insert_into_item' => __( 'Insert into Product', 'products' ), 'uploaded_to_this_item' => __( 'Uploaded to this Product', 'products' ), 'items_list' => __( 'Products list', 'products' ), 'items_list_navigation' => __( 'Products list navigation', 'products' ), 'filter_items_list' => __( 'Filter Products list', 'products' ), );
 $args = array( 'label' => __( 'Product', 'products' ), 'description' => __( '', 'products' ), 'labels' => $labels, 'menu_icon' => 'dashicons-products', 'supports' => array('title', 'editor', 'excerpt', 'thumbnail'), 'taxonomies' => array('products'), 'public' => true, 'show_ui' => true, 'show_in_menu' => true, 'menu_position' => 5, 'show_in_admin_bar' => true, 'show_in_nav_menus' => true, 'can_export' => true, 'has_archive' => true, 'hierarchical' => false, 'exclude_from_search' => false, 'show_in_rest' => true, 'rest_base' => 'products', 'publicly_queryable' => true, 'capability_type' => 'post', );
 register_post_type( "product", $args );}%>

While long-winded, this is pretty standard code for creating a custom post type in Wordpress. Two things to note in our $args array:

  • 'show_in_rest' => true makes the custom post type accessible via the REST API
  • 'rest_base' => 'products' sets the name we use to access Products via the REST API endpoints

Once you have your custom post type showing in the Wordpress admin, let’s make sure we can get a response via the API (you’ll need to create a product so it doesn’t return empty).

//localhost/mysite/wp-json/wp/v2/products

And here’s what we get…

Sweet!

Advanced Custom Fields

I try to limit my usage of plugins as much as possible, but I’ll make an exception for Advanced Custom Fields (ACF). ACF takes all the work out of creating and managing custom fields for post types. Head to your Plugins page, search for Advanced Custom Fields then click “Install” & “Activate”. All done.

It would also be redundant for me to walk you through creating a Field Group using Advanced Custom Fields, so I’ll let their documentation walk you through it if you don’t know how.

Let’s create a Field Group called “Product Meta” and add fields for “Normal Price”, “Discount Price” and “Inventory Quantity” and position them in the sidebar area.

Good.

Now comes the tricky part. The fields we just created through ACF aren’t exposed via the REST API by default. We will have to leverage add_filter and rest_prepare_{$post_type} to add the custom field values to the JSON response. Here, I’ve simply added this bit of code to the bottom of our custom post type plugin file for the sake of brevity.

function my_rest_prepare_post($data, $post, $request) { $_data = $data->data; $fields = get_fields($post->ID);
 foreach ($fields as $key => $value){ $_data[$key] = get_field($key, $post->ID); }
 $data->data = $_data; return $data;}
add_filter("rest_prepare_product", 'my_rest_prepare_post', 10, 3);

Thanks to Cody Sand for the tidbit above.

Express.js

Our Express.js app will provide us a framework for consuming the Wordpress API and presenting products in our store website. Since we are simply consuming an API, we could use any framework of our choosing. Vue.js. Angular. Backbone. React. Rails. Django. Middleman. Jekyll. The front-end world is your oyster.

I’ll assume you already have Node.js installed. If you don’t, it’s dead simple. Let’s start a new Express.js app.

npm install -g express-generator nodemonexpress --css=sass --view=jade --git mystorecd mystorenpm install --save request request-promise && npm install

Here, we are using the Express Generator package to generate a skeleton for our Express app. We’ll also be using SASS for stylesheets and Jade Template Engine. Choose whatever you’re comfortable with. Nodemon will restart our app automatically for us when a file changes, and the Request library will help us make HTTP requests to the Wordpress API. Let’s serve up our Express app:

nodemon

Now, when we pull up //localhost:3000 we should see our Express app running.

Alright, now let’s pull in our products.

var express = require('express');var router = express.Router();const rp = require('request-promise');
/* GET index page. */router.get('/', function(req, res, next) { rp({uri: '//127.0.0.1:8888/test/wp-json/wp/v2/products', json: true}) .then((response) => { console.log(response); res.render('index', {products: response}); }) .catch((err) => { console.log(err); });});
module.exports = router;

In our index.js route file, let’s include the Request-Promise library then make a call to the products endpoint within our root route (/).

If the request is successful, then we render our index view. If there’s an error with the request, we simply log it. Now, the view…

extends layout
block content h1 MyStore ul each product in products li product.title.rendered product.price

Using Jade, we will simply list the products out. Ok, let’s check out our store site.

? There’s your prize. I’ll leave it up to you to continue down the Express road and figure out how to get product listing and index pages working.

Beyond

This is a fairly simple example of how distributed apps work using Wordpress. We could have continued to separate the app into even more parts by integrating a CDN for media storage or moving the database to a separate server. We also didn’t cover authentication for the Wordpress API which is something you would absolutely need in production.

From here, you could implement Stripe or another payment processor and have a fully functional store site. I hope this has inspired some of you to leverage Wordpress in different ways and continue using one of the most ubiquitous CMS solutions out there. Happy coding!