Skip to main content

Creating a Block from a third-party plugin

In this tutorial you will install and create a block using @faustwp/blocks that is using data from a blocks plugin that you downloaded in your WordPress site. It assumes you have already installed both the @faustwp/blocks and wp-graphql-content-blocks plugin.

1. Set up a @faustwp/blocks

If you have not already done so, you will need to follow the Getting Started so that you are ready to create new blocks.

2. Download a third-party plugin that provides Gutenberg Blocks

You need some real working Gutenberg blocks so you can implement them in the Faust application. For this tutorial, we are using Ultimate Blocks which contain a nice selection of blocks we can use.

3. Pick a block that you want to implement

The Ultimate blocks package contains a few interesting blocks. You want to have blocks that have a complete block.json with defined attributes, since the wp-graphql-content-blocks plugin will automatically expose those as GraphQL fields.

For this tutorial, we are going to implement the Call To Action Block.

Ultimate Blocks Call To Action Block Preview

4. Review the Block design in the Editor

Before you try to implement the block, it's usefull to get an ideal of how the block is configured within the editor. You want to create a few sample blocks and test their options.

Navigate to the editor by creating a new Post and insert the Block into the page:

Ultimate Blocks Call To Action Block look and feel in the editor

You can expand the block sidebar options to change some of its styling. For example you can configure the Color, Headline, Content, Button and Link settings for that block. Once you get familiar with the block look and feel, let's explore its attributes from the GraphQL IDE.

5. Review the Block data and attributes in the GraphQL IDE

Within the GraphQL IDE, use the Docs to find the type of the block to display its type and properties. There should be a UBCallToActionBlock that contains all the important fields we can query.

Ultimate Blocks Call To Action Block documentation in GraphQL IDE

Expand the UbCallToActionBlockAttributes to see the block attributes as well:

Ultimate Blocks Call To Action Block attributes documentation in GraphQL IDE

There are a lot of attributes associated with that block. You can use the following query to inspect the block data:

