Skip to main content
DocsHow-To GuidesCustom Blocks

Customize Blocks Rendering

Whether you want to customize the look and feel of a core WordPress block, implement a custom block, or add a block from a third-party plugin, Faust.js makes it easy to render WP blocks to your liking. This guide will show you how to render a block in your Faust.js project.

0. Prerequisites

Ensure that you have completed the steps in our Rendering blocks guide and have WordPress blocks rendering in your app successfully before proceeding with the steps below.

1. Choose a block to override

For this guide, we are going to override the core WordPress Code Block that renders a formatted block of code..

WordPress Code block in the Block editor

2. Review block features and settings

Try using the block yourself in the WordPress block editor and get familiar with the features it has. Review the settings it has in the Settings Panel and change a few of them to see what they do.

3. Inspect the block data via the GraphiQL IDE

In the WordPress admin sidebar, go to GraphQL > GraphiQL IDE to open the GraphiQL IDE. If you're not familiar, this is a tool we can use for composing and testing GraphQL queries. This can help you understand what data your frontend app will receive when it executes a particular query.

Paste the following query into the GraphiQL IDE and hit the ▶️ button to execute the query. Replace /posts/testing with the path to the blog post that contains the block you want to override.

{
	post(id: "/posts/testing", idType: URI) {
		editorBlocks {
			renderedHtml
			... on CoreCode {
				attributes {
					borderColor
					backgroundColor
					content
					style
					textColor
					fontSize
				}
			}
		}
	}
}
Block Type

Each block is given a unique GraphQL type. In this case, the Core Code block is a type of CoreCode. You can find the block type by looking at the __typename field. If you need help figuring this out, the following query will list all the blocks on a post with their types:

{
	post(id: "/posts/testing", idType: URI) {
		editorBlocks {
			__typename
			type
			name
		}
	}
}

The __typename or type fields will show you the block type for each block on a post. You may find it useful to know this is generated from the $block_type argument in the block's registerBlockType function; shown here in the name field.

The GraphiQL IDE will then display the data that was returned in the response to that query. It should look something like the example response below.

{
	"data": {
		"post": {
			"editorBlocks": [
				{
					"renderedHtml": "\n<pre class=\"wp-block-code has-border-color has-tertiary-background-color has-text-color has-background has-small-font-size\" style=\"border-color:#333333;border-width:2px;color:#333333\"><code>// Computes the nth Fibonacci number\nfunction fib(n) {\n    var a = 0, b = 1, c;\n    if (n &lt; 3) {\n        if (n &lt; 0) return fib(-n);\n        if (n === 0) return 0;\n        return 1;\n    }\n    while (--n)\n        c = a + b, a = b, b = c;\n    return c;\n}</code></pre>\n",
					"attributes": {
						"borderColor": null,
						"backgroundColor": "tertiary",
						"content": "// Computes the nth Fibonacci number\nfunction fib(n) {\n    var a = 0, b = 1, c;\n    if (n &lt; 3) {\n        if (n &lt; 0) return fib(-n);\n        if (n === 0) return 0;\n        return 1;\n    }\n    while (--n)\n        c = a + b, a = b, b = c;\n    return c;\n}",
						"style": "{\"color\":{\"text\":\"#333333\"},\"border\":{\"color\":\"#333333\",\"width\":\"2px\"}}",
						"textColor": null,
						"fontSize": "small"
					}
				}
			]
		}
	}
}

You can try modifying the query and running it again to see how the response changes. To learn about the fields that are available for that block, click the Docs link in GraphiQL, search for CoreCode, and click on CoreCodeAttributes. You will see the following:

Core code block attributes

Styles

Notice that with some of the attributes like backgroundColor, the editor used the theme.json palette slug name instead of the actual value, i.e., tertiary. It also stored the custom hardcoded styles in the style fields as a JSON string.

4. Define the block in your frontend app

A. Create a new block component

Create a new CoreCode.js file inside of your wp-blocks folder that contains the following code.

wp-blocks/CoreCode.js
export default function CoreCode(props) {
	console.log(props.attributes);
	return <div>CoreCode</div>;
}
 
CoreCode.displayName = "CoreCode";

For now, we're just rendering a placeholder div and logging the data to the console. This will be replaced with actual block code in subsequent steps.

Context

The displayName property is defined here so that when we run the editorBlocks query in subsequent steps, the __typename field in the query will match this string. This is required so that the WordPressBlocksViewer component can resolve and render the block properly.

B. Register the new block component

Open the index.js file inside the wp-blocks folder and add your new block like this:

wp-blocks/index.js
import { CoreBlocks } from "@faustwp/blocks";
import CoreCode from "./CoreCode";
 
export default {
	...CoreBlocks,
	CoreCode: CoreCode, // [++code]
};
Context

This file will be used to import all of the blocks you're overriding and make them available as the default export, which will be passed into WordPressBlocksProvider in a subsequent step.

We also define the name of the block as CoreCode (the property name to the left of the ":" character). This key must match the __typename value that the blocks has in the GraphQL schema.

C. Create the block GraphQL fragment

Create a fragment that describes the request block fields and attributes. First, import { gql } from @apollo/client. Then add the CoreCode.fragments code block, as shown below. Include all relevant fields for your implementation.

wp-blocks/CoreCode.js
import { gql } from "@apollo/client";
 
export default function CoreCode({ attributes }) {
	console.log(attributes);
	return <div>CoreCode</div>;
}
 
CoreCode.fragments = {
	key: `CoreCodeBlockFragment`,
	entry: gql`
		fragment CoreCodeBlockFragment on CoreCode {
			attributes {
				borderColor
				backgroundColor
				content
				style
				textColor
				fontSize
				fontFamily
				cssClassName
			}
		}
	`,
};
Context

Attaching the fragment as a property of the function component (CoreCode.fragments = ...) is a convention that Faust.js uses to colocate fragments with the components that use them.

D. Include the block fragment in your page template queries

Now, you can include the block fragment inside of the GraphQL query for your posts and pages.

The example below shows a /wp-templates/single.js template.

wp-templates/single.js
import { gql } from "@apollo/client";
import blocks from "../wp-blocks";
 
export default function Page(props) {
	// ...
}
 
Page.query = gql`
  ${blocks.CoreCode.fragments.entry}
  query GetPost {
    post(id: $databaseId, idType: DATABASE_ID, asPreview: $asPreview) {
      editorBlocks {
        name
        __typename
        renderedHtml
        id: clientId
        parentClientId
        ...${blocks.CoreCode.fragments.key}
      }
    }
  }
`;
  • import blocks from "../wp-blocks"; imports the blocks we're overriding.
  • ${blocks.CoreCode.fragments.entry} interpolates the CoreCode GraphQL fragment into the page query.
  • ...${blocks.CoreCode.fragments.key} tells GraphQL to insert the CoreCode GraphQL fragment inside of the editorBlocks { ... } block.

With this code in place, when the GraphQL query for the single page template is executed, the response will now include data for the CoreCode block. You can follow this pattern in your other page templates to query for block data within them, as well.

E. Verify the block data in the frontend app

If you navigate to the page that contains this block, you should be able to inspect the properties in the console and see your block attributes that were logged by console.log(props.attributes) in CoreCode.js.

Browser Console showing logged object

5. Implement the block

You now have the block data available in your frontend app and are ready to implement the block's structure, styling, and functionality.

Options

You've done the hard work of getting the data into your app and integrating with the @faustwp/blocks package. How you implement this block is completely up to you. You can use any React component library, CSS-in-JS solution, or custom styles you like.

Keep in mind, If your implementation deviates from the WordPress implementation, your content editors might find this confusing. For this guide, we'll show you a basic implementation of the CoreCode block.

Replace the CoreCode component with the following code. This code will render the block in the frontend app with a similar structure to the WordPress block editor.

wp-blocks/CoreCode.js
import { gql } from "@apollo/client";
 
export default function CoreCode({ attributes }) {
	return (
		<pre className={attributes?.cssClassName}>
			<code>{`${attributes?.content}`}</code>
		</pre>
	);
}
 
CoreCode.fragments = {
	key: `CoreCodeBlockFragment`,
	entry: gql`
		fragment CoreCodeBlockFragment on CoreCode {
			attributes {
				content
				cssClassName
			}
		}
	`,
};
 
CoreCode.displayName = "CoreCode";

6. Implement the block styles

Let's add some code highlighting to this component to really make it pop.

Options

We're going to leave the specific styling up you. You can choose to statically style in here or you could leverage the other available attributes to style the block dynamically from the WordPress block editor. Faust does support styling blocks using your WordPress Block theme styles.

A. Install the highlight.js package by running the following command:

npm add highlight.js

B. Import the highlight.js package in the _app.js file:

_app.js
// THIS IS VERY IMPORTANT.
// In Next.js, put this in your _app.js file
import "highlight.js/styles/github.css";

C. Update the Component

Update CoreCode.js with the code bellow to add code highlighting:

wp-blocks/CoreCode.js
import { gql } from "@apollo/client";
import { useEffect, useRef } from "react";
import hljs from "highlight.js";
 
export default function CoreCode({ attributes }) {
	// Create a ref for the <code> element
	const codeRef = useRef(null);
 
	useEffect(() => {
		// Once the component has rendered, apply highlight.js to the code element
		if (codeRef.current) {
			hljs.highlightElement(codeRef.current);
		}
	}, [attributes?.content]);
 
	return (
		<pre className={attributes?.cssClassName}>
			<code
				ref={codeRef}
				dangerouslySetInnerHTML={{ __html: attributes?.content }}
			/>
		</pre>
	);
}
 
CoreCode.fragments = {
	key: `CoreCodeBlockFragment`,
	entry: gql`
		fragment CoreCodeBlockFragment on CoreCode {
			attributes {
				content
				cssClassName
			}
		}
	`,
};
 
CoreCode.displayName = "CoreCode";

7. Wrapping up...

Navigate to a page that contains the CoreCode block and you should see the code block with syntax highlighting applied.