Skip to content

WP-CLI bridge: auto-json_decode of values corrupts string meta/options (diverges from real wp-cli) #1

Description

@nick-kimuli-am

Summary

The WP-CLI bridge auto-decodes any argument value that parses as JSON before writing, in includes/class-wpvibe-cli.php:

  • post meta update handler (~line 2064):
    $value = $positional[2];
    // Auto-decode JSON values.
    $decoded = json_decode( $value, true );
    if ( null !== $decoded ) {
        $value = $decoded;
    }
    update_post_meta( $post_id, $key, $value );
  • Same pattern in option update (~1575) and option add (~1621).

This makes it impossible to store a literal JSON string, and silently changes the stored type: a JSON string argument becomes a PHP array, which WordPress then serializes.

Real-world breakage

SeedProd stores theme-template conditions as a JSON string in _seedprod_theme_template_condition and calls json_decode() on it when rendering the Theme Builder admin table. Writing that meta through the bridge:

post meta update 41 _seedprod_theme_template_condition '[{"condition":"include","type":"is_page(x)","value":"40"}]'

stored a:1:{i:0;a:3:{...}} (serialized array) instead of the JSON string, producing a WP critical error (admin screen fatal):

PHP Fatal error: Uncaught TypeError: json_decode(): Argument #1 ($json) must be of type string, array given
in .../seedprod-coming-soon-pro-5/admin/includes/class-seedprod-theme-templates-table.php:384

Any plugin that stores JSON strings in meta/options (a very common pattern) is affected the same way.

Divergence from real wp-cli

Real wp-cli stores values as plaintext by default and only decodes with an explicit --format=json. The bridge guesses based on content, so callers can't control the stored type — and the same command produces different stored data in real wp-cli vs the bridge.

Suggested fix

Match wp-cli semantics: default to plaintext, honor --format=json (the flag parser already exists) for explicit decoding. If backwards compat with current behavior is a concern, at minimum honor --format=plaintext as an opt-out.

Found while building a site through WPVibe MCP (plugin v1.4.0, WP 7.0). Companion defensive-fix issue filed on the SeedProd side.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions