Connecting Angular and the WordPress API with wp-api-angular — SitePoint

April 09, 2018 0 Comments

Connecting Angular and the WordPress API with wp-api-angular — SitePoint

 

 

In this tutorial, you’ll learn how to work with the wp-api-angular library that allows you to interact with the WordPress API from Angular 2+ applications. This library supports all major WP resources including users, posts, comments, media, taxonomies etc. It’s also quite simple to use, so you’ll get the idea in no time.

To see the library in action, we’re going to code the following features:

  • Authentication using JWT

  • Listing the users

  • Listing the posts

  • Creating and editing the posts

  • Deleting the posts

By the end of the article, you’ll become familiar with this library and will be ready to use it on your own.

The source code for this tutorial is available on GitHub.

I’ll assume you’re using Angular 5, but all explained concepts should be valid for Angular 2 as well.

Laying Foundations

Setting Up WordPress

Before we proceed to writing the code, there are a couple of things to take care of. First of all, note that the API we’re going to utilize works only with the self-hosted version of WordPress. For the web version (which can be configured via the WordPress site), there’s a separate API that has many similar concepts, though it’s still quite different.

You also have to enable permalinks — which is required for the API client to work correctly. For Nginx, you’ll need to add the following line to the nginx.conf file:

try_files $uri $uri/ /index.php?$args; 

More detailed information and explanations on how to enable permalinks can be found in this WordPress Codex guide.

Lastly, we should take care of WordPress security which, as they say, is above all. For that, a special plugin called JWT Authentication is required. We’re going to use it in order to authenticate our API client with the help of special tokens (an approach that’s quite common these days).

That’s pretty much it. If you’d like to learn more about the WordPress API in general, skim through this article. When you’re ready, proceed to the next step and let’s see the Angular WordPress client in action!

Bootstrapping an Angular Application

Now that we have WordPress prepared, create a new Angular application by running:

ng new wp-api 

This is going to create a skeleton for the application. We’re not going to discuss its structure thoroughly, but you may find more information in our Angular series.

Next, cd into the directory and install the library itself:

cd wp-api npm install -g typings npm install wp-api-angular --save 

Now we need to import the proper components inside the src/app/app.module.ts file:

// ... other imports import { Http } from '@angular/http'; import { HttpClientModule, HttpClient } from '@angular/common/http'; import { WpApiModule, WpApiLoader, WpApiStaticLoader } from 'wp-api-angular'; 

WpApiModule should also be added to the imports block. Note that we must use an exported factory for AoT compilation or Ionic:

// ... imports @NgModule({ declarations: [ // ... omitted ], imports: [ BrowserModule, FormsModule, HttpClientModule, // <--- WpApiModule.forRoot({ // <--- provide: WpApiLoader, useFactory: (WpApiLoaderFactory), deps: [Http] }) ] // ... }) 

Here’s the factory itself:

export function WpApiLoaderFactory(http: Http) { return new WpApiStaticLoader(http, 'http://YOUR_DOMAIN_HERE/wp-json/wp/v2/', ''); } 

Don’t forget to provide your own domain name here!

Lastly, let’s also add some imports to the app.components.ts file:

import { Component } from '@angular/core'; import { Observable } from 'rxjs'; import { NgForm } from '@angular/forms'; import { HttpClientModule, HttpClient } from '@angular/common/http'; import { Headers } from '@angular/http'; // ... 

We’ll need NgForm to craft forms, HTTP modules to interact with the API and Headers to authenticate the client.

The initial setup is done and we can proceed to the next section.

Authentication

Before interacting with the API, we need to introduce an authentication mechanism. As I already mentioned above, a token-based authentication will be employed, so let’s add a token variable to the app.components.ts:

export class AppComponent { token = null; // ... } 

Also, tweak the app.component.html file by adding a new block:

<div> <app-authentication [(token)]='token'></app-authentication> </div> 

In order for this to work, a separate component is required so generate it now:

ng generate component authentication 

Import the necessary modules inside the src/app/authentication/authentication.component.ts file:

import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; import { HttpClientModule, HttpClient } from '@angular/common/http'; // ... 

The authentication process is going to be very simple: a user should enter their login and password, submit the form, and a special token will be returned if the credentials are correct. This token will then be utilized to perform API requests. Therefore, let’s draft a user and add input and ouput for the AuthenticationComponent:

// ... export class AuthenticationComponent implements OnInit { user = { login: '', password: '' } @Input() token; @Output() tokenChange = new EventEmitter<string>(); // ... } 

Of course, you may define the user as a model, but for the purposes of this demo it’s not mandatory. As for the constructor, pass the HttpClient to it:

// ... constructor( private http: HttpClient ) { } 

Next code the auth method. It’s as simple as sending a POST request to the proper URL with the credentials and waiting for the response:

// ... auth() { this.http.post('http://YOUR_DOMAIN/wp-json/jwt-auth/v1/token', { username: this.user.login, password: this.user.password }).subscribe((data) => { if (data['token']) { // if token is returned this.token = data['token']; this.tokenChange.emit(this.token); } }); } 

Once again, don’t forget to insert your domain name into the URL.

The component is ready, and the last thing to do in this section is create the corresponding form. It should be displayed only if the token is null. When the form is submitted, the auth method should be called:

<form *ngIf='token == null' (ngSubmit)='auth()'> </form> 

Flesh the form out by adding two fields and a Submit button:

<form *ngIf='token == null' (ngSubmit)='auth()'> <div class='form-group'> <label for='login'>Login</label> <input type='text' class='form-control' [(ngModel)]='user.login' name='login' id='login' required> </div> <div class='form-group'> <label for='password'>Password</label> <input type='password' class='form-control' [(ngModel)]='user.password' name='password' id='password' required> </div> <button type="submit" class="btn btn-success">Submit</button> </form> 

That’s it! The authentication feature is finished, and we may start playing with the API itself.

Listing the Users

Usually, reading via the API is simpler than writing, so let’s try to list the users of our website powered by WordPress. Create a new UserList component:

ng generate component user-list 

Inside the src/app/user-list/user-list.component.ts you’ll need to import the WpApiUsers module as well as some other modules:

import { Component, OnInit, Input } from '@angular/core'; import { WpApiUsers } from 'wp-api-angular'; import { Headers } from '@angular/http'; // ... 

We’re going to store users inside the users array, which is initiallity empty:

// ... export class UserListComponent implements OnInit { users = []; } 

Pass WpApiUsers into the constructor and call a getUserList method:

// ... constructor( private wpApiUsers: WpApiUsers ) { this.getUserList(); } 

Now we need to code the getUserList. Every method presented by the API client returns an observable which can be converted to a promise using toPromise. So, to get a list of all users we should call the getList method, convert it to a promise, and assign the users variable with the returned array:

// ... getUserList() { this.wpApiUsers.getList() .toPromise() .then( response => { let json: any = response.json(); this.users = json; }) } 

As you see, nothing complex here. Interestingly, we don’t even need a token in order to perform this method. Therefore, simply render the users in a cycle:

<div> <h2>Users:</h2> <div *ngFor="let user of users"> Name: {{user.name}} </div> </div> 

The user-list component should be added to the app.component.html file:

<!-- ... --> <div> <user-list></user-list> </div> 

Working With Posts

Creating Posts

Now let’s try to implement a somewhat more complex feature and allow users to add new posts via the API. Create a separate post-new component:

ng generate component post-new 

Import the necessary modules inside the filesrc/app/post-new/post-new.component.ts file:

import { Component, OnInit, Input } from '@angular/core'; import { WpApiPosts } from 'wp-api-angular'; import { Headers } from '@angular/http'; // ... 

The WpApiPosts module is going to be the main star here.

Next, provide the token as an input and draft a post model:

// ... export class PostNewComponent implements OnInit { @Input() token; new_post = { title: '', content: '', status: 'publish' } } 

At the very least, each post should contain a title, some content, and the status (which we hard-code as publish to instantly publish the new post).

A constructor should accept the WpApiPosts:

// ... constructor( private wpApiPosts: WpApiPosts ) { } 

Now let’s craft a method to add the post. First, code the authentication logic by setting the Authorization header:

// ... createPost() { let headers: Headers = new Headers({ 'Authorization': 'Bearer ' + this.token }); } 

Now we can simply take the headers variable and pass it to the create method of the WpApiPosts module:

// ... createPost() { let headers: Headers = new Headers({ 'Authorization': 'Bearer ' + this.token }); this.wpApiPosts.create(this.new_post, { headers: headers }) .toPromise() .then( response => { console.log(response); }) } 

What about the form? Well, it’s quite simple really:

<!-- src/app/post-new/post-new.component.html --> <div> <h2> Post Creation </h2> <form (ngSubmit)='createPost()'> <div class="form-group"> <label for="title">Post title</label> <input type="text" class="form-control" [(ngModel)]='new_post.title' name='title' id="title" required> </div> <div class="form-group"> <label for="content">Post content</label> <textarea class="form-control" id="content" required [(ngModel)]='new_post.content' name='content'></textarea> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> 

When the form is submitted, we call the createPost method.

Don’t forget to render the post-new component:

<!-- app.component.html --> <!-- ... --> <div> <h3 *ngIf='token == null'> Please, authorize to create a post </h3> <post-new *ngIf='token' [token]='token'></post-new> </div> 

We check that the token is set, and if not, we ask the user to authenticate.

Listing the Posts

Okay, we’ve added the ability to create the posts. Why don’t we also display them on the page? Create yet another component:

ng generate component post-list 

Import the necessary modules, including WpApiPosts inside the src/app/post-list/post-list.component.ts file:

import { Component, OnInit, Input } from '@angular/core'; import { WpApiPosts } from 'wp-api-angular'; import { Headers } from '@angular/http'; // ... 

Provide the input and the posts array:

// ... export class PostListComponent implements OnInit { @Input() token; posts = []; } 

Code the constructor that should call the getPosts method:

// ... constructor(private wpApiPosts: WpApiPosts) { this.getPosts(); } 

We don’t need to authenticate to fetch the posts, so let’s use the same approach as before:

// ... getPosts() { this.wpApiPosts.getList() .toPromise() .then( response => { let json: any = response.json(); this.posts = json; }); } 

Now render the array of posts:

<!-- src/app/post-list/post-list.component.html --> <div> <h2>Latests Posts:</h2> <hr> <div *ngFor='let post of posts'> <h1 [innerHTML]='post.title.rendered'></h1> <p [innerHTML]='post.content.rendered'></p> <hr> </div> </div> 

Lastly, display the component:

<!-- app.component.html --> <!-- ... --> <div> <post-list [token]='token'></post-list> </div> 

Destroying the Posts

Next, I’d like to add an ability to destroy the posts. This feature can be implemented in the same PostList component. Simply add a Delete button next to each post:

<!-- src/app/post-list/post-list.component.html --> <div> <h2>Latests Posts:</h2> <hr> <div *ngFor='let post of posts'> <h1 [innerHTML]='post.title.rendered'></h1> <p [innerHTML]='post.content.rendered'></p> <button *ngIf='token' (click)='deletePost(post.id, $index)'>Delete</button> <hr> </div> </div> 

Note that this button is displayed only if the token is present. Also, tweak the component by adding the deletePost method:

// src/app/post-list/post-list.component.ts // ... deletePost(id: number, index: number) { let headers: Headers = new Headers({ 'Authorization': 'Bearer ' + this.token }); this.wpApiPosts.delete(id, { headers: headers }) .toPromise() .then( response => { if (response['ok'] == true) { this.posts.splice(index,1); } }) } 

Basically, nothing new here. We’re adding the token to the headers and call the delete method which accepts the post’s ID and its index in the posts array. If the request succeeded, remove the post from the array.

Editing the Posts

The last feature we’re going to introduce today is the ability to edit the posts. Let’s create a new component:

ng generate component post-edit 

This component will be referenced from the PostList. Specifically, I’d like to add an Edit button next to each post and render the PostEdit template whenever it’s clicked:

<!-- src/app/post-list/post-list.component.html --> <div> <h2>Latests Posts:</h2> <hr> <div *ngFor='let post of posts'> <div *ngIf='editingPost != post; else postEdit'> <h1 [innerHTML]='post.title.rendered'></h1> <p [innerHTML]='post.content.rendered'></p> <button *ngIf='token' (click)='deletePost(post.id, $index)'>Delete</button> <button *ngIf='token' (click)='updatePost(post)'>Edit</button> <hr> </div> </div> <ng-template #postEdit> <post-edit [post]='editingPost' [token]='token' (finish)='editingPost = null; getPosts()'></post-edit> </ng-template> 

Tweak the PostListComponent by introducing an editingPost variable and an updatePost method, which is going to assign the editingPost with a proper value:

// src/app/post-list/post-list.component.ts // ... export class PostListComponent implements OnInit { @Input() token; posts = []; editingPost = null; updatePost(post) { this.editingPost = post; } } 

Proceed to the PostEditComponent and import all the required modules:

// src/app/post-edit/post-edit.component.ts import { Component, OnInit, Input, EventEmitter, Output } from '@angular/core'; import { WpApiPosts } from 'wp-api-angular'; import { Headers } from '@angular/http'; // ... 

This component is going to have two inputs: the token and the actual post to edit. Also, we’ll have an output (EventEmitter):

// ... export class PostEditComponent implements OnInit { @Input() token; @Input() post; @Output() finish = new EventEmitter<void>(); post_edit = { title: '', content: '' } } 

As soon as the component is initialized, assign the post_edit variable with the proper title and content taken from the post variable:

// ... ngOnInit() { this.post_edit['title'] = this.post.title.rendered; this.post_edit['content'] = this.post.content.rendered; } 

Now code the updatePost method, which is going to perform authentication. Update the post and emit an event:

// ... updatePost() { let headers: Headers = new Headers({ 'Authorization': 'Bearer ' + this.token }); this.wpApiPosts.update(this.post.id, this.post_edit, { headers: headers }) .toPromise() .then( response => { this.finish.emit(null); }) } 

Note that the update method accepts both the post’s ID and the new value for the title and content.

Here’s the form to edit the post:

<!-- src/app/post-edit/post-edit.component.html --> <div> <h2> Post Editing </h2> <form (ngSubmit)='updatePost()'> <div class="form-group"> <label for="title">Post title</label> <input type="text" class="form-control" [(ngModel)]='post_edit.title' name='title' id="title" required> </div> <div class="form-group"> <label for="content">Post content</label> <textarea class="form-cont rol" id="content" required [(ngModel)]='post_edit.content' name='content'></textarea> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> 

This’s it: the editing feature is ready! You may now boot the server by running:

ng serve --open 

and play with the app to make sure everything is working fine.

Conclusion

In this article, we’ve discussed the usage of the WordPress API client for Angular. We’ve seen it in action by introducing the authentication feature, listing the users and posts, as well as by adding ability to create and manipulate the posts. This client allows you to work with other resources like media and comments, but all these interactions are very similar to the ones we’ve talked about here.

Hopefully you’re now ready to apply the information presented here into practice, but don’t hesitate to send me your questions! As always, thanks for staying with me and until the next time.


Tag cloud