diff --git a/README.md b/README.md
index 9a26ad1..d45312d 100644
--- a/README.md
+++ b/README.md
@@ -22,10 +22,12 @@
- [Views](#visit-monitoring-views)
- [Ajax Requests](#ajax-requests)
- [Visit Monitoring Guest Mode](#visit-monitoring-guest-mode)
+ - [Visit Monitoring Custom Conditions](#visit-monitoring-custom-conditions)
- [Action Monitoring](#action-monitoring)
- [Views](#action-monitoring-views)
- [Reverse Proxy Config](#action-monitoring-reverse-proxy-config)
- [Action Monitoring Guest Mode](#action-monitoring-guest-mode)
+ - [Action Monitoring Custom Conditions](#action-monitoring-custom-conditions)
- [Authentication Monitoring](#authentication-monitoring)
- [Views](#authentication-monitoring-views)
- [How to use in big projects](#how-to-use-in-big-projects)
@@ -366,6 +368,34 @@ When set to `false`, only authenticated user visits will be recorded.
],
```
+
+### Visit Monitoring Custom Conditions
+
+The `Laravel User Monitoring` package allows you to define custom conditions for visit monitoring.
+Conditions give you full control over when a visit should be logged.
+
+#### 🔧 How It Works
+
+- Conditions are checked before a visit is stored.
+- If any condition returns false, the visit will be skipped.
+- You can define conditions as closures or as class-based rules.
+
+```php
+'visit_monitoring' => [
+ 'conditions' => [
+ // Class-based condition (must implement MonitoringCondition interface)
+ \App\Monitoring\YourCustomCondition::class,
+
+ // Closure-based condition (receives the Request and authenticated User)
+ function (Illuminate\Http\Request $request) {
+ $user = $request->user();
+
+ return $user && $user->isAdmin();
+ },
+ ],
+],
+```
+
## Action Monitoring
@@ -457,6 +487,34 @@ When set to `false`, only authenticated user visits will be recorded.
],
```
+
+### Action Monitoring Custom Conditions
+
+The `Laravel User Monitoring` package lets you define custom conditions for action monitoring (create, update, delete events on models).
+Conditions give you control over when model actions should be logged.
+
+#### 🔧 How It Works
+
+- Conditions are checked before an action is stored.
+- If any condition returns false, the action will be skipped.
+- You can define conditions as closures or class-based rules.
+
+```php
+'action_monitoring' => [
+ 'conditions' => [
+ // Class-based condition (must implement MonitoringCondition interface)
+ \App\Monitoring\YourCustomCondition::class,
+
+ // Closure-based condition (receives the Request and authenticated User)
+ function (Illuminate\Http\Request $request) {
+ $user = $request->user();
+
+ return $user && $user->isAdmin();
+ },
+ ],
+],
+```
+
## Authentication Monitoring
diff --git a/config/user-monitoring.php b/config/user-monitoring.php
index 2c9fae4..158cfc3 100644
--- a/config/user-monitoring.php
+++ b/config/user-monitoring.php
@@ -98,6 +98,16 @@
* Determines whether to store `visits` even when the user is not logged in.
*/
'guest_mode' => true,
+
+ /*
+ | Here you can define one or more conditions that determine whether a visit
+ | should be logged. Each condition must return a boolean (true = log visit,
+ | false = skip logging).
+ |
+ | All conditions are evaluated before monitoring. If any condition returns
+ | false, the visit will NOT be recorded.
+ */
+ 'conditions' => [],
],
/*
@@ -136,6 +146,13 @@
* Determines whether to store `actions` even when the user is not logged in.
*/
'guest_mode' => true,
+
+ /*
+ * Here you can define one or more conditions that determine whether an action
+ * should be logged. Each condition must return a boolean (true = log action,
+ * false = skip logging).
+ */
+ 'conditions' => [],
],
/*
diff --git a/src/Contracts/MonitoringCondition.php b/src/Contracts/MonitoringCondition.php
new file mode 100644
index 0000000..a516925
--- /dev/null
+++ b/src/Contracts/MonitoringCondition.php
@@ -0,0 +1,10 @@
+shouldMonitor($request)) {
+ return $next($request);
+ }
+
+ $detector = new Detector;
$exceptPages = config('user-monitoring.visit_monitoring.except_pages', []);
if (empty($exceptPages) || !$this->checkIsExceptPages($request->path(), $exceptPages)) {
@@ -53,4 +59,30 @@ protected function checkIsExceptPages(string $page, array $exceptPages): bool
{
return collect($exceptPages)->contains($page);
}
+
+ /**
+ * Determine if monitoring should be performed for the given request and user.
+ */
+ protected function shouldMonitor(Request $request): bool
+ {
+ $config = config('user-monitoring.visit_monitoring.conditions', []);
+
+ foreach ($config as $condition) {
+ if (is_callable($condition)) {
+ if (! $condition($request)) {
+ return false;
+ }
+ } elseif (is_string($condition)) {
+ $instance = new $condition;
+ if (! $instance instanceof MonitoringCondition) {
+ continue;
+ }
+ if (! $instance->shouldMonitor($request)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
}
diff --git a/src/Traits/Actionable.php b/src/Traits/Actionable.php
index be0a177..8a5f7dc 100644
--- a/src/Traits/Actionable.php
+++ b/src/Traits/Actionable.php
@@ -2,9 +2,11 @@
namespace Binafy\LaravelUserMonitoring\Traits;
+use Binafy\LaravelUserMonitoring\Contracts\MonitoringCondition;
use Binafy\LaravelUserMonitoring\Utills\ActionType;
use Binafy\LaravelUserMonitoring\Utills\Detector;
use Binafy\LaravelUserMonitoring\Utills\UserUtils;
+use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
trait Actionable
@@ -20,6 +22,11 @@ protected static function boot(): void
return;
}
+ // Custom conditions from config
+ if (! static::shouldMonitor(request())) {
+ return;
+ }
+
if (config('user-monitoring.action_monitoring.on_store', false)) {
static::created(function (mixed $model) {
static::insertActionMonitoring($model, ActionType::ACTION_STORE);
@@ -94,4 +101,30 @@ private static function getRealIP(): string
? request()->header(config('user-monitoring.real_ip_header'))
: request()->ip();
}
+
+ /**
+ * Determine if monitoring should be performed for the given request and user.
+ */
+ protected static function shouldMonitor(Request $request): bool
+ {
+ $config = config('user-monitoring.action_monitoring.conditions', []);
+
+ foreach ($config as $condition) {
+ if (is_callable($condition)) {
+ if (! $condition($request)) {
+ return false;
+ }
+ } elseif (is_string($condition)) {
+ $instance = new $condition;
+ if (! $instance instanceof MonitoringCondition) {
+ continue;
+ }
+ if (! $instance->shouldMonitor($request)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
}
diff --git a/tests/Feature/ActionMonitoringTest.php b/tests/Feature/ActionMonitoringTest.php
index d7f9092..ada2dac 100644
--- a/tests/Feature/ActionMonitoringTest.php
+++ b/tests/Feature/ActionMonitoringTest.php
@@ -4,6 +4,7 @@
use Binafy\LaravelUserMonitoring\Utills\ActionType;
use Binafy\LaravelUserMonitoring\Utills\UserUtils;
use Illuminate\Foundation\Testing\RefreshDatabase;
+use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Tests\SetUp\Models\Product;
use Tests\SetUp\Models\ProductSoftDelete;
@@ -361,3 +362,35 @@
// DB Assertions
assertDatabaseCount(config('user-monitoring.action_monitoring.table'), 2);
});
+
+test('action is stored when config conditions are true', function () {
+ config()->set('user-monitoring.action_monitoring.conditions', [
+ function (Request $request) {
+ return true;
+ },
+ ]);
+
+ Product::query()->create([
+ 'title' => 'milwad',
+ 'description' => 'WE ARE HELPING TO OPEN-SOURCE WORLD'
+ ]);
+
+ // DB Assertions
+ assertDatabaseCount(config('user-monitoring.action_monitoring.table'), 1);
+});
+
+test('action is not stored when config conditions are false', function () {
+ config()->set('user-monitoring.action_monitoring.conditions', [
+ function (Request $request) {
+ return false;
+ },
+ ]);
+
+ Product::query()->create([
+ 'title' => 'milwad',
+ 'description' => 'WE ARE HELPING TO OPEN-SOURCE WORLD'
+ ]);
+
+ // DB Assertions
+ assertDatabaseCount(config('user-monitoring.action_monitoring.table'), 0);
+});
diff --git a/tests/Feature/VisitMonitoringTest.php b/tests/Feature/VisitMonitoringTest.php
index 5e8f532..35018ea 100644
--- a/tests/Feature/VisitMonitoringTest.php
+++ b/tests/Feature/VisitMonitoringTest.php
@@ -2,6 +2,7 @@
use Binafy\LaravelUserMonitoring\Models\VisitMonitoring;
use Illuminate\Foundation\Testing\RefreshDatabase;
+use Illuminate\Http\Request;
use Tests\SetUp\Models\User;
use function Pest\Laravel\{actingAs, get};
use function Pest\Laravel\{assertDatabaseCount, assertDatabaseHas, assertDatabaseMissing};
@@ -122,6 +123,34 @@
assertDatabaseCount(config('user-monitoring.visit_monitoring.table'), 1);
});
+test('visit monitoring is store when config conditions are true', function () {
+ config()->set('user-monitoring.visit_monitoring.conditions', [
+ function (Request $request) {
+ return true;
+ },
+ ]);
+
+ $response = get('/');
+ $response->assertContent('milwad');
+
+ // DB Assertions
+ assertDatabaseCount(config('user-monitoring.visit_monitoring.table'), 1);
+});
+
+test('visit monitoring is not store when config conditions are false', function () {
+ config()->set('user-monitoring.visit_monitoring.conditions', [
+ function (Request $request) {
+ return false;
+ },
+ ]);
+
+ $response = get('/');
+ $response->assertContent('milwad');
+
+ // DB Assertions
+ assertDatabaseCount(config('user-monitoring.visit_monitoring.table'), 0);
+});
+
/**
* Create user and return it.
*/