feat(builder): add wizard template and WPML extension points - #389
Conversation
The Pro plugin replaces the wizard presets with ones built on the `<RichText />` component, and needs the attributes it registers outside of the controls to be translatable. - lzb.constructor.wizard.templates - lzb/wpml/translated_attributes The templates filter runs inside the component rather than at the module level, because the scripts hooking it may load after this one.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6995f9cd05
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const wizardTemplates = useMemo( | ||
| () => applyFilters('lzb.constructor.wizard.templates', templates), | ||
| [] | ||
| ); |
There was a problem hiding this comment.
Reapply filters registered after the first wizard render
When an extension bundle registers its filter after Wizard has mounted—the unordered-script case this change is intended to support—the empty dependency array permanently caches the unfiltered templates. Later wizard rerenders therefore never call applyFilters, so the extension's presets remain unavailable for the entire mount; either enforce script ordering or provide a way to recompute after late registration.
Useful? React with 👍 / 👎.
| const [icon, setIcon] = useState(wizardTemplates.basic.blockIcon); | ||
| const [title, setTitle] = useState(wizardTemplates.basic.title); |
There was a problem hiding this comment.
Preserve a default when filters remove the basic preset
If a filter removes basic or replaces the preset collection wholesale, this initializer dereferences undefined.blockIcon and crashes the wizard before any template can be selected. Since the new filter exposes the entire collection for replacement or removal, initialization should use an available filtered preset or explicitly retain a fallback rather than requiring the basic key.
Useful? React with 👍 / 👎.
Exposing the whole collection means a filter may remove `basic` or replace every preset, and the initial state dereferenced `basic` directly. Take the first available preset instead, and close the wizard when there is none. Filtering on every render rather than memoising it once also picks up a filter registered after the wizard has mounted.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d048303ab6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const [title, setTitle] = useState(templates.basic.title); | ||
| const [slug, setSlug] = useState('basic-block'); | ||
| const [category, setCategory] = useState('text'); | ||
| const [template, setTemplate] = useState(firstTemplate); |
There was a problem hiding this comment.
Initialize style variations for the filtered default template
When a filter replaces or reorders the collection so that a preset with styles is first, that preset becomes selected here, but the styles state remains the hard-coded empty array on line 53. Finishing without clicking the already-selected preset therefore saves no style variations, unlike the click path, which copies wizardTemplates[k].styles; initialize this state from firstTemplateData.styles as well.
Useful? React with 👍 / 👎.
Two extension points the Pro plugin needs to ship setup-wizard presets built on the
<RichText />component. No behaviour change on its own — both are no-ops until something hooks them.lzb.constructor.wizard.templatesassets/block-builder/boxes/wizard/index.jsFilters the whole
templatesobject, so a preset can be replaced, extended or removed wholesale — markup, controls, styles, icon and copy all live in that object.It runs inside the component, wrapped in
useMemo, rather than at the module level: the scripts hooking it are separate bundles with no guaranteed load order, and a module-levelapplyFilterswould run before they register.lzb/wpml/translated_attributesclasses/class-wpml.phpwpml_config_array()collects translatable names from the block controls only, so an attribute registered outside of a control can never be translated. The filter runs per block, after the controls are collected, and takes the same WPML config node shapeget_translated_controls_data()produces.Testing
npm run lintpasses. The wizard still offers the four built-in presets and creates the same block for each — the filtered object is identical when nothing hooks it.Needed by the
<RichText />presets in the Pro plugin.