You are here

google_fonts_api.module in @font-your-face 8.3

Google Fonts module file.

File

modules/google_fonts_api/google_fonts_api.module
View source
<?php

/**
 * @file
 * Google Fonts module file.
 */
use Drupal\Core\Link;
use Drupal\Core\Form\FormStateInterface;

/**
 * Implements hook_fontyourface_api().
 */
function google_fonts_api_fontyourface_api() {
  return [
    'version' => '3',
    'name' => 'Google Fonts',
  ];
}

/**
 * Implements hook_modules_installed().
 *
 * Use this hook instead of hook_install, because the route "font.settings" is
 * not defined otherwise.
 */
function google_fonts_api_modules_installed($modules) {
  if (in_array('google_fonts_api', $modules)) {
    Drupal::messenger()
      ->addMessage(t('Due to the number of fonts, automated import from install for Google Fonts is disabled. Please use @link to import Google Fonts.', [
      '@link' => Link::createFromRoute('@font-your-face settings', 'font.settings')
        ->toString(),
    ]));
  }
}

/**
 * Implements hook_page_attachments().
 */
function google_fonts_api_page_attachments(&$page) {
  $enabled_fonts =& drupal_static('fontyourface_fonts', []);
  $fonts = [];
  foreach ($enabled_fonts as $font) {
    if ($font->pid->value == 'google_fonts_api') {
      $fonts[] = $font;
    }
  }
  $url = google_fonts_api_generate_font_family_css($fonts);
  if (!empty($url)) {
    $page['#attached']['html_head'][] = [
      [
        '#type' => 'html_tag',
        '#tag' => 'link',
        '#attributes' => [
          'rel' => 'stylesheet',
          'href' => $url,
          'media' => 'all',
        ],
      ],
      'fontyourface-google-fonts-api',
    ];
  }
}

/**
 * Generates font family css for multiple fonts.
 *
 * @param array $fonts
 *   Array of FontInterface objects.
 *
 * @return string
 *   URL to load fonts on page.
 */
function google_fonts_api_generate_font_family_css(array $fonts) {
  $url = '';
  $paths = [];
  foreach ($fonts as $font) {
    if ($font->pid->value == 'google_fonts_api') {
      $metadata = $font
        ->getMetadata();
      $path_parts = explode(':', $metadata['path']);
      $all_subsets[$metadata['subset']] = $metadata['subset'];
      if (!isset($paths[$path_parts[0]])) {
        $paths[$path_parts[0]] = [];
      }
      if (count($path_parts) > 1) {
        $paths[$path_parts[0]][$path_parts[1]] = $path_parts[1];
      }
      else {
        $paths[$path_parts[0]]['regular'] = 'regular';
      }
    }
  }
  if (count($paths) > 0) {
    $families = [];
    foreach ($paths as $family => $variants) {
      $families[$family] = urlencode($family) . ':' . implode(',', $variants);
    }
    $base = 'https://fonts.googleapis.com/css?family=';
    $url = $base . implode('|', $families) . '&subset=' . implode(',', $all_subsets);
  }
  return $url;
}

/**
 * Implements hook_fontyourface_import().
 */
function google_fonts_api_fontyourface_import($font_context = []) {
  $context = $font_context;
  if (empty($context['sandbox'])) {
    $context['sandbox']['fonts'] = _google_fonts_api_get_fonts_from_api();
    $context['sandbox']['progress'] = 0;
    $all = _google_fonts_api_convert_api_results($context['sandbox']['fonts']);
    $context['sandbox']['max'] = count($all);
  }
  $fonts = _google_fonts_api_convert_api_results($context['sandbox']['fonts']);
  $index = $context['sandbox']['progress'];
  $font = $fonts[$index];
  if (!empty($font)) {
    if (!isset($font->tags)) {
      $font->tags = [];
    }
    fontyourface_save_font($font);
    $context['message'] = "Imported {$context['sandbox']['progress']} of {$context['sandbox']['max']}";
    $context['sandbox']['progress']++;
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
  }
  else {
    Drupal::messenger()
      ->addMessage(t('Imported @count fonts from Google Fonts', [
      '@count' => $context['sandbox']['progress'],
    ]));
  }
  return $context;
}

/**
 * Retrieves fonts from api and parses them for consumption.
 *
 * @param string $temp_key
 *   An API key to use for testing.
 *
 * @return array
 *   List of fonts ready for ingesting as FontInterface objects.
 */
function _google_fonts_api_get_fonts_from_api($temp_key = '') {

  // Return the JSON object with all available fonts.
  $google_api_key = $temp_key ?: \Drupal::config('google_fonts_api.settings')
    ->get('google_api_key');
  try {
    $uri = 'https://www.googleapis.com/webfonts/v1/webfonts?key=' . $google_api_key;
    $response = \Drupal::httpClient()
      ->get($uri, [
      'headers' => [
        'Accept' => 'text/plain',
      ],
      'verify' => FALSE,
    ]);
    if ($response
      ->getStatusCode() == 200) {
      $data = (string) $response
        ->getBody();
      $json_results = json_decode($data);
      return $json_results->items;
    }
    else {

      // Connection was successful but Google responded with an error code.
      throw new \Exception();
    }
  } catch (Exception $e) {
    Drupal::messenger()
      ->addMessage(t('The list of Google Fonts could not be fetched. Verify that your server can connect to the Google servers (https://www.googleapis.com). Error: %error', [
      '%error' => $e
        ->getMessage(),
    ]), 'error');
    return FALSE;
  }
}

/**
 * Converts the Google Fonts API JSON results to a generic Fonts object array.
 *
 * @param array $json_font_list
 *   Array of Google Font objects.
 *
 * @return array
 *   Array of objects compatible with Fontyourface interface.
 */
function _google_fonts_api_convert_api_results(array $json_font_list) {
  $fonts = [];
  foreach ($json_font_list as $json_font) {
    foreach ($json_font->variants as $json_font_variant) {
      foreach ($json_font->subsets as $json_font_subset) {
        $font_id = $json_font->family . ' ' . $json_font_variant . ' (' . $json_font_subset . ')';
        switch ($json_font_variant) {
          case 'regular':
            $css_style = 'normal';
            $css_weight = 'normal';
            break;
          case 'italic':
            $css_style = 'italic';
            $css_weight = 'normal';
            break;
          case 'bold':
            $css_style = 'normal';
            $css_weight = 'bold';
            break;
          case 'bolditalic':
            $css_style = 'italic';
            $css_weight = 'bold';
            break;
          default:

            // For all other cases (eg 400 or 400italic).
            if (is_numeric($json_font_variant)) {

              // Variant is a number, like 400.
              $css_style = 'normal';
              $css_weight = $json_font_variant;
            }
            elseif (is_numeric(substr($json_font_variant, 0, 3))) {

              // Variant is a combined string of number and string, like
              // 400italic.
              // The numeric part is always three characters long, so we can
              // split it easily.
              $css_style = substr($json_font_variant, 3);
              $css_weight = substr($json_font_variant, 0, 3);
            }
        }
        $font = new stdClass();
        $font->name = $font_id;
        $font->url = 'https://www.google.com/webfonts/family?family=' . $json_font->family . '&subset=' . $json_font_subset . '#' . $json_font_variant;
        $font->provider = 'google_fonts_api';
        $font->css_family = $json_font->family;
        $font->css_style = $css_style;
        $font->css_weight = $css_weight;
        $font->designer = '';
        $font->designer_url = '';
        $font->foundry = '';
        $font->foundry_url = '';
        $font->license = '';
        $font->license_url = '';
        $font->classification = [
          $json_font->category,
        ];
        $font->language = [
          $json_font_subset,
        ];
        $font->metadata = [
          'path' => $json_font->family . ':' . $json_font_variant,
          'subset' => $json_font_subset,
        ];
        $fonts[] = $font;
      }
    }
  }
  return $fonts;
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function google_fonts_api_form_font_settings_alter(&$form, FormStateInterface $form_state) {
  $config = \Drupal::config('google_fonts_api.settings');
  $form['google_fonts_api'] = [
    '#type' => 'fieldset',
    '#title' => t('Google Fonts Settings'),
  ];
  $form['google_fonts_api']['google_api_key'] = [
    '#type' => 'textfield',
    '#title' => t('Google API Key'),
    '#description' => t('Add your Google API key to import fonts. Available at <a target="_blank" href=":url">:url</a>.', [
      ':url' => 'https://developers.google.com/fonts/docs/developer_api#APIKey',
    ]),
    '#default_value' => $config
      ->get('google_api_key'),
  ];
  $form['imports']['import_google_fonts_api']['#disabled'] = !(bool) $config
    ->get('google_api_key');
  $form['#validate'][] = 'google_fonts_api_form_font_settings_validate';
  $form['#submit'][] = 'google_fonts_api_form_font_settings_submit';
}

/**
 * Form validation handler for Google Font settings.
 */
function google_fonts_api_form_font_settings_validate(&$form, FormStateInterface $form_state) {
  $google_api_key = trim($form_state
    ->getValue('google_api_key'));
  if ($google_api_key) {
    $connection_works = _google_fonts_api_get_fonts_from_api($google_api_key);
    if (!$connection_works) {

      // The _google_fonts_api_get_fonts_from_api() will output a more
      // thorough error message.
      $form_state
        ->setError($form['google_fonts_api']['google_api_key'], '');
    }
  }
}

/**
 * Form submit handler for Google Font settings.
 */
function google_fonts_api_form_font_settings_submit(&$form, FormStateInterface $form_state) {
  $values = $form_state
    ->getValues();
  $config = \Drupal::configFactory()
    ->getEditable('google_fonts_api.settings');
  $config
    ->set('google_api_key', $values['google_api_key'])
    ->save();
}

Functions

Namesort descending Description
google_fonts_api_fontyourface_api Implements hook_fontyourface_api().
google_fonts_api_fontyourface_import Implements hook_fontyourface_import().
google_fonts_api_form_font_settings_alter Implements hook_form_FORM_ID_alter().
google_fonts_api_form_font_settings_submit Form submit handler for Google Font settings.
google_fonts_api_form_font_settings_validate Form validation handler for Google Font settings.
google_fonts_api_generate_font_family_css Generates font family css for multiple fonts.
google_fonts_api_modules_installed Implements hook_modules_installed().
google_fonts_api_page_attachments Implements hook_page_attachments().
_google_fonts_api_convert_api_results Converts the Google Fonts API JSON results to a generic Fonts object array.
_google_fonts_api_get_fonts_from_api Retrieves fonts from api and parses them for consumption.