Skip to main content

Handlers

XenForo uses a "handler" pattern to allow different content types to plug into shared systems. Rather than having a single monolithic class that knows about every type of content, each system defines an abstract handler class, and individual content types provide their own concrete implementation.

For example, the attachment system doesn't need to know the specifics of how a post or a conversation message works. Instead, each content type provides an attachment handler that tells the system how to check permissions, manage constraints, and clean up when attachments are deleted.

How handlers work

The handler pattern in XenForo follows a consistent structure:

  1. An abstract base class defines the contract, including the methods every handler must implement and any optional hooks.
  2. Concrete handler classes extend the abstract class for each content type that supports the feature.
  3. A content type field registers the handler class against a content type, so the system can discover and instantiate it at runtime.

Content type fields

At the heart of the handler system is the xf_content_type_field table. This table maps content types (like post, thread, profile_post) to handler classes for each system they participate in.

Each row has three columns:

ColumnDescription
content_typeThe content type identifier (e.g. post)
field_nameThe system this handler belongs to (e.g. attachment_handler_class)
field_valueThe fully qualified class name of the handler

For example, the post content type registers its attachment handler like this:

content_typefield_namefield_value
postattachment_handler_classXF\Attachment\PostHandler

A single content type can register handlers for many different systems. The post content type, for instance, has handler registrations for attachments, alerts, reactions, reports, bookmarks, tags, and more.

Registering a handler

Content type fields are managed through the Admin control panel at Development > Execution manipulation > Content types. This area is only available when development mode is enabled.

From here you can add a new content type field by specifying the content type, field name, and the fully qualified class name of the handler. You will also need to associate the content type field with your add-on.

When your add-on's development output is exported, the content type field will be written to a JSON file in your add-on's _output/content_type_fields/ directory following the naming convention {content_type}-{field_name}.json. For example:

src/addons/Demo/Portal/_output/content_type_fields/demo_item-attachment_handler_class.json
{
"content_type": "demo_item",
"field_name": "attachment_handler_class",
"field_value": "Demo\\Portal\\Attachment\\ItemHandler"
}
note

Your entity structure must also declare the matching contentType for the content type system to associate it correctly:

$structure->contentType = 'demo_item';

See Entities, finders and repositories for more details.

How handlers are discovered

At runtime, the content type fields are cached in the data registry. You can look up all handlers for a given system or retrieve a specific handler for a content type:

// Get all attachment handler classes, keyed by content type
$handlers = \XF::app()->getContentTypeField('attachment_handler_class');
// Returns: ['post' => 'XF\Attachment\PostHandler', 'conversation_message' => 'XF\Attachment\ConversationMessageHandler', ...]

// Get a single handler class for a specific content type
$handlerClass = \XF::app()->getContentTypeFieldValue('post', 'attachment_handler_class');
// Returns: 'XF\Attachment\PostHandler'

Each system typically has a repository method that handles instantiation. The general pattern looks like this:

public function getAttachmentHandler(string $type): ?AbstractHandler
{
$handlerClass = \XF::app()->getContentTypeFieldValue($type, 'attachment_handler_class');
if (!$handlerClass)
{
return null;
}

$handlerClass = \XF::extendClass($handlerClass);
return new $handlerClass($type);
}

Note the use of \XF::extendClass(). This ensures that any class extensions applied by other add-ons are respected when the handler is instantiated.

Common handler systems

The following is a list of the handler systems available in XenForo, along with their content type field name and abstract base class:

SystemField nameBase class
Activity logactivity_log_handler_classXF\ActivityLog\AbstractHandler
Alertsalert_handler_classXF\Alert\AbstractHandler
Approval queueapproval_queue_handler_classXF\ApprovalQueue\AbstractHandler
Attachmentsattachment_handler_classXF\Attachment\AbstractHandler
Bookmarksbookmark_handler_classXF\Bookmark\AbstractHandler
Change logchange_log_handler_classXF\ChangeLog\AbstractHandler
Content votingcontent_vote_handler_classXF\ContentVote\AbstractHandler
Edit historyedit_history_handler_classXF\EditHistory\AbstractHandler
Featured contentfeatured_content_handler_classXF\FeaturedContent\AbstractHandler
Find newfind_new_handler_classXF\FindNew\AbstractHandler
Inline moderationinline_mod_handler_classXF\InlineMod\AbstractHandler
Moderator logmoderator_log_handler_classXF\ModeratorLog\AbstractHandler
News feednews_feed_handler_classXF\NewsFeed\AbstractHandler
Pollspoll_handler_classXF\Poll\AbstractHandler
Reactionsreaction_handler_classXF\Reaction\AbstractHandler
Reportsreport_handler_classXF\Report\AbstractHandler
Sitemapsitemap_handler_classXF\Sitemap\AbstractHandler
Statsstats_handler_classXF\Stats\AbstractHandler
Tagstag_handler_classXF\Tag\AbstractHandler
Trending contenttrending_content_handler_classXF\TrendingContent\AbstractHandler
Warningswarning_handler_classXF\Warning\AbstractHandler
Webhook eventswebhook_handler_classXF\Webhook\Event\AbstractHandler