Home  >  Q&A  >  body text

Search posts by tags

I need to display posts by tags. My solution works for a single tag like this:

route:

Route::get('/posts',
   [PostController::class, 'index'])->middleware('auth');

Post model filter:

public function scopeFilter($query, array $filters)
{
    if ($filters['tag'] ?? false) {
        $tagId = Tag::where('name', $filters['tag'])->first()->id;
        $query->whereHas('tags', function($q) use ($tagId) {
                $q->where('tag_id', $tagId);
        });
    }
}

Method index of PostController:

public function index()
{
    return view('posts', [
        'posts' => Post::latest()->filter(request(['tag']))->get()
    ]);
}

This code applies to the following URL: "http://127.0.0.1:8000/posts/?tag=test". But I need to find a way to search for posts with more tags, for example I want to find posts with tags "test" and "unit". To do this I want to use a URL like this: "http://127.0.0.1:8000/posts/?tag=test&unit". I'm stuck because I thought "request(['tag'])" would return "test&unit" but it only returns "test". Is it possible to somehow get the "unit" tag from this request?

P粉323050780P粉323050780179 days ago436

reply all(1)I'll reply

  • P粉596161915

    P粉5961619152024-04-04 18:26:32

    GET requests using query strings can accept multiple parameters. instead of ?tag=test&unit (which won't really work anyway, since &unit will be parsed as $request->input('unit'), and will be null, & are reserved characters), you can send it as:

    http://127.0.0.1:8000/posts?tags[]=test&tags[]=unit

    On the backend, when you access request()->input('tags'), you get the following array:

    $tags = request()->input('tags'); // ['test', 'unit']
    

    So, put them together:

    // ScopeFilter method on your `Post` Model
    public function scopeFilter($query, array $tagNames) {
      if (!empty($tagNames)) {
        $tagIds = Tag::whereIn('name', $tagNames)->pluck('id');
    
        return $query->whereHas('tags', function($subQuery) use ($tagIds) {
          return $subQuery->whereIn('tags.id', $tagIds);
        });
    
        // Alternative without `$tagIds`, using `$tagNames` directly
        // return $query->whereHas('tags', function($subQuery) use ($tagNames) {
        //   return $subQuery->whereIn('tags.name', $tagNames);
        // });
      }
    
      return $query;
    }
    
    // Usage
    public function index() {
      return view('posts', [
        'posts' => Post::latest()->filter(request()->input('tags', []))->get()
      ]);
    }
    
    • Adjust the query to handle multiple values ​​using whereIn()
    • Use request()->input('tags', []) to access ?tags[]=...&tags[]=..., if not Provided is an empty array.

    reply
    0
  • Cancelreply