post(id: "/posts/test", idType: URI) {
contentBlocks {
...on UbCallToActionBlock {
attributes {

This will resolve into:

"data": {
"post": {
"contentBlocks": [
"renderedHtml": "<div class=\"ub_call_to_action\" id=\"ub_call_to_action_37aa7f1a-5d3a-4077-9c2b-a29b3672896c\">\n <div class=\"ub_call_to_action_headline\">\n <p class=\"ub_call_to_action_headline_text\">Call To Action</p></div>\n <div class=\"ub_call_to_action_content\">\n <p class=\"ub_cta_content_text\">Help us achieve our goals</p></div>\n <div class=\"ub_call_to_action_button\">\n <a href=\"http://locahost:3000/donate\" target=\"_self\" rel=\"noopener noreferrer\"\n class=\"ub_cta_button\">\n <p class=\"ub_cta_button_text\">Donate Now</p></a></div></div>",
"attributes": {
"url": "http://locahost:3000/donate",
"openInNewTab": false,
"blockID": "37aa7f1a-5d3a-4077-9c2b-a29b3672896c",
"ubCallToActionHeadlineText": "Call To Action",
"ubCtaButtonText": "Donate Now",
"ubCtaContentText": "Help us achieve our goals"

There are also attributes that control the style of the individual elements so you can query their attributes as well. Once you get familiar with how to query the necessary data from that block, let's see now how to implement the assosiated block in the Decoupled site.

6. Create the initial block

Inside the codebase of your application, create the basic block structure that simply prints the blocks attributes. The steps required to achive that are the following:

6.1 Create the block and save it inside the wp-blocks folder

export default function UbCallToActionBlock(props) {
return <div>UbCallToActionBlock</div>

This component prints the block attributes via the props passed as a parameter.

6.2 Export the block in the index.js

import UbCallToActionBlock from './UbCallToActionBlock';
export default {

By exporting the block in the index.js we make it available in the WordrPressBlocksProvider. You can also use a different name as long as it matches either the Block name or the __typename fields.

This also works:

import UbCallToActionBlock from './UbCallToActionBlock';
export default {
'ub/call-to-action-block': UbCallToActionBlock

6.3 Create the block fragment

You want to create a fragment that describes the request block fields and attributes. Ideally you want to include all the relevant fields for the implementation part:

import {gql} from '@apollo/client';

UbCallToActionBlock.fragments = {
key: `UbCallToActionBlockFragment`,
entry: gql`
fragment UbCallToActionBlockFragment on UbCallToActionBlock {
attributes {

We chose to attach the fragment as a property of the function component itself. This follows a good practice for creating colocated fragments.

6.4 Include the block fragment into the page query string

You want to include the fragment in the page query string and reference the block fragment key so that when the page resolves, the payload would include the data from that block.

In our example we use it in both the Posts and Pages templates when using the Faust Template Hierarchy:

import blocks from '../wp-blocks';

export default function Component(props) {

Component.query = gql`
query GetPost(
post(id: $databaseId, idType: DATABASE_ID, asPreview: $asPreview) {
contentBlocks {
id: nodeId

If you navigate to the page that contains this block, you should be able to inspect the properties in the console:

Ultimate Blocks Call To Action preview of the block attributes in the console

Now you are ready to design the block based on the original block's look and feel.

7. Implement the Block using the provided block attributes and the Editor view

The last part is to implement the Block by using the block attributes and the view in the editor to construct the final HTML markup.

Since the block you want to implement already consists of React elements that the Editor uses, you can review the plugin implmentation of this block and try to port the parts that render the block the block in the frontend.

If you take a look at the wp-content/plugins folder inside the ultimate-blocks/src/blocks/call-to-action folder there are some important files there that you want to review:

$ tree -L 2 wp-content/plugins/ultimate-blocks/src/blocks/call-to-action
├── block.js
├── block.php
├── components.js
├── editor.css
├── editor.scss
├── icons
│ └── icon.js
├── oldVersions.js
├── style.css
└── style.scss

You are interested in the following files:

style.scss: Contains the front-end block styles. You can definatelly include those into our global styles.

* #.# Styles
* CSS for both Frontend+Backend.

.wp-block-ub-block-call-to-action {
margin: 0 auto;
max-width: 100%;

block.js: Contains both the block attributes specification and the save function. According to the docs, the save function is used defines the way in which the different attributes should be combined into the final markup, which is then serialized into post_content.

Most of the times the save function contains the actual implementation of the block, so you can take this markup and adopt it. This way the design of the block in the editor will match the design in the Decoupled site.


In our case we were lucky. Some times the save function is not provided or it returns null. The component is considered then to be dynamic, aka it renders in the server. So you want to check if the register_block_type provides an implementation for rendering the block. In that case, the render_callback will provide the markup for the block using PHP. You can take this implementation and translate it to React.

Since the save function is provided with that block we have a viable stategy that will save us time without having to figure out the actual implementation.

So go ahead and provide the implementation of the Block based on the save function:

export default function UbCallToActionBlock(props) {
const {
} = props.attributes;
return (
<div className={props.className}>
backgroundColor: ctaBackgroundColor,
border: ctaBorderSize + 'px solid',
borderColor: ctaBorderColor,
<div className="ub_call_to_action_headline">
fontSize: headFontSize + 'px',
color: headColor,
textAlign: headAlign,
<div className="ub_call_to_action_content">
fontSize: contentFontSize + 'px',
color: contentColor,
textAlign: contentAlign,
<div className="ub_call_to_action_button">
target={openInNewTab ? '_blank' : '_self'}
rel={`${addNofollow ? 'nofollow ' : ''}noopener noreferrer`}
className={`wp-block-button ub_cta_button`}
backgroundColor: buttonColor,
width: buttonWidth + 'px',
color: buttonTextColor,
fontSize: buttonFontSize + 'px',

Don't forget to include the global scss for the block so that the right styles are applied. You can create a new folder for block styles inside the styles folder and import it there:

// WordPress block styles.
@import './blocks/UbCallToActionBlock' // import block styles here

Not that you have the styles configured correctly, you can navigate into the Headless site's page and check that the block matches the styles with the editor view:

Ultimate Blocks Call To Action demo of the block rendered in the Decoupled Website

Make sure to tweak the block in the editor and inspect the changes reflected in the website.


Next.js won't allow you to import the styles.scss directly into the component since it requires all global CSS to be imported from the pages directory only. See the related error message. So you need to either import the styles from a global module or translate the styles to use Component-Level CSS.

Futher Considerations

What if the block is missing some attributes?

If the block does not have any attributes or has only a few of them declared in the block.json, you can still try to extend the block API by declaring additional attributes for that block. Follow the filters reference guide, to create a block that uses the additional_block_attributes property. The attributes will be available to query from that block.

class UbCallToActionBlock extends WPGraphQL\ContentBlocks\Blocks\Block
protected ?array $additional_block_attributes = array(
// Write your attributes here

If you include those extensions in a custom plugin, it means also that your Decoupled application is dependent on the inclusion of this plugin. You need to make sure you bundle them together otherwise the queries you do in the application will fail.

Can I style the block differently?

Yes, you can style the block in many ways, choosing to ignore some of the attributes altogether. You can also use an external React Library to style the block. For example, use Material UI or ChakraUI. Bear in mind that this will almost always result in degraded user editing experience as the styles of the Editor view won't match the styles of the rendered page.

What if the block contains custom js assets?

Some blocks, include JavaScript assets that are injected into the WordPress page so that they can run in the front view. Typically a lot of Dynamic Blocks use that functionality since they have no way to include user interactivity. Since React is not normally bundled as a dependency in the browser, the JavaScript code usually consists of good old jQuery and document selectors.

In that case you want to be able to review the bundled JavaScript assets and choose one of the following options:

  • Include them in your code: This is not recommended as React does not play well with plain JavaScript and jQuery so you can expect lots of problems.

  • Rewrite them as React components: You can attempt to rewrite the code into React. If the bundled code can be understood and rewritten with low effort then you can make that commitment.

  • Use an equivalent React Component from a library: A simpler alternative is to find a compatible React Package and use that instead of trying to replicate the blocks interactivity. Sometimes this is a viable strategy as it frees the developer from implementing the functionality from scratch.

Innevitably this is a common pain point when trying to leverage the power of Blocks in the Decoupled Website so it's up to you how you want to handle the pros and cons of each approach.