Using ColdFusion to Generate Meta Keywords and Description For Mura CMS

As with most content management systems, Mura CMS offers users the ability to enter a "summary" and "keywords" for each page (among several other options). The problem is, many users fail to utilize these fields. So I whipped up a couple of simple custom display objects to address this problem.

The meta keyword generator will read the main "content" of the page, parse it and then dynamically create a unique listing of keywords. I also use a custom list of keywords to delete common keywords such as "a, in, the," etc., which can easily be modified. This makes for good SEO (search engine optimization) too since you're actually generating keywords based on the actual contents of the page! Let's save the following file as "[siteid]/includes/display_objects/custom/dspMetaKeywordGenerator.cfm"


<cfsilent>
<!---

    Document:        dspMetaKeywordGenerator.cfm
    Version:        20091023.01
    Author:            Stephen Withington | www.stephenwithington.com
    
    Purpose:        I generate meta keywords based on the body content.
    
    Instructions:    Assuming you save this file to:
                    "[siteid]/includes/display_objects/custom/dspMetaKeywordGenerator.cfm"
                    
                    Locate your current meta keywords tag and replace with the following code:
        
                    <cfif len(trim(event.getContentRenderer().getMetaKeywords()))>
                        <meta name="keywords" content="#HTMLEditFormat(event.getContentRenderer().getMetaKeywords())#" />
                        <cfelse>
                        #event.getContentRenderer().dspInclude('display_objects/custom/dspMetaKeywordGenerator.cfm')#
                    </cfif>
                    
                    Typically, the meta keywords tag is found in this file:
                    "[siteid]/includes/themes/[themeName (i.e., "merced")]/templates/inc/html_head.cfm"
                    
    Notes:            Currently ONLY reads the body content and does not take any other content
                    into consideration. (i.e., content objects, etc.)

                    META KEYWORD GENERATOR PROCESS
                    Take the body content then:
                    1.    remove html
                    2.    remove puncuation
                    3.    remove whitespace, line breaks and convert to a list
                    4.    remove duplicate words
                    5.    remove common words (i.e., a, an, the, etc.)
                        - list can be modified in the variable "commonWords" below.
                    6.    sort the list (not necessary, but useful)
    
    Revision Log:    
    20091005.01 - sjw - first draft.
    20091023.01 - sjw - updated mura methods to reflect current best practice: event.getContentRenderer() and event.getContentBean() vs. renderer and request.contentbean, etc.

--->


<!--- LIST OF COMMON WORDS TO BE REMOVED --->
<cfset commonWords = "a, also, an, and, and, are, as, at, be, but, by, for, from, had, have, he, his, i, in, is, it, of, on, or, that, the, they, this, to, too, was, what, who, with" />

<!--- GRAB THE BODY CONTENT --->
<cfset str = event.getContentBean().getBody() />

<!--- helper functions from CFLib.org --->
<cfscript>
/**
* Case-insensitive function for removing duplicate entries in a list.
* Based on dedupe by Raymond Camden
*
* @param list List to be modified. (Required)
* @return Returns a list.
* @author Jeff Howden (cflib@jeffhowden.com)
* @version 1, July 2, 2008
*/

function listDeleteDuplicatesNoCase(list) {
var i = 1;
var delimiter = ',';
var returnValue = '';
if(ArrayLen(arguments) GTE 2)
    delimiter = arguments[2];
    list = ListToArray(list, delimiter);
    for(i = 1; i LTE ArrayLen(list); i = i + 1)
    if(NOT ListFindNoCase(returnValue, list[i], delimiter))
        returnValue = ListAppend(returnValue, list[i], delimiter);
    return returnValue;
}

/**
* Delete items from a list.
*
* @param variable An item, or a list of items, to remove from the list. (Required)
* @param qs The actual list to parse. Can be blank. (Optional)
* @return Returns a string.
* @author Alessandro Chisari (ruchizzy@hotmail.com)
* @version 1, May 17, 2006
*/

function listdelete(variable){
//var to hold the final string
var string = "";
//vars for use in the loop, so we don't have to evaluate lists and arrays more than once
var ii = 1;
var thisVar = "";
var thisIndex = "";
var array = "";
var qs = "";
if(arrayLen(arguments) GT 1)
qs = arguments[2];
//put the query string into an array for easier looping
array = listToArray(qs,",");
//now, loop over the array and rebuild the string
for(ii = 1; ii lte arrayLen(array); ii = ii + 1){
thisIndex = array[ii];
thisVar = thisIndex;
//if this is the var, edit it to the value, otherwise, just append
if(not listFindnocase(variable,thisVar))
string = listAppend(string,thisIndex,",");
}
//return the string
return string;
}
</cfscript>

