fof/discussion-views
Adds view counters to Flarum discussions, tracking how many times each thread is viewed and displaying the count in discussion lists and on the discussion page. Helps community admins gauge interest and surface popular topics. Simple to install and configure.
Install it like any Flarum extension, then enable it — nothing works until you flip the switch in the admin panel:
composer require fof/discussion-views
php flarum migrate
php flarum cache:clear
Then go to Admin → Extensions → Discussion Views and enable it. The composer step only drops files on disk; Flarum's extension manager is what registers the service provider, migrations, and frontend assets.
Where to look first:
extend.php — the whole extension is wired here. You'll see the Extend\Routes, Api\Resource, and Frontend registrations. This tells you exactly which routes and serializers are in play.migrations/ — expect a discussion_views table (likely discussion_id, user_id, ip_address, viewed_at) and possibly an added view_count column on discussions.src/ — a listener or middleware that records a view when a discussion is fetched, plus a DiscussionResource field for output.js/src/forum/ — where the view count is rendered (typically a ViewCount component injected into the discussion list item and the discussion hero).First realistic use case: you want "1.2k views" next to each discussion in the index and under the title on the discussion page, primarily as a social-proof signal. Enable the extension, visit a discussion, refresh the list — if the number appears and increments, the pipeline works end to end. If not, check whether the frontend asset was rebuilt (php flarum cache:clear plus clearing storage/ browser cache) before assuming the backend is broken.
Reading counts from the API. The extension almost certainly exposes the count as a discussion attribute. Consume it from your own tooling rather than scraping:
// In a custom endpoint or scheduled command
$discussions = Discussion::with('mostRecentPost')->limit(20)->get();
foreach ($discussions as $d) {
// attribute name varies — inspect DiscussionResource first
echo $d->view_count;
}
If you're building a widget, alias it deliberately (viewCount in the serializer, view_count on the model) so you're not chasing naming drift across versions.
Filtering and sorting by popularity. The killer day-to-day use is "most viewed this week." Push this to the database, not PHP:
Discussion::where('is_private', false)
->where('last_posted_at', '>=', now()->subWeek())
->orderByDesc('view_count')
->limit(10)
->get();
If the count only lives in the discussion_views pivot, use a withCount('views')->orderByDesc('views_count') instead — but verify which storage strategy the extension actually uses before writing the query, because the two perform very differently at scale.
Recording views from custom frontends. If you have a mobile app or a headless client hitting the API, you need to replicate whatever the frontend does to trigger a count — either a POST /api/discussions/{id}/view style route or the GET itself has a side effect. Test with curl against the JSON API and watch the count move; if a plain GET counts, be aware that every integration poll inflates the number.
Theming the display. The JS bundle exposes a component. Override it in a custom theme rather than editing vendor files:
// js/src/forum/index.js of your own extension
import { extend } from 'flarum/common/extend';
import DiscussionListItem from 'flarum/forum/components/DiscussionListItem';
// append your own view-count markup
Integrating with analytics. Don't try to replace the extension's counter with Google Analytics — they will disagree (bots, cached pages, API clients). Instead, use the extension's number as the user-visible metric and treat GA as directional, or periodically reconcile by exporting the discussion_views table and comparing against access logs.
user_id). Guest dedup requires IP + session + time window, and all three are imperfect behind proxies. If you see the count jump by 5 when you refresh once, dedup is either off, or it's keyed on something that changes per request.view_count is denormalized. If it's a column on discussions, list queries are cheap and ordering is trivial. If it's computed via withCount, every discussion-list request pays a join. For a 1-star, early-life package, assume the simpler design and verify — this assumption determines whether you can safely order by views on the index page.php flarum cache:clear. Symptoms of stale cache: the count renders on the discussion page but not in the list, or the old count persists after a migrate.is_private and tag visibility; if you're exposing counts through your own endpoint, replicate the ScopeVisibility logic Flarum uses on discussions or you'll create an information-disclosure bug.Extend\Middleware wrapper around the route or a where clause injection via a small companion extension — not patching vendor code, which breaks on the next composer update.composer.json and read the release diff before upgrading. You are effectively the QA team.php flarum migrate run? → cache cleared? → asset rebuild needed (dev mode vs. production js/dist)? → does the request actually reach the middleware (log it)? That order catches most issues in under five minutes.How can I help you explore Laravel packages today?