Skip to content

Customizer crashes when single-post element order is stored as an array #4593

Description

@pirate-bot

Summary

Opening the Customizer can trigger a fatal TypeError while evaluating the visibility of single-post comments controls when the saved single-post element order is an array rather than JSON text.

Expected behavior: the Customizer remains available and evaluates the affected controls safely.

Actual behavior: Customizer initialization terminates with json_decode(): Argument #1 ($json) must be of type string, array given.

Impact: affected sites cannot use the Customizer until the incompatible setting value is no longer encountered.

Customer context

  • Product / area: Neve Customizer, single-post layout controls
  • Version: 4.2.11
  • Environment: WordPress 6.9.7; PHP 8.3.32; admin request
  • Integration / third party: None identified
  • Reported error / symptom: TypeError: json_decode(): Argument #1 ($json) must be of type string, array given
  • Impact: 2 telemetry occurrences across 1 production site between 2026-08-18 and 2026-08-20.

Reproduction notes

  1. In a test site, arrange for neve_layout_single_post_elements_order to resolve to an array rather than a JSON string.
  2. Open the WordPress Customizer and navigate to single-post layout settings so a comments-related active callback is evaluated.
  3. Observed production result: the request terminates with json_decode(): Argument #1 ($json) must be of type string, array given.

Production reproduction is confirmed by telemetry; the source of the array value was not captured.

Diagnosis

Conclusion

Production telemetry records an uncaught TypeError at the Customizer active-callback path. In Neve 4.2.11, Layout_Single_Post::element_is_enabled() calls json_decode() on the neve_layout_single_post_elements_order theme-mod result without first ensuring it is a string. The reported argument type establishes that this branch received an array.

Where this likely occurs

  • inc/customizer/options/layout_single_post.phpLayout_Single_Post::element_is_enabled() lines 865-882 obtains the theme-mod at line 880 and passes it directly to json_decode() at line 881.
  • inc/customizer/options/layout_single_post.phpLayout_Single_Post::add_subsections() lines 226-242 registers the comments heading controls with active callbacks that reach element_is_enabled() during Customizer serialization, matching the telemetry stack.
  • inc/customizer/options/layout_single_post.phpLayout_Single_Post::add_controls() lines 446-460 declares this setting's default as JSON text, while inc/customizer/defaults/layout.phpDefaults_Layout::get_layout_defaults() lines 165-170 defines the v4 default as an array.
  • Commit 86c6ff1453eed63e0021adb0dc5efc0497b58abc (fix: defaults on frontend, 2025-01-28) changed this method to use the v4 defaults. The commit is contained in v4.2.11; the direct decode remained present.
  • inc/views/post_layout.phpPost_Layout::get_content_order() lines 213-220 and inc/admin/metabox/manager.phpManager::get_post_elements_default_order() lines 422-429 both check is_string( $content_order ) before decoding the same theme mod. This contrast confirms the Customizer reader lacks a defensive path for the observed value type.

Engineering notes

  • The crash is in Neve core, not the bundled Themeisle SDK; telemetry marks the crash location as outside SDK code.
  • The telemetry confirms an array reached the method, but does not identify the writer or migration that persisted or filtered the array on the affected site.
  • The Customizer setting's configured default is JSON text, so an array is not the nominal control value. The v4 defaults API returns an array and third-party theme-mod filters or pre-existing persisted data may also affect the value; these are inferences rather than established sources of the reported array.

Test coverage status

No relevant PHPUnit or e2e coverage was found during inspection: a search under tests/ found no references to neve_layout_single_post_elements_order. No targeted runtime test was run because the report is confirmed by production telemetry and source inspection.

What to verify or explore next

  • Reproduce in a WordPress test environment by making the neve_layout_single_post_elements_order theme-mod resolve to an array, then opening the Customizer and evaluating the comments controls.
  • Check whether Customizer saves, upgrades, starter content, or registered theme-mod filters can produce this array value in supported upgrade paths.
  • Exercise the same condition on supported PHP versions and with the v4 defaults enabled.

Unknowns / follow-up

  • The telemetry contains no sanitized setting payload, so the exact source of the array value is unknown.
  • It is unknown whether this condition appears only after upgrades, only with another extension/filter, or from an existing persisted configuration.

Confidence

Confidence: 98/100

The production stack trace directly identifies a Neve Customizer callback passing an array to json_decode() on PHP 8.3. The affected 4.2.11 source lacks the type guard present in equivalent frontend and metabox readers, confirming one independently reported product crash.

Crash telemetry

Occurrences 2
Distinct sites 1
First seen 2026-08-18 15:12 UTC
Last seen 2026-08-20 17:03 UTC
Crash location product:inc/customizer/options/layout_single_post.php:881
Request context admin
Inside Themeisle SDK no
Product versions 4.2.11
WP versions 6.9.7
PHP versions 8.3.32
SDK versions 3.3.59

Source: automated crash report — neve, fingerprint c2f056f837a4bc677c63cb7f8161392a
Generated by bug-report-triage (ID: bug-report-triage_6a87e98e254207.33452299)

Metadata

Metadata

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions