Skip to content

Fix multicheck not saving when only the 0 option is checked - #1572

Merged
jtsternberg merged 2 commits into
CMB2:developfrom
faisalahammad:fix/1535-multicheck-zero-value
Oct 11, 2026
Merged

jtsternberg merged 2 commits into
CMB2:developfrom
faisalahammad:fix/1535-multicheck-zero-value

Conversation

@faisalahammad

Copy link
Copy Markdown
Contributor

Description

CMB2_Sanitize::_is_empty_array() used array_filter() to check if a submitted array was empty. array_filter() also drops 0 and '0', so when the only checked multicheck option has the key 0, the value array( '0' ) is treated as empty. default_sanitization() then returns '' and CMB2_Field::save_field() deletes the value.

This PR switches the check to the existing CMB2_Utils::filter_empty() helper, which keeps 0 and '0' and still drops null, '', false and empty arrays.

Before:

$cleaned_up = array_filter( $to_check );

After:

// Keep 0 and '0'. They can be real values, like a multicheck option key.
$cleaned_up = CMB2_Utils::filter_empty( $to_check );

The check was added in 111bdad ("Fix empty arrays saving as a value") to stop arrays like array( '' ) from being saved. That still works the same after this change.

Motivation and Context

Fixes #1535.

Repro: a multicheck field with 'options' => array( 0 => 'Zero', 1 => 'One' ). Check only "Zero" and save. The page reloads with nothing checked and the meta is deleted. If any other option is also checked, it saves fine.

Risk Level

Low.

_is_empty_array() has one caller, CMB2_Sanitize::default_sanitization(), which every field type without its own sanitizer goes through. The only behavior change: a non-repeatable array value that holds only 0 or '0' is now saved instead of deleted. For that value, save_field() now calls update_data() and cmb2_save_field fires with $action = 'updated', where before it called remove_data() with $action = 'removed'. Nothing else changes:

  • Empty arrays and arrays with only '', null or false are still treated as empty, so unchecking every option still removes the value.
  • Arrays with any other value were already kept, so their output is the same.
  • Post meta, the 'multiple' => true branch, group subfields, options pages and the REST API all use the same path, so they all get the fix.

Repeatable fields still drop '0' entries through a separate array_filter() in CMB2_Field::sanitization_cb(). That is older behavior and is not touched here.

Testing procedure

  • Added Test_CMB2_Types::test_multicheck_sanitization_keeps_zero_value. It checks that array( '0' ) and array( 0 ) are kept, and that array() and array( '', null, false ) still return ''.
  • Added Test_CMB2_Field::test_cmb2_multicheck_field_saves_zero_value. It goes through save_field(): saving only '0' stores array( '0' ) in post meta, saving '0' with another option stores both, and saving an empty array removes the meta.
  • I checked that both tests fail with the fix reverted and pass with it.
  • Full PHPUnit suite in wp-env (PHP 8.3, WordPress latest): 330 tests pass. composer phpcs is clean.
  • Tested by hand in WordPress with the code from the issue, plus a multicheck_inline field, a multicheck inside a group and a multicheck on an options page. Checking only "Zero" now stays checked after saving, and unchecking everything clears the value.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)

Checklist:

Screenshots

No UI changes.

CMB2_Sanitize::_is_empty_array() used array_filter() to decide if a
submitted array was empty. array_filter() also drops 0 and '0', so a
multicheck with only the option keyed 0 checked was treated as empty
and its value was deleted on save.

Use CMB2_Utils::filter_empty() instead. It keeps 0 and '0' and still
drops null, '', false and empty arrays, so the original goal of the
check (not saving arrays with no real values) stays the same.

Fixes CMB2#1535
@codecov

codecov Bot commented Oct 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 72.16%. Comparing base (818626c) to head (e0deb9c).

Additional details and impacted files
@@            Coverage Diff             @@
##             develop    #1572   +/-   ##
==========================================
  Coverage      72.16%   72.16%           
  Complexity      1911     1911           
==========================================
  Files             53       53           
  Lines           5034     5034           
==========================================
  Hits            3633     3633           
  Misses          1401     1401           
Flag Coverage Δ
phpunit 72.16% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jtsternberg
jtsternberg merged commit 781d56a into CMB2:develop Oct 11, 2026
18 checks passed
jtsternberg added a commit that referenced this pull request Oct 11, 2026
…staged

Staging such a fix keeps a data-loss bug as the default. Decided while
reviewing #1572 (multicheck dropping a lone '0'); precedent
dba5776 and 7e521ed. Format changes such as reinterpreting stored
values stay staged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KpfVcxMH9VE8CRmGRvjJPS
Co-Authored-By: jtsternberg-bot <me+jtbot@jtsternberg.com>
jtsternberg added a commit that referenced this pull request Oct 11, 2026
The C3 data-loss exception ships this unstaged on the condition that the
changelog spells out what integrations now see.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KpfVcxMH9VE8CRmGRvjJPS
Co-Authored-By: jtsternberg-bot <me+jtbot@jtsternberg.com>
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.

Multiselect does not save when only selecting an option with the integer value 0

2 participants