Ampersand in tags - how to replace with hyphen in url

Hi all - I am trying to create a simple portfolio site and am having trouble getting my head around the formatting of tags (I am using v4).

The issue happens when I have an ampersand in my tags, so in this case ‘photography & video’.

When I enter this tag into a page’s content, the tag is displayed as ‘Photography & Video’ which is correct, but the link is for ‘photography-video’ (again which is correct) but the results are always none. I can only get it to work if I remove the ampersand and have ‘photography video’ in the .txt file.

I really want to be able to replace ampersands with ‘-’ in the url, but have the tag in the tag cloud showing with the &.

I have tried urldecode, urlrawdecode & slugify but I am clearly doing something wrong and don’t fully understand the difference between them.

My code is as follows:

TEMPLATE

<div>
  <?php foreach($tags as $tag): ?>
  <a href="<?= url($page->url(), ['params' => ['tag' => Str::slug($tag)]]) ?>"
    class="tag <?php e($tag === param('tag'), 'text-decoration-underline', '')  ?>">
    <?= html($tag) ?>
  </a>
  <?php endforeach ?>
</div>

CONTROLLER

<?php
return function($page) {

  // fetch the basic set of pages
  $projects = page('work')->children()->listed();

  // fetch all tags
  $tags = $projects->pluck('tags', ',', true);

  // add the tag filter
  if($tag = Str::slug(param('tag'))) {
    $projects = $projects->filterBy('tags', $tag, ',');
  }

  // apply pagination
  $projects = $projects->paginate(15);
  $pagination = $projects->pagination();

  return compact('projects', 'tags', 'tag', 'pagination');

};

Any help greatly appreciated!

Should be

  if($tag = param('tag')) {
	  $projects = $projects->filter(fn($item) => in_array($tag, array_map(fn($tag) => Str::slug($tag), $item->tags()->split(','))));
  }

}

Thanks so much @texnixe - that works! I now get the word tag in the url:

‘projects/tag:photography-video’

so it works fine but if I’m being picky I’d like to remove that - is there an easy way to do so?

Thanks!

Define easy and for who? We try to avoid these words in the docs, what is easy for me, might not be easy for anyone else, and vice-versa.

Thanks, yes I suppose it’s hard to avoid subjective language.

In the case above, I have tried using the following code from that cookbook article but it doesn’t make any difference (url still shows ‘tag:’)

config.php

'routes' => [
        [
            'pattern' => 'our-work/(:any)',
            'action' => function ($tag) {
                if ($page = page('our-work/' . $tag)) {
                    return $page;
                } else {
                    return page('our-work')->render([
                        'tag' => $tag
                    ]);
                }

            }
        ]
    ],

Have you changed how you generate the url?

This code add the parameter to the URL, so without changing this, you won’t achieve anything.

No I haven’t, i didn’t see this mentioned on that page. Are you able to provide more light on what it needs changing to?

Thanks