Routing

Using the framework (1.1.15), is it possible to map this type of url - following Google guidance to index a single page application:

http;//somedomain.com/?_escaped_fragment=page/contact

Where page is my controller. The action is generic and in this case takes the contact value and retrieves that page from the database (this is not important to this discussion).

(My current route definition to handle this is

‘<controller:\w+>/<index:.*>’=>’<controller>/init’)

I’m not an expert on .htaccess - these are the rewrite rules I currently have in place

<IfModule mod_rewrite.c>

RewriteCond %{HTTPS} !=on

RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]

RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]

RewriteCond %{SCRIPT_FILENAME} -f [OR]

RewriteCond %{SCRIPT_FILENAME} -d

RewriteRule .* - [L]

RewriteRule ^search/(.+)/([0-9]+)/?$ search/search?search=$1&page=$2 [QSA,L]

RewriteRule ^(.+)/([0-9]+)/?$ index.php?name=$1&page=$2 [QSA,L]

RewriteRule ^(.+)$ index.php?name=$1 [QSA,L]

</IfModule>

Any help much appreciated !

http://www.yiiframework.com/doc/guide/1.1/en/topics.url

first of all, you enable url rewriting in the htaccess:


RewriteEngine on

RewriteCond %{REQUEST_FILENAME} !-f

RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule . index.php

then you put this in the protected/config/main.php:


'urlManager'=>array(

	'urlFormat'=>'path',

        'showScriptName'=>false,

        'rules'=>array(

	        '?_escaped_fragment'=>'page/contact',


         )

)

Hi, sorry for the late reply - I’ll give this a try!

Hi,

This is what I’ve been trying to do … in my rules I’ve been trying

‘\?escaped_fragment\=<controller:\w+>/<indexID:.*>’=>’<controller>/init’ (where I deal with the indexID in a generic init action

(or ‘\?escaped_fragment\=/<controller:\w+>/<indexID:.*>’=>’<controller>/init’ if the url should look like somedomain.com/?_escaped_fragment=/page/contact rather than the above somedomain.com/?_escaped_fragment=page/contact

My page controller does not get called at all. In the controller component, if I print out $_GET this is what I have




Array

(

    [_escaped_fragment_] => /page/contact

)



Rather than




Array

(

    [name] => page/contact

    [indexID] => contact

)



which is what I get if I don’t use the escaped_fragment portion

Hi,

Does anyone have an answer for this?

Assuming I want to work with http://domain.com/?_escaped_fragment=/site/index

I’ve tried




'<fragment:.*>/<controller:site>/<action:.*>'=>'<controller>/<action>'

'\?_escaped_fragment_\=/<controller:site>/<action:.*>'=>'<controller>/<action>' (you have escape otherwise Yii will throw an error it's not a valid regular expression)




Both generate a 404 error…

Try using routeVar, stick to normal GET URL formats and combine that with hiding index.php.




'urlManager' => array(

	'showScriptName' => false,

	'routeVar' => '_escaped_fragment',

	...

),



HI,

Many thanks for getting back - I still can’t get this work I’m afraid. I can’t use normal GET url format since my JS single page uses a path format and I need to match this server side. Are there no users who’ve built a single page app and used Yii in this way to make the site crawlable?

Hi,

Made some more progress but still having an issue which I’ll describe below.

I have added the routeVar to my urlManager and reverted back to using $_GET like so




'urlManager'=>array(

			// 'urlFormat'=>'path',

			

			'routeVar' => '_escaped_fragment_',

etc etc 




However, the way I had set up my routes prior to trying to use "_escaped_fragment" was to do the following

‘<controller:\w+>/<indexID:.*>’=>’<controller>/init’,

This allowed me to have any indexID (about-us, services etc etc) beign dealt with by an "init" action on my (page) controller.

(I do have examples where I do have a named action (eg contact) in which case page/contact which works fine…)

Using the routeVar, these routes are now being completely by-passed. Unless I have an action of (eg) services, the code won’t work - it’s expecting to find the services action on my page controller which clearly doesnt make sense.

What I am wondering is to see if it’s possible to set up a generic action in the actions method on my (page) controller. Here’s what I would do with an index action




public function actions() {

  return array(

     'index' => array(

       'class' => 'init',

       etc etc 

     )

   )

}



Is it possible to set up a regular expression for the action rather than having to specify it by name - which isn’t going to work for me as I need the actions to be dynamic.

Hope I’ve explained this well enough!

Addition: now I realise that using routeVar and reverting back to standard $_GET (unsetting urlFormat => path) wrecks my REST api …

Sorry, I thought you just wanted that kind of URL format and didn’t notice right away that you wanted to do something else. Anyway, I’ve never built such a site before with google search crawling in mind but this seems to be an interesting goal to achieve.

For your single page site, are you using hash fragments plus ajax calls to your controller actions to achieve such a setup, and just want to support the ugly URL format suggested by google for their crawlers?

Hi, many thanks for getting back - and thanks for your help so far.

For the single page site, I’m using Angular. I have a REST api set up on /api along the lines of this article http://www.yiiframework.com/wiki/175/how-to-create-a-rest-api/

This needs to have urls in the path format - my spa expects this and is built on that basis.

So what I need to achieve is use the path format for my urls on the front end so I can access eg http://test.com/?_escaped_fragment=/page/about-us. As I’ve mentioned, I’ve set up my routes so I can deal with any values for the action (including sub pages about-us/about-us-sub-page etc) which is deal by a generic actin (init in my case) which looks at the url to extract the values I need and makes the model calls from that.

Before you mentioned using routeVar and normal $_GET, I was getting nowhere trying to include ?_escaped_fragment= in my routes. Any help much appreciated!