UNPKG

frontitygit

Version:

A Frontity source package for the REST API of self-hosted and WordPress.com sites

156 lines (139 loc) 4.66 kB
import { Handler } from "../../../types"; import capitalize from "./utils/capitalize"; import { ServerError } from "@frontity/source"; import { PostTypeData } from "@frontity/source/types/data"; /** * The parameters for {@link postTypeHandler}. */ interface PostTypeHandlerParams { /** * The list of [WP REST API endpoints](https://developer.wordpress.org/rest-api/reference/) * from which the generated handler is going to fetch the data. */ endpoints: string[]; } /** * A {@link Handler} function generator for WordPress Post Types. * * This function will generate a handler function for specific * [WP REST API endpoints](https://developer.wordpress.org/rest-api/reference/) * from which the data is going to be fetched. The generated handler will fetch * data from all specified endpoints. * * @param options - Options for the handler generator: {@link PostTypeHandlerParams}. * * @example * ```js * const postTypeHandlerFunc = postTypeHandler({ endpoints: ['post']}); * libraries.source.handlers.push({ * name: "post type", * priority: 30, * pattern: "/(.*)?/:slug", * func: postTypeHandlerFunc, * }) * ``` * * @returns An async "handler" function that can be passed as an argument to the handler object. * This function will be invoked by the frontity framework when calling `source.fetch()` for * a specific entity. */ const postTypeHandler = ({ endpoints, }: PostTypeHandlerParams): Handler => async ({ link, params, state, libraries, force, }) => { // Name of the endpoint that returned an entity. // Used later in case this fetch is for a preview. let matchedEndpoint = ""; // 1. search id in state or get the entity from WP REST API const { route, query } = libraries.source.parse(link); const routeData: Partial<PostTypeData> = state.source.get(route); if (!routeData.id || force) { const { slug } = params; // 1.1 transform "posts" endpoint to state.source.postEndpoint const finalEndpoints = endpoints.map((endpoint) => endpoint === "posts" ? state.source.postEndpoint : endpoint ); // 1.2 iterate over finalEndpoints array let isHandled = false; let isMismatched = false; for (const endpoint of finalEndpoints) { const response = await libraries.source.api.get({ endpoint, params: { slug, _embed: true, ...state.source.params }, }); const populated = await libraries.source.populate({ response, state, force, }); // exit loop if this endpoint returns an entity! if (populated.length > 0) { // We have to check if the link property in the data that we // populated is the same as the current route. if (populated[0].link === route) { isHandled = true; isMismatched = false; matchedEndpoint = endpoint; break; } else { isMismatched = true; } } } if (isMismatched) { throw new ServerError( `You have tried to access content at route: ${route} but it does not exist`, 404 ); } // 1.3 if no entity has found, throw an error if (!isHandled) throw new ServerError( `post type from endpoints "${endpoints}" with slug "${slug}" not found`, 404 ); } // 2. get `type` and `id` from route data and assign props to data const { type, id }: Partial<PostTypeData> = state.source.get(route); const data = state.source.get(link); Object.assign(data, { type, link: link, query, id, isPostType: true, [`is${capitalize(type)}`]: true, }) as PostTypeData; // This ensures the resulting type is correct. // Overwrite properties if the request is a preview. if (query.preview && state.source.auth) { // Get entity from the state. const entity = state.source[type][id]; // Fetch the latest revision using the token. const response = await libraries.source.api.get({ endpoint: `${matchedEndpoint}/${id}/revisions?per_page=1`, params: state.source.params, auth: state.source.auth, }); // Get modified props from revision. const revision = await response.json(); if (revision.code) { console.log(revision); throw new ServerError(revision.message, revision.data.status); } const [json] = revision; if (json.parent === id) { const { title, content, excerpt } = json; // Merge props with entity. Object.assign(entity, { title, content, excerpt }); } else { // Error response. console.warn(json); } } }; export default postTypeHandler;