easy_social-8.x-3.x-dev/easy_social.module
easy_social.module
<?php
/**
* @file
* Easy Social module.
*/
use Drupal\Core\Cache\Cache;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Url;
use Drupal\easy_social\EasySocialException;
/**
* Return the available widgets.
*
* @return array
* An array of widget names, keyed by their machine_name.
*/
function easy_social_get_widgets() {
// Use the advanced drupal_static() pattern.
static $drupal_static_fast;
if (!isset($drupal_static_fast)) {
$drupal_static_fast['widgets'] = &drupal_static(__FUNCTION__);
}
$widgets = &$drupal_static_fast['widgets'];
if (!isset($widgets)) {
// Allow modules to define widgets.
$widgets = \Drupal::moduleHandler()->invokeAll('easy_social_widget');
// Allow modules to alter the defined widgets.
\Drupal::moduleHandler()->alter('easy_social_widget', $widgets);
}
return $widgets;
}
/**
* Implements hook_easy_social_widget().
*
* Define default Easy Social widgets.
*/
function easy_social_easy_social_widget() {
$widgets = [];
// Twitter.
$widgets['twitter'] = [
'name' => t('Twitter'),
'js' => 'easy_social/twitter',
];
// Facebook.
$widgets['facebook'] = [
'name' => t('Facebook'),
'js' => 'easy_social/facebook',
];
// LinkedIn,
$widgets['linkedin'] = [
'name' => t('LinkedIn'),
'js' => 'easy_social/linkedin',
// This widget has some specific requirements when dealing with multiple
// languages so we handle the js in it's pre-process callback instead.
];
// Pinterest.
$widgets['pinterest'] = [
'name' => t('Pinterest'),
'js' => 'easy_social/pinterest',
];
// Email; no extra libraries are required.
$widgets['email'] = [
'name' => t('Email'),
];
return $widgets;
}
/**
* Implements hook_theme().
*/
function easy_social_theme($existing, $type, $theme, $path) {
return [
'easy_social' => [
'variables' => [],
'file' => 'easy_social.theme.inc',
],
'easy_social_twitter' => [
'variables' => [],
'file' => 'easy_social.theme.inc',
],
'easy_social_facebook' => [
'variables' => [],
'file' => 'easy_social.theme.inc',
],
'easy_social_linkedin' => [
'variables' => [],
'file' => 'easy_social.theme.inc',
],
'easy_social_pinterest' => [
'variables' => [],
],
'easy_social_email' => [
'variables' => [],
'file' => 'easy_social.theme.inc',
],
];
}
/**
* Implements hook_preprocess_HOOK() for block.html.twig.
*/
function easy_social_preprocess_block(&$variables) {
// Derive the base plugin ID.
[$plugin_id] = explode(':', $variables['plugin_id'] . ':');
switch ($plugin_id) {
case 'easy_social_block':
$variables['attributes']['role'] = 'complementary';
break;
}
}
/**
* Implements hook_preprocess_HOOK() for easy_social theme.
*
* @see easy_social_theme()
* @see theme_easy_social()
*/
function easy_social_preprocess_easy_social(&$variables) {
$config = Drupal::config('easy_social.settings');
// Load widget definitions.
$definitions = easy_social_get_widgets();
// Add the CSS
$variables['#attached']['library'][] = 'easy_social/easysocial-css';
// Filter active widgets.
$settings_widgets = $config->get('global.widgets');
$settings_widgets = array_filter($settings_widgets);
$widgets = [];
foreach ($settings_widgets as $widget) {
if (!array_key_exists($widget, $definitions)) {
throw new EasySocialException(t('No definition found for the widget: @name', ['@name' => $widget]));
}
// Handle css includes.
$attached = [];
if (array_key_exists('css', $definitions[$widget])) {
$attached['library'][] = $definitions[$widget]['css'];
}
// Determine how to handle js.
if (array_key_exists('js', $definitions[$widget])) {
$attached['library'][] = $definitions[$widget]['js'];
}
$widgets[$widget] = [
'#theme' => "easy_social_{$widget}",
// @todo pass in some kind of context?
// @todo #weight ?,
'#attached' => $attached,
];
}
$variables['widgets'] = $widgets;
}
/**
* Implements hook_preprocess_HOOK() for easy_social_facebook theme.
*
* @see easy_social_theme()
* @see theme_easy_social_facebook()
*/
function easy_social_preprocess_easy_social_twitter(&$variables, $hook) {
// Incidentally, the hook name is almost what we expect the config name to be.
$hook = str_replace('easy_social_', 'easy_social.', $hook);
$attributes = [
'class' => ['twitter-share-button'],
];
if ($config = \Drupal::config($hook)) {
// @todo load contextual config.
$widget_params = $config->get();
if (!empty($widget_params['via'])) {
$attributes['data-via'] = $widget_params['via'];
}
if (!empty($widget_params['related'])) {
$attributes['data-related'] = $widget_params['related'];
}
if (isset($widget_params['size'])) {
$attributes['data-size'] = ($widget_params['size'] == 1) ? 'large' : 'medium';
}
if (!empty($widget_params['count'])) {
$attributes['data-count'] = $widget_params['count'];
}
if (!empty($widget_params['lang'])) {
$attributes['data-lang'] = $widget_params['lang'];
}
if (!empty($widget_params['hashtags'])) {
$attributes['data-hashtags'] = $widget_params['hashtags'];
}
if (isset($widget_params['dnt']) && $widget_params['dnt'] == 1) {
$attributes['data-dnt'] = 'true';
}
}
$variables['attributes'] = $attributes;
}
/**
* Implements hook_preprocess_HOOK() for easy_social_facebook theme.
*
* @see easy_social_theme()
* @see theme_easy_social_facebook()
*/
function easy_social_preprocess_easy_social_facebook(&$variables, $hook) {
// @todo implement this.
$lang = 'en_US';
// Incidentally, the hook name is almost what we expect the config name to be.
$hook = str_replace('easy_social_', 'easy_social.', $hook);
$attributes = [
'class' => ['fb-like'],
];
if ($config = \Drupal::config($hook)) {
// @todo load contextual config.
$widget_params = $config->get();
if (!empty($variables['url'])) {
$attributes['data-href'] = $variables['url'];
}
if (isset($widget_params['send']) && $widget_params['send'] == 1) {
$attributes['data-send'] = 'true';
}
if (isset($widget_params['share']) && $widget_params['share'] == 1) {
$attributes['data-share'] = 'true';
}
if (isset($widget_params['show_faces']) && $widget_params['show_faces'] == 1) {
$attributes['data-show-faces'] = 'true';
}
if (!empty($widget_params['width'])) {
$attributes['data-width'] = $widget_params['width'];
}
if (isset($widget_params['layout']) && $widget_params['layout'] !== 'standard') {
$attributes['data-layout'] = $widget_params['layout'];
}
if (!empty($widget_params['font'])) {
$attributes['data-font'] = $widget_params['font'];
}
if (isset($widget_params['colorscheme']) && $widget_params['colorscheme'] !== 'light') {
$attributes['data-colorscheme'] = $widget_params['colorscheme'];
}
if (isset($widget_params['action']) && $widget_params['action'] !== 'like') {
$attributes['data-action'] = $widget_params['action'];
}
}
$variables['attributes'] = $attributes;
}
/**
* Implements hook_preprocess_HOOK() for easy_social_linkedin theme.
*
* @see easy_social_theme()
* @see theme_easy_social_linkedin()
*/
function easy_social_preprocess_easy_social_linkedin(&$variables, $hook) {
// @todo Figure out how to pass variables to the JS using DrupalSettings
if ($variables['lang'] !== 'en') {
$script = <<<JS
window.___gcfg = {lang: '{$variables['lang']}'};
JS;
}
$hook = str_replace('easy_social_', 'easy_social.', $hook);
$attributes = [
'type' => 'IN/Share',
];
if ($config = \Drupal::config($hook)) {
// @todo load contextual config.
$widget_params = $config->get();
if (!empty($variables['url'])) {
$attributes['data-url'] = $variables['url'];
}
if (isset($widget_params['counter']) && $widget_params['counter'] !== 'none') {
$attributes['data-counter'] = $widget_params['counter'];
}
}
$variables['attributes'] = $attributes;
}
/**
* Implements hook_preprocess_HOOK() for easy_social_pinterest.
*/
function easy_social_preprocess_easy_social_pinterest(&$variables, $hook) {
// @todo Elaborate with: https://developers.pinterest.com/docs/widgets/pin-it/
$hook = str_replace('easy_social_', 'easy_social.', $hook);
if ($config = \Drupal::config($hook)) {
// @todo Load contextual config.
$widget_params = $config->get();
if (!empty($widget_params['url'])) {
$variables['image'] = $widget_params['image'];
}
if (!empty($widget_params['description'])) {
$variables['description'] = $widget_params['description'];
}
}
if (empty($variables['image'])) {
$variables['image'] = '//assets.pinterest.com/images/pidgets/pin_it_button.png';
}
}
/**
* Implements hook_preprocess_HOOK() for easy_social_email theme.
*
* @see easy_social_theme()
* @see theme_easy_social_linkedin()
*/
function easy_social_preprocess_easy_social_email(&$variables, $hook) {
$email_settings = \Drupal::config('easy_social.email');
$variables['subject_encoded'] = ($email_settings->get('subject')) ? rawurlencode($email_settings->get('subject')) : '';
// Add a new line after body so url will be placed below.
$variables['body_encoded'] = ($email_settings->get('body')) ? rawurlencode($email_settings->get('body')) . '%0D%0A' : '';
$variables['button_title'] = $email_settings->get('button_title') ?? '';
$variables['button_label'] = $email_settings->get('button_label') ?? '';
$variables['#cache']['#keys'] = (isset($variables['#cache']['#keys'])) ? Cache::mergeTags($email_settings->getCacheTags(), $variables['#cache']['#keys']) : $email_settings->getCacheTags();
}
/**
* Implements hook_theme_registry_alter().
*
* Adds our custom preprocess to all widget's theme functions.
*
* @see _easy_social_preprocess_widget()
*/
function easy_social_theme_registry_alter(&$theme_registry) {
foreach ($theme_registry as $key => $value) {
if (strpos($key, 'easy_social_') === 0) {
if (!empty($theme_registry[$key]['preprocess functions'])) {
array_unshift($theme_registry[$key]['preprocess functions'], '_easy_social_preprocess_widget');
}
}
}
}
/**
* Custom pre-process function, used to add settings for widgets.
*
* @see easy_social_theme_registry_alter()
*/
function _easy_social_preprocess_widget(&$variables, $hook) {
global $base_url;
$widget = str_replace("easy_social_", "", $hook);
$config = Drupal::config('easy_social.settings');
$variables['async'] = $config->get('global.async');
$definitions = easy_social_get_widgets();
$variables['url'] = $base_url . Url::fromRoute('<current>')->toString();
// @todo get current title.
// $variables['title'] = 'Test';
// @todo get current language from context or fallback to site default.
if (!isset($variables['lang']) || empty($variables['lang'])) {
$variables['lang'] = 'en';
}
}
/**
* Returns entity types we want to attach an extra Easy Social pseudo-field to.
*
* @return array
* An array of entity types.
*/
function easy_social_get_supported_entities() {
static $supported_entity_types;
if (!isset($supported_entity_types)) {
// Support only core by default.
$supported_entity_types = [
'comment',
'file',
'node',
'taxonomy_term',
'user',
];
// Other modules can easily enable support for others.
// @todo add API documentation if we end up keeping this.
\Drupal::moduleHandler()
->alter('easy_social_supported_entity', $supported_entity_types);
}
return $supported_entity_types;
}
/**
* Implements hook_entity_extra_field_info().
*/
function easy_social_entity_extra_field_info() {
$extra = [];
$supported_entity_types = easy_social_get_supported_entities();
$bundle_info_service = \Drupal::service('entity_type.bundle.info');
foreach ($supported_entity_types as $entity_type) {
$bundles = $bundle_info_service->getBundleInfo($entity_type);
foreach (array_keys($bundles) as $bundle) {
$extra[$entity_type][$bundle]['display']['easy_social'] = [
'label' => t('Easy Social widgets'),
'weight' => 0,
'visible' => FALSE,
];
}
}
return $extra;
}
/**
* Implements hook_entity_view().
*/
function easy_social_entity_view(&$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
if ($display->getComponent('easy_social')) {
$build['easy_social'] = [
// @todo Pass in some kind of context?
'#theme' => 'easy_social',
// @todo Enable caching? see Block implementation.
];
}
}
/**
* Helper function that adds javscript includes for widgets asynchronously.
*
* @param array
* The variables passed to the theme function.
* @param string
* Any extra markup to append to the script tag. This is used by some
* widgets to pass extra configuration.
*
* @see theme_easy_social()
*
* @todo this assumes script are external and might break if otherwise.
*/
function _easy_social_add_js($variables, $extra = '') {
$script = <<<JS
(function() {
!x
})();
JS;
$includes = '';
foreach ($variables as $var) {
$url = $var['data'];
$includes .= <<<EOT
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
po.src = '{$url}'; {$extra}
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
EOT;
}
$script = str_replace('!x', $includes, $script);
// drupal_add_js($script, 'inline');
}
