@frontity/wp-source

API reference of `@frontity/wp-source` package

This package is in charge of getting the data from self-hosted WordPress or WordPress.com sites, and make it available from our React components.

Table of Contents

Installation

Add the wp-source package to your project:

npm i @frontity/wp-source

Both of the starter themes (@frontity/mars-theme & @frontity/twentytwenty-theme) available when doing npx frontity create already include this wp-source package

Settings

This package needs to be included in your frontity.settings.js file as one of the packages that will be part of the Frontity project:

module.exports = {
packages: [
"@frontity/mars-theme",
"@frontity/tiny-router",
{
name: "@frontity/wp-source",
state: {
source: {
api: "https://site.com/wp-json",
},
},
},
],
};

These are the settings you can configure for this package in your frontity.settings.js file:

REST API

state.source.url ​

The URL of your WordPress backend installation. The default value of this property is derived from state.frontity.url.

Example:

// frontity.settings.js
export default {
packages: [
{
name: "@frontity/wp-source",
state: {
source: {
url: "https://test.frontity.org",
},
},
},
],
};

If you are using Frontity using the Embedded Mode, you do not normally have to set this property as your state.source.url will be the same as the state.frontity.url.

state.source.api

The URL of your WordPress REST API endpoint.

Typically, you will not need to set it yourself, as its value can usually be computed from the value of state.source.url.

If your WordPress site is hosted on wordpress.com and you are on a Free, Personal or Premium plan, you will also need to set state.wpSource.isWpCom to true, so the proper URL is assigned to state.source.api.

For example, assuming that you have

...
state: {
source: {
url: "https://my-awesome-site.com",
},
},
...
  • If you are self-hosting your WordPress installation or using a third party hosting like WP Engine, Pantheon, etc., the value of state.source.api would be https://my-awesome-site.com/wp-json

  • If you are on a Free, Personal or Premium wordpress.com plan (and you set state.wpSource.isWpCom = true) this value of state.source.api would be https://public-api.wordpress.com/wp/v2/sites/my-awesome-site.com.

You can also directly set to state.source.api the URL of your WordPress REST API endpoint. This will overwrite any computed values got from other properties.

Example:

// frontity.settings.js
export default {
packages: [
{
name: "@frontity/wp-source",
state: {
source: {
api: "https://test.frontity.org/wp-json",
},
},
},
],
};

or for a wordpress.com site...

// frontity.settings.js
export default {
packages: [
{
name: "@frontity/wp-source",
state: {
source: {
api:
"https://public-api.wordpress.com/wp/v2/sites/frontitytest.wordpress.com",
},
},
},
],
};

state.wpSource.isWpCom

Boolean value to indicate if the WordPress installation used as the source of data is a wordpress.com site (Free, Personal or Premium plan).

However, if your WordPress site is hosted on wordpress.com and you are on Free, Personal or Premium plan, you will need to set this value to true

You don't need to set this value if you directly set the URL of your wordpress.com REST API in state.source.api.

Example:

// frontity.settings.js
export default {
packages: [
{
name: "@frontity/wp-source",
state: {
source: {
url: "https://frontitytest.wordpress.com",
},
wpSource: {
isWpCom: true,
},
},
},
],
};

is equivalent to...

// frontity.settings.js
export default {
packages: [
{
name: "@frontity/wp-source",
state: {
source: {
api:
"https://public-api.wordpress.com/wp/v2/sites/frontitytest.wordpress.com",
},
},
},
],
};

state.wpSource.prefix

By using this property you can specify the prefix of your REST API, for example "/wp-json" or "?rest_route=/". The default value is "/wp-json".

This option should only be set if you have changed the path to the REST API endpoint in your WordPress installation. If you have not done that or you're not sure what it means, you can safely ignore this option.

Custom paths

state.source.subdirectory

A name or path indicating the subdirectory of your domain where your Frontity site lives. For example, if your site is in https://mysite.com/blog, you have to use it with the value of blog or /blog. It also transform links of the entities that come from the REST API.

state.source.homepage

This option allows you to show a specific page when accessing the homepage of your site. For example, if you set this value to /about-us then that page will be shown if you access /.

