How to build a headless WordPress website with ReactJS & Frontity - Pt. 3
Adding content to your Frontity project is very simple. In fact, the Mars-Theme includes all of the components that will do the heavy lifting for you. Lets get started with where you'd expect: src/components/index.js
. This component will look something like the following:
import { Global, css, connect, styled, Head } from "frontity";
import Switch from "@frontity/components/switch";
import Header from "./header";
import List from "./list";
import Post from "./post";
import Loading from "./loading";
import Title from "./title";
import PageError from "./page-error";
/**
* Theme is the root React component of our theme. The one we will export
* in roots.
*
* @param props - The props injected by Frontity's {@link connect} HOC.
*
* @returns The top-level react component representing the theme.
*/
const Theme = ({ state }) => {
// Get information about the current URL.
const data = state.source.get(state.router.link);
return (
<>
{/* Add some metatags to the <head> of the HTML. */}
<Title />
<Head>
<meta name="description" content={state.frontity.description} />
<html lang="en" />
</Head>
{/* Add some global styles for the whole site, like body or a's.
Not classes here because we use CSS-in-JS. Only global HTML tags. */}
<Global styles={globalStyles} />
{/* Add the header of the site. */}
<HeadContainer>
<Header />
</HeadContainer>
{/* Add the main section. It renders a different component depending
on the type of URL we are in. */}
<Main>
<Switch>
<Loading when={data.isFetching} />
<List when={data.isArchive} />
<Post when={data.isPostType} />
<PageError when={data.isError} />
</Switch>
</Main>
</>
);
};
Above, I have highlighted in bold the parts of the component that will load the content. Much like in other React frameworks, Frontity uses a <Switch>
component for page routing and it contains a post.js
component which is where the WordPress data is actually fetched from.
The post.js
component will resemble the following:
import { useEffect } from "react";
import { connect, styled } from "frontity";
import Link from "./link";
import List from "./list";
import FeaturedMedia from "./featured-media";
/**
* The Post component that Mars uses to render any kind of "post type", like
* posts, pages, attachments, etc.
*
* It doesn't receive any prop but the Frontity store, which it receives from
* {@link connect}. The current Frontity state is used to know which post type
* should be rendered.
*
* @param props - The Frontity store (state, actions, and libraries).
*
* @example
* ```js
* <Switch>
* <Post when={data.isPostType} />
* </Switch>
* ```
*
* @returns The {@link Post} element rendered.
*/
const Post = ({ state, actions, libraries }) => {
// Get information about the current URL.
const data = state.source.get(state.router.link);
// Get the data of the post.
const post = state.source[data.type][data.id];
// Get the data of the author.
const author = state.source.author[post.author];
// Get a human readable date.
const date = new Date(post.date);
// Get the html2react component.
const Html2React = libraries.html2react.Component;
/**
* Once the post has loaded in the DOM, prefetch both the
* home posts and the list component so if the user visits
* the home page, everything is ready and it loads instantly.
*/
useEffect(() => {
actions.source.fetch("/");
List.preload();
}, [actions.source]);
// Load the post, but only if the data is ready.
return data.isReady ? (
<Container>
<div>
<Title dangerouslySetInnerHTML={{ __html: post.title.rendered }} />
{/* Hide author and date on pages */}
{!data.isPage && (
<div>
{author && (
<StyledLink link={author.link}>
<Author>
By <b>{author.name}</b>
</Author>
</StyledLink>
)}
<DateWrapper>
{" "}
on <b>{date.toDateString()}</b>
</DateWrapper>
</div>
)}
</div>
{/* Look at the settings to see if we should include the featured image */}
{state.theme.featured.showOnPost && (
<FeaturedMedia id={post.featured_media} />
)}
{data.isAttachment ? (
// If the post is an attachment, just render the description property,
// which already contains the thumbnail.
<div dangerouslySetInnerHTML={{ __html: post.description.rendered }} />
) : (
// Render the content using the Html2React component so the HTML is
// processed by the processors we included in the
// libraries.html2react.processors array.
<Content>
<Html2React html={post.content.rendered} />
</Content>
)}
</Container>
) : null;
};
I have highlighted the areas that will automatically fetch your content data and display it depending on whether it's a Page or a Post. This component fetches the data from Frontity state and will then conditionally render the parts of the page necessary for a Page or a Post. dangerouslySetInnerHTML
is used to set meta data such as "titles" and "descriptions", but the main page content data is displayed using one of Frontity's built-in libraries called html2react
. Frontity defines libraries as "a reusable set of tools. However, it is NOT aimed to change the state, but rather other parts of the application and is available for use by many packages". - https://docs.frontity.org/learning-frontity - Core concepts
By now your Frontity project will be displaying content and dynamic menus from your WordPress website. If you inspect the content in your browser inspector, you can see the class names of the divs and sections I recommended adding in the WordPress Block editor earlier (based on your own design). All that's left for you to do, is build out your design in components just like you would for any React application fetching various data from Frontity's API. CSS in JS is used for styling your application and means your CSS can be contained within each component. But why CSS in JS?
Because:
-
It Only loads the CSS needed for each page which improves the performance
-
You don't have to worry about classes and its problems with duplication, typos, etc
-
You don't have to worry about vendor prefixing so you can write your CSS based on the current standard and Frontity handles the rest for you
-
You can use all the power of JavaScript to style your components and create dynamic styles with much less code.
And there you have it, you're up and running with your first WordPress and Frontity app. Decoupled WordPress with Frontity and ReactJS. Enjoy!
Go back to... + How to build a headless WordPress website with Frontity / ReactJS - Pt. 1
This story is also available @ https://www.nmk.dev/post/how-to-build-a-headless-wordpress-website-with-frontity-reactjs-pt-3-ff98d654ac75