Hello! For some reason, this *very* old blog post gets a lot of traffic. Like an insane amount. If you don't mind, send me a quick email (raymondcamden@gmail.com), or DM on Twitter (@raymondcamden), telling me how you got here. I'm just incredibly curious as to where the traffic is coming from. Thank you! First person to answer the mystery gets mega brownie points!

Earlier today Yahoo and Google announced their collaboration on Sitemaps.org. Sitemaps provide a way to describe to a search engine what pages make up your web site. I've had sitemap support in BlogCFC for a while, but today I wrote a little UDF you can use to generate sitemap xml. It will take either a list of URLs or a query of URLs. Enjoy. I'll post it to CFLib later in the week.

<cffunction name="generateSiteMap" output="false" returnType="xml">
	<cfargument name="data" type="any" required="true">
	<cfargument name="lastmod" type="date" required="false">
	<cfargument name="changefreq" type="string" required="false">
	<cfargument name="priority" type="numeric" required="false">
	
	<cfset var header = "<?xml version=""1.0"" encoding=""UTF-8""?><urlset xmlns=""http://www.sitemaps.org/schemas/sitemap/0.9"">">
	<cfset var result = header>
	<cfset var aurl = "">
	<cfset var item = "">
	<cfset var validChangeFreq = "always,hourly,daily,weekly,monthly,yearly,never">
	<cfset var newDate = "">
	<cfset var tz = getTimeZoneInfo().utcHourOffset>
	
	<cfif structKeyExists(arguments, "changefreq") and not listFindNoCase(validChangeFreq, arguments.changefreq)>
		<cfthrow message="Invalid changefreq (#arguments.changefreq#) passed. Valid values are #validChangeFreq#">
	</cfif>

	<cfif structKeyExists(arguments, "priority") and (arguments.priority lt 0 or arguments.priority gt 1)>
		<cfthrow message="Invalid priority (#arguments.priority#) passed. Must be between 0.0 and 1.0">
	</cfif>
	
	<!--- reformat datetime as w3c datetime / http://www.w3.org/TR/NOTE-datetime --->
	<cfif structKeyExists(arguments, "lastmod")>			
		<cfset newDate = dateFormat(arguments.lastmod, "YYYY-MM-DD") & "T" & timeFormat(arguments.lastmod, "HH:mm")>
		<cfif tz gte 0>
			<cfset newDate = newDate & "-" & tz & ":00">
		<cfelse>
			<cfset newDate = newDate & "+" & tz & ":00">
		</cfif>		
	</cfif>
	
	<!--- Support either a query or list of URLs --->
	<cfif isSimpleValue(arguments.data)>
		<cfloop index="aurl" list="#arguments.data#">
			<cfsavecontent variable="item">
<cfoutput>
<url>
	<loc>#xmlFormat(aurl)#</loc>
	<cfif structKeyExists(arguments,"lastmod")>
	<lastmod>#newDate#</lastmod>
	</cfif>
	<cfif structKeyExists(arguments,"changefreq")>
	<changefreq>#arguments.changefreq#</changefreq>
	</cfif>
	<cfif structKeyExists(arguments,"priority")>
	<priority>#arguments.priority#</priority>
	</cfif>
</url>
</cfoutput>
			</cfsavecontent>
			<cfset item = trim(item)>
			<cfset result = result & item>
		</cfloop>
		
	<cfelseif isQuery(arguments.data)>
		<cfloop query="arguments.data">
			<cfsavecontent variable="item">
<cfoutput>
<url>
	<loc>#xmlFormat(url)#</loc>
	<cfif listFindNoCase(arguments.data.columnlist,"lastmod")>
		<cfset newDate = dateFormat(lastmod, "YYYY-MM-DD") & "T" & timeFormat(lastmod, "HH:mm")>
		<cfif tz gte 0>
			<cfset newDate = newDate & "-" & tz & ":00">
		<cfelse>
			<cfset newDate = newDate & "+" & tz & ":00">
		</cfif>		
		<lastmod>#newDate#</lastmod>
	</cfif>
	<cfif listFindNoCase(arguments.data.columnlist,"changefreq")>
	<changefreq>#changefreq#</changefreq>
	</cfif>
	<cfif listFindNoCase(arguments.data.columnlist,"priority")>
	<priority>#priority#</priority>
	</cfif>
</url>
</cfoutput>
			</cfsavecontent>
			<cfset item = trim(item)>
			<cfset result = result & item>
		
		</cfloop>
	</cfif>
	
	<cfset result = result & "</urlset>">
	
	<cfreturn result>
	
</cffunction>