👋 Next.js Conf 2024: Come build, party, run, and connect with us! See all events

Normalize Portable Text blocks

By Per-Kristian Nordnes

Migration script to normalize Portable Text blocks across your whole dataset

normalizeAllBlocks.js

import sanityClient from "part:@sanity/base&client";
import { normalizeBlock } from "@sanity/block-tools";
import { extractWithPath } from"@sanity/mutator";

// Act on all documents
const query = "*[]";

// Adjust the decorators to the set you want to allow
const allowedDecorators = [
  "strong",
  "em",
  "code",
  "underline",
  "strike-through",
  "sub",
  "sup"
];


function convertPath(pathArr) {
  return pathArr
    .map(part => {
      if (Number.isInteger(part)) {
        return `[${part}]`;
      }
      return `.${part}`;
    })
    .join("")
    .substring(1);
}

client.fetch(query).then(results => {
  const patchedDocuments = [];
  results.forEach(async result => {
    const matches = extractWithPath('..[_type=="block"]', result);
    let patch = client.patch(result._id);
    matches.forEach(match => {
      const block = match.value;
      const path = convertPath(match.path);
      const normalizedBlock = normalizeBlock(block, { allowedDecorators });
      const patchData = { [path]: normalizedBlock };
      patch = patch.set(patchData);
    });
    const patchLength = patch.operations.set
      ? Object.keys(patch.operations.set).length
      : 0;
    if (patchLength > 0) {
      patchedDocuments.push(result._id);
      await patch.commit();
      console.log(
        `Patched ${patchLength} blocks in document ${result._id}`
      );
    }
  });
  console.log(
    `Patched ${patchedDocuments.length} documents with ids: ${JSON.stringify(
      patchedDocuments,
      null,
      2
    )}`
  );
});

NOTE: We have shipped content migration tooling for Sanity (v3.27.0) that makes the approach described here. Check out the documentation and cheat sheet for learning how to do this with the proper tooling.

This migration script will go through all your documents, look for all Portable Text blocks and filter out decorators that aren't present in the allowedDecorators array. It will build a transaction of patches to update these blocks.

You can run this script with sanity exec normalizeAllBlocks.js --with-user-token. It might be wise to export your dataset first since this script changes data.

Contributor

Other schemas by author