Converting portable text to plaintext in Sanity.io using a script
pt::text(body), sets that in a
textfield, and then unsets the portable text field. The following should work to copy over to the new field. Note it’s a v2 script so if you’re using v3, you’ll want to adjust the client import. It also doesn’t unset (i.e., remove) the old portable text, as I’m not sure whether you want that or not.
/* eslint-disable no-console */
import sanityClient from 'part:@sanity/base/client'
const client = sanityClient.withConfig({ apiVersion: '2023-03-02' })
const fetchDocuments = () => client.fetch(`*[_type == 'post' && plaintext != pt::text(body)]{_id, _rev, plaintext, 'body': pt::text(body)}`)
const buildPatches = docs => (
docs.map(doc => ({
id: doc._id,
patch: {
set: {
plaintext: doc.body
},
ifRevisionID: doc._rev,
}
}))
)
const createTransaction = patches =>
patches.reduce((tx, patch) => tx.patch(patch.id, patch.patch), client.transaction())
const commitTransaction = tx => tx.commit()
const editNextBatch = async () => {
const documents = await fetchDocuments()
const patches = buildPatches(documents)
if (patches.length === 0) {
console.log('No more documents to edit!')
return null
}
console.log(
`Editing batch:\n %s`,
patches.map(patch => `${patch.id} => ${JSON.stringify(patch.patch)}`).join('\n')
)
const transaction = createTransaction(patches)
await commitTransaction(transaction)
return editNextBatch()
}
editNextBatch().catch(err => {
console.error(err)
process.exit(1)
})scripts/) and are run with
sanity exec scripts/scriptName.js --with-user-token--with-user-tokenflag is needed when a script needs to do something requiring adequate permissions).
Was this answer helpful?
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.