Skip to content

Fix builder rendering failures when stored widget or row style is null (#1366) - #1367

Open
AlexGStapleton wants to merge 3 commits into
developfrom
fix/1366-resolve-prevent-crash-null
Open

Fix builder rendering failures when stored widget or row style is null (#1366)#1367
AlexGStapleton wants to merge 3 commits into
developfrom
fix/1366-resolve-prevent-crash-null

Conversation

@AlexGStapleton

Copy link
Copy Markdown
Member

Resolve #1366

  • Frontend View Guards (widget.js, row.js): Prevent runtime exceptions in toggleVisibilityFade() when encountering null or non-object style values. (bea0fba)
  • Model Loading (builder.js, cell.js, row.js, widget.js): Guard against assigning stored null styles and normalise uninitialized or invalid styles to {} during model instantiation. (0846996)
  • Backend Sanitisation (styles-admin.php): Unset/remove null style entries during sanitize_all() so that corrupted style values do not survive save operations. (6b3d334)

Update toggleVisibilityFade() in js/siteorigin-panels/view/widget.js and js/siteorigin-panels/view/row.js to return early if styles is null or not an object.

Guard checkIfStyleExists() against non-object and null style values to prevent runtime exceptions when checking visibility disable flags.
…efault models

Update loadPanelsData() in js/siteorigin-panels/model/builder.js to verify that panels_info.style and data.grids[i].style are non-null objects before assigning them to model attributes.
Update SiteOrigin_Panels_Styles_Admin::sanitize_all() in inc/styles-admin.php to check if widget, grid, or cell style values are null or non-arrays, and unset/remove them instead of skipping, ensuring null values do not survive save operations.
@AlexGStapleton
AlexGStapleton requested a review from Misplon August 12, 2026 07:32
@AlexGStapleton AlexGStapleton self-assigned this Aug 12, 2026
@Misplon

Misplon commented Aug 30, 2026

Copy link
Copy Markdown
Member

Reviewed this while deciding whether it lets us close siteorigin/siteorigin-premium#1293. The JS half looks right to me: toggleVisibilityFade() now returns for null and non-objects, which covers the read in checkIfStyleExists() at js/siteorigin-panels/view/widget.js:151 where the original Cannot read properties of null (reading 'disable_widget') came from, and the model normalisation stops a stored null reaching the view in the first place.

Two things about the sanitize_all() half, though.

1. The null branch is unreachable. inc/styles-admin.php, all three blocks:

if ( isset( $panels_data['widgets'][ $i ]['panels_info']['style'] ) ) {
    if ( is_null( $panels_data['widgets'][ $i ]['panels_info']['style'] ) || ! is_array( ... ) ) {
        unset( ... );

isset() is false for a key that exists with a null value, so for an actual null the outer condition never opens and the is_null() check never runs:

$d = array( 'widgets' => array( array( 'panels_info' => array( 'style' => null ) ) ) );
isset( $d['widgets'][0]['panels_info']['style'] )            // false
array_key_exists( 'style', $d['widgets'][0]['panels_info'] ) // true

Running the block against that input leaves 'style' => NULL in place. The ! is_array() half still works for a non-null scalar, so the branch isn't dead for every input — just for the one the PR is about. array_key_exists() in place of isset() fixes it.

2. Ordering means this hook can't catch the null we actually hit. Page Builder sanitises before it applies the pre-save filter:

$panels_data = SiteOrigin_Panels_Styles_Admin::single()->sanitize_all( $panels_data );
$panels_data = apply_filters( 'siteorigin_panels_data_pre_save', $panels_data, $post, $post_id );

inc/admin.php:290-291, and the same order at inc/admin.php:1011 and inc/abilities.php:412. Toggle Visibility writes the null from pb_migrate_settings_save(), which is on that later filter, so it lands after sanitize_all() has already run. Even with fix 1 applied, this path cannot clean it up.


What I'm asking for:

  • Change isset() to array_key_exists() in the three blocks, so the null cleanup does what the PR description says it does.
  • Consider whether sanitize_all() is the right place at all given the ordering above, or whether that cleanup wants to be after the pre-save filter.

Why, and what it means for premium#1293: with only this PR applied, the builder stops crashing, but Toggle Visibility keeps writing style => null on every save. The corruption carries on accumulating, just invisibly. That's why we're keeping premium#1293 open rather than closing it in favour of this: it stops the write at the source and repairs data already stored. The two look complementary to us — this one makes Page Builder resilient to bad data from anywhere, #1293 stops Premium producing it.

Not asking you to change that judgement, just explaining why #1293 isn't being closed. Happy to be told I've read the ordering wrong.

Misplon
Misplon previously requested changes Sep 2, 2026

@Misplon Misplon left a comment

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.

Thanks, mate. Please, see my requested changes above.

@Misplon

Misplon commented Sep 5, 2026

Copy link
Copy Markdown
Member

The two changes requested above are the first two commits of #1374, which is now stacked on this branch: bbd27ce3 (one helper using array_key_exists(), run inside sanitize_all() and again after siteorigin_panels_data_pre_save at all three save sites) and 14960a26 (tests, including the real save_post() with a null-writing pre-save callback). Nothing on this branch was touched. Suggested order: merge this PR as-is, then #1374. If you'd rather carry the two commits here, cherry-pick them.

Misplon added a commit that referenced this pull request Sep 5, 2026
…r can add them

A style that is not an array cannot be sanitized or rendered, and a null
one crashes the builder's style checks when the layout loads. The removal
now lives in one helper, remove_invalid_styles(), which sanitize_all()
runs on the output of the data migration filter; the per-list checks it
replaces used isset(), which is false for a key holding null, so the null
case they were written for never reached them.

The three save paths also run the helper on the output of the
siteorigin_panels_data_pre_save filter. sanitize_all() runs before that
filter, so a callback on it could store a null style that nothing cleaned;
the Toggle Visibility migration in SiteOrigin Premium did exactly that.

Refs #1366, #1367.
@Misplon
Misplon dismissed their stale review September 6, 2026 20:30

Both requested changes are answered in #1374, which is stacked on this branch: array_key_exists() in place of isset(), and the cleanup moved into one helper that also runs after the siteorigin_panels_data_pre_save filter at all three save sites. Dismissing so this can merge first; #1374 follows.

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.

Builder Rendering Fails When a Stored Widget or Row Style Is Null

2 participants