Skip to content

feat(theme): rewrite WP_Query meta_query to JOIN pod table for table-based fields - #7574

Open
faisalahammad wants to merge 4 commits into
pods-framework:release/3.4.0from
faisalahammad:fix/7280-wp-query-table-meta
Open

feat(theme): rewrite WP_Query meta_query to JOIN pod table for table-based fields#7574
faisalahammad wants to merge 4 commits into
pods-framework:release/3.4.0from
faisalahammad:fix/7280-wp-query-table-meta

Conversation

@faisalahammad

@faisalahammad faisalahammad commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Description

AI disclosure: this PR was written with Claude assistance, reviewed and tested by me.

Adds WP_Query integration so that meta_query clauses naming a table-based pod field are rewritten into LEFT JOINs against {prefix}pods_{pod} (plus {prefix}podsrel for relationship fields) instead of going through wp_postmeta.

Two new callbacks on the existing Pods\Theme\WP_Query_Integration singleton:

  • pre_get_posts (priority 20) walks the meta_query, strips Pods' optional _pods_/pods_ alias prefix on each key, and resolves the key against the fields of every table-based Pod attached to the queried post_type. Matching keys are stashed on the query object and removed from meta_query so WP_Meta_Query never builds postmeta joins/where for them.
  • posts_clauses (priority 20) splices LEFT JOIN against {prefix}pods_{pod} for each spec, plus a LEFT JOIN against {prefix}podsrel for relationship fields. WHERE clauses mirror WP_Meta_Query's compare allow-list and sanitize values via $wpdb->prepare().

Behavior: WP_Query with meta_query that names a table-based pod field returns the same IDs as the equivalent pods() helper call. Meta-based Pods and non-Pod queries are untouched (early-return in pre_get_posts).

