The Mura contentRenderer.cfc

The majority of Mura's rendering behavior occurs in a special file labeled the "contentRenderer.cfc". Mura's primary, or "Core" contentRenderer is located under:

 {context}/core/mura/content/contentRenderer.cfc

As covered in the Theme Developer's Guide, the "Core" contentRenderer also contains a plethora of helper methods, as well as settings used by Mura's display objects, all of which are frequently used by Mura developers. 

Since the "Core" contentRenderer is a "core" file, it shouldn't be modified directly. Instead, if you wish you to override any of the default settings or methods found in the "core" contentRenderer, Mura will first check the theme, and then the site for a contentRenderer.cfc. If the matching setting or method is found, it will use the custom setting or method in lieu of Mura's default "core" setting or method. You only need to define the setting(s) or method(s) you wish to override in your "Site" or "Theme" contentRenderer.

Custom Rendering Methods

In addition to overriding any of the default settings and methods found in the "Core" contentRenderer, any custom rendering methods defined in the "Site" or "Theme" contentRenderer are available via the Mura Scope. For example, if you have the following method defined in your "Site" or "Theme" contentRenderer:

public string function dspHello() {
  return "<p>Hello from dspHello!</p>";
}

You may invoke the method by simply using the following syntax:

<cfoutput>
  #m.dspHello()#
</cfoutput>

The above code would output:

<p>Hello from dspHello!</p>

Lookup Hierarchy

Mura uses the following lookup hierarchy for settings or methods found in a contentRenderer.cfc. If the setting or method is defined in the first file, Mura will use it and ignore any other identically named methods found in the remaining files.

  1. "Theme" contentRenderer
    • ../themes/{ThemeName}/contentRenderer.cfc
  2. "Site" contentRenderer
    • {context}/sites/{SiteID}/includes/contentRenderer.cfc
  3. "Core" contentRenderer
    • {context}/core/mura/content/contentRenderer.cfc

 

contentRenderer Settings

The vast majority of the contentRenderer settings allow developers to apply custom classes to Mura's modules. This allows developers to use CSS to control the style and display of Mura's modules, without having to override the rendering methods or modules themselves to achieve the desired result.

Mura allows you to override its default contentRenderer settings on a site-by-site basis. To override a setting, simply place a reference to the setting and your desired value in your "Site" or "Theme" contentRenderer.cfc.

Example

this.validateCSRFTokens = true;
this.navOffset = 0;
this.navDepthLimit = 1000;
this.navWrapperClass = 'sidebar-nav well';

Reference

A reference for Mura's "Core" contentRenderer.cfc settings is outlined below. Keep in mind the vast majority of the contentRenderer settings are specific to Mura's modules, and as such, most of these settings are merely the CSS classes that will be applied to them.

Note: The settings listed below are the "default" settings, and many of them may be overwritten in Mura's default theme. Please refer to the theme's contentRenderer.cfc file to review the theme's settings.

Setting Type Default Description
validateCSRFTokens boolean false If true, Mura will check for cross-site request forgery (CSRF) tokens to help prevent CSRF attacks.
navOffset int 0 This allows you to start standard navigation behavior at lower navigation levels. For example, this would be useful if you have a section of your site that should have its own primary navigation, such as a Member's only area with a custom layout template.
navDepthLimit int 1000 This sets the maximum depth that standard navigation will follow.
navParentIdx int 2  
navGrandParentIdx int 3  
navDepthAdjust int 0  
navSelfIdx int 1  
deferMuraJS boolean false If true, Mura will add a "defer" attribute to the script reference for mura.min.js so that the script will be executed when the page has finished parsing.
jsLib string jquery

This determines what JavaScript library Mura should use with its built-in display objects. Valid options are:

  • jquery
  • prototype
jsLibLoaded boolean false This allows developers to not rely on Mura to load the default JavaScript framework and simply add it to their theme's HTML head area.
suppressWhitespace boolean true If true, Mura will remove excess whitespace characters from CFML generated content.
longDateFormat string long This is the default long date format for the site.
shortDateFormat string short This is the default short date format for the site.
showMetaList list jpg,jpeg,png,gif,svg This is a list of file extensions that will not directly download, but instead, will render in a Mura CMS page with the "Summary" being displayed in the body area.
imageInList list jpg,jpeg,png,gif,svg This is a list of what image extensions should be shown in built in content listing display objects.
directImages boolean true This tells Mura whether to serve images indirectly through fileManager.renderImage() or create direct links.
personalization string user This allow developers to choose whether site personalizations such as ratings and favorites are attached to simple cookies or an actual Mura user. Users do not need to login in order to save cookie-based personalizations. Valid options:
  • user
  • cookie
hasEditableObjects boolean false If true, enables editable objects (Version 6.x only)
asyncObjects boolean true If true, Mura will load display objects asynchronously.
asyncRender boolean false  
queueObjects boolean true  
layoutManager boolean false If true, will allow administrators to edit display objects via the front-end of the site. (Version 7.x)
legacyObjects boolean true If false, Mura will enable the inline edit features of Mura (Version 7.x)
siteIDInURLs boolean   If a boolean value exists, it will override the settings.ini.cfm value
indexFileInURLs boolean   If a boolean value exists, it will override the settings.ini.cfm value
hashURLs boolean   If a boolean value exists, it will override the settings.ini.cfm value
enableMuraTag boolean   If a boolean value exists, it will override the settings.ini.cfm value
showAdminToolbar boolean   If true, the front end toolbar will be rendered for administrative users.
showMemberToolbar boolean   If true, the front end toolbar will be rendered for site members
showEditableObjects boolean   If true, editable display objects like components and content collections will be rendered. (Version 6.x)
showInlineEditor boolean   If true, will display the Inline Edit button on the front end toolbar for administrative users. (Version 7.x)
renderHTMLQueues boolean true If true, Mura will render the request's HTMLHeadQueue and HTMLFootQueue.
preloaderMarkup string empty string Allows developers to include a custom preloader.
bodyMetaImageSizeArgs struct {size="medium"}  
bodyMetaImageClass string thumbnail A CSS class applied to the primary associated image.
navsize int 50 An integer value to control the maximum number of navigational items to output for Mura generated navigation.
imageClass string img-thumbnail A CSS class applied to the primary associated image when displayed in a list such as a collection.
categoriesNestCheckboxClass string checkbox A CSS class applied to category checkboxes.
generalWrapperClass string well A CSS class applied to general wrapper HTML elements.

Heading Markup Settings 

When Mura outputs headings, the following settings may be used. The following settings are also used to control the heading tags used for the HTML Editor's "Format" select menu options. The defaults listed below are based on the concept that <h1> tags are reserved for the "Site Name" or logo area of the layout templates, and page titles begin with <h2> tags.

Setting Type Default
headline string h2
subHead1 string h3
subHead2 string h4
subHead3 string h5
subHead4 string h6
subHead5 string h6

Alert Markup Settings 

When Mura outputs an alert, the following settings may be used.

Setting Type Default
alertSuccessClass string alert alert-success
alertInfoClass string alert alert-info
alertWarningClass string alert
alertDangerClass string alert alert-error

Table Markup Settings 

When Mura outputs a table, the following settings may be used.

Setting Type Default
tableClass string table table-bordered table-striped
tableHeadClass string empty string
tableHeaderClass string empty string
tableBodyClass string empty string
tableRowClass string empty string
tableCellClass string empty string
tableFooterClass string empty string

Module (Display Object) Settings

The vast majority of contentRenderer settings are used to control the CSS classes for HTML markup of Mura's baked-in modules. Mura's modules and their associated settings are described below.

Navigation 

The markup for the various types of navigational modules can be found in the files located under:

{context}/core/modules/v1/nav/
Setting Type Default
navWrapperClass string sidebar-nav well
navLIClass string empty string
liHasKidsClass string empty string
liHasKidsAttributes string empty string
liCurrentClass string current
liCurrentAttributes string empty string
liHasKidsNestedClass string empty string
aHasKidsClass string empty string
aHasKidsAttributes string empty string
aCurrentClass string current
aCurrentAttributes string empty string
ulNestedClass string empty string
ulNestedAttributes string empty string
ulTopClass string navSecondary
ulPaginationClass string navSequential
ulPaginationWrapperClass string pagination
aNotCurrentClass string empty string
navCalendarWrapperClass string svCalendar
navCalendarTableClass string table table-bordered
navSequentialWrapperClass string pagination
navSequentialULClass string empty string
tagCloudWrapperClass string svTagCloud
navArchiveWrapperClass string empty string
navArchiveListClass string empty string
navBreadcrumbULClass string breadcrumb

Form

The Form module markup can be found in the files located under:

{context}/core/modules/v1/form/
Setting Type Default
formWrapperClass string well
formFieldWrapperClass string control-group
formFieldLabelClass string control-label
formInputWrapperClass string input-addon
formInputClass string form-control
formCheckboxClass string empty string
formButtonWrapperClass string btn-group
formButtonInnerClass string empty string
formButtonClass string btn btn-default
formRequiredWrapperClass string empty string

Form Builder

The Form Builder module markup can be found in the files located under:

{context}/core/modules/v1/formbuilder/
Setting Type Default
formBuilderFieldWrapperClass string empty string
formBuilderButtonWrapperClass string form-actions
formBuilderSubmitClass string btn btn-default
formBuilderFormFieldsClass string control-group
formBuilderTabHeaderClass string dropdown
formBuilderDisabledInputClass string disabled
formBuilderCheckboxClass string checkbox

Calendar

The Calendar module markup can be found in the files located under:

{context}/core/modules/v1/calendar/
Setting Type Default
calendarWrapperClass string svCalendar
calendarTableClass string table table-bordered
calendarTableHeaderClass string empty string
calendarTitleInDesc boolean true
calendarListWrapperClass string svCalendar
calendarcolors array of structs [
  {background='##3a87ad', text='white'},
  {background='blue', text='white'}
]

Comments

The Comments module markup can be found in the files located under:

