Skip to content

feat(Example Modals, D5) :: Added Custom Modal with various Divi fields, different options and showcase example #7

Open
shohel wants to merge 4 commits intomainfrom
48965-various-fields
Open

feat(Example Modals, D5) :: Added Custom Modal with various Divi fields, different options and showcase example #7
shohel wants to merge 4 commits intomainfrom
48965-various-fields

Conversation

@shohel
Copy link
Copy Markdown

@shohel shohel commented Mar 27, 2026

The Feature

Issue Reference

Fixes: https://github.com/elegantthemes/Divi/issues/48965

Feature Description

Adds a third Visual Builder example, Modal Field Showcase, so third-party developers can copy patterns for a rich custom modal: tabs, in-modal search, footer actions, collapsible groups, a wide set of @divi/field-library controls, a small custom tri-toggle control, and per-post persistence via post meta and REST. Root plugin docs and build scripts are updated so all three packages build together. Follow-up fixes keep the demo aligned with how core expects fields to behave (e.g. color UI that opens the shared color modal, accordion groups wired to the modal tab store, no unnecessary lodash dependency).

Related Context

Issue notes public target https://github.com/elegantthemes/d5-extension-example-modals (no DeepHive); PR is opened there manually. Divi core is unchanged.

The Pull Request

Implementation Approach

Ships a new webpack subpackage under the example modals plugin, registers a builder bar entry, maps a custom modal in divi.modalLibrary.modalMapping, and hydrates or saves settings through divi_visual_builder_settings_data (dedicated key, filter priority 20) plus REST and _d5_modal_field_showcase_v1 post meta. Documentation in the sub-README and root README maps the issue checklist to concrete files and calls out differences from inspector-only behavior (e.g. local search state vs core settings search).

Screencast Verification

modal-fields-showcase.mp4

Testing & Verification

  • Enable plugin; open VB on a saved post; open Modal Field Showcase from the builder bar; confirm tabs, search filtering, groups, footer discard/save, and REST persistence.
  • Appearance tab: open accent and border color controls; confirm the Divi color modal opens and changes update the draft and preview.
  • Regression: open Module Visibility and Post Keyword modals; smoke-test save paths still work.
  • Run npm run build from plugin root after dependency changes.

Alternative Solutions (if any)

Raw ColorPicker was insufficient for inline mode because the full picker is opened via ColorPickerContainer and the modal library; switching to the container matches inspector behavior. No other approaches were prototyped for that fix.

Changelog

Added Modal Field Showcase example to the D5 Extension Example Modals plugin with tabs, search, field-library samples, custom tri-toggle, and per-post meta save, plus README and build updates for all examples.


Note

Low Risk
Low risk documentation-only change; no runtime code paths, dependencies, or build artifacts are modified.

Overview
Adds task documentation for Divi issue #48965, including a focus-chain.md status tracker and a detailed implementation-plan.md covering research findings, proposed modal example scope, and validation steps.

No product/plugin source code changes are included in this PR; it only records planning and execution notes for a separate intended update to d5-extension-example-modals.

Written by Cursor Bugbot for commit f715a4fd4aa117c8f9ec1edac9cdf65b8deaca6e. Configure here.

Introduced the third Visual Builder sample under the example modals
plugin: tabs, local search, footer save/discard, GroupContainer-backed
sections, broad field-library coverage, a small custom tri-toggle, and
per-post persistence via dedicated VB settings data, REST, and post
meta. Wired GroupContainer to the modal tab store so accordions work,
swapped inline ColorPicker usage for ColorPickerContainer so the shared
color modal opens, dropped an unnecessary lodash dependency from the
showcase bundle, and refreshed root and package READMEs plus the root
build script so all three packages build together.

Fixes: elegantthemes/Divi#48965
@etstaging etstaging requested a review from rupakdhiman March 27, 2026 20:28
@shohel
Copy link
Copy Markdown
Author

