# Contentbox Cfml Content Types

> Use this skill when implementing ContentBox content models and rendering flows, including entries/pages/content stores, custom fields, entity relationships, lifecycle callbacks, and content-type specific behaviors.

- Skill: `coldbox/contentbox-cfml-content-types` (Agent Skill)
- Install (CLI): `npx skillmds@latest add coldbox/contentbox-cfml-content-types`
- Raw SKILL.md: https://api.skillmd.com/api/skills/coldbox/contentbox-cfml-content-types/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: ColdBox (https://skillmd.com/u/coldbox)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/coldbox/contentbox-cfml-content-types

---


# ContentBox Content Types & Custom Fields (CFML)

Extend ContentBox content types and add custom fields using CFML. ContentBox supports entries, pages, and ContentStore items with extensible custom field capabilities.

## Content Types

ContentBox has three primary content types:

| Type | Entity | Service | Description |
|------|--------|---------|-------------|
| **Entries** | `Entry` | `entryService@contentbox` | Blog posts with dates, categories, comments |
| **Pages** | `Page` | `pageService@contentbox` | Static pages with hierarchical structure |
| **ContentStore** | `ContentStore` | `contentStoreService@contentbox` | Key-value content blocks |

### Entry Entity

```cfml
property name="entryService" inject="entryService@contentbox";

// Entry properties
entry.getEntryID()
entry.getTitle()
entry.getSlug()
entry.getHTMLContent()
entry.getPlainTextContent()
entry.getPublishedDate()
entry.getCreatedDate()
entry.getModifiedDate()
entry.getIsActive()
entry.getIsPublished()
entry.getHits()
entry.getNumberOfComments()

// Relationships
entry.getAuthor()              // Author entity
entry.getCategories()          // Query of categories
entry.getComments()            // Query of comments
entry.getSite()                // Site entity
entry.getFeaturedImage()       // Media entity

// Status
entry.getStatus()              // "published", "draft", "pending"
entry.isPublished()
entry.isDraft()
```

### Page Entity

```cfml
property name="pageService" inject="pageService@contentbox";

// Page properties
page.getPageID()
page.getTitle()
page.getSlug()
page.getHTMLContent()
page.getPlainTextContent()
page.getCreatedDate()
page.getModifiedDate()
page.getIsActive()
page.getIsPublished()
page.getMenuOrder()            // For ordering in menus
page.getParent()               // Parent page (hierarchical)
page.getChildren()             // Child pages

// Relationships
page.getAuthor()
page.getSite()
page.getFeaturedImage()
```

### ContentStore Entity

```cfml
property name="contentStoreService" inject="contentStoreService@contentbox";

// ContentStore is a key-value store
contentStoreService.getValue( "key" )
contentStoreService.setValue( "key", "value" )
contentStoreService.deleteValue( "key" )
contentStoreService.getAll()

// ContentStore entity
item.getContentStoreID()
item.getSlug()                 // The key
item.getContent()              // The value
item.getCreatedDate()
item.getModifiedDate()
```

## Custom Fields

ContentBox supports custom fields through the `cbCustomField` entity and service:

```cfml
property name="customFieldService" inject="customFieldService@contentbox";

// Create custom field
var field = customFieldService.new( {
	name        : "subtitle",
	label       : "Subtitle",
	type        : "text",         // text, textarea, boolean, select, date, number
	required    : false,
	defaultValue: "",
	contentType : "entry",        // "entry", "page", or "all"
	order       : 1
} );
customFieldService.save( field );

// Get custom fields for content type
var fields = customFieldService.findByContentType( "entry" );
```

### Custom Field Types

| Type | Description |
|------|-------------|
| `text` | Single-line text input |
| `textarea` | Multi-line text area |
| `boolean` | Checkbox toggle |
| `select` | Dropdown select |
| `date` | Date picker |
| `number` | Numeric input |
| `media` | Media picker |
| `html` | HTML editor |

### Accessing Custom Field Values

```cfml
// Get custom field value from entry
var subtitle = entry.getCustomFieldValue( "subtitle" );

// Get all custom field values
var fields = entry.getCustomFields();
```

## Content Helpers (Mixins)

