Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes critical bugs in the caching functionality and improves the PerformanceControls component to align with established patterns. The main bug fixed is that the posts_pre_query and the_posts filters would attempt to cache results for ANY AQL query (where is_aql is set), even when the Enable Caching toggle was off. The fix adds strict boolean checks to ensure caching only happens when explicitly enabled.
Changes:
- Adds
isset()andtrue ===checks to caching filters to prevent unintended caching - Implements
allowedControlspattern in PerformanceControls to respect theaql_allowed_controlsfilter - Fixes
resetAllcallback (was no-op, now properly clearsenable_caching) - Atomically clears
enable_cachingwhen switching orderBy to Random - Adds missing
'advanced-query-loop'text domain to i18n strings - Updates documentation with comprehensive control lists and caching behavior description
- Adds comprehensive PHP unit tests and e2e tests
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| includes/query-loop.php | Adds strict boolean checks to prevent caching when not explicitly enabled |
| src/components/performance-controls.js | Implements allowedControls guard, fixes resetAll, adds text domains |
| src/components/post-order-controls.js | Clears enable_caching when switching to Random order |
| tests/unit/Enable_Caching_Tests.php | Adds tests documenting strict boolean contract for caching filters |
| tests/e2e/tests/enable-caching.spec.ts | Adds 10 e2e tests covering editor UI and frontend rendering |
| readme.txt | Documents Enable Caching control and completes control identifier list |
| readme.md | Documents Enable Caching functionality and adds to control list |
Comments suppressed due to low confidence (1)
includes/query-loop.php:216
- The caching implementation in
posts_pre_query/the_postscaches the entireWP_Queryobject globally in a transient keyed only by$query->query_vars_hash, without taking the current user or capabilities into account. If a privileged user (e.g., an admin or editor) triggers an AQL query that returns posts they are allowed to see (such as private or otherwise restricted content), thatWP_Queryis stored and then transparently reused for later visitors whose requests produce the same query vars hash, bypassingWP_Query’s normal capability-based filtering becauseposts_pre_queryshort-circuits the database query. This can leak private or otherwise access-controlled posts to unauthenticated or lower-privilege users; to fix this, the cache key or caching conditions need to incorporate user-specific context (or be limited to queries that are guaranteed to be user-agnostic, e.g.,post_statusstrictlypublish).
add_filter(
'posts_pre_query',
function ( $null_return, $query ) {
if ( ! $query->is_admin &&
isset( $query->query['is_aql'] ) &&
isset( $query->query['enable_caching'] ) &&
true === $query->query['enable_caching'] &&
! isset( $_GET['context'] ) && // phpcs:ignore
! isset( $_GET['canvas'] ) // phpcs:ignore
) {
$cached_query = get_transient( $query->query_vars_hash );
if ( $cached_query ) {
$query->found_posts = $cached_query->found_posts;
$query->max_num_pages = $cached_query->max_num_pages;
return $cached_query->posts;
}
}
return $null_return;
},
10,
2
);
/**
* Create a cache for the Query generated by the AQL instance.
*/
add_filter(
'the_posts',
function ( $posts, $query ) {
if ( ! $query->is_admin &&
isset( $query->query['is_aql'] ) &&
isset( $query->query['enable_caching'] ) &&
true === $query->query['enable_caching'] &&
! isset( $_GET['context'] ) && // phpcs:ignore
! isset( $_GET['canvas'] ) // phpcs:ignore
) {
if ( ! get_transient( $query->query_vars_hash ) ) {
set_transient( $query->query_vars_hash, $query, HOUR_IN_SECONDS );
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
posts_pre_queryandthe_postsfilters would attempt to cache/serve results for any AQL query, even when the Enable Caching toggle was offallowedControlsguard toPerformanceControlsso the panel respects theaql_allowed_controlsfilter like every other controlresetAllin the Performance Controls panel — it was a no-op and now correctly setsenable_cachingtofalseenable_cachingbeing left set when switchingorderBytoRandom— switching to Random now atomically clears the attribute'advanced-query-loop'text domain to i18n strings inperformance-controls.jsreadme.mdandreadme.txtto document the Enable Caching and Disable Pagination controls and complete the control identifier lists (exclude_postsandenable_cachingwere missing fromreadme.txt)true ===filter contractTest plan
enable_caching: truein block attributes; toggling off sets it tofalseenable_cachingenable_caching: trueattributenpm run test:unitpassesnpm run test:e2epasses (or runnpx playwright test tests/e2e/tests/enable-caching.spec.tsto run only the new tests)