You are here

fb_instant_articles_display.module in Facebook Instant Articles 7

Hook implementations for Facebook Instant Articles Display module.

File

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

/**
 * @file
 * Hook implementations for Facebook Instant Articles Display module.
 */

/**
 * Implements hook_permission().
 */
function fb_instant_articles_display_permission() {
  $permissions = array();
  $permissions['administer fb_instant_articles_display'] = array(
    'title' => t('Administer Facebook Instant Articles Display'),
  );
  return $permissions;
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function fb_instant_articles_display_form_node_type_form_alter(&$form, &$form_state) {

  // Add a vertical tab to the node type form.
  if (user_access('administer fb_instant_articles_display')) {

    // Build fieldset for vertical tab section.
    $fieldset = array(
      '#type' => 'fieldset',
      '#title' => t('Facebook Instant Articles'),
      '#description' => t('Configure content type for Facebook Instant Article mappings.'),
      '#group' => 'additional_settings',
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
    );

    // Has the section already been created (perhaps by a sub module)?
    if (isset($form['fb_instant_articles_display'])) {

      // Add additional fieldset data.
      $form['fb_instant_articles_display'] += $fieldset;
    }
    else {
      $form['fb_instant_articles_display'] = $fieldset;
    }

    // Is an Article type?
    $type = $form['#node_type']->type;
    $fb_instant_enabled = fb_instant_articles_display_is_article_type('node', $type);
    $previously_checked = isset($form_state['values']) && $form_state['values']['fb_instant_articles_display']['fb_instant_enabled'];

    // Build the product checkbox.
    $form['fb_instant_articles_display']['fb_instant_enabled'] = array(
      '#type' => 'checkbox',
      '#title' => t('Include Content Type in Facebook Instant Articles feed.'),
      '#description' => t('Enable content of this type to be included in the Facebook Instant Articles feed.'),
      '#weight' => 0,
      '#default_value' => $previously_checked || $fb_instant_enabled ? TRUE : FALSE,
    );

    // Add custom submit.
    $form['#submit'][] = 'fb_instant_articles_display_node_type_form_submit';
  }
}

/**
 * Submit callback for node type form.
 */
function fb_instant_articles_display_node_type_form_submit($form, &$form_state) {
  $fb_instant_enabled = fb_instant_articles_display_is_article_type('node', $form['#node_type']->type);
  if (!$fb_instant_enabled && $form_state['values']['fb_instant_enabled']) {

    // Save the new article type.
    fb_instant_articles_display_set_entity_type('node', $form['#node_type']->type);
    ctools_include('export');
    ctools_export_crud_enable('fb_instant_articles_display_layout_settings', 'node|article|fb_instant_article');
  }
  elseif (!$form_state['values']['fb_instant_enabled']) {
    fb_instant_articles_display_delete_entity_type('node', $form['#node_type']->type);
  }
}

/**
 * Checks if an entity type and bundle are a Facebook Instant Article type.
 *
 * @param string $entity_type
 *   The entity type name.
 * @param string $bundle
 *   The entity bundle name.
 *
 * @return bool
 *   Boolean TRUE or FALSE.
 */
function fb_instant_articles_display_is_article_type($entity_type, $bundle) {
  $is_type = FALSE;
  if ($types = fb_instant_articles_display_get_article_entity_types()) {

    // See if this entity type and bundle exists.
    if (isset($types[$entity_type]) && isset($types[$entity_type][$bundle])) {
      $is_type = TRUE;
    }
  }

  // Allow other modules to alter.
  drupal_alter('fb_instant_articles_display_is_article_type', $is_type, $entity_type, $bundle);
  return $is_type;
}

/**
 * Gets entity types that are treated as Facebook Instant Articles.
 *
 * @return mixed
 *   Array of entity types and bundles.
 */
function fb_instant_articles_display_get_article_entity_types() {
  ctools_include('export');
  $fia_entity_types = ctools_export_crud_load_all('fb_instant_articles_display_entity_types');
  $entity_types = array();
  foreach ($fia_entity_types as $fia_entity_type) {
    $entity_types[$fia_entity_type->entity_type][$fia_entity_type->entity_bundle] = array(
      'type' => $fia_entity_type->entity_type,
      'bundle' => $fia_entity_type->entity_bundle,
    );
  }

  // Allow other modules to alter.
  drupal_alter('fb_instant_articles_display_entity_types', $entity_types);
  return $entity_types;
}

/**
 * Sets the entity type as an allowable Facebook Instant Article type.
 *
 * @param string $type
 *   The entity type.
 * @param string $bundle
 *   The entity bundle.
 */
function fb_instant_articles_display_set_entity_type($type, $bundle) {
  db_insert('fb_instant_articles_display_entity_types')
    ->fields(array(
    'id' => $type . '|' . $bundle,
    'entity_type' => $type,
    'entity_bundle' => $bundle,
  ))
    ->execute();

  // Allow other modules to perform actions.
  module_invoke_all('fb_instant_articles_display_set_type', $type, $bundle);
}

/**
 * Deletes the entity type as an allowable Facebook Instant Article type.
 *
 * @param string $type
 *   The entity type.
 * @param string $bundle
 *   The entity bundle.
 */
function fb_instant_articles_display_delete_entity_type($type, $bundle) {
  db_delete('fb_instant_articles_display_entity_types')
    ->condition('entity_type', $type)
    ->condition('entity_bundle', $bundle)
    ->execute();

  // Allow other modules to perform actions.
  module_invoke_all('fb_instant_articles_display_delete_type', $type, $bundle);
}

/**
 * Implements hook_entity_info_alter().
 */
function fb_instant_articles_display_entity_info_alter(&$entity_info) {
  $entity_info['node']['view modes']['fb_instant_article'] = array(
    'label' => t('Facebook Instant Articles'),
    'custom settings' => TRUE,
  );
}

/**
 * Implements hook_node_load().
 */
function fb_instant_articles_display_node_load($nodes, $types) {
  if ($enabled_entity_types = fb_instant_articles_display_get_article_entity_types()) {
    $enabled_bundles = array_keys($enabled_entity_types['node']);
    if (!empty($enabled_bundles) && count(array_intersect($enabled_bundles, $types))) {
      foreach ($nodes as $node) {
        $layout_settings = fb_instant_articles_display_get_node_layout_settings($node->type);
        $wrapper = \Drupal\fb_instant_articles_display\DrupalInstantArticleDisplay::create($node, $layout_settings);

        // Store the InstantArticle wrapper object on the node entity to allow
        // field formatters and others to make changes/additions to it until it's
        // finally rendered out in hook_preprocess_node().
        $node->fb_instant_articles_display_wrapper = $wrapper;
      }
    }
  }
}

/**
 * Implements hook_preprocess_node().
 */
function fb_instant_articles_display_preprocess_node(&$vars) {
  if ($vars['view_mode'] === 'fb_instant_article') {
    $vars['theme_hook_suggestions'][] = 'node__fb_instant_article';
  }
}

/**
 * Implements hook_preprocess_HOOK().
 */
function fb_instant_articles_display_preprocess_field(&$vars) {
  $element = $vars['element'];
  if ($element['#view_mode'] == 'fb_instant_article') {
    $vars['theme_hook_suggestions'][] = 'field__fb_instant_article';
  }
}

/**
 * Implements hook_theme().
 */
function fb_instant_articles_display_theme() {
  $theme_path = drupal_get_path('module', 'fb_instant_articles_display') . '/theme';
  return array(
    'node__fb_instant_article' => array(
      'variables' => array(),
    ),
    'field__fb_instant_article' => array(
      'template' => 'field--fb-instant-article',
      'path' => $theme_path,
      'render element' => 'element',
    ),
  );
}

/**
 * Theme function for the fb_instant_article node view mode.
 */
function theme_node__fb_instant_article($vars) {
  $node = $vars['node'];
  if (isset($node->fb_instant_articles_display_wrapper)) {

    /** @var \Drupal\fb_instant_articles_display\DrupalInstantArticleDisplay $wrapper */
    $wrapper = $node->fb_instant_articles_display_wrapper;
    return $wrapper
      ->getArticle()
      ->render();
  }
}

/**
 * Implements hook_form_alter().
 */
function fb_instant_articles_display_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'field_ui_display_overview_form') {
    if ($form['#view_mode'] == 'fb_instant_article') {
      form_load_include($form_state, 'inc', 'fb_instant_articles_display', 'includes/view_mode_layout');
      fb_instant_articles_display_layout_form($form, $form_state);
    }
    else {
      fb_instant_articles_display_cleanup_view_mode_formatters($form);
    }
  }
}

