Rendering ACF Custom Blocks in Gutenberg Using Next.js on Admin Panel #919
-
|
Hello, I’ve recently started configuring a new website using HeadstartWP. My plan is to use Gutenberg with custom blocks defined via Advanced Custom Fields. Everything is working well so far, but I’ve encountered a challenge I’m trying to resolve. Specifically, I’d like to render these custom blocks in the WordPress admin panel using rendering logic written in a Next.js application. Do you have any existing solutions or best practices for achieving this, or is this not currently supported? In my setup, WordPress and Next.js are running in separate Docker containers. My current idea is for WordPress to request rendered output for each block from the Next.js app. I realize this may not be the most optimal solution, but I’d like to avoid duplicating rendering logic between the block templates and the frontend, while also enabling live previews in the editor. I couldn’t find any mention of this use case in the documentation, but I’d appreciate any guidance you could provide. Best regards, |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 3 replies
-
|
Hi @smuzka. Yes there is something we have beeen using internally at 10up/Fueled which we recently open-sourced in a more generic/usable way but I'm not sure it would work with ACF Blocks as I'm not very familiar with it, what I'm going to describe assumes you are building custom blocks using the official WordPress API. We are calling this "Universal Blocks", i.e, blocks that you create in React that can be rendered anywhere. We still lack public documentation but the pieces you would need are all already available. Note: the public API is pretty much in beta and subject to change. The first thing you would need is https://github.com/10up/headstartwp/tree/develop/packages/block-primitives it exposes a set of primitives you can use to build your react components in Next.js/Storybook. Then you can directly import these components into your Gutenberg code. The second thing you would need is a way to share CSS, you would want something that you could easily import into the block editor without causing conflicts with Gutenberg styles. We have used initially experimented this with Linaria but have settled on Vanilla Extract for this use case. Tailwind might work too. Another important piece of this is ensuring that the build tool you are using supports compiling both your react code as well as the css solution you are using. For what I am going to show, I am using https://github.com/10up/10up-toolkit which is capable of compiling react with Linaria or Vanilla Extract. To illustrate how this works, let's say you are building your components in Storybook then you would have something like this: // component-library/src/hero/Hero.tsx
import type {
UniversalBlock,
ImagePrimitiveValue,
LinkPrimitiveValue,
} from '@headstartwp/block-primitives';
import { Image } from '@headstartwp/block-primitives/image';
import { RichText } from '@headstartwp/block-primitives/rich-text';
import { Link } from '@headstartwp/block-primitives/link';
import { InnerBlocks } from '@headstartwp/block-primitives/inner-blocks';
export type HeroAttributes = {
title: string;
content: string;
image: ImagePrimitiveValue;
link: LinkPrimitiveValue;
};
export interface HeroProps extends UniversalBlock<HeroAttributes> {}
export const Hero: FC<HeroProps> = ({ attributes, children, settings }) => {
return (
<div className={containerStyle}>
<RichText
name="title"
tagName="h2"
placeholder="The title"
value={attributes.title}
className={titleStyle}
/>
<RichText
name="content"
tagName="p"
placeholder="Description"
value={attributes.content}
/>
<Image
name="image"
value={attributes.image}
accept={['image/jpg']}
mediaURL={attributes?.image?.url ?? ''}
allowedTypes={['image/jpg']}
/>
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
<Link
name="link"
value={attributes.link}
className={linkStyle}
linkSettings={{ sourceUrl: settings?.sourceUrl, hostUrl: settings?.hostUrl }}
/>
<InnerBlocks allowedBlocks={['core/list']} className={innerBlocksStyle}>
{children}
</InnerBlocks>
</div>
);
};Note how a set of primitives are used to build the block: Link, InnerBlocks, RichText, and image. You can even write a story for it. When building the block inside Gutenberg you can use it like so // theme/includes/blocks/hero/edit.js
import { Hero } from '@headstartwp/component-library/hero';
import { UniversalBlockRenderer } from '@headstartwp/block-primitives/renderer';
const ExampleBlockEdit = () => {
const blockProps = useBlockProps();
return (
<div {...blockProps}>
<UniversalBlockRenderer component={Hero} />
</div>
);
};Note: when building this for Gutenberg, your bundler of choice need to set This will render the Hero component with inline editing capabilities based on the primitives used in the Hero component. To render the custom block in your Next.js application you would pair it up with the BlocksRenderer component. const Blocks: React.FC<BlocksRendererProps> = async ({ html, settings }) => {
const { data } = await queryAppSettings();
return (
<BlocksRenderer
forwardBlockAttributes
html={html}
settings={settings}
blockContext={{ themeJSON: data['theme.json'].settings }}
>
<ImageBlock />
<LinkBlock />
<UniversalBlockRenderer
component={Hero}
test={(node) => isBlockByName(node, 'tenup/hero')}
/>
</BlocksRenderer>
);
};The hero component will automatically receive the custom block’s attribute in the shape that the Hero component expects. You can actually see a demo of this in action if you pull the headstartwp monorepo locally and run This command will spin up a component-library in storybook(https://github.com/10up/headstartwp/tree/develop/test-projects/component-library), a theme (https://github.com/10up/headstartwp/tree/develop/wp/10up-theme) and a next.js app (https://github.com/10up/headstartwp/tree/develop/test-projects/wp-nextjs-universal-blocks) I hope this is helpful, there are quite a few moving pieces but once you get it all up and running it should be fairly easy get going. |
Beta Was this translation helpful? Give feedback.
Hi @smuzka. Yes there is something we have beeen using internally at 10up/Fueled which we recently open-sourced in a more generic/usable way but I'm not sure it would work with ACF Blocks as I'm not very familiar with it, what I'm going to describe assumes you are building custom blocks using the official WordPress API.
We are calling this "Universal Blocks", i.e, blocks that you create in React that can be rendered anywhere.
We still lack public documentation but the pieces you would need are all already available. Note: the public API is pretty much in beta and subject to change.
The first thing you would need is https://github.com/10up/headstartwp/tree/develop/packages/block-primitives …