Contentful Embedded Content in Gatsby
This is specifically for Gatsby as that’s what I was using, but I suppose the implementation will be similar in other React/GraphQL environments.
When using @contentful/rich-text-react-renderer to render a Contentful entry, they suggest passing a custom rendering component for embedded entries.
However, I was unable to get a fully populated node in the render handlers that would contain all the fields I require, with only access to the contentful_id and the entry type. Whatever I fetched in graphql was available in the references key of the content body, but it wasn’t being sent on. Didn’t bother to check how this works under the hood, but managed to achieve what I wanted by passing the references object to the custom renderer and searching for the relevant entry by contentful_id.
| import { documentToReactComponents } from '@contentful/rich-text-react-renderer'; | |
| import { graphql } from 'gatsby'; | |
| import React from 'react'; | |
| // Custom renderer for embedded content which accepts `body` / `references` from the graphql query. | |
| // Search `references` for the embedded object ID for full access to nested content. | |
| const rendererOptions = (references) => ({ | |
| renderNode: { | |
| [BLOCKS.EMBEDDED_ASSET]: (node) => { | |
| const imageID = node.data.target.sys.id; | |
| const { | |
| file: {url}, | |
| title | |
| } = references.find(({contentful_id: id}) => id === imageID); | |
| return <img src={url} alt={title} />; | |
| }, | |
| [BLOCKS.EMBEDDED_ENTRY]: (node) => { | |
| const entryID = node.data.target.sys.id; | |
| const { title, slug } = references.find(({contentful_id: id}) => id === entryID); | |
| return <a href={`/${slug}`}>{title}</a>; | |
| }, | |
| }, | |
| }); | |
| const Post = ({ data }) => { | |
| const { post } = data; | |
| return ( | |
| <article> | |
| {documentToReactComponents( | |
| JSON.parse(post.body.raw), | |
| rendererOptions(post.body.references) | |
| )} | |
| </article> | |
| ); | |
| }; | |
| export default Post; | |
| // Include all required fields for the content references. For GatsbyJS at the least, `contentful_id` and `__typename` are required. | |
| export const query = graphql` | |
| query Post($id: String) { | |
| post: contentfulBlog(id: { eq: $id }) { | |
| body { | |
| raw | |
| references { | |
| ... on ContentfulAsset { | |
| contentful_id | |
| __typename | |
| title | |
| file { | |
| url | |
| } | |
| } | |
| ... on ContentfulArticle { | |
| contentful_id | |
| __typename | |
| title | |
| slug | |
| } | |
| } | |
| } | |
| } | |
| } | |
| `; |