Custom post types
The SiteBox framework leverages the GraphQL mechanism shipped with Gatsby.js, which is a data layer API used to consume external data within a Gatsby-generated website. There is an extensive explanation of how to use data fetched from different providers in the official Gatsby documentation. However, if your project consumes only WordPress-generated data, it is handled out of the box by the SiteBox WordPress plugin. It exposes the GraphQL mechanism as a wp-json extension, which is consumed during the Gatsby.js building process.
Models
The models exposed in the GraphQL interface depend on the project configuration. By default, the SiteBox plugin exposes a list of WordPress native post types, as well as some added by the framework such as Documents, Authors, or People. To find out the full list of available models, simply visit the GraphiQL panel within the WordPress Dashboard, then navigate to SiteBox > GraphQl IDE.
Native Models
Your boilerplate-based project comes with some models ready to use without any configuration. The list may change over time and may be different when manipulated by integrations or extensions, so always refer to the list available in the WordPress dashboard (or GraphiQL interface in Gatsby).
List of native models
- Posts – a collection of posts.
- Categories – a collection of post categories.
- Tags – a collection of post tags.
- Pages – a collection of pages.
- People – a collection of people custom post types enabled by the SiteBox Framework.
- PeopleCategories – a collection of category-like taxonomies applied to people custom post types enabled by the SiteBox Framework.
- PeopleTags – a collection of tag-like taxonomies applied to people custom post types enabled by the SiteBox Framework.
- Documents – a collection of documents custom post types enabled by the SiteBox Framework.
- DocumentCategories – a collection of category-like taxonomies applied to documents custom post types enabled by the SiteBox Framework.
- DocumentTags – a collection of tag-like taxonomies applied to documents custom post types enabled by the SiteBox Framework.
- GutenbergBlocks – a collection of Gutenberg blocks. Please note that blocks are applied as children of custom post
types with Gutenberg experience enabled. These nodes, as long as provided as properties to the
<StatikBlocks>
component, result in rendered Gutenberg content. - MediaItems – a collection of media in the library.
- Megamenus – a collection of WordPress entities with Gutenberg content available to render as a mega menu.
- Menus – a collection of WordPress native menus.
- MenuItems – a collection of items added to WordPress native menus.
Please note, some collections are considered as child nodes applied to other models. The approach allows to query data more efficiently within the Gatsby app.
Custom Post Types
One of the most important features of WordPress is the ability to add custom post types to manage content efficiently. Considering the fact that data is always presented in the front-end application, it needs to be enabled in the WordPress-based GraphQL interface.
The SiteBox Framework covers adding a GraphQL-enabled custom post types using one of the following ways:
- Developers can add CPTs by modifying the WordPress child theme.
- Content editors can use the CPT generator plugin.
Adding CPT by modifying WordPress SiteBox theme
To ensure that WordPress uses the most up-to-date version of a theme, it is recommended not to edit any of its files directly.
Assuming that developers will follow the directory hierarchy of the parent SiteBox theme, to add a custom post type named "Movies," make sure that the following snippet within the functions.php file is available:
/**
* Load Custom post types.
*/
require_once __DIR__ . '/includes/custom-post-types/index.php';
File backend/themes/statik/includes/custom-post-types/index.php
which is required inside
backend/themes/statik/functions.php
is a hub for all custom post types added at a project level.
Next step is to create CPT file and place it to the backend/themes/statik/includes/custom-post-types/movies/
directory. This file will hold all information about the new CPT as shown below.
<?php
declare(strict_types=1);
\defined('ABSPATH') || exit('Direct access is not permitted!');
\add_action('init', 'statik_register_movies_cpt', 1);
if (false === \function_exists('statik_register_movies_cpt')) {
/**
* Register custom post type for Movies.
*
* @since 2.0.0
*/
function statik_register_movies_cpt(): void
{
$labels = [
'name' => \_x('Movies', 'Post Type General Name', 'statik'),
'singular_name' => \_x('Movie', 'Post Type Singular Name', 'statik'),
'menu_name' => \__('Movies', 'statik'),
'name_admin_bar' => \__('Movies', 'statik'),
'archives' => \__('Movie Archives', 'statik'),
'attributes' => \__('Movie Attributes', 'statik'),
'parent_item_colon' => \__('Parent Movie:', 'statik'),
'all_items' => \__('All Movies', 'statik'),
'add_new_item' => \__('Add New Movie', 'statik'),
'add_new' => \__('Add New', 'statik'),
'new_item' => \__('New Movie', 'statik'),
'edit_item' => \__('Edit Movie', 'statik'),
'update_item' => \__('Update Movie', 'statik'),
'view_item' => \__('View Movie', 'statik'),
'view_items' => \__('View Movies', 'statik'),
'search_items' => \__('Search Movie', 'statik'),
'not_found' => \__('Not found', 'statik'),
'not_found_in_trash' => \__('Not found in Trash', 'statik'),
'featured_image' => \__('Featured Image', 'statik'),
'set_featured_image' => \__('Set featured image', 'statik'),
'remove_featured_image' => \__('Remove featured image', 'statik'),
'use_featured_image' => \__('Use as featured image', 'statik'),
'insert_into_item' => \__('Insert into Movie', 'statik'),
'uploaded_to_this_item' => \__('Uploaded to this Movie', 'statik'),
'items_list' => \__('Movies list', 'statik'),
'items_list_navigation' => \__('Movies list navigation', 'statik'),
'filter_items_list' => \__('Filter Movies list', 'statik'),
];
\register_post_type(
'movie',
[
'label' => \__('Movie', 'statik'),
'description' => \__('Movies', 'statik'),
'labels' => $labels,
'supports' => ['title', 'custom-fields', 'revisions'],
'hierarchical' => false,
'public' => true,
'show_ui' => true,
'show_in_menu' => true,
'menu_position' => 20,
'menu_icon' => 'dashicons-media-archive',
'show_in_admin_bar' => true,
'show_in_nav_menus' => true,
'can_export' => true,
'has_archive' => false,
'exclude_from_search' => true,
'publicly_queryable' => true,
'capability_type' => 'post',
'show_in_rest' => true,
'rest_base' => 'documents',
'rewrite' => ['with_front' => false],
'show_in_graphql' => true,
'graphql_single_name' => 'movie',
'graphql_plural_name' => 'movies',
]
);
}
}
Note last properties: show_in_graphql
, graphql_single_name
and graphql_plural_name
enforce the custom post type to
be shown within the WordPress GraphQL interface, making its data available to use in a Gatsby instance.
The next step is to add a reference to the CPT files held in a separate directory.
<?php
declare(strict_types=1);
\defined('ABSPATH') || exit('Direct access is not permitted!');
/**
* In this file can be added more WordPress Custom Post Types.
* Each CPT should be in the separate directory and each file should
* be included there using the `require_once` function.
*/
require_once __DIR__ . '/movies/movies-cpt.php';
Using CPT generator plugin
WIP
Querying data
Any data available in the WordPress GraphQL interface (@TBD: Damian to confirm) can be queried out of front-end Gatsby application. This approach allows to generate data JSONs that hydrates the front-end website during the build time. No further communication with WordPress is required – more about this concept is explained on the Foundation page.
Backend query
Custom post type Movies should be listed in the WordPress backend. Go to 'Movies' and create new movie post type.
In order to test 'Movies' custom post type query, go to the SiteBox -> GraphiQL IDE. In 'Query composer' select
allMovies
query and then nodes
. For this test purpose we will select title, url, movieId, seo title and description.
After clicking 'play' button data from the Movies custom post type should be generated in the right column.
As you can see, data has been pulled from the newly created post inside 'Movies' custom post type.
Frontend query
Example presented below will create a single page that holds a post data. It will be returned for
/insights/hello-world
route. Also, the example implements Gutenberg Blocks support which is explained more in detail
on Blocks page.
A component that is expected to render a Hello World page looks for a post with ID 18
in the GraphQL query. Please
note, no JavaScript variables can be passed to the GraphQL call as it is performed outside the regular JavaScript
lifecycle. If you need to make calls more dynamic, simply consider using Collection Routes explained more in detail on
the Routing page – Collection Routes allows to pass dynamic variables that were picked out of the URL.
import React from 'react';
import PropTypes from 'prop-types';
import { graphql } from 'gatsby';
const HelloWorld = props => {
const {
data: {
post: {
title,
gutenbergBlocks,
},
},
} = props;
return (
<main>
<h1>
{gutenbergBlocks && gutenbergBlocks.nodes && (
<StatikBlocks blocks={gutenbergBlocks.nodes} />
)}
</main>
);
};
HelloWorld.propTypes = {
PropTypes.shape({
post: PropTypes.shape({
title: PropTypes.string,
gutenbergBlocks: PropTypes.shape({
nodes: PropTypes.array,
}),
}),
}),
};
export default HelloWorld;
export const query = graphql`
query Query {
post(id: 18) {
title
gutenbergBlocks {
nodes {
...GutenbergBlockFragment
}
}
}
}
`;
Fragments
In the example above there's a reference to ...GutenbergBlockFragment
, which is a fragment. Fragments are destructed
into additional properties to be fetched in the GraphQL call. In other words, during the build phase, the script will
consider this code
nodes {
...GutenbergBlockFragment
}
as the following
nodes {
id
databaseId
parentId
parentDatabaseId
name
attributes {
key
value
}
rawHtml
}
It will be possible to reference any of the properties in Gatsby frontend application without actually requesting them in the GraphQL call. Developers are in position to create their own fragments, however some of them are already bundled in the SiteBox Framework. Below you can find a list of fragments that might be helpful in the development:
...PostFragment
id
slug
uri
date
seo {
node {
...NodeSeoFieldFragment
}
}
featuredImage {
node {
...MediaItemFragment
}
}
author {
node {
name
}
}
categories {
nodes {
slug
name
}
}
gutenbergBlocks {
nodes {
...GutenbergBlockFragment
}
}
...PageFragment
id
slug
uri
seo {
node {
...NodeSeoFieldFragment
}
}
gutenbergBlocks {
nodes {
...GutenbergBlockFragment
}
}
...MediaItemFragment
sourceUrl
srcSet
placeholderBase64
mediaDetails {
height
width
}
title
altText
...MenuItemFragment
id
parentId
databaseId
parentDatabaseId
url
label
cssClasses
order
childItems {
nodes {
id
}
}
megamenu {
node {
gutenbergBlocks(first: 1000) {
nodes {
...GutenbergBlockFragment
}
}
}
}
...GutenbergBlockFragment
id
databaseId
parentId
parentDatabaseId
name
attributes {
key
value
}
rawHtml
...GutenbergFormsBlockFieldFragment
...GutenbergCoverBlockFieldFragment
...GutenbergCardsBlockFieldFragment
...GutenbergTeamMemberBlockFieldFragment
...NodeSeoFieldFragment
canonicalUrl
description
imageUrl
noarchive
nofollow
noindex
ogDescription
ogTitle
redirectUrl
title
twitterDescription
twitterTitle