WordPress REST Api to Ionic 2 : Converting category id to name

In Ionic 2 by seme0 Comments

This tutorial assumes you have installed and setup the WordPress REST Api Plugin on a wordpress website that you have access to. For more info, refer to:
https://wordpress.org/plugins/rest-api/

Over the course of developing Magaza for WordPress, I’ve encountered this, and chances are you have too. You’ve installed the WordPress REST api plugin, and you’ve connected to it from an Ionic 2 app, fetching content and adding it to your content. Then this happens…

You expected text, and got numbers

When we make a call to /wp-json/wp/v2/posts on your wordpress website, only the category ids. As this isn’t available right now, we have to workaround this with our own method, while minimizing the number of times we hit the endpoint. That’s what we’re going to do now.

Quick explanation:

Here’s what we know:

  • We know the category id of the post.
  • We also know each id corresponds to a category name at /wp-json/wp/v2/categories

That means to achieve the desired outcome:

  • We fetch the category list for the entire site
  • We match that category list to every post where we need to display the category name.

With that, lets begin.

Setup

First, lets create our project:

ionic start wpcategory sidemenu --v2

Open src/pages/page1/page1.html and edit to relfect the following:

<ion-content padding>
    
  <h3>Ionic Menu Starter</h3>

  <ion-list>
    <ion-item>
      <ion-avatar item-left>
        <img src="assets/icon/favicon.ico">
      </ion-avatar>
      <h2>Finn</h2>
      <h3>Don't Know What To Do!</h3>
      <p>I've had a pretty messed up day. If we just...</p>
    </ion-item>
  </ion-list>
  
  <p>
    If you get lost, the <a href="http://ionicframework.com/docs/v2">docs</a> will show you the way.
  </p>
  
</ion-content>

Once done, run ionic serve

Now we’re going to setup our page1.ts to call data from a wordpress-api enabled site.

The data call

Open our src/pages/page1/page1.ts file and edit to reflect the following:

import { Component } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
import { NavController } from 'ionic-angular';

@Component({
  selector: 'page-page1',
  templateUrl: 'page1.html'
})
export class Page1 {
  url: string = 'https://your-wordpress-website/wp-json/wp/v2/posts';
  items: any;

  constructor(
    public navCtrl: NavController,
    private http: Http
  ) {
    //we've placed loadPosts() in our constructor to run immediately.
    this.loadPosts();
  }

  //Our function to call wordpress
  loadPosts() {
    this.http.get( this.url )
      .map(res => res.json())
      .subscribe(data => {
        this.items = data;
        console.log(data);
      });
  }

}

We’re importing http and rxjs to make a data call to our website, which we have wrapped in a function loadPosts() , set to run in our constructor() . http returns an Observable, where in our subscribe, we assign our data to this.items

Next we create an *ngFor loop in our src/pages/page1/page1.html. Edit our page1.htm to the following:

<ion-header>
  <ion-navbar>
    <button ion-button menuToggle>
      <ion-icon name="menu"></ion-icon>
    </button>
    <ion-title>Page One</ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  <h3>Ionic Menu Starter</h3>

  <ion-list>
    <ion-item *ngFor="let item of items">
      <ion-avatar item-left>
        <img src="assets/icon/favicon.ico">
      </ion-avatar>
      <h2 [innerHTML]="item.title.rendered"></h2>
      <h3>{{item.categories | json}}</h3>
      <p [innerHTML]="item.excerpt.rendered"></p>
    </ion-item>
  </ion-list>

  <p>
    If you get lost, the <a href="http://ionicframework.com/docs/v2">docs</a> will show you the way.
  </p>

</ion-content>

In ionic serve we should have something like this:

Notice beneath every post title we have an array of numbers e.g: [140, 6]. We’re going to transform these to text, by using a pipe. Our pipe will give us the right category name for every category id we give it.

Pipe What?

According to Angular Documentation: https://angular.io/docs/ts/latest/guide/pipes.html :
A pipe takes in data as input and transforms it to a desired output.

Creating our category list.

Open and edit our src/pages/page1/page1.ts to the following below. We’ll explain further

import { Component } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
import { NavController } from 'ionic-angular';

@Component({
  selector: 'page-page1',
  templateUrl: 'page1.html'
})
export class Page1 {
  url: string = 'https://your-wordpress-website/wp-json/wp/v2/posts';
  categoryUrl : string = 'https://your-wordpress-website/wp-json/wp/v2/categories';
  categories : any;
  items: any;

  constructor(
    public navCtrl: NavController,
    private http: Http
  ) {
    //we've placed loadPosts() in our constructor to run immediately.
    this.loadPosts();
    this.loadCategories();
  }

