Beyond HTML Comments: How To Save Your Data Any Way You Like with Gutenberg

One of the early controversies around the block editor when it was released was how it wrapped the content of each block in HTML comments

It may surprise you that you can leverage the block editor and save your content in whatever format you like, no HTML comments required.

This article will explain how Gutenberg empowers developers to do that, what we chose to do with the NextGen Form Builder, and other formats you might consider for your own projects.

Why Gutenberg uses HTML Comments to Store Content

The WordPress block editor uses HTML comments to store data about blocks, such as the block type and attributes. This approach has a few advantages:

  1. It allows for backwards compatibility: By storing the block data in HTML comments, the block editor can work with existing content that was created using the classic editor.
  2. It makes it easy to parse the blocks: The HTML comments provide a clear delimiter for where one block begins and another ends, which makes it easy to parse the content and identify individual blocks.
  3. It allows for easy access to block data: By storing data about the blocks in HTML comments, the block editor can easily access and modify the block data without having to rely on JavaScript or other complex methods.
  4. It’s easy to extract the data using regular expressions: Which is more efficient than using a DOM parser.
  5. It fails gracefully if a block no longer exists: In contrast to shortcodes, if a dynamic block is uninstalled then the HTML comment placeholder is not rendered on the front end . No more seeing coded markup when you disable a plugin on your site!

Overall, storing block data in HTML comments is a simple and efficient way for the WordPress block editor to work with and manage the content created using the editor.

How the Storage Mechanism Works and Can be Leveraged

It’s important to keep in mind that this is how the block editor works – using HTML comments is not a requirement of working with the Gutenberg codebase. If you dig into Gutenberg’s code you’ll see that the <BlockEditorProvider/> and <BlockList/> components work in arrays of block objects that can be interacted with however you like.

Each block has the clientId and isValid properties, for use within the editor, in addition to the name, attributes, and innerBlocks properties, which represent the underlying data that is later rendered as post content.

This array of blocks can be serialized and stored for use in the editor for any type of application. This means that while the block editor generates HTML, other applications – like the NextGen Form Builder for GiveWP – can store JSON or any other format according to the needs of the application.

How to Store Your Block Content However You Like

The GiveWP NextGen Donation Form Builder illustrates how the same underlying block data used by Gutenberg can be stored in multiple different formats. Instead of storing annotated HTML for content, GiveWP stores JSON which is then parsed into the Fields API before being consumed by a React application which is the Donation Form.

How the block data is stored is not dictated by Gutenberg, but rather by the application implementing the resulting block editor. As the Gutenberg project grows and gains attention from the broader community there are examples of block editors using Gutenberg in other frameworks and ecosystems. Consider the following implementations:

How GiveWP Stores Block Data

This section is more technical in nature, but the short version is that GiveWP stores block data as JSON, instead of HTML comments, for rendering donation forms. This separation of the storage of the data from the resulting HTML enables us to leverage the form data in flexible and dynamic ways, including client side form rendering as well as server side validation using the same data.

The NextGen Donation Form Builder for GiveWP uses TypeScript to enforce the structure of the FormState and underlying blocks and settings properties.

ts

type FormState = {
  blocks: Block[];
  settings: FormSettings;
};

Each Block in the FormState is typed to match the structure as defined by Gutenberg, as previously mentioned.

ts

type Block = {
  clientId: string;
  name: string;
  isValid: boolean;
  attributes?: {/*...*/}
  innerBlocks?: Block[]
}

The configuration of blocks is derived directly from the <BlockEditorProvider /> and is stored using the React Context API.

jsx

<BlockEditorProvider value={blocks} onChange={dispatchFormBlocks}>
  <BlockList />
</BlockEditorProvider>

The block data is passed to the server, parsed into a BlockCollection from the passed JSON, added to the DonationForm object, and validated. Because GiveWP uses this block data as a form schema, the Fields API is used to convert the BlocksCollection into a format that is consumable by the rendered form. The resulting form schema is used to ensure that the block data is valid before being persisted to the database.

php

$form = DonationForm::find($formId);

$form->blocks = BlockCollection::fromJson(
  $request->get_param('blocks')
);

$this->validateRequiredFields($form->schema())

$form->save();

Join the NextGen Form Builder Journey

We are building this new experience in public and you can join and follow along.

As a quick teaser, here’s an example of our progress on the “Design Tab”:

If you want to join us on this journey, head to the project page and sign-up to get notified of our progress, get sneak peek previews, participate in polls, and you might even get discount codes and swag items too!

Join the Journey today.

About the Author

Share this post

Join Our Newsletter

Get fundraising insights directly in your inbox. Plus a 15% discount off all plans.

  • This field is for validation purposes and should be left unchanged.

Copyright © 2024 Liquid Web, L.L.C.

GiveWP™ is a trademark of Liquid Web, L.L.C.

A Liquid Web Brand

© 2024 All Rights Reserved.