Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Disqus Laravel Package

yajra/laravel-disqus

A Laravel integration for the Disqus commenting platform. It provides a service provider, facade, and configuration to authenticate with the Disqus API, plus a fluent client for retrieving threads, posts, forums, and other comment data, making it simple to embed and manage Disqus comments in Laravel...

View on GitHub
Deep Wiki
Context7

Getting Started

Install and publish:

composer require yajra/laravel-disqus
php artisan vendor:publish --provider="Yajra\Disqus\DisqusServiceProvider"

Service provider is auto-discovered — no config/app.php edit needed on modern Laravel. That gives you config/disqus.php, which is a small file containing your Disqus shortname. Drive it from the environment:

DISQUS_SHORTNAME=your-shortname

If the published config doesn't already read env('DISQUS_SHORTNAME'), add it — every environment should point at its own Disqus site so QA and staging can exercise real threads without polluting production discussions.

Read the source before you trust it. The package is roughly 100–200 lines under vendor/yajra/laravel-disqus/src. Open, in this order: config/disqus.php, the service provider (to see what the facade binds to), and the Blade directive / helper source. You specifically need to answer two questions: which script snippet it emits, and which variable it keys the thread on (disqus_identifier vs. page URL). This is a five-minute read and the single best defense against surprises later. The API surface has drifted between versions — don't assume the README matches what you installed.

First use case: comments on a blog post show page. The canonical pattern is a #disqus_thread container plus an identifier:

{{-- resources/views/posts/show.blade.php --}}
<article>{!! $post->body !!}</article>

@if(config('disqus.shortname'))
    <div id="disqus_thread"></div>
    @disqus('post-'.$post->id, $post->title)
@endif

Load the page and confirm in DevTools → Network that disqus.com/embed.js actually fires and returns 200. If it doesn't, your CSP or an ad blocker is the first suspect — not the package. Get exactly one page working on staging before you generalize.

Implementation Patterns

Wrap the vendor call in one Blade component. Do not scatter @disqus / Disqus::render() across templates. A single component is the one place you change when the embed script, identifier convention, or vendor shifts:

// app/View/Components/Comments.php
class Comments extends Component
{
    public function __construct(
        public Model $model,
        public string $identifier,
        public ?string $title = null,
    ) {}

    public function render() { return view('components.comments'); }
}
{{-- resources/views/components/comments.blade.php --}}
@props(['model', 'identifier', 'title' => null])
<div id="disqus_thread" class="mt-12"></div>
@disqus($identifier, $title ?? $model->title ?? '')

Then <x-comments :model="$post" :identifier="'post-'.$post->id" /> everywhere a thread is needed. Views never touch the vendor package directly, and your fallback (a plain Blade partial with the embed script) is a one-file swap.

Freeze the identifier scheme in code. Disqus keys a thread off disqus_identifier and falls back to the URL. Use a stable, immutable value — 'post-'.$post->id, never the slug or the title. A trait keeps this honest across models:

trait HasDisqusThread
{
    public function disqusIdentifier(): string
    {
        return sprintf('%s-%s', class_basename($this), $this->getKey());
    }
}

Changing this convention on a live page forks the discussion and starts a fresh thread with zero comments, with no way to merge from the app side. Document the rule in the trait's docblock — this is the one piece of institutional knowledge future engineers will violate.

Environment-driven shortnames per deploy target. Staging and QA should hit separate Disqus sites:

# .env.staging
DISQUS_SHORTNAME=myapp-staging

Wire your CI deploy to set this per environment. Maintaining the separate Disqus sites is on you, not the package.

Feature-flag the rollout. Comments are a secondary surface and the vendor relationship may not survive contact with legal. Gate them:

// config/features.php
'comments' => env('FEATURE_COMMENTS', false),

Render an empty view from the component when disabled. Rolling back becomes one env change, not a code revert.

Conditional render at the call site — hide comments on drafts, previews, or non-published content:

@if($post->is_published && feature('comments'))
    <x-comments :model="$post" :identifier="$post->disqusIdentifier()" />
@endif

Server-side comment counts (only if your installed version exposes an API client). Some versions ship a Disqus client that can hit disqus.com/api/3.0/threads. Verify in the source before relying on it. If it exists, wrap it in a cached service — never call it per row in a listing:

Cache::remember("disqus.count.{$id}", now()->addMinutes(15),
    fn () => Disqus::threads()->details($identifier)->posts ?? 0
);

If your version doesn't expose it, drop the idea. The embed snippet is not a data source, and scraping the iframe is not a strategy.

SPA / Livewire / Turbo. The embed initializes on page load only. On client-side route change you must reset it yourself:

DISQUS.reset({
  reload: true,
  config: function () {
    this.page.identifier = identifier;
    this.page.url = url;
  }
});

Call it from your router hook or Livewire navigate/component hook. The package does not do this for you.

Gotchas and Tips

CSP silently eats the embed. The snippet injects disqus.com, its CDN, and ad domains. Without explicit allowances you get a blank #disqus_thread and a console error that looks nothing like a package problem:

script-src  'self' https://*.disqus.com https://*.disquscdn.com;
frame-src   https://disqus.com;
connect-src https://*.disqus.com https://*.disquscdn.com;

Test against your production header policy, not a lax dev one — dev is usually the only place it accidentally works.

Ad blockers and privacy extensions suppress it for a meaningful share of readers — no error, no log, just an empty box. Give the container a graceful "comments unavailable" fallback rather than a gap that reads as a broken page.

Shortname mismatches are the top silent failure. An .env value that doesn't correspond to a real Disqus site loads the script and then simply sits there. Verify against the Disqus admin panel; "the page looks fine" proves nothing.

Thread identifier drift forks discussions. Switching disqus_identifier from an ID to a slug (or vice versa) on a live page starts a fresh thread with zero comments. This is the most common and least reversible failure mode. Pin it in a trait, document it, and add a test asserting the identifier format for each model that exposes one.

Maintenance signal is weak (84 stars, 0 dependents). Pin the version ("yajra/laravel-disqus": "^x.y"), read the source, and be ready to fork or replace with a ten-line Blade partial at the next Laravel major. The surface is tiny so the swap is hours of work — but you have to schedule it, not discover it mid-upgrade. Verify Laravel/PHP compatibility on a throwaway branch before committing.

The package does not do moderation, SSO, or data export. Those are Disqus-side concerns and product/legal decisions. Don't expect the facade to abstract them. If you need per-tenant shortnames, first-party comment data, or a queryable comment table, this is the wrong tool — and Disqus import is one-way and lossy, so leaving later is a migration project.

SEO upside is unproven. Disqus renders client-side and indexation of comment text is inconsistent across crawlers. Don't justify adoption on SEO — measure it on a real page in Search Console if you care.

Extension points are thin by design. No repository interface, no comment model, no event hooks. If you need behavior beyond "emit the snippet with an identifier," fork the package or bypass it with your own Blade partial. Both are cheap, and the partial is often the more maintainable answer — it removes a dependency and costs you the facade's one-line convenience.

Debugging checklist when the box is blank: (1) Is embed.js in the Network tab at all? Not present → CSP or blocker. (2) Present but 200 with nothing rendered → wrong shortname. (3) Rendered but zero comments → identifier changed or URL fallback kicked in. That ordering resolves most reports in under a minute.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log
hsluv/hsluv
seampact/codegen
seampact/hooks
seampact/ir
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk