Files
myeasycms-v2/packages/cms/wordpress/src/wp-client.ts
giancarlo 35ef90b4f8 Update Supabase dependency, delete cookie handling, create logger
Updated Supabase dependency across multiple packages from "^2.41.1" to "^2.42.0". Removed files handling sidebar state and theme cookies. Created a new Logger interface for managing log messages in the shared package. Enhanced the middleware to track accounts membership webhook payload. Minor adjustments were also made in multiple package.json files.
2024-04-03 23:59:41 +08:00

345 lines
8.6 KiB
TypeScript

import type {
WP_REST_API_Category,
WP_REST_API_Post,
WP_REST_API_Tag,
} from 'wp-types';
import { Cms, CmsClient } from '@kit/cms';
import GetTagsOptions = Cms.GetTagsOptions;
/**
* @name WordpressClient
* @description Represents a client for interacting with a Wordpress CMS.
* Implements the CmsClient interface.
*/
export class WordpressClient implements CmsClient {
private readonly apiUrl: string;
constructor(apiUrl = process.env.WORDPRESS_API_URL as string) {
this.apiUrl = apiUrl;
}
/**
* Retrieves content items from a CMS based on the provided options.
*
* @param {Cms.GetContentItemsOptions} options - The options to customize the retrieval of content items.
*/
async getContentItems(options?: Cms.GetContentItemsOptions) {
const queryParams = new URLSearchParams({
_embed: 'true',
});
if (options?.limit) {
queryParams.append('per_page', options.limit.toString());
}
if (options?.offset) {
queryParams.append('offset', options.offset.toString());
}
if (options?.categories) {
const ids = await this.getCategories({
slugs: options.categories,
}).then((categories) => categories.map((category) => category.id));
if (ids.length) {
queryParams.append('categories', ids.join(','));
} else {
console.warn(
'No categories found for the provided slugs',
options.categories,
);
}
}
if (options?.tags) {
const ids = await this.getCategories({
slugs: options.tags,
}).then((tags) => tags.map((tag) => tag.id));
if (ids.length) {
queryParams.append('tags', ids.join(','));
} else {
console.warn('No tags found for the provided slugs', options.tags);
}
}
if (options?.parentIds && options.parentIds.length > 0) {
queryParams.append('parent', options.parentIds.join(','));
}
const endpoints = [
`/wp-json/wp/v2/pages?${queryParams.toString()}`,
`/wp-json/wp/v2/posts?${queryParams.toString()}`,
];
const urls = endpoints.map((endpoint) => `${this.apiUrl}${endpoint}`);
const responses = await Promise.all(
urls.map((url) =>
fetch(url).then((value) => value.json() as Promise<WP_REST_API_Post[]>),
),
).then((values) => values.flat().filter(Boolean));
return await Promise.all(
responses.map(async (item: WP_REST_API_Post) => {
let parentId: string | undefined;
if (!item) {
throw new Error('Failed to fetch content items');
}
if (item.parent) {
parentId = item.parent.toString();
}
const author = await this.getAuthor(item.author);
const categories = await this.getCategoriesByIds(item.categories ?? []);
const tags = await this.getTagsByIds(item.tags ?? []);
const image = item.featured_media ? this.getFeaturedMedia(item) : '';
const order = item.menu_order ?? 0;
return {
id: item.id.toString(),
title: item.title.rendered,
content: item.content.rendered,
description: item.excerpt.rendered,
image,
url: item.link,
slug: item.slug,
publishedAt: new Date(item.date),
author: author?.name,
categories: categories,
tags: tags,
parentId,
order,
children: [],
};
}),
);
}
async getContentItemById(slug: string) {
const searchParams = new URLSearchParams({
_embed: 'true',
slug,
});
const endpoints = [
`/wp-json/wp/v2/pages?${searchParams.toString()}`,
`/wp-json/wp/v2/posts?${searchParams.toString()}`,
];
const promises = endpoints.map((endpoint) =>
fetch(this.apiUrl + endpoint).then(
(res) => res.json() as Promise<WP_REST_API_Post[]>,
),
);
const responses = await Promise.all(promises).then((values) =>
values.filter(Boolean),
);
const item = responses[0] ? responses[0][0] : undefined;
if (!item) {
return;
}
const author = await this.getAuthor(item.author);
const categories = await this.getCategoriesByIds(item.categories ?? []);
const tags = await this.getTagsByIds(item.tags ?? []);
const image = item.featured_media ? this.getFeaturedMedia(item) : '';
return {
id: item.id.toString(),
image,
order: item.menu_order ?? 0,
url: item.link,
description: item.excerpt.rendered,
children: [],
title: item.title.rendered,
content: item.content.rendered,
slug: item.slug,
publishedAt: new Date(item.date),
author: author?.name,
categories,
tags,
parentId: item.parent?.toString(),
};
}
async getCategoryBySlug(slug: string) {
const url = `${this.apiUrl}/wp-json/wp/v2/categories?slug=${slug}`;
const response = await fetch(url);
const data = await response.json();
if (data.length === 0) {
return;
}
const item = data[0] as WP_REST_API_Category;
return {
id: item.id.toString(),
name: item.name,
slug: item.slug,
};
}
async getTagBySlug(slug: string) {
const url = `${this.apiUrl}/wp-json/wp/v2/tags?slug=${slug}`;
const response = await fetch(url);
const data = await response.json();
if (data.length === 0) {
return;
}
const item = data[0] as WP_REST_API_Tag;
return {
id: item.id.toString(),
name: item.name,
slug: item.slug,
};
}
async getCategories(options?: Cms.GetCategoriesOptions) {
const queryParams = new URLSearchParams();
if (options?.limit) {
queryParams.append('per_page', options.limit.toString());
}
if (options?.offset) {
queryParams.append('offset', options.offset.toString());
}
if (options?.slugs) {
const slugs = options.slugs.join(',');
queryParams.append('slug', slugs);
}
const response = await fetch(
`${this.apiUrl}/wp-json/wp/v2/categories?${queryParams.toString()}`,
);
if (!response.ok) {
console.error('Failed to fetch categories', await response.json());
throw new Error('Failed to fetch categories');
}
const data = (await response.json()) as WP_REST_API_Category[];
return data.map((item) => ({
id: item.id.toString(),
name: item.name,
slug: item.slug,
}));
}
async getTags(options: GetTagsOptions) {
const queryParams = new URLSearchParams();
if (options?.limit) {
queryParams.append('per_page', options.limit.toString());
}
if (options?.offset) {
queryParams.append('offset', options.offset.toString());
}
if (options?.slugs) {
const slugs = options.slugs.join(',');
queryParams.append('slug', slugs);
}
const response = await fetch(
`${this.apiUrl}/wp-json/wp/v2/tags?${queryParams.toString()}`,
);
if (!response.ok) {
console.error('Failed to fetch tags', await response.json());
throw new Error('Failed to fetch tags');
}
const data = (await response.json()) as WP_REST_API_Tag[];
return data.map((item) => ({
id: item.id.toString(),
name: item.name,
slug: item.slug,
}));
}
private async getTagsByIds(ids: number[]) {
const promises = ids.map((id) =>
fetch(`${this.apiUrl}/wp-json/wp/v2/tags/${id}`),
);
const responses = await Promise.all(promises);
const data = (await Promise.all(
responses.map((response) => response.json()),
)) as WP_REST_API_Tag[];
return data.map((item) => ({
id: item.id.toString(),
name: item.name,
slug: item.slug,
}));
}
private async getCategoriesByIds(ids: number[]) {
const promises = ids.map((id) =>
fetch(`${this.apiUrl}/wp-json/wp/v2/categories/${id}`),
);
const responses = await Promise.all(promises);
const data = (await Promise.all(
responses.map((response) => response.json()),
)) as WP_REST_API_Category[];
return data.map((item) => ({
id: item.id.toString(),
name: item.name,
slug: item.slug,
}));
}
private async getAuthor(id: number) {
const response = await fetch(`${this.apiUrl}/wp-json/wp/v2/users/${id}`);
if (!response.ok) {
return undefined;
}
const data = await response.json();
return { name: data.name };
}
private getFeaturedMedia(post: WP_REST_API_Post) {
const embedded = post._embedded ?? {
'wp:featuredmedia': [],
};
const media = embedded['wp:featuredmedia'] ?? [];
const item = media?.length > 0 ? media[0] : null;
return item
? (
item as {
source_url: string;
}
).source_url
: '';
}
}