{context}/core/modules/v1/comments/
Setting Type Default
commentsWrapperClass string empty string
commentSortContainerClass string empty string
commentSortWrapperClass string empty string
commentSortSelectClass string empty string
commentFormWrapperClass string empty string
commentFormClass string well
commentNewClass string btn
commentFieldWrapperClass string empty string
commentFieldLabelClass string empty string
commentInputWrapperClass string empty string
commentInputClass string empty string
commentCheckboxClass string checkbox
commentPrefsInputWrapperClass string empty string
commentSubmitButtonWrapperClass string empty string
commentSubmitButtonClass string btn
commentMoreCommentsUpClass string btn btn-default icon-arrow-up
commentMoreCommentsDownClass string btn btn-default icon-arrow-down
commentRequiredWrapperClass string empty string
commentAdminButtonWrapperClass string empty string
commentUserEmailClass string btn
commentDeleteButtonClass string btn
commentEditButtonClass string btn
commentApproveButtonClass string btn
commentThumbClass string img-polaroid
commentSpamClass string btn
commentSpamLinkClass string btn
commentClass string empty string
commentDateTimeClass string empty string
commentReplyClass string empty string
commentAwaitingApproval string empty string
commentAdminButtonWrapperClass string btn-group pull-right
commentUserEmailClass string btn btn-default btn-sm
commentDeleteButtonClass string btn btn-default btn-sm
commentEditButtonClass string btn btn-default btn-sm
commentApproveButtonClass string btn btn-default btn-sm
commentMoreCommentsContainer string well
emailLinkClass string btn
commentsLinkClass string btn
approveCommentLinkClass string btn
deleteCommentLinkClass string btn

Collections, Folders, and List/Grid Output

Collections & List/Grid module markup can be found in the files located under:

{context}/core/modules/v1/collection/
Setting Type Default
contentListImageStyles boolean true
contentListImagePadding int 20
contentListPropertyMap struct {
  containerEl={tag="div"},
  itemEl={tag="dl",class="clearfix"},
  labelEl={tag="span"},
  title={tag="dt"},
  date={tag="dt"},
  credits={tag="dd",showLabel=true,rbkey="list.by"},
  tags={tag="dd",showLabel=true,labelDelim=":",rbkey="tagcloud.tags"},
  rating={tag="dd",showLabel=true,labelDelim=":",rbkey="list.rating"},
  default={tag="dd"}
}
contentGridStyleMap struct {
  '1 Column'='mura-grid-one',
  '2 Column'='mura-grid-two',
  '3 Column'='mura-grid-three',
  '4 Column'='mura-grid-four',
  '5 Column'='mura-grid-five',
  '6 Column'='mura-grid-six',
  '7 Column'='mura-grid-seven',
  '8 Column'='mura-grid-eight',
  '9 Column'='mura-grid-nine'
}
contentGridPropertyMap struct {
  itemEl={tag="div",class="mura-item-meta"},
  labelEl={tag="span"},
  title={tag="div"},
  date={tag="div"},
  credits={tag="div",showLabel=true,labelDelim=":",rbkey="list.by"},
  tags={tag="div",showLabel=true,labelDelim=":",rbkey="tagcloud.tags"},
  rating={tag="div",showLabel=true,labelDelim=":",rbkey="list.rating"},
  'default'={tag="div"}
}
contentListWrapperDivClass string empty string
contentListItemImageLinkClass string thumbnail
folderWrapperClass string svIndex
nextNWrapperClass string empty string

Edit Profile

The Edit Profile module markup can be found in the files located under:

{context}/core/modules/v1/editprofile/
Setting Type Default
editProfileWrapperClass string empty string
editProfileFormClass string form-horizontal
editProfileFormGroupWrapperClass string control-group
editProfileFieldLabelClass string control-label
editProfileFormFieldsWrapperClass string empty string
editProfileFormFieldsClass string empty string
editProfileHelpBlockClass string help-block
editProfileExtAttributeFileWrapperClass string empty string
editProfileExtAttributeFileCheckboxClass string checkbox
editProfileExtAttributeDownloadClass string empty string
editProfileExtAttributeDownloadButtonClass string btn btn-default
editProfileSubmitButtonWrapperClass string empty string
editProfileSubmitButtonClass string btn btn-primary
editProfileSuccessMessageClass string alert alert-success

Event Reminder Form

The Event Reminder Form module markup can be found in the files located under:

{context}/core/modules/v1/event_reminder_form/
Setting Type Default
eventReminderFormWrapperClass  string empty string
eventReminderFormClass string well
eventReminderFieldWrapperClass string control-group
eventReminderFormLabelsClass string control-label
eventReminderSubmitClass string btn btn-default

Feed

The Feed module markup can be found in the files located under:

{context}/core/modules/v1/feed/

You should also review the Collections, Folders, and List/Grid Output settings above for markup information specific to the feed output itself. These settings are merely "wrapper" classes.

Setting Type Default
localIndexWrapperClass string svSyndLocal svFeed svIndex clearfix
remoteFeedWrapperClass string svSyndRemote svIndex svFeed clearfix

Login Form

The Login Form module markup can be found in the files located under:

{context}/core/modules/v1/login/
Setting Type Default
loginWrapperClass string container
loginWrapperInnerClass string row
loginFormClass string form-horizontal
forgotPasswordFormClass string form-horizontal
loginFormGroupWrapperClass string empty string
loginFormFieldLabelClass string control-label
loginFormFieldWrapperClass string empty string
loginFormFieldClass string empty string
loginFormPrefsClass string empty string
loginFormCheckboxClass string checkbox
loginFormSubmitWrapperClass string empty string
loginFormSubmitClass string btn btn-default
notRegisteredLinkClass string btn btn-primary

Search Form & Search Results

The Search Form module markup can be found in the files located under:

{context}/core/modules/v1/search/
Setting Type Default
searchFormClass string empty string
searchFormInputWrapperClass string empty string
searchFormInputClass string empty string
searchFormSubmitWrapperClass string empty string
searchFormSubmitClass string btn btn-default
searchShowNumbers int 1
searchResultWrapperClass string container
searchResultInnerClass string row
searchResultsRowClass string row
searchResultsMoreResultsRowClass string row
searchResultsListClass string svIndex
searchResultsPagerClass string pager
searchAgainRowClass string row
searchAgainInnerClass string empty string
searchAgainFormClass string empty string
searchAgainInputWrapperClass string empty string
searchAgainFormInputClass string empty string
searchAgainButtonWrapperClass string empty string
searchAgainSubmitClass string btn btn-default

User Tools

The User Tools module markup can be found in the files located under:

{context}/core/modules/v1/user_tools/
Setting Type Default
userToolsLoginWrapperClass string well clearfix
userToolsLoginFormClass string form-horizontal
userToolsFormGroupWrapperClass string empty string
userToolsLoginFormLabelClass string control-label
userToolsLoginFormInputWrapperClass string empty string
userToolsLoginFormInputClass string empty string
userToolsLoginFormFieldInnerClass string empty string
userToolsLoginFormCheckboxClass string checkbox
userToolsLoginFormSubmitClass string btn btn-default
userToolsNotRegisteredLinkClass string btn btn-primary
userToolsWrapperClass string clearfix
userToolsEditProfileLinkClass string btn btn-default
userToolsLogoutLinkClass string btn btn-default

Content Rater

The Content Rater module markup can be found in the files located under:

{context}/core/modules/v1/rater/
Setting Type Default
raterObjectWrapperClass string row clearfix
raterWrapperClass string empty string
avgRatingWrapperClass string empty string

 

The Mura [m] Tag

As covered in the Theme Developer's course, you may use "Mura Tags" when you want to output dynamic code within the HTML Editor.

