Make an RSS Feed for Your Splash Site

March 6th, 2010

Using the new Splash Tags for the Splash CMS, you can easily make an RSS feed or an XML sitemap.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<cfcontent type="text/xml" reset="Yes"><?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
  <atom:link href="http://www.YourSite.com/index.cfm/feed"
   rel="self" type="application/rss+xml" />
  <title>YourSite.com</title>
  <link>http://www.YourSite.com</link>
  <description>Your Description Goes Here</description>
  <cfoutput>
    <pubDate>#HTMLEditFormat(DateFormat(now(), 'ddd, dd mmm yyyy'))#
      #HTMLEditFormat(TimeFormat(now(), 'HH:mm:ss'))# EST</pubDate>
  <language>en-us</language>
  <ttl>40</ttl>
  <s:find slug="blog">
  <s:children-each order="publishedAt desc" where="status='published'">
    <item>
      <cfset thisChild = request.tags.currentChild>
      <title>#HTMLEditFormat(thisChild.title)#</title>
      <description><![CDATA[<s:content part="body" page="#thisChild#"/>]]></description>
      <pubDate>#HTMLEditFormat(DateFormat(thisChild.publishedAt, 'ddd, dd mmm yyyy'))#
         #HTMLEditFormat(TimeFormat(thisChild.publishedAt, 'HH:mm:ss'))# EST</pubDate>
      <guid isPermaLink="true">http://www.yoursite.com/index.cfm/#thisChild.slug#</guid>
      <link>http://www.yoursite.com/index.cfm/#thisChild.slug#</link>
    </item>
  </s:children-each>
  </s:find>
</channel></cfoutput>
</rss></cfcontent><cfabort>

Most of this code is the required RSS XML. Just drop in your site-specific domain name, description, etc.

The <s:find slug=”blog> tag finds the blog, and then <s:children-each> loops over all the children that are under the blog page. I used thisChild as a convenience variable instead of having to type request.tags.currentChild every time. The <cfabort> at the end keeps Splash from adding extra HTML tags at the end of the file.

You could also create an easy XML site map using a similar approach. Just change out the XML wrapper.

CFWheels, ColdFusion, Splash CMS , ,

New Splash Tags for the Splash CMS

March 5th, 2010

I recently added several new Splash Tags for the Splash content management system. If you don’t know about Splash, read my Introduction to Splash article.

  • <s: find>
  • <s: children-each>
  • <s: children-first >
  • <s: children-last >
  • <s: ifFirst >
  • <s: unlessFirst >
  • <s: ifLast >
  • <s: unlessLast >

There’s a complete list of tags and documentation over on the GitHub Wiki. But, I’ll give you an overview and show you how to use these tags for a blog.

<s:find> This tag looks up a page and stores the page object so that subsequent tags can use that page object.

<s: children-each> The tag finds all the children of a page and loops over them.

<s: children-first > and <s: children-last > finds the first or last child page.

The rest of the tags are all used inside of a <s: children-each> tag. They check to see if the current child page is the first one, last one, or whatever.

Making a Blog page with Splash Tags

Let’s say you have a page named Blog, that has several posts that are child pages of Blog. Then, in the body for the blog page, put something like this:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
<h3>Articles</h3>
<s:find slug="blog">
  <s:children-each
  order="publishedAt desc"
  where="status='published'">
    <cfset thisChild = request.tags.currentChild>
    <cfoutput>
      <dt class="blogList">
         <a href="#thisChild.slug#">#thisChild.title#</a>
            | #DateFormat(thisChild.publishedAt, 'long')#</dt>
      <dd class="blogDesc">#thisChild.description#</dd>
    </cfoutput>
  </s:children-each>
</s:find>

<s:find slug=”blog”> finds the blog page, and then <s:children-each> loops over all the pages. By the way, <s:children-each> uses the CFWheels findAll model method, so all of the cool CFWheels parameters are available in <s:children-each>!

If you want to see an example of what this looks like, visit the DonorUp blog page.

