Edupala

Comprehensive Full Stack Development Tutorial: Learn Ionic, Angular, React, React Native, and Node.js with JavaScript

Ionic WordPress API – CRUD operation

This article continuation of our previous post where we have learned how to authenticate from our ionic application to the WordPress back-end. In this tutorial, we will further add additional features to our previous application to perform CRUD operations on WordPress posts. We had already added an HTTP interceptor to intercept our HTTP request. The JWT token in the header performs operations like creation, deletion, and update. But for the GET method, we don’t need any authentication.

Here is a screenshot of our Ionic WordPress Apps

Ionic wordpress example
Ionic WordPress CRUD

Setting and configuring the Ionic WordPress project

Creating pages and services for Ionic WordPress post-CRUD operation. We will have different components for displaying posts and adding and editing posts. Let us generate these components with CLI commands first.

$ionic generate page pages/posts
$ionic generate page pages/posts/post
$ionic generate page pages/posts/editPost


We also need two services. The Ionic WordPress service performs post-related activities. The common provider where have our common functionality which is shared by a large number of components, in our case we called it a common service.

$ionic generate service services/wordpress
$ionic generate service services/common

Implementing common service
We have toast functionality which to display toast messages which can be shared by components. Add the following code in the common.service.ts file

import { Injectable } from '@angular/core';
import { ToastController } from '@ionic/angular';

@Injectable()
export class CommonService {

  constructor(private toast: ToastController) { }

  async showToast(message: string, type: string) {
    const toast = await this.toast.create({
      message,
      duration: 3000,
      color: type === 'success' ? 'primary' : 'danger'
    });
    toast.present();
  }
}

Post-service to API CRUD implementation
This service uses HTTP calls to perform the CRUD operations of posts on the WordPress site by using HttpClient from @angular/common/HTTP. We have successfully performed post creation, edit and delete.  The below code doesn’t have featured image implementation, as we need to perform the additional task to post the media image first and then get its id to add in feature_image as the id of the image.

GET /wp-json/wp/v2/posts

The HTTP get method request on WordPress post lacks the support of a Featured image, as it returns only the media image id. We can use another endpoint reference as

GET /wp-json/wp/v2/posts?_embed

By simply appending ?_embed to our request will return additional information relating to the post like Featured Image, including URL for the various available sizes.

Ionic WordPress: List WordPress post Component

The posts component renders the list of posts. We have three-button one to add a new post, another to edit a post, and the other to view a post in detail. Add the following code in the posts.page.ts file

<ion-header>
  <ion-toolbar color="primary">
    <ion-buttons slot="primary">
      <ion-icon slot="icon-only" name="add-outline" routerLink="/posts/new"></ion-icon>
    </ion-buttons>
    <ion-title>Total posts {{ totalPost }}</ion-title>
  </ion-toolbar>
</ion-header>
 
<ion-content> 
  <ion-grid class="ion-no-padding">
    <ion-row>
      <ion-col size-sm="4" size="12" *ngFor="let post of posts">
        <ion-card>
          <ion-card-header class="ion-no-padding">
            <img [src]="post.media_url">
          </ion-card-header>
          <ion-card-content>
            <ion-text color="dark">
              <h2 [innerHTML]="post.title.rendered"></h2>
            </ion-text>
            <ion-button color="primary" size="small" fill="outline" class="ion-float-right" (click)="edit(post)">
              <ion-icon name="create-outline" slot="start"></ion-icon> Edit
            </ion-button>
            
            <ion-text>Date : {{ post.date_gmt |date: 'dd MMM yyy' }}</ion-text>
            <div [innerHTML]="post.excerpt.rendered"></div>
            <a class="ion-float-right" [routerLink]="['/', 'posts', post.id]">Read More</a>
          </ion-card-content>
        </ion-card>
      </ion-col>
    </ion-row>
  </ion-grid>

  <ion-infinite-scroll (ionInfinite)="loadMorePost($event)">
    <ion-infinite-scroll-content loadingText="Loading more posts...">
    </ion-infinite-scroll-content>
  </ion-infinite-scroll>
</ion-content>

Our posts component displays all posts as

import { Component, OnDestroy } from '@angular/core';
import { WordPressService } from '../../services/wordpress.service';
import { LoadingController } from '@ionic/angular';
import { Subscription } from 'rxjs';
import { Router } from '@angular/router';

@Component({
  selector: 'app-posts',
  templateUrl: './posts.page.html',
  styleUrls: ['./posts.page.scss'],
})
export class PostsPage implements OnDestroy {
  posts = [];
  page = 1;
  totalPost: number;
  postsSub: Subscription;

