Skip to main content
Version: 2026.2

Action Handlers

After a targeting rule matches, it runs one or more configured actions. Action handlers, services implementing ActionHandlerInterface, execute these actions.

Shipped Action Handlers

The bundle registers the following action handlers by default (config/pimcore/default.yaml); the action key is what appears in rule configuration and in the pimcore_personalization.targeting.action_handlers map:

Action keyClass
assign_target_groupPimcore\Bundle\PersonalizationBundle\Targeting\ActionHandler\AssignTargetGroup
codesnippetPimcore\Bundle\PersonalizationBundle\Targeting\ActionHandler\CodeSnippet
redirectPimcore\Bundle\PersonalizationBundle\Targeting\ActionHandler\Redirect

As with conditions, a custom action handler has two parts:

Implementing an Action Handler

As an example, implement a simple Log action handler that logs each matched rule with a configured log level. The action handler is a normal service that can depend on other services, as this one depends on the logger.

caution

Don't rely on a visitor ID being set or a rule being passed. The visitor ID may not exist yet on a visitor's first request, and action handlers can run outside the matching engine without a rule. Always check these values before using them.

<?php

// src/Targeting/ActionHandler/Log.php

namespace App\Targeting\ActionHandler;

use Pimcore\Bundle\PersonalizationBundle\Model\Tool\Targeting\Rule;
use Pimcore\Bundle\PersonalizationBundle\Targeting\ActionHandler\ActionHandlerInterface;
use Pimcore\Bundle\PersonalizationBundle\Targeting\Model\VisitorInfo;
use Psr\Log\LoggerInterface;

class Log implements ActionHandlerInterface
{
private LoggerInterface $logger;

public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}

public function apply(VisitorInfo $visitorInfo, array $action, ?Rule $rule = null): void
{
$level = $action['level'] ?? 'info';

$this->logger->log(
$level,
'Matched target rule {ruleName} for visitor ID {visitorID} with config {config}',
[
'visitorID' => $visitorInfo->hasVisitorId() ? $visitorInfo->getVisitorId() : '(no visitor ID)',
'ruleName' => $rule ? $rule->getName() : '(no rule)',
'config' => json_encode($action)
]
);
}
}

Next, register your action handler as a service. This example relies on autowiring to inject the logger automatically; if you don't use autowiring, wire the dependency in the service definition instead.

services:
_defaults:
autowire: true
autoconfigure: true
public: false

App\Targeting\ActionHandler\Log: ~

As a last step, register the action handler with the targeting engine. Keep the identifier unique, since you'll reuse it when registering the Studio dynamic type.

pimcore_personalization:
targeting:
action_handlers:
log: App\Targeting\ActionHandler\Log

Postponed Actions

If your action handler needs to apply data at a later stage of the request/response cycle, it can register an action on the VisitorInfo for later consumption. Currently only the response action scope is defined, applied during the onKernelResponse event, but more action scopes may be added in the future.

See the CodeSnippet action handler as an example. It registers an action via $visitorInfo->addAction() and implements ResponseTransformingActionHandlerInterface::transformResponse(), which the targeting engine calls for every action registered with the response scope.

Registering in Pimcore Studio

Registering the PHP action handler makes it usable in targeting rules, but it won't appear on the Actions tab of the Pimcore Studio rule editor until you also register a matching Studio dynamic type, the same way conditions do (see Conditions).

As with conditions, the rule builder has no global action registry. This bundle creates an instance of the SDK class DynamicTypeRuleActionRegistry and binds it in the Studio DI container under the service ID PersonalizationBundle/ActionRegistry. The Actions tab renders only the types held by that instance.

To add a Studio dynamic type for log, build a small Studio UI plugin bundle that:

  • implements a dynamic type extending DynamicTypeRuleActionAbstract from @pimcore/studio-ui-bundle/modules/rule-builder, decorated with @injectable(), using log as its type key so it matches the PHP registration,
  • binds that class in the container in the plugin's onInit,
  • resolves PersonalizationBundle/ActionRegistry and calls registerDynamicType() on it in the plugin's onStartup, for the same ordering reason described in the Conditions chapter.

See this bundle's own action dynamic types for concrete examples (for instance the Redirect action), and the Studio UI Bundle's Dynamic Types and Getting Started with Your First Plugin guides for the general plugin and dynamic type mechanism.