Url Manager question

I have a site where there is a number of categories and that categories have tags, that act as subcategories.

I need URLs like:


Sure, I need IDs of that category and tag to display the data.

So I have 2 questions:

  1. How to set up url manager for this case?

  2. How to convert between categoryName and categoryID effectively?

Currectly I have the following config:

'urlManager' => array(

        	'urlFormat' => 'path',

        	'urlSuffix' => '.html',

        	'showScriptName' => false,

        	'rules' => array(

        		'<categoryID:s+>' => 'search/index',

        		'<categoryID:s+>/<tagID:s+>' => 'search/index'


But when I go to:

ste.com/Dresses.html, it tells me there is no such controller - dresses

Then I tried:

'rules' => array(

        		'search/<categoryID:s+>' => 'search/index',

        		'search/<categoryID:s+>/<tagID:s+>' => 'search/index'


Now it tells me that action Dresses is not found! Why is it so?

As I can see, the problem is that name of the category can't be distinguished from the name of controller. And name of subcategory - from the controller action.

How to solve this?

The regular exp​ression is not correct for the category. You are using "\s" which means space. I think what you want is "\w" or something.

yeah, really, that works perfectly!

So simple solution for this task! I like this framework :)

Um… not so simple…

Now when I type

site.com/category/, it does not redirect me to the category controller, it tries to use "category" as categoryID…

What can be done here?

For category ID, you should define a new rule which uses pattern "\d+".

No, I need this to be letters!

site.com/Dresses/blue.html should show list of blue dresses

You want to use /category/ to represent the default action of the category controller? Then insert a new rule before your other category rules.

It works, but I have to list ALL controllers and ALL their actions before these 2 lines:

'urlManager' => array(

        	'urlFormat' => 'path',

        	'urlSuffix' => '.html',

        	'showScriptName' => false,

        	'rules' => array(



        		'look' => 'look',

        		'look/create' => 'look/create',

        		'look/list' => 'look/list',

        		'look/show' => 'look/show',

        		'look/update' => 'look/update',

        		'look/delete' => 'look/delete',


        		'categories' => 'category',

        		'<categoryID:w+>/<tagID:w+>' => 'search/index',

        		'<categoryID:w+>' => 'search/index',



So all actions should be listed for each controller. 2 disadvantages:

  1. boring to write all that

  2. will slow the application :(

Any ideas?

You can avoid those "look" rules if you specify some more complex regular exp​ressions with your "category" rules. A simple "\w+" of course will cause problem because it matches "look".

I understand this, but such structure is a requirement :(

I need just site.com/Dresses.html or site.com/Dresses/new.html

Now I'm confused…

A side note: if your URL scheme is fixed (you do not want to change to use a different one), using Apache's URL rewriting is probably a better choice.

Hi KJedi,

Have you found any solution to this?

I am stuck at the same thing, I want to redirect ‘user/username’ to ‘user/show/id/<id>’

Again, it’s the same thing, Yii always look for ‘Id’ rather than ‘username’.

Please tell me if you have found any solution to this

Yes, I’ve got it done. Lots of rules though.

Here are my URL rewriting rules:


			'urlFormat' => 'path',

			'urlSuffix' => '.html',

			'showScriptName' => false,

			'rules' => array(
































					'/womens/looks/' => 'look/list',




					'/womens/clothing/popular' => 'search/popular',

					'/womens/clothing/brandNew' => 'search/brandNew',

					'/womens/clothing/onSale' => 'search/onSale',

					'/womens/clothing/<productName:[a-zA-Z0-9_-]+>__<productID:\d+>' => 'product/view',

					'/womens/clothing/<productID:\d+>' => 'product/view',


					'/womens/clothing/<categoryName:[a-zA-Z0-9_-]+>/<categoryTagName:[a-zA-Z0-9_-]+>/<tagName:[a-zA-Z0-9_-]+>__/p<page:\d+>' => 'search/category',

					'/womens/clothing/<categoryName:[a-zA-Z0-9_-]+>/<tagName:[a-zA-Z0-9_-]+>__/p<page:\d+>' => 'search/category',

					'/womens/clothing/<categoryName:[a-zA-Z0-9_-]+>/<categoryTagName:[a-zA-Z0-9_-]+>/p<page:\d+>' => 'search/category',

					'/womens/clothing/<categoryName:[a-zA-Z0-9_-]+>/p<page:\d+>' => 'search/category',

					'/womens/clothing/<categoryName:[a-zA-Z0-9_-]+>/<categoryTagName:[a-zA-Z0-9_-]+>/<tagName:[a-zA-Z0-9_-]+>__' => 'search/category',

					'/womens/clothing/<categoryName:[a-zA-Z0-9_-]+>/<tagName:[a-zA-Z0-9_-]+>__' => 'search/category',

					'/womens/clothing/<categoryName:[a-zA-Z0-9_-]+>/<categoryTagName:[a-zA-Z0-9_-]+>' => 'search/category',

					'/womens/clothing/<categoryName:[a-zA-Z0-9_-]+>' => 'search/category',



					'/womens/shops/<shopName:[a-zA-Z0-9_-]+>/<categoryName:[a-zA-Z0-9_-]+>/<categoryTagName:[a-zA-Z0-9_-]+>/p<page:\d+>' => 'search/shop',

					'/womens/shops/<shopName:[a-zA-Z0-9_-]+>/<categoryName:[a-zA-Z0-9_-]+>/p<page:\d+>' => 'search/shop',

					'/womens/shops/<shopName:[a-zA-Z0-9_-]+>/p<page:\d+>' => 'search/shop',

					'/womens/shops/<shopName:[a-zA-Z0-9_-]+>/<categoryName:[a-zA-Z0-9_-]+>/<categoryTagName:[a-zA-Z0-9_-]+>' => 'search/shop',

					'/womens/shops/<shopName:[a-zA-Z0-9_-]+>/<categoryName:[a-zA-Z0-9_-]+>' => 'search/shop',

					'/womens/shops/<shopName:[a-zA-Z0-9_-]+>' => 'search/shop',


					'/womens/clothes' => 'site/clothes',

					'/womens/clothes/<tagName:[a-zA-Z0-9_]+>/p<page:\d+>' => 'search/tag',

					'/womens/clothes/<tagName:[a-zA-Z0-9_]+>' => 'search/tag',


					'/womens/search' => 'site/clothes',

					'/womens/search/<term:.+>/p<page:\d+>' => 'search/term',

					'/womens/search/<term:.+>' => 'search/term',

					'/rss/latest/<subscribeID:[a-zA-Z0-9_-]+>' => 'subscription/get',

					'/rss/latest' => 'subscription/get',

					'/rss/author<authorID:\d>/<subscribeID:[a-zA-Z0-9_-]+>' => 'subscription/get',

					'/rss/author<authorID:\d>' => 'subscription/get',

					'/looks/<lookName:[a-zA-Z0-9_-]+>__<lookID:\d+>' => 'look/view',

					'/looks/<lookID:\d+>' => 'look/view',

					'/terms-and-conditions' => 'site/tc',

					'/privacy-policy' => 'site/privacy',

					'/about-us' => 'site/about',

					'/contact-us' => 'site/contact',



@KJedi: you may reduce the number of rules a lot by using more complex regexp and parameters in route. For example:


is equivalent to the following 4 rules:





Cool! Thank you!

By the way, I have to add sorting order and colour into the URLs now.

So example urls should be (components don’t contain dashes or underscores):

/womens/clothing/Dresses.html (simple)




/womens/clothing/Cheap_Black_Dresses_Evening.html (Evening is subcategory)





I proposed changing them and replace underscore with dash so I could distinguish colour from category or shop.

Sorting order should not be distinguished, I have a fixed list for this. So urls turn into:

/womens/clothing/Dresses.html (simple)




/womens/clothing/Cheap_Black-Dresses_Evening.html (Evening is subcategory)

/womens/clothing/shop_Topshop-Black.html(only shop and colour is selected)

/womens/clothing/shop_Topshop_Cheap-Black.html(only shop, sorting order and colour is selected)

/womens/clothing/shop_Topshop_Cheap-Black_Dresses.html (plus category)

/womens/clothing/shop_Topshop_Cheap-Black_Dresses_Evening.html (plus subcategory)

Urls like /womens/clothing/* should redirect to search/category and /woments/clothing/shop_* - to search/shop

Any ideas how to write clever rules to suit all that?

I don’t want to use mod_rewrite because I’ll not be able to use createUrl() method. Maybe writing custom URL management class will do better for me? If so, how to do it?

In these "optional" parameters, currently there is no good solution. We may consider supporting this feature in future.