  constructor(
    private loadingCtrl: LoadingController,
    private router: Router,
    private wordpress: WordPressService) { }

  ionViewWillEnter() {
    this.getPosts();
  }

   async getPosts() {
    const loading = await this.loadingCtrl.create({
      message: 'Loading Data...'
    });
    await loading.present();
    this.postsSub = this.wordpress.getPosts().subscribe(data => {
      this.totalPost = this.wordpress.totalPost;
      this.posts = data;
      loading.dismiss();
    });
  }

  async loadMorePost(event) {
    if (this.page >= this.wordpress.pageCount) {
      event.target.disabled = true;
      return;
    }
    this.page++;
    const loading = await this.loadingCtrl.create({
      message: 'Loading Data...'
    });
    await loading.present();
    this.postsSub = this.wordpress.getPosts(this.page).subscribe(data => {
      this.posts = [...this.posts, ...data];
      this.page++;
      event.target.complete();
      loading.dismiss();
    });
  }

  edit(post: any) {
    /** Pass post data to edit page for modification */
    this.router.navigate(['posts/edit/'], {
      state: { post: JSON.stringify(post)}
    });
  }

  ngOnDestroy() {
    this.postsSub.unsubscribe();
  }
}

Ionic WordPress: Implementing EditPost component

We have editPost page in our Ionic WordPress project, this component we will implement adding new posts, editing existing post information like title, date of publishing, and content of the post, and deleting posts. For the post, put and delete method of HTTP we need the user token in the HTTP header to perform this operation. On the pots page, we have add button at the top and an edit button on each post. We had to implement our code in editPost.page.ts

<ion-header>
  <ion-toolbar color="primary">
    <ion-title *ngIf="!post" size="small">Add new post</ion-title>
    <ion-title *ngIf="post" size="small">Edit post</ion-title>
  </ion-toolbar>
</ion-header>
<ion-content>
  <form [formGroup]="form" class="ion-padding">
    <ion-item>
      <ion-label position="floating">{{ 'Title*' }}</ion-label>
      <ion-input formControlName="title"></ion-input>
    </ion-item>
    <ion-item>
      <ion-label position="floating">Date*</ion-label>
      <ion-datetime displayFormat="D MMM, YYYY" formControlName="date" [max]="maxDate"></ion-datetime>
    </ion-item>
    <ion-item>
      <ion-label position="floating">Content*</ion-label>
      <ion-textarea formControlName="content" rows="4"></ion-textarea>
    </ion-item>
  </form>
</ion-content>
<ion-footer>
  <ion-toolbar>
    <ion-button *ngIf="post" color="danger" size="small" (click)="delete()">Delete</ion-button>
    <ion-button color="primary" size="small" class="ion-float-right" (click)="submit(form.value)">
      Submit
    </ion-button>
  </ion-toolbar>
</ion-footer>
import { Component, OnInit, OnDestroy } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import * as dayjs from 'dayjs';
import { CommonService } from '../../../services/common.service';
import { WordPressService } from 'src/app/services/wordpress.service';
import { Router } from '@angular/router';
import { Subscription } from 'rxjs';

@Component({
  selector: 'app-edit-post',
  templateUrl: './edit-post.page.html',
  styleUrls: ['./edit-post.page.scss'],
})
export class EditPostPage implements OnInit, OnDestroy {
  form: FormGroup;
  post: any;
  postSub: Subscription;
  fileToUpload: File = null;

  constructor(
    private router: Router,
    private formBuilder: FormBuilder,
    private common: CommonService,
    private wordpress: WordPressService
  ) { this.createForm(); }

  ngOnInit() {
    /** Get post date on edit mode */
    if (this.router.getCurrentNavigation().extras.state) {
      const state = this.router.getCurrentNavigation().extras.state;
      this.post = state.post ? JSON.parse(state.post) : '';
    }
    if (this.post) {
      this.form.patchValue({
        title: this.post.title.rendered,
        date: this.post.date,
        content: this.post.content.rendered,
      });
    }
  }

  createForm() {
    this.form = this.formBuilder.group({
      title: ['', Validators.required ],
      date: [dayjs().format()],
      content: ['', Validators.required],
      status: 'publish',
    });
  }

