Skip to content

fix: keep usage logger alive when chart settings meta is not an array - #1360

Open
lucadobrescu wants to merge 2 commits into
developmentfrom
fix/1359-usage-logger-string-settings
Open

fix: keep usage logger alive when chart settings meta is not an array#1360
lucadobrescu wants to merge 2 commits into
developmentfrom
fix/1359-usage-logger-string-settings

Conversation

@lucadobrescu

Copy link
Copy Markdown
Contributor

Scheduled usage telemetry died with TypeError: array_key_exists(): Argument #2 ($array) must be of type array, string given whenever a site had one published chart whose visualizer-settings post meta is a string instead of the sanitized settings array — one bad chart record aborted the whole SDK usage collection request (three production sites hit this on PHP 8.2/8.3). The logger now tolerates malformed chart meta and still reports every healthy chart.

What changed

  • Visualizer_Module_Setup::getUsage() — the manual_config counter reads the settings meta through an is_array() guard. Before → a string (or a chart with no settings meta at all, where get_post_meta() returns '') threw an uncaught TypeError on PHP 8; after → the chart is skipped for that statistic and collection completes.

  • Visualizer_Module_Setup::getUsage() (pro path) — the permissions meta read had the same shape ($permissions['permissions'] on an unvalidated meta value), so it gets the same is_array() guard.

  • Visualizer_Module_Admin — removed its visualizer_logger_data registration: it points to a getLoggerData method that class does not have, so once the first crash is fixed the filter fatals again with "class Visualizer_Module_Admin does not have a method getLoggerData". The working callback in Visualizer_Module_Setup is unchanged.

Note

How the affected sites acquired string-valued settings meta is unknown (the issue's telemetry couldn't tell). The fix deliberately hardens the reader instead of chasing the writer: the logger must never let one bad record kill the whole collection request.

Usage collection flow

flowchart LR
    A[SDK cron:<br/>visualizer_logger_data] --> B[Setup::getUsage<br/>loops published charts]
    B --> C{Changed:<br/>settings meta<br/>is an array?}:::changed
    C -- Yes --> D[Count manual_config]
    C -- No --> E[Skip statistic,<br/>keep looping]
    D --> F[Usage payload returned]
    E --> F
    A -.-> G[New: dangling Admin<br/>callback removed]:::added

    classDef added fill:#1a7f37,color:#fff,stroke:#116329,stroke-width:3px
    classDef changed fill:#9a6700,color:#fff,stroke:#5c3d00,stroke-width:3px,stroke-dasharray:6 3
Loading

QA

  1. Create any chart (WP Admin → Visualizer → Add New Chart, complete the wizard) and corrupt its settings meta with WP-CLI, replacing <chart_id> with the chart's post ID:

    wp post meta update <chart_id> visualizer-settings "corrupted string"
    
  2. Trigger the logger on PHP 8.2+:

    wp eval 'var_export( apply_filters( "visualizer_logger_data", array() ) );'
    

    Expect: a usage array is printed (types, sources, manual_config, …) with no TypeError. On 4.0.7 the same command dies with the array_key_exists() TypeError from the crash report.

Fixes #1359

A published chart whose visualizer-settings meta resolves to a string
crashed Visualizer_Module_Setup::getUsage() with a PHP 8 TypeError at
the unchecked array_key_exists() call, aborting the whole Themeisle SDK
usage collection request. Guard the settings read, harden the sibling
pro-permissions meta read the same way, and drop the dangling
visualizer_logger_data registration in Visualizer_Module_Admin, which
points to a method that class never had and fatals the same filter once
the first crash is fixed.

Fixes #1359

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@pirate-bot

pirate-bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Plugin build for a4de841 is ready 🛎️!

@lucadobrescu lucadobrescu self-assigned this Jul 31, 2026
@lucadobrescu
lucadobrescu requested a review from Copilot July 31, 2026 07:20
@lucadobrescu lucadobrescu added the pr-checklist-skip Allow this Pull Request to skip checklist. label Jul 31, 2026
@pirate-bot pirate-bot added the pr-checklist-complete The Pull Request checklist is complete. (automatic label) label Jul 31, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Hardens usage telemetry against malformed chart metadata so collection continues for healthy charts.

Changes:

  • Guards settings and permissions metadata before access.
  • Removes an invalid Admin logger callback.
  • Adds PHPUnit and E2E regression coverage.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
classes/Visualizer/Module/Setup.php Adds metadata type guards.
classes/Visualizer/Module/Admin.php Removes invalid logger registration.
tests/test-usage-logger.php Adds unit regression tests.
tests/e2e/specs/usage-logger.spec.js Adds end-to-end logger coverage.
tests/e2e/config/mu-plugins/plant-chart-settings.php Exposes a protected E2E logger endpoint.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

if ( Visualizer_Module::is_pro() ) {
$permissions = get_post_meta( $chart_id, Visualizer_Pro::CF_PERMISSIONS, true );
if ( empty( $permissions ) ) {
if ( ! is_array( $permissions ) || empty( $permissions['permissions'] ) ) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed and fixed in a4de841 — the scenario reproduces exactly as described (TypeError at the count() call). Guarded the per-key value with is_array() and added a regression test that forces the pro branch via the visualizer_is_pro filter with a stubbed Visualizer_Pro class.

Comment on lines +1 to +18
/**
* WordPress dependencies
*/
const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' );

/**
* Regression tests for https://github.com/Codeinwp/visualizer/issues/1359
*
* A published chart whose `visualizer-settings` meta is a string (instead of
* the sanitized settings array) crashed `Visualizer_Module_Setup::getUsage()`
* with a PHP 8 TypeError, aborting the whole SDK usage collection request.
* The logger must tolerate such charts and still report the others.
*/
test.describe( 'Usage logger', () => {
let corruptedId;
let manualId;

test.beforeAll( async ( { requestUtils } ) => {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in a4de841 — the spec now calls deleteAllCharts() in beforeAll like the other chart-counting specs.

Copilot review follow-ups: a string where an array-valued permission is
expected (e.g. permissions.edit-specific) still crashed the usage
logger via count() on PHP 8 — guard it and cover the pro branch through
the visualizer_is_pro filter with a stubbed Visualizer_Pro. Also clear
leftover charts before the e2e usage assertions, matching the other
chart-counting specs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

if ( Visualizer_Module::is_pro() ) {
$permissions = get_post_meta( $chart_id, Visualizer_Pro::CF_PERMISSIONS, true );
if ( empty( $permissions ) ) {
if ( ! is_array( $permissions ) || empty( $permissions['permissions'] ) ) {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-checklist-complete The Pull Request checklist is complete. (automatic label) pr-checklist-skip Allow this Pull Request to skip checklist.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants