RichText Component

Previously, we created pages for each content object and also established a structure with folders and internal linking.

Now we need to display the data inside these pages the right way.

In a Plone site, content objects may contain media such as images, videos and even files. The plone.restapi also returns text data in a content object such as a PloneDocument as stringified HTML which could contain media and internal linking.

These cannot be directly used in a GatsbyJS site. Thankfully, the plugin is well equipped to handle these separately. Files and images are cached and backlinked to the page they are present in, with images even optimized with the Sharp plugin.

The stringified HTML is processed and serialized. For usage with React, a RichText component deserializes this data and also handles media and internal linking.

That was a lot of terminology and information, let us get into each part one by one so as to make things clear.

Images And Files

Media content such as Images and Files are processed separately by the plugin, stored in the cache and handled by the gatsby-source-filesystem plugin.

Note

Some configuraton with gatsby-source-filesystem is required in the GatsbyJS site before it can query file nodes. Make sure it is installed and then update gatsby-node.js with:

{
  resolve: 'gatsby-source-filesystem',
  options: {
    path: `${__dirname}/src/static`,
  },
},

And then create a static folder in the src. The plugin requires a folder to be used as source to work even when the file nodes are all generated by our source plugin.

Now files and images can be queried with GraphQL.

In http://localhost:8000/___graphql

allPloneFile(filter: { _backlinks: { eq: $path } }) {
  edges {
    node {
      id
      title
      file {
        filename
        publicURL
      }
      _path
    }
  }
}

allPloneImage(filter: { _backlinks: { eq: $path } }) {
  edges {
    node {
      id
      title
      image {
        publicURL
        childImageSharp {
          fixed(width: 600) {
           ...GatsbyImageSharpFixed
          }
        }
      }
    _path
    }
  }
}

Files can be directly made downloadable by using the publicURL attribute. For images, we use a different approach altogether. They are first optimized and processed by Sharp plugins before they are used. Install them with npm install gatsby-image gatsby-plugin-sharp gatsby-transformer-sharp

Add them to gatsby-node.js:

plugins: [
  'gatsby-plugin-sharp',
  'gatsby-transformer-sharp'
],

Now, the images are available to be queried per the example above.

Note

The fixed width used there is 600 but this can be changed according to your requirements. The whole range of options can be found in the docs.

RichText Component

We already know how images and files can be queried with GraphQL. To use them along with the HTML content, we use the RichText Component.

Before we jump into that, let us inspect how HTML content is handled by the plugin.

Exercise

Explore GraphiQL at http://localhost:8000/___graphql and compare the stringified HTML and serialized React version of the text data.

Hints: Try checking the text field of the nodes of type PloneDocument

Solution

{
  allPloneDocument {
    edges {
      node {
        id
        text {
          data
          react
        }
      }
    }
  }
}

Notice that node.text.react is in serialized form that can be deserialized and used with React.

Note

Internally, react-serialize is used by the RichText component to handle serialized HTML data. This eliminates the use of dangerouslySetInnerHTML, which is recommended to be avoided.

The following is a usage example of the RichText component. Document.js handles all nodes of type PloneDocument on page creation.

import RichText from './RichText';

const Document = ({ data, images = [], files = [] }) => (
  <article key={data._id}>
    <h1>{data.title}</h1>
    {data.text ? (
      <RichText serialized={data.text.react} images={images} files={files} />
    ) : null}
  </article>
);

Let us do a quick review of how it all falls in place together:

  • default.js is the template used for all content objects.
  • Internally in the template, based on the type, the appropriate component is selected.
  • Data is retrieved via GraphQL in the template itself based on the type.
  • For all types of content objects, images and files are queried separately with backlinks and passed in to the component.
  • In the components, RichText component is utilized to display HTML content with images, files and internal links.