
Typo3 Powermail
- 48 installs
- 33 repo stars
- Updated July 27, 2026
- dirnbauer/webconsulting-skills
Build, debug, and extend TYPO3 Powermail 13+ forms with finishers, validators, spam protection, and conditional field visibility.
About
This skill guides Powermail 13+ form development for TYPO3, including finishers, validators, spam protection, email templates, and conditional visibility. A developer uses it when creating, debugging, or extending Powermail forms and mail handling.
- Covers Powermail 13+ forms, finishers, validators, spam protection, and ViewHelpers
- Includes conditional field visibility (powermail_cond) and PSR-14 events
Typo3 Powermail by the numbers
- 48 all-time installs (skills.sh)
- Ranked #3,249 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/dirnbauer/webconsulting-skills --skill typo3-powermailAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 48 |
|---|---|
| repo stars | ★ 33 |
| Last updated | July 27, 2026 |
| Repository | dirnbauer/webconsulting-skills ↗ |
What it does
Build, debug, and extend TYPO3 Powermail 13+ forms with finishers, validators, spam protection, and conditional field visibility.
Files
TYPO3 Powermail Development
Source: https://github.com/dirnbauer/webconsulting-skills
Compatibility: Powermail 13.x currently targets TYPO3 13.4 per Packagist — do not assume v14 until the package declares it. Examples use modern TYPO3 APIs where possible; adjust for your Core version.
All examples use PHP 8.2+.
TYPO3 API First: Always use TYPO3's built-in APIs, core features, and established conventions before creating custom implementations. Do not reinvent what TYPO3 already provides. Always verify that the APIs and methods you use exist and are not deprecated in TYPO3 v14 by checking the official TYPO3 documentation.
Supplements:
- SKILL-CONDITIONS.md - Conditional field/page visibility (powermail_cond)
- PHP 8.4 patterns for finishers, validators, and conditions are covered directly in this skill
- SKILL-EXAMPLES.md - Multi-step shop form with Austrian legal types, DDEV SQL + DataHandler CLI
Powermail vs Core EXT:form
These are different systems. Do not mix migration advice between them.
| Powermail (`in2code/powermail`) | TYPO3 Core EXT:form | |
|---|---|---|
| Purpose | Mail forms built in the Powermail backend module; stored in tx_powermail_* tables | Declarative forms (often YAML), form framework, finishers defined in YAML/PHP |
| Rendering | Powermail plugins / ViewHelpers / TypoScript | Fluid templates + Core form runtime |
| This skill | Documents Powermail APIs, finishers, validators, events as shipped by in2code | Only where your code also touches EXT:form (bridges, shared sites, dual form stacks) |
Sections labeled EXT:form under v14-Only Changes describe Core form-framework removals (hooks → PSR-14, storage adapters). They apply to custom code that hooks into EXT:form, not to ordinary Powermail-only projects—unless you explicitly integrate both.
1. Architecture Overview
Domain Model Hierarchy
Form (tx_powermail_domain_model_form)
└── Page (tx_powermail_domain_model_page)
└── Field (tx_powermail_domain_model_field)
Mail (tx_powermail_domain_model_mail)
└── Answer (tx_powermail_domain_model_answer)
└── references FieldPlugin Registration
- Pi1 (cached/uncached):
form,create,confirmation,optinConfirm,disclaimer - Pi5 (uncached):
marketing(AJAX tracking)
Composer
composer require in2code/powermailTypical requirements (always confirm the current release on Packagist): PHP ^8.2, `typo3/cms-core: ^13.4` (latest stable line at time of writing), plus ext-json, ext-gd, ext-fileinfo, ext-curl. Do not assume TYPO3 v14 until the package constraint is updated upstream.
2. Field Types
| Type | Key | Value Type | Notes |
|---|---|---|---|
| Text | input | TEXT (0) | Standard input |
| Textarea | textarea | TEXT (0) | Multi-line |
| Select | select | TEXT/ARRAY (0/1) | Multiselect possible |
| Checkbox | check | ARRAY (1) | Multiple values |
| Radio | radio | TEXT (0) | Single selection |
| Submit | submit | — | Form submit button |
| Captcha | captcha | TEXT (0) | Built-in CAPTCHA |
| Reset | reset | — | Form reset button |
| Static text | text | — | Display only |
| Content element | content | — | CE reference |
| HTML | html | TEXT (0) | Raw HTML |
| Password | password | PASSWORD (4) | Hashed storage |
| File upload | file | UPLOAD (3) | File attachments |
| Hidden | hidden | TEXT (0) | Hidden input |
| Date | date | DATE (2) | Datepicker |
| Country | country | TEXT (0) | Country selector |
| Location | location | TEXT (0) | Geolocation |
| TypoScript | typoscript | TEXT (0) | TS-generated content |
Answer Value Types
Answer::VALUE_TYPE_TEXT = 0; // String values
Answer::VALUE_TYPE_ARRAY = 1; // JSON-encoded arrays (checkboxes, multiselect)
Answer::VALUE_TYPE_DATE = 2; // Timestamps
Answer::VALUE_TYPE_UPLOAD = 3; // File references
Answer::VALUE_TYPE_PASSWORD = 4; // Hashed passwords3. TypoScript Configuration
Essential Settings
plugin.tx_powermail {
settings {
setup {
# Form settings
main {
pid = {$plugin.tx_powermail.settings.main.pid}
form = {$plugin.tx_powermail.settings.main.form}
confirmation = 0
optin = 0
morestep = 0
}
# Receiver mail
receiver {
enable = 1
subject = Mail from {firstname} {lastname}
body = A new mail from your website
senderNameField = firstname
senderEmailField = email
# Override receiver: receiver.overwrite.email = admin@example.com
# Attach uploads: receiver.attachment = 1
# Add CC: receiver.overwrite.cc = copy@example.com
}
# Sender confirmation mail
sender {
enable = 1
subject = Thank you for your message
body = We received your submission
senderName = Website
senderEmail = noreply@example.com
}
# Double Opt-In
optin {
subject = Please confirm your submission
senderName = Website
senderEmail = noreply@example.com
}
# Thank you page
thx {
redirect = # Page UID for redirect after submit
}
# Spam protection — numeric `methods` keys (matches EXT:powermail `12_Spamshield.typoscript`)
spamshield {
_enable = 1
factor = 75
methods {
1 {
_enable = 1
class = In2code\Powermail\Domain\Validator\SpamShield\HoneyPodMethod
indication = 5
configuration { }
}
2 {
_enable = 1
class = In2code\Powermail\Domain\Validator\SpamShield\LinkMethod
indication = 3
configuration {
linkLimit = 2
}
}
3 {
_enable = 1
class = In2code\Powermail\Domain\Validator\SpamShield\NameMethod
indication = 3
configuration { }
}
# SessionMethod sets a cookie when enabled — shipping TypoScript uses _enable = 0
4 {
_enable = 0
class = In2code\Powermail\Domain\Validator\SpamShield\SessionMethod
indication = 5
configuration { }
}
5 {
_enable = 1
class = In2code\Powermail\Domain\Validator\SpamShield\UniqueMethod
indication = 2
configuration { }
}
6 {
_enable = 1
class = In2code\Powermail\Domain\Validator\SpamShield\ValueBlacklistMethod
indication = 7
configuration {
values = TEXT
values.value = viagra,sex,porn
}
}
7 {
_enable = 1
class = In2code\Powermail\Domain\Validator\SpamShield\IpBlacklistMethod
indication = 7
configuration {
values = TEXT
values.value = 203.0.113.1
}
}
8 {
_enable = 1
class = In2code\Powermail\Domain\Validator\SpamShield\RateLimitMethod
indication = 100
configuration {
interval = 5 minutes
limit = 10
restrictions {
10 = __ipAddress
20 = __formIdentifier
}
}
}
}
}
# Validation
misc {
htmlForLabels = 1
showOnlyFilledValues = 1
ajaxSubmit = 0
file {
folder = uploads/tx_powermail/
size = 25000000
extension = jpg,jpeg,gif,png,tif,txt,doc,docx,xls,xlsx,ppt,pptx,pdf,zip,csv,svg
}
}
}
}
}Prefill Fields via TypoScript
plugin.tx_powermail.settings.setup.prefill {
# By field marker
email = TEXT
email.data = TSFE:fe_user|user|email
firstname = TEXT
firstname.data = TSFE:fe_user|user|first_name
# Prefill from GET/POST
subject = TEXT
subject.data = GP:subject
}Marketing Information
plugin.tx_powermail.settings.setup.marketing {
enable = 1
# Tracked: refererDomain, referer, country, mobileDevice, frontendLanguage, browserLanguage, pageFunnel
}Detailed Reference
Read the full guide when the task needs detailed examples, long templates, troubleshooting matrices, appendices, or sections not included above. Keep this file unloaded for narrow tasks so the skill follows progressive disclosure.
4. Custom Finishers
Continues typo3-powermail from full guide.
4. Custom Finishers
Finishers run after successful form submission, sorted by TypoScript key.
Registration
plugin.tx_powermail.settings.setup.finishers {
# Lower number = runs first
0.class = In2code\Powermail\Finisher\RateLimitFinisher
10.class = In2code\Powermail\Finisher\SaveToAnyTableFinisher
20.class = In2code\Powermail\Finisher\SendParametersFinisher
finally.class = In2code\Powermail\Finisher\RedirectFinisher
# Custom finisher
50.class = Vendor\MyExt\Finisher\CrmFinisher
50.config {
apiUrl = https://crm.example.com/api
apiKey = secret123
}
}Creating a Custom Finisher
<?php
declare(strict_types=1);
namespace Vendor\MyExt\Finisher;
use In2code\Powermail\Finisher\AbstractFinisher;
use In2code\Powermail\Domain\Model\Mail;
final class CrmFinisher extends AbstractFinisher
{
/**
* Method name MUST end with "Finisher"
* Can have initialize*Finisher() called before
*/
public function myCustomFinisher(): void
{
/** @var Mail $mail */
$mail = $this->getMail();
$settings = $this->getSettings();
$configuration = $this->getConfiguration(); // TS config.*
// Access form answers
foreach ($mail->getAnswers() as $answer) {
$fieldMarker = $answer->getField()->getMarker();
$value = $answer->getValue();
// Process...
}
// Access by marker
$answers = $mail->getAnswersByFieldMarker();
$email = $answers['email'] ?? null;
// Check if form was actually submitted (not just displayed)
if (!$this->isFormSubmitted()) {
return;
}
}
}Built-in Finishers
| Class | Key | Purpose |
|---|---|---|
RateLimitFinisher | 0 | Consumes rate limiter tokens |
SaveToAnyTableFinisher | 10 | Save answers to custom DB tables |
SendParametersFinisher | 20 | POST form data to external URL |
RedirectFinisher | finally | Runs last — special TypoScript key, not a numeric sort key |
SaveToAnyTable Configuration
plugin.tx_powermail.settings.setup.dbEntry {
1 {
_enable = TEXT
_enable.value = 1
_table = fe_users
_ifUnique.email = update # update|skip|none
username.value = {email}
email.value = {email}
first_name.value = {firstname}
last_name.value = {lastname}
pid.value = 123
}
}5. Custom Validators
Continues typo3-powermail from full guide.
5. Custom Validators
Creating a Custom Validator (PSR-14 Event)
<?php
declare(strict_types=1);
namespace Vendor\MyExt\EventListener;
use In2code\Powermail\Events\CustomValidatorEvent;
use TYPO3\CMS\Core\Attribute\AsEventListener;
#[AsEventListener('vendor-myext/custom-validator')]
final class CustomValidatorListener
{
public function __invoke(CustomValidatorEvent $event): void
{
$mail = $event->getMail();
$validator = $event->getCustomValidator();
foreach ($mail->getAnswers() as $answer) {
$field = $answer->getField();
if ($field === null || $field->getMarker() !== 'company_vat') {
continue;
}
if (!$this->isValidVat((string)$answer->getValue())) {
$validator->setErrorAndMessage($field, 'Invalid VAT number');
}
}
}
private function isValidVat(string $vat): bool
{
return (bool)preg_match('/^[A-Z]{2}\d{8,12}$/', $vat);
}
}Built-in Validators
| Validator | Purpose |
|---|---|
InputValidator | Email, URL, phone, number, letters, min/max length, regex |
UploadValidator | File size, extension whitelist |
PasswordValidator | Password match and strength |
CaptchaValidator | Built-in CAPTCHA |
| (Spam shield) | Spam checking is distributed across multiple Domain\Validator\SpamShield\AbstractMethod subclasses (HoneyPodMethod, LinkMethod, …), orchestrated by SpamShieldValidator |
UniqueValidator | Unique field values |
ForeignValidator | Validate against foreign table |
CustomValidator | TypoScript-based custom rules |
Spam Shield Methods
| Method | Weight | Description |
|---|---|---|
HoneyPodMethod | 5 | Hidden honeypot field |
LinkMethod | 3 | Excessive links detection |
NameMethod | 3 | Suspicious name patterns |
SessionMethod | 5 | Session/cookie check (shipping TypoScript: `_enable = 0` — opt-in because it sets a cookie) |
UniqueMethod | 2 | Duplicate submission check |
ValueBlacklistMethod | 7 | Blacklisted content |
IpBlacklistMethod | 7 | Blacklisted IP addresses |
RateLimitMethod | 100 | Request rate limiting |
6. PSR-14 Events
Continues typo3-powermail from full guide.
6. PSR-14 Events
Form Lifecycle Events
// Before form is rendered
FormControllerFormActionEvent
// Before confirmation page
FormControllerConfirmationActionEvent
// After mail is saved to database
FormControllerCreateActionAfterMailDbSavedEvent
// After submit view is built
FormControllerCreateActionAfterSubmitViewEvent
// Before final view is rendered
FormControllerCreateActionBeforeRenderViewEvent
// Controller initialization
FormControllerInitializeObjectEventMail Events
// Modify receiver email addresses
ReceiverMailReceiverPropertiesServiceSetReceiverEmailsEvent
// Modify receiver name
ReceiverMailReceiverPropertiesServiceGetReceiverNameEvent
// Modify sender email (receiver mail)
ReceiverMailSenderPropertiesGetSenderEmailEvent
// Modify sender name (receiver mail)
ReceiverMailSenderPropertiesGetSenderNameEvent
// Modify sender email (confirmation mail)
SenderMailPropertiesGetSenderEmailEvent
// Modify sender name (confirmation mail)
SenderMailPropertiesGetSenderNameEvent
// Modify email body before sending
SendMailServiceCreateEmailBodyEvent
// Before email is sent (last chance to modify)
SendMailServicePrepareAndSendEventOther Events
// Control if mail should be saved to DB
CheckIfMailIsAllowedToSaveEvent
// Custom validation logic
CustomValidatorEvent
// Prefill field values
PrefillFieldViewHelperEvent
PrefillMultiFieldViewHelperEvent
// File upload processing
UploadServicePreflightEvent
UploadServiceGetFilesEvent
GetNewPathAndFilenameEvent
// Before password is hashed
MailFactoryBeforePasswordIsHashedEvent
// Modify mail variables/markers
MailRepositoryGetVariablesWithMarkersFromMailEvent
// Validation data attributes
ValidationDataAttributeViewHelperEvent
// Double opt-in confirmation
FormControllerOptinConfirmActionAfterPersistEvent
FormControllerOptinConfirmActionBeforeRenderViewEvent
// Disclaimer/unsubscribe
FormControllerDisclaimerActionBeforeRenderViewEventExample: Modify Receiver Email (from form answers)
ReceiverMailReceiverPropertiesServiceSetReceiverEmailsEvent only exposes getEmailArray() / setEmailArray() and getService() — the service does not publish the Mail model, so you cannot read field markers from that event alone. For routing based on answers, listen when the mail is available, e.g. `SendMailServicePrepareAndSendEvent`:
<?php
declare(strict_types=1);
namespace Vendor\MyExt\EventListener;
use In2code\Powermail\Events\SendMailServicePrepareAndSendEvent;
use TYPO3\CMS\Core\Attribute\AsEventListener;
#[AsEventListener('vendor-myext/dynamic-receiver')]
final class DynamicReceiverListener
{
public function __invoke(SendMailServicePrepareAndSendEvent $event): void
{
$mail = $event->getSendMailService()->getMail();
$answers = $mail->getAnswersByFieldMarker();
$department = $answers['department'] ?? null;
if ($department === null) {
return;
}
$value = (string)$department->getValue();
$emailConfig = $event->getEmail();
// Adjust the receiver list inside $emailConfig for your Powermail / Symfony Mailer setup, then:
// $event->setEmail($emailConfig);
}
}To tweak the raw address list earlier in the pipeline, use `ReceiverMailReceiverPropertiesServiceSetReceiverEmailsEvent` with getEmailArray() / setEmailArray() when you do not need access to individual answers.
Example: Prevent DB Save
<?php
declare(strict_types=1);
namespace Vendor\MyExt\EventListener;
use In2code\Powermail\Events\CheckIfMailIsAllowedToSaveEvent;
use TYPO3\CMS\Core\Attribute\AsEventListener;
#[AsEventListener('vendor-myext/skip-db-save')]
final class SkipDbSaveListener
{
public function __invoke(CheckIfMailIsAllowedToSaveEvent $event): void
{
// Skip DB save for specific forms
$form = $event->getMail()->getForm();
if ($form !== null && $form->getTitle() === 'Contact (no storage)') {
$event->setSavingOfMailAllowed(false);
}
}
}7. Email Templates
Continues typo3-powermail from full guide.
7. Email Templates
Template Paths (TypoScript)
plugin.tx_powermail {
view {
templateRootPaths {
0 = EXT:powermail/Resources/Private/Templates/
10 = EXT:my_ext/Resources/Private/Templates/Powermail/
}
partialRootPaths {
0 = EXT:powermail/Resources/Private/Partials/
10 = EXT:my_ext/Resources/Private/Partials/Powermail/
}
layoutRootPaths {
0 = EXT:powermail/Resources/Private/Layouts/
10 = EXT:my_ext/Resources/Private/Layouts/Powermail/
}
}
}Key Templates
| Template | Purpose |
|---|---|
Form/Form.html | Main form rendering |
Form/Confirmation.html | Confirmation page |
Form/Create.html | Thank you page |
Mail/ReceiverMail.html | Admin notification email |
Mail/SenderMail.html | User confirmation email |
Mail/OptinMail.html | Double opt-in email |
Form/PowermailAll.html | All-fields summary |
Field Partials
Override individual field types by copying partials:
Partials/Form/Field/Input.html
Partials/Form/Field/Textarea.html
Partials/Form/Field/Select.html
Partials/Form/Field/Check.html
Partials/Form/Field/Radio.html
Partials/Form/Field/File.html
Partials/Form/Field/Date.html
Partials/Form/Field/Captcha.html
Partials/Form/Field/Hidden.html
Partials/Form/Field/Password.html
Partials/Form/Field/Country.html
Partials/Form/Field/Location.html
Partials/Form/Field/Html.html
Partials/Form/Field/Content.html
Partials/Form/Field/Typoscript.html
Partials/Form/Field/Submit.html
Partials/Form/Field/Reset.htmlAvailable Variables in Mail Templates
<!-- In ReceiverMail.html / SenderMail.html -->
{mail} <!-- Mail domain object -->
{mail.senderName} <!-- Sender name -->
{mail.senderMail} <!-- Sender email -->
{mail.form.title} <!-- Form title -->
{mail.answers} <!-- All answers (ObjectStorage) -->
<!-- Iterate answers -->
<f:for each="{mail.answers}" as="answer">
{answer.field.title}: {answer.value}
</f:for>
<!-- PowermailAll marker (all fields formatted) -->
{powermail_all}8. Key ViewHelpers
Continues typo3-powermail from full guide.
8. Key ViewHelpers
Validation
<!-- Enable JS validation and/or AJAX submit -->
<vh:validation.enableJavascriptValidationAndAjax
form="{form}"
additionalAttributes="{...}" />
<!-- Validation data attributes on fields -->
<vh:validation.validationDataAttribute field="{field}" />
<!-- Error CSS class -->
<vh:validation.errorClass field="{field}" class="error" />
<!-- Upload attributes (accept, multiple) -->
<vh:validation.uploadAttributes field="{field}" />Form Fields
<!-- Country selector -->
<vh:form.countries
settings="{settings}"
field="{field}"
mail="{mail}" />
<!-- Advanced select with optgroups -->
<vh:form.advancedSelect
field="{field}"
mail="{mail}" />
<!-- Multi-upload -->
<vh:form.multiUpload field="{field}" />Prefill
<!-- Prefill single-value field -->
<vh:misc.prefillField field="{field}" mail="{mail}" />
<!-- Prefill multi-value field (select, check, radio) -->
<vh:misc.prefillMultiField field="{field}" mail="{mail}" cycle="{cycle}" />Conditions
<!-- Check if field is not empty -->
<vh:condition.isNotEmpty val="{value}">
<f:then>Has value</f:then>
</vh:condition.isNotEmpty>
<!-- Check if array -->
<vh:condition.isArray val="{value}">
<f:then>Is array</f:then>
</vh:condition.isArray>
<!-- Check file exists -->
<vh:condition.fileExists file="{path}">
<f:then>File available</f:then>
</vh:condition.fileExists>Backend
<!-- Edit link in backend module -->
<vh:be.editLink table="tx_powermail_domain_model_mail" uid="{mail.uid}">
Edit
</vh:be.editLink>9. AJAX Form Submission
Continues typo3-powermail from full guide.
9. AJAX Form Submission
plugin.tx_powermail.settings.setup.misc.ajaxSubmit = 1When enabled, form submission is handled via AJAX without page reload. The response replaces the form container with the thank-you content.
10. Double Opt-In
Continues typo3-powermail from full guide.
10. Double Opt-In
plugin.tx_powermail.settings.setup.main.optin = 1
plugin.tx_powermail.settings.setup.optin {
subject = Please confirm your submission
senderName = My Website
senderEmail = noreply@example.com
}Flow: 1. User submits form 2. Mail is saved with hidden=1 3. Opt-in email sent with confirmation link (HMAC-secured) 4. User clicks link -> optinConfirmAction unhides the mail 5. Receiver email sent after confirmation
11. Backend Module
Continues typo3-powermail from full guide.
11. Backend Module
Powermail provides a backend module under Web > Powermail:
- List: Browse/filter/search submitted mails
- Export: CSV and Excel (PhpSpreadsheet) export
- Reporting: Form analytics and marketing charts
- System Check: Verify configuration (admin only)
Live Search
Search mails and forms directly from TYPO3 search bar:
#mail:searchterm- Search in mails#form:searchterm- Search in forms
12. Extension Best Practices
Continues typo3-powermail from full guide.
12. Extension Best Practices
Register Services (Services.yaml)
services:
Vendor\MyExt\EventListener\CrmSyncListener:
tags:
- name: event.listener
identifier: 'vendor-myext/crm-sync'Or use the #[AsEventListener] attribute (preferred on TYPO3 v14).
Access Mail Answers Efficiently
// By field marker (most common)
$answers = $mail->getAnswersByFieldMarker();
$email = $answers['email']?->getValue();
// By field UID
$answers = $mail->getAnswersByFieldUid();
// Filter by value type
$uploads = $mail->getAnswersByValueType(Answer::VALUE_TYPE_UPLOAD);Custom Data on Mail Object
// Add custom data (available in all finishers/events)
$mail->addAdditionalData('crm_id', $crmResponse['id']);
// Retrieve in another finisher/event
$crmId = $mail->getAdditionalData()['crm_id'] ?? null;Rate Limiting
Powermail uses Symfony RateLimiter. Configure in ext_conf_template.txt or extension settings.
Garbage Collection
Powermail auto-registers garbage collection for mails and answers (default: 30 days). Configure via Scheduler task TableGarbageCollectionTask.
13. Common Recipes
Continues typo3-powermail from full guide.
13. Common Recipes
Route Enhancer for SEO-Friendly URLs
routeEnhancers:
PowermailOptIn:
type: Plugin
routePath: '/optin/{mail}/{hash}'
namespace: 'tx_powermail_pi1'
requirements:
mail: '\d+'
hash: '[a-zA-Z0-9]+'Conditional Receiver Based on Form Field
Use ReceiverMailReceiverPropertiesServiceSetReceiverEmailsEvent (see Section 6).
Custom Spam Shield Method
<?php
declare(strict_types=1);
namespace Vendor\MyExt\SpamShield;
use In2code\Powermail\Domain\Validator\SpamShield\AbstractMethod;
final class ApiCheckMethod extends AbstractMethod
{
public function spamCheck(): bool
{
$mail = $this->mail;
// Return true if spam detected
return $this->callExternalApi($mail);
}
}Register in TypoScript:
plugin.tx_powermail.settings.setup.spamshield.methods {
100 {
class = Vendor\MyExt\SpamShield\ApiCheckMethod
_enable = 1
configuration {
apiUrl = https://spam-api.example.com
}
}
}Extend Form with TypoScript-Generated Fields
plugin.tx_powermail.settings.setup.manipulateVariablesInPowermailAllMarker {
timestamp = TEXT
# Avoid `strftime` (removed in PHP 8.4); use TEXT `date:` data instead
timestamp.data = date:Y-m-d H:i:s
}14. Database Structure
Continues typo3-powermail from full guide.
14. Database Structure
Conditions tables: See SKILL-CONDITIONS.md Section 12 for tx_powermailcond_* tables.TYPO3 Standard Columns
All powermail tables include these TYPO3-managed columns (not listed per table below):
| Column | Type | Purpose |
|---|---|---|
uid | int AUTO_INCREMENT | Primary key |
pid | int | Storage page UID |
tstamp | int | Last modification timestamp |
crdate | int | Creation timestamp |
deleted | tinyint | Soft-delete flag |
hidden | tinyint | Visibility flag |
sys_language_uid | int | Language UID (0 = default, -1 = all) |
l10n_parent | int | UID of the default language record |
l10n_diffsource | mediumblob | Diff source for translation |
starttime | int | Publish start (Unix timestamp) |
endtime | int | Publish end (Unix timestamp) |
tx_powermail_domain_model_form
| Column | Type | Description |
|---|---|---|
title | varchar(255) | Form title |
note | tinyint | Backend note renderer (internal) |
css | varchar(255) | CSS class for form wrapper |
pages | varchar(255) | IRRE children count or element browser list |
autocomplete_token | varchar(3) | Autocomplete on/off/empty |
is_dummy_record | tinyint | Test record flag |
Indexes: language (l10n_parent, sys_language_uid)
tx_powermail_domain_model_page
| Column | Type | Description |
|---|---|---|
form | int | Parent form UID |
title | varchar(255) | Page/step title |
css | varchar(255) | CSS class for fieldset |
fields | int | IRRE children count |
sorting | int | Sort order within form |
Indexes: parent_form (form), language (l10n_parent, sys_language_uid)
tx_powermail_domain_model_field
| Column | Type | Description |
|---|---|---|
page | int | Parent page UID |
title | varchar(255) | Field label |
type | varchar(255) | Field type key (input, select, check, ...) |
settings | text | Options for select/radio/check (one per line) |
path | varchar(255) | File path reference |
content_element | int | CE reference for type=content |
text | text | Static text for type=text |
prefill_value | text | Default/prefill value |
placeholder | text | Placeholder text |
placeholder_repeat | text | Placeholder for repeat field (password) |
create_from_typoscript | text | TypoScript for type=typoscript |
validation | int | Validation type (0=none, 1=email, ...) |
validation_configuration | varchar(255) | Regex or config for validation |
css | varchar(255) | CSS class for field wrapper |
description | varchar(255) | Help text / description |
multiselect | tinyint | Allow multi-select |
datepicker_settings | varchar(255) | Datepicker format |
feuser_value | varchar(255) | Prefill from fe_user property |
sender_email | tinyint | This field is the sender email |
sender_name | tinyint | This field is the sender name |
mandatory | tinyint | Required field |
own_marker_select | tinyint | Custom marker enabled |
marker | varchar(255) | Field marker (variable name) |
mandatory_text | varchar(255) | Custom mandatory error text |
autocomplete_token | varchar(20) | Autocomplete attribute |
autocomplete_section | varchar(100) | Autocomplete section |
autocomplete_type | varchar(8) | Autocomplete type |
autocomplete_purpose | varchar(8) | Autocomplete purpose |
sorting | int | Sort order within page |
Indexes: parent_page (page), language (l10n_parent, sys_language_uid)
tx_powermail_domain_model_mail
| Column | Type | Description |
|---|---|---|
sender_name | varchar(255) | Submitter name |
sender_mail | varchar(255) | Submitter email |
subject | varchar(255) | Mail subject |
receiver_mail | varchar(1024) | Receiver email(s) |
body | text | Mail body (RTE) |
feuser | int | Frontend user UID (if logged in) |
sender_ip | tinytext | Submitter IP address |
user_agent | text | Browser user agent |
time | int | Submission timestamp |
form | int | Source form UID |
answers | int | IRRE children count |
spam_factor | varchar(255) | Spam score |
marketing_referer_domain | text | HTTP referer domain |
marketing_referer | text | Full HTTP referer |
marketing_country | text | Visitor country |
marketing_mobile_device | tinyint | Mobile device flag |
marketing_frontend_language | int | Frontend language UID |
marketing_browser_language | text | Browser Accept-Language |
marketing_page_funnel | text | Pages visited before submit |
Indexes: form (form), feuser (feuser)
tx_powermail_domain_model_answer
| Column | Type | Description |
|---|---|---|
mail | int | Parent mail UID |
value | text | Answer value (JSON for arrays) |
value_type | int | 0=text, 1=array, 2=date, 3=upload, 4=password |
field | int | Source field UID |
Indexes: mail (mail), deleted (deleted), hidden (hidden), language (l10n_parent, sys_language_uid)
ER Diagram (Relations)
tx_powermail_domain_model_form
│ 1
├──── * tx_powermail_domain_model_page (IRRE via form)
│ │ 1
│ └──── * tx_powermail_domain_model_field (IRRE via page)
│ │
│ │ referenced by
│ ▼
│ tx_powermail_domain_model_answer.field
│
└──── * tx_powermail_domain_model_mail (via form)
│ 1
└──── * tx_powermail_domain_model_answer (IRRE via mail)15. Workspace Support
Continues typo3-powermail from full guide.
15. Workspace Support
Powermail records (forms, pages, fields) fully support TYPO3 workspaces. When EXT:workspaces is installed, editors can draft form changes in a workspace and publish them after review.
Key points:
- All powermail tables gain
t3ver_wsid,t3ver_oid,t3ver_state,t3ver_stagecolumns - Records with
t3ver_wsid > 0are drafts (not visible in live frontend) - Use DataHandler for workspace operations — it handles versioning automatically
- Raw SQL requires manually setting all
t3ver_*columns on every INSERT - Conditions (powermail_cond) must be in the same workspace as the form
Workspace lifecycle: 1. Create records in workspace → t3ver_wsid = <ws_id>, t3ver_state = 1 2. Stage for review → t3ver_stage = 1 3. Publish via backend module or CLI → records become live (t3ver_wsid = 0)
Detailed SQL and DataHandler examples: See SKILL-EXAMPLES.md
for complete workspace-aware queries, publishing workflows, and CLI options.
16. Translations (Localization)
Continues typo3-powermail from full guide.
16. Translations (Localization)
Powermail supports full TYPO3 localization. Form structure (form, pages, fields) can be translated so editors see localized labels, settings, and options. Submitted mails inherit the frontend language.
How Translation Works
| Level | What gets translated | Key columns |
|---|---|---|
| Form | Title | sys_language_uid, l10n_parent |
| Page | Title (step heading) | sys_language_uid, l10n_parent |
| Field | Title, settings, placeholder, mandatory_text, description | sys_language_uid, l10n_parent |
Automatically stored with sys_language_uid from frontend | sys_language_uid | |
| Answer | Stored with language of submission | sys_language_uid |
Translation Rules
sys_language_uid = 0is the default language (e.g., English)sys_language_uid = 1(or higher) is a translation (e.g., German)l10n_parentpoints to the default language record UID- The
markerfield is not translated -- markers stay identical across languages - Field
typeis not translated -- structure is shared - Field
settings(select/radio options) is translated -- option labels change per language
Example: Create Form in English, Translate to German
Default Language (English, sys_language_uid=0)
-- Form
INSERT INTO tx_powermail_domain_model_form (pid, title, sys_language_uid, l10n_parent)
VALUES (1, 'Contact Form', 0, 0);
-- Assume UID = 10
-- Page
INSERT INTO tx_powermail_domain_model_page (pid, form, title, sorting, sys_language_uid, l10n_parent)
VALUES (1, 10, 'Your Details', 1, 0, 0);
-- Assume UID = 20
-- Fields
INSERT INTO tx_powermail_domain_model_field
(pid, page, title, type, marker, mandatory, sender_name, sorting, sys_language_uid, l10n_parent)
VALUES
(1, 20, 'First Name', 'input', 'firstname', 1, 1, 1, 0, 0), -- UID 30
(1, 20, 'Last Name', 'input', 'lastname', 1, 0, 2, 0, 0), -- UID 31
(1, 20, 'Email', 'input', 'email', 1, 0, 3, 0, 0), -- UID 32
(1, 20, 'Message', 'textarea', 'message', 0, 0, 4, 0, 0), -- UID 33
(1, 20, 'Subject', 'select', 'subject', 1, 0, 5, 0, 0), -- UID 34
(1, 20, 'Send', 'submit', 'submit', 0, 0, 6, 0, 0); -- UID 35
-- Select options for subject (English)
UPDATE tx_powermail_domain_model_field
SET settings = 'General Inquiry\nSupport Request\nPartnership\nOther'
WHERE uid = 34;
-- Mark email field as sender_email
UPDATE tx_powermail_domain_model_field SET sender_email = 1 WHERE uid = 32;German Translation (sys_language_uid=1)
-- Form translation (l10n_parent = 10, the English form)
INSERT INTO tx_powermail_domain_model_form (pid, title, sys_language_uid, l10n_parent)
VALUES (1, 'Kontaktformular', 1, 10);
-- Page translation (l10n_parent = 20)
INSERT INTO tx_powermail_domain_model_page
(pid, form, title, sorting, sys_language_uid, l10n_parent)
VALUES (1, 10, 'Ihre Daten', 1, 1, 20);
-- Field translations (l10n_parent points to English field UID)
INSERT INTO tx_powermail_domain_model_field
(pid, page, title, type, marker, mandatory, sender_name, sorting, sys_language_uid, l10n_parent)
VALUES
(1, 20, 'Vorname', 'input', 'firstname', 1, 1, 1, 1, 30),
(1, 20, 'Nachname', 'input', 'lastname', 1, 0, 2, 1, 31),
(1, 20, 'E-Mail-Adresse', 'input', 'email', 1, 0, 3, 1, 32),
(1, 20, 'Nachricht', 'textarea', 'message', 0, 0, 4, 1, 33),
(1, 20, 'Betreff', 'select', 'subject', 1, 0, 5, 1, 34),
(1, 20, 'Absenden', 'submit', 'submit', 0, 0, 6, 1, 35);
-- German select options for subject
UPDATE tx_powermail_domain_model_field
SET settings = 'Allgemeine Anfrage\nSupportanfrage\nPartnerschaft\nSonstiges'
WHERE sys_language_uid = 1 AND l10n_parent = 34;
-- Mark email field as sender_email (must be set on translation too)
UPDATE tx_powermail_domain_model_field
SET sender_email = 1
WHERE sys_language_uid = 1 AND l10n_parent = 32;Translation via DataHandler
<?php
declare(strict_types=1);
use TYPO3\CMS\Core\DataHandling\DataHandler;
use TYPO3\CMS\Core\Utility\GeneralUtility;
$dataHandler = GeneralUtility::makeInstance(DataHandler::class);
$dataHandler->start([], []);
// Localize form (UID 10) to German (sys_language_uid=1)
$cmdMap = [
'tx_powermail_domain_model_form' => [
10 => [
'localize' => 1, // target language UID
],
],
];
$dataHandler->start([], $cmdMap);
$dataHandler->process_cmdmap();
// DataHandler auto-creates translations of all IRRE children (pages + fields)
// Then update the translated titles:
$translatedFormUid = $dataHandler->copyMappingArray_merged['tx_powermail_domain_model_form'][10] ?? null;
if ($translatedFormUid) {
$data = [
'tx_powermail_domain_model_form' => [
$translatedFormUid => [
'title' => 'Kontaktformular',
],
],
];
$dataHandler->start($data, []);
$dataHandler->process_datamap();
}Important Translation Notes
- Markers are language-independent. The marker
emailstaysemailin all languages. - IRRE localization: When you localize a form via DataHandler (
localizecommand), TYPO3 automatically creates translations for all child pages and fields. - Select options: The
settingsfield (select/radio/check options) must be translated separately -- option values should match (for condition evaluation) but labels can differ. - Submitted mails: Mails store
sys_language_uidfrom the frontend context. Answers reference the default-language field UID regardless of submission language. - Backend module: The mail list shows mails from all languages. Filter by language if needed.
17. Full Example: Multi-Step Shop Form with Conditions
Continues typo3-powermail from full guide.
17. Full Example: Multi-Step Shop Form with Conditions
For a comprehensive multi-step mini-shop example with Austrian legal types (Gesellschaftsformen),
conditional fields per legal type, GDPR compliance, and two implementation approaches
(DDEV SQL + DataHandler CLI command), see SKILL-EXAMPLES.md.
TYPO3 Powermail Development Full Guide
Read only the section that matches the current task. These files continue the main SKILL.md after its lightweight workflow and examples.
Sections
- 4. Custom Finishers
- 5. Custom Validators
- 6. PSR-14 Events
- 7. Email Templates
- 8. Key ViewHelpers
- 9. AJAX Form Submission
- 10. Double Opt-In
- 11. Backend Module
- 12. Extension Best Practices
- 13. Common Recipes
- 14. Database Structure
- 15. Workspace Support
- 16. Translations (Localization)
- 17. Full Example: Multi-Step Shop Form with Conditions
- v14-Only Changes
v14-Only Changes
Continues typo3-powermail from full guide.
v14-Only Changes
The following items apply when the TYPO3 Core in your project is v14 (and Powermail itself supports that Core version per itscomposer.json). Until Packagist allowstypo3/cms-core:^14, treat v14 notes as forward-looking for integrations and custom code audits.
EXT:form Hooks Removed [v14 only]
If your custom extension code integrates with Core EXT:form (not only Powermail), note that all EXT:form hooks are removed in v14:
beforeRendering,afterSubmit,initializeFormElementbeforeFormSave,beforeFormDelete,beforeFormDuplicate,beforeFormCreateafterBuildingFinished,beforeRemoveFromParentRenderable
These are replaced by corresponding PSR-14 events (e.g., BeforeFormIsSavedEvent, BeforeRenderableIsRenderedEvent).
AbstractFinisher Changes [v14 only]
AbstractFinisher->getTypoScriptFrontendController() is removed (#107507). Finishers needing request context must use the PSR-7 request from the form runtime instead of $GLOBALS['TSFE'].
EXT:form Storage Adapters [v14.1+ only]
TYPO3 v14.1 introduces Storage Adapters for EXT:form, allowing pluggable storage backends for form definitions. This may affect how Powermail and EXT:form coexist in projects using both.
Fluid 5.0 Template Compatibility [v14 only]
Powermail Fluid templates must comply with Fluid 5.0 strict typing:
- ViewHelper arguments are strictly typed (integers vs strings matter).
- No underscore-prefixed variables in Fluid templates.
- Verify custom Fluid partials and templates for type mismatches.
Source: https://github.com/dirnbauer/webconsulting-skills
Powermail Conditions (powermail_cond)
Compatibility: TYPO3 13.4 with Powermail 13.x and powermail_cond 13.x (verify both on Packagist before assuming TYPO3 v14 support)
Requires: in2code/powermail: ^13.0 (adjust when upgrading majors)1. Overview
powermail_cond adds dynamic conditional visibility to powermail forms. Fields or entire pages (fieldsets) can be shown/hidden based on user input, evaluated via AJAX in real-time.
Installation
composer require in2code/powermail_condInclude the static TypoScript template from powermail_cond.
Architecture
ConditionContainer (tx_powermailcond_domain_model_conditioncontainer)
└── Condition (tx_powermailcond_domain_model_condition)
└── Rule (tx_powermailcond_domain_model_rule)- ConditionContainer: Links to one powermail Form (1:1)
- Condition: Defines a target (field or page) and action (hide/unhide), contains rules with AND/OR conjunction
- Rule: Single comparison against a field value
2. Operators
| # | Operator | Description |
|---|---|---|
| 0 | is set | Field has any value |
| 1 | is not set | Field is empty |
| 2 | contains value | Field value contains string |
| 3 | contains value not | Field value does not contain string |
| 4 | is | Field value equals string exactly |
| 5 | is not | Field value does not equal string |
| 6 | is greater than | Numeric comparison (numbers only) |
| 7 | is less than | Numeric comparison (numbers only) |
| 8 | contains value from field | Field value matches another field's value |
| 9 | contains not value from field | Field value differs from another field's value |
Operators 2–7 compare against a static string (cond_string). Operators 0–1 test field presence (“is set” / “is not set”) and ignore cond_string. Operators 8-9 compare against another form field (equal_field).
3. Backend Configuration
Step 1: Create Condition Container
1. Go to a sysfolder (or the page with the form) 2. Create new record: Condition Container 3. Set Title and select the Form 4. Add Conditions
Step 2: Configure Conditions
Each condition defines:
| Field | Description |
|---|---|
| Title | Descriptive name |
| Target Field | Which field or page to affect |
| Action | hide (0) or unhide (1) |
| Conjunction | OR (any rule matches) or AND (all rules must match) |
| Rules | One or more comparison rules |
Step 3: Configure Rules
Each rule defines:
| Field | Description |
|---|---|
| Title | Descriptive name |
| Start Field | The field whose value is checked |
| Operator | One of the 10 operators above |
| Condition String | Static comparison value (operators 2-7) |
| Equal Field | Other field for comparison (operators 8-9) |
Targeting Pages (Fieldsets)
To show/hide an entire page (fieldset), set the target field to the page. Pages appear in the target dropdown with a fieldset: prefix. When a page is hidden, all its fields are excluded from validation.
4. AJAX Endpoint
Conditions are evaluated server-side via TypeNum 3132.
TypoScript Setup (auto-included)
# TypeNum for AJAX condition evaluation
powermailCondition = PAGE
powermailCondition {
typeNum = 3132
config {
disableAllHeaderCode = 1
no_cache = 1
additionalHeaders.10.header = Content-type: application/json
}
10 = USER
10 {
userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run
extensionName = PowermailCond
vendorName = In2code
controller = Condition
pluginName = Pi1
}
}Route Enhancer for Clean URLs
routeEnhancers:
PageTypeSuffix:
type: PageType
default: /
index: ''
suffix: /
map:
condition.json: 3132JSON Response Format
{
"todo": {
"42": {
"1": {
"email": {
"#action": "hide",
"matching_condition": { "5": "5" }
},
"#action": "un_hide"
}
}
},
"loops": 3,
"loopLimit": 100
}Structure: todo[formUid][pageUid][fieldMarker] or todo[formUid][pageUid] for page-level actions.
5. Reducing Flickering (Server-Side Prerendering)
By default, conditions are loaded via AJAX after page load, causing visible flickering. Prerender conditions server-side to avoid this.
ViewHelper for Prerendering
Add to your copy of EXT:powermail/Resources/Private/Templates/Form/Form.html:
{namespace pc=In2code\PowermailCond\ViewHelpers}
<!-- Prerender conditions as inline JSON -->
<script type="application/json" id="form-{form.uid}-actions">
{pc:conditions(form:form) -> f:format.raw()}
</script>
<!-- Hide fieldsets until conditions are applied -->
<style type="text/css">
.powermail_fieldset {
opacity: 0;
visibility: hidden;
transition: opacity 0.5s, visibility 0.5s;
}
</style>The JavaScript detects the prerendered JSON and skips the initial AJAX call.
6. File Upload Optimization
File upload fields send all selected files with every AJAX condition request. If you don't need conditions based on file uploads, exclude them:
<f:form
action="{action}"
name="field"
enctype="multipart/form-data"
additionalAttributes="{vh:validation.enableJavascriptValidationAndAjax(
form:form,
additionalAttributes:{
data-powermail-cond-excluded-fields: '.powermail_file'
}
)}"
>7. Validator Integration (XCLASS)
powermail_cond XCLASSes powermail's InputValidator with ConditionAwareValidator to skip validation on hidden fields.
// Registered in ext_localconf.php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][
\In2code\Powermail\Domain\Validator\InputValidator::class
] = [
'className' => \In2code\PowermailCond\Domain\Validator\ConditionAwareValidator::class,
];Hidden field state is stored in the frontend user session under key tx_powermail_cond. The validator checks this session data before validating each field.
8. Extension Configuration
Loop Count Safety
The condition container iterates until no changes occur. A safety limit prevents infinite loops.
| Setting | Default | Description |
|---|---|---|
conditionLoopCount | 100 | Maximum iteration loops per evaluation |
Configure via Extension Manager or ext_conf_template.txt.
9. JavaScript Behavior
The frontend JavaScript (PowermailCondition.js) is auto-included via TypoScript:
page.includeJSFooter.powermailCond = EXT:powermail_cond/Resources/Public/JavaScript/PowermailCondition.js
page.includeJSFooter.powermailCond.defer = 1Behavior
- Listens to
changeevents on all form fields (input, textarea, select) - Sends form data to the condition endpoint via
fetch() - Applies hide/show actions via CSS classes (
powermail-cond-hidden) - Manages
requiredattribute (removes on hidden fields, restores on show) - Handles multi-step forms (
powermail_morestep) - Supports
pageshowevent (back/forward cache)
CSS for Hidden Fields
/* Applied by JavaScript */
.powermail-cond-hidden {
display: none !important;
}10. Known Limitations
- Multi-step + conditions:
powermail_condships JavaScript that listens on multi-step (powermail_morestep) forms. If you combine both, use matching majors of Powermail and powermail_cond and test the full wizard (see SKILL-EXAMPLES.md). Report edge cases to the extension vendors rather than assuming an old “never combine” blanket rule. - One container per form: Each form can have exactly one condition container
- XCLASS approach: Only one extension can XCLASS
InputValidator-- conflicts possible with other extensions modifying the same class - jQuery not required: Since powermail_cond 10.0.0, vanilla JS is used (no jQuery dependency)
11. Common Patterns
Show Field Based on Select Value
Scenario: Show "Other" text input when user selects "Other" in a dropdown.
1. Create Condition Container for the form 2. Add Condition:
- Target:
other_detailsfield - Action: hide (hidden by default)
3. Add Rule:
- Start field:
category(the select field) - Operator: is (4)
- Condition string:
Other
The "other_details" field is hidden by default and only shown when "Other" is selected.
Hide Page Based on Checkbox
Scenario: Hide an entire page/fieldset unless a checkbox is checked.
1. Add Condition:
- Target: Page (fieldset) containing the additional fields
- Action: hide
2. Add Rule:
- Start field:
accept_terms(checkbox) - Operator: is not set (1)
Field-to-Field Comparison
Scenario: Show a warning field when two email fields don't match.
1. Add Condition:
- Target:
email_mismatch_warningfield - Action: unhide (show when rule matches)
2. Add Rule:
- Start field:
email - Operator: contains not value from field (9)
- Equal field:
email_repeat
12. Database Structure
Note: powermail_cond usesl18n_parent(notl10n_parent) for its translation pointer.
Powermail core uses l10n_parent. Be careful with the naming difference.TYPO3 Standard Columns
All powermail_cond tables include these TYPO3-managed columns (not listed per table below):
| Column | Type | Purpose |
|---|---|---|
uid | int AUTO_INCREMENT | Primary key |
pid | int | Storage page UID |
tstamp | int | Last modification timestamp |
crdate | int | Creation timestamp |
deleted | tinyint | Soft-delete flag |
hidden | tinyint | Visibility flag |
sys_language_uid | int | Language UID (0 = default) |
l18n_parent | int | UID of the default language record |
l18n_diffsource | mediumblob | Diff source for translation |
starttime | int | Publish start |
endtime | int | Publish end |
tx_powermailcond_domain_model_conditioncontainer
| Column | Type | Description |
|---|---|---|
title | tinytext | Container title |
form | int | Related powermail form UID (1:1) |
conditions | int | IRRE children count |
note | tinyint | Backend warning flag (>30 fields) |
Relations: form -> tx_powermail_domain_model_form.uid
tx_powermailcond_domain_model_condition
| Column | Type | Description |
|---|---|---|
conditioncontainer | int | Parent container UID |
title | tinytext | Condition title |
target_field | tinytext | Target: field UID or fieldset:PAGE_UID |
actions | tinytext | 0 = hide, 1 = unhide |
conjunction | tinytext | OR or AND |
rules | int | IRRE children count |
Indexes: conditioncontainer, target_field(20) Hidden table: Yes (hideTable => 1) -- only editable inline inside container
tx_powermailcond_domain_model_rule
| Column | Type | Description |
|---|---|---|
conditions | int | Parent condition UID |
title | tinytext | Rule title |
start_field | int | Source field UID (the field whose value is checked) |
ops | int | Operator (0-9, see Section 2) |
cond_string | text | Comparison value (operators 2-7) |
equal_field | int | Comparison field UID (operators 8-9) |
Indexes: conditions, start_field, equal_field Hidden table: Yes (hideTable => 1) -- only editable inline inside condition
ER Diagram (Condition Relations)
tx_powermail_domain_model_form
│ 1
└──── 1 tx_powermailcond_domain_model_conditioncontainer (via form)
│ 1
└──── * tx_powermailcond_domain_model_condition (IRRE via conditioncontainer)
│ 1
└──── * tx_powermailcond_domain_model_rule (IRRE via conditions)
│
├── start_field -> tx_powermail_domain_model_field.uid
└── equal_field -> tx_powermail_domain_model_field.uid (ops 8-9)target_field Format
The target_field column uses two formats:
| Format | Example | Meaning |
|---|---|---|
{fieldUid} | 42 | Target is a single field (UID 42) |
fieldset:{pageUid} | fieldset:5 | Target is an entire page/fieldset (page UID 5) |
13. Full Example: Multi-Step Shop with Conditions
For a comprehensive example with Austrian legal types (Gesellschaftsformen),
conditional fields per legal type, and two implementation approaches
(DDEV SQL + DataHandler CLI command), see SKILL-EXAMPLES.md.