I still have some CustomTags that we've used in production for years and, now that I'm writing more cfscript, I thought I'd continue using some of them (for now) using the following syntax that I learned about on StackOverflow:
CFML tag-based approach:
<cf_customTagName param1=param1Value>
CFScript approach:
cf_customTagName(param1=param1Value);
I immediately discovered that the cfscript method was executing the tag twice. In order to execute the tag-based version twice using CFML tag-based syntax, you need to explicitly use a starting and closing tag and then check for thisTag.executionMode
with a value of either start
or end
.
<cf_customTagName param1=param1Value>
<!--- this runs the tag twice w/different executionModes --->
</cf_customTagName>
The "nuance" (that CFM-based custom tags are always executed twice twice via cfscript) isn't documented on the only Adobe documentation that discusses this: "Script support for custom tags". (NOTE: I'm not sure if this behavior is the same in Lucee CFML.)
The solution for this is check whether the CFM file is being executed as a CustomTag (ie, if thisTag.executionMode
exists and is start
) and then exit.
<cfif isDefined("thisTag.executionMode") and thisTag.executionMode is "start">
<cfexit>
</cfif>
If you don't explicitly do it this way, you'll risk having the customtag's functions unknowingly performed twice which can cause data problems or negatively impact performance.
Here's the files I set up to reproduce and test this:
https://gist.github.com/JamoCA/2d48f9eb88ceb7f8bcb93fc3ab718ffa
Top comments (3)
On the Lucee CFML side, I've run into some quirky behaviors trying to get Custom Tags to run in CFScript. Since Lucee allows all tags to be run in script by essentially removing the
cf
prefix,Example,
<cfthread></cfthread>
becomesthread { .. }
Example,
<cfhttp></cfhttp>
becomeshttp { .. }
... I think you can actually run a custom tag by just removing the
cf
.Example,
<cf_helloCount></cf_helloCount>
becomes_helloCount { .. }
With, admittedly, looks strange :D But, there's some strange syntax parsing issues (if I remember correctly it's related to trying to run the tag on a single line vs. with line-breaks around attributes).
Also, I don't believe I've found a way in either engine to use the Prefix feature of custom tags' interplay with
<cfimport>
. I'm pretty sure that neither engine likes the syntax:prefix:tag { ... }
I love CFScript, but I've been sticking to tags for custom tag usage.
On ACF it will also execute twice if you use a self-closing tag, which I would pretty much always do and due to that I always got used to writing them with the execution mode check.
<cf_customTagName param1="param1Value" />
Yeah... I've been careful to not self-close CustomTags. I didn't expect cfscript to treat it as a closed tag as there's a specific syntax for that.