
Laravel when(): Conditional Queries Without Extra if Statements
Use when() for conditional filters, pass the condition value into the callback, add an else branch with the third argument, and avoid falsy-value traps.
when() keeps optional filters inside one query chain instead of breaking query construction with separate if statements.
Its value goes beyond replacing a simple if. The callback can receive the condition value, the third argument acts like else, and falsy values such as 0 need deliberate handling.
Basic when() Usage
$query = User::query(); if ($status) { $query->where('status', $status);} $users = $query->get();$users = User::query() ->when( $status, fn ($query, $status) => $query->where('status', $status), ) ->get();Laravel passes more than the builder into the callback. The callback can receive the value supplied as the first argument to when(), so a separate use ($status) is unnecessary.
User::query() ->when( $status, fn ($query, $status) => $query->where('status', $status), );The Third when() Argument Is the else Branch
The full form when($value, $callback, $default) accepts a second callback. It runs when the first argument is falsy, giving you an if / else shape without leaving the fluent chain.
User::query() ->when( $sortByVotes, fn ($query) => $query->orderBy('votes'), fn ($query) => $query->orderBy('name'), ) ->get();The Trap: 0 and Other Falsy Values
Product::query() ->when( $minPrice, fn ($query, $minPrice) => $query->where('price', '>=', $minPrice), );Product::query() ->when( $minPrice !== null, fn ($query) => $query->where('price', '>=', $minPrice), );when() Is Not Limited to where()
Product::query() ->when( $categoryId, fn ($query, $categoryId) => $query->where('category_id', $categoryId), ) ->when( $onlyAvailable, fn ($query) => $query->where('stock', '>', 0), ) ->when( $sortByPrice, fn ($query) => $query->orderBy('price'), )when() is useful whenever a condition modifies the same builder: it can conditionally add where(), orderBy(), joins, selects, and other query clauses.
You do not need to replace every if with when(). If a separate condition is clearer outside the chain, a normal if is still the better shape. Laravel also provides unless() for the inverse condition.




