Exposing WordPress Data Without the Markup

Before Gutenberg, WordPress relied on a WYSIWYG editor. This had lots of buttons to add tables, quotes or other specifically formatted content.

As time went on, content got more complex. There were more options and styling components was achieved by context menus and code. This wasn’t a great experience for the content editor.

Sites began to use a modern component driven design process. Rather than designing full-pages, content editors were presented with pre-styled blocks. This got us to Gutenberg.

If you’ve created posts on Medium or other platforms, this will be familiar to you. On WordPress though, there are a shedload of blocks shipped by default and you can add your own.

Sadly, the developer experience didn’t improve with Gutenberg (and in fact may have got worse). The editor has a great content creation experience, working with blocks, re-ordering and making their page look great. Gutenberg renders all of the HTML for the page on save and pushes it to the database. This means that by default, we get a huge HTML blob for the whole page in the API. We have no access to which blocks were used, we don’t know which attributes were selected and we have CSS classes being added automatically.

The developer ends up having to parse a single content block. If you are using React, you might use dangerouslySetInnerHtml to render this content on the front-end. Alternatively, you might create a parsing function that sanitises your content.

If you are designing data-driven components on the front-end, that adapt to the content provided by the user dynamically, it can be easier to get the raw content without the wrapping and parsing that is added by WordPress. WordPress developers generally turn to the Advanced Custom Fields (ACF) plugin to help them out with this. There are so many possibilities here – for now, we’ll see how we can add a few fields and leave it open for you to add additional fields as your needs grow.


  1. Add ACF plugin.
  2. Add the WPGraphQL for Advanced Custom Fields plugin.
  3. Create a custom field set.
  4. Exclude the Gutenberg blocks.
  5. Update the graphQL calls.

Add ACF plugin

This is available from the WP plugin library. Here is the projects documentation to help with getting up and running. https://www.advancedcustomfields.com/resources/getting-started-with-acf/

Add the WPGraphQL for Advanced Custom Fields plugin

This isn’t available in the library and will need to be installed manually. The Github repo is https://github.com/wp-graphql/wp-graphql-acf.

How to do that?

  • Go to tags -> latest release -> and zip file in the assets section at the bottom.
  • Download that file
  • Go to Plugins -> Add plugins -> Upload plugin and upload the zip file.
  • Save and activate.

Create a custom field set and expose it to graphQL

When you have created your field set, you’ll need to expose it to graphQL. There are some instructions here. It’s easier to refer to all of the acf field groups with the same name – acf or acfFields. This consistency makes querying the data more straightfoward. https://www.wpgraphql.com/acf/

Exclude the Gutenberg blocks

To exclude all Gutenberg blocks, you’ll need to add some custom code to your theme.

In the WordPress dashboard, navigate to Appearance->Theme Editor. You’ll get a warning here about changing these files – don’t worry, we know what we’re doing!

On the right, you’ll see a list of the theme files. Open your theme functions file (functions.php). Scroll to the bottom and add this code.

add_filter( 'allowed_block_types', 'nextstarter_allowed_block_types' );

function nextstarter_allowed_block_types( $allowed_blocks ) {
	return [];

What’s going on here?

  • add_filter takes two arguments:
    • The first is where in the WordPress lifecycle (the loop) would you like to add the filter.
    • The second is what function responds to that lifecycle event.
  • The function at the bottom is namespaced to nextstarter but could be anything as long it matched the referenced value in the add_filter call. All this function does is return an empty array. In other words, we are allowing no Gutenberg blocks.

Update the graphQL calls

They might look something like this:

  posts {
    nodes {
      acf {
        headerImage {

What’s going on here?

We’re still getting most of the meta fields (title, date, etc). Instead of getting content from the whole page, we are getting it for each ACF field. contentexcerpt and headerImage are all fields in my post object. The first two are just text with some minimal markup, the third is an image. For images we are able to get more targetted information that our frontend will need to consume.

What’s next?

As your front-end design grows and develops, you’ll want to add fields for your users to populate. This more data-driven approaches allows you to provide more restricted options that will always look good. I think of it as a limited set of Lego bricks that always will work together rather than the whole universe of Lego which may look amazing or terrible.