CoursesMigrating content from WordPress to SanityPreparing a Studio and schema types
Track
Replatforming from a legacy CMS to a Content Operation System

Migrating content from WordPress to Sanity

Lesson
3

Preparing a Studio and schema types

Configure the Sanity Studio schema to view your imported WordPress content in real-time.

Log in to mark your progress for each Lesson and Task

You could begin immediately importing data of any shape into the Content Lake before configuring your Sanity Studio with a schema.

By preparing the schema types first, you'll gain the extremely satisfying feedback loop of seeing the Studio update in real time with your imported content. It also makes it possible to collaborate with a content team and get feedback on how the editorial experience works for them.

Notice that we are adapting the implied content model from WordPress fairly 1:1 in this part of the course. Later, we'll walk you through extracting and structuring WordPress content into a more refined content model.

Unless you're working on an existing project, start a new free Sanity project from the command line:

npm create sanity@latest -- --template clean --create-project "Sanity WordPress" --dataset production --typescript --output-path sanity-wordpress
Initialize a new Sanity Studio project folder or navigate to an existing that you want to work from

Once the installation is done, cd into your new Studio folder, and run this command to install the Sanity Icons package (replace npm with your preferred package manager):

npm install @sanity/icons
Install @sanity/icons as a dependency

You'll start by adding schema types to the Studio similar to the response shapes you'll get from WordPress' REST API.

Note that some of these fields correspond to functionality in WordPress but will only be "data" in a Sanity context. For example, the status field will only be data on a document but can be adapted into Sanity's document and workflow model. The sticky field can be used and repurposed when you integrate this content in a front end through queries ("give me the newest document withthe sticky property"). You can also disregard or delete these fields later if you don't need to keep them around.

Create the following files in your Sanity Studio:

Create a schema type for Pages:
./schemaTypes/pageType.ts
import {DocumentIcon} from '@sanity/icons'
import {defineField, defineType} from 'sanity'
export const pageType = defineType({
name: 'page',
title: 'Page',
type: 'document',
icon: DocumentIcon,
fields: [
defineField({name: 'title', type: 'string'}),
defineField({name: 'slug', type: 'slug'}),
defineField({name: 'date', type: 'datetime'}),
defineField({name: 'modified', type: 'datetime'}),
defineField({
name: 'status',
type: 'string',
options: {
list: [
{title: 'Published', value: 'publish'},
{title: 'Future', value: 'future'},
{title: 'Draft', value: 'draft'},
{title: 'Pending', value: 'pending'},
{title: 'Private', value: 'private'},
{title: 'Trash', value: 'trash'},
{title: 'Auto-Draft', value: 'auto-draft'},
{title: 'Inherit', value: 'inherit'},
],
},
}),
defineField({
name: 'content',
type: 'portableText',
}),
defineField({
name: 'excerpt',
type: 'portableText',
}),
defineField({name: 'featuredMedia', type: 'image'}),
defineField({
name: 'author',
type: 'reference',
to: [{type: 'author'}],
}),
],
preview: {
select: {
title: 'title',
subtitle: 'author.name',
media: 'featuredMedia',
},
},
})
Create a schema type for Posts
./schemaTypes/postType.ts
import {ComposeIcon} from '@sanity/icons'
import {defineField, defineType} from 'sanity'
export const postType = defineType({
name: 'post',
title: 'Post',
type: 'document',
icon: ComposeIcon,
fields: [
defineField({name: 'title', type: 'string'}),
defineField({name: 'slug', type: 'slug'}),
defineField({name: 'date', type: 'datetime'}),
defineField({name: 'modified', type: 'datetime'}),
defineField({
name: 'status',
type: 'string',
options: {
list: [
{title: 'Published', value: 'publish'},
{title: 'Future', value: 'future'},
{title: 'Draft', value: 'draft'},
{title: 'Pending', value: 'pending'},
{title: 'Private', value: 'private'},
{title: 'Trash', value: 'trash'},
{title: 'Auto-Draft', value: 'auto-draft'},
{title: 'Inherit', value: 'inherit'},
],
},
}),
defineField({
name: 'content',
type: 'portableText',
}),
defineField({
name: 'excerpt',
type: 'portableText',
}),
defineField({name: 'featuredMedia', type: 'image'}),
defineField({name: 'sticky', type: 'boolean'}),
defineField({
name: 'author',
type: 'reference',
to: [{type: 'author'}],
}),
defineField({
name: 'categories',
type: 'array',
of: [{type: 'reference', to: [{type: 'category'}]}],
}),
defineField({
name: 'tags',
type: 'array',
of: [{type: 'reference', to: [{type: 'tag'}]}],
}),
],
preview: {
select: {
title: 'title',
subtitle: 'author.name',
media: 'featuredMedia',
},
},
})
Create a schema type for tags
./schemaTypes/tagType.ts
import {TagIcon} from '@sanity/icons'
import {defineField, defineType} from 'sanity'
export const tagType = defineType({
name: 'tag',
title: 'Tag',
type: 'document',
icon: TagIcon,
fields: [defineField({name: 'name', type: 'string'}), defineField({name: 'slug', type: 'slug'})],
preview: {
select: {
title: 'name',
subtitle: 'slug.current',
},
},
})
Create a schema type for categories
./schemaTypes/categoryType.ts
import {FilterIcon} from '@sanity/icons'
import {defineField, defineType} from 'sanity'
export const categoryType = defineType({
name: 'category',
title: 'Category',
type: 'document',
icon: FilterIcon,
fields: [
defineField({name: 'name', type: 'string'}),
defineField({name: 'slug', type: 'slug'}),
],
preview: {
select: {
title: 'name',
subtitle: 'slug.current',
},
},
})
Create a schema type for authors
./schemaTypes/authorType.ts
import {UserIcon} from '@sanity/icons'
import {defineField, defineType} from 'sanity'
export const authorType = defineType({
name: 'author',
title: 'Author',
type: 'document',
icon: UserIcon,
fields: [
defineField({name: 'name', type: 'string'}),
defineField({name: 'slug', type: 'slug'}),
defineField({name: 'url', title: 'URL', type: 'url'}),
defineField({name: 'description', type: 'text'}),
defineField({name: 'avatar', type: 'image'}),
],
preview: {
select: {
title: 'name',
subtitle: 'url',
media: 'avatar',
},
},
})

