You are here

social_tour.module in Open Social 8.6

The Social Tour module.

File

modules/custom/social_tour/social_tour.module
View source
<?php

/**
 * @file
 * The Social Tour module.
 */
use Drupal\Core\Form\FormStateInterface;
use Drupal\tour\Entity\Tour;
use Drupal\user\UserInterface;

/**
 * Implements hook_form_FORM_ID_alter().
 */
function social_tour_form_user_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $user = \Drupal::routeMatch()
    ->getParameter('user');
  if ($user instanceof UserInterface) {

    // @TODO: We've currently decided to turn off the possibility for a LU to re-enable the tips.
    if (FALSE) {

      // Only do this when onboarding is disabled.
      // if (\Drupal::service('user.data')->get('social_tour',
      // \Drupal::currentUser()->id(), 'onboarding_disabled')) {
      // Add the card.
      $form['social_tour'] = [
        '#type' => 'fieldset',
        '#title' => t('Other settings'),
        '#tree' => TRUE,
      ];

      // Add the field.
      $form['social_tour']['social_tour_onboarding'] = [
        '#type' => 'checkbox',
        '#title' => t('Show tips on how to use the community'),
        '#defaukt_value' => FALSE,
        '#attributes' => [
          'data-switch' => TRUE,
        ],
      ];

      // Add a submit action.
      $form['actions']['submit']['#submit'][] = '_social_tour_form_user_form_submit';
    }
  }
}

/**
 * Form submit for user_form.
 *
 * @param array $form
 *   Commnent on a post form.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   Form state interface.
 */
function _social_tour_form_user_form_submit(array $form, FormStateInterface $form_state) {
  $onboarding = $form_state
    ->getValue('social_tour');

  // If it's changed do something.
  if ($onboarding['social_tour_onboarding'] == TRUE) {
    $uid = $form_state
      ->getValue('uid');
    \Drupal::service('user.data')
      ->set('social_tour', $uid, 'onboarding_disabled', 0);
  }
}

/**
 * Implements hook_preprocess_HOOK().
 */
function social_tour_preprocess_container(&$variables) {
  if (!_social_tour_init()) {
    return;
  }

  // In TourViewBuilder.php a container is rendered, this container has
  // children attribute with the total count. If the count of these children
  // is 1, we can unset it. We don't want to show 1 of 1 count.
  if (!empty($variables['attributes']['class'])) {
    foreach ($variables['attributes']['class'] as $class_name) {
      if ($class_name === 'tour-progress') {
        $child_arguments = $variables['children']
          ->getArguments();

        // So we found arguments for tour_progress. This is an array consisting
        // of [ '@tour_item' => integer 1, '@total' => integer 1 ]. If we have
        // a total of one. We can unset it, we don't need a 1 of 1 count.
        if (!empty($child_arguments)) {
          if (!empty($child_arguments['@total']) && $child_arguments['@total'] == 1) {
            unset($variables['children']);
          }
        }

        // We found a tour-progress container and did our magic.
        // We can break out the foreach.
        break;
      }
    }
  }
}

/**
 * Implements hook_page_attachments().
 *
 * This will add the social_tour library to all pages that have a tour
 * enabled so we can start it automatically.
 *
 * Only for users with access though.
 */
function social_tour_page_attachments(array &$page) {
  if (!_social_tour_init()) {
    return;
  }

  // Load all of the items and match on route name.
  $route_name = \Drupal::routeMatch()
    ->getRouteName();
  $tags = \Drupal::service('social_tour.onboarding')
    ->getCacheTags($route_name);

  // If we have a tour available, and there is at least one tour tip we attach
  // our JS library that makes sure the tour pops up immediately.
  if ($tags) {
    $page['#attached']['library'][] = 'social_tour/social_tour';
    $page['#cache']['tags'] = $tags;
  }
}

/**
 * Implements hook_module_implements_alter().
 *
 * Making sure here that the social_tour is executed after the tour.
 */
function social_tour_module_implements_alter(&$implementations, $hook) {
  if ($hook === 'page_bottom') {

    // Move social_tour_page_bottom() to the end of the list.
    $st = $implementations['social_tour'];
    unset($implementations['social_tour']);
    $implementations['social_tour'] = $st;
  }
}

/**
 * Implements hook_page_bottom().
 *
 * Because the social_tour weight is higher than the core tour.module weight
 * we make sure this code runs after tour_page_bottom(). Thus we can remove
 * any tours a user has already seen.
 */
function social_tour_page_bottom(array &$page_bottom) {
  if (!_social_tour_init()) {
    return;
  }

  // Load all of the items and match on route name.
  $route_match = \Drupal::routeMatch();
  $route_name = $route_match
    ->getRouteName();
  $seen_before = FALSE;

  // Get all the tours available for the current route name.
  $results = \Drupal::entityQuery('tour')
    ->condition('routes.*.route_name', $route_name)
    ->execute();
  if (!empty($results) && ($tours = Tour::loadMultiple(array_keys($results)))) {
    foreach ($tours as $id => $tour) {

      // EDGE CASE:
      // THIS MUST REMAIN ON TOP OF THE FOREACH.
      // social-profile  needs to made available on your own profile only.
      // So it must be removed from the array, but not marked as seen before,
      // when you visit the profile of others.
      if ($id === 'social_profile' && isset($page_bottom['tour'][$id])) {

        /** @var \Drupal\user\Entity\User $profile */
        $profile = $route_match
          ->getParameter('user');
        if ($profile
          ->id() !== \Drupal::currentUser()
          ->id()) {

          // If it's not your own profile, we don't show this tour.
          unset($tours[$id], $page_bottom['tour'][$id]);
          continue;
        }
      }

      // Now we check the user data, if it's set for the current tour we don't
      // have to render it anymore. because that means the user has already
      // seen it, either they finished the tour or they skipped the tour.
      // But in any way we don't want the user to see the tour twice.
      if (\Drupal::currentUser()
        ->isAuthenticated()) {

        // For logged in users of any role we add it to the user data.
        // For each tour that is rendered we set the tour id to TRUE.
        $seen_before = \Drupal::service('user.data')
          ->get('social_tour', \Drupal::currentUser()
          ->id(), $id);
      }
      else {

        // For Anonymous we put it in a session. Probably they won't even see
        // a tour.
        $seen_before = $_SESSION['social_tour'][$id];
      }
      if ($seen_before) {

        // Remove the tour from the render array.
        unset($tours[$id]);

        // Remove the tour from the page bottom array if the tour module already
        // added it. See tour_page_bottom() in tour.module.
        unset($page_bottom['tour'][$id]);
      }
    }
    if (!empty($tours)) {

      // Ah so we rendered the tour in the bottom of the page, we can also set
      // it to the user data so the user doesn't see it anymore.
      foreach ($tours as $id => $tour) {
        if (\Drupal::currentUser()
          ->isAuthenticated()) {

          // For logged in users of any role we add it to the user data.
          // For each tour that is rendered we set the tour id to TRUE.
          \Drupal::service('user.data')
            ->set('social_tour', \Drupal::currentUser()
            ->id(), $id, TRUE);
        }
        else {

          // For Anonymous we put it in a session. Probably they won't even see
          // a tour.
          $_SESSION['social_tour'][$id] = TRUE;
        }
      }
    }
  }
}

/**
 * Static wrapper, since this is called approx. 8 times per page load.
 */
function _social_tour_init() {
  $data =& drupal_static(__FUNCTION__);
  if (!isset($data['social_tour'])) {
    $data['social_tour'] = _social_tour_check();
  }
  return $data['social_tour'];
}

/**
 * Check some stuff before doing anything with these tours.
 */
function _social_tour_check() {

  /** @var \Drupal\social_tour\SocialTourController $onboarding */
  $onboarding = \Drupal::service('social_tour.onboarding');
  return $onboarding
    ->onboardingEnabled();
}

/**
 * Function that reimports tour configuration.
 */
function social_tour_reimport_config() {
  $config_factory = \Drupal::configFactory();
  $names = $config_factory
    ->listAll('tour.tour.social');

  // Loop through existing content and throw away.
  foreach ($names as $name) {
    $config_factory
      ->getEditable($name)
      ->delete();
  }

  // Re-import config.
  \Drupal::service('config.installer')
    ->installDefaultConfig('module', 'social_tour');
}

Functions

Namesort descending Description
social_tour_form_user_form_alter Implements hook_form_FORM_ID_alter().
social_tour_module_implements_alter Implements hook_module_implements_alter().
social_tour_page_attachments Implements hook_page_attachments().
social_tour_page_bottom Implements hook_page_bottom().
social_tour_preprocess_container Implements hook_preprocess_HOOK().
social_tour_reimport_config Function that reimports tour configuration.
_social_tour_check Check some stuff before doing anything with these tours.
_social_tour_form_user_form_submit Form submit for user_form.
_social_tour_init Static wrapper, since this is called approx. 8 times per page load.