You have to configure your WordPress with the same setting.

As this option overrides the / route, you should set state.source.postsPage as well in order to be able to access the posts archive in a different route.

state.source.postsPage

This option allows you to show the posts archive when accessing a specific URL of your site, instead of the homepage. For example, if you set this value to /blog, then the posts archive will be shown if you access /blog instead of /. It is useful when used in combination with state.source.homepage.

You have to configure your WordPress with the same setting.

state.source.categoryBase

Change the base prefix of URLs for category pages with the indicated one.

For this option to work well, you have to put the same value in the WordPress site options.

state.source.tagBase

Change the base prefix of URLs for tag pages with the indicated one.

For this option to work well, you have to put the same value in the WordPress site options.

state.source.postEndpoint

Set the endpoint against which calls to the REST API are made when posts are requested, i.e. when fetching a single post, the post archive, date archives, categories, tags, authors, etc. This is useful when you want to use another post type as your default, for example β€œproducts”.

The default value is "posts".

Custom requests

state.source.params

Object of params that will be used in every call to the WP REST API when using actions.source.fetch. This is useful to filter fields from the REST API, change the default per_page value and so on. For example, if you set this value to

module.exports = {
packages: [
{
name: "@frontity/wp-source",
state: {
source: {
api: "https://site.com/wp-json",
params: {
per_page: 5,
type: ["post", "page"],
},
},
},
},
],
};

and then you visit a URL (or use actions.source.fetch), the query part of the HTTP call to the REST API will be per_page=5&type[]=post&type[]=page.

Custom Post Types

state.source.postTypes

This option allows you to show the Custom Post Types you create at WordPress when accessing their URLs. It is an array of objects, each object being a different CPT. It has three arguments:

Name

Type

Required

Description

type

string

yes

The slug you configured for your Custom Post Type

endpoint

string

yes

REST API endpoint from where this post type can be fetched.

archive

string

no

the URL of the archive of this Custom Post Type, where all of them are listed.

Differentiating type and endpoint may be confusing as they are usually the same. You can confirm you are doing it correctly going to the CPT endpoint :

So in this case, the settings would be:

postTypes: [
{
type: "movies",
endpoint: "movies",
archive: "/movies_archive",
},
];

state.source.taxonomies

Similar to postTypessetting, this one allows you to show the lists of posts of a Custom Taxonomies you create at WordPress when accessing their URLs. It is an array of objects, each object being a different Custom Taxonomy. It has four arguments:

Name

Type

Required

Description

taxonomy

string

yes

Taxonomy slug. The slug you configured for your Custom Taxonomy.

endpoint

string

yes

REST API endpoint from where this post type can be fetched.

postTypeEndpoint

string

no

REST API endpoint from which posts of this taxonomy can be fetched. If the Custom Taxonomy is meant to load Custom Post Types instead, you have to add its endpoint here. To clarify, although optional for posts in the case of a Custom Post Type this argument is required. Default value is posts

params

object

no

Extra params to be used while fetching the list of posts.

gain, dfferentiating taxonomy and endpointmay be confusing as they usually are the same too. You can confirm you are doing it correctly by going to the Custom Taxonomy endpoint :

Note that in this case taxonomyand endpointare different. In the next example, we will fetch CPT "movies" instead of "posts", and add some params. It would be something like this:

taxonomies: [
{
taxonomy: "actors",
endpoint: "actor",
postTypeEndpoint: "movies",
params: {
per_page: 5,
_embed: true,
},
},
];

How to use

This package will automatically retrieve data from the related WordPress routes when accesing a React route.

The data got from WordPress REST API is organized and normalized in the state. This "normalization" of the data means the data is organized in the state in a way so there's no duplicated data in it and there's only one source of truth.

The state works with two main concepts: links and entities.

The state is designed so that you can know which entities correspond to which link, and then access the data of these entities in a simple way.

Because of this there's a 2 step process to get the information from a link:

  1. Get the data related to the link

  2. Get the data related to the entities available in that link

For the data to exist, it will be necessary to request them previously using the fetch action.

