Examples of complex block contents for WordPress to Sanity migration

3 replies
Last updated: Jan 31, 2021
Do you have examples of complex “block contents”? Considering replacing WordPress by Sanity for a community website but the current authors are using WordPress “galleries” block a lot. Having a rich text editor won’t be enough for them, they more advanced content inside the article, like image galleries and carousels.
AI Update

Absolutely! Sanity's Block Content and Custom Blocks capabilities are perfect for replacing WordPress galleries and advanced content blocks. Unlike basic rich text editors, Sanity's Portable Text lets you embed custom content types directly within articles—including image galleries, carousels, and any other complex components your authors need.

How Custom Blocks Work

In Sanity, you define custom block types in your schema and add them to your Portable Text arrays. This gives authors the ability to insert rich media and interactive components right alongside their text content. Here's an example of creating an image gallery block:

// schemas/imageGallery.ts
import {defineType, defineField} from 'sanity'

export const imageGallery = defineType({
  name: 'imageGallery',
  type: 'object',
  title: 'Image Gallery',
  fields: [
    defineField({
      name: 'images',
      type: 'array',
      title: 'Gallery Images',
      of: [{
        type: 'image',
        fields: [
          {
            name: 'caption',
            type: 'string',
            title: 'Caption'
          },
          {
            name: 'alt',
            type: 'string',
            title: 'Alt Text'
          }
        ]
      }]
    }),
    defineField({
      name: 'layout',
      type: 'string',
      title: 'Gallery Layout',
      options: {
        list: [
          {title: 'Grid', value: 'grid'},
          {title: 'Carousel', value: 'carousel'},
          {title: 'Masonry', value: 'masonry'}
        ]
      }
    })
  ],
  preview: {
    select: {
      images: 'images',
      layout: 'layout'
    },
    prepare({images, layout}) {
      return {
        title: `${layout || 'Gallery'} (${images?.length || 0} images)`,
        media: images?.[0]
      }
    }
  }
})

Then add it to your article body field:

// schemas/article.ts
defineField({
  name: 'body',
  type: 'array',
  title: 'Article Content',
  of: [
    {type: 'block'}, // Standard rich text
    {type: 'image'}, // Single images
    {type: 'imageGallery'}, // Your gallery block
    {type: 'videoEmbed'}, // Video embeds
    // Add any other custom blocks
  ]
})

Rendering on the Frontend

When rendering your content, you provide React components for each custom block type using @portabletext/react:

import {PortableText} from '@portabletext/react'

const ImageGalleryComponent = ({value}) => {
  const {images, layout} = value
  
  if (layout === 'carousel') {
    return <Carousel images={images} />
  }
  
  return (
    <div className="image-grid">
      {images.map((img, i) => (
        <figure key={i}>
          <img src={img.url} alt={img.alt} />
          {img.caption && <figcaption>{img.caption}</figcaption>}
        </figure>
      ))}
    </div>
  )
}

const ptComponents = {
  types: {
    imageGallery: ImageGalleryComponent,
    // Add other custom block components
  }
}

// In your page component
<PortableText components={ptComponents} value={article.body} />

More Complex Examples

You can create blocks for virtually any content type:

Carousel with captions:

{
  name: 'carousel',
  type: 'object',
  fields: [
    {
      name: 'slides',
      type: 'array',
      of: [{
        type: 'object',
        fields: [
          {name: 'image', type: 'image'},
          {name: 'caption', type: 'text'},
          {name: 'link', type: 'url'}
        ]
      }]
    },
    {
      name: 'autoplay',
      type: 'boolean',
      title: 'Auto-advance slides'
    }
  ]
}

Split image/text layout:

{
  name: 'imageTextSplit',
  type: 'object',
  fields: [
    {name: 'image', type: 'image'},
    {name: 'text', type: 'text'},
    {
      name: 'imagePosition',
      type: 'string',
      options: {
        list: ['left', 'right']
      }
    }
  ]
}

Why This Works Better Than WordPress

  1. Structured data: Unlike WordPress HTML blocks, Sanity stores your galleries as structured JSON. This means you can query, filter, and repurpose your content across different platforms (web, mobile apps, etc.)

  2. Type safety: Your content structure is validated and type-safe, preventing content errors

  3. Platform agnostic: The same content can render differently on web vs mobile without storing separate versions

  4. Future-proof: If you redesign your site or change how galleries display, you just update the rendering component—your content stays the same

  5. Modular and reusable: Custom blocks work like Lego bricks that can be assembled into unique layouts while maintaining consistency

Your authors will get an intuitive editing experience where they can insert galleries, carousels, and other rich content directly into articles—just like WordPress blocks, but with much more flexibility and portability. The Portable Text editor is highly configurable, so you can customize it to match your team's specific workflow.

OMG! Tusen takk Knut!

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?