Hogyan lehet izgalmasabbá tenni a Wordpress alkalmazást a Wordpress API, ACF és Express.js segítségével

Azóta dolgozom a Wordpress-szel, hogy terjedése tartalomkezelő rendszerként működik. Alig izgulok, amikor az ügyfelek vagy munkatársak már említik. Robusztusabb keretek között "találtam meg a fényt", és sokkal többet tudtam meg az egyedi webalkalmazások különböző részeiről.

Így a Wordpress iránti szenvedélyem megújítása érdekében elkezdtem a keretrendszer megvalósításának különböző módjait keresni. Az egyik ilyen módszer a front-end és a back-end elválasztása, és a Wordpress Template Tags és a tematikus rendszer használatának néhány fájdalmas pontjának elkerülése. Lássuk.

Monolitikus és terjesztett alkalmazások

A Wordpress egy monolit keretrendszer, vagyis a keretrendszer különböző részei (adatbázis, fájltárolók, prezentációs struktúra és eszközfájlok, üzleti logikai fájlok) együtt vannak csomagolva. Ez egy nagy része annak, amiért a Wordpress olyan könnyen üzembe helyezhető. Telepítse a MAMP-ot, másolja át a legújabb Wordpress-fájlokat, hozzon létre egy adatbázist és változtassa meg a wp-config.phpfájlt. Mehetsz.

Szembe fogunk menni a monolit konvencióval, és ezt a Wordpress webhelyet két különböző részre bontjuk: front-end és back-end, prezentáció és adminisztráció.

Alkalmazásunk adatkezeléséhez a Wordpress alkalmazást fogjuk használni, és egy beépülő modult fogunk használni az egyedi bejegyzés típusunk attribútumainak (mezők) létrehozásában és kezelésében. A dolgok bemutatásának részeként teljesen elhagyunk egy témát, és API-végpontokat fogyasztunk egy Express.js alkalmazásból.

Példa

Ebben a példában egyszerű terméklistát fogunk készíteni. Az elképzelés az, hogy már rendelkezik a Wordpress által működtetett webhellyel, és ugyanazon a felületen szeretné kezelni az eladó termékek listáját. De egy teljesen más weboldalt szeretne létrehozni az áruház számára.

Wordpress API

A 4.7 verzió óta a Wordpress automatikusan közzéteszi közzétett bejegyzéseit (és egyéb adatait) REST API-ján keresztül, JSON formátumban. Ha egy weboldalt fejlesztett a Wordpress 4.7+ alkalmazással, egyszerűen adja hozzá /wp-jsona root URL-hez, és csodálkozzon a visszaküldött szöveg falán.

Ezzel az API-val, amely automatikusan integrálódik a Wordpress telepítésébe, egy elosztott alkalmazás sok munkáját már elvégezték helyettünk. Az API létrehozása akadályt jelenthet, ha elkezdi az alkalmazások új gondolkodását. A Wordpress létrehozott egy fantasztikus, alapvető API-t az adataink bármilyen módon történő felhasználásához.

Ezen a ponton csak az internetet kavarnám, ha bemutatót írnék a Wordpress helyi telepítéséről. Tehát ehelyett egy megbízható forrás felé mutatok a témában.

Függetlenül attól, hogy milyen útvonalon halad a Wordpress-példány elindítása és futtatása érdekében, képesnek kell lennie arra, hogy hozzáférjen ehhez //localhostvagy más URL- en keresztül . Miután megvan az URL, végezzünk egy gyors tesztet, hogy megbizonyosodjunk arról, hogy visszatérnek az adatok. Inkább egy olyan eszközt részesítek előnyben, mint a Postman, de ezt egyszerűvé tesszük, és böngészőnkben meglátogatjuk a következő URL-t (természetesen ennek megfelelően megváltoztatva az URL-t).

//localhost/mysite/wp-json

Ennek vissza kell adnia a Wordpress telepítés REST API-jának összes rendelkezésre álló végpontját.

De igazából, Postás…

Postás

A Postman az egyetlen teljes API fejlesztői környezet az API fejlesztők számára, amelyet több mint 5 millió fejlesztő használ ... www.getpostman.com

Egyéni feladattípusok

Mivel a Wordpress két adattípusra korlátoz minket (Bejegyzések és Oldalak), létre kell hoznunk egy egyedi bejegyzéstípust a Termékeinkhez. Ez egyértelműen elkülöníti a termék bejegyzéseit és az összes többi bejegyzést.

Számos különböző módon hozhat létre egyéni bejegyzéstípusokat. Itt egyetlen fájlt hozunk létre a Wordpress beépülő modulról a Termékek bejegyzés típusának regisztrálásához.


    
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!