You are here

contact.module in Drupal 10

Enables the use of personal and site-wide contact forms.

File

core/modules/contact/contact.module
View source
<?php

/**
 * @file
 * Enables the use of personal and site-wide contact forms.
 */
use Drupal\Core\Url;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\contact\Plugin\rest\resource\ContactMessageResource;
use Drupal\user\Entity\User;

/**
 * Implements hook_help().
 */
function contact_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {
    case 'help.page.contact':
      $menu_page = \Drupal::moduleHandler()
        ->moduleExists('menu_ui') ? Url::fromRoute('entity.menu.collection')
        ->toString() : '#';
      $block_page = \Drupal::moduleHandler()
        ->moduleExists('block') ? Url::fromRoute('block.admin_display')
        ->toString() : '#';
      $contact_page = Url::fromRoute('entity.contact_form.collection')
        ->toString();
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('The Contact module allows visitors to contact registered users on your site, using the personal contact form, and also allows you to set up site-wide contact forms. For more information, see the <a href=":contact">online documentation for the Contact module</a>.', [
        ':contact' => 'https://www.drupal.org/documentation/modules/contact',
      ]) . '</p>';
      $output .= '<h3>' . t('Uses') . '</h3>';
      $output .= '<dl>';
      $output .= '<dt>' . t('Using the personal contact form') . '</dt>';
      $output .= '<dd>' . t("Site visitors can email registered users on your site by using the personal contact form, without knowing or learning the email address of the recipient. When a site visitor is viewing a user profile, the viewer will see a <em>Contact</em> tab or link, which leads to the personal contact form. The personal contact link is not shown when you are viewing your own profile, and users must have both <em>View user information</em> (to see user profiles) and <em>Use users' personal contact forms</em> permission to see the link. The user whose profile is being viewed must also have their personal contact form enabled (this is a user account setting); viewers with <em>Administer users</em> permission can bypass this setting.") . '</dd>';
      $output .= '<dt>' . t('Configuring contact forms') . '</dt>';
      $output .= '<dd>' . t('On the <a href=":contact_admin">Contact forms page</a>, you can configure the fields and display of the personal contact form, and you can set up one or more site-wide contact forms. Each site-wide contact form has a machine name, a label, and one or more defined recipients; when a site visitor submits the form, the field values are sent to those recipients.', [
        ':contact_admin' => $contact_page,
      ]) . '</dd>';
      $output .= '<dt>' . t('Linking to contact forms') . '</dt>';
      $output .= '<dd>' . t('One site-wide contact form can be designated as the default contact form. If you choose to designate a default form, the <em>Contact</em> menu link in the <em>Footer</em> menu will link to it. You can modify this link from the <a href=":menu-settings">Menus page</a> if you have the Menu UI module installed. You can also create links to other contact forms; the URL for each form you have set up has format <em>contact/machine_name_of_form</em>.', [
        ':menu-settings' => $menu_page,
      ]) . '</p>';
      $output .= '<dt>' . t('Adding content to contact forms') . '</dt>';
      $output .= '<dd>' . t('From the <a href=":contact_admin">Contact forms page</a>, you can configure the fields to be shown on contact forms, including their labels and help text. If you would like other content (such as text or images) to appear on a contact form, use a block. You can create and edit blocks on the <a href=":blocks">Block layout page</a>, if the Block module is installed.', [
        ':blocks' => $block_page,
        ':contact_admin' => $contact_page,
      ]) . '</dd>';
      $output .= '</dl>';
      return $output;
  }
}

/**
 * Implements hook_entity_type_alter().
 */
function contact_entity_type_alter(array &$entity_types) {

  /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
  $entity_types['user']
    ->setLinkTemplate('contact-form', '/user/{user}/contact');
}

/**
 * Implements hook_entity_extra_field_info().
 */
function contact_entity_extra_field_info() {
  $fields = [];
  foreach (array_keys(\Drupal::service('entity_type.bundle.info')
    ->getBundleInfo('contact_message')) as $bundle) {
    $fields['contact_message'][$bundle]['form']['name'] = [
      'label' => t('Sender name'),
      'description' => t('Text'),
      'weight' => -50,
    ];
    $fields['contact_message'][$bundle]['form']['mail'] = [
      'label' => t('Sender email'),
      'description' => t('Email'),
      'weight' => -40,
    ];
    if ($bundle == 'personal') {
      $fields['contact_message'][$bundle]['form']['recipient'] = [
        'label' => t('Recipient username'),
        'description' => t('User'),
        'weight' => -30,
      ];
    }
    $fields['contact_message'][$bundle]['form']['preview'] = [
      'label' => t('Preview sender message'),
      'description' => t('Preview'),
      'weight' => 40,
    ];
    $fields['contact_message'][$bundle]['form']['copy'] = [
      'label' => t('Send copy to sender'),
      'description' => t('Option'),
      'weight' => 50,
    ];
  }
  $fields['user']['user']['form']['contact'] = [
    'label' => t('Contact settings'),
    'description' => t('Contact module form element.'),
    'weight' => 5,
  ];
  return $fields;
}

/**
 * Implements hook_menu_local_tasks_alter().
 *
 * Hides the 'Contact' tab on the user profile if the user does not have an
 * email address configured.
 */
function contact_menu_local_tasks_alter(&$data, $route_name) {
  if ($route_name == 'entity.user.canonical') {
    foreach ($data['tabs'][0] as $href => $tab_data) {
      if ($href == 'entity.user.contact_form') {
        $link_params = $tab_data['#link']['url']
          ->getRouteParameters();
        $account = User::load($link_params['user']);
        if (!$account
          ->getEmail()) {
          unset($data['tabs'][0]['entity.user.contact_form']);
        }
      }
    }
  }
}

