Dave asks:
There are two ways of doing this. The first would be with a server side URL rewriter. Apache has this built in, and you can find options for IIS as well. The URL rewriter would simply map example.com/louisiana/lafayette.cfm to example.com/dyncity.cfm?state=louisiana&city=lafayette.cfm.I have a lot of city pages for my site similar to this folder structure: example.com/colorado/denver.cfm
What I have been doing is to create a template called template-city.cfm that gets included in to each city page such as denver.cfm. So basically denver.cfm is just a tiny shell file and the real guts of the page is located in the template-city.cfm, so the thought is that I only have to change the template-city.cfm once and all the others pages like denver.cfm get updated at once.
But in order to do this I had to create tons of city pages within each state (which I automated with CFfile) but a red flag is going off in my brain telling me this is the wrong way to do it. Is there some virtual way to create these city pages and even state folders?
If you don't have access to the web server and you are using ColdFusion 8, there is no reason not to use onMissingTemplate in Application.cfc. Here is a simple example:
<cffunction name="onMissingTemplate" access="public" returnType="boolean" output="true">
<cfargument name="pageRequested" type="string" required="true">
<cfset var city = listLast(arguments.pageRequested, "/")>
<cfset var state = listGetAt(arguments.pageRequested, listLen(arguments.pageRequested,"/")-1, "/")>
<cfset city = replaceNoCase(city, ".cfm", "")>
<cfinclude template="dyncity.cfm">
<cfreturn true>
</cffunction>
Given a request of some.com/louisiana/lafayette.cfm, the value passed to pageRequested will be a string I can parse using list functions. I grab the city at the end, and the state at the second to last position. At that point, what you do is up to your model. You would probably call a CFC method that would translate a state/city string to a particular ID value of a city in the database. In my example I just include a file that displays it:
<cfoutput><h2>#city#, #state#</h2></cfoutput>
I've included the application as a zip to this blog entry. You should be able to extract it to your web server, and then hit any URL. The only drawback is that .cfm must be in the URL.
If you wanted to support example.com/louisiana/lafayette, then you would need to use the URL rewriters I mentioned above.
Archived Comments
Ray,
Thanks for answering my question!
I really like your idea of using the onMissingTemplate method.
I have my own dedicated IIS box (with CF8) so the URL re-writer idea gets really complicated since I am not very good at writing regular expressions.
Thanks again.
I actually do this method in another way using
www.example.com/c.cfm/State...
with c.cfm parsing out State and City off of it
The following function will get the State/City and then I can convert a List with the delimiter of / to an array and get the data off of this.
<cffunction name="getRHS">
<cfset path = cgi.PATH_INFO>
<cfset filename = cgi.script_name>
<cfif not findnocase(filename,path) >
<cfif len(path) gt 1>
<cfset path = right(path,len(path)-1)>
<cfelse>
<cfset path = " ">
</cfif>
<cfelse>
<cfif len(path) gt len(filename)>
<cfset path = right(path,len(path)-len(filename))>
<cfelse>
<cfset path = "">
</cfif>
</cfif>
<cfreturn path>
</cffunction>
Nice post Ray!
Also, IIS7 has a built-in URL Rewrite. Finally.
Ray,
I just added the files to my server and it worked perfectly.
Now I have to remember how the hierarchy works for the Application.cfc since i placed your files in a sub folder.
So is this a reasonable alternative to URL Rewrite? Could use use this to handle SES URLs on your site, say if you are on shared hosting?
Yes, if you are ok with .cfm being in the url someplace. If not, you need to get a rewriter.
On my old IIS sites I remap the 404 pages to a template that handles these types of requests since at the time I didn't know about any rewrite options.
When the template can't find any relevant content it sends a 404 via cfheader statuscode so that the search engines don't think I'm running a spam doorway site.
is this information being stored/pulled from any database on the back end? if so, why not simply use URL variables along the lines of "/index.cfm?state=louisiana&city=lafayette" which would still be pretty seo-friendly too.
I wonder what the performance implications are of using onMissingTemplate over using URLRewrite? Speed, throughput, etc? Anyone out there able to speak to this?
@SW: Yes, the idea is that the city info is stored in the db, and you take the url params and look them up.
So sure, the non short version of the URL isn't so bad. I'm no SEO expert of course. I will say that it is less typing to do /state/city and it is something a non-techy would easier be able to remember.
What happens if there isn't a template for the city?
Well, now we are getting into something specific to his application, and less about the concept in general. The original author would have to say what to do. I'd guess though that you could simply forward to badcity.cfm, a page that says 'The city you wanted doesn't exist.'
Ray,
For some reason I am having a tough time transferring my old Application.cfm to the new Application.cfc so I can use your cool onMissingTemplate idea for my URL structure.
The first thing I am trying to transfer over is the variables that are shared among all pages and all visitors of my site.
So I thought onApplicationStart function would be the best use for my global variables such as company name, but I can't get it to work.
Application.cfc file:
<cfcomponent output="false">
<cffunction name="onApplicationStart" returnType="boolean" output="true">
<cfset Application.companyname = "Joes Diner">
<cfreturn true>
</cffunction>
</cfcomponent>
Normal template:
<cfoutput> #Application.companyname#</cfoutput>
But I get this error when running the page:
Element COMPANYNAME is undefined in APPLICATION.
Sorry I am so confused on this, I have used CFC before in the past with much success.
Dave
You forgot to name your application. Use <cfthis.name="rayrocks"> (or somesuch) above the onApplicationStart method.
You should read the docs on Application.cfc. It will definitely help.
Some more links that may help:
http://www.coldfusionjedi.c...
http://www.coldfusionjedi.c...
Wow, that applicationTimeout had me all screwed up, I would keep changing variables in application.cfc thinking they would change instantly - but instead the hung on for 20 minutes! I have less hair now that I pulled most of it out.
For testing I set it to 5 seconds and now I see how it is working.
Question do I have to use the "Application" prefix on all my Application variables such as <cfset Application.coname = "Daves Diner"> or can I do it like <cfset coname = "Daves Diner">?
By definition, an Application scoped variable will be application.something.
Ray thanks for the quick reply, that is what I thought, now I have to go and change a ton of variables using find replace.
I am using your standard application file that you pointed me to earlier and finding very useful.
Any ideas on using IIS7's rewite with a dynamic CF page? Wehave a 404 handler that has been hadling this...basically the user friendly url comes in, the 404 handler looks up the name in the db and returns an ID in a url that the site understands. For some reason, IIS7 doesn't seem to like this...it returns a 404.0 not found error(404, 404.2 and 404.3 are defined). So I came up with the idea of taking advantage of IIS7's rewrite. This seems to use the web.config file. Is there a way to dynmically do this with data from the DB? Thanks! I'll also post this on CF-talk ;-)
Sorry - I've never used IIS7's rewrite.