  //Our function to call wordpress
  loadPosts() {
    this.http.get( this.url )
      .map(res => res.json())
      .subscribe(data => {
        this.items = data;
        console.log(data);
      });
  }
  
   //Our function to load categories
  loadCategories() {
    this.http.get( this.categoryUrl )
      .map(res => res.json())
      .subscribe(data => {
        let categoryArray = {};

        data.forEach(function(item){
          categoryArray[item.id] = item.name;
        })

        this.categories = categoryArray;

        console.log(categoryArray);
      });
  }

}

So what’s happened:

  • We created a variable to hold the url to our category endpoint, and a variable to hold our category list
    categoryUrl : string = 'https://your-wordpress-website/wp-json/wp/v2/categories';
    categories : any;
  • We created a new function loadCategories(), which is similar to loadPosts(), except for one thing: we create an object categoryArray, and looping through the categories from our data source, add the name and id of each category. See below for emphasis:
    loadCategories() {
        this.http.get( this.categoryUrl )
          .map(res => res.json())
          .subscribe(data => {
    
            // create a variable we can use in function
            let categoryArray = {};
    
            // for every category in our endpoint request, add its name and id
            // to categoryArray
            data.forEach(function(item){
              categoryArray[item.id] = item.name;
            })
    
            // Assign this to our class variable this.categories
            // for use in template
            this.categories = categoryArray;
    
            console.log(categoryArray);
          });
      }

    Now in our browser running ionic serve, open up the developer console (Ctrl+Shift+J) and you’ll see our array of categories in the console:

If you notice, the numbers from our posts list are simply combinations of numbers in our category object. which means we can use the category numbers in our post as the keys of our category object to return the category name.

That last part, we’re going to do inside a pipe, taking our category list as an argument. Run the following command in our prompt:

ionic g pipe categoryIdToName

Let’s import our pipe and add it to our declarations:

import { NgModule, ErrorHandler } from '@angular/core';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { Page1 } from '../pages/page1/page1';
import { Page2 } from '../pages/page2/page2';

//Our imported pipe
import { CategoryIdToName } from '../pipes/category-id-to-name';

@NgModule({
  declarations: [
    MyApp,
    Page1,
    Page2,
    CategoryIdToName
  ],
  imports: [
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    Page1,
    Page2
  ],
  providers: [{provide: ErrorHandler, useClass: IonicErrorHandler}]
})
export class AppModule {}

open our newly created pipe at src/pipes/category-id-to-name.ts. We’re changing the name inside our @Pipe meta-data to remove the hyphens. Just copy the snippet below

import { Injectable, Pipe } from '@angular/core';

/*
  Generated class for the CategoryIdToName pipe.

  See https://angular.io/docs/ts/latest/guide/pipes.html for more info on
  Angular 2 Pipes.
*/
@Pipe({
  name: 'CategoryIdToName'
})
@Injectable()
export class CategoryIdToName {
  /*
    Takes a value and makes it lowercase.
   */
  transform(value, args) {
    value = value + ''; // make sure it's a string
    return value.toLowerCase();
  }
}

So, to explain ahead of our final code with respect to our pipe:

  • We’re taking an array of category ids from our post as our value, and our object of categories will be our arguement args
  • Create a loop of our category ids, where for every number, we set a local variable to the name of the object key equal to our category id.
  • we return the output.

So let’s see our usable code:

import { Injectable, Pipe } from '@angular/core';

/*
  Generated class for the CategoryIdToName pipe.

  See https://angular.io/docs/ts/latest/guide/pipes.html for more info on
  Angular 2 Pipes.
*/
@Pipe({
  name: 'CategoryIdToName'
})
@Injectable()
export class CategoryIdToName {
  /*
    Takes a value and makes it lowercase.
   */
  transform(value, args) {
    let output = '';
    // value = value + ''; // make sure it's a string
    // return value.toLowerCase();
    value.forEach(function(number){
      output = output + ' - '+ args[number]
    })
    return output;
  }
}

And now, we use it in our page1.html like this:

<ion-list>
    <ion-item *ngFor="let item of items">
      <ion-avatar item-left>
        <img src="assets/icon/favicon.ico">
      </ion-avatar>
      <h2 [innerHTML]="item.title.rendered"></h2>
      <!--Our pipe using this.categories as our argument, and item.categories as our value-->
      <h3>{{item.categories | CategoryIdToName:categories }}</h3>
      <p [innerHTML]="item.excerpt.rendered"></p>
    </ion-item>
</ion-list>

Here’s our final result: