Jigsaw: Question: How to filter collection based on metadata list?

Created on 11 Jan 2018  路  6Comments  路  Source: tighten/jigsaw

In my blog posts, I want to use tags. I thought I could use tags: one, two, three in the YAML Frontmatter. In my blog post overview template, I thought about using a conditional loop, such as the following for filtering out all posts with the tag sports:

<ul>
@foreach ($posts as $post)
@if (strpos($post->tag, 'sports') !== false)
   <li>{{ $post->title</li>
@endif
@endforeach
</ul>

This feels like an inefficient hack. How would you solve that feature?

Most helpful comment

I would add a helper function to your collection in config.php, something like:

        'posts' => [
            'hasTag' => function ($page, $tag) {
                return collect(explode(',', $page->tags))->contains($tag);
            },
        ],

And then call it using the collection method filter in your Blade template. With higher-order messages, you can make it really clean:

@foreach ($posts->filter->hasTag('sports') as $post)
    <p>{{ $post->title }}</p>
@endforeach

As for the syntax error in the second case, I suspect that's caused by using a Blade echo inside your @if statement; that should just be $page->tag, not {{ $page->tag }}.

All 6 comments

And it fails when I want to make the comparison string dynamic:

@if (strpos($post->tag, {{ $page->tag }}) !== false)

Throws:

Parse error: syntax error, unexpected '<'

Which obvliously refers to the next line in the template:
<div class="text-center">

I would add a helper function to your collection in config.php, something like:

        'posts' => [
            'hasTag' => function ($page, $tag) {
                return collect(explode(',', $page->tags))->contains($tag);
            },
        ],

And then call it using the collection method filter in your Blade template. With higher-order messages, you can make it really clean:

@foreach ($posts->filter->hasTag('sports') as $post)
    <p>{{ $post->title }}</p>
@endforeach

As for the syntax error in the second case, I suspect that's caused by using a Blade echo inside your @if statement; that should just be $page->tag, not {{ $page->tag }}.

Works flawlessly!

Hm, premature celebrations. This function does only consider the first tag, so in an example YAML tag: one, two, three and I do an hasTag('one'), I only get that record if one is in first position, not if in second or later.

I have no idea how to debug this. What could be going wrong here?

Probably spaces between your tags? The way I wrote it, explode would grab those, so you'd end up with ['one', ' two', ' three']. Remove the spaces and it should work, or add an extra step to trim spaces after exploding.

Sure, whitespace matters! This did solve my problem.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

GenieTim picture GenieTim  路  4Comments

himan72 picture himan72  路  9Comments

imaje89 picture imaje89  路  3Comments

knorthfield picture knorthfield  路  3Comments

DRogueRonin picture DRogueRonin  路  8Comments