All in all, that’s a lot of output for very little programming effort. That’s what I call the secret to programmer happiness!

CFWheels, ColdFusion, Splash CMS , ,

Content Management and the Splash CMS — Introduction

March 5th, 2010

Splash CMS is an open source content management system that runs on top of CFWheels. It’s designed to be a simple, but elegant content management solutions for websites that are managed by small teams.

CFWheels is an open source ColdFusion framework that is inspired by Ruby on Rails. Besides being easy to use and learn, using CFWheels lets you adapt great ideas from Ruby on Rails (RoR) applications. RoR has the Radiant CMS, and Splash is the ColdFusion/CFWheels adaptation!

You can easily download Splash from http://wiki.github.com/russjohnson/SplashCMS/. The documentation for Splash is still kind of sparse, but the Radiant documentation is mostly applicable, and you can easily see how most things are supposed to work. Then, if you get stuck, email the Google Group.

Splash Layouts, Snippets, and Pages

Splash uses Layouts, Snippets, and Pages to build a website.

A layout, as you might imagine, is like a skin for an entire website. You can have multiple layouts and use different layouts for different pages.

Pages are specific URLs on a Splash site, and each page has a specific layout specified. A page can have multiple “page parts.” Most pages will have a “Body” part, but some might also have a “Sidebar” or other parts.

Snippets are reusable content chunks. You might have a navigation snippet that displays the main navigation for your site. Headers and Footers are other common snippets.

Splash Tags

There is one other very powerful component to Splash — Splash Tags. These are ColdFusion custom tags that extend ColdFusion and HTML to work with Splash. Here’s a simple example: the <s:title /> tag. This tag just retrieves the page’s title from the page object and inserts it in place of the tag. So, in your layout, you would typically have something like:

<title><s:title /></title>

The pages title information from the database is then easily inserted into the HTML title tag!

There are a lot more tags, so see the Wiki.

Splash in Action

I recently completed the DonorUp.com website using Splash. I was really pleased with how easily I was able to get many thing to come together. So, try Splash and leave a comment to let me know how you like it!

CFWheels, ColdFusion, Splash CMS , ,

Learning CFWheels — Debugging

February 24th, 2010

CFWheels has some great documentation and examples, but there is still a small learning curve. As you are getting going, it helps to have a few debugging tips. So, keep reading …

On the CFWheels Google Group, Cathy recently asked about the sendEmail() function. This is a pretty good example to show you some debugging tips.

sendEmail() wraps the cfmail tag. Here’s some more information:

CFWheels on sending email.

This all looks pretty straightforward, but what do you do if it’s not working?

First, setup a test view page. Go to the Wheels views folder and add a new folder called test. Then create a new file called index.cfm in the test folder. The path should be /views/test/index.cfm.

In the index.cfm file you just create, put the following:


1
2
3
4
5
6
<cfset
    set(functionName="sendEmail",
    server="yourServer",
    username="yourUsername",
    password="yourPassword")
>

This will trigger the sendEmail() function. You can access the test page at http://localhost/index.cfm/test. But, if you go to this page, you’ll get an error because we didn’t create myemailtemplate, yet. So, make another CFM page in /views/test/ called myemailtemplate.cfm. The content can be anything you want. Something like “Test email” is fine.

Wheels knows you are in the Test controller, so it looks for templates in the /views/test folder. Wait a minute! You never said anything about creating a controller. That’s one of the cool things about Wheels. Even without a controller, it will still show you the view page, and things still work!

Now, go back to the test page at http://localhost/index.cfm/test. If everything is working, you should get an email message. If it’s not working, you can put other stuff in your test page. Try these out:

  • <cfdump var=”#params#”> will show you the params structure with your actions, controller, data you’re passing, etc.
  • <cfdump var=”#wheels#”> will show information on your filters.
  • <cfdump var=”#application.wheels#”> will show all the wheels settings, functions, routes — All kinds of cool things.

Now sendEmail() is a little trickier. It uses ColdFusion’s <cfmail> tag. Put this in your /views/test/index.cfm file:


1
2
3
4
5
<cfmail from="me@mydomain.com"
   to="me@mydomain.com"
   subject="Test Message">
  This is a test
</cfmail>

If this won’t work, then it’s your server configuration, not Wheels. You may have to specify your server name or login information. That’s pretty easy, too. Just put the following in your config/settings:


1
2
3
4
5
6
<cfset
    set(functionName="sendEmail",
    server="yourServer",
    username="yourUsername",
    password="yourPassword")
>

I hope this helps!

CFWheels, ColdFusion

onError Handling for CFWheels and Splash CMS

February 4th, 2010

For most websites it’s usually a good idea to have error pages that have user-friendly error messages that are styled to look like the rest of the site.  Also, you may want to send yourself an eMail when an error happens. Read on to see how to make this work.

For the DonorUp website, I used CFWheels and the Splash CMS. Once I knew the tricks, it turned out to be really easy to make this work. So, I decided to write a post to explain what you need to know.

Typically, in ColdFusion, you add an onError() method to your Application.cfc file. Wheels gives you various hooks into Application.cfc, but Wheels already has an onError() method. So, you can’t add another one! Fortunately, Wheels has an easy way to handle most errors.

How to send error messages from CFWheels

All you have to do to get Wheels to send error message emails  is add the following into your /config/settings.cfm file:

<cfset set(sendEmailOnError = true)>
<cfset set(errorEmailAddress = “you@yourServer.com”)>

Now, whenever there’s an error, you’ll get a really nice email with all the troubleshooting info you’ll need. Easy!

How to setup a custom error page in CFWheels or Splash

As part of its built-in error handling, Wheels runs the file at /events/onerror.cfm. Just put a redirect to your error page at the top of onerror.cfm and you’re done:

<cfset redirectTo(route=”viewer”, slug=”error-page”)>

In my case, I went into the Splash CMS admin and added a page called Error Page. This way, the page is automatically styled to match the rest of the site. The error page apologizes to the user for the error, and let’s them know I am going to fix it!

When Wheels does its error handling, it will run /events/onerror.cfm, and the redirectTo() will send them to my error page! If you aren’t running Splash, you could just use the other arguments of redirectTo() to send them to any controller and action.

You can also put your own HTML or CFML code in onerror.cfm, but I like doing it this way better as it uses all the layouts and styling of my site!

Please leave me a comment if you like this approach or have other ideas!

CFWheels, ColdFusion, Splash CMS ,

Adventures in Mura — Customizing a Site

October 29th, 2009

Mura has a lot of interesting capabilities. However, the documentation is a little sparse.

Recently, I have been customizing a Mura site, so I thought I’d document some of the key things you need to know!

1 – Create a New Site to Customize

When initially installed, Mura automatically creates the  “Default” site. But, don’t customize this site. Make a new site and customize it. This way, you can still do Mura updates without overwriting your customizations.

  • Login to your admin area
  • Go to Site Settings -> Add New Site. (Site Settings is in the upper right of the admin screen.)
  • Name the site whatever you want. For example, you might call it MySite.
  • Now, when you go to customize things, don’t look in the Default folder. Instead find the MySite folder.
  • If you want MySite to come up automatically when you go to www.YourDomain.com, click on Site Settings. Then, use the Order drop downs to set MySite to 1.

2 – Customize /MySite/includes/

Much of what you’ll want to customize is in the /MySite/Includes/ directory. Here are some things you might want to customize:

  • If you are using a theme like Merced, customize the style sheet at /MySite/includes/themes/merced/css/site.css. It’s a good idea not to change the other style sheets. Just override the style in site.css. More Info from Mura …
  • Again, if you’re using Merced or another theme, customize the templates at /MySite/includes/themes/merced/templates/.  Don’t forget to look in the /inc folder for the header and footer includes. More Info from Mura …

3 – Change the behavior of Display Objects