/**
 * Get the layout settings for a specific bundle.
 */
function fb_instant_articles_display_get_node_layout_settings($bundle_name) {
  ctools_include('export');
  $export_id = 'node|' . $bundle_name . '|fb_instant_article';
  $layout_settings = ctools_export_crud_load_all('fb_instant_articles_display_layout_settings');
  $layout = new stdClass();
  if (isset($layout_settings[$export_id])) {
    $layout = $layout_settings[$export_id];
  }
  return $layout;
}

/**
 * Implements hook_field_formatter_info().
 */
function fb_instant_articles_display_field_formatter_info() {
  $formats = array();

  // Header only elements
  $formats['fbia_subtitle_formatter'] = array(
    'label' => t('FBIA Subtitle'),
    'field types' => array(
      'text',
      'text_long',
      'text_with_summary',
    ),
  );
  $formats['fbia_kicker_formatter'] = array(
    'label' => t('FBIA Kicker'),
    'field types' => array(
      'text',
      'text_long',
      'text_with_summary',
    ),
  );
  $formats['fbia_blockquote_formatter'] = array(
    'label' => t('FBIA Blockquote'),
    'field types' => array(
      'text',
      'text_long',
      'text_with_summary',
    ),
  );
  $formats['fbia_pullquote_formatter'] = array(
    'label' => t('FBIA Pullquote'),
    'field types' => array(
      'text',
      'text_long',
      'text_with_summary',
    ),
  );
  $formats['fbia_social_formatter'] = array(
    'label' => t('FBIA Social Embed'),
    'field types' => array(
      'text',
      'text_long',
      'text_with_summary',
    ),
  );
  $formats['fbia_credits_formatter'] = array(
    'label' => t('FBIA Credits'),
    'field types' => array(
      'text',
      'text_long',
      'text_with_summary',
    ),
  );
  $formats['fbia_copyright_formatter'] = array(
    'label' => t('FBIA Copyright'),
    'field types' => array(
      'text',
      'text_long',
      'text_with_summary',
    ),
  );
  $formats['fbia_author_formatter'] = array(
    'label' => t('FBIA Author'),
    'field types' => array(
      'text',
      'text_with_summary',
      'list_text',
    ),
  );
  $formats['fbia_video_formatter'] = array(
    'label' => t('FBIA Video'),
    'field types' => array(
      'file',
    ),
  );
  $formats['fbia_ad_formatter'] = array(
    'label' => t('FBIA Ad'),
    'field types' => array(
      'text',
      'text_long',
      'text_with_summary',
    ),
    'settings' => array(
      'height' => '50',
      'width' => '320',
      'source' => 'url',
    ),
  );
  $formats['fbia_analytics_formatter'] = array(
    'label' => t('FBIA Analytics'),
    'field types' => array(
      'text',
      'text_long',
      'text_with_summary',
    ),
    'settings' => array(
      'source' => 'url',
    ),
  );
  $formats['fbia_image_formatter'] = array(
    'label' => t('FBIA Image'),
    'field types' => array(
      'image',
    ),
    'settings' => array(
      'style' => 'medium',
      'caption' => '',
      'likes' => '',
      'comments' => '',
      'fullscreen' => '',
    ),
  );
  $formats['fbia_interactive_formatter'] = array(
    'label' => t('FBIA Interactive'),
    'field types' => array(
      'text',
      'text_with_summary',
    ),
    'settings' => array(
      'height' => '50',
      'width' => 'no-margin',
    ),
  );
  $formats['fbia_list_formatter'] = array(
    'label' => t('FBIA List'),
    'field types' => array(
      'list_text',
      'list_integer',
      'list_float',
    ),
    'settings' => array(
      'list_type' => 'ol',
    ),
  );
  $formats['fbia_transformer_formatter'] = array(
    'label' => t('FBIA Transfomer'),
    'field types' => array(
      'text',
      'text_long',
      'text_with_summary',
    ),
  );
  return $formats;
}

/**
 * Implements hook_field_formatter_settings_form().
 */
function fb_instant_articles_display_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
  $display = $instance['display'][$view_mode];
  $settings = $display['settings'];
  $element = array();
  switch ($display['type']) {
    case 'fbia_ad_formatter':
      $element['source'] = array(
        '#type' => 'select',
        '#title' => t('Source'),
        '#description' => t('Add your ad specifying the URL or embed the full unescaped HTML.'),
        '#default_value' => $settings['source'],
        '#options' => array(
          'url' => t('Ad URL'),
          'embed' => t('Embedded HTML'),
        ),
      );
      $element['height'] = array(
        '#type' => 'textfield',
        '#title' => t('Height'),
        '#description' => t('Height of the iframe element.'),
        '#default_value' => $settings['height'],
      );
      $element['width'] = array(
        '#type' => 'textfield',
        '#title' => t('Width'),
        '#description' => t('Width of the iframe element.'),
        '#default_value' => $settings['width'],
      );
      break;
    case 'fbia_interactive_formatter':
      $element['height'] = array(
        '#type' => 'textfield',
        '#title' => t('Height'),
        '#description' => t('The height of your interactive graphic.'),
        '#default_value' => $settings['height'],
      );
      $element['width'] = array(
        '#type' => 'select',
        '#title' => t('Width'),
        '#description' => t('The width of your interactive graphic.'),
        '#default_value' => $settings['width'],
        '#options' => array(
          'no-margin' => t('no-margin'),
          'column-width' => t('column-width'),
        ),
      );
      break;
    case 'fbia_list_formatter':
      $element['list_type'] = array(
        '#type' => 'select',
        '#title' => t('List Type'),
        '#description' => t('Choose list type.'),
        '#default_value' => $settings['list_type'],
        '#options' => array(
          'ol' => t('Ordered'),
          'ul' => t('Unordered'),
        ),
      );
      break;
    case 'fbia_image_formatter':
      $image_styles = image_style_options(FALSE, PASS_THROUGH);
      $element['style'] = array(
        '#title' => t('Image style'),
        '#type' => 'select',
        '#default_value' => $settings['style'],
        '#empty_option' => t('None (original image)'),
        '#options' => $image_styles,
      );
      $element['caption'] = array(
        '#type' => 'checkbox',
        '#description' => t('The caption uses the alt text of the image field.'),
        '#title' => t('Enable caption.'),
        '#default_value' => $settings['caption'],
      );
      $element['likes'] = array(
        '#type' => 'checkbox',
        '#title' => t('Enable Facebook Likes. (data-feedback)'),
        '#default_value' => $settings['likes'],
      );
      $element['comments'] = array(
        '#type' => 'checkbox',
        '#title' => t('Enable Facebook Comments. (data-feedback)'),
        '#default_value' => $settings['comments'],
      );
      $element['fullscreen'] = array(
        '#type' => 'checkbox',
        '#title' => t('Enable Fullscreen.'),
        '#default_value' => $settings['fullscreen'],
      );
      break;
    case 'fbia_analytics_formatter':
      $element['source'] = array(
        '#type' => 'select',
        '#title' => t('Source'),
        '#description' => t('Add your tracker specifying the URL or embed the full unescaped HTML.'),
        '#default_value' => $settings['source'],
        '#options' => array(
          'url' => t('Ad URL'),
          'embed' => t('Embedded HTML'),
        ),
      );
      break;
  }
  return $element;
}

/**
 * Implements hook_field_formatter_settings_summary().
 */
function fb_instant_articles_display_field_formatter_settings_summary($field, $instance, $view_mode) {
  $display = $instance['display'][$view_mode];
  $settings = $display['settings'];
  $summary = '';
  switch ($display['type']) {
    case 'fbia_ad_formatter':
      $summary = t('Ad field - set the Source, iFrame height (@height) and width (@width).', array(
        '@height' => $settings['height'],
        '@width' => $settings['width'],
      ));
      break;
    case 'fbia_interactive_formatter':
      $summary = t('Interactive field - set iFrame height (@height) and width (@width).', array(
        '@height' => $settings['height'],
        '@width' => $settings['width'],
      ));
      break;
    case 'fbia_analytics_formatter':
      $summary = t('Analytics field - set the Source of the iframe. (@source)', array(
        '@source' => $settings['source'],
      ));
      break;
    case 'fbia_image_formatter':
      $image_styles = image_style_options(FALSE, PASS_THROUGH);

      // Unset possible 'No defined styles' option.
      unset($image_styles['']);

      // Styles could be lost because of enabled/disabled modules that defines
      // their styles in code.
      if (isset($image_styles[$settings['style']])) {
        $summary = t('Image style: @style', array(
          '@style' => $image_styles[$settings['style']],
        ));
      }
      else {
        $summary = t('Original image');
      }
      break;
    case 'fbia_list_formatter':
      $summary = t('List field - Type:(@list_type)', array(
        '@list_type' => $settings['list_type'],
      ));
      break;
  }
  return $summary;
}