Developers need to use Mura Tags because hash tags (#) are ignored when entered as text in the HTML Editor. Hence, you can only render a CFML variable, or function call.

Globally Enable/Disable the Mura Tag

To globally enable or disable the Mura Tag, open the file located under {context}/config/settings.ini.cfm. Locate the enablemuratag key, and set the value to true to enable the Mura Tag, or false to disable the Mura Tag.

If enablemuratag is set to false, the Mura tag button will not appear on any HTML Editors. In addition, the Mura Tags will not be parsed as CFML, and will only display as a string of text, as it was entered into the HTML Editor.

Enable/Disable the Mura Tag on a Site-by-Site Basis

If you wish to enable or disable the Mura Tag on a site-by-site basis, you may edit the Site or Theme contentRenderer.cfc file located under:

  • Site contentRenderer.cfc
    • {context}/sites/{SiteID}/contentRenderer.cfc
  • Theme contentRenderer.cfc
    • ../themes/{ThemeName}/contentRenderer.cfc

Then, add this.enablemuratag=true to enable, or this.enablemuratag=false to disable. This setting overrides the global setting described above.

Rendering Mura Tags

When you expect Mura Tags in the output, you'll want to use the m.SetDynamicContent(string) function. This function is covered under the setDynamicContent section of the Theme Developer's Guide.

Mura Modules & Display Objects

Mura's baked-in modules are managed via the front-end user interface. Modules are sometimes referred to as "display objects" because often times, that's how the module itself is used. However, a Mura module does not have to contain a "display" of any kind. Modules can be complete applications, or simply contain some custom logic that is triggered based on a desired event.

Note: If you aren't familiar with Mura's default modules (display objects), you should review the Inline Edit Display Objects section of the Content Manager's guide, before continuing in this section.

Mura includes a variety of baked-in modules (display objects) by default while offering content managers the ability to quickly and easily add modules such as Collections, Components, Containers, Forms, Navigation, and many more.

Each of Mura's modules contain some server-side logic, basic markup, styling, and sometimes include JavaScript. In this section, you'll learn how to safely modify this logic, markup, styling, and/or JavaScript, and do so without worrying about your changes getting overwritten whenever Mura's files are updated. In addition, you'll learn how to create your own, custom modules too.

Modifying Mura's Modules

Mura's base modules (display objects) are located under the following directory:

{context}/core/modules/v1/

As illustrated in the image below, there are more modules than the ones listed.

You shouldn't modify any of the files in these directories directly. If you choose to do so, you run the risk of your changes being overwritten whenever Mura is updated to the latest version.

Instead, copy the desired directory and all of its files, then paste it under one of the locations listed in the "Lookup Hierarchy" section below. Then, you can safely make your modifications without fear of losing any of your changes the next time Mura is updated.

Registering a Custom "modules" Directory

While Mura automatically scans for modules in the directories specified in the "Lookup Hierarchy" section below, you may register a custom "modules" directory using the code example below.

m.siteConfig().registerModuleDir(
  dir='/path/to/your/modules/'
);

The directory path should be a logical path to a CFML directory, and is usually registered in the onApplicationLoad() event.

Lookup Hierarchy

As mentioned under "The 'Modules' Directory" section, Mura uses the following lookup hierarchy when searching for modules, and aborts the lookup process once the target module has been located:

  • Registered Module Directory
    • {RegisteredModuleDirectory}/
    • A pre-registered module directory path. See "Registering a Custom 'Modules' Directory" section above.
  • Module
    • ../{module}/modules/
    • A nested "modules" directory nested within a known module.
  • Theme
    • ../themes/{ThemeName}/modules/
    • Theme modules are only used when the specified theme is actively assigned to a site. Keep in mind themes may be located under either the global themes directory ({context}/themes/{ThemeName}), or under a site ({context}/sites/{SiteName}/themes/{ThemeName}).
  • Site
    • {context}/sites/{SiteName}/modules/
    • Site modules are shared across all themes within the specific site.
  • Global
    • {context}/modules/
    • Global modules are shared across all sites under a single Mura instance.
  • Core
    • {context}/core/modules/v1/core_assets/modules/
    • These are the "core" modules or display objects which may be copied and placed into any of the directories above to be safely modified. 

Note: You should not edit the "core" modules directly. If you do, you run the risk of losing your edits or changes whenever you update Mura to the latest version.

Anatomy of a Module

In addition to understanding how Mura's modules are constructed, Mura developers may use the information below to create their own, custom modules.

Directory Structure

First, create a directory under a known or registered "modules" directory. For example, ../modules/mymodule/. Within the {module} directory, you may have the following files and/or directories:

File or Directory Req/Opt Description
index.cfm Optional If your module will be used as a "display object", this file will contain the body or view used by Mura for display file itself. See example "index.cfm" file section below.
config.xml.cfm Optional This is the configuration file for the module itself. This file also allows you to include custom image sizes, class extensions, and more. See example "config.xml.cfm" file section below. Also visit the Elements Of The "config.xml.cfm" File section for information about available elements and attributes.
configurator.cfm Optional This file allows developers to include a form with configuration options which appear on the module configuration panel when using the Inline Edit feature. See example "configurator.cfm" file section below.
/model/ Optional If you wish to leverage Mura ORM, the module could have its own "model" directory, which in turn could also include a "beans" and/or "handlers" directory too. See Mura ORM Configuration section for more information about the "model" directory.
/content_types/ Optional You may also include custom content types. This is useful for keeping content types directly related to specific module(s) together, in a unified directory structure. See Content Types section for more information.
/modules/ Optional You may also nest custom modules. This is useful for keeping related modules together, under one, unified module itself. One caveat is that if you choose to display the nested object on the parent object, content managers will not be able to access the nested object's configurator, if it has one. Because of this, you may wish to either omit the "contenttypes" attribute from your config.xml.cfm's <mura ...> node, or explicitly add contenttypes="" so that the nested object will not appear in the module panel's UI. If you need configurable options for the nested object, you should include the options on the parent object's configurator. To include the nested object in the view of the parent object, use the following syntax:  #m.dspObject(object='{objectName}', objectparams=objectparams)#.

Example "index.cfm" File

The example below illustrates what an "index.cfm" file could contain. However, you may include your own custom markup, code, and more.

<cfparam name="objectparams.mytext" default="" />

<cfoutput>
  <h2>My Object</h2>

  <cfif Len(objectparams.mytext)>
    <p>
      This object has a configurator, and the value of "objectparams.mytext" is:<br>
      <strong>#esapiEncode('html', objectparams.mytext)#</strong>
    </p>
  <cfelse>
    <!--- No value entered for "objectparams.mytext" --->
  </cfif>
</cfoutput>

If you wish to add any CSS or JavaScript to the browser for your module, you'll need to use MuraJS to help you. The example below leverages the loader() method to load both CSS and JavaScript. Simply add this code to your "index.cfm" file. You may have to change the path(s) to match your specific directory structure, and needs.

<!--- Add the following to your "index.cfm" file --->
<script>
  Mura(function(m) {
    m.loader()
      .loadcss(m.themepath + '/modules/myobject/my.css')
      .loadjs(
        m.themepath + '/modules/myobject/my.js',
        m.themepath + '/modules/myobject/other.js',
        function() {
          // Do something with the loaded JS, if desired
        }
      );
  });
</script>

Visit the MuraJS section to learn more about Mura.loader() capabilities.

Rendering Via JavaScript

If your module will be rendered using only JavaScript, your index.cfm file should only contain the following code:

<cfset objectparams.render="client">

Choosing this option means you'll have to load your JavaScript by using a custom event handler method, as shown below.

// ../yourmodule/model/handlers/yourhandler.cfc

component extends='mura.cfobject' {

  function onRenderStart(m) {
    // if script should be included in the <head>
    arguments.m.addToHTMLHeadQueue('<script src="/path/to/script.js"></script>');

    // OR

    // if script should be included before closing </body> tag
    arguments.m.addToHTMLFootQueue('<script src="/path/to/script.js"></script>');
  }

}

Please also see the Modules and Display Objects With Mura.js section, for more information on rendering modules via JavaScript.

Example "config.xml.cfm" File

The example below illustrates a simple example of the "config.xml.cfm" file. Visit the Elements Of The "config.xml.cfm" File section for more details on available elements and attributes.

<?xml version="1.0" encoding="UTF-8"?>
  <mura name="My Module" contenttypes="*" iconclass="mi-rebel">
    <!-- May also include other elements here -->
  </mura>

Example "configurator.cfm" File

The example below illustrates an example "configurator.cfm" file.

<cfparam name="objectparams.mytext" default="" />

<cfoutput>
    <div class="mura-control-group">
        <label class="mura-control-label">My Text</label>
        <input  type="text"
                name="mytext"
                class="objectParam"
                value="#esapiEncode('html_attr', objectparams.mytext)#" />
    </div>
</cfoutput>

Visit the Custom Module Configurators section for information on proper markup conventions.

More Information & Examples

For more information, check out the Super Fast Application Development with Mura 7 on-demand webinar. The presentation slides and code samples can be found at https://github.com/stevewithington/cfsummit-2016.

You may also be interested in checking out the Intro to Mura 7 Display Objects session from MuraCon 2017.

Mura Content Types

In addition to using some of Mura's content-related event hooks, developers can control the rendering of the body area by targeting a content's Type and Subtype. This feature also applies to any custom Class Extensions. For example, "Folder/Contacts", "Page/Contact", etc.

Mura automatically scans the following directories for custom content types:

  • {context}/themes/{ThemeName}/content_types/
  • {context}/sites/{SiteID}/themes/{ThemeName}/content_types/
  • {context}/sites/{SiteID}/content_types/
  • ../content_types/{type}/content_types/
  • ../content_types/{type}_{subtype}/content_types/

Or, you can register any directory you want by using the following syntax:

m.siteConfig().registerContentTypeDir(
  '/path/to/your/content_types/'
);

// Path is a logical path to a CFML directory
// Usually registered in onApplicationLoad();

Note: This feature only works if the layout template is using m.dspBody() to render the body area.

Control Body By Type/Subtype

You target the body's Type/Subtype by a conventional directory structure.

For example, you could target content by only its Type:

../content_types/{type}/

// If you wish to target 'Page'
../content_types/page/index.cfm

Or, you can target by both the Type, and its Subtype:

../content_types/{type}_{subtype}/

// If you wish to target 'Page/Contact'
../content_types/page_contact/index.cfm

Anatomy of a {type}_{subtype} Directory

As previously mentioned, you create a directory under a known or registered "content_types" directory by using {type}_{subtype} (e.g., ../content_types/page_contact/ or ../.content_types/component_default/, etc.). Within the {type}_{subtype} directory, you may have the following files and/or directories:

File or Directory Req/Opt Description
index.cfm Required This is the body or view used by Mura for display file itself. At a minimum, this file should contain <cfoutput>#m.renderEditableAttribute(attribute="body",type="htmlEditor")#</cfoutput>, if you wish to see any text entered into the "Content" area. See example "index.cfm" file below.
config.xml.cfm Optional This is the configuration file. This allows you to include custom image sizes, class extensions, and more. See Elements Of the "config.xml.cfm" File section for more information.
/model/ Optional If you wish to leverage Mura ORM, the content type could have its own "model" directory, which in turn could also include a "beans" and/or "handlers" directory too. See Mura ORM Configuration section for more information about the "model" directory.
/modules/ Optional You may also include custom modules. This is useful for keeping modules and/or display objects directly related to specific content types together, in a unified directory structure. See Modules section for more information. See below for information on how to output modules in your layout template.
/content_types/ Optional You may include a nested "content_types" directory. This is a great way to keep related code items together.

Example "index.cfm" File

The example below illustrates what an "index.cfm" file could contain. However, you may include your own custom markup, code, and more.

<cfoutput>
  <article class="article">
    <!--- Page Title --->
    <h2 class="article__title">#m.renderEditableAttribute(attribute='title')#</h2>

    <!--- Primary Image --->
    <cfif m.content().hasImage(usePlaceholder=false)>
      <figure class="article__image">
        <img src="#m.getURLForImage(fileid=m.content('fileid'), size='medium')#" 
             alt="#esapiEncode('html_attr', m.content('title'))#" />
      </figure>
    </cfif>

    <!--- Content --->
    <div class="article__body">
      #m.renderEditableAttribute(attribute='body', type='htmlEditor')#
    </div>
  </article>
</cfoutput>

How To Output Modules

To output a module (display object) in your custom body layout, use the following syntax:

<cfoutput>
  #m.dspObject(object='{objectName}')#
</cfoutput>

When hardcoding a module in your layout, the "Delete" button will not appear for content managers when using the "Inline Edit" mode.

Including Configurable Modules

The first thing to understand about including configurable modules in your custom body layout is there can only be one (1) module that is configurable. Whichever module you wish to be configurable should include a "objectparams" parameter, and include the "objectparams" as the value, as shown below:

<cfoutput>
  #m.dspObject(object='{objectName}', objectparams=objectparams)#
</cfoutput>

If you attempt to include multiple configurable modules using the code example above, the first module will be configurable, and all others will not. This means, when you select "Inline Edit" mode, only the first configurable module will include the pencil icon and actually be configurable.

To include additional modules, you may pass in any "objectparams" parameters as an object, as show in the example below:

<cfoutput>
  #m.dspObject(
    object='object1', 
    objectparams={param1=objectparams.param1, param2=objectparams.param2}
  )#

  #m.dspObject(object='object2', objectparams=objectparams)#