shohel commented Mar 27, 2026

Developer testing — Modal Field Showcase

One-time setup

From this package directory:

cd wp-content/plugins/d5-extension-example-modals/modal-field-showcase
npm install

Build

All three examples (from plugin root):

cd wp-content/plugins/d5-extension-example-modals
npm install
npm run build

This example only:

cd wp-content/plugins/d5-extension-example-modals/modal-field-showcase
npm run build

Development build (less minified):

npm run build:dev

Watch mode (iterate on JS/CSS)

Plugin root npm start only watches another example. For this modal, run:

cd wp-content/plugins/d5-extension-example-modals/modal-field-showcase
npm run start

Keep the process running; reload the Visual Builder after changes.

WordPress / Visual Builder

  1. Activate D5 Extension Example: Custom Modals (your local copy of the plugin).
  2. Open a saved post or page in the Divi Visual Builder (a real post ID is required for the post-meta save demo).
  3. On the builder bar, click Field showcase (tooltip/label; custom icon alongside the other example buttons).
  4. In the modal: use tabs, Filter settings…, expand GroupContainer sections, edit fields.
  5. Open Appearance tokens → use Accent and Border color pickers; the shared Divi color modal should open and updates should stick in the draft.
  6. Click Save in the footer, reload the builder, reopen the modal, and confirm values persisted. Optionally change something and use Discard to confirm the draft resets.

Scripts reference (package.json)

Script Purpose
build Production webpack build
build:dev Development webpack build
start Webpack in watch mode (-w) for local work

Copy link
Copy Markdown
Member

@ayubadiputra ayubadiputra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shohel I have small feeedback.

And also, could you please update the README or create new one if needed for each modal directory to explain about the file/directory structure? You just remove the on on root (which is good for simpler readme), so we need replacement for each directories.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: Since this is for educational purpose, we need to add some meaningful comment that explain each parts or processes in the code. I don't mean to add comments on all lines but, some areas are important to explain with some comments like why hydratedRef need to be tracked, short comment that explain updateDraft and saveDraft since both of them seem have similar meaning, etc.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines +42 to +44
if (true === merged.enablePolish || false === merged.enablePolish) {
merged.enablePolish = merged.enablePolish ? 'on' : 'off';
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo" Why don't just:

Suggested change
if (true === merged.enablePolish || false === merged.enablePolish) {
merged.enablePolish = merged.enablePolish ? 'on' : 'off';
}
merged.enablePolish = merged.enablePolish ? 'on' : 'off';

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not merged.enablePolish = merged.enablePolish ? 'on' : 'off' for every value

After merge, enablePolish is often already the string 'off'. In JavaScript that is truthy, so a bare ternary would turn it into 'on' and flip the toggle the wrong way. The same guard is why we only coerce booleans (from PHP / older payloads), not strings.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now used like this

    if ('boolean' === typeof merged.enablePolish) {
      merged.enablePolish = merged.enablePolish ? 'on' : 'off';
    }

async payload => {
const id = parseInt(postId, 10);

if (!id || id < 1) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: It's obviously integer now and 0 is basically id < 1.

Suggested change
if (!id || id < 1) {
if (id < 1) {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: Please add comments for each export.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: For class and ID names of the HTML elements, let's not use d5- prefix, for example: https://github.com/elegantthemes/d5-extension-example-modals/blob/main/post-keyword-manager/styles/bundle.css

This way people can easily "copy-paste-adapt".

However, it's fine to use et- or d5- prefix for things like key, name, etc.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: Is it identical with the one we have in codebase?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merge-border-radius.js
Core: visual-builder/packages/modal-library/src/utils/field-rendering/handle-border-radius/index.ts, merges with createDefaultBorderRadiusObject(), validates corner keys, and goes through module onChange typing.

Plugin: Reads the same shape the field emits (inputValue: { value, side, sync } from field-library/.../border-radius/component.tsx), and applies the same sync on → all corners / sync off → one corner rules on prev only — no default merge inside the helper because defaults already live on draft.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: For class and ID names of the HTML elements, let's not use d5- prefix, for example: https://github.com/elegantthemes/d5-extension-example-modals/blob/main/post-keyword-manager/styles/bundle.css
This way people can easily "copy-paste-adapt".
However, it's fine to use et- or d5- prefix for things like key, name, etc.

)
);

register_rest_route(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo:

Suggested change
register_rest_route(
// Modal Field Showcase settings endpoint
register_rest_route(

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

// $future_example_file = $examples_dir . 'future-example/example.php';
// if ( file_exists( $future_example_file ) ) {
// require_once $future_example_file;
// }.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: Please keep these comment lines, don't remove them:

	// Future examples can be loaded here.
	// $future_example_file = $examples_dir . 'future-example/example.php';
	// if ( file_exists( $future_example_file ) ) {
	// require_once $future_example_file;
	// }.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment thread README.md Outdated
Comment on lines +39 to +43
2. **Install dependencies** in each example package that you plan to build (each has its own `package.json`):
- `module-visibility-manager/`
- `post-keyword-manager/`
- `modal-field-showcase/`
3. **Build all examples from the plugin root**: `npm run build` (runs webpack in all three folders)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: Based on what I understand, we need to run npm install on each directories, then npm run build on the root. I just realized this is no efficient yet. I think we can either run npm install on root for 3 of them or making sure to run npm run build for each directories for consistency. Having both of them is good. But, at least, if we can separate the build for each directories, we can make sure we can build the modal that we want without the need to deal with errors (if any) on other directories. If this is already the case, we need to update the README.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We intentionally keep separate node_modules per example (module-visibility-manager/, post-keyword-manager/, modal-field-showcase/) so each webpack stack stays isolated and one broken dependency does not affect the others.

To make the workflow less tedious without changing that model:

  • npm run install:all at the plugin root runs npm install in all three folders in one go.
  • npm run build:module-visibility, npm run build:post-keyword, and npm run build:modal-field-showcase build only that package (same idea as npm run build --prefix …, but documented and named in root package.json). npm run build still builds all three in sequence.

Also updated RADME file to make it clear.

shohel added 3 commits April 15, 2026 13:55
Extended the Modal Field Showcase example and root plugin UX:
documented draft/save/hydration, section comments in the modal body,
field-showcase DOM/CSS naming, safer enablePolish and post-id guards,
icon JSDoc, merge helpers without internal path references, README and
MODAL-TABS-PATTERN doc cleanup, root install:all and per-example build
scripts, and small PHP enqueue comments. Aligns third-party copy-paste
story with review feedback.

Ref: elegantthemes/Divi#48965
Extended the Modal Field Showcase example and root plugin UX:
documented draft/save/hydration, section comments in the modal body,
field-showcase DOM/CSS naming, safer enablePolish and post-id guards,
icon JSDoc, merge helpers without internal path references, README and
MODAL-TABS-PATTERN doc cleanup, root install:all and per-example build
scripts, and small PHP enqueue comments. Aligns third-party copy-paste
story with review feedback.

Ref: elegantthemes/Divi#48965
Documented each webpack example’s layout: new module-visibility-manager
README, Package layout sections in post-keyword and modal-field-showcase,
and root README pointers to those files. Clarifies build/install from root
vs per-folder and replaces the old single-tree blurb.

Ref: elegantthemes/Divi#48965
@shohel
Copy link
Copy Markdown
Author

shohel commented Apr 15, 2026

@shohel I have small feeedback.

And also, could you please update the README or create new one if needed for each modal directory to explain about the file/directory structure? You just remove the on on root (which is good for simpler readme), so we need replacement for each directories.

Thanks @ayubadiputra

I've resolved all your feebacks 👍

@DeepHiveET DeepHiveET self-requested a review April 15, 2026 08:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants