Connecting Angular and the WordPress API with wp-api-angular
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.