</cfoutput>

In the example above, "object2" will be the only configurable module.

JSON API

Introduction

The JSON API allows Mura CMS to be the main content creation hub within an organization, and allows developers to build their front-ends as pure JavaScript clients.

Base URL

The base URL for the API endpoints is:

https://yourDomain.com/{context}/index.cfm/_api/json/v1/

API Endpoint Reference

Method Endpoint Usage Returns
GET /{siteid}/{entityname}/{id} FindOne data
GET /{siteid}/entityname}/{ids} FindMany data
GET /{siteid}/{entityname}/new FindNew data
GET /{siteid}/{entityname}/? FindQuery data
GET /{siteid}/{entityname}/{id}/{releatedentity}/? FindRelatedEntity data
GET,POST /?method=findCalenderItems&siteid={siteid}&calendarid={calendarid}&start={start}&end={end}&format={format} FindCalendarItems data | events
POST /?method=generateCSRFTokens&siteid={siteid}&context={entityid} GenerateCSRFTokens data
POST /{siteid}/{entityname}/?csrf_token={csrf_token}&csrf_token_expires={csrf_token_expires} Save data
DELETE /{siteid}/{entityname}/{id}/?csrf_token={csrf_token}&csrf_token_expires={csrf_token_expires} Delete data
GET,POST /{siteid}/login/?username={username}&password={password} Login data
GET,POST /{siteid}/logout Logout data

Response Format

On success, the HTTP status code in the response header is 200 OK and the response body contains a data object in JSON format. On error, the header status code is an error code and the response body contains an error object.

Example Response

{
	"data": {
		"key": "value"
	}
}

Response Status Codes

The JSON API uses the following response status codes:

Status Code Description
200 OK - The request has succeeded. The client can read the result of the request in the body and the headers of the response.
400 Bad Request - The request could not be understood by the server due to malformed syntax. The message body will contain more information; see Error Handling, below.
401 Unauthorized - The request requires user authentication or, if the request included authoriation credentials, authorization has been refused for those credentials. Also, the JSON API feature may not be enabled for the site; see How To Enable, above.
403 Forbidden - The server understood the request, but is refusing to fulfill it. For example, requestor does not have permission to a requested method.
404 Not Found - The requested resource could not be found. This error can be due to a temporary or permanent condition.

Error Handling

When an error occurs, the response data attribute will not exist. The response will instead contan an error attribute.

Example Error Response

{
	"error": {
		"message": "Insufficient Account Permissions"
	}
}

Example Response Handler

$.getJSON('/index.cfm/json/v1/default/content/').then(
	function( resp ) {
		if ( 'error' in resp ) {
			//handle error
		} else {
			//do stuff
		}
	}
});

History

Feature added in version 6.2.

FindOne

Find an entity.

Endpoint

GET https://yourdomain.com/{context}/index.cfm/_api/json/v1/{siteid}/{entityname}/{id}

OR

GET https://yourdomain.com/{context}/index.cfm/_api/json/v1/?method=findone&site={siteid}&entityname={entityName}&id={id}

Request & Query Parameters

Parameter Value
context The path to where Mura CMS resides within the webroot (typically, an empty string).
siteid The SiteID of the site being searched.
entityname The entityname being searched. For example: "content", "user", "feed", etc.
id The object ID of the entity being searched for.

Example Response

The data object will contain the entity's keys and corresponding values.

{
  "data": {
    "targetparams":"",
    "path":"00000000000000000000000000000000001,2C91A3B0-E375-9383-0B05636E6926868D",
    "menutitle":"Testing",
    "releaseDate":"",
    "fileid":"",
    "responsesendto":"",
    "id":"2C91A3B0-E375-9383-0B05636E6926868D",
    "type":"Page",
    "lastupdatebyid":"AD771D5C-BE0A-D43D-47F4E201B378BD7A",
    "forceSSL":0,
    "responsemessage":"",
    "subtype":"Default",
    "remoteurl":"",
    "contenttype":"",
    "childtemplate":"",
    "keypoints":"",
    "moduleid":"00000000000000000000000000000000000",
    "inheritobjects":"Inherit",
    "searchExclude":0,
    "featureStop":"",
    "newfile":"",
    "remotesourceurl":"",
    "displayStop":"",
    "remotesource":"",
    "remotePubDate":"",
    "tags":"",
    "majorVersion":0,
    "extendautocomplete":true,
    "contentsubtype":"",
    "url":"/index.cfm/testing/",
    "sortby":"orderno",
    "displayTitle":0,
    "approvalstatus":"",
    "credits":"",
    "oldfilename":"",
    "featureStart":"",
    "siteid":"default",
    "doCache":1,
    "imagesize":"small",
    "imagewidth":"AUTO",
    "target":"_self",
    "minorVersion":0,
    "approvalgroupid":"",
    "assocfilename":"",
    "lastUpdate":"2015-01-29T15:45:51",
    "summary":"",
    "images":{},
    "template":"",
    "moduleassign":"",
    "displayStart":"",
    "isFeature":0,
    "filesize":"",
    "approvingchainrequest":false,
    "categoryid":"",
    "tcontent_id":"0",
    "isLocked":0,
    "isNav":1,
    "newstags":"",
    "orderno":1,
    "htmltitle":"Testing",
    "urltitle":"testing",
    "approvalchainoverride":false,
    "body":"",
    "requestid":"",
    "restrictgroups":"",
    "active":1,
    "metadesc":"",
    "audience":"",
    "links":{
      "site":"http://docs.getmura.com:8080/index.cfm/_api/json/v1/default?method=findOne&entityName=site&siteid=default",
      "categoryassignments":"http://cf11:8080/index.cfm/_api/json/v1/default?method=findQuery&siteid=default&entityName=contentCategoryAssign&contenthistid=2C92F953-E042-CBF6-42F66BD74A4BEC0B",
      "parent":"http://docs.getmura.com:8080/index.cfm/_api/json/v1/default?method=findOne&siteid=default&entityName=content&id=00000000000000000000000000000000001",
      "stats":"http://docs.getmura.com:8080/index.cfm/_api/json/v1/default?method=findOne&siteid=default&entityName=stats&id=2C91A3B0-E375-9383-0B05636E6926868D",
      "crumbs":"http://docs.getmura.com:8080/index.cfm/_api/json/v1/default?method=findCrumbArray&siteid=default&entityName=content&id=2C91A3B0-E375-9383-0B05636E6926868D",
      "comments":"http://docs.getmura.com:8080/index.cfm/_api/json/v1/default?method=findQuery&siteid=default&entityName=comment&contentid=2C91A3B0-E375-9383-0B05636E6926868D",
      "relatedcontent":"http://docs.getmura.com:8080/index.cfm/_api/json/v1/default?method=findRelatedContent&siteid=default&id=2C91A3B0-E375-9383-0B05636E6926868D",
      "renderered":"http://docs.getmura.com:8080/index.cfm/_api/json/v1/default/_path/testing",
      "kids":"http://cf11:8080/index.cfm/_api/json/v1/default?method=findQuery&siteid=default&entityName=content&parentid=2C91A3B0-E375-9383-0B05636E6926868D"
    },
    "restricted":0,
    "metakeywords":"",
    "nextN":10,
    "fileext":"",
    "notes":"",
    "display":1,
    "created":"2015-01-29T15:45:51",
    "contenthistid":"2C92F953-E042-CBF6-42F66BD74A4BEC0B",
    "responsedisplayfields":"",
    "expires":"",
    "imageheight":"AUTO",
    "filename":"testing",
    "relatedcontentsetdata":"",
    "sortdirection":"asc",
    "contentid":"2C91A3B0-E375-9383-0B05636E6926868D",
    "changesetid":"",
    "displayinterval":"Daily",
    "sourceiterator":"",
    "mobileExclude":0,
    "extendsetid":"",
    "remoteid":"",
    "parentid":"00000000000000000000000000000000001",
    "preserveid":"2C92F953-E042-CBF6-42F66BD74A4BEC0B",
    "title":"Testing",
    "lastupdateby":"Steve Withington",
    "approved":1,
    "extenddata":"",
    "blogtags":"",
    "responseChart":0
  }
}

History

Added in version 6.2

FindMany

Get multiple entities.

Endpoint

GET https://yourdomain.com/{context}/index.cfm/_api/json/v1/{siteid}/{entityname}/{ids}

OR

GET https://yourdomain.com/{context}/index.cfm/_api/json/v1/?method=findmany&siteid={siteid}&entityname={entityname}&ids={ids}

Request & Query Parameters

Parameter Value
context The path to where Mura CMS resides within the webroot (typically, an empty string).
siteid The SiteID of where the entity will be stored.
entityname The entity's name.
ids A comma-delimited list of entity IDs.

Example Response

If multiple entities are found, an items array will be present in the data object.

{
	"data": {
		"items": [
			{
				"id": "2C91A3B0-E375-9383-0B05636E6926868D",
				"name": "Example",
				"links": {
					"relatedentitylink1": "http://...",
					"relatedentitylink2": "http://..."
				}
			},
			{
				"id": "6C92F953-E042-CBF6-42F66BD74A4BEC0B",
				"name": "Another Example",
				"links": {
					"relatedentitylink1": "http://...",
					"relatedentitylink2": "http://..."
				}
			},

		]
	}
}

If only one entity is found, the data object will contain the entity's keys and corresponding values.

{
	"data": {
		"id": "2C91A3B0-E375-9383-0B05636E6926868D",
		"name": "Example",
		"links": {
			"relatedentitylink1": "http://...",
			"relatedentitylink2": "http://..."
		}
	}
}

History

Added in version 6.2

FindNew

Gets a new entity.

Endpoint

GET https://yourdomain.com/{context}/index.cfm/_api/json/v1/{siteid}/{entityname}/new

OR

GET https://yourdomain.com/{context}/index.cfm/_api/json/v1/?method=findnew&siteid={siteid}&entityname={entityname}

Request & Query Parameters

Parameter Value
context The path to where Mura CMS resides within the webroot (typically, an empty string).
siteid The SiteID of where the entity will be stored.
entityname The entity's name.

Example Response

{
	"data": {
		"id": "2C91A3B0-E375-9383-0B05636E6926868D",
		"name": "Example",
		"links": {
			"relatedentitylink1": "http://...",
			"relatedentitylink2": "http://..."
		}
	}
}

History

Added in version 6.2

FindQuery

Get an array of entity items.

Endpoint

GET https://yourdomain.com/{context}/index.cfm/_api/json/v1/{siteid}/{entityname}/?

OR

GET https://yourdomain.com/{context}/index.cfm/_api/json/v1/?method=findquery&siteid={siteid}&entityname={entityname}/?

Request & Query Parameters

Parameter Value
context The path to where Mura CMS resides within the webroot (typically, an empty string).
siteid The SiteID of where the entity will be stored.
entityname The entity's name. For example: ?entityname=content
fields Optional. A comma-separated listed of fields to return. For example: ?fields=title,summary,contentid
maxitems Optional. Limit the number of records to return. For example: ?maxitems=10
itemsperpage Optional. Sets the desired number of items to return for each page. For example: ?itemsperpage=3
pageindex Optional. Sets the desired page for pagination. For example: ?pageindex=2
sort Optional. Control the sort order and direction of entities by specific attributes/fields. To sort decending, prefix the attribute/field with a minus sign (-). You may explicitly use the plus sign (+) to indicate the default setting of ascending. For example, to sort by "credits" ascending, and "title" decending: ?sort=credits,-title
cachedwithin Optional. Sets the desired cache timespan in seconds. For example: ?cachedwithin=120

Custom Query Parameters

Filter results by passing an attribute name of your entity, and the value to search for. Use the star (*) to denote wildcard.

The following example assumes the entity has an attribute named title:

GET https://yourdomain.com/{context}/index.cfm/_api/json/v1/?method=findquery&siteid={siteid}&entityname={entityname}&title=about*

This should return any entities with a title attribute that starts with about, such as "about, About, About Us, About Time."

Example Response

If one or more entities are found, an items array will be present in the data object.

{
	"data": {
		"endindex": 1,
		"startindex": 1,
		"totalpages": 1,
		"totalitems": 1,
		"links": {
			"self": "http://domain/index.cfm/_api/json/v1/default/?&sort=title&entityname=content&siteid=default&fields=title,summary,contentid&itemsperpage=10&maxitems=50&method=undefined&pageIndex=1"
		},
		"itemsperpage": 10,
		"items": [
			{
				"entityname": "content",
				"images": {},
				"contentid": "00000000000000000000000000000000001",
				"siteid": "default",
				"url": "/",
				"links": {
					"renderered": "http://domain/index.cfm/_api/json/v1/default/_path/",
					"categoryassignments": "http://domain/index.cfm/_api/json/v1/default?method=findQuery&siteid=default&entityName=contentCategoryAssign&contenthistid=14CA1DCF-41A8-4D04-861AFE9D4162CD7C",
					"relatedcontent": "http://domain/index.cfm/_api/json/v1/default?method=findRelatedContent&siteid=default&entityName=content&id=00000000000000000000000000000000001",
					"crumbs": "http://domain/index.cfm/_api/json/v1/default?method=findCrumbArray&siteid=default&entityName=content&id=00000000000000000000000000000000001",
					"stats": "http://domain/index.cfm/_api/json/v1/default?method=findOne&siteid=default&entityName=stats&id=00000000000000000000000000000000001",
					"self": "http://domain/index.cfm/_api/json/v1/default/_path/",
					"comments": "http://domain/index.cfm/_api/json/v1/default?method=findQuery&siteid=default&entityName=comment&contentid=00000000000000000000000000000000001",
					"site": "http://domain/index.cfm/_api/json/v1/default?method=findOne&entityName=site&siteid=default",
					"parent": "http://domain/index.cfm/_api/json/v1/default?method=findOne&siteid=default&entityName=content&id=00000000000000000000000000000000END",
					"kids": "http://domain/index.cfm/_api/json/v1/default?method=findQuery&siteid=default&entityName=content&parentid=00000000000000000000000000000000001"
				},
				"id": "00000000000000000000000000000000001",
				"title": "Home",
				"summary": ""
			}
		],
		"pageindex": 1
	},
	"params": {
		"sort": "title",
		"entityname": "content",
		"siteid": "default",
		"fields": "title,summary,contentid",
		"itemsperpage": 10,
		"maxItems": 50,
		"pageindex": 1
	},
	"method": "findQuery",
	"apiversion": "v1"
}

History

Added in version 6.2

FindRelatedEntity

Gets a related entity.

Endpoint

GET https://yourdomain.com/{context}/index.cfm/_api/json/v1/{siteid}/{entityname}/{id}/{relatedentity}/?

OR

GET https://yourdomain.com/{context}/index.cfm/_api/json/v1/?method=findquery&siteid={siteid}&entityname={relatedentity}&entitynamefk={id}

Request & Query Parameters

Path parameter Value
context The path to where Mura CMS resides within the webroot (typically, an empty string).
siteid The SiteID of where the entity will be stored.
entityname The entity's name.
id The ID of an entity.
relatedentity The name of a related entity.
entitynamefk The ID of an entity.

Example Response

If multiple entities are found, an items array will be present in the data object.

{
	"data": {
		"items": [
			{
				"id": "2C91A3B0-E375-9383-0B05636E6926868D",
				"name": "Example",
				"links": {
					"relatedentitylink1": "http://...",
					"relatedentitylink2": "http://..."
				}
			},
			{
				"id": "6C92F953-E042-CBF6-42F66BD74A4BEC0B",
				"name": "Another Example",
				"links": {
					"relatedentitylink1": "http://...",
					"relatedentitylink2": "http://..."
				}
			},

		]
	}
}

If only one entity is found, the data object will contain the entity's keys and corresponding values.

{
	"data": {
		"id": "2C91A3B0-E375-9383-0B05636E6926868D",
		"name": "Example",
		"links": {
			"relatedentitylink1": "http://...",
			"relatedentitylink2": "http://..."
		}
	}
}

History

Added in version 6.2

FindCalendarItems

Get calendar content items.

Endpoint

GET https://yourdomain.com/{context}/index.cfm/_api/json/v1/?method=findcalendaritems&siteid={siteid}&calendarid={calendarid}&start={start}&end={end}&format={format}

Request & Query Parameters

Path parameter Value
context The path to where Mura CMS resides within the webroot (typically, an empty string).
siteid The SiteID of where the entity will be stored.
calendarid The contentid of a Mura CMS content item with the "Type" set to Calendar.
start Optional. The start date to filter by.
end Optional. The end date to filter by.
format Optional. Options are default (the default setting) or fullcalendar. This determines how the response is formatted.
categoryid Optional. Filters results by categoryid.
tag Optional. Filters results by tag.

Example "Default" Response

If multiple entities are found, an items array will be present in the data object.

{
	"data": {
    	"items": [
			{
				"contentid": "2C91A3B0-E375-9383-0B05636E6926868D",
				"title": "Event 1",
				...
			},
			{
				"contentid": "6C92F953-E042-CBF6-42F66BD74A4BEC0B",
				"title": "Event 2",
				...
			},
			...
		]
	}
}

If only one entity is found, the data object will contain the entity's keys and corresponding values.

{
	"data": {
		"contentid": "2C91A3B0-E375-9383-0B05636E6926868D",
		"title": "Event 1",
		...
	}
}

Example "FullCalendar" Response

An events array will be returned.

{
	"events": [
		{
			"contentid": "2C91A3B0-E375-9383-0B05636E6926868D",
			"title": "Event 1",
			...
		},
		{
			"contentid": "6C92F953-E042-CBF6-42F66BD74A4BEC0B",
			"title": "Event 2",
			...
		},
		...
	]
}

History

Added in version 6.2

GenerateCSRFTokens

Get a CSRF (Cross-Site Request Forgery) token. The CSRF token is required for special API methods such as delete and save.

Endpoint

GET https://yourdomain.com/{context}/index.cfm/_api/json/v1/?method=generateCSRFTokens&siteid={siteid}&context={entityid}

Request & Query Parameters

Parameter Value
context The path to where Mura CMS resides within the webroot (typically, an empty string).
siteid The SiteID of where the entity will be stored.
context The primary id of the entity currently being processed.

Example Response

{
	"data": {
		"csrf_token": "469153A8855FFA7ECB5A11BC8EB3F3C4",
		"csrf_token_expires": "42041.6270023"
	}
}

History

Added in version 6.2

Save

Save an entity.

Endpoint

POST https://yourdomain.com/{context}/index.cfm/_api/json/v1/{siteid}/{entityname}/?csrf_token={csrf_token}&csrf_token_expires={csrf_token_expires}

OR

POST https://yourdomain.com/{context}/index.cfm/_api/json/v1/?method=save&siteid={siteid}&entityname={entityname}&csrf_token={csrf_token}&csrf_token_expires={csrf_token_expires}

Request & Query Parameters

Path parameter Value
context The path to where Mura CMS resides within the webroot (typically, an empty string).
siteid The SiteID of where the entity will be stored.
entityname The entity's name.
csrf_token The csrf_token is generated by the generateCSRFTokens method.
csrf_token_expires The csrf_token_expires is generated by the generateCSRFTokens method.

Example Response

The data object will contain the entity's keys and corresponding values.

{
	"data": {
		"id": "2C91A3B0-E375-9383-0B05636E6926868D",
		"name": "Example",
		"links": {
			"relatedentitylink1": "http://...",
			"relatedentitylink2": "http://..."
		}
	}
}

History

Added in version 6.2

Delete

Delete an entity.

Endpoint

DELETE https://yourdomain.com/{context}/index.cfm/_api/json/v1/{siteid}/{entityname}/{id}/?csrf_token={csrf_token}&csrf_token_expires={csrf_token_expires}

OR

DELETE https://yourdomain.com/{context}/index.cfm/_api/json/v1/?method=delete&siteid={siteid}&entityname={entityname}&id={id}&csrf_token={csrf_token}&csrf_token_expires={csrf_token_expires}

Request & Query Parameters

Path parameter Value
context The path to where Mura CMS resides within the webroot (typically, an empty string).
siteid The SiteID of where the entity is stored.
entityname The entity's name.
id The ID of the entity.
csrf_token The csrf_token is generated by the generateCSRFTokens method.
csrf_token_expires The csrf_token_expires is generated by the generateCSRFTokens method.

Example Response