  submit(form) {
    if (!this.form.valid) {
      this.common.showToast('Please fill all required field', 'error');
      return;
    }
    if (this.post) {
      /** Edit mode */
      for (const key in form) {
        if (form.hasOwnProperty(key)) {
          this.post[key] = form[key];
        }
      }
      this.wordpress.updatePost(this.post.id, this.post)
      .subscribe(() => {
        this.common.showToast('Update post successful', 'success');
        this.router.navigateByUrl('/posts');
      });
    } else {
      /** New post */
      this.wordpress.createPost(this.form.value)
      .subscribe(() => {
        this.common.showToast('Post add successful', 'success');
        this.router.navigateByUrl('/posts');
      });
    }
  }

  delete() {
    this.postSub = this.wordpress.deletePost(this.post.id).subscribe(() => {
      this.common.showToast('Delete post successful', 'success');
      this.router.navigateByUrl('');
    });
  }

  ngOnDestroy() {
    if (this.postSub) {
      this.postSub.unsubscribe();
    }
  }
}

Ionic WordPress Implementing post component

To display posts in detail we have a post component. When the user clicks on the read more button on the posts page will take you to a new page to display post detailed information about a post. We have our implementation of post.component.ts in Ionic WordPress project as

<ion-header>
  <ion-toolbar>
    <ion-title [innerHTML]="post?.title.rendered"></ion-title>
  </ion-toolbar>
</ion-header>

<ion-content class="ion-padding">
  <div *ngIf="post">
    <ion-grid>
      <ion-row>
        <ion-col size-sm="8" offset-sm="2">
          <img [src]="post.media_url" [style.width]="'100%'">
          <div [innerHTML]="post.content.rendered"></div>
        </ion-col>
      </ion-row>
    </ion-grid>
  </div>
</ion-content>
import { Component, OnInit, OnDestroy } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { WordPressService } from 'src/app/services/wordpress.service';
import { Subscription } from 'rxjs';

@Component({
  selector: 'app-post',
  templateUrl: './post.page.html',
  styleUrls: ['./post.page.scss'],
})
export class PostPage implements OnInit, OnDestroy {
  post: any;
  postSub: Subscription;

  constructor(
    private activatedRoute: ActivatedRoute,
    private wordpress: WordPressService
    ) { }

  ngOnInit() {
    const id = this.activatedRoute.snapshot.paramMap.get('id');
    this.postSub = this.wordpress.getPost(id).subscribe(data => {
      this.post = data;
    });
  }

  ngOnDestroy() {
    this.postSub.unsubscribe();
  }
}

Note we have created a common post module and routing for all post-related components on the post page. We also deleted the module and routing file of both editPost and post pages. We need to import both editPost and postPage components in our post.module.ts file in our Ionic WordPress app as

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ReactiveFormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { PostsPageRoutingModule } from './posts-routing.module';
import { PostsPage } from './posts.page';
import { PostPage } from './post/post.page';
import { EditPostPage } from './edit-post/edit-post.page';

@NgModule({
  imports: [
    CommonModule,
    ReactiveFormsModule,
    IonicModule,
    PostsPageRoutingModule
  ],
  declarations: [PostsPage, PostPage, EditPostPage]
})
export class PostsPageModule {}

Our common routing for all posts has the following implementations in Ionic WordPress app .

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { PostPage } from './post/post.page';
import { PostsPage } from './posts.page';
import { EditPostPage } from './edit-post/edit-post.page';

const routes: Routes = [
  { path: '', component: PostsPage },
  { path: 'new', component: EditPostPage },
  { path: 'edit', component: EditPostPage },
  { path: ':id', component: PostPage },
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule],
})
export class PostsPageRoutingModule {}

Our main app-routing.module.ts file has the following implementation, we don’t need to import editPost and post routing as both are children routes on the posts route.

import { NgModule } from '@angular/core';
import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
import { AuthGuard } from './auth/auth.guard';

const routes: Routes = [
  { path: '', redirectTo: 'post', pathMatch: 'full', canActivate: [AuthGuard] },
  {
    path: 'posts', loadChildren: () => import('./pages/posts/posts.module').then( m => m.PostsPageModule), canActivate: [AuthGuard]
  },
  {
    path: 'login',
    loadChildren: () => import('./auth/login/login.module').then( m => m.LoginPageModule)
  },
];

@NgModule({
  imports: [
    RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })
  ],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Conclusion
In this article, we have how to integrate WordPress with the Ionic framework, we can create, edit, update and list all posts from the WordPress websites. I hope you got some idea of how to integrate Ionic with WordPress.

Related posts

Ionic WordPress API – CRUD operation

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to top