Skip to content

Hooks and filters

Text domain: ad-form. All hook names are prefixed ad_form_.

Constants live in Dingfelder\AdForm\Core\Hooks.

Actions

HookWhen
ad_form_register_servicesAfter core bindings, before boot()
ad_form_loadedPlugin fully booted
ad_form_register_fieldsRegister field types on FieldRegistry
ad_form_rest_routesAfter core REST routes
ad_form_elementor_registerAfter core hooked the Elementor widget/category
ad_form_gutenberg_registerAfter core attempted to register ad-form/form
ad_form_before_form_saveBefore insert/update
ad_form_after_form_saveAfter insert/update
ad_form_after_form_deleteAfter form delete
ad_form_before_form_renderBefore frontend HTML is built
ad_form_after_form_renderAfter frontend HTML is built
ad_form_before_submissionBefore a submission is stored
ad_form_after_submissionAfter a submission is stored (Submission, Form). Not fired for honeypot hits.
ad_form_after_entry_statusAfter an entry is read/spam/trashed/starred
ad_form_after_entry_deleteAfter an entry is permanently deleted
ad_form_before_validationBefore submitted values are sanitized and validated (Form, raw values)
ad_form_after_validationAfter validation (Form, sanitized visible values, field errors)
ad_form_before_actionBefore a submit action runs (type, settings, ActionContext). Not fired for an action the plan does not include
ad_form_after_actionAfter a submit action ran (type, ActionResultInterface, ActionContext)
ad_form_license_activatedAfter a licence was connected (plan, state)
ad_form_license_deactivatedAfter a licence was released from this installation
ad_form_license_changedAfter a manual licence refresh (state)
ad_form_register_featuresRegister add-on features on FeatureRegistry. Core keys cannot be redefined
ad_form_register_gated_modulesDeclare a module's required entitlements on ModuleGate
ad_form_feature_deniedA feature was refused (feature, required_plan). Observation only

Filters

HookPurpose
ad_form_service_providersAdd/replace service providers
ad_form_capabilitiesExtra capability names
ad_form_form_definitionSanitized form definition JSON
ad_form_form_queryForm list query
ad_form_form_rest_itemSerialized REST form
ad_form_submission_queryEntry list query
ad_form_submission_rest_itemSerialized REST entry
ad_form_fieldsRegistered field type map (type => FieldInterface)
ad_form_actionsRegistered submit action map (type => ActionInterface)
ad_form_merge_tagsMerge tag map (tag => replacement) for email templates
ad_form_condition_operatorsCondition operator catalogue (id, label, needs_value)
ad_form_validation_rulesExtra rules (later)
ad_form_integrationsIntegration modules (later)
ad_form_settingsSettings array
ad_form_log_contextSanitize log context
ad_form_rendered_htmlFinal frontend HTML
ad_form_license_api_baseLicence API base URL. For staging. Grants nothing: payloads still need a valid signature
ad_form_license_dashboard_urlDashboard base URL
ad_form_license_timeoutLicence HTTP timeout, clamped to 1–30 seconds
ad_form_upgrade_urlUpgrade destination
ad_form_billing_urlBilling destination

Licensing has no escape hatch

Every licensing hook above is an action, and the five licensing filters are presentational. There is deliberately no filter that can rewrite entitlements, the feature registry or the licence state: each would be a documented one-line bypass. FeatureRegistry::register() refuses any key that is already a core key, and ModuleGate::register() refuses to redefine a core module id.

See docs/ENTITLEMENTS.md and docs/adr/0004-feature-gating.md.

Capabilities

Granted to administrator on activation:

  • manage_ad_form_forms
  • create_ad_form_forms
  • edit_ad_form_forms
  • delete_ad_form_forms
  • view_ad_form_submissions
  • edit_ad_form_submissions
  • delete_ad_form_submissions
  • manage_ad_form_settings

PHP interfaces for add-ons

  • Dingfelder\AdForm\Forms\FormRepositoryInterface
  • Dingfelder\AdForm\Fields\FieldInterface
  • Dingfelder\AdForm\Actions\ActionInterface
  • Dingfelder\AdForm\Integrations\IntegrationInterface
  • Dingfelder\AdForm\Payments\PaymentGatewayInterface
  • Dingfelder\AdForm\Conditions\ConditionEngineInterface
  • Dingfelder\AdForm\Calculations\CalculationEngineInterface
  • Dingfelder\AdForm\Templates\FormRendererInterface
  • Dingfelder\AdForm\Support\ValidationRuleInterface
  • Dingfelder\AdForm\Core\ModuleInterface
  • Dingfelder\AdForm\Licensing\ApiTransportInterface

Declaring entitlements on your own types

required_entitlements() is declared on AbstractField and AbstractAction, not on the interfaces, so an add-on implementing FieldInterface or ActionInterface directly keeps working and simply declares no requirements.

php
final class SignatureField extends \Dingfelder\AdForm\Fields\AbstractField {

	public function type(): string {
		return 'signature';
	}

	/**
	 * All of these must be granted before the field can be saved or rendered.
	 *
	 * @return list<string>
	 */
	public function required_entitlements(): array {
		return array( 'fields.advanced', 'fields.signature' );
	}
}

Declaring it once is enough: the registry, the definition scanner, the save gate, the builder palette and the REST catalogue all read the same method.

Digitale Lösungen. Persönlich. Zukunftssicher.