You are here

emogrifier.module in Emogrifier 7.2

Same filename and directory in other branches
  1. 8 emogrifier.module
  2. 6 emogrifier.module
  3. 7 emogrifier.module

This module uses the emogrifier class library as an input filter to convert stylesheet rules to inline style attributes. This ensures proper display on email and mobile device readers that lack stylesheet support.

File

emogrifier.module
View source
<?php

/**
 * @file
 * This module uses the emogrifier class library as an input filter to convert
 * stylesheet rules to inline style attributes.  This ensures proper display
 * on email and mobile device readers that lack stylesheet support.
 *
 * @see http://www.pelagodesign.com/sidecar/emogrifier/
 */

/**
 * Implements hook_help().
 */
function emogrifier_help($path = 'admin/help#emogrifier', $arg) {
  switch ($path) {
    case 'admin/help#emogrifier':
      return '<p>' . t('The <a href="!module">%emogrifier</a> module uses the <a href="!class">%emogrifier</a> class library to convert stylesheet rules to inline style attributes. This ensures proper display on email and mobile device readers that lack stylesheet support.', array(
        '!module' => url('http://drupal.org/project/emogrifier'),
        '%emogrifier' => 'emogrifier',
        '!class' => url('http://www.pelagodesign.com/sidecar/emogrifier/'),
      )) . '</p>';
      break;
  }
}

/**
 * Implements hook_filter_info().
 */
function emogrifier_filter_info() {
  return array(
    'filter_emogrifier' => array(
      'title' => t('Emogrifier'),
      'description' => t('Converts stylesheet rules to inline style attributes.'),
      'process callback' => '_emogrifier_process',
      'settings callback' => '_emogrifier_filter_settings',
      'tips callback' => '_emogrifier_filter_tips',
    ),
  );
}

/**
 * Implements hook_filter_FILTER_process().
 * @see emogrifier_filter_info()
 */
function _emogrifier_process($text, $filter, $format, $langcode, $cache, $cache_id) {
  if (empty($text)) {
    return '';
  }

  // Avoid PHP fatal errors when the 'dom' extension is not loaded.
  if (!extension_loaded('dom')) {
    watchdog('emogrifier', 'The PHP <a href="!dom">%dom</a> extension required by <a href="!emogrifier">%emogrifier</a> is not loaded.', array(
      '!dom' => url('http://php.net/dom'),
      '%dom' => 'dom',
      '!emogrifier' => url('http://drupal.org/project/emogrifier'),
      '%emogrifier' => 'Emogrifier',
    ), WATCHDOG_WARNING);
    return $text;
  }
  if (!_emogrifier_available()) {
    watchdog('emogrifier', 'The <a href="!library">%emogrifier</a> class library required by the <a href="!module">%emogrifier</a> module could not be loaded.', array(
      '!library' => url('http://www.pelagodesign.com/sidecar/emogrifier/'),
      '%emogrifier' => 'emogrifier',
      '!module' => url('http://drupal.org/project/emogrifier'),
    ), WATCHDOG_WARNING);
    return $text;
  }
  $emogrifier = new \Pelago\Emogrifier($text);
  $css = '';

  // Add external css from settings, add it to $urls to be parsed.
  if (isset($filter->settings['external_css']) && !empty($filter->settings['external_css'])) {
    $stylesheets = explode('\\n', str_replace('\\r', '', $filter->settings['external_css']));
    foreach ($stylesheets as $stylesheet) {

      // Check if file exists to avoid warning.
      if (file_exists($stylesheet)) {
        $css = file_get_contents($stylesheet);
      }
    }
  }

  // Add inline css from settings, add it to $styles to be parsed.
  if (isset($filter->settings['inline_css']) && !empty($filter->settings['inline_css'])) {
    $css .= $filter->settings['inline_css'];
  }
  if (!empty($css)) {
    @$emogrifier
      ->setCss($css);
  }
  if (isset($filter->settings['disable_styles_block_parsing']) && !empty($filter->settings['disable_styles_block_parsing'])) {
    @$emogrifier
      ->disableStyleBlocksParsing();
  }
  if (isset($filter->settings['disable_inline_styles_parsing']) && !empty($filter->settings['disable_inline_styles_parsing'])) {
    @$emogrifier
      ->disableInlineStyleAttributesParsing();
  }
  if (isset($filter->settings['disable_invisible_node_removal']) && !empty($filter->settings['disable_invisible_node_removal'])) {
    @$emogrifier
      ->disableInvisibleNodeRemoval();
  }
  if (isset($filter->settings['enable_css_to_html_mapping']) && !empty($filter->settings['enable_css_to_html_mapping'])) {
    @$emogrifier
      ->enableCssToHtmlMapping();
  }
  if (isset($filter->settings['add_allowed_media_type']) && !empty($filter->settings['add_allowed_media_type'])) {
    $media_types = explode(',', $filter->settings['add_allowed_media_type']);
    foreach ($media_types as $media_type) {
      @$emogrifier
        ->addAllowedMediaType(trim($media_type));
    }
  }
  if (isset($filter->settings['remove_allowed_media_type']) && !empty($filter->settings['remove_allowed_media_type'])) {
    foreach ($filter->settings['remove_allowed_media_type'] as $media_type) {
      @$emogrifier
        ->removeAllowedMediaType($media_type);
    }
  }
  if (isset($filter->settings['add_excluded_selector']) && !empty($filter->settings['add_excluded_selector'])) {
    $excluded_selectors = explode(',', $filter->settings['add_excluded_selector']);
    foreach ($excluded_selectors as $excluded_selector) {
      @$emogrifier
        ->addExcludedSelector(trim($excluded_selector));
    }
  }
  $content = @$emogrifier
    ->emogrify();

  // Emogrifier has a problem with [ and ] inside quotes.
  // This stops tokens inside of href and src attributes from being processed.
  // See https://github.com/jjriv/emogrifier/issues/98.
  $content = str_replace('%5B', '[', $content);
  $content = str_replace('%5D', ']', $content);
  return $content;
}

/**
 * Returns TRUE if the Emogrifier class is available.
 */
function _emogrifier_available() {

  // Maybe something loaded the class without telling libraries API.
  if (class_exists('\\Pelago\\Emogrifier')) {
    return TRUE;
  }
  @(include_once libraries_get_path('emogrifier') . '/Classes/Emogrifier.php');
  return class_exists('\\Pelago\\Emogrifier');
}

/**
 * Implements hook_filter_FILTER_settings().
 * @see emogrifier_filter_info()
 */
function _emogrifier_filter_settings($form, &$form_state, $filter, $format, $defaults, $filters) {
  $filter->settings += $defaults;

  // Do this to show error if files for external CSS not found.
  if (empty($form_state['input'])) {
    $external_css = $filter->settings['external_css'];
    if (isset($external_css) && !empty($external_css)) {
      $stylesheets = explode('\\n', str_replace('\\r', '', $external_css));
      foreach ($stylesheets as $stylesheet) {
        if (!file_exists($stylesheet)) {
          drupal_set_message(t('File @stylesheet does not exist.', array(
            '@stylesheet' => $stylesheet,
          )), 'error', FALSE);
        }
      }
    }
  }
  return array(
    'disable_styles_block_parsing' => array(
      '#type' => 'checkbox',
      '#title' => 'Disable inline styles parsing',
      '#description' => t('By default, Emogrifier will grab all &lt;style&gt; blocks in the HTML and will apply the CSS styles as inline "style" attributes to the HTML. The &lt;style&gt; blocks will then be removed from the HTML. If you want to disable this functionality so that Emogrifier leaves these &lt;style&gt; blocks in the HTML and does not parse them, you should use this option. If you use this option, the contents of the &lt;style&gt; blocks will not be applied as inline styles and any CSS you want Emogrifier to use must be passed using the external css and inline css options below.'),
      '#default_value' => isset($filter->settings['disable_styles_block_parsing']) ? $filter->settings['disable_styles_block_parsing'] : FALSE,
      '#checked' => isset($filter->settings['disable_styles_block_parsing']) ? $filter->settings['disable_styles_block_parsing'] : FALSE,
    ),
    'disable_inline_styles_parsing' => array(
      '#type' => 'checkbox',
      '#title' => 'Disable inline styles parsing',
      '#description' => t('By default, Emogrifier preserves all of the "style" attributes on tags in the HTML you pass to it. However if you want to discard all existing inline styles in the HTML before the CSS is applied, you should use this option.'),
      '#default_value' => isset($filter->settings['disable_inline_styles_parsing']) ? $filter->settings['disable_inline_styles_parsing'] : FALSE,
      '#checked' => isset($filter->settings['disable_inline_styles_parsing']) ? $filter->settings['disable_inline_styles_parsing'] : FALSE,
    ),
    'disable_invisible_node_removal' => array(
      '#type' => 'checkbox',
      '#title' => 'Disable invisible node removal',
      '#description' => t('By default, Emogrifier removes elements from the DOM that have the style attribute display: none;. If you would like to keep invisible elements in the DOM, use this option.'),
      '#default_value' => isset($filter->settings['disable_invisible_node_removal']) ? $filter->settings['disable_invisible_node_removal'] : FALSE,
      '#checked' => isset($filter->settings['disable_invisible_node_removal']) ? $filter->settings['disable_invisible_node_removal'] : FALSE,
    ),
    'enable_css_to_html_mapping' => array(
      '#type' => 'checkbox',
      '#title' => 'Enable CSS to HTML Mapping',
      '#description' => t('Some email clients don\'t support CSS well, even if inline and prefer HTML attributes. This function allows you to put properties such as height, width, background color and font color in your CSS while the transformed content will have all the available HTML tags set.'),
      '#default_value' => isset($filter->settings['enable_css_to_html_mapping']) ? $filter->settings['enable_css_to_html_mapping'] : FALSE,
      '#checked' => isset($filter->settings['enable_css_to_html_mapping']) ? $filter->settings['enable_css_to_html_mapping'] : FALSE,
    ),
    'add_allowed_media_type' => array(
      '#type' => 'textfield',
      '#maxlength' => 1024,
      '#title' => t('Add allowed media types'),
      '#description' => t('By default, Emogrifier will keep only media types all, screen and print. If you want to keep some others, you can use this method to define them. Enter a comma separated list of media types.'),
      '#default_value' => isset($filter->settings['add_allowed_media_type']) ? $filter->settings['add_allowed_media_type'] : '',
    ),
    'remove_allowed_media_type' => array(
      '#type' => 'checkboxes',
      '#title' => t('Remove allowed media types'),
      '#description' => t('Remove default media types media types that Emogrifier keeps.'),
      '#options' => array(
        'all' => 'All',
        'screen' => 'Screen',
        'print' => 'Print',
      ),
      '#default_value' => isset($filter->settings['remove_allowed_media_type']) ? $filter->settings['remove_allowed_media_type'] : array(),
    ),
    'add_excluded_selector' => array(
      '#type' => 'textfield',
      '#maxlength' => 1024,
      '#title' => t('Add excluded selectors'),
      '#description' => t('Keeps elements from being affected by emogrification. Enter a comma separated list of selectors.'),
      '#default_value' => isset($filter->settings['add_excluded_selector']) ? $filter->settings['add_excluded_selector'] : '',
    ),
    'external_css' => array(
      '#type' => 'textarea',
      '#title' => t('Relative CSS paths to be included. One file path per line.'),
      '#description' => t('For example: sites/all/themes/my_theme/css/mail.css'),
      '#default_value' => isset($filter->settings['external_css']) ? $filter->settings['external_css'] : '',
    ),
    'inline_css' => array(
      '#type' => 'textarea',
      '#title' => t('Inline CSS to be included.'),
      '#description' => t('Do not add &lt;style&gt; tags.'),
      '#default_value' => isset($filter->settings['inline_css']) ? $filter->settings['inline_css'] : "",
    ),
  );
}

/**
 * Implements hook_filter_FILTER_tips().
 * @see emogrifier_filter_info()
 */
function _emogrifier_filter_tips($filter, $format, $long) {
  return t('Stylesheet rules will be converted to inline style attributes.');
}

Functions

Namesort descending Description
emogrifier_filter_info Implements hook_filter_info().
emogrifier_help Implements hook_help().
_emogrifier_available Returns TRUE if the Emogrifier class is available.
_emogrifier_filter_settings Implements hook_filter_FILTER_settings().
_emogrifier_filter_tips Implements hook_filter_FILTER_tips().
_emogrifier_process Implements hook_filter_FILTER_process().