Skip to content

IRL - Woo Fast Search Plugin - Wholesale filter contract mismatch wipes customers and breaks response shape #103

@noelsaw1

Description

@noelsaw1

Short answer

Not with the current WPCC stack.

  • Static grep rules and the PHP golden rules analyzer are designed for local, syntactic patterns (e.g., “unbounded WP_Query”, “unsanitized superglobal”, “file_get_contents on URL”), not cross‑function data‑structure contract checks.
  • The bug you described is a contract mismatch across multiple functions/classes (search_customers() → filter interface → Ajax handler → JS expectations). That’s semantic / type‑shape logic, which our current grep‑based system doesn’t model.

So: this specific “flat array vs hash” mismatch would not be reliably caught by the existing scanner or golden rules analyzer.


Why this kind of bug is hard for grep / golden rules

Your bug is essentially:

  • Producer: search_customers() returns array<Customer> (flat list).
  • Filter contract: apply( $results ) expects ['customers' => [...], 'guest_orders' => [...], 'orders' => [...]].
  • Filter apply() checks isset( $results['customers'] ) and, if not present, returns ['customers' => [], 'guest_orders' => [], 'orders' => []].
  • Ajax handler then:
    • Treats this hash as “customers payload”
    • JS expects data.customers to be an array, but instead gets { customers: [], guest_orders: [], orders: [] }.

To detect this statically you’d need to:

  1. Track what shape search_customers() returns.
  2. Track that it passes that value through a filter (or interface method).
  3. Know the intended shape in the filter interface (interface-kiss-woo-order-filter.php).
  4. Compare the shapes and see they’re incompatible.

Our current system:

  • Doesn’t track return types or array shapes across functions.
  • Doesn’t understand hook/filter contracts beyond string matching on hook names.
  • Golden rules are largely single‑file, regex + small validator script checks, not inter‑procedural type analysis.

That’s the kind of thing tools like PHPStan/Psalm with strict types or runtime tests are good at, but it’s beyond what a pure grep + line‑window validator can reliably do.


Could we add some heuristic for this class of bug?

We could design very narrow, heuristic rules for this plugin, for example:

  • Flag filters whose apply():
    • Return a structure like ['customers' => [], 'guest_orders' => [], 'orders' => []], and
    • Are wired into code that later treats the filter result as a flat array (e.g., foreach ( $customers as $customer ) without going through $customers['customers']).

Or:

  • Flag any place where a function named *search_customers*:
    • Calls apply_filters( 'kiss_woo_wholesale_filter', $results ), and
    • Subsequently treats $results as a flat list, while there exists a filter implementation that wraps it into a hash.

But:

  • That would be highly plugin‑specific and brittle.
  • It still wouldn’t be generally reliable across arbitrary codebases.

For a general solution, you’d want one or more of:

  • Static typing (PHPStan/Psalm) with:
    • Return type for search_customers(): array<Customer>
    • Interface defining apply(array{customers: list<Customer>, guest_orders: list<...>, orders: list<...>})
    • Those tools would then complain when the types don’t line up.
  • Runtime tests:
    • Unit test that calls search_customers() with the “Wholesale only” flag and asserts the result shape matches what JS expects, and that customers aren’t wiped.

Bottom line

  • Today:

    • Our static grep scanner and the PHP golden rules analyzer will not catch this “hash vs flat array” mismatch in a dependable way.
    • They don’t model data shapes, interfaces, or cross‑function contracts.
  • To catch this class of issue well, you’d need:

    • Type‑aware static analysis (PHPStan/Psalm or similar) or
    • Focused unit/integration tests that assert the response shape under “Wholesale only” (including guest_orders).

If you want, I can outline what a minimal test (PHPUnit or WP_UnitTestCase) would look like to lock this bug down, or sketch how a PHPStan rule for your KISS_Woo_Order_Filter interface might be structured.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions