<?php
// $Id: nodewords_tokens.module,v 1.1.2.13 2010/04/18 14:08:39 kiam Exp $

define('NODEWORDS_DESCRIPTION_GENERATION_BODY', 1);
define('NODEWORDS_DESCRIPTION_GENERATION_TEASER', 2);
define('NODEWORDS_DESCRIPTION_GENERATION_TEASER_BODY', 3);

/**
 * @file
 * Implement tokens that can be used to set the content of meta tags.
 */

/**
 * Implements hook_form_FORM_ID_alter().
 */
function nodewords_tokens_form_nodewords_admin_settings_form_alter(&$form, $form_state) {
  $form['tokens_generation'] = array(
    '#type' => 'fieldset',
    '#title' => t('Tokens generation options'),
    '#description' => t('These options change the way tokens are generated.'),
    '#collapsible' => TRUE,
    '#weight' => 8,
    '#group' => 'nodewords',
  );

  $form['tokens_generation']['description'] = array(
    '#type' => 'fieldset',
    '#title' => t('Token %token options', array('%token' => 'metatags-description')),
    '#collapsible' => TRUE,
  );

  $form['tokens_generation']['description']['nodewords_use_alt_attribute'] = array(
    '#type' => 'checkbox',
    '#title' => t('Replace the tag IMG content with the attribute ALT'),
    '#default_value' => variable_get('nodewords_use_alt_attribute', TRUE),
  );

  $options = array(
    'imagebrowser' => 'imagebrowser.module',
    'img_assist' => 'img_assist.module',
  );

  $form['tokens_generation']['description']['nodewords_filter_modules_output'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Filter the text added by third-party modules in the node teaser'),
    '#options' => $options,
    '#default_value' => variable_get('nodewords_filter_modules_output', array()),
    '#checkall' => variable_get('nodewords_enable_checkall', FALSE),
  );

  $form['tokens_generation']['description']['nodewords_filter_regexp'] = array(
    '#type' => 'textfield',
    '#title' => t('Custom regular expression'),
    '#description' => t('A regular expression used to filter the text added in the node teaser from a third-party module. The regular expression uses the <a href="http://www.php.net/manual/en/pcre.pattern.php">Perl compatible</a> syntax.'),
    '#element_validate' => array('nodewords_tokens_filter_regex_validate'),
    '#default_value' => variable_get('nodewords_filter_regexp', ''),
    '#size' => 60,
  );

  $options = array(
    NODEWORDS_DESCRIPTION_GENERATION_BODY => t('Generate the token from the node body'),
    NODEWORDS_DESCRIPTION_GENERATION_TEASER => t('Generate the token from the node teaser'),
    NODEWORDS_DESCRIPTION_GENERATION_TEASER_BODY => t('Generate the token from the node teaser, or the node body when the node teaser is empty'),
  );

  $form['tokens_generation']['description']['nodewords_description_generation_source'] = array(
    '#type' => 'radios',
    '#title' => t('Generation source'),
    '#options' => $options,
    '#default_value' => variable_get('nodewords_description_generation_source', NODEWORDS_DESCRIPTION_GENERATION_TEASER),
  );

  $form['tokens_generation']['taxonomy_keywords'] = array(
    '#type' => 'fieldset',
    '#title' => t('Token %token options', array('%token' => 'metatags-taxonomy-keywords')),
    '#collapsible' => TRUE,
  );

  if (module_exists('taxonomy')) {
    $options = array();

    foreach (taxonomy_get_vocabularies() as $vocabulary) {
      $options[$vocabulary->vid] = check_plain($vocabulary->name);
    }

    if ($count = count($options)) {
      $form['tokens_generation']['taxonomy_keywords']['nodewords_keyword_vids'] = array(
        '#type' => $count > 10 ? 'select' : 'checkboxes',
        '#title' => t('Auto-keywords vocabularies'),
        '#description' => t('Select the vocabularies which contain terms you want to add to the keywords meta tag for nodes.'),
        '#default_value' => variable_get('nodewords_keyword_vids', array()),
        '#options' => $options,
      );

      if ($count > 10) {
        $form['tokens_generation']['taxonomy_keywords']['nodewords_keyword_vids']['#multiple'] = TRUE;
      }
      elseif ($count > 2) {
        // Add support for Check All if the checkboxes are more than two.
        $form['tokens_generation']['taxonomy_keywords']['nodewords_keyword_vids']['#checkall'] = variable_get('nodewords_enable_checkall', FALSE);
      }
    }
  }

  if (empty($options)) {
    $form['tokens_generation']['taxonomy_keywords']['nodewords_keyword_vids'] = array(
      '#type' => 'value',
      '#default_value' => variable_get('nodewords_keyword_vids', array()),
    );

    $form['tokens_generation']['taxonomy_keywords']['taxonomy_message'] = array(
      '#value' => module_exists('taxonomy') ? t('There are no vocabularies currently defined.') : t('The module %module is not enabled; if you want to use taxonomy terms to automatically set the content of the meta tag KEYWORDS, you first need to <a href="@modules-page">enable %module</a>', array('%module' => 'taxonomy.module', '@modules-page' => url('admin/build/modules'))),
      '#prefix' => '<div class="messages">',
      '#suffix' => '</div>',
    );
  }

  $form['tokens_generation']['global_keywords'] = array(
    '#type' => 'fieldset',
    '#title' => t('Global keywords token options'),
    '#collapsible' => TRUE,
  );

  $form['tokens_generation']['global_keywords']['nodewords_global_keywords_1'] = array(
    '#type' => 'textfield',
    '#title' => t('Global keywords - first group'),
    '#description' => t('Enter a comma separated list of keywords. Avoid duplication of words as this will lower your search engine ranking.'),
    '#default_value' => variable_get('nodewords_global_keywords_1', ''),
    '#size' => 60,
  );

  $form['tokens_generation']['global_keywords']['nodewords_global_keywords_2'] = array(
    '#type' => 'textfield',
    '#title' => t('Global keywords - second group'),
    '#description' => t('Enter a comma separated list of keywords. Avoid duplication of words as this will lower your search engine ranking.'),
    '#default_value' => variable_get('nodewords_global_keywords_2', ''),
    '#size' => 60,
  );
}

