You are here

nodewords.module in Nodewords: D6 Meta Tags 5

Same filename and directory in other branches
  1. 6.3 nodewords.module
  2. 6 nodewords.module
  3. 6.2 nodewords.module

Assign META tags to nodes, vocabularies, terms and pages.

File

nodewords.module
View source
<?php

/**
 * @file
 * Assign META tags to nodes, vocabularies, terms and pages.
 */

/**
 * Implementation of hook_block().
 */
function nodewords_block($op = 'list', $delta = 0, $edit = array()) {
  switch ($op) {
    case 'list':
      $blocks = array();
      $blocks[0] = array(
        'info' => t('Meta tags'),
      );
      return $blocks;
    case 'view':
      $block = array();
      switch ($delta) {
        case 0:
          $tags = nodewords_get();
          if (isset($tags['keywords'])) {
            $tags['keywords'] = str_replace(',', ', ', $tags['keywords']);
          }
          $block['subject'] = t('Meta tags');
          $block['content'] = theme('nodewords_content', $tags);
          break;
      }
      return $block;
  }
}

/**
 *  Implemenation of hook_help().
 */
function nodewords_help($section) {
  switch ($section) {
    case 'admin/content/nodewords/frontpage':
      return t('On this page you can enter the meta tags for the front page of your site.');
  }
}

/**
 * Implementation of hook_nodewords().
 */
function nodewords_nodewords(&$tags, $op, $type = NULL, $ids = NULL) {
  switch ($op) {
    case 'list':
      return _nodewords_get_builtin_tags();
    case 'prepare':
      $settings = _nodewords_get_settings();
      foreach (_nodewords_get_builtin_tags() as $tag) {
        $function = _nodewords_get_builtin_function($tag, 'prepare');
        if (function_exists($function)) {
          $tags[$tag] = $function($type, $ids, isset($tags[$tag]) ? $tags[$tag] : '', $settings);
        }
      }
      break;
  }
}

/**
 * Implementation of hook_token_values().
 */
function nodewords_token_values($type, $object = NULL, $options = array()) {
  $tokens = array();
  if ($type = 'node') {
    $tokens['meta-keywords'] = $object->nodewords['keywords'];
    $tokens['meta-description'] = $object->nodewords['description'];
  }
  return $tokens;
}

/**
 * Implementation of hook_token_list().
 */
function nodewords_token_list($type = 'all') {
  $tokens = array();
  if ($type == 'node' || $type == 'all') {
    $tokens['node']['meta-keywords'] = t("The meta keywords");
    $tokens['node']['meta-description'] = t("The meta description");
  }
  return $tokens;
}

/**
 * Implementation of hook_menu().
 */
function nodewords_menu($may_cache) {
  $items = array();
  if ($may_cache) {
    $items[] = array(
      'title' => t('Meta tags'),
      'path' => 'admin/content/nodewords',
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'nodewords_settings_form',
      ),
      'description' => t('Configure HTML meta tags for all content.'),
      'access' => user_access('administer meta tags'),
      'type' => MENU_NORMAL_ITEM,
    );
    $items[] = array(
      'title' => t('Settings'),
      'path' => 'admin/content/nodewords/global',
      'access' => user_access('administer meta tags'),
      'type' => MENU_DEFAULT_LOCAL_TASK,
      'weight' => -10,
    );
    $items[] = array(
      'title' => t('Front page'),
      'path' => 'admin/content/nodewords/frontpage',
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'nodewords_frontpage_form',
      ),
      'access' => user_access('administer meta tags'),
      'type' => MENU_LOCAL_TASK,
    );
  }
  else {
    $tags = nodewords_get();
    foreach ($tags as $name => $content) {
      if (!empty($content)) {
        drupal_set_html_head('<meta name="' . $name . '" content="' . $content . '" />');
      }
    }
  }
  return $items;
}

/**
 * Implementation of hook_nodeapi().
 */
function nodewords_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
  switch ($op) {
    case 'delete':
      if (user_access('edit meta tags')) {
        _nodewords_delete('node', $node->nid);
      }
      break;
    case 'insert':
    case 'update':
      if (isset($node->nodewords) && user_access('edit meta tags')) {
        _nodewords_set('node', $node->nid, $node->nodewords);
      }
      break;
    case 'update index':
      $output = '<h2>' . $node->nodewords['keywords'] . '</h2>';
      $output .= '<h3>' . $node->nodewords['description'] . '</h3>';
      return $output;
    case 'load':
      $node->nodewords = _nodewords_load('node', $node->nid);
      break;
  }
}

/**
 * Implementation of hook_form_alter().
 */
function nodewords_form_alter($form_id, &$form) {
  if ($form_id == 'node_type_form' && isset($form['#node_type'])) {
    $form['workflow']['nodewords'] = array(
      '#type' => 'checkbox',
      '#title' => t('Allow editing of meta tags'),
      '#default_value' => variable_get('nodewords_' . $form['#node_type']->type, 1),
      '#description' => t('Users with the <em>edit meta tags</em> permission will be able to edit the meta tags for this content type.'),
    );
    return;
  }
  if (!user_access('edit meta tags')) {
    return;
  }
  if (isset($form['type']) && $form_id == $form['type']['#value'] . '_node_form') {
    if (variable_get('nodewords_' . $form['type']['#value'], 1)) {
      $type = 'node';
      $id = $form['nid']['#value'];
    }
  }
  elseif ($form_id == 'taxonomy_form_vocabulary') {
    $type = 'vocabulary';
    $id = $form['vid']['#value'];
    $form['submit']['#weight'] = 45;
    $form['delete']['#weight'] = 50;
  }
  elseif ($form_id == 'taxonomy_form_term') {
    $type = 'term';
    $id = $form['tid']['#value'];
    $form['submit']['#weight'] = 45;
    $form['delete']['#weight'] = 50;
  }
  elseif ($form_id == 'panels_edit_form') {
    $type = 'panels';
    $id = $form['did']['#value'];
    $form['submit']['#weight'] = 45;
    $form['#submit']['nodewords_panels_handler'] = array();
  }
  elseif ($form_id == 'panels_delete_confirm') {
    $form['#submit']['nodewords_panels_handler'] = array();
  }
  elseif ($form_id == 'panels_page_edit_form') {
    $panels_page = panels_page_get_current($form);
    $type = 'panels';
    $id = $panels_page['panel_page']['#value']->did;
    $form['submit']['#weight'] = 45;
    $form['#submit']['nodewords_panels_page_handler'] = array();
  }
  elseif ($form_id == 'panels_page_delete_confirm') {
    $form['#submit']['nodewords_panels_page_handler'] = array();
  }
  elseif ($form_id == 'views_edit_view') {
    $type = 'views';
    $id = $form['vid']['#value'];
    $form['save']['#weight'] = 40;
    $form['save_and_edit']['#weight'] = 45;
    if (isset($form['delete'])) {
      $form['delete']['#weight'] = 50;
    }
    $form['cancel']['#weight'] = 55;
    $form['#submit']['nodewords_views_handler'] = array();
  }
  elseif ($form_id == 'views_ui_admin_delete_confirm') {
    $form['#submit'] = array_merge(array(
      'nodewords_views_handler' => array(),
    ), (array) $form['#submit']);
  }
  if (isset($type)) {
    if (isset($id) && is_numeric($id)) {
      $tags = _nodewords_load($type, $id);
    }
    else {
      $tags = array();
    }
    $form['nodewords'] = _nodewords_form($type, $tags, !(isset($id) && is_numeric($id)));
  }
}

/**
 * Implementation of hook_perm().
 */
function nodewords_perm() {
  return array(
    'administer meta tags',
    'edit meta tags',
  );
}

/**
 * Implementation of hook_taxonomy().
 */
function nodewords_taxonomy($op, $type, $object = NULL) {
  if ($type == 'term') {
    $id = $object['tid'];
  }
  elseif ($type == 'vocabulary') {
    $id = $object['vid'];
  }
  else {
    return;
  }
  switch ($op) {
    case 'delete':
      if (user_access('edit meta tags')) {
        _nodewords_delete($type, $id);
      }
      break;
    case 'insert':
    case 'update':
      if (isset($object['nodewords']) && user_access('edit meta tags')) {
        _nodewords_set($type, $id, $object['nodewords']);
      }
      break;
  }
}

/**
 * Menu callback: settings form.
 */
function nodewords_settings_form() {
  $settings = _nodewords_get_settings();
  $form = array();
  $form['nodewords'] = array(
    '#tree' => TRUE,
  );
  $form['nodewords']['global'] = array(
    '#tree' => TRUE,
  );
  $form['nodewords']['global']['copyright'] = array(
    '#type' => 'textfield',
    '#title' => t('Global copyright'),
    '#default_value' => $settings['global']['copyright'],
    '#size' => 60,
    '#maxlength' => $settings['max_size'],
    '#description' => t('Enter a short copyright statement (one line) that will be used on all pages unless specifically set.'),
  );
  $form['nodewords']['global']['geourl'] = array(
    '#type' => 'textfield',
    '#title' => t('Global GeoURL'),
    '#default_value' => $settings['global']['geourl'],
    '#size' => 60,
    '#maxlength' => $settings['max_size'],
    '#description' => t('Enter a GeoURL (latitude, longitude) that will be used on all pages unless specifically set.'),
  );
  $form['nodewords']['global']['keywords'] = array(
    '#type' => 'textfield',
    '#title' => t('Global keywords'),
    '#default_value' => $settings['global']['keywords'],
    '#size' => 60,
    '#maxlength' => $settings['max_size'],
    '#description' => t('Enter a comma separated list of global keywords. These global keywords will be added after the page-specific keywords on all pages.'),
  );
  if (function_exists('taxonomy_get_vocabularies')) {
    $select = array();
    foreach (taxonomy_get_vocabularies() as $vocabulary) {
      $select[$vocabulary->vid] = check_plain($vocabulary->name);
    }
    if (count($select) > 0) {
      $form['nodewords']['keywords_vids'] = array(
        '#type' => 'select',
        '#title' => t('Auto-keywords vocabularies'),
        '#default_value' => $settings['keywords_vids'],
        '#options' => $select,
        '#description' => t('Select the vocabularies which contain terms you want to add to the keywords meta tag for nodes. The terms of these vocabularies are added before the global keywords but after the page-specific keywords.'),
        '#multiple' => TRUE,
      );
      $form['nodewords']['keywords_include_parents'] = array(
        '#type' => 'checkbox',
        '#title' => t('Include parent terms of auto-keyword vocabularies in keywords meta tag'),
        '#default_value' => $settings['keywords_include_parents'],
        '#description' => t('If you select a vocabulary above, checking this option will include the parent terms of selected terms in the keywords meta tag. If unsure, unselect this option.'),
      );
    }
  }
  $form['nodewords']['use_teaser'] = array(
    '#type' => 'checkbox',
    '#title' => t('Use the teaser of the page if the meta description is not set.'),
    '#default_value' => $settings['use_teaser'],
  );
  $form['nodewords']['global']['robots'] = array(
    '#type' => 'select',
    '#title' => t('Default robots meta tag'),
    '#options' => array(
      'index,follow' => 'ALL=INDEX,FOLLOW',
      'noindex,follow' => 'NOINDEX,FOLLOW',
      'index,nofollow' => 'INDEX,NOFOLLOW',
      'noindex,nofollow' => 'NONE=NOINDEX,NOFOLLOW',
    ),
    '#multiple' => FALSE,
    '#default_value' => $settings['global']['robots'],
    '#description' => t('The ROBOTS meta tag offers a simple mechanism to indicate to web robots and crawlers wether the page should be indexed (INDEX or NOINDEX) and whether links on the page should be followed (FOLLOW or NOFOLLOW). Here you can enter the default robots meta tag to use for all pages. If unsure, select "ALL=INDEX,FOLLOW".'),
  );
  $form['nodewords']['max_size'] = array(
    '#type' => 'textfield',
    '#title' => t('Text length'),
    '#default_value' => $settings['max_size'],
    '#size' => 6,
    '#maxlength' => 6,
    '#description' => t('The maximum number of characters the content of a meta tag can contain.'),
  );
  $form['nodewords']['edit'] = array(
    '#type' => 'fieldset',
    '#title' => t('Tags to show on edit form'),
    '#tree' => TRUE,
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
    '#description' => t('Select the meta tags you want to be able to edit on the edit page of nodes, terms and vocabularies.'),
  );
  $form['nodewords']['head'] = array(
    '#type' => 'fieldset',
    '#title' => t('Tags to output in html head'),
    '#tree' => TRUE,
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
    '#description' => t('Select the meta tags you want to appear in the HEAD section of the HTML pages.'),
  );
  foreach (_nodewords_get_possible_tags() as $name) {
    foreach (array(
      'edit',
      'head',
    ) as $where) {
      $form['nodewords'][$where][$name] = array(
        '#type' => 'checkbox',
        '#title' => ucfirst($name),
        //TODO: is this UTF8 safe?
        '#default_value' => $settings[$where][$name],
      );
    }
  }
  $form['advanced'] = array(
    '#type' => 'fieldset',
    '#title' => t('Advanced options'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  );
  $form['advanced']['nodewords-repeat'] = array(
    '#type' => 'checkbox',
    '#title' => t('Repeat meta tags for lists'),
    '#default_value' => variable_get('nodewords-repeat', 0),
    '#description' => t('Some search engines punish sites that use the same meta tags on different pages. Uncheck this option if you want to suppress the repetition of the same meta tags on pages that use the pager - if unchecked, Drupal will only display the meta tags for the first page and not for subsequent pages. If unsure, select this option.'),
  );
  $form['advanced']['nodewords-use_front'] = array(
    '#type' => 'checkbox',
    '#title' => t('Use front page meta tags'),
    '#default_value' => variable_get('nodewords-use_front', 1),
    '#description' => t('Check this option if you want to use the <a href="!front-page-url" title="Meta tags for front page">meta tags for the front page</a> even if the <a href="!site-settings-url" title="Site information">default front page</a> specified is a view, panel or node - in this case, the meta tags specified for the view, panel or node will be ignored. If you want to use the meta tags of the view, panel or node instead, uncheck this option. If unsure, select this option and specify the meta tags you want on the <a href="!front-page-url" title="Meta tags for front page">meta tags for the front page</a>.', array(
      '!front-page-url' => url('admin/content/nodewords/frontpage'),
      '!site-settings-url' => url('admin/settings/site-information'),
    )),
  );
  return system_settings_form($form);
}

/**
 * Menu callback: front page settings form.
 */
function nodewords_frontpage_form() {
  $tags = _nodewords_load('page', '');
  $form = array();
  $form['nodewords'] = _nodewords_form('page', $tags);
  unset($form['nodewords']['#title']);
  unset($form['nodewords']['#type']);
  if (empty($form['nodewords'])) {
    $form['nodewords'] = array(
      '#value' => t('Currently no meta tags can be assigned to the front page because you have disabled all tags to show on the edit forms. <a href="!nodewords-settings-url" title="meta tags settings">Enable some meta tags to show on edit forms</a> first.', array(
        '!nodewords-settings-url' => url('admin/content/nodewords'),
      )),
    );
  }
  else {
    if (!variable_get('nodewords-use_front', 1)) {
      $form['nodewords'] = array(
        '#value' => t('You can not assign meta tags for the front page here because you have disabled them at the <a href="!nodewords-settings-url" title="Meta tags settings">meta tags settings page</a>. Instead, the meta tags for the view, panel or node you have set as front page will be used.', array(
          '!nodewords-settings-url' => url('admin/content/nodewords'),
        )),
      );
    }
    else {
      $form['submit'] = array(
        '#type' => 'submit',
        '#value' => t('Submit'),
        '#weight' => 40,
      );
    }
  }
  return $form;
}
function nodewords_frontpage_form_submit($form_id, $form_values) {
  if ($form_values['op'] == t('Submit')) {
    _nodewords_set('page', '', $form_values['nodewords']);
    drupal_set_message(t('The meta tags for the front page have been saved.'));
  }
}

/**
 * Handling of edit/delete form for panels.
 */
function nodewords_panels_handler($form_id, $form_values) {
  switch ($_POST['op']) {
    case t('Save'):
      if (isset($form_values['nodewords']) && user_access('administer meta tags')) {
        _nodewords_set('panels', $form_values['did'], $form_values['nodewords']);
      }
      break;
    case t('Delete'):
      if ($form_values['confirm']) {
        _nodewords_delete('panels', $form_values['did']);
      }
      break;
  }
}

/**
 * Handling of edit/delete form for panels (v2).
 */
function nodewords_panels_page_handler($form_id, $form_values) {
  switch ($_POST['op']) {
    case t('Save'):
      if (isset($form_values['nodewords']) && user_access('administer meta tags')) {
        _nodewords_set('panels', $form_values['panel_page']->did, $form_values['nodewords']);
      }
      break;
    case t('Delete'):
      if ($form_values['confirm']) {
        _nodewords_delete('panels', $form_values->did);
      }
      break;
  }
}

/**
 * Handling of edit/delete form for views.
 */
function nodewords_views_handler($form_id, $form_values) {
  switch ($_POST['op']) {
    case t('Save'):
    case t('Save and edit'):
      if (isset($form_values['nodewords']) && user_access('administer meta tags')) {
        if ($form_values['vid'] > 0) {
          _nodewords_set('views', $form_values['vid'], $form_values['nodewords']);
        }
        elseif ($result = db_fetch_object(db_query("SELECT * FROM {view_view} WHERE url = '%s'", $form_values['url']))) {
          _nodewords_set('views', $result->vid, $form_values['nodewords']);
        }
      }
      break;
    case t('Delete'):
      if ($form_values['confirm']) {
        _nodewords_delete('views', $form_values['vid']);
      }
      break;
  }
}

/**
 * Theming functions.
 */

/**
 * Displays the defined meta tags $tags as content, eg in a
 * block or body.
 *
 * @param $tags
 *   Associative array of defined tags.
 *   No need to 'check_plain' on content.
 * @return
 *   Formatted HTML.
 */
function theme_nodewords_content($tags) {
  $output = '';
  foreach ($tags as $name => $content) {
    if (!empty($content)) {
      $class = "meta-tags-{$name}";
      $output .= '<dt class="' . $class . '">' . $name . '</dt>';
      $output .= '<dd class="' . $class . '">' . $content . '</dd>';
    }
  }
  if (!empty($output)) {
    $output = '<dl class="meta-tags">' . $output . '</dl>';
  }
  return $output;
}

/**
 * Nodewords API functions.
 */

/**
 * Get the defined meta tags for $type / $id.
 *
 * @param $type
 *   Realm of the object the meta tags are associated with.
 *   This is one of the following: 'node', 'page', 'term',
 *   'vocabulary'.
 * @param $ids
 *   Id (or path) of the object to get the meta tags from.
 *   This is one of the following:
 *   - 'node' => array of 'nid' of the node
 *   - 'page' => array of 'path' of the displayed page
 *   - 'term' => array of 'tid' of the term
 *   - 'vocabulary' => array of 'vid' of the vocabulary
 *   - 'panels' => array of 'did' of the panel
 *   - 'views' => array of 'vid' of the view
 *   If $type or $ids is not set, an attempt will be made to
 *   get it from $_GET['q'].
 * @param $filtered
 *   If TRUE, only the meta tags that the user configured for
 *   output will be returned.
 *   If FALSE, all meta tags will be returned.
 * @return
 *   An associative array of the defined meta tags.
 */
function nodewords_get($type = NULL, $ids = NULL, $filtered = TRUE) {

  // Autodetect if $type and/or $ids is not set
  if ($type == NULL || $ids == NULL) {
    $result = _nodewords_detect_type_and_ids();
    $type = $result['type'];
    $ids = $result['ids'];
  }
  if (!is_array($ids)) {
    $ids = array(
      $ids,
    );
  }

  // Load the values from the database
  if (count($ids) == 1 && ($type != 'node' || node_access('view', node_load($ids[0])))) {
    $tags = _nodewords_load($type, $ids[0]);
  }
  else {
    $tags = array();
  }

  // Pages with more than one node/term/vocabulary/...
  if ($type == 'term') {
    if (isset($tags['keywords'])) {
      $terms = array(
        $tags['keywords'],
      );
    }
    else {
      $terms = array();
    }
    foreach ($ids as $id) {
      $term = taxonomy_get_term($id);
      if ($term) {
        $terms[] = $term->name;
      }
    }
    if (count($terms)) {
      $tags['keywords'] = implode(',', $terms);
    }
  }

  // Prepare tags for output
  $tags = _nodewords_prepare($type, $ids, $tags, $filtered);
  return $tags;
}

/**
 * Database access functions.
 */

/**
 * Update or insert tags in the table
 */
function _nodewords_set($type, $id, $tags) {
  foreach ($tags as $name => $content) {
    if (empty($content)) {
      _nodewords_delete_tag($type, $id, $name);
    }
    else {
      _nodewords_update_tag($type, $id, $name, $content);
    }
  }
}

/**
 * Delete tags from table
 */
function _nodewords_delete($type, $id) {
  return db_query("DELETE FROM {nodewords} WHERE type = '%s' AND id = '%s'", $type, $id);
}

/**
 * Load tags from table
 */
function _nodewords_load($type, $id) {
  $tags = array();
  $result = db_query("SELECT * FROM {nodewords} WHERE type = '%s' AND id = '%s'", $type, $id);
  while ($row = db_fetch_object($result)) {
    $tags[$row->name] = $row->content;
  }
  return $tags;
}

/**
 * Set one tag
 */
function _nodewords_update_tag($type, $id, $name, $content) {
  $result = db_query("SELECT * FROM {nodewords} WHERE type = '%s' AND id = '%s' AND name = '%s'", $type, $id, $name);
  if (db_num_rows($result) == 0) {
    db_query("INSERT INTO {nodewords} (type, id, name, content) VALUES ('%s', '%s', '%s', '%s')", $type, $id, $name, $content);
  }
  else {
    db_query("UPDATE {nodewords} SET content = '%s' WHERE type = '%s' AND id = '%s' AND name = '%s'", $content, $type, $id, $name);
  }
}

/**
 * Delete one tag
 */
function _nodewords_delete_tag($type, $id, $name) {
  db_query("DELETE FROM {nodewords} WHERE type = '%s' and id = '%s' AND name = '%s'", $type, $id, $name);
}

/**
 * Helper functions - forms.
 */

/**
 * Create a form - returns a $form variable
 */
function _nodewords_form($type, $tags, $expanded = FALSE) {
  $settings = _nodewords_get_settings();
  $form = array();
  foreach (_nodewords_get_possible_tags() as $tag) {
    $function = _nodewords_get_builtin_function($tag, 'form');
    if ($settings['edit'][$tag] && function_exists($function)) {
      $element = $function($type, $tags[$tag], $settings);
      if ($element) {
        $form[$tag] = $element;
      }
    }
  }
  if (!empty($form)) {
    $form['#type'] = 'fieldset';
    $form['#title'] = t('Meta tags');
    $form['#tree'] = TRUE;
    $form['#collapsible'] = TRUE;
    $form['#collapsed'] = empty($tags) && !$expanded;
    $form['#weight'] = 20;
  }
  return $form;
}

/**
 * Helper functions - settings.
 */

/**
 * Load default and user-defined settings. If $defaults => default settings are returned.
 */
function _nodewords_get_settings($defaults = FALSE) {
  static $settings = NULL;
  static $default_settings = array(
    'use_teaser' => 1,
    'max_size' => 255,
    'keywords_vids' => array(),
    'keywords_include_parents' => 0,
    'dc_title_only_if_set' => 0,
    'global' => array(
      'copyright' => '',
      'geourl' => '',
      'keywords' => '',
      'robots' => 'index,follow',
    ),
    'head' => array(
      'abstract' => 1,
      'copyright' => 1,
      'DC.Title' => 1,
      'description' => 1,
      'geourl' => 1,
      'keywords' => 1,
      'Revisit-After' => 1,
      'robots' => 1,
    ),
    'edit' => array(
      'abstract' => 0,
      'copyright' => 0,
      'DC.Title' => 0,
      'description' => 1,
      'geourl' => 0,
      'keywords' => 1,
      'Revisit-After' => 0,
      'robots' => 0,
    ),
  );
  if ($defaults) {
    return $default_settings;
  }
  if ($settings == NULL) {
    $settings = variable_get('nodewords', array());
    foreach ($default_settings as $key => $value) {
      if (is_array($value)) {
        $settings[$key] = isset($settings[$key]) ? array_merge($value, $settings[$key]) : $value;
      }
      elseif (!isset($settings[$key])) {
        $settings[$key] = $value;
      }
    }
  }
  return $settings;
}

/**
 * Return a list of possible output tags
 */
function _nodewords_get_possible_tags() {
  static $tags;
  if (!isset($tags)) {
    $tags = _nodewords_invoke($tags, 'list', NULL, NULL);
    sort($tags);
  }
  return $tags;
}

/**
 * Return a list of builtin tags from the metatags/ directory.
 */
function _nodewords_get_builtin_tags() {
  static $tags;
  if (!isset($tags)) {
    $tags = array();
    $path = drupal_get_path('module', 'nodewords') . '/metatags';
    $files = file_scan_directory($path, '.*\\.inc$');
    foreach ($files as $filename => $file) {
      include_once "./{$filename}";
      $tags[] = basename($filename, '.inc');
    }
  }
  return $tags;
}

/**
 * Return a list of viewable output tags
 */
function _nodewords_get_viewable_tags($where = 'head') {
  $settings = _nodewords_get_settings();
  $output = array();
  foreach ($settings[$where] as $name => $viewable) {
    if ($viewable) {
      $output[] = $name;
    }
  }
  return $output;
}

/**
 * Helper functions - other.
 */

/**
 * Prepare the tags so they are ready for output. This includes:
 * - setting default values if the tag is empty
 * - adding or altering some content (eg add global keywords)
 */
function _nodewords_prepare($type, $ids, $tags, $filtered = TRUE) {

  // Prepare the tags
  _nodewords_invoke($tags, 'prepare', $type, $ids);

  // Filter out tags the user has chosen not to see
  if ($filtered) {
    $tags = _nodewords_filter_viewable($tags);
  }

  // EXCEPTION - QUICK HACK - DANGER AHEAD - BRAIN SWITCH-OFF
  if (isset($tags['geourl']) && !empty($tags['geourl'])) {
    $tags['geourl'] = str_replace(array(
      ' ',
      '	',
    ), '', $tags['geourl']);
    $tags['geo.position'] = str_replace(',', ';', $tags['geourl']);
    $tags['ICBM'] = str_replace(';', ',', $tags['geourl']);
    unset($tags['geourl']);
  }

  // Check 'content' of each tag
  $tags = array_map('_nodewords_check_content', $tags);
  return $tags;
}

/**
 * Remove the meta tags from $tags that the user chose not to show.
 */
function _nodewords_filter_viewable($tags, $where = 'head') {
  $output = array();
  if (is_array($tags)) {
    $viewables = _nodewords_get_viewable_tags($where);
    foreach ($viewables as $name) {
      if (isset($tags[$name])) {
        $output[$name] = $tags[$name];
      }
    }
  }
  return $output;
}

/**
 * Remove any content from the $tag that is not allowed in a meta content attribute.
 */
function _nodewords_check_content($text) {
  $settings = _nodewords_get_settings();
  $size = $settings['max_size'];
  if (function_exists('preg_replace')) {
    $pattern = '/<img\\s[^>]*alt=["\']([^"\']*)["\'][^>]*>/i';
    $replacement = '${1}';
    $text = preg_replace($pattern, $replacement, $text);
  }
  $text = strip_tags($text);
  $text = check_plain($text);
  $needles = array(
    '&nbsp;',
    "\r",
    "\n",
    '&#039;',
  );
  $replaces = array(
    ' ',
    ' ',
    ' ',
    "'",
  );
  $text = str_replace($needles, $replaces, $text);
  $text = trim($text);
  $text = preg_replace('/\\s+/', ' ', $text);
  if ($size > 0 && drupal_strlen($text) > $size) {
    $text = truncate_utf8($text, $size);
    $length = strrpos($text, ' ');

    //TODO: is this UTF safe?
    if (!is_bool($length)) {
      $text = substr($text, 0, $length);

      //TODO: is this UTF safe?
    }
  }

  // Do not index pager pages
  if (isset($_GET['page']) && is_numeric($_GET['page'])) {
    $text = preg_replace('!^index!', 'noindex', $text);
  }
  return $text;
}

/**
 * Try to guess the $type and $ids by looking at $_GET['q'].
 */
function _nodewords_detect_type_and_ids() {
  if (!variable_get('nodewords-repeat', 1) && isset($_REQUEST['page']) && intval($_REQUEST['page']) > 0) {
    return array(
      'type' => 'none',
      'ids' => array(),
    );
  }
  if (drupal_is_front_page()) {
    if (variable_get('nodewords-use_front', 1)) {
      return array(
        'type' => 'page',
        'ids' => array(
          '',
        ),
      );
    }
  }
  if (module_exists('panels')) {
    if (function_exists('panels_api_version') && module_exists('panels_page')) {
      $version = panels_api_version();
      if ($version[0] == 2 && $version[1] == 0) {
        $panel = db_fetch_array(db_query("SELECT * FROM {panels_page} WHERE path = '%s'", $_GET['q']));
      }
    }
    else {
      if (db_table_exists('panels_info')) {
        $panel = db_fetch_array(db_query("SELECT * FROM {panels_info} WHERE path = '%s'", $_GET['q']));
      }
    }
    if ($panel) {
      return array(
        'type' => 'panels',
        'ids' => array(
          $panel['did'],
        ),
      );
    }
  }
  if (module_exists('views') && drupal_strlen($_GET['q']) > 0) {
    static $views_urls;

    // Get all urls from views cache.
    if (!is_array($views_urls)) {
      $views_urls = array_flip(array_filter(views_get_all_urls()));
    }

    // Check for exact match first.
    if (isset($views_urls[$_GET['q']])) {
      $view = views_get_view($views_urls[$_GET['q']]);
      return array(
        'type' => 'views',
        'ids' => array(
          $view->vid,
        ),
      );
    }

    // Check for views that begin with current url.
    foreach ($views_urls as $view_url => $view_name) {
      if (0 === strpos($view_url, $_GET['q'])) {
        $view = views_get_view($view_name);
        return array(
          'type' => 'views',
          'ids' => array(
            $view->vid,
          ),
        );
      }
    }
  }
  switch (arg(0)) {
    case 'node':

      // Node paths: node/$nid
      if (is_numeric(arg(1)) && !arg(2)) {
        return array(
          'type' => 'node',
          'ids' => arg(1),
        );
      }
      break;
    case 'user':

      // User paths translated into nodes: user/$uid -> node/$bio_nid
      if (is_numeric(arg(1)) && module_exists('bio') && variable_get('bio_profile_takeover', 0)) {
        if ($bio_nid = bio_for_user(arg(1))) {
          return array(
            'type' => 'node',
            'ids' => $bio_nid,
          );
        }
      }
      break;
    case 'taxonomy':

      // Taxonomy paths: term/$tid , term/$tid1+$tid2 , vocabulary/$vid
      if (arg(1) == 'term' || arg(1) == 'vocabulary') {
        $ids = preg_split('![+, ]!', arg(2));
        if (count($ids)) {
          return array(
            'type' => arg(1),
            'ids' => $ids,
          );
        }
      }
      break;
    case 'forum':

      // Forum paths: forum/$tid , forum/
      if (is_numeric(arg(1))) {
        return array(
          'type' => 'term',
          'ids' => arg(1),
        );
      }
      elseif (is_null(arg(1))) {
        return array(
          'type' => 'vocabulary',
          'ids' => variable_get('forum_nav_vocabulary', 0),
        );
      }
      break;
    case 'image':

      // Image gallery paths: image/ , image/???/$tid
      if (is_null(arg(1))) {
        return array(
          'type' => 'vocabulary',
          'ids' => variable_get('image_gallery_nav_vocabulary', 0),
        );
      }
      else {
        if (is_numeric(arg(2))) {
          return array(
            'type' => 'term',
            'ids' => arg(2),
          );
        }
      }
      break;
    case 'taxonomy_menu':

      // Taxonomy menu paths: taxonomy_menu/$vid, taxonomy_menu/$vid/$tid
      if (!is_null(arg(2)) && is_numeric(arg(2))) {
        return array(
          'type' => 'term',
          'ids' => arg(2),
        );
      }
      else {
        if (is_numeric(arg(1))) {
          return array(
            'type' => 'vocabulary',
            'ids' => arg(1),
          );
        }
      }
      break;
  }
  return array(
    'type' => 'none',
    'ids' => array(),
  );
}

/**
 * Invoke a hook_nodewords() operation in all modules.
 *
 * @param &$tags
 *   A tags object.
 * @param $op
 *   A string containing the name of the nodewords operation ('prepare' => prepares the
 *   tags before output).
 * @param $a3, $a4
 *   Additional parameters to pass through this hook (for 'prepare': $a3 is the type of
 *   page ('node', 'taxonomy', ...) and $a4 is an array of ids of the page of this type).
 * @return
 *   The returned value of the invoked hooks.
 */
function _nodewords_invoke(&$tags, $op, $a3, $a4) {
  $return = array();
  foreach (module_implements('nodewords') as $name) {
    $function = $name . '_nodewords';
    $result = $function($tags, $op, $a3, $a4);
    if (isset($result) && is_array($result)) {
      $return = array_merge($return, $result);
    }
    else {
      if (isset($result)) {
        $return[] = $result;
      }
    }
  }
  return $return;
}

/**
 * Create the correct function name to call for builtin tags.
 */
function _nodewords_get_builtin_function($tag, $name) {
  return 'nodewords_' . strtr(strtolower($tag), '.-', '__') . '_' . $name;
}

Functions

Namesort descending Description
nodewords_block Implementation of hook_block().
nodewords_form_alter Implementation of hook_form_alter().
nodewords_frontpage_form Menu callback: front page settings form.
nodewords_frontpage_form_submit
nodewords_get Get the defined meta tags for $type / $id.
nodewords_help Implemenation of hook_help().
nodewords_menu Implementation of hook_menu().
nodewords_nodeapi Implementation of hook_nodeapi().
nodewords_nodewords Implementation of hook_nodewords().
nodewords_panels_handler Handling of edit/delete form for panels.
nodewords_panels_page_handler Handling of edit/delete form for panels (v2).
nodewords_perm Implementation of hook_perm().
nodewords_settings_form Menu callback: settings form.
nodewords_taxonomy Implementation of hook_taxonomy().
nodewords_token_list Implementation of hook_token_list().
nodewords_token_values Implementation of hook_token_values().
nodewords_views_handler Handling of edit/delete form for views.
theme_nodewords_content Displays the defined meta tags $tags as content, eg in a block or body.
_nodewords_check_content Remove any content from the $tag that is not allowed in a meta content attribute.
_nodewords_delete Delete tags from table
_nodewords_delete_tag Delete one tag
_nodewords_detect_type_and_ids Try to guess the $type and $ids by looking at $_GET['q'].
_nodewords_filter_viewable Remove the meta tags from $tags that the user chose not to show.
_nodewords_form Create a form - returns a $form variable
_nodewords_get_builtin_function Create the correct function name to call for builtin tags.
_nodewords_get_builtin_tags Return a list of builtin tags from the metatags/ directory.
_nodewords_get_possible_tags Return a list of possible output tags
_nodewords_get_settings Load default and user-defined settings. If $defaults => default settings are returned.
_nodewords_get_viewable_tags Return a list of viewable output tags
_nodewords_invoke Invoke a hook_nodewords() operation in all modules.
_nodewords_load Load tags from table
_nodewords_prepare Prepare the tags so they are ready for output. This includes:
_nodewords_set Update or insert tags in the table
_nodewords_update_tag Set one tag