|
| 1 | +<!-- |
| 2 | +{ |
| 3 | + "title": "Custom Tag Mappings", |
| 4 | + "id": "mappings-custom-tag-mappings", |
| 5 | + "related": [ |
| 6 | + "mappings-component-mappings", |
| 7 | + "mappings-how-to-define-a-reg-mapping", |
| 8 | + "tag-application", |
| 9 | + "tag-import", |
| 10 | + "import" |
| 11 | + ], |
| 12 | + "categories": [ |
| 13 | + "application", |
| 14 | + "tags", |
| 15 | + "server" |
| 16 | + ], |
| 17 | + "description": "How to define and use custom tag mappings in Lucee.", |
| 18 | + "keywords": [ |
| 19 | + "Custom Tag Mapping", |
| 20 | + "Custom Tags", |
| 21 | + "cfimport", |
| 22 | + "Application.cfc", |
| 23 | + "Lucee archive", |
| 24 | + "taglib" |
| 25 | + ] |
| 26 | +} |
| 27 | +--> |
| 28 | + |
| 29 | +# Custom Tag Mappings |
| 30 | + |
| 31 | +Custom tag mappings in Lucee define locations where the server will look for CFML custom tags when you use them in your code. |
| 32 | + |
| 33 | +They provide a way to organize and access your custom tags without having to specify the full path each time or use [[tag-import]] repeatedly. |
| 34 | + |
| 35 | +## Understanding Custom Tag Mappings |
| 36 | + |
| 37 | +Custom tags are reusable CFML templates that you can call like built-in tags. Custom tag mappings tell Lucee where to find these custom tag files. |
| 38 | + |
| 39 | +For example, if you have a custom tag file at: |
| 40 | + |
| 41 | +``` |
| 42 | +/path/to/your/app/customtags/myTag.cfm |
| 43 | +``` |
| 44 | + |
| 45 | +With a custom tag mapping pointing to `/path/to/your/app/customtags/`, you can use the tag in your code like: |
| 46 | + |
| 47 | +```coldfusion |
| 48 | +<cf_myTag attribute="value"> |
| 49 | +``` |
| 50 | + |
| 51 | +Like other mapping types in Lucee (regular mappings and component mappings), custom tag mappings consist of several parts: |
| 52 | + |
| 53 | +- **physical**: Physical directory where custom tag files are stored |
| 54 | +- **archive**: A Lucee archive (.lar file) that contains the custom tags; a .lar file is the same as a .jar file in Java, containing the compiled templates (and optionally the source) |
| 55 | +- **primary**: When both "physical" and "archive" are defined, this setting determines where to look first for a custom tag; by default, it looks first in "physical"; possible values are "physical" and "archive" |
| 56 | +- **readonly**: Determines if the mapping can be configured in the Lucee admin or not (not needed for mappings defined in Application.cfc) |
| 57 | +- **hidden**: Controls visibility in the Lucee admin (not needed for mappings defined in Application.cfc) |
| 58 | +- **inspectTemplate**: Controls Lucee's behavior when checking for changes |
| 59 | + |
| 60 | +## Defining Custom Tag Mappings |
| 61 | + |
| 62 | +### In the Lucee Administrator |
| 63 | + |
| 64 | +Custom tag mappings can be defined in the Lucee Server or Web Administrator. Go to the **Archives & Resources / Custom Tag** page. |
| 65 | + |
| 66 | +Mappings defined in the Server Administrator are visible to all web contexts, while mappings defined in the Web Administrator are only visible to the current web context. |
| 67 | + |
| 68 | +The default mapping for custom tags is under `{lucee-config}/customtags/`, where the `{lucee-config}` is a [[configuration-directory-placeholders]] which resolves to your `lucee-server\context` directory. |
| 69 | + |
| 70 | +```cfml |
| 71 | +dump( expandPath( "{lucee-config}" ) ); |
| 72 | +``` |
| 73 | + |
| 74 | +### Using CFConfig |
| 75 | + |
| 76 | +Custom tag mappings can be defined in a CFConfig JSON file: |
| 77 | + |
| 78 | +```json |
| 79 | +{ |
| 80 | + "customTagMappings": [ |
| 81 | + { |
| 82 | + "physical": "/path/to/customtags/", |
| 83 | + "archive": "", |
| 84 | + "primary": "physical", |
| 85 | + "inspectTemplate": "always" |
| 86 | + } |
| 87 | + ] |
| 88 | +} |
| 89 | +``` |
| 90 | + |
| 91 | +Remember, the Lucee Admin is a GUI for `.CFConfig.json`. |
| 92 | + |
| 93 | +### In Application.cfc |
| 94 | + |
| 95 | +Custom tag mappings can also be defined in the `Application.cfc` file, making them specific to the current application: |
| 96 | + |
| 97 | +```cfs |
| 98 | +// Application.cfc |
| 99 | +component { |
| 100 | + this.customTagPaths = [ |
| 101 | + getDirectoryFromPath( getCurrentTemplatePath() ) & "customtags" |
| 102 | + ]; |
| 103 | +} |
| 104 | +``` |
| 105 | + |
| 106 | +**Important**: Unlike `this.mappings` (which uses structs), `this.customTagPaths` takes an **array** because there is no "virtual path" that needs to be defined. Custom tags are found by filename in any of the mapped directories. |
| 107 | + |
| 108 | +## Using Custom Tags |
| 109 | + |
| 110 | +Once you've defined your custom tag mappings, you can use custom tags in your code: |
| 111 | + |
| 112 | +```cfml |
| 113 | +<!-- Using the cf_ prefix notation --> |
| 114 | +<cf_myCustomTag attribute="value"> |
| 115 | +
|
| 116 | +<!-- Or with closing tag --> |
| 117 | +<cf_myCustomTag attribute="value"> |
| 118 | + Some content here |
| 119 | +</cf_myCustomTag> |
| 120 | +``` |
| 121 | + |
| 122 | +Custom tags can also be invoked using `cfmodule`: |
| 123 | + |
| 124 | +```cfml |
| 125 | +<cfmodule template="myCustomTag.cfm" attribute="value"> |
| 126 | +``` |
| 127 | + |
| 128 | +## Using cfimport for Prefixed Custom Tags |
| 129 | + |
| 130 | +Instead of using the `cf_` prefix, you can import custom tags with a custom prefix using `cfimport`: |
| 131 | + |
| 132 | +```cfml |
| 133 | +<cfimport prefix="my" taglib="/customtags/"> |
| 134 | +
|
| 135 | +<!-- Then use with your custom prefix --> |
| 136 | +<my:customTag attribute="value"> |
| 137 | +``` |
| 138 | + |
| 139 | +Or in script syntax: |
| 140 | + |
| 141 | +```cfml |
| 142 | +cfimport( prefix="my", taglib="/customtags/" ); |
| 143 | +``` |
| 144 | + |
| 145 | +**Note**: The `import` keyword cannot be used for custom tags—only `cfimport` supports the `prefix` and `taglib` attributes. |
| 146 | + |
| 147 | +The `cfimport` approach is useful when: |
| 148 | + |
| 149 | +- You want to use a more descriptive prefix than `cf_` |
| 150 | +- You have custom tags from different sources and want to namespace them |
| 151 | +- You want to make it clear where a custom tag comes from in your code |
| 152 | + |
| 153 | +## Advanced Usage |
| 154 | + |
| 155 | +### Using Archives |
| 156 | + |
| 157 | +You can package your custom tags into a Lucee Archive (.lar) file and reference it in your custom tag mapping: |
| 158 | + |
| 159 | +```cfs |
| 160 | +// Application.cfc |
| 161 | +component { |
| 162 | + this.customTagPaths = [ |
| 163 | + { |
| 164 | + physical: getDirectoryFromPath( getCurrentTemplatePath() ) & 'customtags', |
| 165 | + archive: getDirectoryFromPath( getCurrentTemplatePath() ) & 'customtags.lar', |
| 166 | + primary: 'archive' |
| 167 | + } |
| 168 | + ]; |
| 169 | +} |
| 170 | +``` |
| 171 | + |
| 172 | +With `primary` set to "archive", Lucee first checks the .lar file for custom tags. If not found there, it looks in the physical path. |
| 173 | + |
| 174 | +This is particularly useful for: |
| 175 | + |
| 176 | +- Deploying compiled custom tags |
| 177 | +- Protecting source code |
| 178 | +- Improving performance by reducing file system checks |
| 179 | + |
| 180 | +### InspectTemplate Options |
| 181 | + |
| 182 | +The `inspectTemplate` attribute controls how Lucee checks for changes to your custom tags: |
| 183 | + |
| 184 | +- **auto**: Monitors the filesystem for changes (default) |
| 185 | +- **never**: Never checks for changes (best for production) |
| 186 | +- **once**: Checks filesystem once per request |
| 187 | +- **always**: Slow, checks the filesystem everytime the templates are accessed. |
| 188 | + |
| 189 | +By default, mappings inherit the server-level `inspectTemplate` setting. You can override this per mapping if needed. |
| 190 | + |
| 191 | +```cfs |
| 192 | +// Application.cfc |
| 193 | +component { |
| 194 | + this.customTagPaths = [ |
| 195 | + { |
| 196 | + physical: getDirectoryFromPath( getCurrentTemplatePath() ) & 'customtags', |
| 197 | + inspectTemplate: 'never' |
| 198 | + } |
| 199 | + ]; |
| 200 | +} |
| 201 | +``` |
| 202 | + |
| 203 | +### Multiple Custom Tag Paths |
| 204 | + |
| 205 | +You can define multiple custom tag paths, and Lucee will search them in order: |
| 206 | + |
| 207 | +```cfs |
| 208 | +// Application.cfc |
| 209 | +component { |
| 210 | + this.customTagPaths = [ |
| 211 | + getDirectoryFromPath( getCurrentTemplatePath() ) & "customtags", |
| 212 | + expandPath( "/shared/customtags" ), |
| 213 | + getDirectoryFromPath( getCurrentTemplatePath() ) & "vendor/tags" |
| 214 | + ]; |
| 215 | +} |
| 216 | +``` |
| 217 | + |
| 218 | +When you use a custom tag, Lucee will search each path in order until it finds the matching custom tag file. |
| 219 | + |
| 220 | +## Creating Custom Tags |
| 221 | + |
| 222 | +Custom tags are simply CFML templates that can access special variables: |
| 223 | + |
| 224 | +- `attributes` scope: Contains all attributes passed to the custom tag |
| 225 | +- `caller` scope: Allows the custom tag to read and write variables in the calling template |
| 226 | +- `thisTag` scope: Contains metadata about the custom tag execution |
| 227 | + |
| 228 | +Example custom tag (`customtags/greeting.cfm`): |
| 229 | + |
| 230 | +```coldfusion |
| 231 | +<cfparam name="attributes.name" default="World"> |
| 232 | +
|
| 233 | +<cfoutput> |
| 234 | + Hello, #attributes.name#! |
| 235 | +</cfoutput> |
| 236 | +``` |
| 237 | + |
| 238 | +Usage: |
| 239 | + |
| 240 | +```coldfusion |
| 241 | +<cf_greeting name="Lucee"> |
| 242 | +<!-- Outputs: Hello, Lucee! --> |
| 243 | +``` |
| 244 | + |
| 245 | +## Best Practices |
| 246 | + |
| 247 | +1. **Use Application.cfc for application-specific tags**: Define custom tag paths in Application.cfc to keep them version-controlled and portable with your application. |
| 248 | + |
| 249 | +2. **Set inspectTemplate appropriately**: Use **auto** or **once** during development, but **never** in production for better performance. |
| 250 | + |
| 251 | +3. **Organize tags by purpose**: Consider organizing custom tags into subdirectories by functionality (e.g., `customtags/forms/`, `customtags/layout/`). |
| 252 | + |
| 253 | +4. **Use cfimport for clarity**: When working with multiple tag libraries, use `cfimport` with descriptive prefixes to make your code more readable. |
| 254 | + |
| 255 | +## Differences from Component and Regular Mappings |
| 256 | + |
| 257 | +| Feature | Regular Mappings | Component Mappings | Custom Tag Mappings | |
| 258 | +|---------|------------------|-------------------|-------------------| |
| 259 | +| Application.cfc Property | `this.mappings` | `this.componentPaths` | `this.customTagPaths` | |
| 260 | +| Data Structure | Struct (with virtual paths) | Array | Array | |
| 261 | +| Usage | `cfinclude`, `cffile`, etc. | `new`, `createObject()` | `cf_tagname`, `cfimport` | |
| 262 | +| Requires Virtual Path | Yes | No | No | |
0 commit comments