Part 1 can be found here
Showing the featured image on the home page
First update the rxjs imports in the wordpress-restapi.service.ts
with the following imports.
import { Observable, forkJoin, throwError, empty, of } from 'rxjs';
import { catchError, map, mergeMap } from 'rxjs/operators';
At the bottom of the wordpress-restapi.service.ts
add a new Media class object to hold a posts featured media data.
export class Media {
date: string;
date_gmt: string;
guid: object;
id: number;
link: string;
modified: string;
modified_gmt: string;
slug: string;
status: string;
type: string;
title: object;
author: number;
comment_status: string;
ping_status: string;
meta: object;
template: string;
alt_text: string;
caption: object;
description: object;
media_type: string;
mime_type: string;
media_details: object;
post: number;
source_url: string;
constructor(values: Object = {}) {
Object.assign(this, values);
}
hasThumbnail() {
if (Object.keys(this).length > 0) {
return true;
}
return false;
}
getThumbnail(size: string = 'thumbnail') {
if (this.media_details.hasOwnProperty('sizes')) {
if (size == 'full') {
return this.media_details['sizes'].full.source_url;
}
if (size == 'medium') {
return this.media_details['sizes'].medium.source_url;
}
return this.media_details['sizes'].thumbnail.source_url;
}
return;
}
}
Then update the getRecentPosts() method with the following.
getRecentPosts(categoryId: number, page: number = 1): Observable<any> {
// Get posts by a category if a category id is passed
let category_url = categoryId ? ("&categories=" + categoryId) : "";
return this.httpClient.get(this.baseRestApiUrl + "posts?page=" + page + category_url).pipe(
map((res: any) => res),
mergeMap((posts: Post[]) => {
if (posts.length > 0) {
return forkJoin(
posts.map((post: Post) => {
if (post.featured_media === 0) {
post.media = new Media;
return of(new Post(post));
}
else {
return this.httpClient.get(this.baseRestApiUrl + "media/" + post.featured_media).pipe(
map((res: any) => {
post.media = new Media(res);
return new Post(post);
}),
catchError(val => of(val))
);
}
})
);
}
return empty();
}),
catchError(val => of(val))
);
}
The updated method uses mergmap and forkJoin to get a posts media if it has any.
In the home.page.html file update the ion-item with the following code snippet.
<ion-item *ngFor="let post of posts" (click)="openPost(post.id)">
<ion-thumbnail *ngIf="post.media.hasThumbnail()" slot="end">
<ion-img [src]="post.media.media_details.sizes.thumbnail.source_url"></ion-img>
</ion-thumbnail>
<ion-label [innerHTML]="post.title.rendered" text-wrap></ion-label>
<span [innerHTML]="post.date | date:longDate" class="post-date"></span>
</ion-item>
If there is a featured image to show then it will add a thumbnail image to the end of the ion-item.
Showing the featured image, categories, tags and comments on the post page.
Update the wordpress-restapi.service.ts
s with class objects for Tag, Category and Comment.
export class Tag {
id: number;
count: number;
description: string;
link: string;
name: string;
slug: string;
taxonomy: string;
meta: object;
constructor(values: Object = {}) {
Object.assign(this, values);
}
}
export class Category {
id: number;
count: number;
description: string;
link: string;
name: string;
slug: string;
taxonomy: string;
parent: number;
meta: object;
constructor(values: Object = {}) {
Object.assign(this, values);
}
}
export class Comment {
id: number;
author: number;
author_email: string;
author_ip: string;
author_name: string;
author_url: string;
author_user_agent: string;
content: object;
date: string;
date_gmt: string;
link: string;
parent: number;
post: number;
status: string;
type: string;
author_avatar_urls: object;
meta: object;
constructor(values: Object = {}) {
Object.assign(this, values);
}
}
Next create methods to get the featured media, tags, categories, and comments from the WordPress API.
getTags(post) {
let observableBatch = [];
post.tags.forEach(tag => {
observableBatch.push(this.getTag(tag));
});
return forkJoin(observableBatch);
}
getTag(tagId: number): Observable<Tag> {
return this.httpClient.get(this.baseRestApiUrl + "tags/" + tagId).pipe(
map(tag => {
return new Tag(tag);
}),
catchError(val => of(val))
);
}
getComments(postId: number, page: number = 1) {
return this.httpClient.get(this.baseRestApiUrl + "comments?post=" + postId).pipe(
map(comments => {
let commentsArray = [];
Object.keys(comments).forEach(function (key) {
commentsArray.push(new Comment(comments[key]));
});
return commentsArray;
}),
catchError(val => of(val))
);
}
getCategories(post) {
let observableBatch = [];
post.categories.forEach(category => {
observableBatch.push(this.getCategory(category));
});
return forkJoin(observableBatch);
}
getCategory(categoryid: number): Observable<Category> {
return this.httpClient.get(this.baseRestApiUrl + "categories/" + categoryid).pipe(
map(category => {
return new Category(category);
}),
catchError(val => of(val))
);
}
getMedia(mediaId: number): Observable<Media> {
if (mediaId > 0) {
return this.httpClient.get(this.baseRestApiUrl + "media/" + mediaId).pipe(
map(media => {
return new Media(media);
}),
catchError(val => of(val))
);
}
return of(new Media);
}
Now update the getPost() method in wordpress-restapi.service.ts
to get the featured media, tags, categories and comments along with the post data.
getPost(postId) {
return this.httpClient.get(this.baseRestApiUrl + "posts/" + postId).pipe(
map((res: any) => res),
flatMap((post: any) => {
return forkJoin(
of(new Post(post)),
this.getComments(post.id),
this.getMedia(post.featured_media),
this.getTags(post),
this.getCategories(post)
)
})
);
}
Next update the post.page.html
to display the post along with the featured image, categories, tags and comments.
<ion-header>
<ion-toolbar>
<ion-title>Post</ion-title>
<ion-buttons slot="start">
<ion-back-button defaultHref="/"></ion-back-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content padding>
<figure *ngIf="media.hasThumbnail()">
<ion-img [src]="media.getThumbnail('full')"></ion-img>
</figure>
<h1 *ngIf="post.title" [innerHTML]="post.getTitle()"></h1>
<p *ngIf="post.date" [innerHTML]="post.getDate()"></p>
<p *ngIf="categories.length">
Posted in: <span *ngFor="let category of categories; let isLast=last">{{category.name}}{{isLast ? '' : ', '}}</span>
</p>
<p *ngIf="tags.length">
Tagged: <span *ngFor="let tag of tags; let isLast=last">#{{tag.name}}{{isLast ? '' : ', '}}</span>
</p>
<div *ngIf="post.content" [innerHTML]="post.content.rendered"></div>
<div *ngIf="comments.length" class="posts-comments-wrapper">
<p class="bold-title">Comments:</p>
<ion-item *ngFor="let comment of comments">
<ion-avatar item-start>
<img src="{{comment.author_avatar_urls[24]}}">
</ion-avatar>
<div>{{comment.author_name}}</div>
<p [innerHTML]="comment.content.rendered"></p>
</ion-item>
</div><!-- /.post-comments-wrapper-->
</ion-content>
Update the post.page.ts
file with the following code.
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { LoadingController } from '@ionic/angular';
import { WordPressRestapiService, Post, Media, Tag, Category, Comment } from '../services/wordpress-restapi.service';
@Component({
selector: 'app-post',
templateUrl: './post.page.html',
styleUrls: ['./post.page.scss'],
})
export class PostPage implements OnInit {
id: string;
private post: Post = new Post;
private media: Media = new Media;
private tags: Tag[] = [];
private categories: Category[] = [];
private comments: Comment[] = [];
constructor(
public loadingController: LoadingController,
private route: ActivatedRoute,
private wordpressService: WordPressRestapiService) { }
async ngOnInit() {
const loading = await this.loadingController.create();
await loading.present();
this.id = this.route.snapshot.paramMap.get('id');
this.getPost(this.id).subscribe((data: any) => {
this.post = data[0];
this.comments = data[1];
this.media = data[2];
this.tags = data[3];
this.categories = data[4];
loading.dismiss();
});
}
getPost(postId) {
return this.wordpressService.getPost(postId);
}
}
In the next part I’ll look at;
- Infinite Scroll
- Browsing by category and tags