<cfif len(trim(str))>
    <!--- 1. remove html (using built-in mura method) --->
    <cfset str = event.getContentRenderer().stripHTML(str) />
    <!--- 2. remove punctuation (this regex ain't pretty, but it works) --->
    <cfset str = REReplace(str, "[;\\/:""*?<>|\!\+\-\=\.`\##\&_\(\)\[\]\%\^\$\@~\',\{\}]+", "", "ALL") />

    <!--- 3. remove whitespace, line breaks and convert to a list --->
    <cfset str = REReplace(str, "\s|\r?\n", ",", "ALL") />
    <!--- 4. remove duplicate words --->
    <cfset str = listDeleteDuplicatesNoCase(str) />
    <!--- 5. remove common words --->    
    <cfset str = listdelete(commonWords,str) />
    <!--- 6. sort the list --->
    <cfset str = listSort(lcase(str), "text") />
</cfif>

</cfsilent>
<cfoutput><meta name="keywords" content="#str#" /></cfoutput>

The meta description generator will also read the main "content" of the page and grab the first twenty-five (25) words to automatically create the meta description. This also makes for good SEO since the description matches what's actually found on the page. Let's save the following file at "[siteid]/includes/display_objects/custom/dspMetaDescriptionGenerator.cfm"


<cfsilent>
<!---

    Document:        dspMetaDescriptionGenerator.cfm
    Version:        20091023.01
    Author:            Stephen Withington | www.stephenwithington.com
    
    Purpose:        I generate a meta description based on the body content.
    
    Instructions:    Assuming you save this file to:
                    "[siteid]/includes/display_objects/custom/dspMetaDescriptionGenerator.cfm"
                    
                    Locate your current meta description tag and replace with the following code:
        
                    <cfif len(trim(event.getContentRenderer().getMetaDesc()))>
                        <meta name="description" content="#HTMLEditFormat(event.getContentRenderer().getMetaDesc())#" />
                        <cfelse>
                        #event.getContentRenderer().dspInclude('display_objects/custom/dspMetaDescriptionGenerator.cfm')#
                    </cfif>

                    Typically, the meta description tag is found in this file:
                    "[siteid]/includes/themes/[themeName (i.e., "merced")]/templates/inc/html_head.cfm"
                    
    Notes:            Currently ONLY reads the body content and does not take any other content
                    into consideration. (i.e., content objects, etc.)

                    META DESCRIPTION GENERATOR PROCESS
                    Take the body content then:
                    1.    remove html
                    2.    remove whitespace, line breaks
                    3.    since Google will cut off anything more than
                        155(roughly) characters, let's limit this to the first 25 words.
    
    Props:            Ben Nadel's Post "Displaying A Blog Teaser":
                    http://www.bennadel.com/index.cfm?dax=blog:1718.view
                    John Whish's (www.aliaspooryorik.com/blog/) comments on Ben's Post above.
    
    Revision Log:    
    20091005.01 - sjw - first draft.
    20091023.01 - sjw - updated mura methods to reflect current best practice: event.getContentRenderer() and event.getContentBean() vs. renderer and request.contentbean, etc.
    
--->


<!--- GRAB THE BODY CONTENT --->
<cfset str = event.getContentBean().getbody() />

<cfif len(trim(str))>
    <!--- 1. remove html (using built-in mura method) --->
    <cfset str = event.getContentRenderer().stripHTML(str) />
    <!--- 2. remove whitespace, line breaks and replace with a space between each word --->
    <cfset str = REReplace(str, "[\s|\r?\n]+", " ", "ALL") />    
    <!--- 3. limit to the first 25 words --->
    <cfset javaArray = CreateObject("java","java.util.Arrays") />
    <cfset wordArray = javaArray.copyOf(str.Split( " " ), 26) />
    <cfset str = ArrayToList(wordArray, " ") />
</cfif>

</cfsilent>
<cfoutput><meta name="description" content="#trim(str)#" /></cfoutput>

How To Use

Since there may be users who actually do use the description and/or keywords fields in the admin area of Mura CMS, you want to be sure to check for that first. So, all we need to do is locate where the meta tags are being displayed at, and then replace with some simple code. In most installations, the meta tags can be found in this file "[siteid]/includes/themes/[themeName (i.e., "merced")]/templates/inc/html_head.cfm."


<cfif len(trim(event.getContentRenderer().getMetaDesc()))>
    <meta name="description" content="#HTMLEditFormat(event.getContentRenderer().getMetaDesc())#" />
    <cfelse>
    #event.getContentRenderer().dspInclude('display_objects/custom/dspMetaDescriptionGenerator.cfm')#
</cfif>

<cfif len(trim(event.getContentRenderer().getMetaKeywords()))>
    <meta name="keywords" content="#HTMLEditFormat(event.getContentRenderer().getMetaKeywords())#" />
    <cfelse>
    #event.getContentRenderer().dspInclude('display_objects/custom/dspMetaKeywordGenerator.cfm')#
</cfif>

Hope this helps!

Outlines of My BFusion 2009 Presentations

Listed below are outlines of the sessions I'll be presenting at BFusion 2009:

1. Getting Started with Mura CMS

Intermediate Track, hands-on, 90-minutes

  • Installing Mura CMS
  • Creating your first site
  • Creating your first form
  • Creating your first Mura component
  • Setting up navigation
  • Creating a custom 404 page
  • Exploring built-in features & objects
  • Exploring Mura templates & themes

2. Integrating Your Custom Design with Mura CMS

Intermediate Track, hands-on, 90-minutes

  • Exploring Mura templates & themes
  • Integrating your custom CSS & HTML
  • Creating Mura components
  • Creating Feeds/Indexes
  • Creating Custom Feeds/Indexes

Software Requirements / Files

Attendees will be required to have the following installed on their computers:

 

MySpace Can Update Your Twitter Status ... Who Cares?

MySpace has announced users can now automatically sync their status updates with Twitter. Is having the ability to create a "Global Social Status" (yes, you can use that ... I just made it up) really such a good thing?

Not long ago I ran across an application in Facebook that would pull in my Twitter updates and automagically update my Facebook status. I quickly learned that this was not exactly the best idea in the world (and I'll tell you why in a moment), so I'm not so certain the efforts of MySpace are going to bring about any kind of improvements in the social media communities.

Let's think about this for a minute ... if you're a friend of mine on Facebook (or MySpace) AND you follow me on Twitter ... do you really want to read my status updates everywhere you go? For serious, does it make sense to "shotgun" your updates to every single social community you belong to? I think not.

Sure, there are rare occasions that you might want to do this ... but I say resist the temptation! I've found that for the most part, people I follow on Twitter are a completely different group of people than I have on Facebook. Sure, there is some overlap and that's to be expected, but the vast majority of people I know of Facebook (or MySpace) are people I've actually met, am friends with, family with, grew up with, you get the picture. Many of the people (and/or companies) I follow on Twitter are people I've never personally met (although many I hope to meet someday) but we share some commonalities ... maybe it's programming, maybe it's music, maybe it's geography. You know?

Where I'm going with this is that something I might "tweet" about may not necessarily be something I want to update my "Global Social Status" with. The audiences are completely different and often warrant their own unique message, even if the messages are very similar.

The flip side to this is if you like to Twitter ... and you know who you are ... you have the potential of overwhelming your family and friends with updates like "RT @stevewithington CF9 is the bees knees ... I have ORM, do you?" or "This site rocks: http://tinyurl.com/nv62na #muracms #mura #coldfusion #sql"

Heck, I don't know about you, but I already get a little irritated having to scroll through things like "Help Me on Mafia Wars" or the ever popular "Steve Withington took the 'What Kind of Car Are You?' quiz and got the result: You're a 1969 Bitchin' Camaro. Read more ..."

So if you're goal in life is to annoy the crap out of people in your social communities, then go right ahead and applaud the efforts of MySpace and others in their quest to become THE place to go to update your Global Social Status. In the mean time, I'll continue along, grumbling and complaining about silly things like this.

More Entries

© 2026, Stephen J. Withington, Jr.  |  Hosted by Hostek.com

Creative Commons License   |   This work is licensed under a Creative Commons Attribution 3.0 Unported License.