/**
 * Implements hook_field_formatter_view().
 */
function fb_instant_articles_display_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {

  // Grab the InstantArticle object we're going to be building up.  If it's not
  // present, it means that a site admin selected an FB IA field formatter for
  // a non-FB IA content type.
  if (isset($entity->fb_instant_articles_display_wrapper)) {

    /** @var \Drupal\fb_instant_articles_display\DrupalInstantArticleDisplay $wrapper */
    $wrapper = $entity->fb_instant_articles_display_wrapper;
    $wrapper
      ->fieldFormatterView($field, $instance, $langcode, $items, $display);
  }
}

/**
 * Remove formatters from view modes which are not Facebook Instant Articles.
 */
function fb_instant_articles_display_cleanup_view_mode_formatters(&$form) {
  foreach ($form['fields'] as $field_key => $field) {
    if (strpos($field_key, '#') === FALSE) {
      foreach ($field['format']['type']['#options'] as $format_key => $format) {
        if (strpos($format_key, 'fbia') !== FALSE) {
          unset($form['fields'][$field_key]['format']['type']['#options'][$format_key]);
        }
      }
    }
  }
}

/**
 * Format time elements.
 */
function fb_instant_articles_display_time_element($timestamp, $class) {
  $class = ' class="' . $class . '"';
  $date = new \DateTime("@{$timestamp}");
  $datetime = ' datetime="' . $date
    ->format(\DateTime::ATOM) . '"';
  $text_time = $date
    ->format('F jS, g:i A');
  $element = '<time' . $class . $datetime . '>' . $text_time . '</time>';
  return $element;
}

Functions

Namesort descending Description
fb_instant_articles_display_cleanup_view_mode_formatters Remove formatters from view modes which are not Facebook Instant Articles.
fb_instant_articles_display_delete_entity_type Deletes the entity type as an allowable Facebook Instant Article type.
fb_instant_articles_display_entity_info_alter Implements hook_entity_info_alter().
fb_instant_articles_display_field_formatter_info Implements hook_field_formatter_info().
fb_instant_articles_display_field_formatter_settings_form Implements hook_field_formatter_settings_form().
fb_instant_articles_display_field_formatter_settings_summary Implements hook_field_formatter_settings_summary().
fb_instant_articles_display_field_formatter_view Implements hook_field_formatter_view().
fb_instant_articles_display_form_alter Implements hook_form_alter().
fb_instant_articles_display_form_node_type_form_alter Implements hook_form_FORM_ID_alter().
fb_instant_articles_display_get_article_entity_types Gets entity types that are treated as Facebook Instant Articles.
fb_instant_articles_display_get_node_layout_settings Get the layout settings for a specific bundle.
fb_instant_articles_display_is_article_type Checks if an entity type and bundle are a Facebook Instant Article type.
fb_instant_articles_display_node_load Implements hook_node_load().
fb_instant_articles_display_node_type_form_submit Submit callback for node type form.
fb_instant_articles_display_permission Implements hook_permission().
fb_instant_articles_display_preprocess_field Implements hook_preprocess_HOOK().
fb_instant_articles_display_preprocess_node Implements hook_preprocess_node().
fb_instant_articles_display_set_entity_type Sets the entity type as an allowable Facebook Instant Article type.
fb_instant_articles_display_theme Implements hook_theme().
fb_instant_articles_display_time_element Format time elements.
theme_node__fb_instant_article Theme function for the fb_instant_article node view mode.