You can change how the Display Objects work! For many Display Objects, you can just copy the display object, put it in /MySite/includes/display_objects/custom/ and modify your copy. I wanted to add a download link to the images in the image gallery, so it was more complicated. Matt Levine of Mura advised me to:

  • Go get /MySite/includes/eventHandler.cfc and add a new onGalleryBodyRender function (See below).
  • Create a new directory named gallery at /MySite/includes/display_objects/custom/gallery. Into this new directory, copy index.cfm from /default/includes/display_objects/gallery/index.cfm. Now we have a copy of the gallery file to customize, so customize your heart out!
  • Stay in /gallery/index.cfm. Find the references to getSite() and queryPermFilter() method calls. Change these to renderer.getSite() and renderer.queryPermFilter().
  • Still in /gallery/index.cfm, change the template path in <cfinclude template=”../dsp_nextN.cfm”>. The new path should be ../../../dsp_nextN.cfm.
  • Reload the app either by clicking Reload Application in the admin, or adding ?appreload to the end of the url. A lot of the objects are loaded when the application starts, so I found it’s a good idea to reload after making changes.

Here’s the code for the updated eventHandler.cfc:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre>
<cffunction name="onGalleryBodyRender" output="true" returntype="void">
<cfargument name="event">
<cfset var renderer=event.getContentRenderer()>
<cfsilent>
<cfset renderer.loadShadowBoxJS() />
<cfset renderer.addToHTMLHeadQueue("custom/gallery/htmlhead/gallery.cfm")>
<cfif not event.valueExists('galleryItemID')><cfset event.setValue('galleryItemID','')></cfif>
</cfsilent>

<!--- When you override default output you need to run content throught the renderer.setDynamicContent() method to process [mura] tag calls--->
<cfoutput>#renderer.setDynamicContent(event.getValue('contentBean').getBody())#</cfoutput>

<!--- Now include the customized display object --->
<cf_CacheOMatic key="portalBody#event.getValue('contentBean').getcontentID()##event.getValue('startRow')##event.getValue('galleryItemID')#" nocache="#event.getValue('r').restrict#">
<cfinclude template="display_objects/custom/gallery/index.cfm">
</cf_CacheOMatic>

</cffunction>
<pre>

I hope this helps someone get started with Mura! If you have suggestions for improving this information or just have a question, please leave a comment.

ColdFusion, Mura ,

CFWheels — Using Layouts and Stylesheets

September 6th, 2009

On Page 73 of Head First Rails, we need to add a design for the meBay site.

Just like Rails, CFWheels supports layouts to create a master template and to avoid repeating yourself.

For our simple app, we could just work with the default layout located at /views/layout.cfm. But, to follow the book, let’s create a controller-specific layout at: /views/ads/layout.cfm. So, this layout.cfm in the /view/ads/ subdirectory will only be used for views associated with the ads controller.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
</pre>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<cfoutput>
<title>Ads: #params.action#</title>
#stylesheetLinkTag("default")#
</cfoutput>
</head>
<body>
<cfoutput>
<div id="wrapper">
<div id="header">
<div>
<h1>MeBay</h1>
<ul id="nav">
<li>#linkTo(text="All Ads", route="adsNoKey")#</li>
</ul>
</div>
</div>

<div id="content">
#contentForLayout()#
</div>
<div id="clearfooter"></div>
</div>
<div id="footer"></div>
</cfoutput>
</body>
</html>
<pre>

Most of this code is HTML boilerplate. #params.action# inserts the name of the current action in the Title tag. The params structure is always passed from the controller to the view. It includes the name of the action, variables, etc. You can always cfdump it out if you want to see what all is in there.

#stylesheetLinkTag(“default”)# uses another CFWheels helper function. By convention, stylesheets are located in the /stylesheets directory. So this function builds the link to our stylesheet named default.css. Download the code for Chapter 2 from the Head First Rails website, and get default.css from the /public/stylesheets/ folder. In CFWheels, put default.css in your /stylesheets folder. If you have trouble with the stylesheet, make sure all the images references are correct. If your web server configuration is different, you might need to adjust the paths.

On line 16, we’ve setup a link to our index action.