The data element will be an empty string.

{
  "data": ""
}

History

Added in version 6.2

Login

Login a user.

Endpoint

POST https://yourdomain.com/{context}/index.cfm/_api/json/v1/{siteid}/login/?username={username}&password={password}

OR

POST https://yourdomain.com/{context}/index.cfm/_api/json/v1/?method=login&siteid={siteid}&username={username}&password={password}

Request & Query Parameters

Parameter Value
context The path to where Mura CMS resides within the webroot (typically, an empty string).
siteid The SiteID of the site attempting to login to.
username The User's username.
password The User's password.

Example Response

{
  "data": {
	"status": "success"
  }
}

data object

Key Value Type Value Description
status string success or failed, depending on the result of the attempt to login.

History

Added in version 6.2

Logout

Logout the current user.

Endpoint

POST https://yourdomain.com/{context}/index.cfm/_api/json/v1/{siteid}/logout

OR

POST https://yourdomain.com/{context}/index.cfm/_api/json/v1/?method=logout&siteid={siteid}

Request & Query Parameters

Parameter Value
context The path to where Mura CMS resides within the webroot (typically, an empty string).
siteid The SiteID of where the entity will be stored.

Example Response

{
  "data": {
    "status": "succes"
  }
}

data object

Key Value Type Value Description
status string success is always returned.

History

Added in version 6.2

Register Custom API Method

This is an example of how to register a custom JSON API method:

<cfscript>
var APIUtility = getBean('settingsManager').getSite({siteid}).getAPI('json', 'v1');
APIUtility.registerMethod(methodName='applyProperty', method=applyProperty);

public any function applyProperty() {
  // do something
}
</cfscript>

Register Custom API Linking Method

Within the API, all entities contain a "link" attribute that contains HREFs to access related entities. For example, a content entity would have a a value set to access the content children with entity.link.kids. By default, Mura will read through the entity's properties and auto populate its links for you. However, sometimes you will want to add custom link logic.

<cfscript>
var APIUtility=getBean('settingsManager').getSite({siteid}).getApi('json','v1');
APIUtility.registerLinkMethod(method=myCustomLinkMethod);

public any function myCustomLinkMethod(entity,links){
  if ( entity.getEntityName()=='targetEntity' ) {
    arguments.links['runs']='#getEndPoint()#?method=myCustomMethod&siteid=#arguments.entity.getValue('siteid')#';
  } 
}
</cfscript>

History

Feature added in version 6.2.

Creating API methods with Module Beans

You can create components within a module's {moduleDir}/model/beans directory that extend eithermura.bean.bean or mura.bean.beanORM. Within these components any method set to remote access with be availabe via the JSON/REST API.

component extends="mura.bean.bean" {

    remote function mymethod(){
        return "Hello!";
    }
}

You can then call the method like this https://www.domain.com/index.cfm/_api/json/v1/{siteid}/{beanName}/{methodName} .

History

Feature added in version 7.1.

Register Custom Mura ORM Entity

This is an example of how to register a custom Mura ORM entity:

<cfscript>
var APIUtility = getBean('settingsManager').getSite({siteid}).getAPI('json', 'v1');
APIUtility.registerEntity(entityName='myCustomEntity', config={});
</cfscript>

Mura ORM Entity Config Options

Argument Type Description
fields string A comma-separated list of fields that you would like to return as a default for the JSON objects.
allowfieldselect boolean If false, Mura will not allow custom field selects.
moduleid string The Mura CMS module or plugin that permissions for this entity should be tied to.
public boolean If false, will apply permissions based on the config.

Example Mura ORM Entity Config

<cfscript>
myConfig = {
  fields = 'domain,siteid',
  allowfieldselect = false
};

var APIUtility = getBean('settingsManager').getSite({siteid}).getAPI('json', 'v1');
APIUtility.registerEntity(entityName='myCustomEntity', config=myConfig);
</cfscript>

History

Feature added in version 6.2.

Creating Mura ORM Entities from within Modules

You can create components within a module's {moduleDir}/model/beans directory that extend mura.bean.beanORM. Then do a manual application reload with the ?applydbupdates url variable.

component
	extends="mura.bean.beanORM"
	entityname="widget"
	displayname="Widget"
	table="widget"
	orderby="name"
	bundleable=false
	scaffold=true
	public=false
	{
		property name="widgetid" fieldtype="id";
		property name="siteid" default="default" required=true datatype="varchar" length="25";
		property name="name" required=true datatype="varchar";
		property name="description" datatype="text";
}

You can then call the it's endpoint like this https://www.domain.com/index.cfm/_api/json/v1/{siteid}/{beanName} . (Learn more about Mura ORM)

History

Feature added in version 7.1.

Mura.js

Mura.js originally began as a lightweight utility to decouple Mura's dependency on jQuery, a popular JavaScript library. Since its inception, Mura.js has also grown into a JavaScript framework for interacting with Mura's JSON API, which allows Mura CMS to be the main content creation hub within an organization, and allows developers to build their applications as pure JavaScript clients.

Mura.js is hosted as a completely separate project on Github as of Mura v7.1. You can view and/or contribute at https://github.com/blueriver/MuraJS.

In addition, Mura.js has been added as a package to the npmjs registry. Instructions and examples on how to work with the npm pacakge can be found at https://www.npmjs.com/package/mura.js.

Familiar Syntax

If you've ever used jQuery, you'll find the syntax quite familiar.

Selecting Elements

The example below illustrates how to use Mura.js to select multiple DOM elements with the same class, and replace the content of each of the selected elements with custom HTML.

<script>
Mura(function(m) {
  m('.target').each(function() {
    m(this).html('Mura found you!');
  });
});
</script>

Ajax Support

Mura.js includes baked-in Ajax (asynchronous JavaScript and XML) support. The example below illustrates how to perform a simple Ajax request.

<script>
Mura.ajax({
  type: 'post',
  url: 'https://domain.com/path/',
  data: { key: value },
  success: function(resp) {
    console.log(resp);
  },
  error: function(resp) {
    console.log(resp);
  }
});
</script>

Promise Support

Mura.js also includes support for JavaScript promises. See the following examples for more details.

Mura.post() With Promises

