PHPackages                             dive-be/laravel-wishlist - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. dive-be/laravel-wishlist

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

dive-be/laravel-wishlist
========================

Manage your users' wishes in a Laravel app

1.5.0(1y ago)712.7k↑25%2[1 issues](https://github.com/dive-be/laravel-wishlist/issues)MITPHPPHP ~8.4CI passing

Since Sep 2Pushed 1y agoCompare

[ Source](https://github.com/dive-be/laravel-wishlist)[ Packagist](https://packagist.org/packages/dive-be/laravel-wishlist)[ Docs](https://github.com/dive-be/laravel-wishlist)[ RSS](/packages/dive-be-laravel-wishlist/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (10)Dependencies (12)Versions (11)Used By (0)

❤️ - Manage your users' wishes in a Laravel app
===============================================

[](#️---manage-your-users-wishes-in-a-laravel-app)

[![Latest Version on Packagist](https://camo.githubusercontent.com/02e800c3036a1a723efa384739c8edd2d49040bfaffb3a2772e30565f73f4a47/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f646976652d62652f6c61726176656c2d776973686c6973742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/dive-be/laravel-wishlist)[![GitHub Tests Action Status](https://camo.githubusercontent.com/0866dc905ff2058e002fe146301b60da90d0442402f3ce3bdc3bbc98afad3ea6/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f776f726b666c6f772f7374617475732f646976652d62652f6c61726176656c2d776973686c6973742f54657374733f6c6162656c3d7465737473)](https://github.com/dive-be/laravel-wishlist/actions?query=workflow%3ATests+branch%3Amaster)[![Software License](https://camo.githubusercontent.com/55c0218c8f8009f06ad4ddae837ddd05301481fcf0dff8e0ed9dadda8780713e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)](LICENSE.md)[![Total Downloads](https://camo.githubusercontent.com/734d4cdd20341b06034db9929e7cceb220f11e7c6800182a30e9995db2b26b86/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f646976652d62652f6c61726176656c2d776973686c6973742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/dive-be/laravel-wishlist)

What problem does this package solve?
-------------------------------------

[](#what-problem-does-this-package-solve)

This package provides solutions to common problems when managing a user's wishlist. It also allows for seamless transitions between storage drivers depending on a user's authentication state.

Installation
------------

[](#installation)

You can install the package via composer:

```
composer require dive-be/laravel-wishlist
```

You can publish the config file and migrations with:

```
php artisan wishlist:install
```

This is the contents of the published config file:

```
return [

    /**
     * The authentication guard to use when using the `eloquent` or `upgrade` drivers.
     */
    'auth_guard' => config('auth.defaults.guard'),

    'cookie' => [

        /**
         * You may choose to scope the cookies to a particular subdomain.
         * Especially useful when serving multiple apps.
         * The default (no scoping) will suffice for most apps, though.
         */
        'domain' => env('WISHLIST_COOKIE_DOMAIN', env('SESSION_DOMAIN')),

        /**
         * Time-to-Live in minutes. Default 43200 (1 month).
         */
        'max_age' => env('WISHLIST_COOKIE_MAX_AGE', 43_200),

        /**
         * You may customize the name of the cookie. Completely optional.
         */
        'name' => env('WISHLIST_COOKIE_NAME', 'wishlist'),
    ],

    /**
     * Supported drivers:
     * - "array" (only available during the current request lifecycle)
     * - "cookie" (persists the user's wishes as a serialized string inside a cookie)
     * - "eloquent" (persists the users' wishes to the `wishes` table)
     * - "upgrade" (uses the cookie driver if a user is not authenticated, otherwise uses the eloquent driver)
     */
    'driver' => env('WISHLIST_DRIVER', Dive\Wishlist\WishlistManager::ELOQUENT),

    'eloquent' => [

        /**
         * The model that should be used with this driver.
         * It must be, or extend the base Wish model.
         */
        'model' => Dive\Wishlist\Models\Wish::class,

        /**
         * You may choose to provide a context for the saved wishes in the database.
         * Particularly useful when serving multiple apps. The default will suffice for most apps, though.
         */
        'scope' => 'default',

        /**
         * The user model of your application. For most apps, the default will suffice.
         * However, if you wish, you may customize that here. This is used for the Wish model's
         * user relationship so you can display the owner of the wish in e.g. Laravel Nova.
         */
        'user' => config('auth.providers.users.model'),
    ],
];
```

Usage
-----

[](#usage)

### Configuration

[](#configuration)

First things first, you should take a look at the published configuration file and adjust the values to your needs. If you need additional information about the available options, read on.

### Drivers

[](#drivers)

#### Array ⏳

[](#array-)

This driver is meant for use in testing. Its contents are ephemeral and should *not* be used in production.

See [Testing section](#testing-) below for additional information regarding unit tests.

#### Cookie 🍪

[](#cookie-)

The user's wishlist will be persisted client-side as a stringified JSON. You should make use of [Laravel's cookie encryption](https://laravel.com/docs/8.x/requests#retrieving-cookies-from-requests) (enabled by default) or any user will be able to crash your application (because there is no validation) when the cookie values are tampered with. The internal structure of your code base will be leaked partially as well if you do not make use of [relation morph maps](https://laravel.com/docs/8.x/eloquent-relationships#custom-polymorphic-types).

> Note: make sure the name of the cookie you wish to use (pun intended) is not excluded for encryption in the `\App\Http\Middleware\EncryptCookies::$excluded` array.

#### Eloquent 🧑‍🎨

[](#eloquent-‍)

The user's wishlist will be persisted server-side in the `wishes` table. You can only use this driver inside routes that are protected by the `auth` middleware as it requires an instance of an authenticated user.

> Note: do not forget to publish and run the migrations if you opt to use this driver.

#### Upgrade 🚀

[](#upgrade-)

**&gt; This &lt;** is the driver that makes this package shine.

- When a guest (an unauthenticated user) is browsing your app, the [Cookie driver](#cookie-) will be used to persist the wishlist.
- When the user is authenticated, the [Eloquent driver](#eloquent-) will be used.

🤌 Best of all? You don't have to change anything in your code.

But hold on, there is more! When the user logs in, the wishes can be carried over to the database automatically! 🙀 See [Migrating wishes section](#migrating-wishes-) below for additional information.

### Preparing Wishable models

[](#preparing-wishable-models)

Next, you must make the Eloquent models that can be wished for `Wishable` i.e. implement the contract and use the `CanBeWished` trait.

An example:

```
use Dive\Wishlist\Contracts\Wishable;
use Dive\Wishlist\Models\Concerns\CanBeWished;

class Product extends Model implements Wishable
{
    use CanBeWished;
}
```

### Preparing User model (optional)

[](#preparing-user-model-optional)

For convenience, this package also provides an `InteractsWithWishlist` trait which you can use in your `User` model to interact with the wishlist.

```
use Dive\Wishlist\Models\Concerns\InteractsWithWishlist;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use InteractsWithWishlist;
}
```

You can now do the following:

```
$user = auth()->user();

$user->wish(Product::first()); // adds the product to the wishlist
$user->unwish(Product::first()); // removes the product from the wishlist
$user->wishes(); // retrieves all of the user's wishes
```

### Resolving the wishlist

[](#resolving-the-wishlist)

This package provides every possible way to resolve a `Wishlist` instance out of the IoC container. We've got you covered!

#### Facade

[](#facade)

```
use Dive\Wishlist\Facades\Wishlist;

Wishlist::all();
```

or using the alias (particularly helpful in Blade views)

```
use Wishlist;

Wishlist::all();
```

#### Helper

[](#helper)

```
wishlist()->all();
```

#### Dependency injection

[](#dependency-injection)

```
use Dive\Wishlist\Contracts\Wishlist;

public function index(Wishlist $wishlist)
{
    return view('wishlist.index')->with('wishes', $wishlist->all());
}
```

#### Service Location

[](#service-location)

```
app('wishlist')->all();
```

Capabilities 💪
--------------

[](#capabilities-)

You can refer to the [Wishlist contract](src/Contracts/Wishlist.php) for an exhaustive list.

### Adding a wish

[](#adding-a-wish)

```
$wish = Wishlist::add($product);
```

You will receive an instance of [`Dive\Wishlist\Wish`](src/Wish.php).

### Retrieving all wishes

[](#retrieving-all-wishes)

```
$wishes = Wishlist::all();
```

You will receive an instance of [`Dive\Wishlist\WishCollection`](src/WishCollection.php). Refer to the class definition for all convenience methods.

### Finding a wish

[](#finding-a-wish)

```
$wish = Wishlist::find($product);
```

### Eager loading wish relations

[](#eager-loading-wish-relations)

When there is only a single type of `Wishable` (and you know for sure there won't be any other), you may omit the morph types entirely:

```
// ✅ Collection only contains Wishables of type "product"
$wishes = Wishlist::all()->load(['productable', 'variant']);
```

In other cases, you must provide a type-relation map:

```
$wishes = Wishlist::all()->load([
    Product::class => ['productable', 'variant'],
    Sample::class  => 'purveyor',
]); // ✅ Collection contains multiple wishables
```

A `LogicException` will be thrown in case of ambiguity:

```
// 🚫 Collection contains 2 types of Wishable: Product & Sample
$wishes = Wishlist::all()->load(['productable', 'variant']);
```

### Retrieving total count

[](#retrieving-total-count)

```
$count = Wishlist::count();
```

### Existence checks

[](#existence-checks)

```
$isWished = Wishlist::has($product);
```

### Emptiness checks

[](#emptiness-checks)

```
Wishlist::isEmpty();
Wishlist::isNotEmpty();
```

### Purging

[](#purging)

```
$amountOfWishesRemoved = Wishlist::purge();
```

### Wish removal

[](#wish-removal)

You can remove a wish either by its `id`

```
public function destroy(int $id)
{
    Wishlist::remove($id);
}
```

or by its underlying `Wishable`

```
public function destroy(Product $product)
{
    Wishlist::remove($product);
}
```

Migrating wishes 🚚
------------------

[](#migrating-wishes-)

While using the [Upgrade driver](#upgrade-), you may want to carry over the user's cookie wishlist to the database. This is not enabled by default, but you have 2 options to opt into this behavior:

### Event listener

[](#event-listener)

Listen to the `Login` event in `EventServiceProvider`:

```
class EventServiceProvider extends ServiceProvider
{
    protected $listen = [
        \Illuminate\Auth\Events\Login::class => [
            \Dive\Wishlist\Listeners\MigrateWishes::class,
        ],
    ];
}
```

### Middleware

[](#middleware)

Add the `MigrateWishes` middleware to your application's middleware stack:

```
class Kernel extends HttpKernel
{
    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Dive\Wishlist\Middleware\MigrateWishes::class, // 👈
            // omitted for brevity
        ],
    ];
}
```

> Note: make sure to place the middleware **after** `EncryptCookies`

Route model binding
-------------------

[](#route-model-binding)

Wouldn't it be nice to have a wish automatically resolved from a route parameter?

Well, say no more! 👇

```
use Dive\Wishlist\Wish;

Route::delete('wishlist/{wish}/delete', function (Wish $wish) {
    $wish->delete();

    return redirect()->to('dashboard');
});
```

- As this is **not** an Eloquent model, you can still use this syntax even if you only use the [Cookie driver](#cookie-)! 🎉
- Just like Eloquent models, a `ModelNotFoundException` will be thrown if the requested wish cannot be found.

> Note: you cannot make the `wish` parameter a child of a parent parameter because it does not make sense. An exception will be thrown if you attempt to do so.

Retrieving a particular user's wishlist 👱🏻‍♂️
---------------------------------------------

[](#retrieving-a-particular-users-wishlist-‍️)

You may want to modify a user's wishlist in e.g. an Artisan command where no auth context is available. For these cases, you can invoke the `forUser` method with a `User` instance to retrieve a wishlist scoped to that user:

```
class ClearWishlistCommand extends Command
{
    public function handle()
    {
        $user = User::first();

        Wishlist::forUser($user)->purge();
    }
```

> Note: this is only available for the [Eloquent driver](#eloquent-)

Extending the wishlist 👣
------------------------

[](#extending-the-wishlist-)

If the default drivers do not fulfill your needs, you may extend the `WishlistManager` with your own custom drivers:

```
Wishlist::extend('redis', function () {
    return new RedisWishlist();
});
```

Testing 🔎
---------

[](#testing-)

This package offers a fake implementation of the `Wishlist` contract so you can make assertions in your unit tests and make sure you ship that bug-free code 💪.

```
use App\Http\Livewire\HeartButton;
use Database\Factories\ProductFactory;
use Dive\Wishlist\Facades\Wishlist;
use function Pest\Livewire\livewire;

test('A wish is added when the visitor clicks on the heart icon', function () {
    Wishlist::fake();

    livewire(HeartButton::class)->call('wish', ProductFactory::new()->create()->getKey());

    expect(Wishlist::count())->toBe(1);
});
```

Testing (package)
-----------------

[](#testing-package)

```
composer test
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

Security
--------

[](#security)

If you discover any security related issues, please email  instead of using the issue tracker.

Credits
-------

[](#credits)

- [Muhammed Sari](https://github.com/mabdullahsari)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

45

—

FairBetter than 93% of packages

Maintenance46

Moderate activity, may be stable

Popularity32

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity74

Established project with proven stability

 Bus Factor1

Top contributor holds 93.3% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~149 days

Recently: every ~240 days

Total

10

Last Release

379d ago

Major Versions

0.2 → 1.02021-09-12

PHP version history (5 changes)0.1PHP ^8.0

1.2PHP ^8.1

1.3.0PHP ~8.2

1.4.0PHP ~8.3

1.5.0PHP ~8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/a265853c8db7c699f64f523ee782dc5ec095bfb456379222d1b0b97d90e4c735?d=identicon)[dive](/maintainers/dive)

---

Top Contributors

[![mabdullahsari](https://avatars.githubusercontent.com/u/24608797?v=4)](https://github.com/mabdullahsari "mabdullahsari (14 commits)")[![liepumartins](https://avatars.githubusercontent.com/u/2070205?v=4)](https://github.com/liepumartins "liepumartins (1 commits)")

---

Tags

wishlistFavoritesdivelaravel-wishlist

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/dive-be-laravel-wishlist/health.svg)

```
[![Health](https://phpackages.com/badges/dive-be-laravel-wishlist/health.svg)](https://phpackages.com/packages/dive-be-laravel-wishlist)
```

###  Alternatives

[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

245.2k](/packages/aedart-athenaeum)[laravel/passport

Laravel Passport provides OAuth2 server support to Laravel.

3.4k85.0M532](/packages/laravel-passport)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9682.1M97](/packages/roots-acorn)[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k12.1M99](/packages/laravel-pulse)[spatie/laravel-enum

Laravel Enum support

3655.4M31](/packages/spatie-laravel-enum)[psalm/plugin-laravel

Psalm plugin for Laravel

3274.9M308](/packages/psalm-plugin-laravel)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