On line 22, you see #contentForLayout()#. This is where CFWheels puts the content from the other view pages — show.cfm and index.cfm. It’s the equivalent of <%= yield %> in Rails.

That’s it! Now we have a pretty, styled meBay application. Visit http://localhost/index.cfm/ads/ and see how pretty things look.

Next, it’s on to Chapter 3. In software development, things always change. And, now meBay wants to let people post ads online!

CFWheels, ColdFusion

CFWheels — Adding a Custom Index Page

September 6th, 2009

Starting on Page 73 of Head First Rails, we need to add an index page so that people can find the pages they want!

First, let’s add a new route so that http://localhost/index.cfm/ads/ goes to the new index action we’ll add in a minute.

Open up /config/routes.cfm, and change it to:


1
2
3
4
5
6
</pre>
<cfset addRoute(name="ads", pattern="/ads/[key]", controller="ads", action="show")>
<cfset addRoute(name="adsNoKey", pattern="/ads/", controller="ads", action="index")>
<cfset addRoute(name="catchall", pattern="[path]", controller="redirect", action="index")>
<cfset addRoute(name="home", pattern="", controller="redirect", action="index")>
<pre>

Notice the new route on line 2: <cfset addRoute(name=”adsNoKey”, pattern=”/ads/”, controller=”ads”, action=”index”)>. CFWheels checks the routes in order. So, if the URL pattern matches /ads/[key], it will go to the show action. But, if the key isn’t there, it matches the /ads/ pattern and goes to the new index action.

Now, we need to add an index action to the controller and then an index.cfm view. Open up /controllers/Ads.cfc and add the new index function. Leave the show function alone.


1
2
3
4
5
6
7
</pre>
<!--- ads/index --->
<cffunction name="index">
<cfset ads = model("Ad").findAll()>
<cfdump var="#ads#"><cfabort>
</cffunction>
<pre>

Notice the that we set ads = model(“Ad”).findAll().  This tells Wheels, to go get the Ad model, and findAll the data — Pretty Powerful! The data comes back as a ColdFusion query object.

For testing, put the <cfdump>line  in your controller, and send your browser to:  http://localhost/index.cfm/ads/. You’ll see the query dumped out in all its glory! This is a pretty good debugging trick. Add a <cfdump> to your controller to see what variables and data the controller is passing to the view. Remove the <cfdump> line, and let’s go create the view.

Go create /views/ads/index.cfm:


1
2
3
4
5
6
7
8
</pre>
<h1>All Ads</h1>
<ul>
<cfoutput query="ads">
<li>#linkTo(text="#ads.name#", route="ads", key="#ads.id#")#</li>
</cfoutput>
</ul>
<pre>

Pretty simple! Specifying the query attribute in <cfoutput> makes this just like a <cfloop>. You end up with a bunch of List Items (<li>) — One for each record in the query we got from the controller.

linkTo() is another cool Wheels helper function. You could just use an <a> tag. However, using the linkTo() function is a best practice because it makes your application more portable. We specified the “ads” route in the function. If, later on, we changed our subfolders or URL rewriting, everything would still work.

That’s it. Send your browser to: http://localhost/index.cfm/ads/ and you should see a list of ads. Each ad will have a link that takes you to the show action and displays the ad.

CFWheels, ColdFusion

CFWheels — Fixing the Controller and View

August 30th, 2009

Last time, we setup our route, and now if you go to: http://localhost/index.cfm/ads/3, you won’t get an error. But, just like on Page 63 of Head First Rails, the ads are blank and the page is kind of boring — There’s no data.

First, we need to fix our controller at /controllers/Ads.cfc. Make sure your show function looks like:


1
2
3
4
5
6
</pre>
<cffunction name="show">
<!--- Find the record --->
<cfset ad = model("Ad").findByKey(params.key)>
</cffunction>
<pre>

When Wheels created the model, it automatically adds the findByKey method. All we have to do is tell it which key we want, and params.key has the key value!

We still need to fix /views/ads/show.cfm to display the data. Change this file to:


1
2
3
4
5
6
7
8
9
10
</pre>
<cfoutput>
<p><b>Name:</b>#ad.name#</p>
<p><b>Description:</b>#ad.description#</p>
<p><b>Price:</b>#ad.price#</p>
<p><b>Seller Id:</b>#ad.seller_id#</p>
<p><b>Email:</b>#ad.email#</p>
<p><img src="#ad.img_url#"/></p>
</cfoutput>
<pre>

Pretty neat. Just put the values in the view and wrap it up in a <cfoutput> tag! Wheels handles the hard part of getting the data from the database into the model.

Go back to: http://localhost/index.cfm/ads/3, and you’ll see that the data is now being correctly displayed.

CFWheels, ColdFusion

CFWheels — How to Setup and Use Routes

August 30th, 2009

Routes offer a way to map web URLs to specific controllers in your application. It’s one place where you might use configuration in CFWheels.

There’s a good section in the CFWheels docs on Using Routes.  But, I’m going to continue following along with the examples in Head First Rails, starting on page 56.

If you try a URL like this: http://localhost/index.cfm/ads/3, Wheels will give you an error: Could not find the view page for the ’3′ action in the ‘ads’ controller. That’s because, Wheels is looking for the Ads controller with the “3″ action. Rails would complain that there is no action (Method in the Ads controller) called ’3′. But, Wheels is smarter and just goes straight to the view. We don’t have a ’3′ method in Ads.cfc, but Wheels still tries to load a view from /views/ads/3.cfm. The file isn’t there, so it throws an error.

Setting up a Route will let us fix this! Open up /config/routes.cfm. It defaults to something like:


1
2
3
</pre>
<cfset addRoute(name="home", pattern="", controller="wheels", action="congratulations")>
<pre>

Did you ever wonder how you got to that nice congratulations page when you just go to: http://localhost/? What happens is that our route, the “home” route, says, that if the URL pattern is “” (Blank String), Wheels should go the the wheels controller, and run the action congratulations.

Take a peek at /controllers/Wheels.cfc. Sure enough, there is a congratulations method that loads up info on the current version of Wheels. And, then of course, it looks for the view in /views/wheels/congratulations.cfm. The file is already there as part of the default Wheels installation. If you open it up, you can see the HTML code including the place where it inserts the version information Wheels got from the controller.

The default routes.cfm file is nice, but lets make some changes!


1
2
3
4
5
</pre>
<cfset addRoute(name="ads", pattern="/ads/[key]", controller="ads", action="show")>
<cfset addRoute(name="catchall", pattern="[path]", controller="redirect", action="index")>
<cfset addRoute(name="home", pattern="", controller="redirect", action="index")>
<pre>

It’s important to understand that Wheels goes through the routes in order from top to bottom. As soon as it finds a match, it goes to the appropriate controller. Here’s how you interpret this route.cfm:

  • Ads. If the URL pattern looks like: http//localhost/index.cfm/ads/3, go to the show action in the ads controller. Did you notice the pattern includes [key]? This tells Wheels to set the key parameter to whatever is in the URL — 3 in this case.
  • Catchall. If the URL doesn’t match the Ads pattern, Wheels will try the next pattern. This pattern matches [path]. In other words, it matches anything, and puts the value in the path parameter. Actually, it doesn’t put everything in the path paramter — Just the part before the next slash, “/”. http//localhost/index.cfm/xxx/yyy/zzz/3 will only have “xxx” in the path parameter. A route like this is a good one to add to catch any unknown URLs a user might enter — Sort of like a 404 Error page.
  • Home. If the URL pattern  is blank, we’ve got one more route to cover that case. Remember, the pattern is just the stuff that comes after http//localhost/index.cfm/.

Ultimately Routes just offer a convenient way to map a URL to a controller. They are useful for having prettier URLs that make more sense to the users.  You can always use query params in your URL and completely bypass routes. This URL, http://localhost/index.cfm?controller=ads&action=show&key=3 directly specifies the controller and action, so there’s no need for Wheels to check the route!

CFWheels, ColdFusion