Search code examples
sanityeleventy

Sanity Serializers in Eleventy (11ty)


I've implemented Sanity CMS into Eleventy, and have a working 11ty filter that converts Portable Text to HTML.

I have a fair number of custom blocks, and therefore I'm also passing serializers. However, I am incapable of making one of those serializers work.

Here is my code:

On .eleventy.js

    // Portable Text to HTML Filter for Sanity
eleventyConfig.addFilter('sanityToHTML', function(value) {
    return blocksToHtml({
      blocks: value,
      serializers: serializers
    })
  })

On serializers.js

const { h } = require("@sanity/block-content-to-html");

module.exports = {
  types: {
      cta: ({ node }) => {
        return h(
          'a',
          {
            className:
              'bg-yellow-500 text-white',
            href: node.ctaUrl,
          },
          node.ctaText,
        )
      },
      infoText: ({ node }) => {
        return h(
          'p',
          {
            className:
              'bg-blue-500 text-white',
          },
          node.bodyInfo.map(children => children.text).join(''),
        )
      },
    },
  }

Eleventy is oputputting the <p class="bg-blue-500 text-white"></p> , but without content.

I've tried all combinations that I can think of.

My Sanity blog post has the following structure:

{
  "_createdAt": "2021-09-14T11:25:05Z",
  "_id": "89ff5403-326b-4db1-8752-04ea1c85f114",
  "_rev": "7dkOKJtWoyCn0kHUhHzZu7",
  "_type": "post",
  "_updatedAt": "2021-09-20T06:38:14Z",
  "body": [
    {
      "_key": "f84e932860bf",
      "_type": "block",
      "children": [
        {
          "_key": "bd29bce1dda1",
          "_type": "span",
          "marks": [],
          "text": ""
        }
      ],
      "markDefs": [
        {
          "_key": "38aa715c6214",
          "_type": "link",
          "href": "........"
        }
      ],
      "style": "normal"
    },
    {
      "_key": "bf5d17f3da91",
      "_type": "cta",
      "ctaText": "test",
      "ctaUrl": ".........."
    },
    {
      "_key": "595873ddfc54",
      "_type": "block",
      "children": [
        {
          "_key": "ba794ddbef68",
          "_type": "span",
          "marks": [],
          "text": ""
        }
      ],
      "markDefs": [
        {
          "_key": "38aa715c6214",
          "_type": "link",
          "href": ".........."
        }
      ],
      "style": "normal"
    },
    {
      "_key": "8acb94638c0c",
      "_type": "infoText",
      "bodyInfo": [
        {
          "_key": "6b6e533e67fd",
          "_type": "block",
          "children": [
            {
              "_key": "3593ad3abdf9",
              "_type": "span",
              "marks": [],
              "text": "test test info"
            }
          ],
          "markDefs": [],
          "style": "normal"
        }
      ]
    },
    .....etc

Any tips on how to make it display the actual content?


Solution

  • I believe the issue is in your infoText serializer. In that function, you're mapping over node.bodyInfo and then accessing the text property on the objects in bodyInfo. However, the objects in bodyInfo do not actually have a text property.

    {
      "_key": "8acb94638c0c",
      "_type": "infoText",
      "bodyInfo": [
        {
          "_key": "6b6e533e67fd",
          "_type": "block",
          "children": [
            {
              "_key": "3593ad3abdf9",
              "_type": "span",
              "marks": [],
              "text": "test test info"
            }
          ],
          "markDefs": [],
          "style": "normal"
        }
      ]
    }
    

    The string you are trying to extract is at bodyInfo[].children[].text, not bodyInfo[].text. To fix this, you might want to update your infoText serializer.

    infoText: ({ node }) => {
      return h(
        'p',
        {
          className: 'bg-blue-500 text-white',
        },
        node.bodyInfo.map(({children}) => children.map(child => child.text)).flat().join(''),
      )
    }
    

    In this version, we first map over bodyInfo, which is an array, then destructure the children property from the objects within. We then map over that to get our inner strings, then flatten the array to join.