From 379e2a33ee7483a137ab2e1b24e71314e075079f Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Thu, 12 Mar 2026 08:31:44 +0000 Subject: [PATCH 1/4] Make entries count more performant when we use eloquent for terms and entries --- src/Taxonomies/TermRepository.php | 27 ++++++++++++++ tests/Terms/TermTest.php | 58 +++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/src/Taxonomies/TermRepository.php b/src/Taxonomies/TermRepository.php index a0666211..273efe16 100644 --- a/src/Taxonomies/TermRepository.php +++ b/src/Taxonomies/TermRepository.php @@ -3,11 +3,14 @@ namespace Statamic\Eloquent\Taxonomies; use Statamic\Contracts\Taxonomies\Term as TermContract; +use Statamic\Eloquent\Taxonomies\Term; use Statamic\Facades\Blink; use Statamic\Facades\Collection; +use Statamic\Facades\Entry; use Statamic\Facades\Taxonomy; use Statamic\Stache\Repositories\TermRepository as StacheRepository; use Statamic\Support\Str; +use Statamic\Taxonomies\LocalizedTerm; class TermRepository extends StacheRepository { @@ -131,4 +134,28 @@ protected function ensureAssociations() parent::ensureAssociations(); } + + public function entriesCount(TermContract $term, ?string $status = null): int + { + if (config('statamic.eloquent-driver.entries.driver', 'file') !== 'eloquent') { + return parent::entriesCount($term, $status); + } + + $query = Entry::query() + ->whereTaxonomy($term->taxonomyHandle().'::'.$term->inDefaultLocale()->slug()); + + if ($term instanceof LocalizedTerm) { + $query->where('site', $term->locale()); + } + + if ($collection = $term->collection()) { + $query->where('collection', $collection->handle()); + } + + if ($status) { + $query->whereStatus($status); + } + + return $query->count(); + } } diff --git a/tests/Terms/TermTest.php b/tests/Terms/TermTest.php index b1e5ac8d..8b48e3ea 100644 --- a/tests/Terms/TermTest.php +++ b/tests/Terms/TermTest.php @@ -15,6 +15,7 @@ use Statamic\Facades\Taxonomy as TaxonomyFacade; use Statamic\Facades\Term as TermFacade; use Statamic\Statamic; +use Statamic\Taxonomies\Term; use Statamic\Testing\Concerns\PreventsSavingStacheItemsToDisk; use Tests\TestCase; @@ -84,6 +85,63 @@ public function it_gets_entry_count_for_term() $this->assertEquals(2, TermFacade::entriesCount($term)); } + #[Test] + public function it_gets_entry_count_for_term_filtered_by_status() + { + Taxonomy::make('test')->title('test')->save(); + + $term = tap(TermFacade::make('test-term')->taxonomy('test')->data([]))->save(); + + $collection = Collection::make('blog')->routes('blog/{slug}')->taxonomies(['test'])->save(); + + (new Entry)->id(1)->collection($collection)->data(['title' => 'Post 1', 'test' => ['test-term']])->slug('alfa')->published(true)->save(); + (new Entry)->id(2)->collection($collection)->data(['title' => 'Post 2', 'test' => ['test-term']])->slug('bravo')->published(false)->save(); + (new Entry)->id(3)->collection($collection)->data(['title' => 'Post 3', 'test' => ['test-term']])->slug('charlie')->published(false)->save(); + + $this->assertEquals(1, TermFacade::entriesCount($term, 'published')); + $this->assertEquals(2, TermFacade::entriesCount($term, 'draft')); + } + + #[Test] + public function it_gets_entry_count_for_term_scoped_to_collection() + { + Taxonomy::make('test')->title('test')->save(); + + $term = tap(TermFacade::make('test-term')->taxonomy('test')->data([]))->save(); + + $blog = Collection::make('blog')->routes('blog/{slug}')->taxonomies(['test'])->save(); + $news = Collection::make('news')->routes('news/{slug}')->taxonomies(['test'])->save(); + + (new Entry)->id(1)->collection($blog)->data(['title' => 'Blog 1', 'test' => ['test-term']])->slug('alfa')->save(); + (new Entry)->id(2)->collection($blog)->data(['title' => 'Blog 2', 'test' => ['test-term']])->slug('bravo')->save(); + (new Entry)->id(3)->collection($news)->data(['title' => 'News 1', 'test' => ['test-term']])->slug('charlie')->save(); + + $this->assertEquals(2, TermFacade::entriesCount(TermFacade::find('test::test-term')->collection($blog))); + $this->assertEquals(1, TermFacade::entriesCount(TermFacade::find('test::test-term')->collection($news))); + } + + #[Test] + public function it_gets_entry_count_for_term_filtered_by_site() + { + $this->setSites([ + 'en' => ['url' => '/', 'locale' => 'en_US', 'name' => 'English'], + 'fr' => ['url' => '/fr/', 'locale' => 'fr_FR', 'name' => 'French'], + ]); + + Taxonomy::make('test')->title('test')->sites(['en', 'fr'])->save(); + + $term = tap(TermFacade::make('test-term')->taxonomy('test')->data([]))->save(); + + $collection = Collection::make('blog')->routes('blog/{slug}')->taxonomies(['test'])->sites(['en', 'fr'])->save(); + + (new Entry)->id(1)->collection($collection)->locale('en')->data(['title' => 'Post 1', 'test' => ['test-term']])->slug('alfa')->save(); + (new Entry)->id(2)->collection($collection)->locale('en')->data(['title' => 'Post 2', 'test' => ['test-term']])->slug('bravo')->save(); + (new Entry)->id(3)->collection($collection)->locale('fr')->data(['title' => 'Post 3', 'test' => ['test-term']])->slug('charlie')->save(); + + $this->assertEquals(2, TermFacade::entriesCount($term->in('en'))); + $this->assertEquals(1, TermFacade::entriesCount($term->in('fr'))); + } + #[Test] public function it_build_stache_associations_when_taxonomy_driver_is_not_eloquent() { From 0f62e8165d7c02d634102bc2f88f939c9feeafc7 Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Thu, 12 Mar 2026 08:33:46 +0000 Subject: [PATCH 2/4] :beer: --- src/Taxonomies/TermRepository.php | 1 - tests/Terms/TermTest.php | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Taxonomies/TermRepository.php b/src/Taxonomies/TermRepository.php index 273efe16..118c17a4 100644 --- a/src/Taxonomies/TermRepository.php +++ b/src/Taxonomies/TermRepository.php @@ -3,7 +3,6 @@ namespace Statamic\Eloquent\Taxonomies; use Statamic\Contracts\Taxonomies\Term as TermContract; -use Statamic\Eloquent\Taxonomies\Term; use Statamic\Facades\Blink; use Statamic\Facades\Collection; use Statamic\Facades\Entry; diff --git a/tests/Terms/TermTest.php b/tests/Terms/TermTest.php index 8b48e3ea..f9737c15 100644 --- a/tests/Terms/TermTest.php +++ b/tests/Terms/TermTest.php @@ -15,7 +15,6 @@ use Statamic\Facades\Taxonomy as TaxonomyFacade; use Statamic\Facades\Term as TermFacade; use Statamic\Statamic; -use Statamic\Taxonomies\Term; use Statamic\Testing\Concerns\PreventsSavingStacheItemsToDisk; use Tests\TestCase; From 338aec05cf38ef5ed40e10389262fe3114cf1e4e Mon Sep 17 00:00:00 2001 From: Duncan McClean Date: Thu, 12 Mar 2026 10:19:02 +0000 Subject: [PATCH 3/4] Avoid constructing reference manually --- src/Taxonomies/TermRepository.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Taxonomies/TermRepository.php b/src/Taxonomies/TermRepository.php index 118c17a4..b8ad89e8 100644 --- a/src/Taxonomies/TermRepository.php +++ b/src/Taxonomies/TermRepository.php @@ -140,8 +140,7 @@ public function entriesCount(TermContract $term, ?string $status = null): int return parent::entriesCount($term, $status); } - $query = Entry::query() - ->whereTaxonomy($term->taxonomyHandle().'::'.$term->inDefaultLocale()->slug()); + $query = Entry::query()->whereTaxonomy($term->inDefaultLocale()->reference()); if ($term instanceof LocalizedTerm) { $query->where('site', $term->locale()); From 67caeac3eb010325179d1a922b8174e8d58867b0 Mon Sep 17 00:00:00 2001 From: Duncan McClean Date: Thu, 12 Mar 2026 10:20:35 +0000 Subject: [PATCH 4/4] Revert "Avoid constructing reference manually" This reverts commit 338aec05cf38ef5ed40e10389262fe3114cf1e4e. --- src/Taxonomies/TermRepository.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Taxonomies/TermRepository.php b/src/Taxonomies/TermRepository.php index b8ad89e8..118c17a4 100644 --- a/src/Taxonomies/TermRepository.php +++ b/src/Taxonomies/TermRepository.php @@ -140,7 +140,8 @@ public function entriesCount(TermContract $term, ?string $status = null): int return parent::entriesCount($term, $status); } - $query = Entry::query()->whereTaxonomy($term->inDefaultLocale()->reference()); + $query = Entry::query() + ->whereTaxonomy($term->taxonomyHandle().'::'.$term->inDefaultLocale()->slug()); if ($term instanceof LocalizedTerm) { $query->where('site', $term->locale());