Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
* Fixed featured Community Cloud snippets failing to load with some cloud API responses. (PRO)
* Fixed bulk actions in Community Cloud running against an empty selection, so selected snippets were never downloaded.
(PRO)
* Fixed a fatal error in the Elementor editor on Elementor versions older than 3.19.

## [3.10.2] (2026-09-01)

Expand Down
18 changes: 18 additions & 0 deletions src/php/Integration/Promotions/Other/Elementor_Editor.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ public function __construct() {
* Promotion on the Custom CSS section, inside the Elementor Editor.
*/
public function promotion_in_custom_css_section() {
if ( ! $this->supports_notice_control() ) {
return;
}

// Elementor Core.
add_action(
'elementor/element/common/section_custom_css/after_section_start',
Expand All @@ -40,6 +44,20 @@ function ( $element ) {
);
}

/**
* Check whether this version of Elementor offers the notice control type.
*
* The type arrived in Elementor 3.19. On anything older the constant does
* not exist, and reading it while the editor builds its controls raises an
* Error that leaves the editor unusable, so the promotion is skipped
* rather than degraded.
*
* @return bool
*/
protected function supports_notice_control(): bool {
return defined( Controls_Manager::class . '::NOTICE' );
}

/**
* Register promotion section in the Custom CSS section.
*
Expand Down
86 changes: 86 additions & 0 deletions tests/unit/Integration/Promotions/Other/Elementor_Editor_Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php

namespace Code_Snippets\Integration\Promotions\Other;

use Code_Snippets\UnitTestCase;

/**
* Tests for the Elementor editor promotion.
*
* @group promotions
*/
class Elementor_Editor_Test extends UnitTestCase {

/**
* Elementor hooks the promotion registers its controls on.
*/
private const PROMOTION_HOOKS = [
'elementor/element/common/section_custom_css/after_section_start',
'elementor/element/common/section_custom_css_pro/after_section_start',
];

/**
* Tear down after each test.
*
* @return void
*/
public function tear_down() {
foreach ( self::PROMOTION_HOOKS as $hook ) {
remove_all_actions( $hook );
}

parent::tear_down();
}

/**
* The promotion is left unregistered when the notice control type is absent.
*
* Elementor gained that control type in 3.19. Registering against an older
* version reads a constant that does not exist, and the resulting Error is
* raised while the editor builds its controls, leaving the editor unusable.
*
* Elementor is not installed for these tests, so the constant is genuinely
* missing here, which is the same condition an older Elementor presents.
*
* @return void
*/
public function test_promotion_is_skipped_when_the_notice_control_is_missing(): void {
$promotion = new Elementor_Editor();

$promotion->promotion_in_custom_css_section();

foreach ( self::PROMOTION_HOOKS as $hook ) {
$this->assertFalse(
has_action( $hook ),
"the promotion should not be registered on $hook without the notice control type"
);
}
}

/**
* The promotion is still registered on a version that offers the control type.
*
* @return void
*/
public function test_promotion_is_registered_when_the_notice_control_exists(): void {
$promotion = new class() extends Elementor_Editor {
/**
* Stand in for an Elementor new enough to offer the control type.
*
* @return bool
*/
protected function supports_notice_control(): bool {
return true;
}
};

$promotion->promotion_in_custom_css_section();

foreach ( self::PROMOTION_HOOKS as $hook ) {
$this->assertNotFalse(
has_action( $hook ),
"the promotion should still be registered on $hook when the control type exists"
);
}
}
}
Loading