knplabs/knp-disqus-bundle
Symfony bundle for adding Disqus comments to your application. It handles Disqus configuration and provides Twig helpers to render comment threads, so you can embed community discussions with minimal boilerplate. Ideal for Symfony sites already using Disqus.
Install and register. composer require knplabs/knp-disqus-bundle (the Disqus PHP client is pulled in transitively), then add Knp\Bundle\DisqusBundle\KnpDisqusBundle to config/bundles.php. As of v4.1.0 the package's composer.json finally allows PHP 8, so a plain install works on a modern PHP runtime — but note the release was a constraint bump only (no feature or bug-fix work), and the Symfony constraint was not widened. Run composer why-not knplabs/knp-disqus-bundle before committing if you're on Symfony 6+, and expect to tune or override if it complains.
Get credentials. Create an API application at disqus.com/api/applications to obtain a public API key (the secret is only needed for OAuth; you do not need it for read-only comment fetching). Note your forum shortname (the *.disqus.com subdomain).
Configure.
# config/packages/knp_disqus.yaml
knp_disqus:
api_key: '%env(DISQUS_API_KEY)%'
forum: 'my_blog' # default forum shortname
# cache: cache.app # optional cache pool/service
# forums: { ... } # named forums if you run more than one
Put DISQUS_API_KEY in .env.local / your secret store.
First use case. Render a blog post's comment thread server-side so crawlers see real markup instead of the empty <div> that the Disqus JavaScript embed leaves behind:
{{ knp_disqus_render('my_blog', 'post-' ~ post.id, {'limit': 25, 'order': 'asc'}) }}
Where to look first. The bundle's DependencyInjection/Configuration.php (every option and its default), its Twig extension (the exact function signature and supported options), and Resources/views/ (the default templates you'll override). The README is short and mostly mirrors these.
Use a stable thread identifier, not the URL. Disqus keys threads by ident and link; if you pass the URL, changing your route/slug orphans the thread. Always pass post-{id} (or another immutable key) as the identifier and let Disqus store the link separately.
Two rendering paths, pick per page:
knp_disqus_render(forum, thread, options) fetches and renders the default comment template. Override the template in your app (standard bundle override path, e.g. templates/bundles/KnpDisqusBundle/...) to match your design.->fetch($forum, $thread, ['limit' => ..., 'order' => ...]). You get back a thread object with comments you can iterate, which is what you want if you need extra data on the page.Drive more than comments from the same fetch. Build JSON-LD (DiscussionForumPosting / Comment nodes), comment counts for index pages, or a "latest comments" sidebar from the same thread object. Doing this in one controller action avoids double API hits.
Paginate with limit + offset. Disqus caps a single request (100), so for long threads either page explicitly or fetch the first N for the page view and lazy-load the rest via the JS embed.
Cache aggressively, and warm it. Every page view that calls the Disqus API costs latency and quota. Point the bundle at a Symfony cache pool and set a TTL of a few minutes to an hour depending on traffic. For high-traffic articles, add a small console command or console-scheduled job that calls the same service to refresh the cache off the request path.
Coexist with the JS embed deliberately. Typical setup: render the fetched comments server-side inside the disqus_thread container, then include the standard Disqus embed script so live users get real-time behavior. Decide up front whether you're doing "SEO-only static render" or "hydrated embed" — mixing both without thinking leaves you with duplicated comment markup.
Testing. In test env, disable/bypass the bundle cache and either mock the Disqus service or point it at a stub; treat "thread doesn't exist yet" as a fixture case rather than an exception. Keep API keys out of test fixtures.
Multiple forums. The forums map lets you target different shortnames from different areas (e.g., docs vs. blog) while keeping one default.
composer.json. Skim the code you depend on (the Twig extension and API wrapper) for anything passing null to non-nullable internal functions or other deprecation-triggering patterns, and run your test suite with deprecations surfaced before you rely on it.parent reference; the bundle won't rebuild a nested tree for you. If you want threaded display, group by parent yourself before rendering.|raw.knp_disqus_render in a loop is an easy way to blow your API quota.How can I help you explore Laravel packages today?