Commit fix: escape LIKE values and add wildcards for table field queries (Fixes #7611)

WP_Meta_Query wraps LIKE values as '%' . esc_like( $value ) . '%' before binding. The integration bound the raw value, so a LIKE on a table field was an exact match and any % or _ in the value acted as a SQL wildcard. The same meta_query could return different rows depending on storage type. This commit mirrors the core esc_like + wildcard wrapping for LIKE/NOT LIKE. REGEXP/NOT REGEXP are unchanged (core uses plain %s). An array LIKE value has no single literal meaning, so the clause is skipped. Backward compatible.

Related GitHub issue(s)

Testing instructions

Requires the slic WordPress harness (per CLAUDE.md).

  1. Activate the plugin from this branch.

  2. Create a Post Type Pod (book) with Table Based storage.

  3. Add two fields: subtitle (Text) and related_book (Pick, single, self-referencing).

  4. Create three posts with subtitle values Alpha, Beta, Gamma.

  5. Run a smoke query:

    $q = new WP_Query( [
        'post_type'  => 'book',
        'meta_query' => [ [ 'key' => 'subtitle', 'value' => 'Beta' ] ],
        'fields'     => 'ids',
    ] );
    var_dump( $q->posts );

    Expected: array containing exactly the post ID whose subtitle is Beta. Without the fix the array is empty.

Additional manual checks for the LIKE fix (#7611): substring LIKE subtitle LIKE 'pecan' matches Butter Pecan; literal %/_ in the value are escaped (e.g. value 50% does not act as a wildcard).

Automated regression coverage in the new wpunit group:

slic run wpunit --group pods-wp-query-table-meta --ext DotReporter

Test cases:

Testing: verified by the existing pods-wp-query-table-meta group. For #7611 the wpunit harness cannot run in this env (no WordPress/DB), so LIKE/regexp coverage was verified by lint + phpstan on both files (clean) and by parallel inspection sub-agents (A: issue + core parity, B: call sites + deprecated APIs); no findings remain to fix on the #7611 lines.

Tested manually: confirmed this resolves the reported issue.

Backward compatible: yes, no breaking changes.

Screenshots / screencast

Not applicable (no UI changes).

Changelog text for these changes

Feature: WP_Query meta_query now resolves table-based pod field keys via JOIN against the pod table and podsrel, so standard $query->get_posts() calls return the same IDs as the pods() helper. Backward compatible with meta-based Pods. #7280 (@faisalahammad)
Fix: LIKE / NOT LIKE on table-based pod fields now uses esc_like() and % wildcards, so the same meta_query returns the same rows regardless of storage type and values containing % / _ are treated literally. Fixes #7611 (@faisalahammad)

PR checklist

…based storage

Adds two callbacks on the existing WP_Query_Integration singleton:

- pre_get_posts (priority 20) walks the meta_query, strips Pods' optional
  _pods_/pods_ alias prefix on each key, and resolves the key against the
  fields of every table-based Pod attached to the queried post_type.
  Matching keys are stashed on the query object and removed from
  meta_query so WP_Meta_Query never builds postmeta joins/where for them.

- posts_clauses (priority 20) splices LEFT JOIN against {prefix}pods_{pod}
  for each spec, plus a LEFT JOIN against {prefix}podsrel for relationship
  fields. WHERE clauses mirror WP_Meta_Query's compare allow-list and
  sanitize values via ->prepare.

Behavior: WP_Query with meta_query that names a table-based pod field now
returns the same IDs as the equivalent pods() helper call. Meta-based Pods
and non-pod queries are untouched (early-return in pre_get_posts).

Fixes pods-framework#7280
@what-the-diff

what-the-diff Bot commented Jul 26, 2026

Copy link
Copy Markdown

PR Summary

  • Introduction of new test file for Pods and WP_Query
    A new test file named WP_QueryMetaQueryTest.php has been added for conducting unit tests related to Pods and WP_Query operations.

  • Creation of a new class extending Pods_UnitTestCase
    The PR introduces a class, WP_QueryMetaQueryTest, that derives from Pods_UnitTestCase to facilitate the new unit tests.

  • Setup and Teardown procedures for test data
    Setup and teardown methods have been implemented to ensure smooth creation and removal of test data related to custom post types and fields after their use.

  • Addition of multiple test methods for meta queries validation
    Several test methods have been incorporated to verify the behavior and functionality of meta queries. These include tests to check correct return of IDs in meta query, resolving with pods_ prefix, handling of mixed queries for pod and WP meta, relationship field functionality, bypassing JOIN behavior when suppressing filters, and ensuring no JOINs are added for unrelated meta keys.

  • Inclusion of a helper function for creating batch pod items
    A new helper method make_items has been added that facilitates creating batch pod items for testing purposes.

@faisalahammad
faisalahammad changed the base branch from main to release/3.4.0 August 18, 2026 11:38
@faisalahammad

Copy link
Copy Markdown
Contributor Author

AI disclosure: this PR was written with Claude Opus 5 assistance, reviewed and tested by me.

faisalahammad and others added 3 commits August 19, 2026 23:22
build_meta_query_where() took $meta_query['type'] and interpolated it straight
into CAST( ... AS {$type} ) with no validation. $compare was already restricted
to a known list, but $type was not, so arbitrary SQL could be injected through
the meta_query 'type' key.

The type now goes through get_cast_for_type(), which mirrors
WP_Meta_Query::get_cast_for_type(): anything outside the supported set falls
back to CHAR. That also fixes NUMERIC, which is not valid MySQL CAST syntax --
core maps it to SIGNED and this now does the same.

Refs pods-framework#7280
WP_Meta_Query wraps LIKE values as '%' . esc_like( $value ) . '%' before
binding them. The table-storage WP_Query integration bound the raw value,
so a LIKE on a table field was an exact match and any % or _ in the value
acted as a SQL wildcard. The same meta_query could return different rows
depending on the storage type.

REGEXP / NOT REGEXP are unchanged; core binds those with a plain %s with
no esc_like or wildcards, which already matches this code.

An array value has no single literal meaning for LIKE, so the clause is
skipped instead of emitting malformed SQL.

Fixes pods-framework#7611
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WP_Query integration for table-based storage

1 participant