where(function (Builder $query) use ($attributes, $searchTerm) { foreach (Arr::wrap($attributes) as $attribute) { $query->when( // Check if the attribute is not an expression and contains a dot (indicating a related model) ! ($attribute instanceof \Illuminate\Contracts\Database\Query\Expression) && str_contains((string) $attribute, '.'), function (Builder $query) use ($attribute, $searchTerm) { // Split the attribute into a relation and related attribute [$relation, $relatedAttribute] = explode('.', (string) $attribute); // Perform a 'LIKE' search on the related model's attribute $query->orWhereHas($relation, function (Builder $query) use ($relatedAttribute, $searchTerm) { $query->where($relatedAttribute, 'LIKE', "%{$searchTerm}%"); }); // if need more deep nesting then commonet above code and // use below (which is not recommend) // Split the attribute into a relation and related attribute // $attrs = explode('.', (string) $attribute); // $relatedAttribute = array_pop($attrs); // $relation = implode('.', $attrs); // Perform a 'LIKE' search on the related model's attribute // $query->orWhereRelation($relation, $relatedAttribute, 'LIKE', "%{$searchTerm}%"); }, function (Builder $query) use ($attribute, $searchTerm) { // Perform a 'LIKE' search on the current model's attribute // also attribute can be an expression $query->orWhere($attribute, 'LIKE', "%{$searchTerm}%"); } ); } }); }); } } // example of usage 👇 Post::query() ->whereLike([ 'title', // search in the current model's 'title' attribute 'description', // search in the current model's 'description' attribute 'user.name', // search in the related model's 'name' attribute 'user.email', // search in the related model's 'email' attribute DB::raw('DATE_FORMAT(created_at, "%d/%m/%Y")'), // search in the formatted 'created_at' attribute DB::raw('CONCAT(user.first_name, " ", user.last_name)'), // search in the concatenated 'first_name' and 'last_name' attributes ], request()->search) // search for the request's 'search' query parameter ->with('user') ->get();