Lifecycle Events vs. Contextual Events
Before you continue through this section, you'll need to understand the differences between Mura's lifecycle events and Mura's contextual events.
- "Lifecycle" events generally get triggered on every page request, and represent the execution of Mura's normal request flow. Mura consists of two unique lifecycles: the Front-end Lifecycle, and the Admin Lifecycle.
- "Contextual" events aren't triggered on every page request, because they occur in response to the specific event(s) or action(s) that preceded them.
For example, Mura-related events that occur when editing a "User" are only triggered when a user is being created or updated, and would not necessarily be triggered in the course of a normal front-end request.
Note: Contextual events only contain data that is directly supplied to it by the Mura core. If you need to access to the full event scope itself (i.e., during a front-end or admin rendering event), it can be accessed via m.getGlobalEvent()
.
Mura "event" Scope
When working with events, keep CFML's scopes in mind. As noted in the Mura Scope section, in addition to the CFML scopes, Mura has its own scope called the Mura Scope.
The Mura Scope has a special subscope called the "event" scope, and it is created on every request. It can be referenced via m.event()
. If you need to access the global event scope from within a contextual event, you may use m.getGlobalEvent()
.
Mura's event
scope wraps CFML's request
, form
, and URL
scopes. Mura also injects additional data and helper methods into the event
scope, and the availability of the data is dependent upon the context in which you may be accessing it. As covered in the Mura Objects section, you may also store your own data in Mura's event
scope for use within your own application logic.
Syntax
You can use the following examples to "get" and/or "set" various attributes of Mura's event
scope. Use whichever syntax feels best to you.
Getters
m.event('attributeName')
m.event().get('attributeName')
m.event().get{AttributeName}()
m.event().getValue('attributeName')
Setters
m.event('attributeName', 'someValue')
m.event().set('attributeName', 'someValue')
m.event().set{AttributeName}('someValue')
m.event().setValue('attributeName', 'someValue')
Event Hooks
In this section, we'll cover Mura's various event hooks/methods, or trigger points, you can use to either add to, or even replace Mura's business logic and functionality.
One thing you'll want to think of when using this section is determining the point(s) in which you wish to add your logic. For example, are you trying to do something that occurs while the Mura application is loading up? Or, are you attempting to do something during a normal, front-end request? Are you trying to do something when a content item is being updated? Maybe you're attempting to do something when a session begins. These are all good questions that can point you in the right direction. Once you've determined the answers to these types of questions, you can dig into the available event hooks, register your event handlers, and implement your custom application logic.
Also, when working with Mura events, keep in mind that all events are automatically passed in the Mura (m
) scope as an argument. The example below illustrates a sample method with the argument being passed in.
public any function onSomeEvent(m) {
// do something here
}
To can obtain the event
scope via the Mura scope, follow the example below.
public any function onSomeEvent(m) {
// obtain the `event` scope via the Mura Scope
var e = arguments.m.event();
}
Keep in mind when working with some contextual events, you may need to access the "global" event
scope itself. The example below demonstrates accessing the global event, if necessary.
public any function onSomeEvent(m) {
// access the global event scope
var globalEvent = arguments.m.getGlobalEvent();
}
Finally, you may add any of these events to a registered event handler, in order for Mura to execute them. See the Event Handlers section for more information.
Event Prefixes
As you review the available events, you'll notice a common naming convention. Mura's events all start with a prefix, which informs you whether you're replacing Mura's business logic, or adding to Mura's business logic. Keep the following information in mind as you dive into the rest of this section.
- standard{Event}
- All "standard" events are points where you can replace Mura's business logic and functionality. These events are all defined within the file located at
{context}/core/mura/Handler/standardEventsHandler.cfc
- on{Event}
- All "on" events are points where you can add to Mura's business logic and functionality. The important thing to understand about "on" events is that these are not necessarily "defined" anywhere. These types of events are merely "announced" during the normal execution of a request.
Global vs. Site
In addition to the "standard" vs. "on" prefixes, you'll notice many events also have additional common names after the prefix:
- onGlobal{Event}
- All "global" events are those that occur throughout the entire instance of Mura, and are not bound to any specific site.
- onSite{Event}
- All "site" events occur site-wide, and are bound to the specific site they have been registered to.
Before vs. After
Another common naming convention includes using the words "before" and "after" to indicate whether something is happening immediately before Mura is about to do something, or after Mura has finished doing something.
- onBefore{Event}
- All "before" events are announced immediately before Mura is about to execute its normal functionality.
- onAfter{Event}
- All "after" events are announced immediately after Mura has executed its normal functionality.
CFML Application Events
As a CFML developer, you should be familiar with using application event handlers. The most commonly used CFML methods are outlined below, with a direct mapping to Mura's methods. Using Mura's methods in your own event handlers allows you to stay on the upgrade path, without having to modify Mura's Application.cfc
directly.
Standard Events
As previously discussed, events prefixed with "standard" are points where you can replace Mura's business logic and functionality. To view their method definitions, and what they're doing specifically, open the file located under {context}/core/mura/Handler/standardEventsHandler.cfc
. You can also view these methods via Mura's Component API at http://www.getmura.com/component-api/7.1/index.html?mura/Handler/standardEventsHandler.html.
There are three primary suffixes for "standard" events:
-
validator
- Validators inspect the "event" or "request" itself, and forward the request/event to the appropriate handler, if necessary.
- handler
- Handlers usually set values in the "global event", or redirect the user somewhere.
- translator
- Translators check to see if the requested
returnformat
is JSON
, and if so, utilizes Mura's JSON API to handle the request.
Method |
When run |
standard404Handler |
Called by standard404Validator when the content bean in the current request is new. |
standard404Validator |
Called by standardSetContentHandler on each request. |
standardDoActionsHandler |
|
standardDoResponseHandler |
|
standardEnableLockdownHandler |
|
standardEnableLockdownValidator |
|
standardFileTranslationHandler |
|
standardFileTranslator |
|
standardForceSSLHandler |
|
standardForceSSLValidator |
|
standardJSONTranslator |
|
standardLinkTranslationHandler |
|
standardLinkTranslator |
|
standardMobileHandler |
|
standardMobileValidator |
|
standardPostLogoutHandler |
|
standardRequireLoginHandler |
|
standardRequireLoginValidator |
|
standardSetContentHandler |
|
standardSetIsOnDisplayHandler |
|
standardSetLocaleHandler |
|
standardSetPermissionsHandler |
|
standardSetPreviewHandler |
|
standardTrackSessionHandler |
|
standardTrackSessionValidator |
|
standardTranslationHandler |
|
standardWrongDomainValidator |
|
standardWrongFilenameHandler |
|
standardWrongFilenameValidator |
|
App-Related Events
The events listed below are specifically related to the Mura application itself.
Analogous CFML Application Events
Event |
Rendered |
Description |
onApplicationLoad |
|
Announced in the CFML onApplicationStart method. |
onGlobalSessionStart |
|
Announced in the CFML onRequestStart method, if session management is enabled, and request.doMuraGlobalSessionStart is true . |
onGlobalSessionEnd |
|
Announced in the CFML onSessionEnd method, if session.siteid is not defined. |
onSiteSessionEnd |
|
Announced in the CFML onSessionEnd method, if session.siteid is defined. |
onGlobalRequestStart |
|
Announced in the CFML onRequestStart method. |
onGlobalRequestEnd |
|
Announced in the CFML onRequestEnd method. |
onGlobalMissingTemplate |
|
Announced in the CFML onMissingTemplate method, if siteid is not defined in the event . |
onSiteMissingTemplate |
|
Announced in the CFML onMissingTemplate method, if siteid is defined in the event . |
onGlobalError |
|
Announced in the CFML onError method, if siteid is not defined in the event . |
onSiteError |
|
Announced in the CFML onError method, if siteid is defined in the event . |
Administration Events
Event |
Rendered |
Description |
onBeforeAutoUpdate |
|
Announced before performing an auto update. |
onAfterAutoUpdate |
|
Announced after the auto update has completed. |
onGlobalThreatDetect |
|
Announced if the request.remoteAddr is blocked by the Script Protection Filter. Used to help prevent Cross-Site Scripting attacks. |
onAdminRequestStart |
|
Announced at the end of the administration area's Application.cfc:setupRequest method. |
onAdminRequestEnd |
|
Announced in the administration area's Application.cfc:onRequestEnd method. |
onSiteDeploy |
|
Announced before a site is deployed. |
onBeforeSiteDeploy |
|
Announced before a site is deployed. |
onAfterSiteDeploy |
|
Announced after a site is deployed. |
onAfterSiteDeployRender |
X |
Announced after a site is deployed, and will render any returned string. |
onSiteCopy |
|
Announced before a site is copied. |
onBeforeSiteUpdate |
|
Announced before a site has been updated/saved. |
onBeforeSiteSave |
|
Announced before a site has been updated/saved. |
onAfterSiteUpdate |
|
Announced after a site has been updated/saved. |
onAfterSiteSave |
|
Announced after a site has been updated/saved. |
onBeforeSiteDelete |
|
Announced before a site is deleted. |
onAfterSiteDelete |
|
Announced after a site has been deleted. |
onBeforeSiteCreate |
|
Announced before a site is created/saved. |
onAfterSiteCreate |
|
Announced after a site has been created/saved. |
onBeforeSiteEmptyTrash |
|
Announced before emptying the site trash, if session.siteid exists. |
onBeforeGlobalEmptyTrash |
|
Announced before emptying the site trash, if session.siteid does not exist. |
onAfterSiteEmptyTrash |
|
Announced after the site trash has been emptied, if session.siteid exists. |
onAfterGlobalEmptyTrash |
|
Announced after the site trash has been emptied, if session.siteid does not exist. |
onBeforeProxyBundleDeploy |
|
|
onAfterProxyBundleDeploy |
|
|
onBeforeChangeSetPublish |
|
Announced before publishing a change set. |
onAfterChangeSetPublish |
|
Announced after publishing a change set. |
onAfterChangeSetPublishError |
|
Announced after publishing a change set with an error. |
Administration Area Rendering Events
Event |
Rendered |
Description |
onDashboardReplacement |
X |
Announced before rendering Mura's default administration area dashboard. Allows for a completely custom dashboard. |
onDashboardPrimaryTop |
X |
Announced before rendering the top portion of Mura's default administration area dashboard. Allows for adding custom output above the main dashboard. |
onDashboardPrimaryBottom |
X |
Announced before rendering the bottom portion of Mura's default administration area dashboard. Allows for adding custom output below the main dashboard. |
onDashboardSidebarTop |
X |
Announced before rendering the top portion of Mura's default administration area dashboard's sidebar. Allows for adding custom output above the main dashboard's sidebar. |
onDashboardSidebarBottom |
X |
Announced before rendering the bottom portion of Mura's default administration area dashboard's sidebar. Allows for adding custom output below the main dashboard's sidebar. |
onAdminNavMainRender |
X |
Announced when rendering the main navigation in the back-end administration area. Allows developers to render additional main navigation menu items. |
onFEToolbarExtensionRender |
X |
Announced when rendering the front-end editing toolbar. Allows developers to render additional front-end toolbar menu items. |
onAdminHTMLHeadRender |
X |
Announced just before rendering the closing </head> tag in the administration area layout template. |
onAdminHTMLFootRender |
X |
Announced just before rendering the closing </body> tag in the administration area layout template. |
onAdminMFAChallengeRender |
X |
If Multi-Factor Authentication (MFA) is enabled, this event is announced when rendering the MFA section of the administration area's login screen. |
onContentSecondaryNavRender |
X |
Announced after rendering the "Actions" navigation on the "Edit Content" screen. |
on{Type}SecondaryNavRender |
X |
Announced after rendering the "Actions" navigation on the "Edit Content" screen, based on the content/object type. For example:
- onPageSecondaryNavRender
- onFolderSecondaryNavRender
- onCalendarSecondaryNavRender
- onLinkSecondaryNavRender
- onFileSecondaryNavRender
- onComponentSecondaryNavRender
- onFormSecondaryNavRender
|
on{Type}{Subtype}SecondaryNavRender |
X |
Announced after rendering the "Actions" navigation on the "Edit Content" screen, based on the content/object type and subtype. For example:
- onPageDefaultSecondaryNavRender
- onFolderDefaultSecondaryNavRender
- onCalendarDefaultSecondaryNavRender
- onLinkDefaultSecondaryNavRender
- onFileDefaultSecondaryNavRender
- onComponentDefaultSecondaryNavRender
- onFormDefaultSecondaryNavRender
|
onNewContentMenuRender |
X |
Announced after the "Select Content Type" dialog window has finished. Allows you to add to the output of the menu. |
on{Type}{Subtype}NewContentMenuRender |
X |
Announced after the "Select Content Type" dialog window has finished. Allows you to add to the output of the menu, based on content type and subtype. For example:
- onPageDefaultNewContentMenuRender
- onFolderDefaultNewContentMenuRender
- onCalendarDefaultNewContentMenuRender
- onLinkDefaultNewContentMenuRender
- onFileDefaultNewContentMenuRender
- onComponentDefaultNewContentMenuRender
- onFormDefaultNewContentMenuRender
|
JSON API Events
Event |
Rendered |
Description |
onAPIResponse |
|
|
on{Type}APIResponse |
|
|
on{Type}{Subtype}APIResponse |
|
|
onAPIError |
|
|
onSiteAsyncRequestStart |
|
|
onAsyncRenderStart |
|
|
Content-Related Events
The events listed below are specifically related to content items.
Content Editing Events
Event |
Rendered |
Description |
onBeforeContentSave |
|
Announced before content is saved. |
onBefore{Type}Save |
|
Announced before content is saved, based on its type. For example:
- onBeforePageSave
- onBeforeFolderSave
- onBeforeCalendarSave
- onBeforeLinkSave
|
onBefore{Type}{Subtype}Save |
|
Announced before content is saved, based on its type and subtype. For example:
- onBeforePageDefaultSave
- onBeforeFolderDefaultSave
- onBeforeCalendarDefaultSave
- onBeforeLinkDefaultSave
|
onAfterContentSave |
|
Announced after content is saved. |
onAfter{Type}Save |
|
Announced after content is saved, based on its type. For example:
- onAfterPageSave
- onAfterFolderSave
- onAfterCalendarSave
- onAfterLinkSave
|
onAfter{Type}{Subtype}Save |
|
Announced after content is saved, based on its type and subtype. |
onBeforeContentDelete |
|
Announced before content is deleted. |
onBefore{Type}Delete |
|
Announced before content is deleted, based on its type. |
onBefore{Type}{Subtype}Delete |
|
Announced before content is deleted, based on its type and subtype. |
onContentDelete |
|
Announced before content is deleted. |
on{Type}Delete |
|
Announced before content is deleted, based on its type. |
on{Type}{Subtype}Delete |
|
Announced before content is deleted, based on its type and subtype. |
onAfterContentDelete |
|
Announced after content is deleted. |
onAfter{Type}Delete |
|
Announced after content is deleted, based on its type. |
onAfter{Type}{Subtype}Delete |
|
Announced after content is deleted, based on its type and subtype. |
Content Version History Events
Event |
Rendered |
Description |
onContentDeleteVersionHistory |
|
Announced before a content item's entire version history is deleted. |
onBeforeContentDeleteVersionHistory |
|
Announced before a content item's entire version history is deleted. |
onBefore{Type}DeleteVersionHistory |
|
Announced before a content item's entire version history is deleted, based on its type. |
onBefore{Type}{Subtype}DeleteVersionHistory |
|
Announced before a content item's entire version history is deleted, based on its type and subtype. |
onBefore{Type}{Subtype}DeleteVersion |
|
Announced before a content item's entire version history is deleted, based on its type and subtype. |
on{Type}DeleteVersionHistory |
|
Announced before a content item's entire version history is deleted, based on its type. |
on{Type}{Subtype}DeleteVersionHistory |
|
Announced before a content item's entire version history is deleted, based on its type and subtype. |
onAfterContentDeleteVersionHistory |
|
Announced after a content item's entire version history is deleted. |
onAfter{Type}DeleteVersionHistory |
|
Announced after a content item's entire version history is deleted, based on its type. |
onAfter{Type}{Subtype}DeleteVersionHistory |
|
Announced after a content item's entire version history is deleted, based on its type and subtype. |
onContentDeleteVersion |
|
Announced before a specific version of a content item is deleted. |
onBeforeContentDeleteVersion |
|
Announced before a specific version of a content item is deleted. |
onBefore{Type}DeleteVersion |
|
Announced before a specific version of a content item is deleted, based on its type. |
onBefore{Type}{Subtype}DeleteVersion |
|
Announced before a specific version of a content item is deleted, based on its type and subtype. |
onAfterContentDeleteVersion |
|
Announced after a specific version of a content item is deleted. |
onAfter{Type}DeleteVersion |
|
Announced after a specific version of a content item is deleted, based on its type. |
onAfter{Type}{Subtype}DeleteVersion |
|
Announced after a specific version of a content item is deleted, based on its type, and subtype. |
Content Rendering Events
Event |
Rendered |
Description |
onSite404 |
|
Announced when a requested content item does not exist. |
onSiteCKEditorConfigRender |
X |
This event enables developers to programmatically add data to the CKEditor config.js.cfm file. |
onSiteCKFinderConfig |
|
This event enables developers to programmatically access, and manipulate the configuration settings for instances of CKFinder. |
onContentEdit |
X |
Renders a custom tab when editing content. Useful for creating a custom user interface to collect data on custom class extension attributes where the specified container is "Custom UI". Use m.event('tabLabel', 'Your Label Name') to set the tab label name. |
on{Type}Edit |
X |
For example:
- onPageEdit
- onFolderEdit
- onCalendarEdit
- onLinkEdit
|
on{Type}{Subtype}Edit |
X |
For example:
- onPageDefaultEdit
- onFolderDefaultEdit
- onCalendarDefaultEdit
- onLinkDefaultEdit
See https://gist.github.com/stevewithington/f3dd405d5a188fb594a1 for example useage.
|
onContentEditMessageRender |
X |
Announced before rendering the tabbed form on the "Edit Content" screen. Allows you to return a string to display as a message. See the Admin Alerts and Help Blocks section of the Mura UI Markup Conventions guide for markup-related information. |
on{Type}EditMessageRender |
X |
Announced before rendering the tabbed form on the "Edit Content" screen, based on the content type. Allows you to return a string to display as a message. See the Admin Alerts and Help Blocks section of the Mura UI Markup Conventions guide for markup-related information. For example:
- onPageEditMessageRender
- onFolderEditMessageRender
- onCalendarEditMessageRender
- onLinkEditMessageRender
|
on{Type}{Subtype}EditMessageRender |
X |
Announced before rendering the tabbed form on the "Edit Content" screen, based on the content type and subtype. Allows you to return a string to display as a message. See the Admin Alerts and Help Blocks section of the Mura UI Markup Conventions guide for markup-related information. For example:
- onPageDefaultEditMessageRender
- onFolderDefaultEditMessageRender
- onCalendarDefaultEditMessageRender
- onLinkDefaultEditMessageRender
|
onFeedEditMessageRender |
X |
Announced before rendering the tabbed form on the "Edit Local Index / Collection" screen. Allows you to return a string to display as a message. See the Admin Alerts and Help Blocks section of the Mura UI Markup Conventions guide for markup-related information. |
onSiteSearchRender |
X |
Announced before rendering search results. If a string is returned, it will be used in lieu of the default display. |
onDisplayRender |
X |
Announced when a value exists for the display event (e.g., ./?display=help ). Allows developers to return a custom display for the body area of a layout template based on the display URL parameter. Visit https://gist.github.com/stevewithington/6271863 for example usage. |
on{Type}{Subtype}BodyRender |
X |
For example:
- onPageDefaultBodyRender
- onFolderDefaultBodyRender
- onCalendarDefaultBodyRender
- onLinkDefaultBodyRender
|
on{Type}BodyRender |
X |
For example:
- onPageBodyRender
- onFolderBodyRender
- onCalendarBodyRender
- onLinkBodyRender
|
Comments Events
Event |
Rendered |
Description |
onBeforeCommentCreate |
|
Announced before comment is created. |
onBeforeCommentSave |
|
Announced before a comment is saved. |
onBeforeCommentUpdate |
|
Announced before a comment is updated. |
onBeforeCommentDelete |
|
Announced before a comment is deleted. |
onAfterCommentCreate |
|
Announced after a comment is created. |
onAfterCommentSave |
|
Announced after a comment is saved. |
onAfterCommentUpdate |
|
Announced after a comment is updated. |
onAfterCommentDelete |
|
Announced after a comment is deleted. |
onBeforeCommentUndelete |
|
Announced before a comment is undeleted. |
onAfterCommentUndelete |
|
Announced after a comment is undeleted. |
onBeforeCommentFlag |
|
Announced before a comment is flagged. |
onAfterCommentFlag |
|
Announced after a comment is flagged. |
onBeforeCommentMarkAsSpam |
|
Announced before a comment is marked as spam. |
onAfterCommentMarkAsSpam |
|
Announced after a comment is marked as spam. |
onBeforeCommentUnMarkAsSpam |
|
Announced before a comment is unmarked as spam. |
onAfterCommentUnMarkAsSpam |
|
Announced after a comment is unmarked as spam. |
Category Events
Event |
Rendered |
Description |
onBeforeCategoryCreate |
|
Announced before category is created. |
onBeforeCategorySave |
|
Announced before a category is saved. |
onBeforeCategoryUpdate |
|
Announced before a category is updated. |
onBeforeCategoryDelete |
|
Announced before a category is deleted. |
onAfterCategoryCreate |
|
Announced after a category is created. |
onAfterCategorySave |
|
Announced after a category is saved. |
onAfterCategoryUpdate |
|
Announced after a category is updated. |
onAfterCategoryDelete |
|
Announced after a category is deleted. |
File-specific Events
Event |
Rendered |
Description |
onFileEdit |
X |
Renders a custom tab when editing "file" content types. Useful for creating a custom user interface to collect data on custom class extension attributes where the specified container is "Custom UI". Use m.event('tabLabel', 'Your Label Name') to set the tab label name. |
onFileDefaultEdit |
X |
Same as onFileEdit , but using the subtype to be more specific. |
onBeforeFileCache |
|
|
onFileCache |
|
|
onAfterFileCache |
|
|
onFileCacheDelete |
|
|
onBeforeFileCacheDelete |
|
|
onAfterFileCacheDelete |
|
|
onBeforeFileRender |
|
|
onAfterFileRender |
|
|
onBeforeFilenameCreate |
|
|
onAfterFilenameCreate |
|
|
onBeforeImageManipulation |
|
Announced before an associated image is re-cropped, flipped or rotated. Sometimes used to tell a CDN to clear the existing version from cache. |
onAfterImageManipulation |
|
Announced after an associated image is re-cropped, flipped or rotated. |
Form-specific Events
Event |
Rendered |
Description |
onFormElementBasicTabRender |
X |
Announced when rendering a Mura Form element. |
onForm{Subtype}BodyRender |
X |
Announced before rendering a form. |
onBeforeFormSubmitSave |
|
Announced before a submitted form has been saved. |
onBeforeForm{Subtype}SubmitSave |
|
Announced before a submitted form with a subtype has been saved. |
onAfterFormSubmitSave |
|
Announced after a submitted form has been saved. |
onAfterForm{Subtype}SubmitSave |
|
Announced after a submitted form with a subtype has been saved. |
onFormSubmitErrorRender |
X |
Announced before displaying any errors from the form submission. |
onFormSubmitResponseRender |
X |
Announced when rendering the "success" response. |
onBeforeFormSubmitRedirect |
X |
Announced after the "success" response has rendered, and if request.redirect_url has been defined. Useful for rendering a custom response before displaying the request.redirect_url along with a request.redirect_label to display text for the link. Otherwise, if redirect_url is defined without a redirect_label , Mura will forward the user to the URL. |
Feed-specific Events
Event |
Rendered |
Description |
onBeforeFeedCreate |
|
Announced before a feed is created. |
onBeforeFeedSave |
|
Announced before a feed is saved. |
onBeforeFeedUpdate |
|
Announced before a feed is updated. |
onBeforeFeedDelete |
|
Announced before a feed is deleted. |
onFeedCreate |
|
Announced after a feed is created. |
onFeedSave |
|
Announced after a feed is saved. |
onFeedUpdate |
|
Announced after a feed is updated. |
onFeedDelete |
|
Announced after a feed is deleted. |
onAfterFeedCreate |
|
Announced after a feed is created. |
onAfterFeedSave |
|
Announced after a feed is saved. |
onAfterFeedUpdate |
|
Announced after a feed is updated. |
onAfterFeedDelete |
|
Announced after a feed is deleted. |
User-Related Events
The methods listed below are specifically related to Mura users.
User Editing Events
Event |
Rendered |
Description |
onBeforeUserCreate |
|
Announced before a Mura User is created. |
onBeforeUserUpdate |
|
Announced before a Mura User is updated. |
onBeforeUserSave |
|
Announced before a Mura User is saved. |
onBeforeUserDelete |
|
Announced before a Mura User is deleted. |
onBeforeUser{Subtype}Create |
|
Announced before a Mura User with a subtype is created. |
onBeforeUser{Subtype}Update |
|
Announced before a Mura User with a subtype is updated. |
onBeforeUser{Subtype}Save |
|
Announced before a Mura User with a subtype is saved. |
onBeforeUser{Subtype}Delete |
|
Announced before a Mura User with a subtype is deleted. |
onUserCreate |
|
Announced before a Mura User is created. |
onUserUpdate |
|
Announced before a Mura User is updated. |
onUserSave |
|
Announced before a Mura User is saved. |
onUserDelete |
|
Announced before a Mura User is deleted. |
onAfterUserCreate |
|
Announced after a Mura User has been created. |
onAfterUserUpdate |
|
Announced after a Mura User has been updated. |
onAfterUserSave |
|
Announced after a Mura User has been saved. |
onAfterUserDelete |
|
Announced after a Mura User has been deleted. |
onAfterUser{Subtype}Create |
|
Announced after a Mura User with a subtype has been created. |
onAfterUser{Subtype}Update |
|
Announced after a Mura User with a subtype has been updated. |
onAfterUser{Subtype}Save |
|
Announced after a Mura User with a subtype has been saved. |
onAfterUser{Subtype}Delete |
|
Announced after a Mura User with a subtype has been deleted. |
Group Editing Events
Event |
Rendered |
Description |
onBeforeGroupCreate |
|
Announced before a Mura Group is created. |
onBeforeGroupUpdate |
|
Announced before a Mura Group is updated. |
onBeforeGroupSave |
|
Announced before a Mura Group is saved. |
onBeforeGroupDelete |
|
Announced before a Mura Group is deleted. |
onBeforeGroup{Subtype}Create |
|
Announced before a Mura Group with a subtype is created. |
onBeforeGroup{Subtype}Update |
|
Announced before a Mura Group with a subtype is updated. |
onBeforeGroup{Subtype}Save |
|
Announced before a Mura Group with a subtype is saved. |
onBeforeGroup{Subtype}Delete |
|
Announced before a Mura Group with a subtype is deleted. |
onGroupCreate |
|
Announced before a Mura Group is created. |
onGroupUpdate |
|
Announced before a Mura Group is updated. |
onGroupSave |
|
Announced before a Mura Group is saved. |
onGroupDelete |
|
Announced before a Mura Group is deleted. |
onGroup{Subtype}Create |
|
Announced before a Mura Group with a subtype is created. |
onGroup{Subtype}Update |
|
Announced before a Mura Group with a subtype is updated. |
onGroup{Subtype}Save |
|
Announced before a Mura Group with a subtype is saved. |
onGroup{Subtype}Delete |
|
Announced before a Mura Group with a subtype is deleted. |
onAfterGroup{Subtype}Create |
|
Announced after a Mura Group with a subtype is created. |
onAfterGroup{Subtype}Update |
|
Announced after a Mura Group with a subtype is updated. |
onAfterGroup{Subtype}Save |
|
Announced after a Mura Group with a subtype is saved. |
onAfterGroup{Subtype}Delete |
|
Announced after a Mura Group with a subtype is deleted. |
Group & User Rendering Events
Event |
Rendered |
Description |
onGroupEdit |
X |
Renders a tab when editing a group |
onUserEdit |
X |
Renders a tab when editing a user |
Login Related Events
Event |
Rendered |
Description |
onSiteLogin |
|
Announced when a user is logging in, if session.siteid exists. |
onSiteLoginSuccess |
|
Announced when a user has successfully logged in, if session.siteid exists. |
onSiteLoginFailure |
|
Announced when a user has failed to log in due to incorrect credentials, if session.siteid exists. |
onSiteLoginBlocked |
|
Announced when a user has unsuccessfully attempted to log in too many times, if session.siteid exists. |
onSiteLogout |
|
Announced when a user has logged out, if session.siteid exists. |
onBeforeSiteLogout |
|
Announced before a user is logged out, if session.siteid exists. |
onAfterSiteLogout |
|
Announced after a user has logged out, if session.siteid exists. |
onGlobalLogin |
|
Announced when a user is logging in, if session.siteid does not exist. |
onGlobalLoginSuccess |
|
Announced when a user has successfully logged in, if session.siteid does not exist. |
onGlobalLoginFailure |
|
Announced when a user has failed to log in, if session.siteid does not exist. |
onGlobalLoginBlocked |
|
Announced when a user has unsuccessfully attempted to log in too many times, if session.siteid does not exist. |
onGlobalLogout |
|
Announced when a user has logged, if session.siteid does not exist. |
onBeforeGlobalLogout |
|
Announced before a user is logged out, if session.siteid does not exist. |
onAfterGlobalLogout |
|
Announced after a user has logged out, if session.siteid does not exist. |
onSiteEditProfileRender |
X |
Announced when a user is about to be presented with the "Edit Profile" form. If returning a string, the result will be displayed to the end-user in lieu of the default form. |
onSiteLoginPromptRender |
X |
Announced when a user is about to be presented with the "Login" form. If returning a string, the result will be displayed to the end-user in lieu of the default form. |
onContentDenialRender |
X |
Announced when a user is about to be presented with the "Restricted" screen. If returning a string, the result will be displayed to the end-user in lieu of the default screen. |
onAdminMFAChallengeRender |
X |
If Multi-Factor Authentication (MFA) is enabled, this event is announced when rendering the MFA section of the Admin login screen. |
onSiteMFAChallengeRender |
X |
If Multi-Factor Authentication (MFA) is enabled, this event is announced when rendering the MFA section of the site's login screen. |
onMFAAttemptChallenge |
|
If Multi-Factor Authentication (MFA) is enabled, this event is announced when checking to see if the authcode entered is valid. Should return true if valid, or false if invalid, or nothing if you wish Mura to validate it. |
Custom Events
In addition to all of Mura's event hooks, developers may also create their own, custom event hooks. The main decision you'll want to make is whether you wish to "announce" an event, or "render" an event. Regardless of whether you choose to announce an event, or render an event, Mura will trigger your event as illustrated below, and in turn, any registered event handlers with these methods defined, will be executed:
on{YourEvent}
Announcing Events
When you "announce" an event, you're essentially sending a notification throughout Mura that something in particular is about to occur, or has just occurred. You may omit the "on" from your event name when announcing it. However, your method itself should contain the "on" prefix.
Syntax
The basic syntax for announcing an event is:
m.announceEvent('YourEvent', m);
// OR
m.announceEvent('onYourEvent', m);
When Mura encounters the code above, it will search for any registered event handlers to locate onYourEvent()
, and if found, the method will be executed.
Example
The following example illustrates a very simple form, with a text field named myField
. The value
attribute will be pre-populated with its own value. In other words, since the event
scope itself wraps CFML's URL
, Form
, and Request
scopes, we can check the event
scope for the value, and if the form is submitted, then any value entered will be used to pre-populate itself.
<form method="post">
<input type="text" name="myField" value="[m]esapiEncode('html_attr', m.event('myField'))[/m]">
<input type="hidden" name="myFormIsSubmitted" value="true">
<input type="submit">
</form>
In the example form above, we're using a hidden field named myFormIsSubmitted
with its value set to "true". By checking the event
scope for this value, if found, we can trigger an event to occur, as shown the example below.
// check form submission via `onRenderStart`, and if found, announce your custom event.
public any function onRenderStart(m) {
if ( arguments.m.event('myFormIsSubmitted') == 'true' ) {
// announcing the event
arguments.m.announceEvent('CustomFormSubmitted', arguments.m);
}
}
If the form has been submitted, our customFormSubmitted
event is announced, triggering any registered event handlers to execute.
public any function onCustomFormSubmitted(m) {
// you could do whatever you want here
// including dumping out the entire event itself to inspect it
// or simply dumping out the value of a specific form filed
// and then halt the rest of the process (for example only)
WriteDump(var=arguments.m.event('myField'), abort=true);
}
Rendering Events
If you wish to "render" an event, in addition to sending a notification throughout Mura that something in particular is about to occur, or has just occurred, you are allowing for the possibility to render something to the browser. In other words, your code should be checking for a string to return, and if nothing is returned, then you'll most likely want to display something else by default.
Syntax
The basic syntax for rendering an event is:
m.renderEvent('YourEvent');
Examples
There are several ways you could choose to render event output. The following example illustrates a simple way to output the result of a rendered event.
<cfoutput>
#esapiEncode('html', m.renderEvent('YourEvent'))#
</cfoutput>
The example below is typical of how Mura renders events in its own code.
eventOutput = esapiEncode('html', m.renderEvent('YourEvent'));
if ( Len(eventOutput) ) {
WriteOutput(eventOutput);
} else {
// render something else / default output
}
Event Lifecycles
Lifecycle events are generally triggered on every page request, and represent the execution of Mura's normal request flow. Mura consists of primarily two unique lifecycles: the Front-end Request Lifecycle, and the Admin Request Lifecycle. During the flow of these lifecycles, other contextual events are triggered, and are dependent upon the requested action that precedes it.
Admin Request Lifecycle
The administration area of Mura has a multitude of contextual events that could be triggered, depending on the requested action. For example, a user could be attempting to create new content, updating a user, or deleting a category. Each of these actions would trigger their own contextual events, in addition to the routine request flow outlined below.
onGlobalRequestStart
onAdminRequestStart
onAdminHTMLHeadRender // renders just before the closing </head> tag
onAdminMFAChallengeRender // Multi-factor Auth area of login screen
onDashboardReplacement // render a completely new dashboard
onDashboardPrimaryTop // renders in the top of the dashboard
onDashboardPrimaryBottom // renders in the bottom of the dashboard
onDashboardSidebarTop // renders in the top of the dashboard sidebar
onDashboardSidebarBottom // renders in the bottom of the dashboard sidebar
onAdminNavMainRender // render additional main nav menu items
onFEToolbarExtensionRender // render additional front-end toolbar menu items
on{Type}SecondaryNavRender
on{Type}{Subtype}SecondaryNavRender
on{Type}{Subtype}NewContentMenuRender
onNewContentMenuRender
onAdminHTMLFootRender // renders just before the closing </body> tag
onAdminRequestEnd
onGlobalRequestEnd
Front-End Request Lifecycle
While there may be any number of contextual events that are triggered, dependent upon the requested action, the events listed below generally occur during a typical front-end request.
When it comes to the front-end request lifecycle, if you're most interested in the final string of code that will be returned to the browser, then you'll want to be aware of m.event('__MuraResponse__')
. That's a double-underscore in front of, and after "MuraResponse". As noted in the lifecycle below, the "MuraResponse" will be sent to the browser.
onGlobalRequestStart
onSiteRequestInit
onSiteRequestStart
standardEnableLockdownValidator
standardEnableLockdownHandler // if lockdown enabled
standardSetContentHandler
// if `previewid` exists
standardSetPreviewHandler
// else
standardSetAdTrackingHandler
standardWrongFilenameValidator
standardWrongFilenameHandler // if wrong filename
standard404Validator
standard404Handler // contextual: if content item not found
onSite404
standardWrongDomainValidator
standardWrongDomainHandler // if invalid domain
standardTrackSessionValidator
standardTrackSessionHandler // if session tracking enabled
standardSetIsOnDisplayHandler
standardDoActionsHandler // checks `doaction` (e.g., login, logout, etc.)
standardSetPermissionsHandler
standardRequireLoginValidator
standardRequireLoginHandler // if login required
standardSetLocaleHandler
standardMobileValidator
standardMobileHandler // if `request.muraMobileRequest` and no `altTheme`
standardSetCommentPermissions
standardDoResponseHandler
standardForceSSLValidator
standardForceSSLHandler // if necessary
// This is a great place to put your logic
// Mura begins compiling the code that will be returned to the browser
onRenderStart
// if content type is link
standardLinkTranslationHandler
// else if content type is file
standardFileTranslationHandler
standardFileTranslator
onBeforeFileRender
onAfterFileRender
// else
standardTranslationHandler // sets m.event('__MuraResponse__')
// if `returnformat` is JSON
standardJSONTranslator
onAPIResponse
on{Type}APIResponse
on{Type}{Subtype}APIResponse
onAPIError // if an error occurs
// else
standardHTMLTranslator // parses layout template and renders queues
// other events could be announced, based on template code
// `m.dspBody()` invokes several events (and is included in most templates)
// if event('display') is `search`
onSiteSearchRender
// else if event('display') is `editprofile`
onSiteEditProfileRender
// else if event('display') is `login`
onSiteLoginPromptRender
// else if content is restricted and user not allowed
onContentDenialRender
// else if content is not on display
onContentOfflineRender
// else if `m.event('display')` is not an empty string
onDisplayRender // allows you to have custom displays
// else
// default body rendering
on{Type}{Subtype}BodyRender // e.g., onPageDefaultBodyRender
// if a string isn't returned, then
on{Type}BodyRender // e.g., onPageBodyRender
// if a string still isn't returned, then
// Mura will look for files by content type
// `../{ThemeName}/content_types/{Type}_{Subtype}/index.cfm`
// Then, `../{ThemeName}/content_types/{Type}/index.cfm`
// and so forth.
// See the "Mura Rendering" section for more information
// Mura has finished compiling the code to return to the browser
// In other words, the train is about to leave the station ...
onRenderEnd // m.event('__MuraResponse__') is ready
onSiteRequestEnd
onGlobalRequestEnd
Event Handlers
Mura event handlers are simply ColdFusion components (CFCs), or files saved with the extension .cfc
. They contain methods/functions, and may contain other variables and/or data. Most event handlers will contain one or more of Mura's event hooks, and/or custom event hooks.
The event hooks are merely "announced" during specific points of a request. Registered event handlers will be parsed when the event they're registered for occurs, and if any event hooks are found, they will be executed. For example, if you have two registered even handlers, and both of them contain a method listening for the same event hook, both methods will execute, whenever the event is announced.
As described in the Standard Events section, Mura's standard events handler is located under {context}/core/mura/Handler/standardEventsHandler.cfc
. The methods may be viewed via Mura's Component API at http://www.getmura.com/component-api/7.1/index.html?mura/Handler/standardEventsHandler.html.
Developers may have several Mura event handlers throughout your sites, themes, content types, modules, and plugins. As of Mura v7.1, you may also register your event handler(s) for specific entities. In addition, you can choose to register your event handlers by convention, or explicitly register them via a known event handler. Examples and options are described below.
Example Event Handler
With the exception of the "Site" event handler, or the "Theme" event handler, you can name your event handler anything you want, as long as it has the .cfc
file extension. All event handlers should extend mura.cfobject
. By doing so, you allow yourself the ability to leverage many of Mura's baked-in methods and functionality for working with Mura objects.
CFScript-based .CFC Example
component extends="mura.cfobject" {
public any function onSomeEvent(m) {
// arguments.m is "The Mura Scope"
// Do something
}
}
Tag-based .CFC Example
<cfcomponent extends="mura.cfobject" output="false">
<cffunction name="onSomeEvent" access="public" returntype="any">
<cfargument name="m" hint="Mura Scope">
<!--- Do something --->
</cffunction>
</cfcomponent>
Plugin Event Handlers
Plugin event handlers should extend mura.plugin.pluginGenericEventHandler
, instead of using the typical mura.cfobject
. Doing so allows you access to the plugin's own configuration information via variables.pluginConfig
, as well as Mura's configuration data via variables.configBean
.
Registering event handlers in plugins is covered in the Plugins section.
How To Register Event Handlers By Convention
One way to register a Mura event handler is by convention. This means, if you create a .CFC
file, and place it in a "known" location, Mura will automatically register it, and any event hooks contained within it will be executed when announced.
The "Site" Event Handler
Mura automatically checks every site for a specific file, labeled eventHandler.cfc
,under the following location:
{context}/sites/{SiteID}/eventHandler.cfc
If this file is found, Mura will instantiate it on every front-end request. This means that any methods placed within this file should be specific to front-end requests. If you attempt to add any other request types here, for example, any events which occur only during the admin request lifecycle, they will not be executed.
The "Theme" Event Handler
Mura automatically checks the theme for a specific file, labeled eventHandler.cfc, under the following location:
{context}/sites/{SiteID}/themes/{ThemeName}/eventHandler.cfc
// OR
{context}/themes/{ThemeName}/eventHandler.cfc
Mura checks for this file during the onApplicationLoad
event. When discovered, Mura instantiates it, and places the file into the application
scope.
Note: Since the file is only instantiated when the application loads, you must reload Mura anytime you make a change to the file itself.
Content Type & Module Event Handlers
Mura automatically scans both the content_types
and modules
directories for the following directory structure:
../model/handlers/{anyFilename}.cfc
Any .cfc
discovered under these ../model/handlers/
directories will be registered as event handlers. Currently, content_types
and modules
directories can reside under a site and/or a theme.
// Sites
{context}/sites/{SiteID}/content_types/{Type}_{Subtype}/model/handlers/
{context}/sites/{SiteID}/modules/{module}/model/handlers/
// Themes
../themes/{ThemeName}/content_types/{Type}_{Subtype}/model/handlers/
../themes/{ThemeName}/modules/{module}/model/handlers/
Additional information regarding content types and modules can be found in the Mura Rendering section.
How To Explicitly Register Event Handlers
The basic syntax for explicitly registering a custom event handler is:
m.getBean('pluginManager').addEventHandler(
{handlerObject or path}
, {SiteID}
);
For example, you may use one of the "known" registered event handlers, such as either the "Site" or "Theme" event handler. Then, using the onApplicationLoad
event, you can register your custom event handler as follows:
public any function onApplicationLoad(m) {
// Assuming the customHandler.cfc file exists in the same directory as this file
var myHandler = new customHandler();
// Register the custom handler
arguments.m.getBean('pluginManager').addEventHandler(
myHandler
, arguments.event.get('siteid')
);
}
Entity Event Handlers
Introduced in Mura v7.1, developers may register event handlers for specific beans/objects or entities such as content beans, user beans, or even your own custom entities/objects. This allows developers the ability to create more focused business logic and code clarity.
For example, if you registered an event handler for "onRenderStart
", your method will be invoked on each and every front-end page request, regardless of the content type, etc. Using targeted logic allows you to specify not only the object and type, you could also target a very specific object by loading it up, and attaching a custom event handler to it.
To target a specific bean/object, we begin by using the "onApplicationLoad
" event of a registered event handler.
public any function onApplicationLoad(m} {
// This is where our code will be
}
Then, we'll target a specific bean/object, and use either the "on
" or "addEventHander
" methods described below.
on
A bean/object helper method to dynamically register an event handler. Methods may be chained to attach multiple event handlers.
Function Syntax
m.getBean('someBean').on( eventName, fn )
Parameters
Parameter |
Type |
Req/Opt |
Description |
eventName |
string |
Req |
The name of the event you wish to register, without the "on " prefix. For example, if you wish to target the "onRenderStart " method, set this to "renderStart ". |
fn |
function |
Req |
A function, or name of a function containing the code you wish to execute. |
Examples
In this example, we're going to target a specific content bean, and attach a custom "onRenderStart
" event handler to it.
public any function onApplicationLoad(m) {
m.getBean('content')
.loadBy(title='Contact Us')
.on('renderStart', function(m) {
// do something
});
}
In this example, we're targeting a user bean, and attaching a custom "onUserDelete
" event handler.
public any function onApplicationLoad(m) {
m.getBean('user')
.loadBy(useranme='steve')
.on('userDelete', function(m) {
// do something
});
}
In this example, we're targeting the global config bean, and attaching a custom "onRenderEnd
" event handler.
public any function onApplicationLoad(m) {
m.getBean('configBean')
.on('onRenderEnd', function(m) {
// do something
});
// OR
m.globalConfig()
.on('onRenderEnd', function(m) {
// do something
});
}
Note: When attaching event handlers to the global config bean, the event handler(s) will apply throughout the entire instance of Mura, across all sites.
In this example, we're loading a content bean to target a specific form, and attaching a custom "onSubmitSave
" event handler, and then chaining an additional handler for the "onSubmitResponseRender
" event.
public any function onApplicationLoad(m) {
m.getBean('content')
.loadBy(title='Information Request Form')
.on('submitSave', function(m) {
// do something
})
.on('submitResponseRender', function(m) {
// do something
});
}
In this example, we're targeting the global config bean, and attaching custom handlers for a custom ORM bean which will be invoked throughout all of Mura, regardless of which site is running.
public any function onApplicationLoad(m) {
m.getBean('configBean')
.on('beforeWidgetSave', function(m) {
// do something
})
.on('widgetSave', function(m) {
// do something
})
.on('widgetSave', function(m) {
// do something
});
}
addEventHandler
A bean/object helper method to dynamically register event handlers.
Function Syntax
m.getBean('someBean').addEventHandler( component )
Parameters
Parameter |
Type |
Req/Opt |
Description |
component |
struct |
Req |
A struct of key/value pairs of eventNames and functions to execute as event handlers for the specified eventName(s). |
Examples
In this example, we're targeting the global config bean, and attaching custom handlers for a custom ORM bean which will be invoked throughout all of Mura, regardless of which site is running.
public any function onApplicationLoad(m) {
m.getBean('configBean')
.addEventHandler({
beforeWidgetSave = function(m) {
// do something
}
, widgetSave = function(m) {
// do something
}
, afterWidgetSave = function(m) {
// do something
}
});
}
In this example, we're targeting a specific custom ORM bean and attaching some custom event handlers.
public any function onApplicationLoad(m) {
m.getBean('widget')
.loadBy(id='someID')
.addEventHandler({
beforeSave = function(m) {
// do something
}
, save = function(m) {
// do something
}
, afterSave = function(m) {
// do something
}
});
}
Mura's Event Log
Mura has the capability to output an event log as a stack trace, including the time it took to execute, in milliseconds, directly to the browser. This feature is quite useful for troubleshooting and debugging, as well as discovering which areas of your code may benefit from applying performance optimization techniques.
How to Enable/Disable the Stack Trace
To enable the stack trace, you must first be logged in to Mura as an Administrator. Then, simply append /?showtrace=1
to the URL, and reload your browser. Once you do this, Mura will append a stack trace output to the end of your page, similar to the following example.

Mura will then set a cookie, so you don't have to continually add it to each and every page you visit.
If you wish to disable this feature, simply append /?showtrace=0
to the URL, and the stack trace should disappear after reloading your browser.
How to Read/Use the Stack Trace
The stack trace displays information useful for both debugging or troubleshooting, as well as identifying areas of code execution that might benefit from using some performance optimization techniques, such as caching, or possibly even rewriting the code to run more efficiently.
Each item in the stack trace is listed in the order in which it was encountered during the execution of the request. Some items in the list simply display informational messages, and don't necessarily point to any specific line of code, while others output the entire path to the file or method being parsed.
In the parenthesis to the right of each item in the list are two numbers. The number on the left indicates the number of milliseconds it took the server to parse the specific file or method, while the number on the right reflects the point in the total request (in milliseconds) when the file or method finished executing.
So, for example, if you review the following stack trace, note item number 14.

Item number 14 indicates that Mura was parsing the two_column_SR.cfm
layout template, and it took the server a total of 334 milliseconds to execute, and completed its execution at the 482nd millisecond.
Item number 15 indicates a method call to contentRenderer.dspPrimaryNav
, which in turn was invoked during the execution of parsing the two_column_SR.cfm
file. The dspPrimaryNav
method finished executing at the 255th millisecond. Subsequent items were then executed in the order listed.
While you may not necessarily have the ability to optimize some of Mura's core methods, you can see the two_column_SR.cfm
layout template is code you have direct control over. Maybe some of the code within the layout template could benefit from using a caching strategy, or some other form of performance optimization.
Custom Stack Trace Points
As a Mura developer, you may add your own custom messages to the stack trace output. This is useful for inspecting how long it takes for your custom code to execute, quickly and easily.
The example below illustrates how to add your own trace point(s).
<!--- Place this either at the top of your file, or at the beginning of a block of code you wish to trace --->
<cfset myTracePoint = $.initTracePoint('your filename, method name, or other description to identify this trace point goes here ... this is what will output in the Stack Trace') />
<!--- file content or block of code goes here --->
<!--- Place this either at the bottom of your file, or at the end of a block of code you wish to trace --->
<cfset m.commitTracePoint(myTracePoint) />
This is an example stack trace output, using the above code in the footer.cfm
layout template of the default theme.

Summary
Throughout this section, we covered the differences between lifecycle events and contextual events, the Mura "event" scope, and the wide variety of possible events that may occur during any given request, as well as how to register your own event handlers targeting the specific event(s) related to the task(s) you wish to accomplish. Finally, you learned how to create your own custom events, and how to use Mura's event log for debugging and performance optimization purposes.
We hope that as you completed this section, you have a much better understanding on how you, as a Mura developer, can add to, or in some cases, even replace, Mura's own business logic and functionality.