WordPress stores a document's "author" in the database as a "user." While keeping track of who did what to all documents in the Content Lake, Sanity does not automatically add project member data to your documents. The advantage of this separation is that you can treat "authors" more as an editorial concern, extend the author model as you wish to, and have authors that don't correspond to project members (for example, guest authors outside of your organization). This also allows you to migrate the single author field into an array of authors fields later.

So, you will create an "author" document for every WordPress "user" and reference that document in posts and pages.

The Sanity User Select input is a useful plugin if you need to relate Sanity project members to a document.

The document schema types created above use custom schema types that must also be registered to the Studio configuration.

A field for storing rich text and block content, including images, and a custom schema type for storing an external image URL.

Create a schema type for Portable Text
./schemaTypes/portableTextType.ts
import {defineField} from 'sanity'
export const portableTextType = defineField({
name: 'portableText',
type: 'array',
of: [{type: 'block'}, {type: 'image'}, {type: 'externalImage'}],
})

The custom type for an external image, useful during the migration and upload process.

Create a schema type for the externalImage block
./schemaTypes/externalImageType.ts
import {defineType} from 'sanity'
export const externalImageType = defineType({
name: 'externalImage',
title: 'External Image',
type: 'object',
fields: [
{
name: 'url',
title: 'URL',
type: 'url',
},
],
})
Add these to your schemaTypes array in your sanity.config.ts file.
./schemaTypes/index.ts
import {authorType} from './authorType'
import {categoryType} from './categoryType'
import {externalImageType} from './externalImageType'
import {pageType} from './pageType'
import {postType} from './postType'
import {tagType} from './tagType'
import {portableTextType} from './portableTextType'
export const schemaTypes = [
authorType,
categoryType,
pageType,
postType,
tagType,
externalImageType,
portableTextType
]

Now, run your development server:

npm run dev

Open your Studio at http://localhost:3333. Once logged in, you should see the Structure tool with your five document schema types.

With the Studio primed to author and query content, let's prepare a basic migration script to import some content.

Courses in the "Replatforming from a legacy CMS to a Content Operation System" track