Integrating frontity with gutenberg (using processors)

Hello everyone!

I’m just getting started with React and Frontity. I’m trying to build a theme but I need to be sure of how I should handle page building.

So far, I’ve come to the conclusion that the best way to build the pages that Frontity will get is with Gutenberg, however I can’t seem to find a lot of resources regarding this. So far, this topic (more specifically @luisherranz 's answer with the Gallery example and https://docs.frontity.org/api-reference-1/frontity-html2react have been my main sources of information, but I still have some questions.

For example, I’m trying to build a Component to handle the .wp-block-quote Gutenberg block. This block, specifically renders like this:

<blockquote class="wp-block-quote">
    <p>No more of this</p>
    <cite>Some guy said this</cite>
</blockquote>

And I’ve build a Component like this:

const Quote = ({ props }) => {
    return (
        <div>
            <h3>{props.quote}</h3>
            <h5>{props.author}</h5>
        </div>
    )
}

Now I’m trying to build a processor so that I can map the <p> to the <h3> and the <cite> to the <h5>, and here is what I have so far:

const quote = {
    name: 'quote',
    priority: 20,
    test: ({ component, props }) =>
        component === "blockquote" &&
        props.className === "wp-block-quote",
    processor: ({ node }) => {
        return {
          component: Quote,
          props: {  },
        }
      },
}

export default quote;

But I don’t know how to indicate that the <p> content should go to the <h3> and that the <cite> should go to the <h5>.

Can someone help me?
Thanks

2 Likes

I managed to find the solution. In case somebody else faces the same challenge, here is what I did:

I realised that the node object has the children in it so I passed the node children in the props like this:

const quote = {
    name: 'quote',
    priority: 20,
    test: ({ noce }) =>
        node.component === "blockquote" &&
        node.props.className === "wp-block-quote",
    processor: ({ node }) => {
        return {
          component: Quote,
          props: { 
            quote: node.children[0].children[0].content,
            author: node.children[1].children[0].content,
          },
        }
      },
}

export default quote;

and then I changed my component to the following:

const Quote = ({ quote, author }) => {
    return (
        <div>
            <h3>{quote}</h3>
            <h5>{author}</h5>
        </div>
    )
}

And it worked.

1 Like

Hi @filipe,

I’m glad you found out the solution.
I’ve used this use case to prepare a demo as an example of how to create (and use) a custom processor

@juanma Thanks!! I’m glad my question can help others! Maybe this https://docs.frontity.org/api-reference-1/frontity-html2react#create-your-own-processors should have another example? Because the Image Processor example doesn’t cover a lot of use cases, including those such as this one, where you want to pass the “processed” html into multiple different places inside the Component.

What do you think?

can you post full example of gutenburge gallery to React Carousel ? probably on https://github.com/frontity-demos/frontity-examples

i have following code sample inspired from @luisherranz post, but no luck

You are probably missing the CSS styling for this. I added the Gutenberg stylesheet locally to my project to make the default Gutenberg blocks work somewhat.

I think Frontity is working on something better but that is not available at the moment: Gutenberg Package

Hey! Are you importing the processors?

Here’s what I mean: https://github.com/frontity-demos/frontity-examples/blob/295043a89783962c38ca5661a9f15719896b0dcf/processor-blockquote/packages/mars-theme/src/index.js#L49

I am asking this because from what you posted, it looks like the HTML rendered is the one coming straight from Gutenberg and not being processed.

Hi @filipe,

We did a full explanation of Processors using this use case in one of our Frontity Talks

For this specific demo:

Here you can see how the blockquote is indeed parsed and modified by the processor

The way it works is that in /processor-blockquote/packages/mars-theme/src/index.js

import Theme from "./components";
import image from "@frontity/html2react/processors/image";
import iframe from "@frontity/html2react/processors/iframe";
import quote from "./processors/quote";

const marsTheme = {
  name: "@frontity/mars-theme",
  ...
  libraries: {
    html2react: {
      processors: [image, iframe, quote],
    },
  },
};

export default marsTheme;

we define the specific processors that will be used by the html2react package for this theme

Each processor will be applied when parsing the HTML displayed in React through the <Html2React> component

<Html2React html={post.content.rendered} />

These processors are defined by a pattern that will be looked for the HTML and a React component that will be returned instead of every piece of HTML that matchesthe pattern

Hope this helps

2 Likes

Hello.

Nice video re. processors. Could you clarify one thing for me?

If I have the default style for a blockquote set via Global.

Then I want to apply styling overrides to the elements with a class, is there a way to perform more than one test on the element or do I need to create a separate processor file for each match?

I tried doing this but to no avail:

const quote = {
    name: 'quote',
    priority: 10,
    test: ({ component, props }) => component === "blockquote" && props.className.includes("q-primary"),
    processor: ({ node }) => {

        console.log('Quote1');

        const quote = node.children[0].children[0].content
        const author = node.children[1].children[0].content
        return {
            component: Quote,
            props: { quote, author },
        }
    },
    test: ({ component, props }) => component === "blockquote" && props.className.includes("q-secondary"),
    processor: ({ node }) => {

        console.log('Quote2');

        const quote = node.children[0].children[0].content
        const author = node.children[1].children[0].content
        return {
            component: Quote,
            props: { quote, author },
        }
    },
}

Yeah, I’m not sure but I think you will need a different processor file for each match. If you check here: https://docs.frontity.org/api-reference-1/frontity-html2react#create-your-own-processors

A processor is an object with four properties: name , priority , test , and processor .

Hi @shaun,

In case you want to use several conditions to create a pattern that returns a specific component, you can try something like this

const quote = {
    name: 'quote',
    priority: 10,
    test: ({ component, props }) => component === "blockquote" && (props.className.includes("q-primary") || props.className.includes("q-secondary")),
    processor: ({ node }) => {
        const quote = node.children[0].children[0].content
        const author = node.children[1].children[0].content
        return {
            component: Quote,
            props: { quote, author },
        }
    }

test expects a function which will receive each component (each tag) with its props (its attributes).

This function returns a boolean value, so inside this function you can perform any operation and comparison as long as the function returns a boolean value that reflects the matching pattern you want for that processor

In a more verbose way, this processor could be defined as…

const quote = {
    name: 'quote',
    priority: 10,
    test: ({ component, props }) => {
      const isBlockquoteTag = component === "blockquote"
      const hasProperClassNames =  (props.className.includes("q-primary") || props.className.includes("q-secondary"))
      // // also ↓
      // const patternClassNames = ["q-primary", "q-secondary"]
      // const hasProperClassNames = props.className.some(c => patternClassNames.includes(c))
      return isBlockquoteTag && hasProperClassNames
    },
    processor: ({ node }) => {
        const quote = node.children[0].children[0].content
        const author = node.children[1].children[0].content
        return {
            component: Quote,
            props: { quote, author },
        }
    }

I think @shaun is trying to return different components depending on the className, which is a different situation from what you are describing @juanma

in that case, yes, you need a processor for every component you want to return.

OK, thanks for the input…

I’ve had a play this morning, I’m close but no cigar!

Here’s the dev deployment, if you F12 you will see the issue: https://primitivestuff.primitiveshaun.vercel.app/frontity-tests/

I tried using one processor (blockquote.js) file and two but see the same problem > Processors

The props are alternating as undefined, am I doing something wrong?