nelson-nguyen / craft-store-view
Craft CMS Track total/day/week/month views per element.
Installs: 2
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
Type:craft-plugin
pkg:composer/nelson-nguyen/craft-store-view
Requires
- php: >=8.0
- craftcms/cms: ^5.0 || ^4.3.5
- jaybizzle/crawler-detect: ^1.3
Requires (Dev)
- craftcms/ecs: dev-main
- craftcms/phpstan: dev-main
README
Track total, daily, weekly, and monthly views for entries, categories, tags, and custom routes. Fully supports multi-site setups, Blitz static caching, and works with Craft CMS 4 and 5.
โจ Main Features
- Track views of Entries, Categories, Tags, and custom routes
- Multi-site support
- View counting via AJAX/fetch for Blitz/static cache compatibility
- Compatible with Craft CMS 4 and 5
๐ Installation
Install via the Craft Plugin Store or with Composer:
composer require nelson-nguyen/craft-store-view
Search for "Store View" in the Craft Plugin Store and install from the Control Panel.
๐งน Reset Views Command
To clear all stored view counts (total, daily, weekly, monthly), run the following console command manually:
./craft store-view/reset-view
โฐ Automate with Cron Job
You can schedule this command to run automatically every day at midnight using cron.
- Open your server's crontab editor:
crontab -e
- Add this line to run the reset command daily at midnight:
0 0 * * * /path/to/craft store-view/reset-view >/dev/null 2>&1
Make sure to replace /path/to/craft with the full path to your Craft CMS craft executable.
- Save and exit the editor.
This will reset your view counts daily at 00:00 server time.
๐ข Count Views
Manually trigger a view count for any supported element or custom URI:
{# Entry #} {% do craft.storeView.count(entry.id) %} {# Category #} {% do craft.storeView.count(category.id) %} {# Tag #} {% do craft.storeView.count(tag.id) %} {# Custom route (e.g., static page) #} {% do craft.storeView.count(craft.app.request.getPathInfo()) %}
๐ AJAX View Tracking (For Blitz/Static Cache Support)
Use the following code to send an AJAX request that registers a view:
{% js %}
fetch('/store-view/api/track-page-view' + window.location.search, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-CSRF-Token': '{{ craft.app.request.csrfToken }}'
},
body: JSON.stringify({
elementId: {{ entry.id ?? 'null' }},
siteId: {{ currentSite.id ?? 'null' }},
uri: window.location.pathname
}),
});
{% endjs %}
๐ Querying Store Views
Use craft.storeView.entries() to retrieve and filter view statistics with a fluent API.
๐ง Basic Usage
{% set views = craft.storeView.entries().all() %}
๐ Filter by Section
{% set blogViews = craft.storeView.entries().sections('blog').all() %}
Multiple sections:
{% set views = craft.storeView.entries().sections(['blog', 'news']).all() %}
๐ Filter by Category Group
{% set views = craft.storeView.entries().categories('topics').all() %}
๐ Filter by Tag Group
{% set views = craft.storeView.entries().tags('labels').all() %}
๐ Filter by Date Range
{% set todayViews = craft.storeView.entries().withRange('today').all() %}
{% set thisWeekViews = craft.storeView.entries().withRange('thisWeek').all() %}
{% set thisMonthViews = craft.storeView.entries().withRange('thisMonth').all() %}
๐ Custom Filters
{% set views = craft.storeView.entries()
.where({ elementId: 123 })
.limit(10)
.offset(5)
.orderBy('total DESC')
.all() %}
๐ Get One Record
{% set view = craft.storeView.entries().where({ elementId: 123 }).one() %}
๐ข Count Total
{% set count = craft.storeView.entries().sections('blog').count() %}
๐งฑ Data Structure
Each result is an instance of nelsonnguyen\craftstoreview\models\StoreViewModel.
Example Output:
nelsonnguyen\craftstoreview\models\StoreViewModel { id: 1, uri: "custom/custom", elementId: null, siteId: 1, total: 2, day: 2, week: 2, month: 2, lastUpdated: DateTimeImmutable('2025-06-08 07:10:33.0 UTC'), element: null, }
Or with populated element:
nelsonnguyen\craftstoreview\models\StoreViewModel { id: 1, uri: "custom/custom", elementId: null, siteId: 1, total: 2, day: 2, week: 2, month: 2, lastUpdated: DateTimeImmutable('2025-06-08 07:10:33.0 UTC'), element: { id: 2, title: "test channel", slug: "test-channel", uri: "channel/test-channel", type: "Entry" } }
๐ Notes
.sections(),.categories(), and.tags()accept a string or array of handles..withRange()accepts:'today','thisWeek','thisMonth'- All methods are chainable.
๐ License
This is a commercial plugin available via the Craft CMS Plugin Store.