You're reading docs for Nextly Alpha. APIs may change between releases.

Page Builder

Locked areas

Lock a block's slot so authors keep its structure, and choose what they may still change.

A block can lock one of its slots. A locked slot holds the blocks it starts with, the ones its defaultBlock creates when the block is placed, so a designed section keeps its shape however an author edits the page. The locks use WordPress's templateLock names and meanings, so authors who know one know the other.

The four locks

import { defineBlock } from "@nextlyhq/plugin-sdk/blocks";

export const hero = defineBlock({
  name: "acme/hero",
  version: 1,
  description: "A headline and a call to action, in that order.",
  example: { props: {} },
  slots: {
    content: {
      defaultBlock: [{ type: "acme/headline" }, { type: "acme/button" }],
      lock: "all",
    },
  },
  render: ({ renderSlot }) => renderSlot("content"),
});
lockBlocks can be added or removedBlocks can be movedWhat can change
"insert"noyescontent and design
"all"nonocontent and design
"contentOnly"nonocontent only
falseyesyesanything (the slot is unlocked)

A slot that declares no lock takes the lock of the slot its block sits in, so a locked section stays locked all the way down. false stops that, except beneath "contentOnly", which nothing inside it can loosen.

Declare what is content

Inside a "contentOnly" slot, only the props a block declares as content can change: its text, its media, its links. Mark them with role: "content", as a WordPress block attribute is marked.

import { defineBlock } from "@nextlyhq/plugin-sdk/blocks";

export const headline = defineBlock({
  name: "acme/headline",
  version: 1,
  description: "A heading.",
  example: { props: { text: "Title", align: "left" } },
  props: {
    text: { type: "text", role: "content" },
    align: { type: "select" },
  },
  defaultProps: { text: "Title", align: "left" },
  render: ({ props }) => props.text,
});

The core blocks already declare theirs: a heading's text and link, an image's media, alt text and caption, a button's label and link, and so on.

Everything else stays as the block started: its other props, its styles, classes, its root element's id and attributes, visibility, custom CSS and its own lock. So does whether it renders: a block marked as failing its migration, or at a version ahead of its definition's, is drawn as a placeholder, and neither can change there. A block that declares no content props has nothing an author can change inside a "contentOnly" slot. Its layer name stays editable, since the page never draws it.

Who is held to a lock

Every save, whoever sends it: the editor, the API, an import or an agent. A save that breaks a lock is refused with an error naming the slot and the rule, for example:

The "content" slot of a "acme/hero" is locked "all", so it holds "acme/headline", "acme/button", in that order. It holds "acme/headline".

A lock is measured against the blocks the slot starts with, so changing a locked slot's defaultBlock changes what every stored page must hold. Bump the block's version and migrate the pages already stored.

Changing a block's defaultProps doesn't lock existing pages out. Inside a "contentOnly" slot, a save may keep any value the page already stores in the same place, or put it back as the block now starts. Only a third value is refused. A page saved for the first time, a single, and a localized blocks field are measured against the starting blocks alone. A page placing a component keeps what the component itself holds.

Components and locks

A lock inside a component holds on every page that places it. A placement cannot use an exposed field or an exposed slot to change what the lock holds, and such a page is refused, naming the placement.

A component cannot add an exposed field that drives something a "contentOnly" lock holds, since no placement could change it. Expose a content field instead, remove the exposure, or loosen the lock on that slot. An exposure a component already stores is kept, and reported in the server log, so an unrelated edit still saves.

Registration refuses a lock value other than the four, and a role other than "content", naming the block. nextly generate refuses them too, so a block manifest is never written for blocks the app would refuse at boot.