Illustration: YAML configuration for custom form templates

Assign custom templates to the new EXT:form framework

With TYPO3 v8 LTS, a completely revised extension to create all kinds of forms was introduced. This time I'll show you how you can assign custom templates only to selected forms.

Introduction

The new form extension is configured entirely with YAML – this markup language was established in the TYPO3 universe with the new version 8. It is also used for the configuration of the new rich text editor ckeditor. Especially for the new form framework, a lot of configuration exists because the core developers wanted it to be as versatile as possible. TYPO3 integrators will have to adapt to this new configuration method. Thankfully, the backend module of form contains a quite helpful form editor which assists you with creating a new form.

One great advantage compared to proven form extensions like powermail is the way forms are stored. Every form is saved as a separate YAML file including all form fields, validators and finishers, e.g. to send emails. By default these files are saved inside the fileadmin folder by the backend module, but it's possible to save to site packages (template extensions). This way you can easily version your generated forms and reuse them in other TYPO3 installations. You can configure the backend module so that you're able to modify forms that have been outsourced to an extension. I will add this setting further below.

The general concept of the form extension is described in great detail on this page. You can find the configuration reference and API reference on the subsequent pages.

The documentation mentioned above (working draft) contains an example how to add custom templates. But these templates would be used for every form on your website, which is not always desired. Using TypoScript conditions would be inconvenient. There is an elegant way to achieve custom templates for single forms, though. For that, we'll need at least two YAML configuration files:

  • one YAML file to modify the basic configuration of form
  • one YAML file for every created form

File structure

I'll use a site package in this tutorial to store my files. The file structure is based on a typical TYPO3 Extbase extension:

  • ext_typoscript_setup.txt
    After installing the extension, the TypoScript inside this file is automatically loaded.
  • Configuration/Yaml/CustomFormSetup.yaml
    With this file we'll modify form to our needs.
  • Resources/Private/Forms/
    Here all created forms are stored.
  • Resources/Private/Frontend/Partials/
    Location for your customized frontend partials.
  • Resources/Private/Frontend/Templates/
    Location for your customized frontend templates.

If you wanted to adjust templates for the backend module, the location would be Resources/Private/Backend/Templates/. Please remember to respect the inner file structure of the templates: The small Partial to mark mandatory fields has to be saved inside Resources/Private/Frontend/Partials/Field/Required.html. Also keep in mind that a site package needs some basic configuration files to work, e.g. an ext_emconf.php. Of course you can store the configuration files and templates in every accessible folder on your webserver. The usage of a site package is the professional and recommended way, though.

Register YAML configuration with TypoScript

First of all we'll set a link to the following YAML file which will contain our modifications of the basic config. As the numbers 10 to 30 are already reserved by form, we'll use a higher number like 100 to add our path to the array of file paths.

Since this file will be used to also configure the backend module, we'll set the link in both top level objects plugin and module:

ext_typoscript_setup.txt

plugin.tx_form.settings.yamlConfigurations {
    100 = EXT:my_extension/Configuration/Yaml/CustomFormSetup.yaml
}

module.tx_form.settings.yamlConfigurations {
    100 = EXT:my_extension/Configuration/Yaml/CustomFormSetup.yaml
}

Create the YAML configuration

Next we'll create the YAML file which we specified above and include the following modifications:

  1. allowedExtensionPaths allows us to save forms inside on or more site packages and folders.
  2. allowSaveToExtensionPaths and allowDeleteFromExtensionPaths are pretty much self explaining. They enable us to edit forms within the backend module. Please check if your editors should be able to to this. Otherwise restrict access to the backend module or don't use these configurations.
  3. Finally we'll create a new so-called prototype which I just called mycontactform. The name is arbitrary. It it important to add the operator __inheritances to copy the definition of the standard prototype to our new prototype object. This operator behaves similar to the < operator in TypoScript. Subsequently we can set the rootPaths for our custom templates and partials.

CustomFormSetup.yaml

TYPO3:
  CMS:
    Form:
      persistenceManager:
        allowedExtensionPaths:
          10: EXT:my_extension/Resources/Private/Forms/
        allowSaveToExtensionPaths: true
        allowDeleteFromExtensionPaths: true

      prototypes:
        mycontactform:
          __inheritances:
            10: 'TYPO3.CMS.Form.prototypes.standard'
          formElementsDefinition:
            Form:
              renderingOptions:
                templateRootPaths:
                  100: 'EXT:my_extension/Resources/Private/Frontend/Templates/'
                partialRootPaths:
                  100: 'EXT:my_extension/Resources/Private/Frontend/Partials/'
                layoutRootPaths:
                  100: 'EXT:my_extension/Resources/Private/Frontend/Layouts/'

Create an example form

The following example form is shipped with the form extension and can be loaded inside the backend module. I only changed the prototypeName from standard to our new prototype mycontactform.

BasicContactForm.yaml

identifier: BasicContactForm
label: 'Basic contact form'
type: Form
prototypeName: mycontactform
finishers:
  -
    options:
      subject: 'Your message: {subject}'
      recipientAddress: your.company@example.com
      recipientName: 'Your Company name'
      senderAddress: '{email}'
      senderName: '{name}'
      replyToAddress: ''
      carbonCopyAddress: ''
      blindCarbonCopyAddress: ''
      format: html
      attachUploads: 'true'
      translation:
        language: ''
    identifier: EmailToReceiver
renderables:
  -
    identifier: page-1
    label: 'Contact Form'
    type: Page
    renderables:
      -
        defaultValue: ''
        identifier: name
        label: Name
        type: Text
        properties:
          fluidAdditionalAttributes:
            placeholder: Name
        validators:
          -
            identifier: NotEmpty
      -
        defaultValue: ''
        identifier: subject
        label: Subject
        type: Text
        properties:
          fluidAdditionalAttributes:
            placeholder: Subject
        validators:
          -
            identifier: NotEmpty
      -
        defaultValue: ''
        identifier: email
        label: Email
        type: Text
        properties:
          fluidAdditionalAttributes:
            placeholder: 'Email address'
        validators:
          -
            identifier: NotEmpty
          -
            identifier: EmailAddress
      -
        defaultValue: ''
        identifier: message
        label: Message
        type: Textarea
        properties:
          fluidAdditionalAttributes:
            placeholder: ''
        validators:
          -
            identifier: NotEmpty
  -
    identifier: summarypage
    label: 'Summary page'
    type: SummaryPage

Conclusion

What's so great about this simple configuration is that every form can get an individual template, even if more than one form exist on a single page.

By the way: If you only want to change CSS class names, custom templates aren't necessary – there are several configurations to change these. The default classes come from the Bootstrap framework. An example:

TYPO3:
  CMS:
    Form:
      prototypes:
        standard:
          formElementsDefinition:
            Textarea:
              properties:
                elementClassAttribute: 'xxlarge'
Back