/**
 * Function to validate the regular expression.
 *
 */
function nodewords_tokens_filter_regex_validate($element, &$form_state) {
  if (!empty($element['#value'])) {
    $value = trim($element['#value']);

    if (empty($value)) {
      form_error($element, t('The regular expression contains only spaces, and other not printable characters.'));
    }
  }
}

/**
 * Implements hook_token_list().
 */
function nodewords_tokens_token_list($type = 'all') {
  $tokens = array();

  if ($type == 'all' || $type == 'global') {
    $tokens['global']['metatags-global-keywords-1'] = t('The global keywords.');
    $tokens['global']['metatags-global-keywords-2'] = t('The global keywords.');
    $tokens['global']['metatags-global-keywords-1-raw'] = t('The raw global keywords.');
    $tokens['global']['metatags-global-keywords-2-raw'] = t('The raw global keywords.');
    $tokens['global']['metatags-normal-url'] = t('The internal URL of the current page.');
    $tokens['global']['metatags-url-alias'] = t('The alias of the current page URL.');
  }

  if ($type == 'all' || $type == 'node') {
    $tokens['node']['metatags-description'] = t('The node description generated from the node body, or the node teaser.');
    $tokens['node']['metatags-description-raw'] = t('The node description generated from the node body, or the node teaser. WARNING - raw user input.');
    $tokens['node']['metatags-taxonomy-keywords'] = t('The node keywords generated from the taxonomy terms associated with the node.');
    $tokens['node']['metatags-taxonomy-keywords-raw'] = t('The node keywords generated from the taxonomy terms associated with the node. WARNING - raw user input.');
  }

  return $tokens;
}

/**
 * Implements hook_token_values().
 *
 * @param $object
 *   The module name of the search routine.
 */
function nodewords_tokens_token_values($type, $object = NULL, $options = array()) {
  $values = array();

  switch ($type) {
    case 'global':
      $value = nodewords_unique_values(variable_get('metatags_extra_global_keywords_1', ''));
      $values['metatags-global-keywords-1-raw'] = $value;
      $values['metatags-global-keywords-1'] = check_plain($value);

      $value = nodewords_unique_values(variable_get('metatags_extra_global_keywords_2', ''));
      $values['metatags-global-keywords-2-raw'] = $value;
      $values['metatags-global-keywords-2'] = check_plain($value);

      if (drupal_is_front_page()) {
        $path = '<front>';
      }
      else {
        $path = $_GET['q'];
      }

      $values['metatags-normal-url'] = nodewords_url($path);
      $values['metatags-url-alias'] = nodewords_url($path, array('alias' => FALSE));
      break;

    case 'node':
      $value = '';
      $values['metatags-description-raw'] = _nodewords_tokens_metatag_from_node_content($object);
      $values['metatags-description'] = check_plain($values['metatags-description-raw']);

      if (module_exists('taxonomy')) {
        foreach (taxonomy_node_get_terms($object) as $term) {
          if (in_array($term->vid, variable_get('nodewords_keyword_vids', array()))) {
            $value .= ',' . $term->name;
          }
        }
      }
      $value = nodewords_unique_values($value);
      $values['metatags-taxonomy-keywords-raw'] = $value;
      $values['metatags-taxonomy-keywords'] = check_plain($value);
      break;
  }

  return $values;
}

