-
-
Notifications
You must be signed in to change notification settings - Fork 615
Description
Bug description
What happened?
When an entries (or relationship) field has query_scopes configured (e.g., my_awesome_scope), the index request (e.g., opening the "Link Entry" picker in the CP) is built with applyIndexQueryScopes($query, $request->all()). Each scope's apply($query, $params) is called with that same $params (i.e., $request->all()).
Statamic\Fieldtypes\Entries::getIndexQuery() passes $request->all() as the second argument to applyIndexQueryScopes() (src/Fieldtypes/Entries.php line 257); Statamic\Fieldtypes\Relationship::applyIndexQueryScopes() then passes that $params unchanged to each scope's apply($query, $params) (src/Fieldtypes/Relationship.php lines 349–354).
$params is just the raw request (config, page, perPage, etc.). The scope handles live inside the decoded config (used to set up the fieldtype), but that decoded config is never merged into $params — so $params never has queryScopes.
Any scope that needs to know which scope handles are active (e.g., by reading $params['queryScopes']) never sees them and cannot apply the right filter. The index then shows entries that should have been filtered out.
What did you expect to happen?
Scopes that rely on $params['queryScopes'] (or equivalent) to know which handles are in effect should receive that list. For example, a scope like MyAwesomeScope (see below) only applies when its handle is in $values['queryScopes']; when it runs, it does $query->whereIn('id', []) so the index is empty. I expected the field's configured query_scopes to be passed into $params (e.g., as queryScopes) before calling each scope's apply().
Root cause
In Statamic\Fieldtypes\Relationship::applyIndexQueryScopes(), the second argument to each scope's apply() is always $request->all(). The field's query_scopes config is never merged into that array, so scopes never receive the list of active scope handles in $params.
Use case: one scope class, many handles
Scopes can use the optional aliases() method so that one scope class is registered under multiple handles. Core supports this in src/Extend/RegistersItself.php: when a scope registers, if it defines aliases(), each returned handle is bound to the same class. That allows a single scope (e.g. EntriesByType) to back many handles (e.g. entries_by_type_basic, entries_by_type_fancy). In that case the scope must know which handle(s) were requested so it can apply the right filter; the only way to pass that context is via $params['queryScopes']. Without it, aliased scopes cannot behave correctly.
How to reproduce
- Create a custom query scope that extends
Statamic\Query\Scopes\Scope, is registered with handlemy_awesome_scope, and implementsapply()as follows (only applies when its handle is in$values['queryScopes']; when applied, returns no results):
<?php
namespace App\Scopes;
use Statamic\Query\Scopes\Scope;
class MyAwesomeScope extends Scope
{
protected static $handle = 'my_awesome_scope';
public function apply($query, $values): void
{
if (
! \in_array(
static::$handle,
(array) ($values['queryScopes'] ?? []),
true
)
) {
return;
}
$query->whereIn('id', []);
}
}- Add an
entries(or relationship) field to a blueprint with:collections: e.g.,['pages']query_scopes: e.g.,['my_awesome_scope']
- Edit an entry that uses that blueprint and click "Link Entry" (or equivalent) to open the relationship index.
- Observe: The index shows all entries, because
$values['queryScopes']is missing and the scope never applies, so the "empty result" constraint is never added. - Expected: The index shows no entries when
my_awesome_scopeis inquery_scopes(scope runs and applieswhereIn('id', [])).
Logs
Environment
Environment
Application Name: UAMS Statamic
Laravel Version: 12.54.0
PHP Version: 8.4.16
Composer Version: 2.8.11
Environment: local
Debug Mode: ENABLED
URL: uams-statamic.test
Maintenance Mode: OFF
Timezone: UTC
Locale: en
Cache
Config: NOT CACHED
Events: CACHED
Routes: NOT CACHED
Views: CACHED
Drivers
Broadcasting: log
Cache: file
Database: sqlite
Logs: stack / single
Mail: smtp
Queue: sync
Session: file
Storage
public/storage: NOT LINKED
Statamic
Addons: 7
Sites: 255 (University of Arkansas for Medical Sciences, UAMS Health, AR-IMPACT, and 252 more)
Stache Watcher: Enabled (auto)
Static Caching: Disabled
Version: 6.5.0 PRO
Statamic Addons
el-schneider/statamic-admin-bar: 0.3.1
jacksleight/statamic-bard-mutator: 3.0.5
jacksleight/statamic-bard-texstyle: 4.0.2
statamic/eloquent-driver: 5.3.0
statamic/ssg: 4.1.0
studio1902/statamic-peak-seo: 11.0.2
studio1902/statamic-peak-tools: 9.0.2
Statamic Eloquent Driver
Addon Settings: file
Asset Containers: file
Assets: eloquent
Blueprints: file
Collection Trees: file
Collections: file
Entries: file
Fieldsets: file
Form Submissions: file
Forms: file
Global Sets: file
Global Variables: file
Navigation Trees: file
Navigations: file
Revisions: file
Sites: file
Taxonomies: file
Terms: file
Tokens: fileInstallation
Fresh statamic/statamic site via CLI
Additional details
Merge the field's query_scopes into $params before calling each scope, so that $params includes the active scope handles. For example:
protected function applyIndexQueryScopes($query, $params)
{
$params = [
...$params,
'queryScopes' => Arr::wrap($this->config('query_scopes')),
];
collect(Arr::wrap($this->config('query_scopes')))
->map(fn ($handle) => Scope::find($handle))
->filter()
->each(fn ($scope) => $scope->apply($query, $params));
}