How to implement Gutenberg blocks

I open this topic to answer David Rhoderick question started in GitHub.

Original question

I apologize if this is a naive but I am experienced with WordPress but haven’t worked much with Gutenberg blocks. How would one approach styling the Gutenberg blocks accordingly? For example, if I want to use reactstrap to add a carousel element for a gallery block created by Gutenberg, how would one do that? Feel free to close this if it is not in the scope of this project’s documentation.

This is how Gutenberg gallery blocks are exposed in the content field of the WordPress REST API post response:

<ul
  class="wp-block-gallery columns-3 is-cropped">
  <li class="blocks-gallery-item">
    <figure><img ... /></figure>
  </li>
  <li class="blocks-gallery-item">
    <figure><img ... /></figure>
  </li>
  <li class="blocks-gallery-item">
    <figure><img ... /></figure>
  </li>
  <li class="blocks-gallery-item">
    <figure><img ... /></figure>
  </li>
</ul>

In order to modify this content field HTML we have created a new package called html2react.

You need to create a “processor” that looks for <ul> with class="wp-block-gallery" and returns the proper React component.

import { Carousel } from 'reactstrap';

const gutenbergGallery = {
  test: ({ component, props }) =>
    component === "ul" &&
    props.className === "wp-block-gallery"
  process: ({ node }) => {
    // node contains all the info of the <ul>, including node.children
    // with info of the <li>.
    return {
      component: Carousel,
      props: { ... },
    }
  },
};

const myTheme = {
  actions: {
    init: ({ libraries }) => {
      libraries.html2react.processors.push(gutenbergGallery);
    }
  }
}

We have a PR right now with html2react almost ready to be merged: https://github.com/frontity/frontity/pull/116

This is probably the most difficult part of Frontity, but there’s no way around it. The info of the content is exposed as HTML by WordPress and if you want to use React, you need an html2react library no matter what framework you use :slight_smile:


@orballo could you please take a look at my code and edit what’s wrong. I don’t have in mind the final API of html2react yet.

If I’m not mistaken I think you can return children and then the children nodes will be processed by html2react as well. So you could use it to process the items in individual processes:

import { Carousel, CarouselItem } from 'reactstrap';

const gutenbergGallery = {
  test: ({ component, props }) =>
    component === "ul" &&
    props.className === "wp-block-gallery"
  process: ({ node }) => {
    // node contains all the info of the <ul>, including node.children
    // with info of the <li>.
    return {
      component: Carousel,
      props: { ... },
      // return children nodes so they are processed again by html2react.
      children: node.children, 
    }
  },
};

const gutenbergGalleryItem = {
  test: ({ component, props }) =>
    component === "li" &&
    props.className === "blocks-gallery-item"
  process: ({ node }) => {
    // this is now the item
    return {
      component: CarouselItem,
      props: { ... }
    }
  },
};

const myTheme = {
  actions: {
    init: ({ libraries }) => {
      libraries.html2react.processors.push(gutenbergGallery);
      libraries.html2react.processors.push(gutenbergGalleryItem);
    }
  }
}

Is this right @development-team?

Yep, I think that’s right. If what you are trying to support only needs some custom CSS, you might do just well with the css function from emotion and assigning the return value to the css prop.

But if you are passing a new component that doesn’t accept children, you might need to collect all the data in the process function and map into the props needed by your component. For example, in this case maybe you want to get all the src attributes from the images and push them into an array that you want to pass as a prop to Carousel.

You can watch how implement it in this short video https://youtu.be/jauZCeLrGFA

We are taking a deeper look at how Gutenberg works and what is the best approach to integrate it with Frontity. This is the topic in case anyone is interested: Gutenberg Support.