fb_instant_articles_display.module in Facebook Instant Articles 7.2
Same filename and directory in other branches
Hook implementations for Facebook Instant Articles Display module.
File
modules/fb_instant_articles_display/fb_instant_articles_display.moduleView source
<?php
/**
* @file
* Hook implementations for Facebook Instant Articles Display module.
*/
/**
* Load all Field module hooks for Facebook Instant Articles Display module.
*/
require_once __DIR__ . '/includes/field.inc';
/**
* Implements hook_entity_load().
*/
function fb_instant_articles_display_entity_load($entities, $type) {
$enabled_entity_types = fb_instant_articles_display_get_article_entity_types();
foreach ($entities as $entity) {
// Only proceed if the entity is of the configured entity type and bundle.
list($id, $vid, $bundle) = entity_extract_ids($type, $entity);
if (!in_array($type, array_keys($enabled_entity_types)) || !in_array($bundle, array_keys($enabled_entity_types[$type]))) {
return FALSE;
}
// We add Entity-specific information when constructing the ArticleWrapper
// object, so that other modules can make use of this when implementing
// hook_fb_instant_articles_article_alter(). We then attach the
// InstantArticle object directly onto the Entity so that it will be
// available during hook_field_formatter_view() for mapping field data onto
// the InstantArticle object.
$context = array(
'entity_type' => $type,
'entity' => $entity,
);
$entity->fb_instant_article = \Drupal\fb_instant_articles\ArticleWrapper::create($context)
->getArticle();
}
}
/**
* Implements hook_fb_instant_articles_article_alter().
*
* @see fb_instant_articles_display_module_implements_alter()
*/
function fb_instant_articles_display_fb_instant_articles_article_alter($instantArticle, $context) {
if (!isset($context['entity_type']) || !isset($context['entity'])) {
return FALSE;
}
// We map the Entity properties here, so we can ensure it runs only once per
// Entity (during load). If other modules wish to alter this, they should
// implement hook_fb_instant_articles_article_alter().
\Drupal\fb_instant_articles_display\EntityPropertyMapper::create($context['entity_type'], $context['entity'], $instantArticle)
->map();
}
/**
* Implements hook_module_implements_alter().
*
* @see fb_instant_articles_display_declare_entity_preprocess_hooks()
*/
function fb_instant_articles_display_module_implements_alter(&$implementations, $hook) {
// Ensure hook_fb_instant_articles_article_alter() runs first, so that other
// modules can override mappings made by this module by implementing
// hook_fb_instant_articles_article_alter().
if ($hook != 'fb_instant_articles_article_alter') {
return;
}
$module = 'fb_instant_articles_display';
$group = array(
$module => $implementations[$module],
);
unset($implementations[$module]);
$implementations = $group + $implementations;
}
/**
* Implements hook_preprocess().
*
* Add template suggestions for an entity based on view modes if they do not
* already exist.
*/
function fb_instant_articles_display_preprocess(&$variables, $hook) {
$entities = array_keys(entity_get_info());
if (isset($variables['elements']['#entity_type']) && in_array($variables['elements']['#entity_type'], $entities, TRUE)) {
// Sometimes a rendered entity is passed into another theme function, in
// which case do not process. Also account that #theme may be a hook
// suggestion itself. For example. #theme = 'comment__node_type' and
// $hook = 'comment'.
$theme_keys = is_string($variables['elements']['#theme']) ? array(
$variables['elements']['#theme'],
) : $variables['elements']['#theme'];
foreach ($theme_keys as $theme) {
if ($theme != $hook && strpos($theme, $hook . '__') !== 0) {
return;
}
}
if (isset($variables['view_mode']) && $variables['view_mode'] === 'fb_instant_article') {
$suggestions =& $variables['theme_hook_suggestions'];
array_push($suggestions, 'entity__fb_instant_article');
}
}
}
/**
* Implements hook_theme().
*
* @see fb_instant_articles_display_declare_entity_preprocess_hooks()
* @see theme_entity__fb_instant_article()
*/
function fb_instant_articles_display_theme() {
$theme_path = drupal_get_path('module', 'fb_instant_articles_display') . '/theme';
return array(
'entity__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 Entity view mode.
*
* @see fb_instant_articles_display_preprocess_entity()
*
* @ingroup themeable
*/
function theme_entity__fb_instant_article($variables) {
if (!isset($variables['fb_instant_article'])) {
return FALSE;
}
return $variables['fb_instant_article']
->render('<!doctype html>', TRUE);
}
/**
* 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_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().
*
* @see fb_instant_articles_display_node_type_form_submit()
*
* @todo Decouple from alter hook to more easily support other entity types.
*/
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.
*
* @see fb_instant_articles_display_form_node_type_form_alter()
*/
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);
// Clear entity info cache, since this setting influences it. Also clear the
// menu cache.
entity_info_cache_clear();
}
/**
* 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_types = fb_instant_articles_display_get_article_entity_types();
foreach (array_keys($entity_types) as $entity_type) {
$entity_info[$entity_type]['view modes']['fb_instant_article'] = array(
'label' => t('Facebook Instant Articles'),
'custom settings' => TRUE,
);
}
}
/**
* 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.
*
* @param string $entity_type
* @param string $bundle_name
*
* @return stdClass
*
* @todo Add update hook to change export ID, and note this in the API
* changelog.
*/
function fb_instant_articles_display_get_layout_settings($entity_type, $bundle_name) {
ctools_include('export');
$export_id = $entity_type . '|' . $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;
}
/**
* 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]);
}
}
}
}
}