/**
 * Implements hook_mail().
 */
function contact_mail($key, &$message, $params) {
  $contact_message = $params['contact_message'];

  /** @var \Drupal\user\UserInterface $sender */
  $sender = $params['sender'];
  $language = \Drupal::languageManager()
    ->getLanguage($message['langcode']);
  $variables = [
    '@site-name' => \Drupal::config('system.site')
      ->get('name'),
    '@subject' => $contact_message
      ->getSubject(),
    '@form' => !empty($params['contact_form']) ? $params['contact_form']
      ->label() : '',
    '@form-url' => Url::fromRoute('<current>', [], [
      'absolute' => TRUE,
      'language' => $language,
    ])
      ->toString(),
    '@sender-name' => $sender
      ->getDisplayName(),
  ];
  if ($sender
    ->isAuthenticated()) {
    $variables['@sender-url'] = $sender
      ->toUrl('canonical', [
      'absolute' => TRUE,
      'language' => $language,
    ])
      ->toString();
  }
  else {
    $variables['@sender-url'] = $params['sender']
      ->getEmail() ?? '';
  }
  $options = [
    'langcode' => $language
      ->getId(),
  ];
  switch ($key) {
    case 'page_mail':
    case 'page_copy':
      $message['subject'] .= t('[@form] @subject', $variables, $options);
      $message['body'][] = t("@sender-name (@sender-url) sent a message using the contact form at @form-url.", $variables, $options);
      $build = \Drupal::entityTypeManager()
        ->getViewBuilder('contact_message')
        ->view($contact_message, 'mail');
      $message['body'][] = \Drupal::service('renderer')
        ->renderPlain($build);
      break;
    case 'page_autoreply':
      $message['subject'] .= t('[@form] @subject', $variables, $options);
      $message['body'][] = $params['contact_form']
        ->getReply();
      break;
    case 'user_mail':
    case 'user_copy':
      $variables += [
        '@recipient-name' => $params['recipient']
          ->getDisplayName(),
        '@recipient-edit-url' => $params['recipient']
          ->toUrl('edit-form', [
          'absolute' => TRUE,
          'language' => $language,
        ])
          ->toString(),
      ];
      $message['subject'] .= t('[@site-name] @subject', $variables, $options);
      $message['body'][] = t('Hello @recipient-name,', $variables, $options);
      $message['body'][] = t("@sender-name (@sender-url) has sent you a message via your contact form at @site-name.", $variables, $options);
      $message['body'][] = t("If you don't want to receive such emails, you can change your settings at @recipient-edit-url.", $variables, $options);
      $build = \Drupal::entityTypeManager()
        ->getViewBuilder('contact_message')
        ->view($contact_message, 'mail');
      $message['body'][] = \Drupal::service('renderer')
        ->renderPlain($build);
      break;
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Add the enable personal contact form to an individual user's account page.
 *
 * @see \Drupal\user\ProfileForm::form()
 */
function contact_form_user_form_alter(&$form, FormStateInterface $form_state) {
  $form['contact'] = [
    '#type' => 'details',
    '#title' => t('Contact settings'),
    '#open' => TRUE,
    '#weight' => 5,
  ];
  $account = $form_state
    ->getFormObject()
    ->getEntity();
  if (!\Drupal::currentUser()
    ->isAnonymous() && $account
    ->id()) {
    $account_data = \Drupal::service('user.data')
      ->get('contact', $account
      ->id(), 'enabled');
  }
  $form['contact']['contact'] = [
    '#type' => 'checkbox',
    '#title' => t('Personal contact form'),
    '#default_value' => $account_data ?? \Drupal::config('contact.settings')
      ->get('user_default_enabled'),
    '#description' => t('Allow other users to contact you via a personal contact form which keeps your email address hidden. Note that some privileged users such as site administrators are still able to contact you even if you choose to disable this feature.'),
  ];
  $form['actions']['submit']['#submit'][] = 'contact_user_profile_form_submit';
}

/**
 * Submit callback for the user profile form to save the contact page setting.
 */
function contact_user_profile_form_submit($form, FormStateInterface $form_state) {
  $account = $form_state
    ->getFormObject()
    ->getEntity();
  if ($account
    ->id() && $form_state
    ->hasValue('contact')) {
    \Drupal::service('user.data')
      ->set('contact', $account
      ->id(), 'enabled', (int) $form_state
      ->getValue('contact'));
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Add the default personal contact setting on the user settings page.
 *
 * @see \Drupal\user\AccountSettingsForm
 */
function contact_form_user_admin_settings_alter(&$form, FormStateInterface $form_state) {
  $form['contact'] = [
    '#type' => 'details',
    '#title' => t('Contact settings'),
    '#open' => TRUE,
    '#weight' => 0,
  ];
  $form['contact']['contact_default_status'] = [
    '#type' => 'checkbox',
    '#title' => t('Enable the personal contact form by default for new users'),
    '#description' => t('Changing this setting will not affect existing users.'),
    '#default_value' => \Drupal::configFactory()
      ->getEditable('contact.settings')
      ->get('user_default_enabled'),
  ];

  // Add submit handler to save contact configuration.
  $form['#submit'][] = 'contact_form_user_admin_settings_submit';
}

/**
 * Form submission handler for user_admin_settings().
 *
 * @see contact_form_user_admin_settings_alter()
 */
function contact_form_user_admin_settings_submit($form, FormStateInterface $form_state) {
  \Drupal::configFactory()
    ->getEditable('contact.settings')
    ->set('user_default_enabled', $form_state
    ->getValue('contact_default_status'))
    ->save();
}

/**
 * Implements hook_rest_resource_alter().
 */
function contact_rest_resource_alter(&$definitions) {
  $definitions['entity:contact_message']['class'] = ContactMessageResource::class;
}