NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages
Reviews for Laravel

Querying reviews

List one subject’s reviews, or every review, through the facade — both respect a swapped reviews.model:

use RoundlyConsulting\Reviews\Facades\Reviews;

Reviews::for($restaurant)->query()->approved()->mostHelpful()->paginate();  // one subject, top-level only
Reviews::query()->pending()->latestFirst()->paginate();                     // every subject

Scopes

The Review model ships expressive scopes, and they chain on both facade queries. They live in the HasReviewScopes trait, so a custom review model keeps them:

use RoundlyConsulting\Reviews\Models\Review;

Review::query()->approved()->latestFirst()->get();
Review::query()->latestFirst()->get();            // newest approval first, never-approved last
Review::query()->pending()->get();
Review::query()->rejected()->get();
Review::query()->rated()->get();                  // has a rating
Review::query()->withRatingOf(5)->get();
Review::query()->minRating(4)->get();
Review::query()->authoredBy($user)->get();
Review::query()->for($restaurant)->get();
Review::query()->verified()->get();
Review::query()->unverified()->get();
Review::query()->topLevel()->get();               // excludes owner responses
Review::query()->responses()->get();              // only owner responses
Review::query()->mostHelpful()->get();            // by net helpful score
ScopeEffect
approved() / pending() / rejected()Filter by moderation status.
rated()Only reviews with a rating.
withRatingOf(int $rating)Exact rating.
minRating(int $rating)Rating greater than or equal to the value.
authoredBy(Model $author)Written by one author.
for(Model $reviewable)About one subject.
verified() / unverified()Filter by the verified flag.
topLevel() / responses()Exclude, or return only, owner responses.
latestFirst()Newest approval first — never-approved reviews last on every engine — then by created_at.
mostHelpful()Order by helpful_count − unhelpful_count, then newest.

Composing scopes

Scopes chain on the HasReviews relations as well as on Review::query():

// A product page: verified 4–5 star reviews, most helpful first, with replies.
$reviews = $restaurant->approvedReviews()
    ->verified()
    ->minRating(4)
    ->mostHelpful()
    ->with('responses')
    ->paginate(10);

Authoring lookups

CanReview answers “has this user reviewed this?” without writing a query:

$user->reviewsAuthored;               // MorphMany (reviews and owner responses)
$user->hasReviewed($restaurant);      // bool
$user->reviewFor($restaurant);        // ?Review

Both lookups consider every non-deleted review the model authored for that subject, whatever its status — but reviews only: an owner response the user wrote on the subject doesn’t count as having reviewed it, and doesn’t trip one_per_author either. The reviewsAuthored relation itself covers reviews and owner responses.

Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

More ways to support, including crypto

By donating, you agree to our donation terms.

Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.