dxpr_theme-5.0.1/features/sooper-fonts/fonts-theme-settings-controller.inc

features/sooper-fonts/fonts-theme-settings-controller.inc
<?php

/**
 * @file
 * Applying theme font settings.
 */

use Drupal\Core\File\FileSystemInterface;

/**
 * Process theme font theme settings.
 *
 * @param array $variables
 *   Variables array for the html template.
 *
 * @throws \Drupal\Core\Entity\EntityStorageException
 */
function fonts_theme_settings_controller(array &$variables) {
  $dxpr_theme_fonts = [];
  $dxpr_theme_fonts[] = theme_get_setting('body_font_face');
  $dxpr_theme_fonts[] = theme_get_setting('headings_font_face');
  $dxpr_theme_fonts[] = theme_get_setting('nav_font_face');
  $dxpr_theme_fonts[] = theme_get_setting('sitename_font_face');
  $dxpr_theme_fonts[] = theme_get_setting('blockquote_font_face');

  $dxpr_theme_fonts = array_unique($dxpr_theme_fonts);
  $requested_google_fonts = [];

  foreach ($dxpr_theme_fonts as $dxpr_theme_font) {
    if (isset($dxpr_theme_font[0]) && $dxpr_theme_font[0] === '0') {
      $dxpr_theme_font = trim(substr($dxpr_theme_font, 1), ':');
      $requested_google_fonts[] = $dxpr_theme_font;
    }
    elseif (isset($dxpr_theme_font[0]) && $dxpr_theme_font[0] === '1') {
      _dxpr_theme_add_local_font($dxpr_theme_font, $variables);
    }
  }

  if (!empty($requested_google_fonts)) {
    _dxpr_theme_add_google_fonts($requested_google_fonts, $variables);
  }
}

/**
 * Helper function to add google fonts to the page.
 *
 * @param array $google_fonts
 *   Requested Google fonts.
 * @param array $variables
 *   Variables array.
 *
 * @throws \Drupal\Core\Entity\EntityStorageException
 */
function _dxpr_theme_add_google_fonts(array $google_fonts, array &$variables) {
  $state = \Drupal::state();
  $planned_fonts_update = $state->get('dxpr_theme_fonts_update');
  $stored_fonts = $state->get('dxpr_theme_stored_fonts');

  $active_theme = \Drupal::service('theme.manager')->getActiveTheme();
  /** @var \Drupal\Core\File\FileSystemInterface $file_system */
  $file_system = \Drupal::service('file_system');

  // Google font files are stored in public files for each theme.
  $fonts_folder_uri = 'public://' . $active_theme->getName() . '/fonts';

  // Check if fonts were already saved to files folder.
  $file_system->prepareDirectory($fonts_folder_uri, FileSystemInterface::CREATE_DIRECTORY);
  $font_family_exists = file_exists($fonts_folder_uri . '/font-face.css');

  $obsolete_fonts_cache = time() > $planned_fonts_update ||
    $stored_fonts !== implode(',', $google_fonts);

  if ($obsolete_fonts_cache || !$font_family_exists) {
    _dxpr_theme_remove_google_fonts();
    _dxpr_theme_cache_google_fonts($google_fonts, $fonts_folder_uri);
  }

  if ($wrapper = \Drupal::service('stream_wrapper_manager')->getViaUri($fonts_folder_uri . '/' . 'font-face.css')) {
    $local_path = $wrapper->realpath();

    if (!empty($local_path)) {
      $file_content = file_get_contents($local_path);
      $file_content = str_replace(["\r", "\n"], '', $file_content);

      $element = [
        '#tag' => 'style',
        '#value' => $file_content,
      ];

      $variables['#attached']['html_head'][] = [
        $element,
        'dxpr_theme_google_fonts',
      ];
    }
  }

}

/**
 * Cache requested Google fonts in public folder.
 *
 * @param array $google_fonts
 *   Requested Google fonts.
 * @param string $fonts_folder_uri
 *   Path to "cached" Google fonts.
 *
 * @throws \Drupal\Core\Entity\EntityStorageException
 * @throws \GuzzleHttp\Exception\GuzzleException
 */
function _dxpr_theme_cache_google_fonts(array $google_fonts, string $fonts_folder_uri) {
  $fonts_url = '';
  $state = \Drupal::state();
  /** @var \GuzzleHttp\ClientInterface $http_client */
  $http_client = \Drupal::httpClient();
  /** @var \Drupal\file\FileRepositoryInterface $file_repository */
  $file_repository = \Drupal::service('file.repository');

  // Build url to request Google fonts.
  foreach ($google_fonts as $google_font) {
    $font_params = explode(':', $google_font);

    if (!isset($font_params[1])) {
      $fonts_url .= 'family=' . $google_font . '&';
    }
    elseif (is_numeric($font_params[1])) {
      $fonts_url .= 'family=' . $font_params[0] . ':wght@' . $font_params[1] . '&';
    }
    elseif ($font_params[1] === 'italic') {
      $fonts_url .= 'family=' . $font_params[0] . ':ital@0;1&';
    }
    else {
      preg_match_all('/\d+/', $font_params[1], $matches);
      $font_weight = $matches[0][0];
      $fonts_url .= 'family=' . $font_params[0] . ':ital,wght@1,' . $font_weight . '&';
    }
  }

  // Store font-face css file.
  try {
    $response = $http_client->request('GET', '//fonts.googleapis.com/css2?' . $fonts_url . 'display=swap', [
      'headers' => [
        'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36',
      ],
    ]);
    $font_face = $response->getBody()->getContents();
  }
  catch (\Exception $exception) {
    \Drupal::logger('default')->error($exception->getMessage());
    return;
  }

  // Store font-face source.
  preg_match_all('/src[\s]*:[\s]*url\([\'"]*(.+?)[\'"]*\)[\s]*format\([\'"]*(.+?)[\'"]*\)/i', $font_face, $font_source_matches);
  foreach ($font_source_matches[1] as $font_source) {
    try {
      $response = $http_client->get($font_source);
      $google_font_source = $response->getBody()->getContents();
    }
    catch (\Exception $exception) {
      \Drupal::logger('default')->error($exception->getMessage());
      continue;
    }

    preg_match('/[A-Za-z0-9_\-\.]+\.[A-Za-z0-9]+$/i', $font_source, $font_name);
    $file_name = $fonts_folder_uri . '/' . $font_name[0];
    $file_repository->writeData($google_font_source, $file_name, FileSystemInterface::EXISTS_REPLACE);

    // Update font-face to use local links.
    if ($wrapper = \Drupal::service('stream_wrapper_manager')->getViaUri($file_name)) {
      $relative_file_source = \Drupal::service('file_url_generator')
        ->transformRelative($wrapper->getExternalUrl());
      $font_face = str_replace($font_source, $relative_file_source, $font_face);
    }
  }

  $file_repository->writeData($font_face, $fonts_folder_uri . '/' . 'font-face.css', FileSystemInterface::EXISTS_REPLACE);
  $state->set('dxpr_theme_fonts_update', strtotime("+1 week"));
  $state->set('dxpr_theme_stored_fonts', implode(',', $google_fonts));
}

/**
 * Delete existing "cached" Google fonts for before re-download.
 */
function _dxpr_theme_remove_google_fonts() {
  $active_theme = \Drupal::service('theme.manager')->getActiveTheme();
  $fonts_folder = 'public://' . $active_theme->getName() . '/fonts';

  $iterator = new RecursiveDirectoryIterator($fonts_folder, RecursiveDirectoryIterator::SKIP_DOTS);
  foreach ($iterator as $file) {
    \Drupal::service('file_system')->deleteRecursive($fonts_folder . '/' . $file->getFilename());
  }
}

/**
 * Helper function to add local fonts to the page.
 *
 * Add query string to stylesheet to prevent identically named files
 * to overwrite each other.
 *
 * @param string $font
 *   Font family name.
 * @param array $variables
 *   Variables array.
 */
function _dxpr_theme_add_local_font($font, array &$variables) {
  global $base_url;

  $added_stylesheets = &drupal_static(__FUNCTION__);
  $added_stylesheets = $added_stylesheets ?? [];

  $font = explode('|', substr($font, 1));
  $path = \Drupal::service('extension.list.theme')->getPath($font[0]) . $font[1];
  if (empty($added_stylesheets[$path])) {
    $element = [
      '#tag' => 'link',
      '#attributes' => [
        'href' => $base_url . '/' . $path,
        'rel' => 'stylesheet',
        'preload' => 'preload',
      ],
    ];
    $variables['#attached']['html_head'][] = [$element, $font[2]];
    $added_stylesheets[$path] = $path;
  }

  _dxpr_theme_add_local_font_preload_link($path, $font[2], $variables);
}

/**
 * Helper function to add preload links for local fonts to the page header.
 *
 * @param string $path
 *   Path to the fonts stylesheet file.
 * @param string $font_family
 *   Font family name.
 * @param array $variables
 *   Variables array.
 */
function _dxpr_theme_add_local_font_preload_link($path, $font_family, array &$variables) {
  $font_families = _dxpr_theme_add_local_font_parse_font_families($path);
  if (!empty($font_families[$font_family])) {
    $element = [
      '#type' => 'html_tag',
      '#tag' => 'link',
      '#attributes' => [
        'rel' => 'preload',
        'href' => '/' . dirname($path) . '/' . $font_families[$font_family]['url'],
        'as' => 'font',
        'type' => 'font/' . $font_families[$font_family]['format'],
      ],
    ];
    $variables['#attached']['html_head'][] = [
      $element,
      $font_family . '_preload',
    ];
  }
}

/**
 * Parse stylesheet file to fetch font files url and format.
 *
 * @param string $path
 *   Path to the fonts stylesheet file.
 *
 * @return array
 *   Array of the parsed data for the provided stylesheet file.
 */
function _dxpr_theme_add_local_font_parse_font_families($path) {
  $font_families = &drupal_static(__FUNCTION__);
  $font_families = $font_families ?? [];
  if (!isset($font_families[$path])) {
    $font_families[$path] = [];
    if ($wrapper = \Drupal::service('stream_wrapper_manager')->getViaUri($path)) {
      $local_path = $wrapper->realpath();
      $content = file_get_contents($local_path);
      preg_match_all('/@font-face\s*{([\s\S]*?)}/i', $content, $font_faces);
      foreach ($font_faces[1] as $font_face) {
        if (preg_match('/font-family: [\'"](.*?)[\'"]/i', $font_face, $font_family)) {
          $font_families[$path][$font_family[1]] = [];
          if (preg_match('/src[\s]*:[\s]*url\([\'"]*(.+?)[\'"]*\)[\s]*format\([\'"]*(.+?)[\'"]*\)/i', $font_face, $matches)) {
            $font_families[$path][$font_family[1]] = [
              'url' => $matches[1],
              'format' => $matches[2],
            ];
          }
        }
      }
    }
  }
  return $font_families[$path];
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc