Skip to content

Divi Integration#38

Open
Arukuen wants to merge 5 commits into
developfrom
feat/divi-integration
Open

Divi Integration#38
Arukuen wants to merge 5 commits into
developfrom
feat/divi-integration

Conversation

@Arukuen

@Arukuen Arukuen commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features
    • Added interaction editing support for the Divi Visual Builder, including a Divi-specific launcher/panel and editor behavior.
    • Enhanced builder integration across Divi/Elementor/Bricks, including improved interaction library access and preset apply/insert flows.
  • Bug Fixes
    • Publishing now reliably completes editor save handling and consistently resets status/dirty state even on failures.
    • Divi target picking refined: picker is disabled for manual CSS class targets and Divi dropdown options are filtered/reordered for compatibility.
  • UI/Style
    • Updated launcher visibility/positioning to include Divi and adjusted Divi panel layout.

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

The plugin now detects Divi and supported builders, adds a Divi editor adapter with target persistence and picking, integrates the shared Interaction Library across editors, updates builder-specific controls and styles, and saves the active editor during interaction publishing.

Divi editor integration

Layer / File(s) Summary
Editor mode wiring and enqueueing
interactions.php, src/editor/editor.php, src/editor/editors/abstract.js, src/editor/editors/index.js
Divi is recognized as a builder, its editor assets are conditionally enqueued, and adapter, save, and preset delegates are exposed.
Divi adapter and target persistence
src/editor/editors/divi.js
The adapter mounts the UI, integrates with the Divi canvas and data API, persists module targets, tracks selection, and implements element picking.
Builder interaction library integration
src/editor/editors/*, src/editor/interaction-library/*
The shared library root is mounted across builders, while preset insertion and target mapping are delegated to the active editor adapter.
Builder controls and save synchronization
src/editor/app.js, src/editor/components/*, src/editor/editor.scss
Builder library controls, Divi target restrictions, launcher styles, panel layout, and editor-save completion handling are updated.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DiviVisualBuilder
  participant DiviInteractionsEditor
  participant DiviDataAPI
  participant InteractionLibrary
  participant InteractionPanel
  DiviVisualBuilder->>DiviInteractionsEditor: load divi editor
  DiviInteractionsEditor->>DiviDataAPI: read or persist module target
  DiviDataAPI-->>DiviInteractionsEditor: return target data
  DiviInteractionsEditor->>InteractionLibrary: open apply mode with selected target
  InteractionLibrary->>InteractionPanel: apply interaction
  InteractionPanel->>DiviInteractionsEditor: save current editor
Loading

Possibly related PRs

  • gambitph/Interactions#31: Refactors the Interaction Library modal flow and builder-aware target logic in the same modal implementation area.

Suggested reviewers: bfintal

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main change: adding Divi support and integration across the editor stack.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/divi-integration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Arukuen Arukuen self-assigned this Jul 15, 2026
@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown

🤖 Pull request artifacts

file commit
pr38-interactions-38-merge.zip dc59b0c

github-actions Bot added a commit that referenced this pull request Jul 15, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/editor/components/interaction-panel/index.js (1)

225-237: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

UI can get stuck in "publishing" forever if saveCurrentEditor() rejects or throws.

There's no .catch on this chain. If the active editor's saveEditor() (e.g. Divi's DOM-based implementation) throws synchronously or its promise rejects, .finally()'s state resets (setStatus('idle'), setIsDirty(false), and the optional callback) never run, leaving the panel permanently busy with no recovery short of a page reload.

🛡️ Suggested fix
 onChange( editedInteraction ).then( () => {
-    return Promise.resolve( saveCurrentEditor() ).finally( () => {
+    return Promise.resolve( saveCurrentEditor() ).catch( () => {} ).finally( () => {
         setStatus( 'idle' )
         setIsDirty( false )
         if ( callback ) {
             setTimeout( callback, 1 ) // Need a timeout here because re-publishing may be too fast.
         }
     } )
 } )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/editor/components/interaction-panel/index.js` around lines 225 - 237,
Update onPublishHandler so both synchronous throws and rejected promises from
saveCurrentEditor() still reset publishing state. Wrap the saveCurrentEditor
invocation in a promise-safe flow and ensure setStatus('idle'),
setIsDirty(false), and the optional callback execute on success or failure,
while preserving the existing callback timing and allowing the rejection to be
handled appropriately.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/editor/editors/divi.js`:
- Around line 270-330: Update registerSelectionTracking so it tracks the
specific document currently bound rather than relying only on isBound, allowing
bindListeners to reattach when getCanvasDocument() returns a new iframe
document. Replace the one-shot 10-second observer shutdown with a retry
mechanism or iframe load handling that still binds canvases loading after the
initial attempt, while preserving cleanup of listeners, observers, and timers in
the returned teardown function.
- Around line 119-131: Update saveEditor() to identify Divi’s save button using
a locale-independent attribute or selector instead of the English text label,
then return a promise that resolves only after Divi finishes persisting the page
following saveButton.click(). Preserve the existing no-button and
disabled-button early-return behavior.

---

Outside diff comments:
In `@src/editor/components/interaction-panel/index.js`:
- Around line 225-237: Update onPublishHandler so both synchronous throws and
rejected promises from saveCurrentEditor() still reset publishing state. Wrap
the saveCurrentEditor invocation in a promise-safe flow and ensure
setStatus('idle'), setIsDirty(false), and the optional callback execute on
success or failure, while preserving the existing callback timing and allowing
the rejection to be handled appropriately.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ab2b8f4c-80c3-4199-a296-f76c9d6a2c5b

📥 Commits

Reviewing files that changed from the base of the PR and between da7b2c7 and 8c29c81.

📒 Files selected for processing (8)
  • interactions.php
  • src/editor/components/interaction-panel/index.js
  • src/editor/components/target-selector/index.js
  • src/editor/editor.php
  • src/editor/editor.scss
  • src/editor/editors/abstract.js
  • src/editor/editors/divi.js
  • src/editor/editors/index.js

Comment on lines +119 to +131
saveEditor() {
// Reuse Divi's own save button so the builder persists the current page
// after an interaction modifies module attributes such as target IDs.
const saveButton = Array.from( document.querySelectorAll( '.et-vb-page-bar-action-button' ) )
.find( button => button.textContent?.trim() === 'Save' )

if ( ! saveButton || saveButton.disabled ) {
return Promise.resolve()
}

saveButton.click()
return Promise.resolve()
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if a similar textContent-based matching pattern already exists elsewhere
# in the codebase (e.g. for Bricks/Elementor save flows) for consistency reference.
rg -n "textContent" src/editor/editors -C2
rg -n "saveEditor" src/editor/editors -C3
fd . src/editor/editors

Repository: gambitph/Interactions

Length of output: 1946


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant editor implementations and surrounding call sites.
sed -n '1,220p' src/editor/editors/divi.js | cat -n
printf '\n==== abstract.js ====\n'
sed -n '1,180p' src/editor/editors/abstract.js | cat -n
printf '\n==== index.js ====\n'
sed -n '1,120p' src/editor/editors/index.js | cat -n

printf '\n==== Divi-specific searches ====\n'
rg -n "et-vb-page-bar-action-button|Save|saveEditor|click\(\)|promise|await|mutation|event" src/editor -C2

Repository: gambitph/Interactions

Length of output: 49115


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the save flow to see how saveCurrentEditor() is consumed.
rg -n "saveCurrentEditor\(" src -C3
printf '\n==== interaction-panel save flow ====\n'
sed -n '220,380p' src/editor/components/interaction-panel/index.js | cat -n

printf '\n==== use-on-post-save helper ====\n'
sed -n '1,140p' src/editor/use-on-post-save.js | cat -n

Repository: gambitph/Interactions

Length of output: 9974


saveEditor() shouldn't depend on the English "Save" label or return before Divi finishes persisting. textContent?.trim() === 'Save' misses localized UIs, and click() is followed by an immediate Promise.resolve(), so saveCurrentEditor() can advance before Divi has actually saved.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/editor/editors/divi.js` around lines 119 - 131, Update saveEditor() to
identify Divi’s save button using a locale-independent attribute or selector
instead of the English text label, then return a promise that resolves only
after Divi finishes persisting the page following saveButton.click(). Preserve
the existing no-button and disabled-button early-return behavior.

Comment thread src/editor/editors/divi.js
github-actions Bot added a commit that referenced this pull request Jul 20, 2026
github-actions Bot added a commit that referenced this pull request Jul 20, 2026
github-actions Bot added a commit that referenced this pull request Jul 23, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/editor/interaction-library/configure-modal.js`:
- Around line 90-100: Builder preset insertion is currently unavailable for
Bricks and Elementor because their adapters inherit the null implementation. In
src/editor/interaction-library/configure-modal.js lines 90-100, retain the
adapter-based insert flow but expose and use insert mode only when the active
adapter supports insertion; in src/editor/editors/bricks.js line 94, implement
insertLibraryPreset() to insert the preset and return the descriptor required by
resolveLibraryPresetTargets; apply the corresponding implementation in
src/editor/editors/elementor.js line 106.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 556696a0-6a53-41c7-be2b-2b7f10eec50b

📥 Commits

Reviewing files that changed from the base of the PR and between b9c5655 and dc59b0c.

📒 Files selected for processing (11)
  • interactions.php
  • src/editor/app.js
  • src/editor/editors/abstract.js
  • src/editor/editors/bricks.js
  • src/editor/editors/divi.js
  • src/editor/editors/elementor.js
  • src/editor/editors/gutenberg.js
  • src/editor/editors/index.js
  • src/editor/interaction-library/configure-modal.js
  • src/editor/interaction-library/index.js
  • src/editor/interaction-library/select-modal.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/editor/editors/index.js
  • src/editor/editors/divi.js

Comment on lines +90 to +100
// In insert mode, let the active editor adapter own how preset content
// is created so this modal no longer depends on Gutenberg block APIs.
if ( mode === 'insert' ) {
const block = parse( selectedPreset.serializedBlockExample ?? '' )[ 0 ]
if ( ! block ) {
const insertedContent = insertLibraryPreset( selectedPreset )
if ( ! insertedContent ) {
return
}
dispatch( 'core/block-editor' ).insertBlocks( block )

// If target mappings are provided, dynamically create target for each.
applyTargetMappings( interactionSetup, targetMappings, block, )
resolveLibraryPresetTargets( interactionSetup, selectedPreset, insertedContent )
} else if ( mode === 'apply' ) {
applyTargetMappings( interactionSetup, targetMappings, selectedTarget )
resolveLibraryPresetTargets( interactionSetup, selectedPreset, selectedTarget )

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Builder preset insertion is a no-op outside Gutenberg.

ConfigureModal now delegates insertion to the active adapter, but Bricks and Elementor inherit the abstract insertLibraryPreset() implementation, which returns null. Selecting Insert in either newly mounted library exits at Line 95 without adding content or an interaction.

  • src/editor/interaction-library/configure-modal.js#L90-L100: retain the adapter flow, but only expose/use insert mode where the active adapter implements insertion.
  • src/editor/editors/bricks.js#L94-L94: implement insertLibraryPreset() and return the inserted-content descriptor required for target mapping.
  • src/editor/editors/elementor.js#L106-L106: implement the corresponding Elementor insertion adapter and descriptor.
📍 Affects 3 files
  • src/editor/interaction-library/configure-modal.js#L90-L100 (this comment)
  • src/editor/editors/bricks.js#L94-L94
  • src/editor/editors/elementor.js#L106-L106
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/editor/interaction-library/configure-modal.js` around lines 90 - 100,
Builder preset insertion is currently unavailable for Bricks and Elementor
because their adapters inherit the null implementation. In
src/editor/interaction-library/configure-modal.js lines 90-100, retain the
adapter-based insert flow but expose and use insert mode only when the active
adapter supports insertion; in src/editor/editors/bricks.js line 94, implement
insertLibraryPreset() to insert the preset and return the descriptor required by
resolveLibraryPresetTargets; apply the corresponding implementation in
src/editor/editors/elementor.js line 106.

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.

1 participant