Generate slug from text field on Structure

I have a esctructure for categories. It has 2 text fields, one for the name of the category other for the slug of that category.

Can the second text field auto generate the slug from the first field? or any other way to do it instead of letting the user write the slug?

fields:
categories:
    label: Categories
    type: structure
    fields:
      categories:
        label: Category
        type: text
      slug:
        label: ID
        type: text
        converter: slug

You could achieve that via a hook, but why do you need the slug field at all?

I want to have access to the name and the slug saved on the parent page, but I don’t trust users writing a proper slug. I’m trying to figure out what’s the best way to do it.

Maybe I’m missing something, but what is the purpose of the slug field? Can’t you just generate a slug from the category in your template or wherever you need it without having to actually store it?

I had not thought of generating it from the name, maybe with Str::slug()?
I want to use the category on the front end as filter, a slug would be better for SEO purposes

Exactly. Then when filtering, you replace the filterBy() method with the filter($callback) method are you are fine.

1 Like

Thank you! I’ll give it a shot

I want to expand this a bit. I tried following this cookbook but with a custom filter but i get an error with “Undefined variable: category” https://getkirby.com/docs/cookbook/content/filter-via-route

config.php

    'routes' => [
        		[
        		'pattern' => 'catalogo/category/(:any)',
        		'action' => function ($category) {
        			return page('catalog')->render([
        				'category' => $category
        			]);
        		}
        	]
        ]

catalog.php

    <?php
    	return function($page, $site, $category) {
    		
    	// fetch the basic set of pages
    	$productos = $page->children()->listed();
    		
    	// add filters
    	if($category) {
    		$productos = $productos->filter(function ($child) {
    			return str::contains(str::slug($child->category()), str::slug($category));
    		});
    	};
    };

You’re using $categoryinside the callback without passing it to it, you can do that using the use() keyword:

 	// add filters
    	if($category) {
    		$productos = $productos->filter(function ($child) use($category) {
    			return str::contains(str::slug($child->category()), str::slug($category));
    		});
    	};
2 Likes

That worked, thank you!