Inject mixins into all content objects via settings:

```cfml
// In ModuleConfig.cfc configure()
settings.contentHelpers = [
	"mymodule.models.mixins.MyContentMixin"
];
```

### Creating a Content Mixin

```cfml
<!--- models/mixins/MyContentMixin.cfc --->
<cfcomponent>

	<cffunction name="getExcerpt" access="public" returntype="string">
		<cfargument name="maxLength" type="numeric" default="200">
		<cfreturn left( this.getPlainTextContent(), arguments.maxLength ) & "...">
	</cffunction>

	<cffunction name="getReadingTime" access="public" returntype="numeric">
		<cfset var wordCount = arrayLen( listToArray( this.getPlainTextContent(), " " ) )>
		<cfreturn ceiling( wordCount / 200 )>
	</cffunction>

</cfcomponent>
```

### Using Content Mixins

```cfml
// After injecting, methods are available on all content objects
var excerpt = entry.getExcerpt( 150 );
var readTime = entry.getReadingTime();
```

## Content Rendering

### Content Renderers

ContentBox uses interceptors to process content before rendering:

| Renderer | Class | Purpose |
|----------|-------|---------|
| **Link Renderer** | `LinkRenderer@contentbox` | Process internal links |
| **Widget Renderer** | `WidgetRenderer@contentbox` | Process `{widget:...}` shortcodes |
| **Setting Renderer** | `SettingRenderer@contentbox` | Process `{setting:...}` shortcodes |
| **Markdown Renderer** | `MarkdownRenderer@contentbox` | Process Markdown content |

### Widget Shortcode

```
{widget:WidgetName arg1="value" arg2="value"}
```

### Setting Shortcode

```
{setting:cb_site_title}
```

## Content Lifecycle

### Entry Lifecycle

```cfml
// Interception points
cbadmin_preEntrySave      // Before entry saved
cbadmin_postEntrySave     // After entry saved
cbadmin_preEntryRemove    // Before entry deleted
cbadmin_postEntryRemove   // After entry deleted
cbadmin_onEntryStatusUpdate  // When status changes
cb_onContentRendering     // Before content rendered
```

### Page Lifecycle

```cfml
// Interception points
cbadmin_prePageSave
cbadmin_postPageSave
cbadmin_prePageRemove
cbadmin_postPageRemove
cbadmin_onPageStatusUpdate
cb_onContentRendering
```

## Content Queries

### EntryService Queries

```cfml
property name="entryService" inject="entryService@contentbox";

// Find published entries
var entries = entryService.findPublishedContent(
	max       : 10,
	category  : "news",
	searchTerm: "search term",
	sortOrder : "publishedDate DESC",
	siteID    : siteId
);

// Find by slug
var entry = entryService.findBySlug( "my-entry-slug" );

// Find by category
var entries = entryService.findByCategory( "news" );

// Find by author
var entries = entryService.findByAuthor( authorId );

// Count entries
var count = entryService.countPublishedContent( siteID : siteId );
```

### PageService Queries

```cfml
property name="pageService" inject="pageService@contentbox";

// Find all pages
var pages = pageService.findAllWhere( { siteID : siteId, isPublished : true } );

// Find by slug
var page = pageService.findBySlug( "about" );

// Find children
var children = pageService.findChildren( parentId );

// Find hierarchical
var tree = pageService.getHierarchicalPages( siteId );
```

## Best Practices

1. **Use services** — `entryService`, `pageService`, `contentStoreService`
2. **Use `findBySlug()`** — for human-readable URL lookups
3. **Always filter by `siteID`** — in multi-site installations
4. **Use content helpers** — for reusable content methods
5. **Use interception points** — for content lifecycle hooks
6. **Validate custom fields** — ensure data integrity
7. **Use `getPlainTextContent()`** — for excerpts and search
8. **Use `getHTMLContent()`** — for rendering
9. **Handle soft deletes** — check `isDeleted` flag
10. **Cache expensive queries** — use CacheBox for performance

## Engine Compatibility

This skill targets **CFML engines** (Lucee 5+, Adobe ColdFusion 2018+). For BoxLang-specific syntax and features, see the BoxLang variant of this skill.