/**
 * Create the content of a meta tag from a node teaser.
 *
 * @param $node
 *   The node object the meta tag refers to.
 * @param $content
 *   The meta tag content.
 * @param $options
 *  An array of options.
 *
 * @return
 *   The string used as meta tag content.
 */
function _nodewords_tokens_metatag_from_node_content($node, $options = array()) {
  $default_options = array(
    'size' => variable_get('nodewords_max_size', 350),
    'source' => variable_get('nodewords_description_generation_source', NODEWORDS_DESCRIPTION_GENERATION_TEASER),
  );
  $filters = filter_list_format($node->format);
  $options += $default_options;
  $result = '';
  $source = $options['source'];

  $bool = (
    $source == NODEWORDS_DESCRIPTION_GENERATION_TEASER ||
    $source == NODEWORDS_DESCRIPTION_GENERATION_TEASER_BODY
  );

  if ($bool) {
    // Check for the presence of the PHP evaluator filter in the current
    // format. If the text contains PHP code, do not split it up to prevent
    // parse errors.
    if (isset($filters['php/0']) && strpos($node->teaser, '<?') !== FALSE) {
      $result = '';
    }
    else {
      // Replace the tag IMG with the attribute ALT, and strip off all the
      // HTML tags.
      $result = strip_tags(
        preg_replace_callback("/<img\s[^>]*alt=[\"']([^\"']*)[\"'][^>]*>/i",
          '_nodewords_tokens_teaser_match_callback',
          $node->teaser
        )
      );

      // Remove the strings added from third-party modules.
      $modules = array_filter(
        variable_get('nodewords_filter_modules_output', array())
      );
      $regexps = array(
        'imagebrowser' => '/\[ibimage[^\]]*\]/i',
        'img_assist' => '/\[img_assist[^\]]*\]/i',
      );

      foreach ($regexps as $module => $regexp) {
        if (isset($modules[$module])) {
          $result = preg_replace($regexp, '', $result);
        }
      }

      // Remove the text matching the regular expression.
      $regexp = trim(variable_get('nodewords_filter_regexp', ''));
      if (!empty($regexp)) {
        $result = preg_replace('/' . $regexp . '/i', '', $result);
      }

      $result = node_teaser(
        trim(preg_replace('/(\r\n?|\n)/', ' ', $result)),
        $node->format, $options['size']
      );
    }
  }

  $bool = (
    $source == NODEWORDS_DESCRIPTION_GENERATION_BODY ||
    (
      $source == NODEWORDS_DESCRIPTION_GENERATION_TEASER_BODY && empty($result)
    )
  );

  if ($bool) {
    // We check for the presence of the PHP evaluator filter in the current
    // format. If the text contains PHP code, we do not split it up to prevent
    // parse errors.
    if (isset($filters['php/0']) && strpos($node->body, '<?') !== FALSE) {
      return '';
    }

    // Replace the tag IMG with the attribute ALT, and strip off all the
    // HTML tags.
    $result = strip_tags(
      preg_replace_callback("/<img\s[^>]*alt=[\"']([^\"']*)[\"'][^>]*>/i",
        '_nodewords_tokens_teaser_match_callback',
        $node->body
      )
    );

    $result = node_teaser(
      trim(preg_replace('/(\r\n?|\n)/', ' ', $result)),
      $node->format, $options['size']
    );
  }

  return $result;
}

/**
 * Helper function for preg_match_callback(), called when replacing the tag IMG
 * in the teaser, when using it as meta tag DESCRIPTION content.
 */
function _nodewords_tokens_teaser_match_callback($matches) {
  static $bool;

  if (!isset($bool)) {
    $bool = variable_get('nodewords_use_alt_attribute', FALSE);
  }

  if ($bool && !empty($matches[1])) {
    return ' ' . $matches[1] . ' ';
  }

  return '';
}