From ee8d5eb5f4f4a1049002ee32c9fe01e2e1d086d3 Mon Sep 17 00:00:00 2001 From: Michael Aerni Date: Tue, 19 Dec 2023 16:14:43 -0500 Subject: [PATCH 01/27] Add site filter to the entries selector --- .../inputs/relationship/Selector.vue | 22 +++++++++++++++++-- src/Query/Scopes/Filters/Site.php | 2 +- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/resources/js/components/inputs/relationship/Selector.vue b/resources/js/components/inputs/relationship/Selector.vue index 10772c78ac..475d4c2083 100644 --- a/resources/js/components/inputs/relationship/Selector.vue +++ b/resources/js/components/inputs/relationship/Selector.vue @@ -240,7 +240,8 @@ export default { columns: this.initialColumns, visibleColumns: this.initialColumns.filter(column => column.visible), view: 'list', - lastItemClicked: null + lastItemClicked: null, + currentSite: this.site, } }, @@ -251,7 +252,7 @@ export default { sort: this.sortColumn, order: this.sortDirection, page: this.page, - site: this.site, + site: this.currentSite, exclusions: this.exclusions, filters: utf8btoa(JSON.stringify(this.activeFilters)), columns: this.visibleColumns.map(column => column.field).join(','), @@ -293,12 +294,25 @@ export default { this.getFilters().then(() => { this.autoApplyFilters(this.filters); + this.setSiteFilter(this.currentSite) this.initialRequest(); }); }, watch: { + activeFilters: { + deep: true, + handler(filters) { + this.currentSite = filters.site ? filters.site.site : null; + } + }, + + currentSite(site) { + this.setSiteFilter(site); + this.$emit('site-changed', site); + }, + parameters: { deep: true, handler(after, before) { @@ -345,6 +359,10 @@ export default { }); }, + setSiteFilter(site) { + this.filterChanged({ handle: 'site', values: { site }}); + }, + initialRequest() { return this.request().then(() => { if (this.search && this.view === 'list') this.$refs.search.focus(); diff --git a/src/Query/Scopes/Filters/Site.php b/src/Query/Scopes/Filters/Site.php index c316400c08..a8b9177273 100644 --- a/src/Query/Scopes/Filters/Site.php +++ b/src/Query/Scopes/Filters/Site.php @@ -46,7 +46,7 @@ public function badge($values) public function visibleTo($key) { - return $key === 'entries' && Facades\Site::hasMultiple(); + return in_array($key, ['entries', 'entries-fieldtype']) && Facades\Site::hasMultiple(); } protected function options() From 7c2222d564e684ff12aea13ad92899ebd2602430 Mon Sep 17 00:00:00 2001 From: Michael Aerni Date: Tue, 19 Dec 2023 18:52:16 -0500 Subject: [PATCH 02/27] Only query sites the user has permission to --- src/Fieldtypes/Entries.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Fieldtypes/Entries.php b/src/Fieldtypes/Entries.php index f29272c518..cbfc3838bd 100644 --- a/src/Fieldtypes/Entries.php +++ b/src/Fieldtypes/Entries.php @@ -203,8 +203,8 @@ protected function getIndexQuery($request) $query = $this->toSearchQuery($query, $request); - if ($site = $request->site) { - $query->where('site', $site); + if (Site::hasMultiple()) { + $query->whereIn('site', Site::authorized()->map->handle()->all()); } if ($request->exclusions) { From a5ea34a65067763b68294d4624a30557da50e408 Mon Sep 17 00:00:00 2001 From: Michael Aerni Date: Tue, 19 Dec 2023 18:58:13 -0500 Subject: [PATCH 03/27] Hide filter if only one authorized site --- resources/js/components/inputs/relationship/Selector.vue | 8 +++++++- src/Query/Scopes/Filters/Site.php | 3 ++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/resources/js/components/inputs/relationship/Selector.vue b/resources/js/components/inputs/relationship/Selector.vue index 475d4c2083..a4a6b072f2 100644 --- a/resources/js/components/inputs/relationship/Selector.vue +++ b/resources/js/components/inputs/relationship/Selector.vue @@ -285,7 +285,11 @@ export default { viewLocalStorageKey() { return `statamic.selector.field.${this.name}`; - } + }, + + hasSiteFilter() { + return this.filters.some(filter => filter.handle === 'site'); + }, }, @@ -360,6 +364,8 @@ export default { }, setSiteFilter(site) { + if (!this.hasSiteFilter) return; + this.filterChanged({ handle: 'site', values: { site }}); }, diff --git a/src/Query/Scopes/Filters/Site.php b/src/Query/Scopes/Filters/Site.php index a8b9177273..f47e1b82f7 100644 --- a/src/Query/Scopes/Filters/Site.php +++ b/src/Query/Scopes/Filters/Site.php @@ -46,7 +46,8 @@ public function badge($values) public function visibleTo($key) { - return in_array($key, ['entries', 'entries-fieldtype']) && Facades\Site::hasMultiple(); + return in_array($key, ['entries', 'entries-fieldtype']) + && Facades\Site::authorized()->count() > 1; } protected function options() From 7714328b2034046236d0a7e39af6d4b845516650 Mon Sep 17 00:00:00 2001 From: Michael Aerni Date: Tue, 19 Dec 2023 19:13:55 -0500 Subject: [PATCH 04/27] Only show configured sites in the site filter --- src/Query/Scopes/Filters/Site.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Query/Scopes/Filters/Site.php b/src/Query/Scopes/Filters/Site.php index f47e1b82f7..4eb5dc3267 100644 --- a/src/Query/Scopes/Filters/Site.php +++ b/src/Query/Scopes/Filters/Site.php @@ -3,6 +3,7 @@ namespace Statamic\Query\Scopes\Filters; use Statamic\Facades; +use Statamic\Facades\Collection; use Statamic\Query\Scopes\Filter; class Site extends Filter @@ -52,8 +53,10 @@ public function visibleTo($key) protected function options() { - return Facades\Site::authorized()->mapWithKeys(function ($site) { - return [$site->handle() => __($site->name())]; - }); + $configuredSites = Collection::find($this->context['collection'])->sites(); + + return Facades\Site::authorized() + ->filter(fn ($site) => $configuredSites->contains($site->handle())) + ->mapWithKeys(fn ($site) => [$site->handle() => __($site->name())]); } } From 9b6b24002a28199708836ff0e8b50001a716f57e Mon Sep 17 00:00:00 2001 From: Michael Aerni Date: Tue, 19 Dec 2023 19:56:51 -0500 Subject: [PATCH 05/27] Account for multiple collections --- src/Query/Scopes/Filters/Site.php | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/Query/Scopes/Filters/Site.php b/src/Query/Scopes/Filters/Site.php index 4eb5dc3267..3ec5cdb098 100644 --- a/src/Query/Scopes/Filters/Site.php +++ b/src/Query/Scopes/Filters/Site.php @@ -2,6 +2,7 @@ namespace Statamic\Query\Scopes\Filters; +use Illuminate\Support\Arr; use Statamic\Facades; use Statamic\Facades\Collection; use Statamic\Query\Scopes\Filter; @@ -48,15 +49,32 @@ public function badge($values) public function visibleTo($key) { return in_array($key, ['entries', 'entries-fieldtype']) - && Facades\Site::authorized()->count() > 1; + && $this->availableSites()->count() > 1; } protected function options() { - $configuredSites = Collection::find($this->context['collection'])->sites(); + return $this->availableSites() + ->mapWithKeys(fn ($site) => [$site->handle() => __($site->name())]); + } + + protected function availableSites() + { + // Get the configured sites of a single collection when on the entries index view. + if ($collection = Arr::get($this->context, 'collection')) { + $configuredSites = Collection::find($collection)->sites(); + } + + // Get the configured sites of multiple collections when in the entries fieldtype. + if ($collections = Arr::get($this->context, 'collections')) { + $configuredSites = collect($collections)->flatMap(fn ($collection) => Collection::find($collection)->sites()); + } + + if (! isset($configuredSites)) { + return Facades\Site::authorized(); + } return Facades\Site::authorized() - ->filter(fn ($site) => $configuredSites->contains($site->handle())) - ->mapWithKeys(fn ($site) => [$site->handle() => __($site->name())]); + ->filter(fn ($site) => $configuredSites->contains($site->handle())); } } From e7c6294041f44cf6397586f3e530bb508daec7ff Mon Sep 17 00:00:00 2001 From: edalzell Date: Wed, 20 Dec 2023 11:45:47 -0800 Subject: [PATCH 06/27] fallback to selected site --- .../fieldtypes/relationship/RelationshipFieldtype.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/components/fieldtypes/relationship/RelationshipFieldtype.vue b/resources/js/components/fieldtypes/relationship/RelationshipFieldtype.vue index 90962a95b8..d92b261a7c 100644 --- a/resources/js/components/fieldtypes/relationship/RelationshipFieldtype.vue +++ b/resources/js/components/fieldtypes/relationship/RelationshipFieldtype.vue @@ -94,7 +94,7 @@ export default { site() { if (! this.storeName) return this.$config.get('selectedSite'); - return this.$store.state.publish[this.storeName].site; + return this.$store.state.publish[this.storeName].site ?? this.$config.get('selectedSite'); }, canEdit() { From be7086edf1d7c696967566c038015ec4d5ba98a2 Mon Sep 17 00:00:00 2001 From: edalzell Date: Wed, 20 Dec 2023 11:46:04 -0800 Subject: [PATCH 07/27] handle `select` mode --- src/Fieldtypes/Entries.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Fieldtypes/Entries.php b/src/Fieldtypes/Entries.php index cbfc3838bd..66315e6f7c 100644 --- a/src/Fieldtypes/Entries.php +++ b/src/Fieldtypes/Entries.php @@ -203,8 +203,9 @@ protected function getIndexQuery($request) $query = $this->toSearchQuery($query, $request); + if (Site::hasMultiple()) { - $query->whereIn('site', Site::authorized()->map->handle()->all()); + $query->whereIn('site', $this->getSites($request)); } if ($request->exclusions) { @@ -216,6 +217,15 @@ protected function getIndexQuery($request) return $query; } + private function getSites($request): array + { + if ($request->site && Arr::get($this->field()->config(), 'mode') == 'select') { + return [$request->site]; + } + + return Site::authorized()->map->handle()->all(); + } + private function toSearchQuery($query, $request) { if (! $search = $request->search) { From fa3b1b11168b9988cb6272d568dd2ca75311dfc8 Mon Sep 17 00:00:00 2001 From: edalzell Date: Wed, 20 Dec 2023 12:31:17 -0800 Subject: [PATCH 08/27] add site when in stack mode and have multiple sites --- src/Fieldtypes/Entries.php | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/Fieldtypes/Entries.php b/src/Fieldtypes/Entries.php index 66315e6f7c..3d5ae9cf62 100644 --- a/src/Fieldtypes/Entries.php +++ b/src/Fieldtypes/Entries.php @@ -6,6 +6,7 @@ use Statamic\Contracts\Data\Localization; use Statamic\Contracts\Entries\Entry as EntryContract; use Statamic\CP\Column; +use Statamic\CP\Columns; use Statamic\Exceptions\CollectionNotFoundException; use Statamic\Facades\Collection; use Statamic\Facades\Entry; @@ -203,7 +204,6 @@ protected function getIndexQuery($request) $query = $this->toSearchQuery($query, $request); - if (Site::hasMultiple()) { $query->whereIn('site', $this->getSites($request)); } @@ -400,20 +400,18 @@ public function getColumns() if (count($this->getConfiguredCollections()) === 1) { $columns = $this->getBlueprint()->columns(); - $status = Column::make('status') - ->listable(true) - ->visible(true) - ->defaultVisibility(true) - ->sortable(false); - - $columns->put('status', $status); + $this->addColumn($columns, 'status'); $columns->setPreferred("collections.{$this->getConfiguredCollections()[0]}.columns"); return $columns->rejectUnlisted()->values(); } - return $this->getBlueprint()->columns()->values()->all(); + $columns = $this->getBlueprint()->columns(); + + $this->addColumn($columns, 'site'); + + return $columns->values(); } protected function getItemsForPreProcessIndex($values): SupportCollection @@ -449,4 +447,15 @@ public function preload() 'expectsRoot' => $collection->structure()->expectsRoot(), ]]); } + + private function addColumn(Columns $columns, string $columnKey): void + { + $column = Column::make($columnKey) + ->listable(true) + ->visible(true) + ->defaultVisibility(true) + ->sortable(false); + + $columns->put($columnKey, $column); + } } From 73b93355ba87cfb18f22051bc454deb2515b49f0 Mon Sep 17 00:00:00 2001 From: edalzell Date: Wed, 20 Dec 2023 12:32:54 -0800 Subject: [PATCH 09/27] tidy --- src/Fieldtypes/Entries.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Fieldtypes/Entries.php b/src/Fieldtypes/Entries.php index 3d5ae9cf62..70a69b1ce2 100644 --- a/src/Fieldtypes/Entries.php +++ b/src/Fieldtypes/Entries.php @@ -217,15 +217,6 @@ protected function getIndexQuery($request) return $query; } - private function getSites($request): array - { - if ($request->site && Arr::get($this->field()->config(), 'mode') == 'select') { - return [$request->site]; - } - - return Site::authorized()->map->handle()->all(); - } - private function toSearchQuery($query, $request) { if (! $search = $request->search) { @@ -458,4 +449,13 @@ private function addColumn(Columns $columns, string $columnKey): void $columns->put($columnKey, $column); } + + private function getSites($request): array + { + if ($request->site && Arr::get($this->field()->config(), 'mode') == 'select') { + return [$request->site]; + } + + return Site::authorized()->map->handle()->all(); + } } From 5a45cbfbe8d5d90faada90dfd593252a99c8017d Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Mon, 29 Jan 2024 15:31:35 -0500 Subject: [PATCH 10/27] prevent deselecting --- resources/js/components/inputs/relationship/Selector.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/components/inputs/relationship/Selector.vue b/resources/js/components/inputs/relationship/Selector.vue index a4a6b072f2..d0506e6905 100644 --- a/resources/js/components/inputs/relationship/Selector.vue +++ b/resources/js/components/inputs/relationship/Selector.vue @@ -366,7 +366,7 @@ export default { setSiteFilter(site) { if (!this.hasSiteFilter) return; - this.filterChanged({ handle: 'site', values: { site }}); + this.filterChanged({ handle: 'site', values: { site }}, false); }, initialRequest() { From 8b137df98d19db0744cd70fc976050c81ceccf29 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 30 Jan 2024 09:38:19 -0500 Subject: [PATCH 11/27] opting into the site setting opts out of localizing during augmentation --- src/Fieldtypes/Entries.php | 13 +++++++++---- tests/Fieldtypes/EntriesTest.php | 6 ++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/Fieldtypes/Entries.php b/src/Fieldtypes/Entries.php index 70a69b1ce2..802068b622 100644 --- a/src/Fieldtypes/Entries.php +++ b/src/Fieldtypes/Entries.php @@ -326,13 +326,18 @@ public function augment($values) $site = $parent->locale(); } + // If they've opted into selecting across sites, we won't automatically localize or + // filter out entries that don't exist in the current site. They would do that. + $shouldLocalize = ! $this->config('select_across_sites', false); + $ids = (new OrderedQueryBuilder(Entry::query(), $ids = Arr::wrap($values))) ->whereIn('id', $ids) ->get() - ->map(function ($entry) use ($site) { - return optional($entry->in($site))->id(); - }) - ->filter() + ->when($shouldLocalize, fn ($entries) => $entries + ->map(fn ($entry) => $entry->in($site)) + ->filter() + ) + ->map->id() ->all(); $query = (new StatusQueryBuilder(new OrderedQueryBuilder(Entry::query(), $ids))) diff --git a/tests/Fieldtypes/EntriesTest.php b/tests/Fieldtypes/EntriesTest.php index 2d3890657f..1556cef840 100644 --- a/tests/Fieldtypes/EntriesTest.php +++ b/tests/Fieldtypes/EntriesTest.php @@ -360,6 +360,12 @@ public function it_localizes_the_shallow_augmented_item_to_the_current_sites_loc $this->assertNull($augmented); // 456 isnt localized } + /** @test */ + public function it_doesnt_localize_when_select_across_sites_setting_is_enabled() + { + $this->markTestIncomplete(); + } + public function fieldtype($config = [], $parent = null) { $field = new Field('test', array_merge([ From 57476b9b12abd12483175f2df3b0dcc92fb21fe9 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 30 Jan 2024 10:31:30 -0500 Subject: [PATCH 12/27] undo unnecessary js changes --- .../inputs/relationship/Selector.vue | 30 ++----------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/resources/js/components/inputs/relationship/Selector.vue b/resources/js/components/inputs/relationship/Selector.vue index d0506e6905..10772c78ac 100644 --- a/resources/js/components/inputs/relationship/Selector.vue +++ b/resources/js/components/inputs/relationship/Selector.vue @@ -240,8 +240,7 @@ export default { columns: this.initialColumns, visibleColumns: this.initialColumns.filter(column => column.visible), view: 'list', - lastItemClicked: null, - currentSite: this.site, + lastItemClicked: null } }, @@ -252,7 +251,7 @@ export default { sort: this.sortColumn, order: this.sortDirection, page: this.page, - site: this.currentSite, + site: this.site, exclusions: this.exclusions, filters: utf8btoa(JSON.stringify(this.activeFilters)), columns: this.visibleColumns.map(column => column.field).join(','), @@ -285,11 +284,7 @@ export default { viewLocalStorageKey() { return `statamic.selector.field.${this.name}`; - }, - - hasSiteFilter() { - return this.filters.some(filter => filter.handle === 'site'); - }, + } }, @@ -298,25 +293,12 @@ export default { this.getFilters().then(() => { this.autoApplyFilters(this.filters); - this.setSiteFilter(this.currentSite) this.initialRequest(); }); }, watch: { - activeFilters: { - deep: true, - handler(filters) { - this.currentSite = filters.site ? filters.site.site : null; - } - }, - - currentSite(site) { - this.setSiteFilter(site); - this.$emit('site-changed', site); - }, - parameters: { deep: true, handler(after, before) { @@ -363,12 +345,6 @@ export default { }); }, - setSiteFilter(site) { - if (!this.hasSiteFilter) return; - - this.filterChanged({ handle: 'site', values: { site }}, false); - }, - initialRequest() { return this.request().then(() => { if (this.search && this.view === 'list') this.$refs.search.focus(); From a654e32e73d963104f00e880cfe791f0e91b0546 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 30 Jan 2024 10:34:51 -0500 Subject: [PATCH 13/27] wrap in option --- resources/lang/en/fieldtypes.php | 1 + src/Fieldtypes/Entries.php | 25 +++++++++++++++++++++---- src/Query/Scopes/Filters/Site.php | 15 +++++++++++++-- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/resources/lang/en/fieldtypes.php b/resources/lang/en/fieldtypes.php index 9c2d9a928c..cc800d6a96 100644 --- a/resources/lang/en/fieldtypes.php +++ b/resources/lang/en/fieldtypes.php @@ -76,6 +76,7 @@ 'entries.config.collections' => 'Choose which collections the user can select from.', 'entries.config.query_scopes' => 'Choose which query scopes should be applied when retrieving selectable entries.', 'entries.config.search_index' => 'An appropriate search index will be used automatically where possible, but you may define an explicit one.', + 'entries.config.select_across_sites' => 'Allow selecting entries from other sites. This also disables localizing options on the front-end. Learn more in the [documentation](https://statamic.dev/fieldtypes/entries). ', 'entries.title' => 'Entries', 'float.title' => 'Float', 'form.config.max_items' => 'Set a maximum number of selectable forms.', diff --git a/src/Fieldtypes/Entries.php b/src/Fieldtypes/Entries.php index 802068b622..62ab444fab 100644 --- a/src/Fieldtypes/Entries.php +++ b/src/Fieldtypes/Entries.php @@ -106,6 +106,11 @@ protected function configFieldItems(): array 'instructions' => __('statamic::fieldtypes.entries.config.query_scopes'), 'type' => 'taggable', ], + 'select_across_sites' => [ + 'display' => __('Select Across Sites'), + 'instructions' => __('statamic::fieldtypes.entries.config.select_across_sites'), + 'type' => 'toggle', + ], ], ], ]; @@ -204,8 +209,10 @@ protected function getIndexQuery($request) $query = $this->toSearchQuery($query, $request); - if (Site::hasMultiple()) { + if ($this->canSelectAcrossSites()) { $query->whereIn('site', $this->getSites($request)); + } elseif ($site = $request->site) { + $query->where('site', $site); } if ($request->exclusions) { @@ -328,7 +335,7 @@ public function augment($values) // If they've opted into selecting across sites, we won't automatically localize or // filter out entries that don't exist in the current site. They would do that. - $shouldLocalize = ! $this->config('select_across_sites', false); + $shouldLocalize = ! $this->canSelectAcrossSites(); $ids = (new OrderedQueryBuilder(Entry::query(), $ids = Arr::wrap($values))) ->whereIn('id', $ids) @@ -370,7 +377,10 @@ public function getSelectionFilters() protected function getSelectionFilterContext() { - return ['collections' => $this->getConfiguredCollections()]; + return [ + 'collections' => $this->getConfiguredCollections(), + 'showSiteFilter' => $this->canSelectAcrossSites(), + ]; } protected function getConfiguredCollections() @@ -405,7 +415,9 @@ public function getColumns() $columns = $this->getBlueprint()->columns(); - $this->addColumn($columns, 'site'); + if ($this->canSelectAcrossSites()) { + $this->addColumn($columns, 'site'); + } return $columns->values(); } @@ -463,4 +475,9 @@ private function getSites($request): array return Site::authorized()->map->handle()->all(); } + + private function canSelectAcrossSites(): bool + { + return $this->config('select_across_sites', false); + } } diff --git a/src/Query/Scopes/Filters/Site.php b/src/Query/Scopes/Filters/Site.php index 3ec5cdb098..a51ed00704 100644 --- a/src/Query/Scopes/Filters/Site.php +++ b/src/Query/Scopes/Filters/Site.php @@ -48,8 +48,15 @@ public function badge($values) public function visibleTo($key) { - return in_array($key, ['entries', 'entries-fieldtype']) - && $this->availableSites()->count() > 1; + if ($this->availableSites()->isEmpty()) { + return false; + } + + if ($key === 'entries') { + return true; + } + + return $key === 'entries-fieldtype' && $this->context['showSiteFilter']; } protected function options() @@ -60,6 +67,10 @@ protected function options() protected function availableSites() { + if (! Facades\Site::hasMultiple()) { + return collect(); + } + // Get the configured sites of a single collection when on the entries index view. if ($collection = Arr::get($this->context, 'collection')) { $configuredSites = Collection::find($collection)->sites(); From 09b524bb7024b583b47a8b5a7032e7def17881a6 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 30 Jan 2024 11:02:23 -0500 Subject: [PATCH 14/27] rework condition so it prevents checking sites if we know its not an an entry listing --- src/Query/Scopes/Filters/Site.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Query/Scopes/Filters/Site.php b/src/Query/Scopes/Filters/Site.php index a51ed00704..e359fad65f 100644 --- a/src/Query/Scopes/Filters/Site.php +++ b/src/Query/Scopes/Filters/Site.php @@ -48,15 +48,11 @@ public function badge($values) public function visibleTo($key) { - if ($this->availableSites()->isEmpty()) { - return false; - } - - if ($key === 'entries') { + if ($key === 'entries' && $this->availableSites()->isNotEmpty()) { return true; } - return $key === 'entries-fieldtype' && $this->context['showSiteFilter']; + return $key === 'entries-fieldtype' && $this->context['showSiteFilter'] && $this->availableSites()->isNotEmpty(); } protected function options() From 5dd82eabb89e0fb1e0db7cbe52e5931e44eff4c9 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 30 Jan 2024 11:07:06 -0500 Subject: [PATCH 15/27] more than one --- src/Query/Scopes/Filters/Site.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Query/Scopes/Filters/Site.php b/src/Query/Scopes/Filters/Site.php index e359fad65f..a54af04de1 100644 --- a/src/Query/Scopes/Filters/Site.php +++ b/src/Query/Scopes/Filters/Site.php @@ -48,11 +48,11 @@ public function badge($values) public function visibleTo($key) { - if ($key === 'entries' && $this->availableSites()->isNotEmpty()) { + if ($key === 'entries' && $this->availableSites()->count() > 1) { return true; } - return $key === 'entries-fieldtype' && $this->context['showSiteFilter'] && $this->availableSites()->isNotEmpty(); + return $key === 'entries-fieldtype' && $this->context['showSiteFilter'] && $this->availableSites()->count() > 1; } protected function options() From 61a9033c83c2e9b8f93a974791ec8592cc87f65a Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 30 Jan 2024 11:11:48 -0500 Subject: [PATCH 16/27] fluent --- src/Query/Scopes/Filters/Site.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Query/Scopes/Filters/Site.php b/src/Query/Scopes/Filters/Site.php index a54af04de1..31273cda6b 100644 --- a/src/Query/Scopes/Filters/Site.php +++ b/src/Query/Scopes/Filters/Site.php @@ -77,11 +77,7 @@ protected function availableSites() $configuredSites = collect($collections)->flatMap(fn ($collection) => Collection::find($collection)->sites()); } - if (! isset($configuredSites)) { - return Facades\Site::authorized(); - } - return Facades\Site::authorized() - ->filter(fn ($site) => $configuredSites->contains($site->handle())); + ->when(isset($configuredSites), fn ($sites) => $sites->filter(fn ($site) => $configuredSites->contains($site->handle()))); } } From 43428b17d7de6058e32a162123b93b5e717aa9a7 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 30 Jan 2024 11:13:51 -0500 Subject: [PATCH 17/27] do a single flatmap for both situations --- src/Query/Scopes/Filters/Site.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Query/Scopes/Filters/Site.php b/src/Query/Scopes/Filters/Site.php index 31273cda6b..21ed0dcea7 100644 --- a/src/Query/Scopes/Filters/Site.php +++ b/src/Query/Scopes/Filters/Site.php @@ -67,15 +67,15 @@ protected function availableSites() return collect(); } + // Get the configured sites of multiple collections when in the entries fieldtype. + $collections = Arr::get($this->context, 'collections'); + // Get the configured sites of a single collection when on the entries index view. if ($collection = Arr::get($this->context, 'collection')) { - $configuredSites = Collection::find($collection)->sites(); + $collections = [$collection]; } - // Get the configured sites of multiple collections when in the entries fieldtype. - if ($collections = Arr::get($this->context, 'collections')) { - $configuredSites = collect($collections)->flatMap(fn ($collection) => Collection::find($collection)->sites()); - } + $configuredSites = collect($collections)->flatMap(fn ($collection) => Collection::find($collection)->sites()); return Facades\Site::authorized() ->when(isset($configuredSites), fn ($sites) => $sites->filter(fn ($site) => $configuredSites->contains($site->handle()))); From 39d54065168adbbc300a17b2666033f62750114a Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 30 Jan 2024 11:38:29 -0500 Subject: [PATCH 18/27] itll be here --- resources/lang/en/fieldtypes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lang/en/fieldtypes.php b/resources/lang/en/fieldtypes.php index cc800d6a96..e5be81d17d 100644 --- a/resources/lang/en/fieldtypes.php +++ b/resources/lang/en/fieldtypes.php @@ -76,7 +76,7 @@ 'entries.config.collections' => 'Choose which collections the user can select from.', 'entries.config.query_scopes' => 'Choose which query scopes should be applied when retrieving selectable entries.', 'entries.config.search_index' => 'An appropriate search index will be used automatically where possible, but you may define an explicit one.', - 'entries.config.select_across_sites' => 'Allow selecting entries from other sites. This also disables localizing options on the front-end. Learn more in the [documentation](https://statamic.dev/fieldtypes/entries). ', + 'entries.config.select_across_sites' => 'Allow selecting entries from other sites. This also disables localizing options on the front-end. Learn more in the [documentation](https://statamic.dev/fieldtypes/entries#select-across-sites).', 'entries.title' => 'Entries', 'float.title' => 'Float', 'form.config.max_items' => 'Set a maximum number of selectable forms.', From 78afe75a2ea5631a1d9cbba1bda707876c96c0bf Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 30 Jan 2024 11:46:52 -0500 Subject: [PATCH 19/27] test --- tests/Fieldtypes/EntriesTest.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/Fieldtypes/EntriesTest.php b/tests/Fieldtypes/EntriesTest.php index 1556cef840..2c1d2eb5da 100644 --- a/tests/Fieldtypes/EntriesTest.php +++ b/tests/Fieldtypes/EntriesTest.php @@ -363,7 +363,17 @@ public function it_localizes_the_shallow_augmented_item_to_the_current_sites_loc /** @test */ public function it_doesnt_localize_when_select_across_sites_setting_is_enabled() { - $this->markTestIncomplete(); + $parent = EntryFactory::id('parent')->collection('blog')->slug('theparent')->locale('fr')->create(); + + EntryFactory::id('123-fr')->origin('123')->locale('fr')->collection('blog')->slug('one-fr')->data(['title' => 'Le One'])->date('2021-01-02')->create(); + EntryFactory::id('789-fr')->origin('789')->locale('fr')->collection('blog')->slug('three-fr')->data(['title' => 'Le Three'])->date('2021-01-02')->published(false)->create(); + EntryFactory::id('910-fr')->origin('910')->locale('fr')->collection('blog')->slug('four-fr')->data(['title' => 'Le Four'])->date('2021-01-02')->create(); + + $augmented = $this->fieldtype(['select_across_sites' => true], $parent)->augment(['123', 'invalid', 456, 789, 910, 'draft', 'scheduled', 'expired']); + + $this->assertInstanceOf(Builder::class, $augmented); + $this->assertEveryItemIsInstanceOf(Entry::class, $augmented->get()); + $this->assertEquals(['one', 'two', 'three', 'four'], $augmented->get()->map->slug()->all()); } public function fieldtype($config = [], $parent = null) From 3b2e77a6bac4f32b19ce9b1cb5d58e2b0d8021e3 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 30 Jan 2024 14:30:15 -0500 Subject: [PATCH 20/27] allow the select ui mode to pick from other sites too --- .../relationship/RelationshipFieldtype.vue | 1 + .../inputs/relationship/RelationshipInput.vue | 2 ++ .../inputs/relationship/SelectField.vue | 12 ++++++- src/Fieldtypes/Entries.php | 32 ++++++++++++------- src/Http/Resources/CP/Entries/ListedEntry.php | 1 + 5 files changed, 36 insertions(+), 12 deletions(-) diff --git a/resources/js/components/fieldtypes/relationship/RelationshipFieldtype.vue b/resources/js/components/fieldtypes/relationship/RelationshipFieldtype.vue index b0efc76512..91892378bf 100644 --- a/resources/js/components/fieldtypes/relationship/RelationshipFieldtype.vue +++ b/resources/js/components/fieldtypes/relationship/RelationshipFieldtype.vue @@ -7,6 +7,7 @@ :mode="config.mode" :can-edit="canEdit" :config="config" + :meta="meta" :can-create="canCreate" :can-reorder="canReorder" :site="site" diff --git a/resources/js/components/inputs/relationship/RelationshipInput.vue b/resources/js/components/inputs/relationship/RelationshipInput.vue index 3ba22ab8ee..f9ed71acf1 100644 --- a/resources/js/components/inputs/relationship/RelationshipInput.vue +++ b/resources/js/components/inputs/relationship/RelationshipInput.vue @@ -5,6 +5,7 @@ +