In this tutorial, we will use Livewire to create a component for Like/Dislike, similar to YouTube or any social network. We will show the count of likes and dislikes, also minimizing the number of queries to the DB.

Laravel Project Preparation
We'll show the list of posts and the number of votes for every post.
For this demo, we'll use our own Laravel Breeze Pages Skeleton which will give use Breeze-like layout but with a public page for posts list.
First, we need a Post Model, Controller, and View. For now, without any Livewire.
php artisan make:model Post -mc
database/migrations/xxxx_create_posts_table.php:
return new class extends Migration { public function up(): void { Schema::create('posts', function (Blueprint $table) { $table->id(); $table->string('title'); $table->text('text'); $table->timestamps(); }); }};
app/Models/Post.php:
class Post extends Model{ protected $fillable = [ 'title', 'text', ];}
app/Http/Controllers/PostController.php:
class PostController extends Controller{ public function __invoke(): View { $posts = Post::latest()->paginate(); return view('posts', compact('posts')); }}
And a simple Blade file to show the list of the posts.
resources/views/posts.blade.php:
<x-app-layout> <x-slot name="header"> <h2 class="text-xl font-semibold leading-tight text-gray-800 dark:text-gray-200"> {{ __('Posts') }} </h2> </x-slot> <div class="py-12"> <div class="mx-auto max-w-7xl sm:px-6 lg:px-8"> <div class="overflow-hidden bg-white shadow-sm dark:bg-gray-800 sm:rounded-lg"> <div class="p-6 text-gray-900 dark:text-gray-100"> @foreach($posts as $post) <h3 class="text-xl font-medium">{{ $post->title }}</h3> <p>{{ $post->text }}</p> <hr class="my-4"> @endforeach {{ $posts->links() }} </div> </div> </div> </div></x-app-layout>

Next, we need to save votes. For this, we will create a Vote Model.
php artisan make:model Vote -m
database/migrations/xxxx_create_votes_table.php:
return new class extends Migration { public function up(): void { Schema::create('votes', function (Blueprint $table) { $table->id(); $table->foreignId('post_id')->constrained()->cascadeOnDelete(); $table->foreignId('user_id')->constrained()->cascadeOnDelete(); $table->smallInteger('vote'); $table->timestamps(); }); }};
app/Models/Vote.php:
class Vote extends Model{ protected $fillable = [ 'post_id', 'user_id', 'vote', ];}
Now let's add Vote relations to the Post Model.
app/Models/Post.php:
use Illuminate\Database\Eloquent\Relations\HasOne;use Illuminate\Database\Eloquent\Relations\HasMany; class Post extends Model{ protected $fillable = [ 'title', 'text', ]; public function votes(): HasMany { return $this->hasMany(Vote::class); } public function userVotes(): HasOne { return $this->votes()->one()->where('user_id', auth()->id()); } }
We'll need two relations. The first one is just a regular One To Many relation which we will use to create and update the vote for the post.
The second one is more interesting: the userVotes relation will return null if a user hasn't voted yet. Otherwise, it will return the Vote model from which we will be able to tell if a user liked or disliked a post.
Livewire Component
Now let's create a Livewire component.
php artisan make:livewire LikeDislike
First, let's add the Livewire component after the post text and...
Premium Members Only
This advanced tutorial is available exclusively to Laravel Daily Premium members.
Already a member? Login here
Premium membership includes:
A quick question:
First, I'll like to say thanks a lot for this free weekend. This particular feature caught my interest and I tried implementing it on my application but I'm crrently having this error:
Call to undefined relationship [userVotes] on model [App\Models\Post].
on the error page this particular controller instance was highlighted.
The error "Call to undefined relationship [userVotes] on model [App\Models\Post]." means that you literally don't have that method in the Model class. Maybe you named it somehow differently? Could you put your code and GitHub and I would debug for you?
Thank you very much for your reply. I have sent an email with the link to the project on GitHub.
Thanks again.