uw_fdsu_theme_resp.theme 17 KB
Newer Older
1
<?php
Liam Morland's avatar
Liam Morland committed
2

3 4
/**
 * @file
Liam Morland's avatar
Liam Morland committed
5
 * Theme file for uw_fdsu_theme_resp.
6 7
 */

8
use Drupal\Core\Url;
Liam Morland's avatar
Liam Morland committed
9 10 11
use Drupal\file\Plugin\Field\FieldType\FileFieldItemList;
use Drupal\image\Plugin\Field\FieldType\ImageItem;
use Drupal\Core\Form\FormStateInterface;
12
use Drupal\node\Entity\Node;
13

14 15 16 17 18 19 20 21 22 23 24 25
/**
 * @file
 * Functions to support theming.
 */

require_once dirname(__FILE__) . '/includes/block.inc';
require_once dirname(__FILE__) . '/includes/field.inc';
require_once dirname(__FILE__) . '/includes/form.inc';
require_once dirname(__FILE__) . '/includes/html.inc';
require_once dirname(__FILE__) . '/includes/navigation.inc';
require_once dirname(__FILE__) . '/includes/taxonomy.inc';
require_once dirname(__FILE__) . '/includes/views.inc';
26

27 28 29
/**
 * Implements hook_preprocess_HOOK().
 *
30
 * Setting the faculty class colour and favicon information.
31 32 33 34
 */
function uw_fdsu_theme_resp_preprocess_html(&$variables) {

  // Adding the faculty colour class to the body.
35
  $variables['attributes']['class'][] = theme_get_setting('wcms_colour_scheme', 'uw_fdsu_theme_resp') ? theme_get_setting('wcms_colour_scheme', 'uw_fdsu_theme_resp') : 'org-default';
36
  $variables['uw_admin_page'] = \Drupal::service('uw_cfg_common.uw_analytics')->administrationPage();
37

38
  _uw_fdsu_theme_resp_add_favicons($variables);
39

Tyler Struyk's avatar
Tyler Struyk committed
40
  // Add Javascript only on the user login page.
41 42 43 44
  $route_name = \Drupal::routeMatch()->getRouteName();
  if ($route_name == 'user.login') {
    $variables['#attached']['library'][] = 'uw_fdsu_theme_resp/user.login';
  }
45 46
}

47 48 49 50 51 52 53 54 55
/**
 * Implements hook_preprocess_responsive_image().
 */
function uw_fdsu_theme_resp_preprocess_responsive_image(&$variables) {

  // Step through each of the responsive image objects and get out source info.
  foreach ($variables['sources'] as $source) {

    // Set the a variable with the actual source info that we need.
Liam Morland's avatar
Liam Morland committed
56
    $new_sources[] = [
57 58 59
      'srcset' => $source['srcset']->value(),
      'media' => $source['media']->value(),
      'type' => $source['type']->value(),
Liam Morland's avatar
Liam Morland committed
60
    ];
61 62 63 64 65 66
  }

  // Set the sources variable to the new sources.
  $variables['sources'] = $new_sources;
}

67 68 69 70
/**
 * Implements hook_preprocess_region().
 */
function uw_fdsu_theme_resp_preprocess_region(&$variables) {
Eric Bremner's avatar
Eric Bremner committed
71

72 73 74
  // Get the region from variables.
  $region = $variables['elements']['#region'];

75 76 77
  // Variables that we want to have access to regardless of region.
  $variables['branding_level'] = theme_get_setting('wcms_branding_level', 'uw_fdsu_theme_resp') ? theme_get_setting('wcms_branding_level', 'uw_fdsu_theme_resp') : 'full';

78 79 80
  // If we are on the header, add the correct header classes
  // TO DO: Store the colour scheme used for the theme
  // (i.e. faculty colour and get the correct class here).
Liam Morland's avatar
Liam Morland committed
81
  if ($region == "header") {
Eric Bremner's avatar
Eric Bremner committed
82

83 84 85
    // Get the home page link.
    $variables['home_link'] = Url::fromRoute('<front>')->setAbsolute()->toString();

86
    // Set the main menu variable.
87
    $variables['main_menu'] = \Drupal::service('uw_cfg_common.uw_service')->uwGetMenu('main', TRUE, TRUE);
88

89
    // Set the secondary menu variable.
90
    $variables['secondary_menu'] = \Drupal::service('uw_cfg_common.uw_service')->uwGetMenu('uw-menu-audience-menu', TRUE, TRUE);
91

92
    // The class that is used for the header.
93
    $variables['classes'][] = 'uw-header';
94

95 96 97 98
    // Get the site name for placing inside the menu.
    $config = \Drupal::config('system.site');
    $variables['site_name'] = $config->get('name');

99
    $variables['faculty'] = theme_get_setting('wcms_colour_scheme', 'uw_fdsu_theme_resp') ? theme_get_setting('wcms_colour_scheme', 'uw_fdsu_theme_resp') : 'org-default';
100 101 102 103 104 105 106 107 108 109 110

    // Global message content.
    $global_message = file_get_contents('https://uwaterloo.ca/global-message.html');

    // If there is something to display, make sure to include css file, and
    // pass message as render array, then use render twig filter to avoid using
    // raw twig filter. Trimming message before sending to template, this
    // will remove any empty lines/spaces that message may have.
    if (!empty($global_message)) {
      $variables['global_message'] = ['#markup' => trim($global_message)];
    }
111
  }
112 113

  // ISTWCMS-4847.
114
  // If we are on the main content section, the check if not a node and add
115 116 117 118
  // appropriate classes to display proper width.
  if ($region == 'content') {

    // Get the route name.
119
    $route_match = \Drupal::routeMatch();
120

121 122
    // If we are on not on a node, add appropriate classes to show
    // proper width.
123
    $route_name = $route_match->getRouteName();
124
    $exemptions = [
125 126 127
      'entity.node.canonical',
      'entity.node.latest_version',
      'layout_builder.overrides.node.view',
128 129
    ];
    if (!in_array($route_name, $exemptions)) {
130 131 132 133
      $variables['classes'][] = 'layout';
      $variables['classes'][] = 'uw-contained-width';
    }
  }
134
}
135

136
/**
Eric Bremner's avatar
Eric Bremner committed
137
 * Implements hook_FORM_ID_alter().
138 139 140
 *
 * Add settings for colour scheme.
 */
Liam Morland's avatar
Liam Morland committed
141
function uw_fdsu_theme_resp_form_system_theme_settings_alter(&$form, FormStateInterface &$form_state, $form_id = NULL) {
142 143 144 145 146 147 148

  // Work-around for a core bug affecting admin themes. See issue #943212.
  if (isset($form_id)) {
    return;
  }

  // Fieldset for colour scheme.
Liam Morland's avatar
Liam Morland committed
149
  $form['colour_scheme'] = [
150 151 152
    '#type' => 'details',
    '#open' => TRUE,
    '#title' => t('Colour scheme'),
Liam Morland's avatar
Liam Morland committed
153
  ];
154 155

  // Colour scheme select list.
Liam Morland's avatar
Liam Morland committed
156
  $form['colour_scheme']['wcms_colour_scheme'] = [
157 158 159 160
    '#type'          => 'select',
    '#default_value' => theme_get_setting('wcms_colour_scheme', 'uw_fdsu_theme_resp') ? theme_get_setting('wcms_colour_scheme', 'uw_fdsu_theme_resp') : 'default',
    '#description'   => t("Select a color scheme to use"),
    '#options' => [
161 162 163 164 165 166 167 168
      'org-default' => t('Yellow/red (Default)'),
      'org-art' => t('Orange (Arts)'),
      'org-eng' => t('Purple (Engineering)'),
      'org-env' => t('Green (Environment)'),
      'org-ahs' => t('Teal (Health)'),
      'org-mat' => t('Pink (Mathematics)'),
      'org-sci' => t('Blue (Science)'),
      'org-school' => t('Red (School)'),
169
    ],
Liam Morland's avatar
Liam Morland committed
170
  ];
171 172 173 174 175 176 177 178 179 180 181 182 183

  // Fieldset for branding options.
  $form['branding_options'] = [
    '#type' => 'details',
    '#open' => TRUE,
    '#title' => t('Branding options'),
  ];

  // Branding select option.
  $form['branding_options']['wcms_branding_level'] = [
    '#type' => 'select',
    '#options' => [
      'full' => t('Full University branding'),
184 185
      'generic' => t('Generic with University wordmark'),
      'generic_barebones' => t('Fully generic'),
186 187 188
    ],
    '#default_value' => theme_get_setting('wcms_branding_level', 'uw_fdsu_theme_resp') ?: 'full',
  ];
189 190
}

191 192 193 194 195 196
/**
 * Add favicons to the page when called from hook_preprocess_html().
 *
 * @param array $variables
 *   The variables array.
 */
Kevin Paxman's avatar
Kevin Paxman committed
197
function _uw_fdsu_theme_resp_add_favicons(array &$variables) {
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
  // Remove Drupal's favicon.
  foreach ($variables['page']['#attached']['html_head_link'] as $id => $html_head_link) {
    if (isset($html_head_link[0]['rel']) && $html_head_link[0]['rel'] == 'shortcut icon') {
      unset($variables['page']['#attached']['html_head_link'][$id]);
      break;
    }
  }

  // Specify new favicon locations.
  // Based on https://evilmartians.com/chronicles/how-to-favicon-in-2021-six-files-that-fit-most-needs.
  $favicon_base_path = base_path() . drupal_get_path('theme', 'uw_fdsu_theme_resp');
  $favicon = [
    'rel' => 'icon',
    'href' => $favicon_base_path . '/favicon.ico',
  ];
  $variables['page']['#attached']['html_head_link'][] = [$favicon];
  $favicon_svg = [
    'rel' => 'icon',
    'href' => $favicon_base_path . '/icon.svg',
    'type' => 'image/svg+xml',
  ];
  $variables['page']['#attached']['html_head_link'][] = [$favicon_svg];
  $favicon_apple = [
    'rel' => 'apple-touch-icon',
    'href' => $favicon_base_path . '/apple-touch-icon.png',
  ];
224
  $variables['page']['#attached']['html_head_link'][] = [$favicon_apple];
225 226
  // Manifest needs a full URL.
  $favicon_base_path = \Drupal::request()->getSchemeAndHttpHost() . $favicon_base_path;
227 228 229 230 231 232 233 234 235 236 237
  $manifest = [
    'icons' => [
      [
        'src' => $favicon_base_path . '/icon-192.png',
        'type' => 'image/png',
        'sizes' => '192x192',
      ],
      [
        'src' => $favicon_base_path . '/icon-512.png',
        'type' => 'image/png',
        'sizes' => '512x512',
Kevin Paxman's avatar
Kevin Paxman committed
238
      ],
239 240
    ],
  ];
241
  $manifest = urlencode(json_encode($manifest));
242 243
  $favicon_manifest = [
    'rel' => 'manifest',
244
    'href' => 'data:application/manifest+json,' . $manifest,
245 246 247 248
  ];
  $variables['page']['#attached']['html_head_link'][] = [$favicon_manifest];
}

249
/**
Liam Morland's avatar
Liam Morland committed
250
 * Get the specified field value from a paragraph.
251
 *
Liam Morland's avatar
Liam Morland committed
252 253 254 255
 * @param object $paragraph
 *   The paragraph object.
 * @param string $field
 *   The name of the field.
256 257
 *
 * @return mixed
Liam Morland's avatar
Liam Morland committed
258
 *   The field value.
259 260
 */
function _uw_fdsu_theme_resp_get_field_value_from_paragraph($paragraph, $field) {
Eric Bremner's avatar
Eric Bremner committed
261

262 263 264 265 266
  // Get the field value.
  $field_value = $paragraph->get($field)->first();

  return $field_value->getValue()['value'];
}
Liam Morland's avatar
Liam Morland committed
267

268 269 270
/**
 * Set the variables required for a responsive image.
 *
Liam Morland's avatar
Liam Morland committed
271 272
 * @param array $variables
 *   The variables array.
Eric Bremner's avatar
Eric Bremner committed
273
 * @param \Drupal\image\Plugin\Field\FieldType\ImageItem $field
Liam Morland's avatar
Liam Morland committed
274 275 276 277
 *   The field object.
 * @param string $responsive_image_style
 *   The ID of the responsive image style.
 *
278 279 280 281
 * @return array|null
 *   An array with keys:
 *    - sources: An array of image sources.
 *    - alt: The alternative text.
282
 */
Liam Morland's avatar
Liam Morland committed
283
function _uw_fdsu_theme_resp_add_responsive_image_variables(array &$variables, ImageItem $field, string $responsive_image_style) : ?array {
Eric Bremner's avatar
Eric Bremner committed
284

285
  // If there is a file present, set responsive image variables.
286
  if ($file = $field->entity) {
Eric Bremner's avatar
Eric Bremner committed
287

288 289 290 291 292 293 294 295
    // Set uri and image style id.
    $variables['uri'] = $file->getFileUri();
    $variables['responsive_image_style_id'] = $responsive_image_style;

    // Call template function from responsive image core module.
    // It sets variables for srcset, media, type and img_element
    // for the responsive image style.
    template_preprocess_responsive_image($variables);
296

297
    // Step through each source and get string values.
298
    $sources = [];
Eric Bremner's avatar
Eric Bremner committed
299

300
    foreach ($variables['sources'] as $source) {
Eric Bremner's avatar
Eric Bremner committed
301

302
      $sources[] = [
303 304 305
        'srcset' => $source['srcset']->value(),
        'media' => $source['media']->value(),
        'type' => $source['type']->value(),
Liam Morland's avatar
Liam Morland committed
306
      ];
307 308
    }

309 310 311 312
    return [
      'sources' => $sources,
      'alt' => $field->get('alt')->getValue(),
    ];
313
  }
314
  return NULL;
315
}
316 317 318 319