import React, { useEffect } from "react";
import { connect } from "frontity";
​
// In a React component that uses "connect":
const CategoryNature = ({ state, actions }) => {
// 1. fetch data related to a path
// With this useEffect we make the call to fetch
// only the first time the component is rendered.
// When the data is fetched, the state is updated with the new data
// so the component is re-rendered and "data" will get proper content
​
useEffect(() => {
actions.source.fetch("/category/nature/");
}, []);
​
// 2. get data from frontity state
const data = state.source.get("/category/nature/");
​
// 3. get entities from frontity state
if (data.isCategory) {
// the category entity
const category = state.source.category[data.id];
​
// posts from that category
const posts = data.items.map(({ type, id }) => state.source[type][id]);
​
// 4. render!
return (
<>
<h1>{category.name}</h1>
{posts.map((p) => (
<a href={p.link}>{p.title.rendered}</a>
))}
</>
);
}
​
return null;
};
​
export default connect(CategoryNature);

​

If you want to know more about how to use the wp-source package, here you have some videos where Frontity DevRel team talks about it:

API Reference

The wp-source package implements the interface defined in the source package and adds some extra API​

Actions

Actions don't return data. Data is always accessed via the state. That's because Frontity is following the Flux pattern (like Redux).

Read more about actions here​

actions.source.fetch()

This action fetches all entities related to a link, i.e. the pathname of a URL in your site.

It populates the state with both:

  • An entry in state.source.data with information about that link.

  • Normalized entities in relevant part of the state, like state.source.post, state.source.category or state.source.author and so on.

Syntax

(link: string, options: object) => Promise`

Arguments

Name

Type

Required

Description

link

string

yes

Link representing a REST API endpoint or custom handler

options

object

no

REST API endpoint from where this post type can be fetched.

options.force

boolean

-

The entities should be fetched again.

Return value

Type

Description

Promise

it doesn't return data but a promise that is resolved when the action is finished (and state is updated)

All received data are populated in state.source and are accessible using the methods explained in the next section.

actions.source.fetch("/category/nature/");

Even though actions don't return data, they return a promise that resolves when the action is finished.

So, you can do something like this:

await actions.source.fetch("/some-post");

which is useful when you need to access the new state just after calling the action:

await actions.source.fetch("/some-post"); // <- Wait until we fetch "/some-post".
const somePost = state.source.get("/some-post"); // <- The data will exist.

In React components, you won't need to use async/await with fetch because:

const SomePost = ({ actions, state }) => {
useEffect(() => {
// No need to use `async/await` here
actions.source.fetch("/some-post");
}, []);
​
// The data will not exist at first, `dataPost.isReady` will be false.
// But then, it will rerender when `actions.source.fetch` is finished.
const dataPost = state.source.get("/some-post");
​
// This will work just fine.
return dataPost.isReady ? <Post link="/some-post" /> : <Loading />;
};

When fetch is called again for the same link it does nothing, as all the entities have already been fetched and there is no need to request them again. If you do want to fetch them again, you can pass an options object to source.fetch with force: true:

actions.source.fetch("/category/nature/", { force: true });

State

state.source.get()

Returns an object that gives you info about the type of that link and related entities.

Syntax

(link: string) => object`

Arguments

Name

Type

Required

Description

link

string

yes

Link representing a REST API endpoint or custom handler

Return value

Type

Description

object

Info about the type of data represented in the URL

Fr exampe:

state.source.get("/category/nature/");

will return something like

{
// Entity properties.
taxonomy: "category",
id: 7,
link: "/category/nature/page/3?s=park",
query: {
s: "park"
},
​
// Booleans that identify the type of link.
isArchive: true,
isCategory: true,
isTaxonomy: true,
​
// Booleans that show the fetch status.
isFetching: false,
isReady: true,
​
// Archive properties.
items: [{ type: "post", id: 60, link: "..." }, ...],
total: 53,
totalPages: 6,
page: 3,
route: "/category/nature",
next: "/category/nature/page/4?s=park",
previous: "/category/nature/page/2?s=park",
​
// Search properties.
isSearch: true,
searchQuery: "park",
}