<script>
Mura.post('https://domain.com/path/', { key: 'value' })
  .then(function(result) {
    // handle success
   })
  .catch(function(err) {
    // handle error
  };
</script>

Mura.get() With Promises

<script>
Mura.get('https://domain.com/path/')
  .then(function(result) { 
    // success
    // do something with the result
    Mura('#target').html(result.data.html);
  })
  .catch(function(err) { 
    // handle error
    console.log(err);
  });
</script>

Chaining Promises

The following example illustrates how you could handle multiple Ajax requests with Mura.js using JavaScript Promises chaining, and avoid the "pyramid of doom". In other words, avoid nesting your Ajax requests.

<script>
var exampleFunc1 = function() {
    return new Promise(function (resolve, reject) {
        Mura.post('https://domain.com/path/', { apikey: 'value' })
            .then(function(result) {
                if ( result.hasOwnProperty('id') ) {
                    resolve(result);
                } else {
                    reject('result does not contain an id');
                }
            })
            .catch(function(err) {
                reject(err);
            });
    });
};
 
var exampleFunc2 = function(id) {
    return new Promise(function (resolve, reject) {
        Mura.get('https://domain.com/path/?id=' + id)
            .then(function(result) {
                resolve(result);
            })
            .catch(function(err) {
                reject(err);
            });
    });
};
 
exampleFunc1()
    .then(function(exampleFunc1Result) {
        return exampleFunc2(exampleFunc1Result.id);
    })
    .then(function(result) {
        console.log(result);
    })
    .catch(function(err) {
        console.log(err);
    });
</script>

DOM Event Handlers

Mura.js allows for registering DOM event handlers, as shown in the example below.

<script>
Mura('#mybutton').on('click', function(e) {
  e.preventDefault();
  console.log(e);
});
</script>

You can also register multiple event handlers using a custom "addEventHandler" method, as shown below.

<script>
Mura('.myclass').addEventHandler({
  click: function(e) {
    e.preventDefault();
    console.log(e);
  }
  , touch: function(e) {
    // do something
    console.log(e);
  }
});
</script>

Mura.DOMSelection Class

The DOM selection methods available via Mura.js is handled by the Mura.DOMSelection class. This wraps your selected targets via the Mura() method.

Mura.js allows you to handle selected DOM elements as a single object, or as a collection.

Single Object Example
Mura('#target')
  .html('Hello world!');
Collection Example
Mura('.target')
  .each(function() {
    Mura(this)
      .html('Hello world!');
  });

Supported DOMSelection methods may be found at https://github.com/blueriver/MuraJS/blob/master/src/core/domselection.js.

Mura ORM With Mura.js

Mura.js enables JavaScript developers to interact with Mura ORM, exposing access to its ORM Feed API, and allows for common CRUD (Create, Read, Update, and Delete) functionality.

Mura.js CRUD Functionality

Outlined below are code examples for performing basic CRUD operations on Mura ORM objects/entities via Mura.js. For developers who are primarily used to working with server-side languages, it may take a little time to adjust to working on the client side, because we need to "wait" until the object/entity is loaded in order to work with it. For this reason, it may be helpful to review how to work with JavaScript Promises.

Loading/Reading Mura ORM Objects/Entities

This example simply illustrates how to load a Mura ORM entity, using Mura.js.

<script>
var personid = 'some-uuid';

Mura.getEntity('person')
    .loadBy('personid', personid)
    .then(function(person) {
        console.log(person);
    })
    .catch(function(err) {
        console.log(err.get('errors'));
    });
</script>

Creating/Updating Mura ORM Objects/Entities

This example drives home how to segregate your Ajax calls using JS Promises, and avoid nesting or stacking your Mura.js methods.

<script>
var getPersonByID = function(personid) {
    return new Promise(function(resolve, reject) {
        Mura.getEntity('person').loadBy('personid', personid)
          .then(function(person) {
            resolve(person);
          })
          .catch(function(err) {
            reject(err);
            console.log(err.get('errors'));
          });
    });
};

var savePerson = function(person) {
    return new Promise(function(resolve, reject) {
        person.save()
            .then(function(result) {
                resolve(result);
            })
            .catch(function(err) {
                reject(err);
            });
    });
}

getPersonByID('some-uuid')
    .then(function(person) {
        person.set('namelast', 'Withington');
        return savePerson(person);
    })
    .then(function(result) {
        console.log(result);
    })
    .catch(function(err) {
        console.log(err);
    });
</script>

Deleting Mura ORM Objects/Entities

This is another example of how to segregate your Ajax calls using JS Promises to avoid nesting your Mura.js methods.

<script>
var getPersonByID = function(personid) {
    return new Promise(function(resolve, reject) {
        Mura.getEntity('person').loadBy('personid', personid)
          .then(function(person) {
            resolve(person);
          })
          .catch(function(err) {
            reject(err);
            console.log(err.get('errors'));
          });
    });
};

var deletePerson = function(person) {
    return new Promise(function(resolve, reject) {
        person.delete()
            .then(function(result) {
                resolve(result);
            })
            .catch(function(err) {
                reject(err);
            });
    });
}

getPersonByID('some-uuid')
    .then(function(person) {
        return deletePerson(person);
    })
    .then(function(result) {
        console.log(result);
    })
    .catch(function(err) {
        console.log(err);
    });
</script>

Mura.js Feed API

The following example illustrates how to obtain a feed of Mura ORM objects/entities, and then loop over the returned recordset. As you'll see, it's quite similar to using Mura's ORM Feed syntax.

var person;

Mura
  .getFeed('person')
  .where() //optional
  .prop('namelast')
  .isEQ('Levine')
  .orProp('namelast')
  .beginsWith('Withing')
  .getQuery()
  .then(function(people) {
    // handle success
    people.each(function(person, idx) {
      result = person.get('namefirst') + ' ' + person.get('namelast');
      console.log(result);
    });
  })
  .catch(function(err) {
    // handle error
    console.log(err);
  });

This example demonstrates how to use the aggregate method introduced in Mura v7.1. The example assumes a custom ORM object named "widget" exists, and has a property of "price".

var widget;

Mura
  .getFeed('widget')
  .aggregate('count', '*')
  .aggregate('sum', 'price')
  .aggregate('min', 'price')
  .aggregate('max', 'price')
  .aggregate('avg', 'price')
  .getQuery()
  .then(function(widgets) {
    // handle success
    console.log(widgets.getAll());
  })
  .catch(function(err) {
    // handle error
    console.log(err);
  });

See the "Key Methods" area of the Feed Bean section, for details on the Mura.js Feed API Methods.

Loading JavaScript and CSS Files With Mura.js

Mura.js allows JavaScript developers to load their JS and CSS files synchronously or asynchronously. This is especially useful for modules rendered via CFML.

Note: This is NOT recommend for modules rendered via JavaScript. See the Anatomy of a Module's Rendering Via JavaScript section for more information.

Mura.loader()

The Mura.loader() method is for JavaScript and CSS parallel loading with dependencies management. Using this method also prevents duplicate JavaScript and/or CSS files from being loaded.

There are two primary methods associated with Mura.loader(), loadjs() and loadcss() described below. 

loadjs(url, cb)

Parameter Description
url If the first parameter is an array, files will be loaded asynchronously. If it's a string, the files will be loaded synchronously. If the file is located under your theme, you may use m.themepath to dynamically generate the path to the theme location. For example: loadjs(m.themepath + '/script.js')
cb A callback function to execute when all scripts have been loaded.

loadcss(url, attrs, cb)

Parameter Description
url The URL for the CSS file. If the file is located under your theme, you may use m.themepath to dynamically generate the path to the theme location. For example: loadcss(m.themepath + '/file.css')
attrs You may optionally pass in an object to specify the media type attribute for the CSS file. For example: loadcss(m.themepath + '/file/css', {media: "print"})

Valid options include:
  • all
  • aural
  • braille
  • embossed
  • handheld
  • print
  • projection
  • screen
  • tty
  • tv
cb A callback function which executes immediately.

Examples

This example illustrates the basic syntax for loading a JavaScript file, with a desired callback function.

<script>
Mura(function(m) {
    m.loader()
        .loadjs(m.themepath + '/js/mylibrary.js', function() {/* callback */});
});
</script>

The example below illustrates loading some scripts in parallel with another batch of scripts being loaded in order. In the example below, the first loadjs() will be executed in parallel of the second loadjs(). However, in the second loadjs(), the myDependentLib.js file won't be loaded until myRequiredLib.js has finished loading. Then, when they've finished loading, the callback function will execute.

<script>
Mura(function(m) {
    m.loader()
        .loadjs(m.themepath + '/myLib.js')
        .loadjs(
          m.themepath + '/myRequiredLib.js', 
          m.themepath + '/myDependentLib.js', 
          function() {
            // callback
          });
});
</script>

The example below illustrates loading multiple CSS & JavaScript files, and includes a callback function that runs after the script files have all been loaded.

<script>
Mura(function(m) {
    m.loader()
        .loadcss(m.themepath + '/path/to/all.css', { media: 'all' })
        .loadcss(m.themepath + '/path/to/print.css', { media: 'print' })
        .loadjs(
            m.themepath + '/path/to/script1.js',
            m.themepath + '/path/to/script2.js',
            function() {
                // Now do something with the loaded JS
            });
});
</script>

 

Modules With Mura.js

As introduced in the Anatomy of a Module section, developers may choose to render their modules using purely JavaScript. When doing so, the module's index.cfm file should only contain the following line of code, which informs Mura it has nothing to render via server-side processing, and all rendering will occur via the "client" or browser.

<cfset objectparams.render="client">

Then, in order to load your script(s), you'll need to use a custom event handler, and register the onRenderStart event to dynamically load your script file(s), as illustrated below.

// ../yourmodule/model/handlers/yourhandler.cfc

component extends='mura.cfobject' {

  function onRenderStart(m) {
    // if script should be included in the <head>
    arguments.m.addToHTMLHeadQueue('<script src="/path/to/script.js"></script>');

    // OR

    // if script should be included before closing </body> tag
    arguments.m.addToHTMLFootQueue('<script src="/path/to/script.js"></script>');
  }

}

By using addToHTMLHeadQueue and/or addToHTMLFootQueue, your scripts will only be loaded once, regardless of how many times your module has been applied to the layout.

The Custom JavaScript File

Assuming you've followed the instructions above to get your custom script file included into either the "head" portion of your theme, or before the closing "body" tag, you will most likely want to control when your script(s) are executed. However, you may also simply allow your scripts to run at all times.

Running Scripts on Every Request

If you merely wish for your script(s) to execute, regardless of whether or not your module has been applied to the layout, then you may simply include any JavaScript you wish. In other words, since your script files are being added on every request via your custom event handler's onRenderStart method, your scripts will automatically execute. This is useful for merely adding a utility script, such as a tracking script, etc.

The content of your script file may look as simple as the following example.

// your-script.js
console.log('Hello from your module!');

Running Scripts Only If Your Module Has Been Applied

Unless your scripts are utilities, such as tracking scripts, developers will most often wish their scripts to execute only when the module has been applied to the layout. In addition, when the module includes a configurator, each instance of the module will have access to its own configuration information.

First, it's important to understand that modules rendered via the client, are automatically registered to Mura's namespace under Mura.Module.YourModuleDirectoryName. Also, Mura will automatically invoke a "render" method via Mura.UI, on each request. By defining your own "render" method, you're able to pretty much do whatever you want.

The example below illustrates a skeleton script. You should substitute "yourModuleDirectoryName" with the actual directory name of your display object.

// your-script.js
Mura.Module.YourModuleDirectoryName = Mura.UI.extend({
  render: function() {
    // Your code goes here ...
    return this;
  }
});

this.context

When using JavaScript to render a Mura "Module" via the client, developers are most interested in two (2) primary pieces of information:

  1. How to target the container element of where the module has been applied to the layout.
  2. How to access "objectparams", or the data collected via a configurator.

You can easily access either of these by using "this.context" in your custom script.

  • this.context.targetEl
    • Use this to target the container element of where the module has been applied to the layout. Keep in mind, each instance of the module in the layout will have its own, unique container element.
  • this.context.{yourObjectParam}
    • Use this to access any "objectparams", or data collected via a configurator. Each instance of the module will have access to its own, unique configuration data.

The example below illustrates how to use the above information, and may be used as a starter file in your own projects.

// your-script.js
Mura.Module.YourModuleDirectoryName = Mura.UI.extend({

  render: function() {
    // reference to the container element
    this.container = Mura(this.context.targetEl);
    
    // assuming you have an objectparam named 'mytext'
    var txt = this.context.mytext || 'mytext is empty';

    // Having fun by replacing the content of the container
    // Remember, using Mura.js, we can do jQuery-esque DOM manipulation
    this.container.html('<h3>Hello from yourDisplayObject</h3>');
    this.container.append('<h4>' + txt + '</h4>');

    // The rest of your code goes here ...
    return this;
  }

});

If you're interested in seeing what else is available via Mura.UI, feel free to review the code found at https://github.com/blueriver/MuraJS/blob/master/src/core/ui.js.

To see an example of how to use Mura.js along with Mura ORM, Grunt, and Handlebars, visit https://github.com/stevewithington/muracontacts/tree/js.

Forms & Mura.js

Mura forms are loaded asynchronously. So, if you wish to run some scripts, you need to use a special method to "reopen" the form, and then add your scripts. This can be done by leveraging a special Mura.js method: Mura.DisplayObject.Form.reopen({});.

Once the form has been "reopened," simply leverage one or more of the predefined events from the code example below to inject any custom logic.

NOTE: If not using deferred Mura.js then you do not need to reopen the display object classes within a Mura.preInit() method. The option to defer the loading of Mura.js was introduced in Mura 7.1 and is controlled by the this.deferMuraJS theme contentRenderer.cfc value.

Mura.preInit(function(m) {

	Mura.DisplayObject.Form.reopen({
		// triggered after the form has rendered on the browser
		onAfterRender: function() {
			var form_container = this.context.targetEl
				, the_form = m(form_container).find('form');

			console.log('afterRender triggered');

			// This is where you register your custom form listeners, 
                        // for example ...
			m('button.form-submit').on('click', function(event) {
				console.log('Form button clicked!')
				console.log(event.target.form);
			});
		}

		// triggered when the form has been submitted, 
                // before processing/validation begins
		, onSubmit: function () {
			var the_button = event.target
				, the_form = the_button.form;

			console.log('onSubmit triggered');
			console.log(the_button);
			console.log(the_form);

			// you could run a script here (obviously) ... then,
			// return true if you want to continue, 
                        // or false if you wish to stop processing
			return true;
		}

		// triggered after submit, and form has errors
		, onAfterErrorRender: function() {
			var resp = JSON.parse(event.currentTarget.response)
				, errors = resp.data.errors;

			console.log('afterErrorRender triggered');
			console.log(errors);
		}

		// triggered after successful form submit (no errors)
		, onAfterResponseRender: function () {
			var response_container = this.context.targetEl;

			console.log('afterResponseRender triggered');
			console.log(response_container);
		}
	});

});

Internationalization & Localization

Mura utilizes resource bundles to internationalize various areas of the user interface, making the code locale-independent.

Resource bundles are .properties files, located under specified directories in Mura. These .properties files, or resource bundles, are named to indicate the language code, and country code. For example, the language code for English (en) and the country code for United States (US) would be represented as en_US.properties. If Mura cannot find a direct language and region match, it will search for a language match. If a locale's language cannot be found, Mura will fall back to its default of English, or en_US.properties.

The file itself is comprised of key-value pairs. The keys remain the same throughout each of the .properties files, and the value is translated into the file's designated language. If Mura is searching for a specific key-value pair within a translation, and cannot locate it, Mura will fall back to the English translation.

The image below illustrates the en_US.properties file side-by-side with the es_ES.properties file:

Lookup Hierarchy

Mura automatically searches for resource bundles under specific directories, and uses the key-value pair(s) found in the order outlined below. If a resource_bundles directory does not exist in the following locations, you may safely create one, and place your resource bundle files there.

  • Module
    • ../{module}/resource_bundles/
    • Module (aka "Display Object") resource bundles are used for the specific module itself.
  • Content Types
    • ../content_types/{type}_{subtype}/resource_bundles/
    • Content Types resource bundles are used for the specified content type.
  • Theme
    • ../{ThemeName}/resource_bundles/
    • Theme resource bundles are only used when the specified theme is actively assigned to a site.
  • Site
    • {context}/sites/{SiteID}/resource_bundles/
    • Site resource bundles are shared across all themes within the specified site.
  • Global
    • {context}/resource_bundles/
    • Global resource bundles are shared across all sites under a single Mura instance.
  • Core
    • {context}/core/modules/v1/core_assets/resource_bundles/
    • If the requested key-value pair is not defined in any of the locations above, Mura will use the "core" resource bundles located here for Mura's modules.

Note: Admin-area resource bundles are located under {context}/core/mura/resourceBundle/resources/. However, as of v7.1, many key-value pairs are not able to be overwritten using the technique described above at this time. Allowing for this option is under consideration for a future version.

Contribute

If you would like to contribute to the translations project, please visit https://crowdin.com/project/muracms. Your help will be greatly appreciated!

Custom Keys

As previously documented, Mura searches for custom ".properties" files, under the directories listed in the "Lookup Hierarchy" section.

You don't have to include all of the key-value pairs from the original files. You only have to include the key-value pairs you wish to override. In addition, if you have any custom keys you would like to use in your site, you can simply include them in your custom ".properties" files.

Displaying Custom Keys

To output a custom key-value from your ".properties" file, simply use m.rbKey({keyName}).

So, for example, to output a key of "myCustomString", use the following syntax.

<cfoutput>
  #m.rbKey('myCustomString')#
</cfoutput>

Custom Factories

Mura allows you to create your own resource bundle factories, and fall back to Mura's original lookup hierarchy when a requested key-value is not found. This is especially useful when creating plugins, or integrating a custom application.

The code example below demonstrates how you could go about creating a custom resource bundle factory.

customResourceBundleDirectory = ExpandPath('#m.globalConfig('context')#/path/to/your/RBFactory/');

customFactory = new mura.resourceBundle.resourceBundleFactory(
  parentFactory = m.siteConfig('rbFactory')
  , resourceDirectory = customResourceBundleDirectory
  , locale = m.siteConfig('JavaLocale')
);

You could wrap this up into a custom method to obtain a reference to your custom factory using something similar to the following example.

public any function getResourceBundleFactory(required struct m) {
  var resourceDirectory = ExpandPath('#arguments.m.globalConfig('context')#/plugins/MyPlugin/rb/');
  return new mura.resourceBundle.resourceBundleFactory(
    parentFactory = arguments.m.siteConfig('rbFactory')
    , resourceDirectory = resourceDirectory
    , locale = arguments.m.siteConfig('JavaLocale')
  );
}

Once you've created your custom resource bundle factory, simply use {yourCustomFactoryVariableName}.getKey({yourKey})

So, for example, to output a key of "myCustomString", with a custom factory variable named "customFactory", use the following syntax.

<cfoutput>
  #customFactory.getKey('myCustomString')#
</cfoutput>

Caching

Mura has a built-in caching mechanism that, when enabled, will store data in memory for reuse. The purpose for this is to improve overall site performance, by decreasing the amount of reads to the database. Mura's caching uses a "lazy load" approach, which means data won't be cached until it's called upon the first time.

How to Enable/Disable Site Caching

Follow the steps below to enable and/or disable site caching.

  1. From the back-end administrator, on the main navigation, click Site Settings, then select Edit Settings.
  2. From the Site Settings screen, select the Basic tab.
  3. Scroll down to Site Caching.
    • Select On to enable site caching.
    • Select Off to disable site caching.
  4. After making your selection, click Save Settings.

Cache Free Memory Threshold

By default, when Site Caching is enabled, Mura will only store data into memory when the Java virtual machine (JVM) has at least sixty percent (60%) available memory. You may choose to set an alternate minimum desired percentage by following the steps outlined below.

  1. From the back-end administrator, on the main navigation, click Site Settings, then select Edit Settings.
  2. From the Site Settings screen, select the Basic tab.
  3. Scroll down to Cache Free Memory Threshold (Defaults to 60%), and enter in your desired percentage amount. If you enter zero (0), Mura will revert to using its default setting of sixty percent (60%).
  4. After entering your desired amount, click Save Settings.

cf_CacheOMatic Tags

One of the easiest ways to improve the performance of your site, is to use proven caching techniques. In addition to the native caching strategies for CFML, Mura also offers a special, custom tag, <cf_CacheOMatic>, to use for expensive database transaction code, or other time-consuming CFML code that doesn't need to be executed during each request.

Using Mura's <cf_CacheOMatic> tag allows you to add data to Mura's cache. The tag only works when Site Caching is enabled, which is a great reason to use it since you can easily disable it, if necessary. 

The custom tag is located under {context}/core/mura/customtags/CacheOMatic.cfm if you would like to inspect the file to see how it works under the hood.

Tag Syntax

<cf_CacheOMatic>
  Code or data to cache.
</cf_CacheOMatic>

Attributes

Attribute Type Default Description
key string CGI.scriptname & CGI.query_string A unique string to associate with the specified data. Used to retrieve the cached data, when Site Caching is enabled.
timespan datetime CreateTimeSpan(0,0,30,0) The desired time period the data should be cached for before it expires. (Defaults to 30 minutes).
scope string application The desired CFML scope in which to store the data. Valid options are application, session, and server.
nocache boolean false If true, Mura will not cache the code/data contained within the tag. Useful for explicitly omitting code from being cached.
purgecache boolean request.purgecache If true, Mura will empty its cache.
siteid string request.siteid You may choose to specify an alternate SiteID to associate the cache to.

Usage

Use this custom tag to cache inline content or data within layout templates.

Examples

Using the "key" Attribute

This example uses the ContentID of the content item as the key with prefix of "page-".

<cf_CacheOMatic key="page-#m.content('contentid')#">
  <h2 class="page-title">#esapiEncode('html', m.content('pagetitle'))#</h2>
</cf_CacheOMatic>

Using the "nocache" Attribute

The following example demonstrates how you could use the nocache attribute to see an "un-cached" version of the output by simply appending ?nocache=true to the URL.

<cf_CacheOMatic 
     key="example-timestamp1" 
     nocache="#m.event('nocache')#">
  <p>The time is now: #LSTimeFormat(Now())#</p>
</cf_CacheOMatic>

Using the "timespan" Attribute

In this example, we're setting the cache to expire in five (5) hours.

<cf_CacheOMatic
     key="example-timestamp2"
     nocache="#m.event('nocache')#"
     timespan="#CreateTimeSpan(0,5,0,0)#">
  <p>The time is now: #LSTimeFormat(Now())#</p>
</cf_CacheOMatic>

Programmatic Caching

As covered in the cf_CacheOMatic Tags section, Mura allows developers to add data to Mura's cache. One thing to keep in mind is your data or code may be either intentionally or even inadvertently wrapped by cf_CacheOMatic tags, subjecting your output to the settings of the tag.

However, as a developer, you may have data or code you wish to either explicitly exclude from being added to Mura's cache. Or, you may wish to set a specific duration of time the data or code may be cached for. Mura also allows developers to achieve this using the code snippets described below.

request.cacheItem

This code snippet controls whether the code or data will be cached if wrapped by cf_CacheOMatic tags. If true, the code or data will be cached according to the settings of the containing cf_CacheOMatic tags. If false, the code or data will not be cached.

Note: A side-effect of setting request.cacheItem to false is none of the code or data within the containing cf_CacheOMatic tags will be cached at all.

Syntax

request.cacheItem = {true || false}

Example

<cfset request.cacheItem = false />
<!--- The following timestamp will NOT be cached --->
<cfoutput>
  <p>The date/time is #Now()#</p>
</cfoutput>

request.cacheItemTimeSpan

This code snippet controls the duration of time the code or data will be cached for.

Syntax

request.cacheItemTimeSpan = {TimeSpan Object}

Example

<cfset request.cacheItemTimeSpan = CreateTimeSpan(0, 0, 5, 0) />
<!--- The following timestamp will be cached for 5 minutes, if wrapped by cf_CacheOMatic tags --->
<cfoutput>
  <p>The date/time is #Now()#.</p>
</cfoutput>

Summary

Throughout this section, you built upon the knowledge obtained in the Theme Developer's area, and learned how to override Mura's default rendering methods, as well as how to create some sophisticated display objects, and how to target specific content types to provide custom body rendering. In addition, you learned about Mura.js, and how to use it in your development efforts, as well as other important information such as internationalization/localization, and how to leverage caching to improve your site's performance.