How to Add Wishlist in Laravel

In this section, we’ll see how to integrate a wishlist system into Laravel 9 using the Laravel Markable package. This package facilitates wishlist management, allowing users to create and edit their own wishlists.

Step 1: Install Laravel & Connect Database

Run below command to create laravel project.

composer create-project laravel/laravel laravel-wishlist

Now, you need to connect the Laravel app to the database. Open the .env configuration file and add the database credentials as suggested below.

.env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=database_name
DB_USERNAME=database_user_name
DB_PASSWORD=database_password

Step 2: Install Breeze

Install laravel breeze via composer:

composer require laravel/breeze --dev

Next, run below command.

php artisan breeze:install

And final install Dependencies.

npm install && npm run dev 
php artisan migrate

Step 3: Create Product Modal Migration Seeder and Controller

Run below command to create model, migration and controller.

php artisan make:model Product -mcr

create_products_table.php

public function up()
{
    Schema::create('products', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->double('price');
        $table->text('description');
        $table->string('image');
        $table->timestamps();
    });
}

app/Models/Product.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    use HasFactory;

    protected $fillable = [
        'name',
        'price',
        'image',
        'description',
    ];
}

Step 4: Create Product Seeder

php artisan make:seeder ProductSeeder

Now add dummy data in seeder.

database/seeders/ProductSeeder.php

<?php

namespace Database\Seeders;

use App\Models\Product;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;

class ProductSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $products = [
            [
                'name' => 'Fesh milk 250ml',
                'price' => 250,
                'description' => 'lorem ipsum',
                'image' => 'https://cdn.pixabay.com/photo/2016/12/06/18/27/milk-1887234__340.jpg'
            ],
            [
                'name' => '12 Egs',
                'price' => 6,
                'description' => 'lorem ipsum',
                'image' => 'https://cdn.pixabay.com/photo/2016/07/23/15/24/egg-1536990__340.jpg'
            ],
            [
                'name' => 'Wine 500ml',
                'price' => 50,
                'description' => 'lorem ipsum',
                'image' => 'https://cdn.pixabay.com/photo/2015/11/07/12/00/alcohol-1031713__340.png'
            ],
            [
                'name' => 'Homey 100ml',
                'price' => 12,
                'description' => 'lorem ipsum',
                'image' => 'https://cdn.pixabay.com/photo/2017/01/06/17/49/honey-1958464__340.jpg'
            ]
        ];
        Product::insert($products);
    }
}

database/seeders/DatabaseSeeder.php

<?php

namespace Database\Seeders;

// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call(ProductSeeder::class);

        // \App\Models\User::factory(10)->create();

        // \App\Models\User::factory()->create([
        //     'name' => 'Test User',
        //     'email' => '[email protected]',
        // ]);
    }
}

app/Http/Controllers/ProductController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Product;


class ProductController extends Controller
{
    public function productList()
    {
        $products = Product::all();

        return view('products', compact('products'));
    }
}

Step 5: Install & Setup Laravel Markable For Wishlist

You can install the package via composer:

composer require maize-tech/laravel-markable

publishes favorite migration.

php artisan vendor:publish --tag="markable-migration-favorite"

You can publish the config file with:

php artisan vendor:publish --tag="markable-config"

Migrate table with seeder.

php artisan migrate:fresh --seed

Step 6: Add Markable Favorite in Product Modal

app/Models/Product.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Maize\Markable\Markable;
use Maize\Markable\Models\Favorite;

class Product extends Model
{
    use HasFactory, Markable;

    protected $fillable = [
        'name',
        'price',
        'image',
        'description',
    ];

    protected static $marks = [
        Favorite::class,
    ];
}

Step 7: Create Wishlist Controller and Routes

Copy the following code below to create a wishlist controller.

php artisan make:controller WishlistController

To implement the functionality of adding and removing items to and from the wishlist in the Wishlist class, you can create the favoriteAdd and favoriteRemove methods. These methods will be responsible for managing the items in the wishlist.

app/Http/Controllers/WishlistController.php

<?php

namespace App\Http\Controllers;

use App\Models\Product;
use Maize\Markable\Models\Favorite;
use Illuminate\Http\Request;

class WishlistController extends Controller
{
    public function wishlist()
    {
        $products = Product::whereHasFavorite(
            auth()->user()
        )->get(); 
        // dd($products);
        return view('wishlist',compact('products'));
    }

    public function favoriteAdd($id)
    {
        $product = Product::find($id);
        $user = auth()->user();
        Favorite::add($product, $user);
        session()->flash('success', 'Product is Added to Favorite Successfully !');

        return redirect()->route('wishlist');
    }

    public function favoriteRemove($id)
    {
        $product = Product::find($id);
        $user = auth()->user();
        Favorite::remove($product, $user);
        session()->flash('success', 'Product is Remove to Favorite Successfully !');

        return redirect()->route('wishlist');
    }
}

Create routes.

<?php

use App\Http\Controllers\ProductController;
use App\Http\Controllers\WishlistController;
use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('welcome');
});


Route::get('products', [ProductController::class, 'productList'])->name('products.list');
Route::post('favorite-add/{id}', [WishlistController::class, 'favoriteAdd'])->name('favorite.add');
Route::delete('favorite-remove/{id}', [WishlistController::class, 'favoriteRemove'])->name('favorite.remove');


Route::get('wishlist', [WishlistController::class, 'wishlist'])->name('wishlist');

Route::get('/dashboard', function () {
    return view('dashboard');
})->middleware(['auth'])->name('dashboard');

require __DIR__.'/auth.php';

Step 8: Add Wishlist in Laravel Blade View Files

resources/views/products.blade.php

<x-app-layout>
    <x-slot name="header">
        <h2 class="text-xl font-semibold leading-tight text-gray-800">
            {{ __('Product List') }}
        </h2>
    </x-slot>
    <div class="container px-12 py-8 mx-auto">
        <h3 class="text-2xl font-bold text-purple-700">Our Product</h3>
        <div class="h-1 bg-red-500 w-36"></div>
        <div class="grid grid-cols-1 gap-6 mt-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
            @foreach ($products as $product)
            <div class="w-full max-w-sm mx-auto overflow-hidden bg-white rounded-md shadow-md">
                <img src="{{ url($product->image) }}" alt="" class="w-full max-h-60">
                <div class="flex items-end justify-end w-full bg-cover">

                </div>
                <div class="px-5 py-3">
                    <h3 class="text-gray-700 uppercase">{{ $product->name }}</h3>
                    <span class="mt-2 text-gray-500">${{ $product->price }}</span>
                    <form action="{{ route('favorite.add', $product->id) }}" method="POST"
                        enctype="multipart/form-data">
                        @csrf
                        <button class="p-2 bg-red-100 rounded hover:bg-red-600">
                            <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
                                stroke="currentColor" class="w-6 h-6 text-red-700 hover:text-red-100">
                                <path stroke-linecap="round" stroke-linejoin="round"
                                    d="M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12z" />
                            </svg>

                        </button>
                    </form>
                </div>

            </div>
            @endforeach
        </div>
    </div>
</x-app-layout>
product with wishlist icon

resources/views/wishlist.blade.php

<x-app-layout>
    <x-slot name="header">
        <h2 class="text-xl font-semibold leading-tight text-gray-800">
            {{ __('wishlist') }}
        </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 sm:rounded-lg">
                <div class="p-6 bg-white border-b border-gray-200">
                    Wishlist List
                    @if ($message = Session::get('success'))
                          <div class="p-4 mb-3 bg-green-400 rounded">
                              <p class="text-green-800">{{ $message }}</p>
                          </div>
                      @endif
                    <div class="flex flex-col">
                        <div class="overflow-x-auto">
                            <div class="p-1.5 w-full inline-block align-middle">
                                <div class="overflow-hidden border rounded-lg">
                                    <table class="min-w-full divide-y divide-gray-200">
                                        <thead class="bg-gray-50">
                                            <tr>
                                                <th
                                                    scope="col"
                                                    class="px-6 py-3 text-xs font-bold text-left text-gray-500 uppercase"
                                                >
                                                    ID
                                                </th>
                                                <th
                                                    scope="col"
                                                    class="px-6 py-3 text-xs font-bold text-left text-gray-500 uppercase"
                                                >
                                                   Product Name
                                                </th>
                                                <th
                                                    scope="col"
                                                    class="px-6 py-3 text-xs font-bold text-left text-gray-500 uppercase"
                                                >
                                                    Price
                                                </th>
                                                <th
                                                    scope="col"
                                                    class="px-6 py-3 text-xs font-bold text-left text-gray-500 uppercase"
                                                >
                                                    Image
                                                </th>
                                                <th
                                                    scope="col"
                                                    class="px-6 py-3 text-xs font-bold text-right text-gray-500 uppercase"
                                                >
                                                    Delete
                                                </th>
                                            </tr>
                                        </thead>
                                        <tbody class="divide-y divide-gray-200">
                                            @foreach ($products as $product)
                                                
                                            
                                            <tr>
                                                <td
                                                    class="px-6 py-4 text-sm font-medium text-gray-800 whitespace-nowrap"
                                                >
                                                    {{ $product->id }}
                                                </td>
                                                <td
                                                    class="px-6 py-4 text-sm text-gray-800 whitespace-nowrap"
                                                >
                                                {{ $product->name }}
                                                   
                                                </td>
                                                <td
                                                    class="px-6 py-4 text-sm text-gray-800 whitespace-nowrap"
                                                >
                                                {{ $product->price }}
                                                    
                                                </td>
                                                <td
                                                    class="px-6 py-4 text-sm text-gray-800 whitespace-nowrap"
                                                >
                                              <img src="{{ $product->image }}" alt="{{ $product->image }}" class="w-12 h-12">  
                                                    
                                                </td>
                                               
                                                <td
                                                    class="px-6 py-4 text-sm font-medium text-right whitespace-nowrap"
                                                >
                                                <form action="{{ route('favorite.remove',$product->id) }}" method="POST"
                                                    onsubmit="return confirm('{{ trans('are You Sure ? ') }}');"
                                                    style="display: inline-block;">
                                                    <input type="hidden" name="_method" value="DELETE">
                                                    <input type="hidden" name="_token" value="{{ csrf_token() }}">
                                                    <input type="submit" class="px-4 py-2 text-white bg-red-700 rounded"
                                                        value="Delete">
                                                </form>
                                                </td>
                                            </tr>
                                            @endforeach
                                        </tbody>
                                    </table>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>

                
            </div>
        </div>
    </div>
</x-app-layout>
add and remove wishlist

Step 9: Run Laravel and vite server

php artisan serve
# and 
npm run dev
saim ansari
saim ansari

I'm Saim Ansari, a full-stack developer with 4+ years of hands-on experience who thrives on building web applications that leave a lasting impression. When it comes to tech, I'm particularly adept at Laravel, React, Tailwind CSS, and the Tall Stack