The information to distinguish each type of link is based on the WP Template Hierarchy and is as follows:

  • archives: isArchive

    • taxonomy: isTaxonomy

      • category: isCategory

      • tag: isTag

      • deal: isDeal

    • author: isAuthor

    • postTypeArchive: isPostTypeArchive

      • post: isHome, isPostArchive (isFrontPage optional)

      • product: isProductArchive

    • date: isDate

  • postTypes: isPostType

    • post: isPost

    • page: isPage (isFrontPage optional)

    • product: isProduct

    • media: isMedia, isAttachment

  • 404: is404

Additionally, if calling get() has returned a status code higher than 400, we add information about the error to the state. For example, if an error code was 500, the state will include the following properties:

{
isError: true,
is500: true,
errorStatus: 500,
errorStatusText: "Some string describing the error",
​
// booleans that describe the fetch status
isReady: true,
isFetching: false
}

Properties added to each type are also based on the WP REST API:

  • taxonomy: taxonomy, id

  • author: id

  • postTypeArchive: type

  • date: year, month, date

  • postType: type, id

state.source[taxonomy][id]

Access category, tag, or custom taxonomy’s entities. These entities have the same schema as specified in the WP REST API.

We are actually changing the WP REST API response, but only for tags, in which we are replacing the taxonomy value from post_tag to tag.

source.category[2]
source.tag[13]
source.deal[3]

state.source[type][id]

Access posts, pages, attachments or custom post type’s entities. These entities have the same schema as specified in the WP REST API.

source.post[60]
source.page[7]
source.product[36]

state.source.author[id]

Access author entities. These entities have the same schema as specified in the WP REST API.

source.author[4]

Libraries

libraries.source.api.init()

Set the URL to the WordPress REST API.

Syntax

(options: object) => Promise;

Arguments

Name

Type

Required

Description

options

object

yes

options object

options.api

string

yes

URL pointing to a valid WP REST API.

options.isWpCom

boolean

no

if the WP REST route is from a WordPress.com hosted site.

Example

const { api } = libraries.source;
​
// for wp.org
api.init({
api: "https://test.frontity.io/wp-json",
isWpCom: false,
});
​
// for wp.com
api.init({
api: "https://public-api.wordpress.com/wp/v2/sites/test.frontity.io",
isWpCom: false,
});

libraries.source.api.get()

Request entity from the WordPress REST API.

Syntax

(options: object) => Promise;

Arguments

Name

Type

Required

Description

options

object

yes

options object

options.endpoint

string

yes

Name of the endpoint if is a /wp/v2 endpoint (e.g. posts), or the full path of other REST endpoints (e.g. /acf/v3/posts).

options.params

object

no

Any parameter that will be included in the query params.

options.api

string

no

Overrides the value set with api.set.

options.isWpCom

boolean

no

Overrides the value set with api.set.

Return value

Type

Description

Promise

it doesn't return data but a promise that is resolved when the action is finished (and state is updated)

For more info, visit the WP REST API reference.

Example

const { api } = libraries.source;
​
// Get posts from categories 2, 3 and 4
const postsCategories = await api.get({
endpoint: "posts",
params: { _embed: true, categories: "2,3,4" },
});
​
// Get the page 14
const page14 = await api.get({
endpoint: "pages",
params: { _embed: true, include: "14" },
});
​
// Other endpoints:
const postBeautiesGullfoss = await api.get({
endpoint: "/acf/v3/posts",
params: { slug: "/the-beauties-of-gullfoss" },
});

libraries.source.populate()

Add entities to the Frontity state.

(options: object) => Promise;

Arguments

Name

Type

Required

Description

options

object

yes

Options object

options.response

oject

yes

The response object returned by api.get().

options.state

object

yes

The tate object from the Frontity store.

options.subdirectory

strin

no

Domain's subdirectory where your Frontity site is accessible. When this options is passed, this subdirectory is added to the entities' links. </br> Default Value is value defined in state.source.subdirectory

options.force

boolean

no

Value indicating if the entities should be overwritten </br> Default Value is false

Return value

Type

Description

Array

An array of objects with attributes type, id and link representing the added entities.

Entities are normally never overwritten. So, if an entity already exists in the state and a new one is fetched, the one in the state will prevail. If you want to overwrite them, populate should be called with force: true.

Example

const response = await libraries.source.api.get({ endpoint: "posts" })
const entitiesAdded = await libraries.source.populate({ response, state })
​
entitiesAdded.forEach(({type, id, link}) => {
console.log({type, id, link})
})

libraries.source.handlers

Handlers are objects that associate a path pattern with a function that gets the entities contained in that path. These handlers are used when actions.source.fetch is called.

A handler is defined by an object with the following properties:

Name

Type

Required

Description

name

string

yes

Identifier of the handler.

priority

number

yes

Number that lets fetch to know in which order handlers should be evaluated.

pattern

regExp

yes

Pattern which paths are compared with. We use path-to-regexp under the hood, so check its documentation to know how to write patterns.

func

function

yes

Asynchronous function that retrieves entities and adds all info to the state.

The func property

Arguments

The func property defined will receive an object with the following properties

Name

Type

Description

link

string

The link that are being fetched.

params

string

values obtained from the pattern after a match

state

object

Frontity state.

libraries

objet

Frotity libraries.

force

boolean

f the etities should be fetched again. Internally, this parameter will be passed to the actions.source.fetch call.

Return

Type

Description

Promise

Promise resolving to custom data

libraries.source.handlers is an array., so to add new handlers we can use libraries.source.handlers.push()

Example

// A handler example to retrieve products
libraries.source.handlers.push({
name: "product",
priority: 10,
pattern: "/product/:slug",
func: async ({ link, params, state, libraries, force }) => {
// 1. get product
const response = await libraries.source.api.get({
endpoint: "products",
params: { slug: params.slug },
});
​
// 2. add product to state
const [product] = await libraries.source.populate({
response,
state,
force,
});
​
// 3. add link to data
Object.assign(state.source.datalink, {
id: product.id,
type: product.type,
isPostType: true,
isProduct: true,
});
},
});

libraries.source.redirections

Redirections are objects that associate a path pattern with a function that returns a new path. These redirections are used when actions.source.fetch is executed, before handlers.

A redirection is defined by an object with the following properties:

Name

Type

Required

Description

name

string

yes

Identifier of the redirection.

priority

number

yes

Let fetch to know in which order redirections should be evaluated.

pattern

regExp

yes

Pattern which paths are compared with. We use path-to-regexp under the hood, so check its documentation to know how to write patterns.

func

function

yes

Function that returns a new path. It receives an object with the params obtained after a match.

The func property

Arguments

The func property defined will receive an object with the following properties

Name

Type

Description

slug

string

The link that is being fetched.

Return

Type

Description

string

a new path

Example

// A redirection example to change tag base prefix
libraries.source.redirections.push({
name: "tags",
priority: 10,
pattern: "/tag/:slug/",
func: ({ slug }) => `/label/${slug}/`,
});

libraries.source.parse()

Utility for parsing links.

Syntax

(link: string) => object;

Arguments

Name

Type

Required

Description

link

string

yes

any link that points to entities in your site (links, custom lists, etc.)

Return value

Name

Type

Description

resultParse

object

Options object

resultParse.path

string

athname without the page

resultParse.page

number

The page number

resultParse.query

string

Object with query parameters

resultParse.hash

string

The hash value (with #).

libraries.source.stringify()

Utility for building links from its attributes.

Syntax

(args: object) => string;

Arguments

Name

Type

Required

Description

path

string

yes

pathname without the page

page

number

no

The page number

query

object

no

Object with query parameters

hash

string

o

Thehash value (with #).

Return value

Name

Type

Description

link

string

Normalized link

libraries.source.normalize()

Syntax

(link: string) => string;

Arguments

Name

Type

Required

Description

link

string

yes

Any link that points to entities in your site (links, custom lists, etc.)

Return value

Name

Type

Description

link

string

Normalized link

Still have questions? Ask the community! We are here to help 😊