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)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions