We use cookies to make your viewing experience better. By accepting you consent, you agree to our Cookie policy
Efficiently retrieving entry counts is crucial for performant Craft CMS projects, yet it's easy to hurt site speed with unoptimized queries. This guide provides targeted solutions to count entries fast, from leveraging Twig and JavaScript to intelligently caching and eager loading. Follow our strategic counting techniques to keep your Craft site speedy even at scale. Dramatically boost performance by counting entries the right way.
Craft CMS offers several efficient methods to count entries, including count() for quick totals, looping to accumulate filtered counts, search() for customized criteria, outputting directly in Twig templates, and JavaScript for dynamic real-time updates. Carefully selecting the optimal technique improves performance.
Craft CMS offers several methods for efficiently retrieving entry counts, each with their own strengths depending on the specific use case. The count() function can quickly get a total count of entries in a section or across multiple sections. This works well when you need an overall count.
Looping through entries allows iterating over each one to accumulate a total count. This provides more flexibility to count entries matching certain criteria. The search() method also facilitates querying for filtered entry counts based on element criteria.
Outputting entry counts directly in templates is useful for displaying totals publicly. Twig's {% set %} tag can cache counts in variables for improved performance. For dynamic updating, JavaScript can fetch entry counts via AJAX requests.
Carefully selecting the optimal technique improves performance. Use count() and search() for simple overall counts. Opt for loops or JavaScript when needing filtered or frequently updated counts. Understanding the options helps choose the right approach.
Optimizing entry count queries offers significant performance and efficiency improvements for Craft CMS sites. By caching counts instead of running complex database queries, page load times are reduced.
Counting entries can easily trigger N+1 query issues, causing excessive database hits. Optimizing avoids these problems, limiting index rebuilds from inefficient queries. Intelligently caching totals also prevents unnecessary calls to regenerate counts.
The cumulative effect is markedly faster response times. Pages load quicker by minimizing expensive operations. The frontend feels more responsive, improving user experience. Optimized entry counts save server resources too.
For large entries, these optimizations become even more impactful. Craft CMS sites with hundreds or thousands of entries benefit immensely from proper count querying and caching. Just a few tweaks can translate to major speed boosts.
The count() function in Craft CMS offers a straightforward way to retrieve total entry counts. For example, Entry.count() gets the total count of all entries across all sections.
To count entries in a specific section:
{% set totalNews = craft.entries.section('news').count() %}
Filters can target counts even further:
{% set publishedNews = craft.entries.section('news').status('live').count() %}
count() works great for quick overall entry totals. The simple syntax and ease of use makes it ideal for basic count needs.
While convenient, using count() without optimizations can hurt performance in Craft CMS. Calling it repeatedly triggers excessive database queries, especially if using unfiltered queries on large entry sets.
Every count() call must scan all entries, becoming increasingly expensive at scale. Without caching or targeting filters, thousands of entries means thousands of database hits for every count.
Performance issues compound on pages with multiple count() calls. Slow load times result as the database struggles under the load. Proper indexing and caching becomes critical to optimize count().
The count() function works best for straightforward total counts directly in templates. A common use case is displaying a simple entry count publicly, like "5 blog posts found".
For more complex or dynamic counting needs, count() has limitations. Alternate options like looping may be better for filtered counts. Updating counts frequently via JavaScript is also easier with other techniques.
Overall count() is a good option when basic entry totals are sufficient. It's simple, fast, and avoids more complex logic when a quick total count is all that's needed. Just be mindful of performance, and optimize queries for large entry sets.
When looping through a large number of entries in Craft CMS, pagination is key for optimized performance. The .limit() and .offset() parameters on entry queries allow fetching a subset of entries per page.
For example:
{% set entries = craft.entries.section('blog').limit(10).offset(0) %}
This loads the first 10 entries, with .offset() specifying the starting point. Subsequent pages can increment the offset to lazy load the next set.
Paginating entries avoids loading hundreds or thousands of entries at once. By working in smaller batched sets, databases and servers aren't overwhelmed.
Looping through entries normally triggers a fresh database query for every iteration. Cache keys allow caching the looped entries to prevent excessive queries.
The cache key defines the criteria for cache invalidation. For example:
{% cache using key 'entries-blog-section' %}
{% for entry in entries %}
...
{% endfor %}
{% endcache %}
Now the looped entries are cached until any blog section entry changes. The cache key limits queries while keeping data fresh.
Careful cache invalidation is still needed to purge stale data. But cache keys effectively optimize entry loops and restrict queries.
Set limits on looped entry criteria to prevent runaway queries on uncontrolled sets
Avoid dynamic or frequently changing sort orders that prevent effective caching
Simplify entry criteria to allow more caching opportunities
Fetch only the data needed in each iteration instead of full entries
Use eager-loading for any relational data to avoid N+1 queries
Load assets simultaneously with entries to reduce separate queries
Consider caching at the template level to minimize duplicated effort
Optimized entry loops are vital for performant Craft CMS sites. A few key techniques go a long way to efficient iteration.
Craft's search feature allows retrieving targeted entry counts based on specific criteria. For example:
{% set newsCount = craft.entries()
.search('section:news status:live postDate:>='~now|date_modify('-1 month'))
.count() %}
This counts live news entries from the past month. Search enables flexible date, attribute, and relational filters for custom counts.
Multiple search parameters can be combined for very customized counts. Specific entry types, categories, authors, and more can be targeted.
When counting entries from search results, eager loading any relations optimizes performance. For example:
{% set entries = craft.entries()
.with(['author', 'categories'])
.search(query)
.count() %}
Eager loading avoids N+1 query issues that would hit the database for every entry's relations separately. A single optimized query retrieves the entries and related data.
For large result sets, the difference can be dramatic, from thousands of queries to just one. Always eager load for search counts.
Index search columns used for filters for faster search performance
Be as specific as possible with search criteria to allow better caching
Watch out for eagerness vs lazy loading based on context
Avoid search parameters that prevent caching like random ordering
Consider caching search results and then displaying counts
Too many search parameters can result in overly complex queries
Test searches at scale to identify expensive operations
Craft's search makes retrieving targeted entry counts easy. With proper optimization and indexing, it's a powerful tool for flexible and performant entry counting.
Twig makes it easy to output entry counts directly in Craft CMS templates. For example:
<p>{{ entryCount }}</p>
<p>Total entries: {{ entryQuery.total }}</p>
The entryCount variable contains the cached count, while entryQuery.total outputs the total right from the query.
Other examples include:
{% set entryCount = craft.entries.section('news').count() %}
{% set entries = craft.entries.section('news') %}
<p>{{ entries|length }}</p>
So assigning to variables, Twig filters like length, or query objects can all display counts.
Caching entry counts in Twig variables prevents repeated, expensive queries:
{% set entryCount = craft.entries.section('news').count() %}
Now entryCount is cached until the cache is cleared . No matter how many times it's output, the count is not re-queried.
This caching optimizes performance dramatically compared to calling .count() repeatedly. Variables also enable reusing the count efficiently.
Conditionals allow selectively outputting counts only when needed:
{% if entryCount %}
<p>There are {{ entryCount }} total entries<p>
{% endif %}
This avoids even caching or querying for a count if unused on a given page.
Similarly, switch tags can display different text based on the count. Counts can also be limited to specific templates where needed.
Outputting entry counts directly in templates provides tons of flexibility. With proper caching and conditionals, it's an optimized approach.
JavaScript enables retrieving entry counts from frontend controllers and API endpoints. For example:
fetch('/actions/entries/count')
.then(response => response.json())
.then(data => {
// Display count from data.count
});
The endpoint runs a query and returns the count as JSON. Axios, jQuery, or any HTTP client can call these endpoints.
This allows updating counts in real-time without full page loads. The frontend stays responsive and fast.
Caching entry counts in client storage avoids expensive API requests:
let count = localStorage.getItem('entryCount');
if (!count) {
// Fetch count via API
localStorage.setItem('entryCount', count);
}
Now the count is only fetched when undefined. Subsequent requests read from cache until invalidated.
This caching is crucial for performance. Without it, heavy API requesting degrades experience, especially on slower networks.
JavaScript counting shines for dynamic displays that update in real-time. As new entries are added, counts can increment automatically without refreshing.
It also prevents full page loads just to get updated counts. The API can be called in the background as needed.
JavaScript enables counting entries without hard page reloads. For frequently changing data, it's more performant and flexible.
Enabling caching and query caching dramatically improves entry count performance in Craft CMS.
Redis provides a fast cache backend to offload count caching from the database. Count queries hit Redis instead of running heavy database operations.
Database query caching caches the SQL queries and results. This prevents identical count queries from hitting the database at all.
Together, Redis and query caching deliver optimized performance by eliminating unnecessary queries. Entry counts come from fast in-memory caches.
Eager loading any relations avoids N+1 queries that can plague count performance:
{% set entries = craft.entries()
.with(['categories', 'author'])
.all() %}
{{ entries|length }}
This single queryeager loads the categories and authors with the entries. Without it, separate queries would be executed per entry relation.
For large entry sets, eager loading is critical to avoid thousands of extra queries. Always load related data upfront when counting.
Limit index rebuilds from unoptimized queries hammering the database
Simplify criteria to allow better caching opportunities
Use the optimize command to index columns used for filtering
Enable template level caching to prevent duplicated querying effort
Test any dynamic parameters for their performance impact
Minimize separate asset queries when eager loading entries
Set environment variables to cache counts in production environments
Keep an eye on slow database queries that point to count optimizations
Entry counting in Craft CMS offers many levers for performance. Fine-tuning caching, eager loading, indexing, and more results in lightning fast count queries.
Choosing the best entry counting technique depends on the specific use case and requirements:
count() - Simple overall counts displayed in templates
Loops - Filtered, complex, or frequently changing counts
Search - Targeted counts by custom criteria
Templates - Public display of entry counts
JavaScript - Dynamic updating of counts in real-time
count() is fastest for basic counts but inflexible. Loops offer more customization while search provides targeted filtering. Templates work well for display purposes while JavaScript enables live updating.
There are tradeoffs to each approach:
count() is very fast but less customizable
Loops are flexible but can hurt performance without optimization
Search enables advanced filtering at the cost of complexity
Templates simplify display but duplicate query logic
JavaScript adds dynamism but requires API and client-side work
Factor in performance needs, caching abilities, display requirements, and count complexity when deciding. Optimally combine techniques to leverage their strengths.
Use count() to show total blog posts in a sidebar widget
Leverage search to display entries from the past month
Loop through entries to filter and display authors' post counts
Update entry counts dynamically in real-time with JavaScript
Show paginated entry listings with total count in templates
The technique depends on the context. Evaluate the options against requirements to pick the best approach or combination of techniques.
Andy has scaled multiple businesses and is a big believer in Craft CMS as a tool that benefits both Designer, Developer and Client.