Skip to content
JS Filters

lzb.constructor.panels

Filters the collapsible panels the block builder puts in the Inspector under the general settings. Add a panel here when an extension keeps its own data on the block and needs somewhere in the builder to edit it.

The default array holds four panels in this order: style-variations, supports, supports-ghost-kit and condition. All four start collapsed.

Attributes

NameTypeDescription
panelsArraypanel definitions, rendered in array order
dataObjectblockData, updateBlockData

Each panel is an object with four keys:

NameTypeDescription
nameStringReact key of the panel, and the handle other extensions match on
titleStringheading shown on the panel
componentFunctionReact component type, rendered with data and updateData props
initialOpenBooleanwhether the panel is expanded on first render

component is the component itself, not an element. The builder writes <PanelComponent data={blockData} updateData={updateBlockData} /> inside a PanelBody, so a panel that sets component to <MyPanel /> hands React an element where it expects a type and nothing renders.

data.updateBlockData shallow merges the object you give it into the block data, so a panel writes one field with updateData({ my_field: value }).

Usage

The Relationships panel finds the condition panel and splices itself in after it, which keeps the ordering stable when other extensions add panels too.

JS
const { TextControl } = wp.components;
 
function TrackingPanel({ data, updateData }) {
  return (
    <TextControl
      label="Tracking ID"
      value={data.my_tracking_id || ""}
      onChange={(value) => updateData({ my_tracking_id: value })}
    />
  );
}
 
wp.hooks.addFilter(
  "lzb.constructor.panels",
  "my.custom.namespace",
  function (panels) {
    const conditionIndex = panels.findIndex(
      (panel) => panel.name === "condition",
    );
    const insertIndex =
      conditionIndex === -1 ? panels.length : conditionIndex + 1;
 
    panels.splice(insertIndex, 0, {
      name: "my-tracking",
      title: "Tracking",
      component: TrackingPanel,
      initialOpen: false,
    });
 
    return panels;
  },
);

The builder calls panels.map() on the result, so returning anything but an array throws panels.map is not a function and leaves the block builder Inspector blank. A handler that decides to do nothing must return the incoming panels.

Was this article helpful?

Copyright © 2026 Lazy Blocks.