/**
 * Get image properties from an image field.
 *
Eric Bremner's avatar
Eric Bremner committed
320
 * @param \Drupal\file\Plugin\Field\FieldType\FileFieldItemList $field
321 322 323 324 325 326
 *   The image field.
 *
 * @return array|null
 *   An array of image properties or NULL if $field does not contain the
 *   required information.
 */
Liam Morland's avatar
Liam Morland committed
327
function _uw_fdsu_theme_resp_get_image_info(FileFieldItemList $field) {
Eric Bremner's avatar
Eric Bremner committed
328

329 330
  // If there is an image, process it.
  if ($img_entity = $field->first()) {
Eric Bremner's avatar
Eric Bremner committed
331

332 333
    // If we can load a file, grab the info about the file.
    if ($file_entity = $img_entity->get('entity')->getTarget()) {
Eric Bremner's avatar
Eric Bremner committed
334

335 336 337 338 339 340 341
      return [
        'src' => file_create_url($file_entity->get('uri')->getString()),
        'alt' => $img_entity->get('alt')->getString(),
      ];
    }
  }
}
342

343 344 345 346 347 348 349
/**
 * Implements hook_preprocess_node().
 *
 * Set variables for node and teaser.
 */
function uw_fdsu_theme_resp_preprocess_node(&$variables) {

350 351 352
  // The UW service object.
  $uwService = \Drupal::service('uw_cfg_common.uw_service');

353 354
  $nodeContent = \Drupal::service('uw_cfg_common.uw_node_content');

355
  // The types of nodes the need preprocessing.
356
  $nodes_to_preprocess = $uwService->uwGetNodePreprocessing('full');
357 358

  // Teaser to be preprocessed.
359
  $teasers_to_preprocess = $uwService->uwGetNodePreprocessing('teaser');
360 361 362

  // If there is a node that needs preprocessing,
  // set the appropriate variables.
363 364
  if (in_array($variables['node']->getType(), $nodes_to_preprocess) ||
    in_array($variables['node']->getType(), $teasers_to_preprocess)) {
365 366

    // If on a teaser page get the variables for teaser.
367 368
    if ($variables['view_mode'] == 'teaser' &&
      in_array($variables['node']->getType(), $teasers_to_preprocess)) {
369
      $variables['teaser'] = $nodeContent->getNodeContent($variables['node'], 'teaser', 'all');
370 371 372
    }

    // If on a node page get the variables for now.
373
    if ($variables['view_mode'] == 'full' &&
374 375 376
      in_array($variables['node']->getType(), $nodes_to_preprocess
    )) {
      $variables['node_data'] = $nodeContent->getNodeContent($variables['node'], 'full', 'all');
377 378 379 380 381 382 383 384 385
      $variables['node_data']['content'] = $variables['content'];
    }

    // Unset the content variable, so that we do not get
    // a second print of all the content.
    unset($variables['content']);
  }
}

386 387 388 389 390 391 392
/**
 * Implements hook_preprocess_block().
 *
 * Add the admin_label and css classes if we are in layout builder.
 */
function uw_fdsu_theme_resp_preprocess_block(&$variables) {

393 394 395 396
  // Look at page title block to see if we have a featured image.
  // If we do then, set variable to not show page title.
  if ($variables['plugin_id'] == 'page_title_block') {

397
    // Set the featured image variable to no, we will only
398
    // change if there is a featured image.
399
    $variables['featured_image'] = 'no';
400 401 402 403

    // Load the node.
    $node = \Drupal::routeMatch()->getParameter('node');

404 405 406 407
    // ISTWCMS-4943: ensure that we get a node object.
    // If node is not object by this point, probably on
    // a revision page where node is an integer, so load
    // the node.
408
    if ($node && !is_object($node)) {
409 410 411
      $node = Node::load($node);
    }

412 413 414 415 416 417
    // If there is a node, check that it has a featured image.
    if ($node) {

      // The UW service object.
      $uwService = \Drupal::service('uw_cfg_common.uw_service');

418
      $variables['featured_image'] = $uwService->uwCheckNodeForFeaturedImage($node);
419 420 421
    }
  }

Eric Bremner's avatar
Eric Bremner committed
422 423 424
  // If we are in layout builder (this is set much earlier in
  // the page load process), then continue to look if we need
  // to add the admin_label and css classes.
425 426 427 428 429
  if (isset($variables['in_layout_builder']) && $variables['in_layout_builder'] == TRUE) {

    // Get the block manager object.
    $blockManager = \Drupal::service('plugin.manager.block');

Eric Bremner's avatar
Eric Bremner committed
430 431
    // Get the plugin definitions for the block, using the
    // plugin_id of the block.
432 433
    $plugin_definitions = $blockManager->getDefinition($variables['plugin_id']);

Eric Bremner's avatar
Eric Bremner committed
434 435 436 437 438 439 440 441
    // The admin labels to exclude, these are ones that we do not
    // want the admin label to appear on the layout builder page.
    $admin_labels_to_exclude = [
      'Messages',
      'Tabs',
      'Page title',
      'Global header',
      'Main navigation',
442
      'Site Footer block',
Eric Bremner's avatar
Eric Bremner committed
443
    ];
444

Eric Bremner's avatar
Eric Bremner committed
445 446 447 448 449 450
    // Check if the admin_label is an object, we need to do this
    // because some admin labels are translatable and are therefore
    // translatable markup objects (usually through code way of
    // building blocks.  Others are not, if translations are not turned
    // on for this block (usually through the GUI way of creating a block,
    // where the translation option is not set).
451 452
    if (is_object($plugin_definitions['admin_label'])) {

Eric Bremner's avatar
Eric Bremner committed
453 454
      // The admin label is a translatable markup, so just render
      // the object to set the admin label variable..
455 456 457 458
      $admin_label = $plugin_definitions['admin_label']->render();
    }
    else {

Eric Bremner's avatar
Eric Bremner committed
459 460
      // The admin label is not an object so just set the
      // admin label variable.
461 462 463
      $admin_label = $plugin_definitions['admin_label'];
    }

Eric Bremner's avatar
Eric Bremner committed
464 465 466
    // If the admin label is not in the ones to exclude add it
    // to the template variables and set the class to be used
    // to display the admin label.
467 468
    if (!in_array($admin_label, $admin_labels_to_exclude)) {
      $variables['admin_label'] = $admin_label;
469
      $variables['attributes']['class'][] = 'in-layout-builder';
470 471 472
    }
  }
}
473 474 475 476 477 478 479 480 481 482 483 484 485 486 487

/**
 * Implements template_preprocess_container().
 */
function uw_fdsu_theme_resp_preprocess_container(&$variables) {

  // Ensure that we are on a layout page.
  if (\Drupal::routeMatch()->getRouteName() == 'layout_builder.overrides.node.view') {

    // Ensure that we are on the first layout builder container.
    if (
      isset($variables['attributes']['class']) &&
      $variables['attributes']['class'][0] == 'layout-builder'
    ) {

488 489 490
      // The UW service object.
      $uwService = \Drupal::service('uw_cfg_common.uw_service');

491 492 493
      // The UW node content service.
      $uwNodeContent = \Drupal::service('uw_cfg_common.uw_node_content');

494 495
      // The list of content types that will have header
      // and footer in layout builder pages.
496
      $content_types = $uwService->uwGetNodePreprocessing('layout_container');
497

498 499 500
      // Get the node object.
      $node = \Drupal::routeMatch()->getParameter('node');

501 502 503 504 505 506 507 508
      // If there is a node object, and it is a content
      // type that has header and footer for layout pages,
      // get the header and footer.
      if ($node && in_array($node->getType(), $content_types)) {

        // Get the node object.
        $node = \Drupal::routeMatch()->getParameter('node');

509 510 511 512
        // Set variables for featured image.
        $variables['node_type'] = str_replace('_', '-', $node->getType());
        $variables['featured_image'] = $uwService->uwCheckNodeForFeaturedImage($node);

513 514
        // If there is a node object, get the header and footer data.
        if ($node) {
515 516
          $variables['header_data'] = $uwNodeContent->getNodeContent($node, 'teaser', 'header');
          $variables['footer_data'] = $uwNodeContent->getNodeContent($node, 'teaser', 'footer');
517
        }
518 519 520 521
      }
    }
  }
}