Skip to content
Snippets Groups Projects
uw_cfg_common.module 37.1 KiB
Newer Older
Liam Morland's avatar
Liam Morland committed
<?php

/**
 * @file
 * Module file.
 */

use Drupal\Component\Utility\Html;
use Drupal\Core\Access\AccessResult;
Igor Biki's avatar
Igor Biki committed
use Drupal\Core\Entity\EntityInterface;
Liam Morland's avatar
Liam Morland committed
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Session\AccountInterface;
use Drupal\media_library\MediaLibraryState;
use Drupal\uw_cfg_common\Service\UWService;
use Drupal\webform\WebformInterface;
use Drupal\webform\WebformSubmissionStorageInterface;
Liam Morland's avatar
Liam Morland committed

/**
 * Implements hook_sendgrid_integration_categories_alter().
 *
 * Set the category for all sendmail as WCMS.
 */
function uw_cfg_common_sendgrid_integration_categories_alter($message, $categories) {
  $categories = ['WCMS'];

  return $categories;
}

 * Implements hook_metatags_attachments_alter().
function uw_cfg_common_metatags_attachments_alter(array &$metatag_attachments) {
  // Check if the image and og:image fields are empty.
  // We do this here instead of in hook_metatags_alter() because we want to
  // check if they're empty after tokens have been applied.
  // We also want to support the use case where they don't upload an image,
  // but do manually specify an image.
  // Because of where the information is stored, we have to loop to find it.
  $found_image_src = FALSE;
  $found_og_image = FALSE;
  foreach ($metatag_attachments['#attached']['html_head'] as $attachment) {
    if ($attachment[1] == 'image_src') {
      $found_image_src = TRUE;
    }
    elseif ($attachment[1] == 'og_image_0') {
      $found_og_image = TRUE;
    }
  }
  // Define what the fallback image is, so we only need to change it once.
  $fallback_image = 'https://uwaterloo.ca/university-of-waterloo-logo-152.png';
  // If the image_src field is missing, create one with the UWaterloo logo.
  if (!$found_image_src) {
    $metatag_attachments['#attached']['html_head'][] = [
      0 => [
        '#tag' => 'link',
        '#attributes' => [
          'rel' => "image_src",
          'href' => $fallback_image,
      ],
      1 => 'image_src',
    ];
  }
  // If the og:image field is missing, create one with the UWaterloo logo.
  if (!$found_og_image) {
    $metatag_attachments['#attached']['html_head'][] = [
      0 => [
        '#tag' => 'meta',
        '#attributes' => [
          'property' => "og:image",
          'content' => $fallback_image,
      ],
      1 => 'og_image_0',
    ];
Igor Biki's avatar
Igor Biki committed
function uw_cfg_common_entity_presave(EntityInterface $entity) {

  // Check if we are on a menu link.
  if ($entity->getEntityTypeId() == 'menu_link_content') {

    // Check that we are on a Information For (audience) link.
    if ($entity->menu_name->value == 'uw-menu-audience-menu') {

      // Invalid all the menu caching.
      \Drupal::cache('menu')->invalidateAll();

      // Rebuild all the menus.
      \Drupal::service('plugin.manager.menu.link')->rebuild();
    }
  }

  // On a node entity save, check if the responsive
  // image has created the derivatives so that things
  // like hero images will load when no image has yet
  // been rendered.  If we do not do this, most hero
  // images will not work.
  if ($entity->getEntityTypeId() == 'node') {

    // If there is a hero image (media), continue to process.
    if (
      $entity->hasField('field_uw_hero_image') &&
      $media = $entity->field_uw_hero_image->entity
    ) {
      // Hero media exists, get file entity from media.
      if ($file = $media->field_media_image->entity) {

        // Load the image styles that are needed for the hero.
        $uw_styles = \Drupal::service('uw_cfg_common.uw_service')->uwGetResponsiveImageStyles();

        // Step through each of the image styles and ensure that
        // the derivative is created.
        foreach ($uw_styles as $uw_style) {

          // Load the image style.
          $style = \Drupal::entityTypeManager()
            ->getStorage('image_style')
            ->load($uw_style);

          // Get the styled image derivative.
          $destination = $style->buildUri($file->getFileUri());

          // If the derivative doesn't exist yet (as the image style may
          // have been added post launch), create it.
          if (!file_exists($destination)) {
            $style->createDerivative($file->getFileUri(), $destination);
          }

    // If there is a type of media, ensure that we do only have
    // values in the fields that are selected.
    if ($entity->hasField('field_uw_type_of_media')) {

      // Get the type of media.
      $type_of_media = $entity->field_uw_type_of_media->value;

      // If it is null then set the hero image to null.
      if ($type_of_media == NULL) {
        $entity->set('field_uw_hero_image', NULL);
      }
    }
Liam Morland's avatar
Liam Morland committed
/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Remove the None option from layout builder styles.
 */
function uw_cfg_common_form_layout_builder_configure_section_alter(array &$form, FormStateInterface $form_state, string $form_id): void {
Liam Morland's avatar
Liam Morland committed
  // Remove the None option from layout builder styles.
  unset($form['layout_builder_style']['#empty_option']);

  // Ensuring that the contained width is selected by default.
  $form['layout_builder_style']['#default_value'] = $form['layout_builder_style']['#default_value'] ?: 'uw_lbs_contained_width';
Liam Morland's avatar
Liam Morland committed
}
/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Configure admin/structure/webform/config/submissions.
 */
function uw_cfg_common_form_webform_admin_config_submissions_form_alter(array &$form, FormStateInterface $form_state, string $form_id): void {
  // Remove undesired features.
  $form['views_settings']['#access'] = FALSE;
/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Configure admin/structure/webform/manage/WEBFORM_ID/access.
 */
function uw_cfg_common_form_webform_settings_access_form_alter(array &$form, FormStateInterface $form_state, string $form_id): void {
  /** @var \Drupal\webform\WebformInterface $webform */
  $webform = $form_state->getFormObject()->getEntity();

  // Choose access control method.
  $form['access']['create']['uw_access_control_method'] = [
    '#type' => 'radios',
    '#title' => t('Choose who can view and submit the form'),
    '#options' => [
      'all' => t('Everyone'),
      'auth' => t('Users who are logged in'),
      'group' => t('Users specified by Active Directory groups'),
      'user' => t('Users specified below'),
      'anon' => t('Users who are logged out (for anonymous submission)'),
    ],
    '#default_value' => $webform->getThirdPartySetting('uw_cfg_common', 'access_control_method') ?: 'all',
    '#required' => TRUE,
    '#weight' => -50,
  ];

  // Access by Active Directory group.
  $form['access']['create']['uw_ad_access'] = [
    '#type' => 'details',
    '#title' => t('Access control by Active Directory group'),
    '#required' => TRUE,
    '#open' => TRUE,
    '#states' => [
      'visible' => [
        'input[name="access[create][uw_access_control_method]"]' => ['value' => 'group'],
      ],
    ],
  ];
  $form['access']['create']['uw_ad_access']['ad_require_groups'] = [
    '#type' => 'textarea',
    '#title' => t('Limit form submission to these Active Directory groups'),
    '#description' => t('Put one Active Directory group per line. To complete the form, the user must be in at least one of these groups. Leave blank to allow everyone.'),
    '#default_value' => implode("\r\n", $webform->getThirdPartySetting('uw_cfg_common', 'ad_require_groups') ?: []),
  ];
  $form['access']['create']['uw_ad_access']['ad_deny_groups'] = [
    '#type' => 'textarea',
    '#title' => t('Prevent form submission for these Active Directory groups'),
    '#description' => t('Put one Active Directory group per line. To complete the form, the user must not be in any of these groups. Leave blank to allow everyone.'),
    '#default_value' => implode("\r\n", $webform->getThirdPartySetting('uw_cfg_common', 'ad_deny_groups') ?: []),
  ];

  // Validate and submit handler to save UW settings.
  $form['actions']['submit']['#validate'][] = '_uw_cfg_common_form_webform_settings_access_form_validate';
  $form['actions']['submit']['#submit'][] = '_uw_cfg_common_form_webform_settings_access_form_submit';

  // Users control is hidden or required, the latter when authz by user.
  $access_rule = [
    'input[name="access[create][uw_access_control_method]"]' => ['value' => 'user'],
  ];
  $form['access']['create']['users']['#states']['required'][] = $access_rule;
  $form['access']['create']['users']['#states']['visible'][] = $access_rule;

  // Remove sections for access control that should not be available.
  $sections_to_remove = [
    'update_any',
    'update_own',
    'delete_own',
    'administer',
    'configuration',
  ];
  foreach ($sections_to_remove as $section) {
    $form['access'][$section]['#access'] = FALSE;
  }

  // Remove all but user-based access for submissions and test.
  $permissions_to_edit = [
    'create',
    'view_any',
    'delete_any',
    'purge_any',
    'view_own',
    'test',
  ];
  $access_types_to_remove = [
    'roles',
    'permissions',
  ];
  foreach ($permissions_to_edit as $permission) {
    foreach ($access_types_to_remove as $type) {
      $form['access'][$permission][$type]['#access'] = FALSE;
/**
 * Form validate handler.
 */
function _uw_cfg_common_form_webform_settings_access_form_validate(array $form, FormStateInterface $form_state): void {
  // Validate UW settings.
  $access_control_method = [
    'access',
    'create',
    'uw_access_control_method',
  ];
  $access_control_method = $form_state->getValue($access_control_method);
  switch ($access_control_method) {
    // Validate AD groups.
    case 'group':
      $fields = [
        'ad_require_groups' => NULL,
        'ad_deny_groups' => NULL,
      ];
      foreach (array_keys($fields) as $field) {
        // Get groups.
        $setting = [
          'access',
          'create',
          'uw_ad_access',
          $field,
        ];
        $fields[$field] = uw_cfg_common_array_split_clean($form_state->getValue($setting));
        $form_state->setValue($setting, $fields[$field]);

        // Raise error for invalid groups.
        foreach ($fields[$field] as $group) {
          if (!preg_match('/^[A-Za-z0-9_& -]+$/', $group)) {
            $form_state->setError(
              $form['access']['create']['uw_ad_access'][$field],
              t(
                'Invalid group: %group.',
                ['%group' => substr($group, 0, 100)]
              )
            );
            break;
          }
        }
      }

      // Raise error if no groups are entered.
      if (!array_filter($fields)) {
        $form_state->setError(
          $form['access']['create']['uw_ad_access'],
          t('Provide at least one group to use for access control.')
        );
      }
      // Fall-through.
    case 'all':
    case 'auth':
    case 'anon':
      // Except for case 'user', ensure no user access constraint is set.
      $form_state->setValue(['access', 'create', 'users'], NULL);
      break;
  }
}

/**
 * Form submit handler.
 */
function _uw_cfg_common_form_webform_settings_access_form_submit(array $form, FormStateInterface $form_state): void {
  // Save UW settings.
  if ($webform = $form_state->getFormObject()->getEntity()) {
    // Access control method.
    $access_control_method = [
      'access',
      'create',
      'uw_access_control_method',
    ];
    $access_control_method = $form_state->getValue($access_control_method);
    $webform->setThirdPartySetting('uw_cfg_common', 'access_control_method', $access_control_method);

    // Only save groups if that is the access method. Otherwise, they would be
    // saved without having been validated.
    if ($access_control_method === 'group') {
      // AD group access.
      foreach (['ad_require_groups', 'ad_deny_groups'] as $field) {
        $setting = [
          'access',
          'create',
          'uw_ad_access',
          $field,
        ];
        $setting = $form_state->getValue($setting);
        $webform->setThirdPartySetting('uw_cfg_common', $field, $setting);
      }
    }

    $webform->save();
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Configure admin/structure/webform/manage/WEBFORM_ID/settings/confirmation.
 */
function uw_cfg_common_form_webform_settings_confirmation_form_alter(array &$form, FormStateInterface $form_state, string $form_id): void {
  // Remove undesirable Webform submission confirmation types.
  // The 'modal' type is just a different way to display the message. Disable
  // for consistency.
  unset($form['confirmation_type']['confirmation_type']['#options']['modal']);
  // The 'none' type is only useful along with a custom handler which provides
  // the confirmation message.
  unset($form['confirmation_type']['confirmation_type']['#options']['none']);

  // Remove undesired features.
  $form['confirmation_attributes_container']['#access'] = FALSE;
  $form['back']['back_container']['confirmation_back_attributes_container']['#access'] = FALSE;
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Configure admin/structure/webform/manage/WEBFORM_ID/settings.
 */
function uw_cfg_common_form_webform_settings_form_alter(array &$form, FormStateInterface $form_state, string $form_id): void {
  // Remove undesired features.
  $form['ajax_settings']['#access'] = FALSE;

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Configure admin/structure/webform/manage/WEBFORM_ID/settings/form.
 */
function uw_cfg_common_form_webform_settings_form_form_alter(array &$form, FormStateInterface $form_state, string $form_id): void {
  // Unset the source entity settings in webforms.
  $form['form_behaviors']['form_prepopulate_source_entity']['#access'] = FALSE;
  $form['form_behaviors']['form_prepopulate_source_entity_required']['#access'] = FALSE;
  $form['form_behaviors']['form_prepopulate_source_entity_type']['#access'] = FALSE;

  // Remove undesired features.
  $form['access_denied']['#access'] = FALSE;
  $form['custom_settings']['#access'] = FALSE;
  $form['form_behaviors']['form_autofocus']['#access'] = FALSE;
  $form['form_behaviors']['form_disable_back']['#access'] = FALSE;
  $form['form_behaviors']['form_novalidate']['#access'] = FALSE;
  $form['form_behaviors']['form_required']['#access'] = FALSE;
  $form['form_behaviors']['form_reset']['#access'] = FALSE;
  $form['form_behaviors']['form_submit_back']['#access'] = FALSE;
  $form['form_settings']['form_attributes']['#access'] = FALSE;
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Configure admin/structure/webform/manage/WEBFORM_ID/settings/submissions.
 */
function uw_cfg_common_form_webform_settings_submissions_form_alter(array &$form, FormStateInterface $form_state, string $form_id): void {
  // Remove undesired features.
  $form['access_denied']['#access'] = FALSE;
  $form['submission_behaviors']['form_convert_anonymous']['#access'] = FALSE;
  $form['submission_behaviors']['submission_log']['#access'] = FALSE;
  $form['submission_behaviors']['token_update']['#access'] = FALSE;
  $form['views_settings']['#access'] = FALSE;
/**
 * Implements hook_ENTITY_TYPE_create().
 */
function uw_cfg_common_webform_create(WebformInterface $webform) {
  // Submission purge settings. Set the default to purge drafts after 28 days.
  $webform->setSetting('purge', WebformSubmissionStorageInterface::PURGE_DRAFT);
  $webform->setSetting('purge_days', 28);
  // On admin/structure/webform/manage/FORM/settings/confirmation, default
  // "Confirmation type" to "inline".
  $webform->setSetting('confirmation_type', WebformInterface::CONFIRMATION_INLINE);
  // Set so that uw_cfg_common_webform_build_access_denied_alter() will run.
  // This value is tested for in Webform::preRenderWebformElement().
  $webform->setSetting('form_access_denied', WebformInterface::ACCESS_DENIED_PAGE);
/**
 * Implements hook_toolbar_alter().
 *
 * Remove the Manage link from the toolbar for authenticated users.
 */
function uw_cfg_common_toolbar_alter(&$items) {
  // Get the current user.
  $current_user = \Drupal::currentUser();

  // Remove the "manage" people for non-admin users.
  if (!$current_user->hasPermission('access manage toolbar item')) {
    // Remove "Manage" toolbar item.
    unset($items['administration']);
  }

  // Add "people" and "reports" links to "Workbench".
  // Note: 'dashboards' is renamed in
  // uw_dashboard_toolbar_alter().
  $links = [
    'entity.user.collection' => t('People'),
    'system.admin_reports' => t('Reports'),
  ];
  foreach ($links as $route => $title) {
    $url = Url::fromRoute($route);
    if ($url->access()) {
      $items['dashboards']['tray']['dashboards']['#items'][] = [
        '#type' => 'link',
        '#title' => $title,
        '#url' => $url,
      ];

/**
 * Implements hook_preprocess_node().
 */
function uw_cfg_common_preprocess_node(&$variables) {

  // Get the current path.
  $path = explode('/', \Drupal::service('path.current')->getPath());

  // The paths to place the content moderation block on.  Made this
  // an array to future proof, if there are more pages later.
  $paths_for_content_moderation = ['latest'];

  // ISTWCMS-4493: adding class if section has full width.
  // If there is a sidebar on the node, check all sections for full width.
  if (isset($variables['sidebar'])) {

    // Get the layouts from the node.
    $layouts = $variables['node']->layout_builder__layout->getValue();

    // Step through each of the layouts and check for full width.
    foreach ($layouts as $layout) {

      // Get the layout settings from the section.
      $settings = $layout['section']->getLayoutSettings();

      // If the layout builder style is set to full width, then set
      // the classes variable for the node and exit the loop.
      if (isset($settings['layout_builder_styles_style']) &&
        $settings['layout_builder_styles_style'] == "uw_lbs_full_width"
      ) {

        // Add a class to the node for full width on a section.
        $variables['attributes']['class'][] = 'uw-section-has-full-width';

        // Break out of the loop to save computational time.
        break;
      }
    }
  }

  // Check if we are to add the content moderation place.
  if (in_array(end($path), $paths_for_content_moderation)) {

    // Add the content moderation block.
    $variables['uw_content_moderation_form'] = \Drupal::formBuilder()->getForm('Drupal\content_moderation\Form\EntityModerationForm', $variables['node']);
  }
  else {

    $block_manager = \Drupal::service('plugin.manager.block');

    $plugin_block = $block_manager->createInstance('uw_cbl_content_moderation', []);

    $access_result = $plugin_block->access(\Drupal::currentUser());

    // Return empty render array if user doesn't have access.
    // $access_result can be boolean or an AccessResult class.
    if (is_object($access_result) && $access_result->isForbidden() || is_bool($access_result) && !$access_result) {
      return [];
    }

    $render = $plugin_block->build();

    $variables['uw_content_moderation_form'] = $render;
  }
}
/**
 * Implements hook_page_attachments().
 */
function uw_cfg_common_page_attachments(array &$page) {
  $page['#attached']['library'][] = 'uw_cfg_common/uw_mathjax';

  // Load uw_cfg_common module analytics configuration.
  $config = \Drupal::config('uw_cfg_common.google_settings');

  if ($config && $gso = $config->get('uw_cfg_common_google_site_ownership')) {
    $data = [
      '#tag' => 'meta',
      '#attributes' => [
        'name' => 'google-site-verification',
    // Attach tag to HEAD section.
    $page['#attached']['html_head'][] = [$data, 'uw-google-site-verification'];
  $admin_page = \Drupal::service('uw_cfg_common.uw_analytics')->administrationPage();
  // Get the code from config and inject to the page.
  if (!$admin_page && !empty($config->get('uw_cfg_common_ga_account'))) {
    $code = Html::escape($config->get('uw_cfg_common_ga_account'));

    $firstLetter = strtolower(substr($code, 0, 1));
    $snippet = _uw_cfg_common_google_analytics_snippet($firstLetter, $code);

    if ($firstLetter === 'g') {
      $external_script_data = [
        '#tag' => 'script',
        '#attributes' => [
          'async' => TRUE,
          'src' => 'https://www.googletagmanager.com/gtag/js?id=' . $code,
        ],
      ];
      $page['#attached']['html_head'][] = [
        $external_script_data,
        'uw-google-tag-manager',
      ];
    }

    $analytics = [
      '#type' => 'html_tag',
      '#tag' => 'script',
      '#value' => $snippet,
    ];

    $page['#attached']['html_head'][] = [
      $analytics,
 * Returns Google Analytics snippet code.
 *
 * @param string $firstLetter
 *   First letter of the code in lowercase.
 * @param string $code
 *   Analytics code, could be G-9999999999 or UA-99999999-99.
 * @param int $code_id
 *   Code order number.
 *
 * @return string
 *   Code snippet to be injected to html page in script tag.
 */
function _uw_cfg_common_google_analytics_snippet($firstLetter, $code, $code_id = 0): string {
  $snippet['u'] = "(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

ga('create', '@gtag', 'auto', {'name': 'tracker@code_id'});
ga('tracker@code_id.send', 'pageview');";

  $snippet['g'] = "window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '@gtag');";

  $output = str_replace('@gtag', $code, $snippet[$firstLetter]);

  if ($firstLetter === 'u') {
    $output = str_replace('@code_id', $code_id, $output);
  }

  return $output;
/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Set the default of preview mode disabled.
 */
function uw_cfg_common_form_node_type_add_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $form['submission']['preview_mode']['#default_value'] = 0;
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Node edit form: node/NID/edit.
 *
 * Prevent certain changes to the home page.
 */
function uw_cfg_common_form_node_uw_ct_web_page_edit_form_alter(array &$form, FormStateInterface $form_state, string $form_id): void {
  // No changes for those with access.
  if (\Drupal::currentUser()->hasPermission('bypass home page protection')) {
    return;
  }

  // Do not allow the home page to be parent of any item.
  unset($form['menu']['link']['menu_parent']['#options']['main:uw_base_profile.front_page']);

  // Early return if not editing home page.
  $nid = (int) \Drupal::routeMatch()->getRawParameter('node');
  if (!UWService::nodeIsHomePage($nid)) {
    return;
  }

  // Remove access to certain controls.
  $form['path']['#access'] = FALSE;
  $form['promote']['#access'] = FALSE;
  $form['sticky']['#access'] = FALSE;
  // For 'menu', setting #access did not work for non-admins. So, also hide the
  // sub-components and make it a container so that nothing appears on the page.
  $form['menu']['#access'] = FALSE;
  $form['menu']['#type'] = 'container';
  $form['menu']['enabled']['#access'] = FALSE;
  $form['menu']['link']['#access'] = FALSE;

  // Hide delete link if no access. This should happen by itself, but does not.
  if (!$form['actions']['delete']['#url']->access()) {
    $form['actions']['delete']['#access'] = FALSE;
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Menu edit form: admin/structure/menu/manage/{menu}.
 */
function uw_cfg_common_form_menu_edit_form_alter(array &$form, FormStateInterface $form_state, string $form_id): void {
  // Hide links to menu edit and delete for non-admin.
  if (!\Drupal::currentUser()->hasPermission('administer menu')) {
    foreach (Element::children($form['links']['links']) as $element_key) {
      $form['links']['links'][$element_key]['operations']['#access'] = FALSE;
    }
  }

  // Prevent certain changes to the home page.
  //
  // No changes for those with access.
  if (\Drupal::currentUser()->hasPermission('bypass home page protection')) {
    return;
  }

  // Return early if not editing "Main navigation" menu.
  if (!isset($form['links']['links']['menu_plugin_id:uw_base_profile.front_page'])) {
    return;
  }

  // Remove access to home page controls.
  $form['links']['links']['menu_plugin_id:uw_base_profile.front_page']['enabled']['#access'] = FALSE;
  $form['links']['links']['menu_plugin_id:uw_base_profile.front_page']['operations']['#access'] = FALSE;
  $form['links']['links']['menu_plugin_id:uw_base_profile.front_page']['weight']['#access'] = FALSE;
  // Make home page not draggable.
  $key = array_search('draggable', $form['links']['links']['menu_plugin_id:uw_base_profile.front_page']['#attributes']['class'], TRUE);
  unset($form['links']['links']['menu_plugin_id:uw_base_profile.front_page']['#attributes']['class'][$key]);
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Menu link edit form: admin/structure/menu/item/ID/edit.
 *
 * Do not allow the home page to be parent of any item.
 */
function uw_cfg_common_form_menu_link_content_menu_link_content_form_alter(array &$form, FormStateInterface $form_state, string $form_id): void {
  // No changes for those with access.
  if (\Drupal::currentUser()->hasPermission('bypass home page protection')) {
    return;
  }

  // Do not allow the home page to be parent of any item.
  unset($form['menu_parent']['#options']['main:uw_base_profile.front_page']);
}
/**
 * Implements template_preprocess_responsive_images().
 */
function uw_cfg_common_preprocess_responsive_image(&$variables) {

  // Get the current path.
  $current_path = \Drupal::service('path.current')->getPath();

  // Explode the current path so we can check where we are.
  $current_path_parts = explode('/', $current_path);

  // Get the media library parameters, we will use this
  // if we are on a media library page/modal.
  $media_lib_parameters = \Drupal::request()->query->get('media_library_opener_parameters');
  // If the current path has a node or media library params,
  // we need to alter the image styles.
  if (
    $current_path_parts[1] == 'node' ||
    $media_lib_parameters
  ) {

    // If we are on a contact image, remove all styles
    // but those for portraits.
    if (
      $media_lib_parameters['bundle'] == 'uw_ct_contact' ||
      end($current_path_parts) == 'uw_ct_contact'
    ) {

      // Get the styles used for portraits.
      $uw_styles = \Drupal::service('uw_cfg_common.uw_service')->getCropImageStyles('portrait');
    }
    else {

      // Get the styles used for responsive.
      $uw_styles = \Drupal::service('uw_cfg_common.uw_service')->getCropImageStyles('responsive');
    }

    // Step through each of the sources and see if we are.
    // to use it.
    foreach ($variables['sources'] as $index => $source) {

      // Get the srcset.
      $srcset = $source->storage()['srcset']->render();

      // Break into parts so that we can check for image styles.
      $srcset_parts = explode('/', $srcset);

      // Step through each of the srcset parts.
      foreach ($srcset_parts as $sp) {

        // Ensure that we are on an image style.
        if (strpos($sp, 'uw_is') !== FALSE) {

          // If not in the list of image styles, remove
          // it from the sources.
          if (!in_array($sp, $uw_styles)) {
            unset($variables['sources'][$index]);
          }
        }
      }
    }
  }
}

/**
 * Implements hook_form_alter().
 *
 * Hide/disable metatag information on our nodes.
 */
function uw_cfg_common_form_alter(array &$form, FormStateInterface $form_state, string $form_id): void {

  // ISTWCMS-4648: removing revisions from layout builder page.
  if (\Drupal::routeMatch()->getRouteName() == 'layout_builder.overrides.node.view') {
    $form['revision']['#access'] = FALSE;
    $form['advanced']['#access'] = FALSE;
  // Ensure that we are on a UW content type node.
  if (preg_match('/node_uw.*add_form/', $form_id) || preg_match('/node_uw.*edit_form/', $form_id)) {

    // Ensure that the node has metatag information.
    if (isset($form['field_uw_meta_tags'])) {

      // Hide elements under advanced settings.
      $form['field_uw_meta_tags']['widget'][0]['advanced']['canonical_url']['#access'] = FALSE;
      $form['field_uw_meta_tags']['widget'][0]['advanced']['shortlink_url']['#access'] = FALSE;

      // Hide elements under open graph.
      $form['field_uw_meta_tags']['widget'][0]['open_graph']['og_type']['#access'] = FALSE;
      $form['field_uw_meta_tags']['widget'][0]['open_graph']['og_url']['#access'] = FALSE;
      $form['field_uw_meta_tags']['widget'][0]['open_graph']['og_updated_time']['#access'] = FALSE;
      $form['field_uw_meta_tags']['widget'][0]['open_graph']['og_locale']['#access'] = FALSE;

      // Hide elements under Twitter settings.
      $form['field_uw_meta_tags']['widget'][0]['twitter_cards']['twitter_cards_page_url']['#access'] = FALSE;
      $form['field_uw_meta_tags']['widget'][0]['twitter_cards']['twitter_cards_page_url']['#access'] = FALSE;
    }
  }

  // If there is a type of media field, it means that we are
  // on a node add/edit page, so add the states for the
  // actual media types in the hero section.
  if (isset($form['field_uw_type_of_media'])) {
    $form['field_uw_hero_image']['#states'] = [
      'visible' => [
        [
          'select[name="field_uw_type_of_media"]' => [
            ['value' => 'image'],
          ],
        ],
      ],
    ];
  }
  // If we are on the media upload form, we want to restrict
  // what crops are available.
  if ($form_id == 'media_library_add_form_upload') {

    // If the crop widget is on the form, unset certain crops.
    if (isset($form['media'][0]['fields']['field_media_image']['widget'][0]['#crop_list'])) {

      // Get the parameters from the request, this was the only
      // way to get out what the bundle was.  Since this is a new
      // form call from media_library, we could not use get current
      // path or uri, since it would only return /media_library.
      // The media library parameters has everything listed for the
      // node and the node types.
      $media_lib_parameters = \Drupal::request()->query->get('media_library_opener_parameters');

      // If there are media lib parameters, process them.
      if ($media_lib_parameters) {

        // If there is a bundle on the parameters, continue
        // to process.
        if (isset($media_lib_parameters['bundle'])) {

          // If this is a contact, remove all the responsive crops.
          // If anything else, remove the portrait crop.
          if ($media_lib_parameters['bundle'] == 'uw_ct_contact') {
            foreach ($form['media'][0]['fields']['field_media_image']['widget'][0]['#crop_list'] as $index => $crop) {
              if ($crop !== 'uw_crop_portrait') {
                unset($form['media'][0]['fields']['field_media_image']['widget'][0]['#crop_list'][$index]);
              }
            }
          }
          else {
            foreach ($form['media'][0]['fields']['field_media_image']['widget'][0]['#crop_list'] as $index => $crop) {
              if ($crop == 'uw_crop_portrait') {
                unset($form['media'][0]['fields']['field_media_image']['widget'][0]['#crop_list'][$index]);
              }
            }
          }
        }
      }
    }
  }

/**
 * Implements hook_field_widget_WIDGET_TYPE_form_alter().
 */
function uw_cfg_common_field_widget_media_library_widget_form_alter(array &$element, FormStateInterface $form_state, array $context): void {
  /** @var \Drupal\Core\Routing\RouteMatchInterface $route_match */
  $route_match = \Drupal::routeMatch();

  if ($route_match->getRouteName() === 'layout_builder.add_block') {
    /** @var \Drupal\media_library\MediaLibraryState $state */
    $state = $element['open_button']['#media_library_state'];
    $openerParameters = $state->getOpenerParameters();
    $openerParameters['plugin_id'] = $route_match->getParameters()->get('plugin_id');
    $new_state = MediaLibraryState::create($state->getOpenerId(), $state->getAllowedTypeIds(), $state->getSelectedTypeId(), $state->getAvailableSlots(), $openerParameters);
    $element['open_button']['#media_library_state'] = $new_state;
  }
}

/**
 * Implements hook_ENTITY_TYPE_create_access().
 */
function uw_cfg_common_block_content_create_access(AccountInterface $account, array $context, string $entity_bundle): AccessResult {
  $route_name = \Drupal::routeMatch()->getRouteName();

  if ($route_name === 'media_library.ui') {
    /** @var \Drupal\media_library\MediaLibraryState $state */
    $state = MediaLibraryState::fromRequest(\Drupal::request());
    $openerParameters = $state->getOpenerParameters();

    // If the plugin ID exists within the opener parameters, we know
    // the media library is being used on the layout builder form.
    if (isset($openerParameters['plugin_id']) && substr($openerParameters['plugin_id'], 0, 12) === 'inline_block') {

      if ($account->hasPermission('create and edit custom blocks')) {
        return AccessResult::allowed();
      }
    }
  }

  // No opinion.
  return AccessResult::neutral();
}
/**
 * Implements hook_ENTITY_TYPE_access() for webform entities.
 */
function uw_cfg_common_webform_access(WebformInterface $webform, string $operation, AccountInterface $account): AccessResult {
  // Always allow access for Form editor so they can see the forms they create.
  if ($account->hasPermission('create webform')) {
    return AccessResult::neutral();
  }

  // Allow access to submissions for Form results access.
  if ($account->hasPermission('view any webform submission') && $operation === 'submission_view_any') {
    return AccessResult::neutral();
  }

  switch ($webform->getThirdPartySetting('uw_cfg_common', 'access_control_method')) {
    case 'anon':
      if (!$account->isAnonymous()) {
        return AccessResult::forbidden();
      }
      break;

    case 'auth':
      if (!$account->isAuthenticated()) {
        return AccessResult::forbidden();
      }
      break;

    case 'group':
      // Must be authenticated for group auth.
      if (!$account->isAuthenticated()) {
        return AccessResult::forbidden();
      }
      // Access control by Active Directory group.
      $user_ad_groups = uw_cfg_common_get_user_ad_groups() ?: [];
      // Required group. If at least one is provided, the user must be in it.
      $ad_require_groups = $webform->getThirdPartySetting('uw_cfg_common', 'ad_require_groups');
      if ($ad_require_groups && !array_intersect($ad_require_groups, $user_ad_groups)) {
        return AccessResult::forbidden();
      }
      // Deny group. If at least one is provided, the user must not be in it.
      $ad_deny_groups = $webform->getThirdPartySetting('uw_cfg_common', 'ad_deny_groups');
      if ($ad_deny_groups && array_intersect($ad_deny_groups, $user_ad_groups)) {
        return AccessResult::forbidden();
      }
      break;
  }

  return AccessResult::neutral();
}

/**
 * Implements hook_views_plugins_field_alter().
 */
function uw_cfg_common_views_plugins_field_alter(array &$plugins): void {