PHPackages                             wsmallnews/preference - 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. wsmallnews/preference

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

wsmallnews/preference
=====================

Wsmallnews system preference modules

v1.0.2(1mo ago)162MITPHP ^8.2

Since Apr 29Compare

[ Source](https://github.com/Wsmallnews/preference)[ Packagist](https://packagist.org/packages/wsmallnews/preference)[ Docs](https://github.com/wsmallnews/preference)[ GitHub Sponsors](https://github.com/Wsmallnews)[ RSS](/packages/wsmallnews-preference/feed)WikiDiscussions Synced 3w ago

READMEChangelog (3)Dependencies (26)Versions (5)Used By (2)

Preference
==========

[](#preference)

[![Latest Version on Packagist](https://camo.githubusercontent.com/f44756e2764bb795ebcf37a03b91e50b349583569f5d62b226d6a174e9f2eb93/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f77736d616c6c6e6577732f707265666572656e63652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/wsmallnews/preference)[![GitHub Tests Action Status](https://camo.githubusercontent.com/d7ba5a7ea17d9ae430700246636709df45f8242e2b4bfad93fb59c287e05da54/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f77736d616c6c6e6577732f707265666572656e63652f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/wsmallnews/preference/actions?query=workflow%3Arun-tests+branch%3Amain)[![GitHub Code Style Action Status](https://camo.githubusercontent.com/74b8e3bdc47a8aded95f1a694d5e72c56ff940574d6933a47a75a6cb3ecf7b4a/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f77736d616c6c6e6577732f707265666572656e63652f6669782d7068702d636f64652d7374796c652d6973737565732e796d6c3f6272616e63683d6d61696e266c6162656c3d636f64652532307374796c65267374796c653d666c61742d737175617265)](https://github.com/wsmallnews/preference/actions?query=workflow%3A%22Fix+PHP+code+style+issues%22+branch%3Amain)[![Total Downloads](https://camo.githubusercontent.com/e945aa64fb73fcc70973a55302f4229c33fbc9711ba0674e79686cf8bbfaa87c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f77736d616c6c6e6577732f707265666572656e63652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/wsmallnews/preference)

Wsmallnews Universal Preference Record System, built on Laravel + Filament. Supports unified recording and management of preference behaviors such as likes, follows, and views. Designed with polymorphic relationships, any Eloquent model can be integrated.

Overview
--------

[](#overview)

- **Like**: Full-featured like/unlike/toggle like, with automatic counter maintenance
- **Follow**: Follow/unfollow/toggle follow, supports mutual follow detection, with automatic bidirectional counter maintenance
- **View**: View recording/counting, supports anonymous user statistics without authentication
- **Polymorphic Design**: Any model can be a preference subject (Preferenceable) or preference operator (Preferencer)
- **Scope Isolation**: Multi-scope data isolation via scope\_type + scope\_id
- **Multi-Tenancy Support**: Automatic team\_id association
- **Batch Status Attachment**: Efficiently attach like/follow/view statuses to collections or paginated data (avoids N+1 queries)
- **Counter Integration**: Supports automatic increment/decrement of JSON `counter` field
- **Mutual Follow Support**: Built-in mutual follow detection and `followed_at` timestamp recording in Follow system

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

[](#installation)

You can install the package via composer:

```
composer require wsmallnews/preference:^1.0
```

Installing this package will publish the configuration files and migration files of both the third-party dependency package and the current package:

```
php artisan sn-preference:install
```

You can publish only the config file individually:

```
php artisan vendor:publish --tag="sn-preference-config"
```

Publish and run only the migrations individually:

```
php artisan vendor:publish --tag="sn-preference-migrations"
```

Multi language support, you can publish the language files using:

```
php artisan vendor:publish --tag="sn-preference-translations"
```

Publish the views (optional):

```
php artisan vendor:publish --tag="sn-preference-views"
```

This is the contents of the published config file `config/sn-preference.php`:

```
use Wsmallnews\Preference\Models;

return [
    /**
     * Default scopeable configuration
     */
    'scopeable' => [
        'scope_type' => 'sn-preference',
        'scope_id' => 0,
    ],

    /**
     * Custom models
     */
    'models' => [
        'preference' => Models\Preference::class,
    ],

    /**
     * Base file directory, will automatically append current date (used only for filament default upload component)
     */
    'file_directory' => 'sn/preference/',
];
```

Usage
-----

[](#usage)

### 1. Add Preference Capabilities to Models

[](#1-add-preference-capabilities-to-models)

Include the corresponding Traits in your models:

```
use Illuminate\Database\Eloquent\Model;
use Wsmallnews\Preference\Models\Concerns\Preferenceable;
use Wsmallnews\Preference\Models\Concerns\Preferencer;
use Wsmallnews\Preference\Models\Concerns\Preferenceable\Likeable;
use Wsmallnews\Preference\Models\Concerns\Preferenceable\Followable;
use Wsmallnews\Preference\Models\Concerns\Preferenceable\Viewable;
use Wsmallnews\Preference\Models\Concerns\Preferencer\Liker;
use Wsmallnews\Preference\Models\Concerns\Preferencer\Follower;
use Wsmallnews\Preference\Models\Concerns\Preferencer\Viewer;

class Post extends Model
{
    use Preferenceable;   // Basic preference capability
    use Likeable;         // Can be liked
    use Followable;       // Can be followed
    use Viewable;         // Can be viewed
}

class User extends Model
{
    use Preferencer;      // Basic operator capability
    use Liker;            // Can perform like operations
    use Follower;         // Can perform follow operations
    use Viewer;           // Can perform view operations
}
```

### 2. Add counter field

[](#2-add-counter-field)

Add a JSON counter field to your model's migration:

```
$table->json('counter')->nullable()->comment('Counter: like_num, comment_num, etc.');
```

### 3. Like

[](#3-like)

```
$post = Post::find(1);
$user = User::find(1);

// Like
$user->like($post);

// Unlike
$user->unlike($post);

// Toggle like status
$user->toggleLike($post);

// Check if liked
$user->hasLiked($post);        // true / false

// Batch attach like status
$user->attachLikeStatus($posts);

// Check if post is liked by user (from Likeable side)
$post->isLikedBy($user);       // true / false
```

The counter field is automatically maintained and updated when counts increase/decrease:

```
counter: {"like_num": 1}
```

### 4. Follow

[](#4-follow)

```
$userA = User::find(1);
$userB = User::find(2);

// Follow
$userA->follow($userB);

// Unfollow
$userA->unfollow($userB);

// Toggle follow status
$userA->toggleFollow($userB);

// Check if following
$userA->isFollowing($userB);          // true / false

// Check if mutual follow
$userA->isMutualFollowed($userB);     // true / false

// Get following count
$userA->followingCount();             // Number of following

// Batch attach follow status
$userA->attachFollowStatus($userB);
```

Counter is automatically maintained:

```
// Bidirectional counts automatically update after following
counter: {"follow_num": 1, "followed_num": 1}
```

When following each other, the time is automatically recorded:

```
// When B also follows A, the followed_at timestamp is automatically written to options
options: {"followed_at": "2023-01-01 00:00:00"}
```

### 5. View

[](#5-view)

```
$post = Post::find(1);
$user = User::find(1);

// User views post
$user->view($post);

// Anonymous view (only increments counter, no viewer recorded)
$post->view();                    // Automatically called from Viewable side

// Check if viewed
$user->hasViewed($post);          // true / false

// Check if post is viewed by user (from Viewable side)
$post->isViewedBy($user);         // true / false

// Delete view record
$user->deleteView($post);

// Batch attach view status
$user->attachViewStatus($posts);

// Clear all views of a type
$user->clearAllViews(Post::class);

// Clear views within a scope
$user->clearScopeableViews(
    ['scope_type' => 'blog', 'scope_id' => 1],
    Post::class
);
```

Counter is automatically maintained:

```
counter: {"view_num": 1}
```

Use Cases
---------

[](#use-cases)

Use CaseTraits UsedExampleArticle Like`Likeable` + `Liker`User likes an articleUser Follow`Followable` + `Follower`Users follow each otherContent View`Viewable` + `Viewer`Record article views and user browsing historyComment Like`Likeable` + `Liker`User likes a comment (used in comment package)Product FavoriteCustom type extensionExtend new behavior types based on Preference modelChangelog
---------

[](#changelog)

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

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

[](#contributing)

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

Security Vulnerabilities
------------------------

[](#security-vulnerabilities)

Please review [our security policy](../../security/policy) on how to report security vulnerabilities.

Credits
-------

[](#credits)

- [smallnews](https://github.com/Wsmallnews)
- [bezhansalleh/filament-plugin-essentials](https://github.com/bezhansalleh/filament-plugin-essentials)
- [filament/filament](https://github.com/filamentphp/filament)
- [Wsmallnews/support](https://github.com/wsmallnews/support)
- [All Contributors](../../contributors)

License
-------

[](#license)

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

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance91

Actively maintained with recent releases

Popularity8

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

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 ~18 days

Total

4

Last Release

32d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/16216215?v=4)[小新](/maintainers/Wsmallnews)[@Wsmallnews](https://github.com/Wsmallnews)

---

Tags

laravelfilamentfilament-pluginfilamentphpWsmallnewspreference

###  Code Quality

TestsPest

Static AnalysisPHPStan, Rector

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/wsmallnews-preference/health.svg)

```
[![Health](https://phpackages.com/badges/wsmallnews-preference/health.svg)](https://phpackages.com/packages/wsmallnews-preference)
```

###  Alternatives

[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3914.8k](/packages/rawilk-profile-filament-plugin)[wsmallnews/filament-nestedset

Filament nestedset tree builder powered by kalnoy/nestedset with Filament v4 and v5 support

197.8k19](/packages/wsmallnews-filament-nestedset)[backstage/mails

View logged mails and events in a beautiful Filament UI.

16121.5k](/packages/backstage-mails)[marcelweidum/filament-passkeys

Use passkeys in your filamentphp app

6649.5k2](/packages/marcelweidum-filament-passkeys)[jibaymcs/filament-tour

Bring the power of DriverJs to your Filament panels and start a tour !

12453.6k](/packages/jibaymcs-filament-tour)[tapp/filament-form-builder

User facing form builder using Filament components

132.4k5](/packages/tapp-filament-form-builder)

PHPackages © 2026

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