I am trying to create a new Email Template for the Account object using hook_form_alter. Here is how I create the template:

function my_module_form_user_admin_settings_alter(&$form, &$form_state, $form_id) {
    // Adds the Course Link email template to the Account Settings form
    $form['email_course_link'] = [
        '#type' => 'details',
        '#title' => t('Course link'),
        '#description' => t('Edit the course link e-mail messages sent to mobile app users.'),
        '#group' => 'email',
    $form['email_course_link']['user_mail_course_link_subject'] = [
        '#type' => 'textfield',
        '#title' => t('Subject'),
        '#maxlength' => 180,
    $form['email_course_link']['user_mail_course_link_body'] = [
        '#type' => 'textarea',
        '#title' => t('Body'),
        '#rows' => 15,

This adds the email template to my Account Settings form, but I am having two issues:

  1. When I go to edit the template and hit save configurations, nothing gets saved. The subject and body edits I made are wiped out and they no longer exist.

  2. When I go to use the template via _user_mail_notify('email_course_link', $user) I get NULL as the response and there are zero errors to be found and I never get the email...

What else am I missing here?


Specifically, your code is modifying the AccountSettingsForm, which is part of the core Drupal "user" module.

If you look at the source code for that form, you will see that like all forms in Drupal, it has both a buildForm() method and a submitForm() method. The problem with your code is that you've added form elements to the form array created by default in buildForm(), but you HAVEN'T added any code to process those new form elements and save the entered data, which is normally done in submitForm(). If you create new form elements in an existing form, you are responsible for processing the input and saving the entered values. Your custom module is the only thing that knows about those new elements, and your custom module is responsible for storing that data.

Let's look at one of the other elements defined in AccountSettingsForm, for example the email_admin_created details element which contains a user_mail_register_admin_created_subject and a user_mail_register_admin_created_body. It looks like you copied this code and changed the names for your own purpose, which is a good way to approach this. But if you search AccountSettingsForm, you will see that those form elements are also processed and saved in submitForm(), and you haven't added any new equivalent code for your new form elements.

The key then is to write your own function to execute on form submit, and in that function you need to save the values entered into your custom form elements. The way to tell Drupal about your custom submit function is to add the following at the end of your hook_form_alter():

$form['actions']['submit']['#submit'][] = 'my_module_email_course_link_submit';

Then add your function to my_module.module:

 * Submit callback to  process and save email_course_link form elements.
function my_module_email_course_link_submit(array $form, FormStateInterface $form_state) {
  $entered_body_value = $form_state->getValue('user_mail_course_link_body');
  $entered_subject_value = $form_state->getValue('user_mail_course_link_subject');

  // Save $entered_body_value and $entered_subject_value somewhere.
  // For example, in a database table created by your module, or
  // in a config object created by your module.
  // Where and how you save it is up to you.

You will also have to add use Drupal\Core\Form\FormStateInterface; at the top of my_module.module.

When you look at AccountSettingsForm you will see the user module saves form elements in the user.settings and user.mail configs. DON'T use those configs to store your custom data - define your own custom config if you want to store your own custom data in a configuration object.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.