UNPKG

@frontity/yoast

Version:

Integrate your Frontity site with Yoast SEO plugin.

107 lines (92 loc) 2.97 kB
import { useMemo } from "react"; import { decode, useConnect } from "frontity"; import { transformAllLinks } from "../utils"; import { Packages, WithYoastHead } from "../../types"; import { isPostType, isTerm, isAuthor, isPostTypeArchive, } from "@frontity/source"; /** * Object returned for {@link useYoastHead} hook. */ interface UseYoastHeadResult { /** * The <title> tag content. */ title?: string; /** * All the head tags in string format. */ head?: string; } /** * Hook that returns either the content of the <title> tag or all the head tags. * * @param link - Link pointing to a page in Frontity. * @returns Object of type {@link UseYoastHeadResult}. */ export const useYoastHead = (link: string): UseYoastHeadResult => { const { state } = useConnect<Packages>(); // Get the data object associated to link. const data = state.source.get(link); // Get the entity pointed by the given link. let entity: WithYoastHead = null; // Entities are stored in different places depending on their type. if (isPostType(data)) { const { type, id } = data; entity = state.source[type][id]; } else if (isTerm(data)) { const { taxonomy, id } = data; entity = state.source[taxonomy][id]; } else if (isAuthor(data)) { const { id } = data; entity = state.source.author[id]; } else if (isPostTypeArchive(data)) { const { type } = data; entity = state.source.type[type]; } // Get the `yoast_head` field from entity. const html = entity?.yoast_head || ""; const shouldUseTitle = state.yoast.renderTags === "server" && state.frontity.rendering === "csr"; const shouldTransformLinks = !!state.yoast.transformLinks; let ignore = ""; let base = ""; let newBase = ""; // Props to replace all links present in `yoast_head`. if (state.yoast.transformLinks) { ignore = state.yoast.transformLinks.ignore; base = state.yoast.transformLinks.base || state.source.url.replace(/\/?$/, "/"); newBase = state.frontity.url; } // Return a memoized object depending on the previously generated values. return useMemo(() => { /** * Extract the title string from the `yoast_head` field and return it if * found. */ if (shouldUseTitle) { const titleMatch = /<title>(.+)<\/title>/.exec(html); if (titleMatch) { return { title: decode(titleMatch[1]) }; } } // Transform links in the `yoast_head` string and return it. if (html && shouldTransformLinks) { const head = transformAllLinks({ html, ignore, base, newBase }); return { head }; } // Return just the `yoast_head` string. if (html && !shouldTransformLinks) { return { head: html }; } /** * Return an empty object if neither the title nor the head tags are going * to be rendered for this link. */ return {}; }, [shouldUseTitle, shouldTransformLinks, html, ignore, base, newBase]); };