home | career | drupal | java | mac | mysql | perl | php | scala | uml | unix

Drupal example source code file (nodewords.module)

This example Drupal source code file (nodewords.module) is included in the DevDaily.com "Drupal Source Code Warehouse" project. The intent of this project is to help you "Learn Drupal by Example".

PHP - Drupal tags/keywords

array, file, form, function, if, isset, meta, page, php, result, return, tags, type, variable

The nodewords.module Drupal example source code

<?php
// $Id: nodewords.module,v 1.57.2.282 2009/12/31 01:22:06 kiam Exp $

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

/**
 * @addtogroup nodewords
 * @{
 */

/**
 * The minimum API version supported.
 */
define('NODEWORDS_MINIMUM_API_VERSION', '1.9');

/**
 * The current API version implemented.
 */
define('NODEWORDS_API_VERSION', '1.9');

/**
 * The type of objects to which the meta tags are associated.
 */
define('NODEWORDS_TYPE_DEFAULT',    1);
define('NODEWORDS_TYPE_ERRORPAGE',  2);
define('NODEWORDS_TYPE_FRONTPAGE',  3);
define('NODEWORDS_TYPE_NONE',       0);
define('NODEWORDS_TYPE_NODE',       5);
define('NODEWORDS_TYPE_PAGE',      10);
define('NODEWORDS_TYPE_PAGER',      4);
define('NODEWORDS_TYPE_TERM',       6);
define('NODEWORDS_TYPE_TRACKER',    7);
define('NODEWORDS_TYPE_USER',       8);
define('NODEWORDS_TYPE_VOCABULARY', 9);

/**
 * The types of meta tags the module is able to handle.
 */
define('NODEWORDS_META', 0);
define('NODEWORDS_HTTP_EQUIV', 1);
define('NODEWORDS_LINK_REL', 2);
define('NODEWORDS_LINK_REV', 3);

define('NODEWORDS_GENERATION_NONE', 0);
define('NODEWORDS_GENERATION_WHEN_EMPTY', 1);

define('NODEWORDS_GENERATION_BODY', 1);
define('NODEWORDS_GENERATION_TEASER', 2);
define('NODEWORDS_GENERATION_TEASER_BODY', 3);

/**
 * Implements hook_content_extra_fields().
 * Allow the meta tags fields to be sorted in the node edit forms.
 */
function nodewords_content_extra_fields() {
  $extras = array();

  $extras['nodewords'] = array(
    'label' => t('Meta tags'),
    'description' => t('Meta tags fieldset.'),
    'weight' => 10,
  );

  return $extras;
}

/**
 * Implements hook_form_alter().
 */
function nodewords_form_alter(&$form, &$form_state, $form_id) {
  $bool = (
    isset($form['type']) &&
    isset($form['type']['#value']) &&
    $form_id == $form['type']['#value'] . '_node_form' &&
    isset($form['#node']) &&
    variable_get('nodewords_edit_metatags_' . $form['type']['#value'], TRUE)
  );

  if ($bool) {
    $node = $form['#node'];

    $form['nodewords'] = nodewords_form(
      NODEWORDS_TYPE_NODE,
      !empty($node->nodewords) ? $node->nodewords : array(),
      array(
        'tag_options' => array('node_type' => $form['type']['#value']),
      )
    );
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function nodewords_form_node_type_form_alter(&$form, &$form_state) {
  if (isset($form['#node_type'])) {

    $form['nodewords'] = array(
      '#type' => 'fieldset',
      '#title' => t('Meta tags settings'),
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
      '#group' => 'additional_settings',
    );

    $form['nodewords']['nodewords_edit_metatags'] = array(
      '#type' => 'checkbox',
      '#title' => t('Allow editing of meta tags'),
      '#description' => t('If selected, the node edit form will allow the users with the right permissions to edit the meta tags associated with nodes of this content type.'),
      '#default_value' => variable_get('nodewords_edit_metatags_' . $form['#node_type']->type, TRUE),
    );

    $form['nodewords']['metatags_generation'] = array(
      '#type' => 'fieldset',
      '#title' => t('Meta tags content generation options'),
      '#description' => t('These options change how a meta tag content is generated from the node content. These settings apply to specific meta tags.'),
      '#collapsible' => TRUE,
    );

    $options = array(
      NODEWORDS_GENERATION_NONE => t('Do not generate meta tags content'),
      NODEWORDS_GENERATION_WHEN_EMPTY => t('Generate meta tag content when the meta tag content is empty'),
    );

    $form['nodewords']['metatags_generation']['nodewords_metatags_generation_method'] = array(
      '#type' => 'radios',
      '#options' => $options,
      '#default_value' => variable_get(
        'nodewords_metatags_generation_method_' . $form['#node_type']->type,
        variable_get('nodewords_metatags_generation_method', NODEWORDS_GENERATION_NONE)
      ),
    );

    $options = array(
      NODEWORDS_GENERATION_BODY => t('Generate meta tags content from the node body'),
      NODEWORDS_GENERATION_TEASER => t('Generate meta tags content from the node teaser'),
      NODEWORDS_GENERATION_TEASER_BODY => t('Generate meta tags content from the node teaser, or the node body when the node teaser is empty'),
    );

    $form['nodewords']['metatags_generation']['nodewords_metatags_generation_source'] = array(
      '#type' => 'radios',
      '#title' => t('Generation source'),
      '#options' => $options,
      '#default_value' => variable_get(
        'nodewords_metatags_generation_source_' . $form['#node_type']->type,
        variable_get('nodewords_metatags_generation_source', NODEWORDS_GENERATION_TEASER)
      ),
    );

    $form['nodewords']['metatags_generation']['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_' . $form['#node_type']->type,
        variable_get('nodewords_use_alt_attribute', TRUE)
      ),
    );

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

    $form['nodewords']['metatags_generation']['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_' . $form['#node_type']->type,
        variable_get('nodewords_filter_modules_output', array())
      ),
      '#checkall' => TRUE,
    );

    $form['nodewords']['metatags_generation']['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_filter_regexp_validate'),
      '#default_value' => variable_get(
        'nodewords_filter_regexp_' . $form['#node_type']->type,
        variable_get('nodewords_filter_regexp', '')
      ),
      '#size' => 60,
    );

    foreach (nodewords_get_possible_tags() as $name => $info) {
      $function = $info['tag:function:prefix'] . '_settings_form';
      $options = array(
        'parameters' => !empty($info['tag:function:parameters']) ? $info['tag:function:parameters'] : array(),
      );

      if (function_exists($function)) {
        $function($form, 'node_type_form', $options);
      }
    }
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function nodewords_form_taxonomy_form_term_alter(&$form, &$form_state) {
  $bool = (isset($form['tid']['#value']) &&
    !isset($form_state['confirm_delete']) &&
    !isset($form_state['confirm_parents'])
  );

  if ($bool) {
    $id = $form['tid']['#value'];

    if (!empty($form_state['values']['nodewords'])) {
      $tags = $form_state['values']['nodewords'];
    }
    elseif (isset($id) && is_numeric($id)) {
      $tags = nodewords_load_tags(NODEWORDS_TYPE_TERM, $id);
    }
    else {
      $tags = array();
    }

    $form['nodewords'] = nodewords_form(
      NODEWORDS_TYPE_TERM,
      $tags
    );

    $form['submit']['#weight'] = 45;
    $form['delete']['#weight'] = 50;
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function nodewords_form_taxonomy_form_vocabulary_alter(&$form, &$form_state) {
  if (isset($form['vid']['#value'])) {
    $id = $form['vid']['#value'];

    if (!empty($form_state['values']['nodewords'])) {
      $tags = $form_state['values']['nodewords'];
    }
    elseif (isset($id) && is_numeric($id)) {
      $tags = nodewords_load_tags(NODEWORDS_TYPE_VOCABULARY, $id);
    }
    else {
      $tags = array();
    }

    $form['nodewords'] = nodewords_form(
      NODEWORDS_TYPE_VOCABULARY,
      $tags
    );

    $form['submit']['#weight'] = 45;
    $form['delete']['#weight'] = 50;
  }
}

/**
 *  Implemenation of hook_help().
 */
function nodewords_help($path, $arg) {
  switch ($path) {
    case 'admin/content/nodewords/meta-tags':
      $output = '<p>' . t('On this page you can enter the default values for the meta tags of your site.') . '</p>';
      break;

    case 'admin/content/nodewords/meta-tags/errorpage_403':
      $output = '<p>' . t('On this page you can enter the meta tags for the <q>access denied</q> error page of your site.') . '</p>';
      break;

    case 'admin/content/nodewords/meta-tags/errorpage_404':
      $output = '<p>' . t('On this page you can enter the meta tags for the <q>page not found</q> error page of your site.') . '</p>';
      break;

    case 'admin/content/nodewords/meta-tags/frontpage':
      $output = '<p>' . t('On this page you can enter the meta tags for the front page of your site.') . '</p>';
      break;

    case 'admin/content/nodewords/meta-tags/other':
      $output = '<p>' . t('On this page you can enter the meta tags for other pages of your site. The meta tags set in these page are used before the ones set for nodes or user profiles, and they can ovverride those meta tags.') . '</p>';
      break;

    case 'admin/content/nodewords/meta-tags/tracker':
      $output = '<p>' . t('On this page you can enter the meta tags for tracker pages of your site.') . '</p>';
      break;

    default:
      $output = '';
      break;
  }

  return $output;
}

/**
 * Implements hook_menu().
 */
function nodewords_menu() {
  $admin_access = array('administer meta tags');
  $items = array();

  $items['admin/content/nodewords'] = array(
    'title' => 'Meta tags',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('nodewords_settings_form'),
    'description' => 'Configure HTML meta tags for all the content.',
    'access arguments' => $admin_access,
    'type' => MENU_NORMAL_ITEM,
    'file' => 'nodewords.admin.inc',
  );

  $items['admin/content/nodewords/settings'] = array(
    'title' => 'Settings',
    'access arguments' => $admin_access,
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -1,
    'file' => 'nodewords.admin.inc',
  );

  $items['admin/content/nodewords/meta-tags'] = array(
    'title' => 'Default and specific meta tags',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('nodewords_tags_form'),
    'access arguments' => $admin_access,
    'type' => MENU_LOCAL_TASK,
    'file' => 'nodewords.admin.inc',
  );

  $items['admin/content/nodewords/meta-tags/default'] = array(
    'title' => 'Default values',
    'access arguments' => $admin_access,
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'file' => 'nodewords.admin.inc',
  );

  $items['admin/content/nodewords/meta-tags/errorpage_403'] = array(
    'title' => 'Error 403 page',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('nodewords_tags_form', (string) NODEWORDS_TYPE_ERRORPAGE, '403'),
    'access arguments' => $admin_access,
    'type' => MENU_LOCAL_TASK,
    'file' => 'nodewords.admin.inc',
  );

  $items['admin/content/nodewords/meta-tags/errorpage_404'] = array(
    'title' => 'Error 404 page',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('nodewords_tags_form', (string) NODEWORDS_TYPE_ERRORPAGE, '404'),
    'access arguments' => $admin_access,
    'type' => MENU_LOCAL_TASK,
    'file' => 'nodewords.admin.inc',
  );

  $items['admin/content/nodewords/meta-tags/frontpage'] = array(
    'title' => 'Front page',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('nodewords_tags_form', (string) NODEWORDS_TYPE_FRONTPAGE),
    'access arguments' => $admin_access,
    'type' => MENU_LOCAL_TASK,
    'file' => 'nodewords.admin.inc',
  );

  $items['admin/content/nodewords/meta-tags/tracker'] = array(
    'title' => 'Tracker pages',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('nodewords_tags_form', (string) NODEWORDS_TYPE_TRACKER),
    'access arguments' => $admin_access,
    'type' => MENU_LOCAL_TASK,
    'file' => 'nodewords.admin.inc',
  );

  $items['admin/content/nodewords/meta-tags/other'] = array(
    'title' => 'Other pages',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('nodewords_pages_overview'),
    'access arguments' => $admin_access,
    'type' => MENU_LOCAL_TASK,
    'weight' => 5,
    'file' => 'nodewords.admin.inc',
  );

  $items['admin/content/nodewords/meta-tags/other/add'] = array(
    'title' => 'Add page meta tags',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('nodewords_pages_edit'),
    'access arguments' => $admin_access,
    'type' => MENU_CALLBACK,
    'file' => 'nodewords.admin.inc',
  );

  $items['admin/content/nodewords/meta-tags/other/delete/%nodewords_page'] = array(
    'title' => 'Delete page meta tags',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('nodewords_pages_confirm_delete', 6),
    'access arguments' => $admin_access,
    'parent' => 'admin/content/nodewords/meta-tags/other',
    'type' => MENU_CALLBACK,
    'file' => 'nodewords.admin.inc',
  );

  $items['admin/content/nodewords/meta-tags/other/edit/%nodewords_page'] = array(
    'title' => 'Edit page meta tags',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('nodewords_pages_edit', 6),
    'access arguments' => $admin_access,
    'parent' => 'admin/content/nodewords/meta-tags/other',
    'type' => MENU_CALLBACK,
    'file' => 'nodewords.admin.inc',
  );

  return $items;
}

/**
 * Implements hook_node_operations().
 */
function nodewords_node_operations() {
  $operations = array(
    'delete_metatags' => array(
      'label' => t('Delete meta tags'),
      'callback' => 'nodewords_mass_delete_tags',
      'callback arguments' => array('type' => NODEWORDS_TYPE_NODE),
    ),
  );

  return $operations;
}

/**
 * Implements hook_node_type().
 */
function nodewords_node_type($op, $info) {
  if ($op == 'delete') {
    $variables = array(
      'nodewords_metatags_generation_method_',
      'nodewords_metatags_generation_source_',
      'nodewords_edit_metatags_',
      'nodewords_filter_modules_output_',
      'nodewords_filter_regexp_',
      'nodewords_use_teaser_',
    );

    foreach ($variables as $variable) {
      variable_del($variable . $info->type);
    }
  }
}

/**
 * Implements hook_nodeapi().
 */
function nodewords_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
  switch ($op) {
    case 'delete':
      nodewords_delete_tags(NODEWORDS_TYPE_NODE, $node->nid);
      break;

    case 'insert':
    case 'update':
      if (isset($node->nodewords)) {
        nodewords_save_tags(NODEWORDS_TYPE_NODE, $node->nid, $node->nodewords, TRUE);
      }
      break;

    case 'load':
      return array(
        'nodewords' => nodewords_load_tags(NODEWORDS_TYPE_NODE, $node->nid),
      );

    case 'prepare translation':
      if (isset($node->translation_source->nodewords)) {
        $node->nodewords = $node->translation_source->nodewords;
      }
      break;

    case 'update index':
      $output_tags = array();
      $tag_options = array(
        'type' => NODEWORDS_TYPE_NODE,
        'ids' => array($node->nid),
        'output' => 'update index',
      );

      if (isset($node->nodewords)) {
        // Prepare the tags.
        foreach (nodewords_get_possible_tags() as $name => $info) {
          $bool = (
            !empty($info['tag:template:index']) &&
            function_exists($function = $info['tag:function:prefix'] . '_prepare')
          );

          if ($bool) {
            $tag_options['parameters'] = !empty($info['tag:function:parameters']) ? $info['tag:function:parameters'] : array();

            $function(
              $output_tags,
              isset($node->nodewords[$name]) ? $node->nodewords[$name] : array(),
              $tag_options
            );
          }
        }

        drupal_alter('nodewords_tags', $output_tags, $tag_options);
        $output = nodewords_output_tags($output_tags, 'update index');
        drupal_alter('nodewords_tags_output', $output, $tag_options);

        return $output;
      }

      return '';
  }
}

/**
 * Implements hook_perm().
 */
function nodewords_perm() {
  return array('administer meta tags');
}

/**
 * Implements hook_preprocess_page().
 */
function nodewords_preprocess_page(&$variables) {
  $result = _nodewords_detect_type_and_ids();

  $tags = nodewords_get_tags($result[0], $result[1]);
  $parameters = array(
    'type' => $result[0],
    'ids' => $result[1],
    'output' => 'head',
  );

  drupal_alter('nodewords_tags', $tags, $parameters);
  $output = nodewords_output_tags($tags);
  drupal_alter('nodewords_tags_output', $output, $parameters);

  $variables['head'] = "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n" .
    $output . "\n" . 
    drupal_set_html_head();
}

/**
 * Implements hook_taxonomy().
 */
function nodewords_taxonomy($op, $type, $object = NULL) {
  if ($type == NODEWORDS_TYPE_TERM) {
    $id = $object['tid'];
  }
  elseif ($type == NODEWORDS_TYPE_VOCABULARY) {
    $id = $object['vid'];
  }
  else {
    return;
  }

  switch ($op) {
    case 'delete':
      nodewords_delete_tags($type, $id);
      break;

    case 'insert':
    case 'update':
      if (isset($object['nodewords'])) {
        nodewords_save_tags($type, $id, $object['nodewords'], TRUE);
      }
      break;
  }
}

/**
 * Implements hook_theme().
 */
function nodewords_theme() {
  return array(
    'nodewords_pages_overview' => array(
      'arguments' => array('form' => array()),
      'file' => 'nodewords.admin.inc',
    ),
  );
}

/**
 * Implements hook_user().
 */
function nodewords_user($op, &$edit, &$account, $category = NULL) {
  switch ($op) {
    case 'load':
      if (variable_get('nodewords_enable_user_metatags', TRUE)) {
        $account->nodewords = nodewords_load_tags(NODEWORDS_TYPE_USER, $account->uid);
      }
      break;

    case 'delete':
      nodewords_delete_tags(NODEWORDS_TYPE_USER, $account->uid);
      break;

    case 'insert':
    case 'update':
      if (isset($edit['nodewords'])) {
        nodewords_save_tags(NODEWORDS_TYPE_USER, $account->uid, $edit['nodewords'], TRUE);
      }
      break;

    case 'form':
      if ($category == 'account') {
        if (variable_get('nodewords_enable_user_metatags', TRUE)) {
          $tags = nodewords_load_tags(NODEWORDS_TYPE_USER, $account->uid);
          $form['nodewords'] = nodewords_form(
            NODEWORDS_TYPE_USER,
            $tags
          );

          return $form;
        }
      }
      break;
  }
}

/**
 * Implements hook_user_operations().
 */
function nodewords_user_operations() {
  $operations = array(
    'delete_metatags' => array(
      'label' => t('Delete meta tags'),
      'callback' => 'nodewords_mass_delete_tags',
      'callback arguments' => array('type' => NODEWORDS_TYPE_USER),
    ),
  );

  return $operations;
}

/**
 * Delete tags from table.
 */
function nodewords_delete_tags($type, $id) {
  db_query("DELETE FROM {nodewords} WHERE type = %d AND id = %d", $type, $id);

  if ($type == NODEWORDS_TYPE_PAGE) {
    db_query("DELETE FROM {nodewords_custom} WHERE pid = %d", $id);
  }
}

/**
 * Return the form used to set the meta tags values.
 *
 * @param $type
 *   The object to which the meta tags are associated (node, user, taxonomy
 *   term, etc...).
 * @param $tags
 *   The meta tags array as returned by nodewords_load_tags().
 *
 * @return
 *   An array as requested by the form API.
 */
function nodewords_form($type, $tags, $options = array()) {
  $default_options = array(
    'fieldset' => TRUE,
    'fieldset:title' => t('Meta tags'),
    'fieldset:weight' => 20,
    'page:permissions:see_all_tags' => 'administer meta tags',
  );
  $default_tag_options = array(
    'default' => nodewords_load_tags(),
    'type' => $type,
  );
  $edit_tags = variable_get('nodewords_edit', array());
  $form = array();
  $options += $default_options;

  if (isset($options['tag_options']) && is_array($options['tag_options'])) {
    $tag_options = $options['tag_options'] + $default_tag_options;
  }
  else {
    $tag_options = $default_tag_options;
  }

  $tags_info = nodewords_get_possible_tags();

  foreach ($tags_info as $name => $info) {
    $bool = (
      (
        $options['page:permissions:see_all_tags'] &&
        user_access($options['page:permissions:see_all_tags'])
      ) ||
      !empty($edit_tags[$name])
    );

    if ($bool) {
      $bool = (
        (
          !empty($info['tag:context:allowed']) &&
          is_array($info['tag:context:allowed']) &&
          !in_array($type, $info['tag:context:allowed'])
        ) ||
        (
          !empty($info['tag:context:denied']) &&
          is_array($info['tag:context:denied']) &&
          in_array($type, $info['tag:context:denied'])
        )
      );

      if ($bool) {
        continue;
      }

      $bool = (
        (
          $options['page:permissions:see_all_tags'] &&
          user_access($options['page:permissions:see_all_tags'])
        ) ||
        (
          !empty($info['widget:permission']) &&
          user_access($info['widget:permission'])
        )
      );

      if ($bool) {
        if (function_exists($function = $info['tag:function:prefix'] . '_form')) {
          $tag_options['parameters'] = !empty($info['tag:function:parameters']) ? $info['tag:function:parameters'] : array();

          $function($form, isset($tags[$name]) ? $tags[$name] : array(), $tag_options);
        }
      }
    }
  }

  if (!empty($form) && $options['fieldset']) {
    $form['#type'] = 'fieldset';
    $form['#title'] = $options['fieldset:title'];
    $form['#tree'] = TRUE;
    $form['#collapsible'] = TRUE;
    $form['#collapsed'] = TRUE;
    $form['#weight'] = $options['fieldset:weight'];
    $form['#group'] = 'additional_settings';
  }

  return $form;
}

/**
 * Return a list of possible output tags.
 *
 * @return
 *   An array containing the list of meta tags.
 */
function nodewords_get_possible_tags() {
  static $tags_info;


  if (empty($tags_info)) {
    $tags_info = array();

    // Allow third-party modules to alter the  meta tags list, or to add new
    // meta tags.
    foreach (module_implements('nodewords_tags_info') as $module) {
      if (module_hook($module, 'nodewords_api')) {
        $result = module_invoke($module, 'nodewords_api');
        $version = 0;

        if (isset($result)) {
          if (is_numeric($result)) {
            $version = $result;
          }
          elseif (is_array($result) && isset($result['version'])) {
            $version = $result['version'];
          }
        }

        $bool = (
          version_compare($version, NODEWORDS_MINIMUM_API_VERSION, '<') ||
          version_compare($version, NODEWORDS_API_VERSION, '>')
        );

        if ($bool) {
          continue;
        }

        $result = module_invoke($module, 'nodewords_tags_info');

        if (isset($result) && is_array($result)) {
          $tags_info = array_merge($tags_info, $result);
        }
      }
    }
  }

  return $tags_info;
}

/**
 * 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: NODEWORDS_TYPE_ERRORPAGE, NODEWORDS_TYPE_FRONTPAGE, NODEWORDS_TYPE_NODE,
 *     NODEWORDS_TYPE_PAGE, NODEWORDS_TYPE_TERM, NODEWORDS_TYPE_TRACKER, NODEWORDS_TYPE_VOCABULARY.
 * @param $ids
 *     ID of the object to get the meta tags from.
 *     This is one of the following:
 *     - NODEWORDS_TYPE_ERRORPAGE => an array containing the HTML error code (403 or 404).
 *     - NODEWORDS_TYPE_FRONTPAGE => none.
 *     - NODEWORDS_TYPE_NODE => an array containing the node ID.
 *     - NODEWORDS_TYPE_PAGE => an array containing the page path.
 *     - NODEWORDS_TYPE_TERM => an array of term IDs.
 *     - NODEWORDS_TYPE_USER => an array containing the user ID.
 *     - NODEWORDS_TYPE_VOCABULARY => an array of vocabulary IDs.
 * @param $options
 *   An array of additional options. Currently the only defined is 'filter',
 *   which filter the list of meta tags to the enabled ones.
 *
 * @return
 *   An associative array of the defined meta tags.
 */
function nodewords_get_tags($type, $ids = array(0), $options = array()) {
  $default_options = array(
    'filter' => TRUE,
  );
  $head_tags = variable_get('nodewords_head', array());
  $options += $default_options;
  $output_tags = array();

  if (!is_array($ids)) {
    $ids = array($ids);
  }

  $tag_options = array(
    'default' => nodewords_load_tags(),
    'type' => $type,
    'ids' => $ids,
  );

  if ($type == NODEWORDS_TYPE_PAGER) {
    foreach (nodewords_get_possible_tags() as $name => $info) {
      // Filter out tags the user has chosen not to see
      if ($options['filter'] && empty($head_tags[$name])) {
        continue;
      }

      $bool = (
        !empty($info['tag:context:allowed']) &&
        in_array(NODEWORDS_TYPE_PAGER, $info['tag:context:allowed']) &&
        function_exists($function = $info['tag:function:prefix'] . '_prepare')
      );

      if ($bool) {
        $tag_options['parameters'] = !empty($info['tag:function:parameters']) ? $info['tag:function:parameters'] : array();

        $function($output_tags, array(), $tag_options);
      }
    }
  }
  else {
    // User profiles meta tags are not enabled.
    if ($type == NODEWORDS_TYPE_USER && !variable_get('nodewords_enable_user_metatags', TRUE)) {
      return array();
    }
    // Load the values from the database
    elseif (count($ids) == 1 && ($type != NODEWORDS_TYPE_NODE || node_access('view', node_load($ids[0])))) {
      $tags = nodewords_load_tags($type, $ids[0]);
    }
    else {
      $tags = array();
    }

    // Prepare the tags.
    foreach (nodewords_get_possible_tags() as $name => $info) {
      // Filter out tags the user has chosen not to see
      if ($options['filter'] && empty($head_tags[$name])) {
        continue;
      }

      if (function_exists($function = $info['tag:function:prefix'] . '_prepare')) {
        $tag_options['parameters'] = !empty($info['tag:function:parameters']) ? $info['tag:function:parameters'] : array();

        $function($output_tags, isset($tags[$name]) ? $tags[$name] : array(), $tag_options);
      }
    }
  }

  return $output_tags;
}

/**
 * Return the term object matching a term ID. This is a modified version of
 * taxonomy_get_term() which uses db_rewrite_sql().
 *
 * @param $tid
 *   A term's ID.
 *
 * @return
 *   A term object. Results are statically cached.
 */
function nodewords_get_term($tid) {
  global $user;
  static $previous_uid = -1, $terms = array();

  if ($user->uid <> $previous_uid) {
    $terms = array();
    $previous_uid = $user->uid;
  }

  if (!isset($terms[$tid])) {
    $terms[$tid] = db_fetch_object(
      db_query(
        db_rewrite_sql('SELECT * FROM {term_data} t WHERE t.tid = %d', 't', 'tid'),
        $tid
      )
    );
  }

  return $terms[$tid];
}

/**
 * Load tags from table.
 */
function nodewords_load_tags($type = NODEWORDS_TYPE_DEFAULT, $id = 0) {
  $result = db_query("SELECT * FROM {nodewords} WHERE type = %d AND id = %d", $type, $id);
  $tags = array();
  $tags_info = nodewords_get_possible_tags();

  while ($row = db_fetch_object($result)) {
    if (isset($tags_info[$row->name])) {
      $tags[$row->name] = unserialize($row->content);
    }
  }

  if (empty($tags) && $type == NODEWORDS_TYPE_TERM) {
    return nodewords_load_tags(NODEWORDS_TYPE_VOCABULARY, db_result(db_query('SELECT vid FROM {term_data} WHERE tid = %d', $id)));
  }

  return $tags;
}

/**
 * Delete the nodes meta tags.
 *
 * @param $ids
 *  An array of IDs.
 * @param $type
 *  The type of the object associated with the IDs (NODEWORDS_TYPE_NODE, NODEWORDS_TYPE_USER,
 *  NODEWORDS_TYPE_PAGER, NODEWORDS_TYPE_PAGE, ...).
 */
function nodewords_mass_delete_tags($ids, $type) {
  db_query("DELETE FROM {nodewords} WHERE id IN (" . db_placeholders($ids, 'int') . ") AND type = %d",
    array_merge($ids, array($type))
  );

  drupal_set_message(t('The update has been performed.'));
}

/**
 * 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; currently, the only used is the maximum allowed
 *  length.
 *
 * @return
 *   The string used as meta tag content.
 */
function nodewords_metatag_from_node_content($node, $content, $options = array()) {
  $default_options = array(
    'size' => variable_get('nodewords_max_size', 350),
  );
  $filters = filter_list_format($node->format);
  $method = variable_get(
    'nodewords_metatags_generation_method_' . $node->type,
    variable_get('nodewords_metatags_generation_method', NODEWORDS_GENERATION_NONE)
  );
  $options += $default_options;
  $result = '';
  $source = variable_get(
    'nodewords_metatags_generation_source_' . $node->type,
    variable_get('nodewords_metatags_generation_source', NODEWORDS_GENERATION_TEASER)
  );

  $bool = (
    $method == NODEWORDS_GENERATION_NONE ||
    (
      $method == NODEWORDS_GENERATION_WHEN_EMPTY && !empty($content)
    )
  );

  if ($bool) {
    return $content;
  }

  if ($source == NODEWORDS_GENERATION_TEASER) {
    // 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->teaser, '<?') !== FALSE) {
      $result = '';
    }
    else {
      // Replace the tag IMG with the attribute ALT, and strip off all the
      // HTML tags.
      $text = strip_tags(
        preg_replace_callback('/<img\s[^>]*alt=["\']([^"\']*)["\'][^>]*>/i',
          '_nodewords_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])) {
          $text = preg_replace($regexp, '', $text);
        }
      }

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


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

  $bool = (
    $source == NODEWORDS_GENERATION_BODY ||
    (
      $source == NODEWORDS_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.
    $text = strip_tags(
      preg_replace_callback('/<img\s[^>]*alt=["\']([^"\']*)["\'][^>]*>/i',
        '_nodewords_match_callback',
        $node->body
      )
    );

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

  return $result;
}

/**
 * Render the meta tag values as HTML.
 *
 * @param $tags
 *   An array of tags (as returned by nodewords_get_tags()).
 *
 * @param $output_type
 *  The type of output, 'head' (default), or 'update index'.
 *
 * @return
 *   A string containing the HTML output for the META tag.
 */
function nodewords_output_tags($tags, $output_type = 'head') {
  $output = array();
  $tags_info = nodewords_get_possible_tags();
  $weights = array();

  foreach ($tags as $name => $content) {
    if (empty($content)) {
      continue;
    }

    $parts = explode(':', $name);

    if (!isset($parts[1])) {
      $parts[1] = $parts[0];
    }

    if ($output_type == 'update index') {
      $bool = (
        isset($tags_info[$parts[0]]['tag:template:index'][$parts[1]]) &&
        ($meta_content = trim(check_plain(strip_tags(decode_entities($content)))))
      );

      if ($bool) {
        $replace = array(
          '%content' => $meta_content,
          '%attributes' => empty($tags_info[$parts[0]]['tag:attributes'][$parts[1]]) ? '' : drupal_attributes($tags_info[$parts[0]]['tag:attributes'][$parts[1]]),
        );
        $template = $tags_info[$parts[0]]['tag:template:index'][$parts[1]];
        $weight = isset($tags_info[$parts[0]]['tag:weight'][$parts[1]]) ? $tags_info[$parts[0]]['tag:weight'][$parts[1]] : 0;
      }
    }
    else {
      $bool = (
        isset($tags_info[$parts[0]]['tag:template'][$parts[1]]) &&
        ($meta_name = check_plain(strip_tags(decode_entities($parts[1])))) &&
        ($meta_content = trim(check_plain(strip_tags(decode_entities($content)))))
      );

      if ($bool) {
        $replace = array(
          '%name' => $meta_name,
          '%content' => $meta_content,
          '%attributes' => empty($tags_info[$parts[0]]['tag:attributes'][$parts[1]]) ? '' : drupal_attributes($tags_info[$parts[0]]['tag:attributes'][$parts[1]]),
        );
        $template = $tags_info[$parts[0]]['tag:template'][$parts[1]];
        $weight = isset($tags_info[$parts[0]]['tag:weight'][$parts[1]]) ? $tags_info[$parts[0]]['tag:weight'][$parts[1]] : 0;

        switch ($template) {
          case NODEWORDS_META:
            $template = '<meta name="%name" content="%content"%attributes />';
            break;

          case NODEWORDS_HTTP_EQUIV:
            $template = '<meta http-equiv="%name" content="%content"%attributes />';
            break;

          case NODEWORDS_LINK_REL:
            $template = '<link rel="%name" href="%content"%attributes />';
            break;

          case NODEWORDS_LINK_REV:
            $template = '<link rev="%name" href="%content"%attributes />';
            break;

          default:
            if (!is_string($template)) {
              $template = '';
            }
            break;
        }
      }
    }

    if (!empty($template)) {
      $output[] = strtr($template, $replace);
      $weights[] = $weight;
    }
  }

  if (count($output)) {
    array_multisort($weights, $output);

    return implode("\n", $output);
  }
  else {
    return '';
  }
}

/**
 * This function is used from the menu system when a menu callback path contains
 * %nodewords_page_load.
 */
function nodewords_page_load($pid) {
  return _nodewords_get_pages_data($pid);
}

/**
 * Update or insert tags in the table.
 */
function nodewords_save_tags($type, $id, $tags, $log_message = FALSE) {
  global $user;

  $done = FALSE;
  $tags_info = nodewords_get_possible_tags();

  foreach ($tags as $name => $content) {
    if (isset($tags_info[$name])) {
      $content = serialize($content);
      $result = db_fetch_object(db_query("SELECT * FROM {nodewords} WHERE type = %d AND id = %d AND name = '%s'", $type, $id, $name));

      if ($result === FALSE) {
        $row = new stdClass();
        $row->type = $type;
        $row->id = $id;
        $row->name = $name;
      }
      else {
        $row = $result;
      }

      $row->content = $content;

      drupal_write_record('nodewords', $row, $result !== FALSE ? 'mtid' : array());

      if (!$done) {
        watchdog('nodewords', 'User %name changed the meta tags for type %type (%id).', array('%name' => $user->name, '%type' => $type, '%id' => $id));
        $done = TRUE;
      }
    }
  }
}

/*
 * Remove the duplicates from a list of items separated from the separator,
 * preserving the order in which they appear.
 * @param $text
 *   The string containing the list of items concatenated using $separator.
 * @param $separator
 *   The string used to split the string into an array. A space will be appended
 *   to the string before it is used to create the string from the array of
 *   unique items found in the string passed as argument.
 * @param $max_items
 *   The maximum number of items accepted in the returned array; the default
 *   value is -1, which means no limit.
 *
 * @return
 *   A string containing only unique items present in the string of concatenated
 *   items.
 */
function nodewords_unique($text, $separator = ',', $max_items = -1) {
  $lc_values = array();
  $unique_values = array();

  if (empty($text)) {
    return '';
  }

  foreach (array_filter(array_map('trim', explode($separator, $text))) as $item) {
    $lowercase = drupal_strtolower($item);

    if (!in_array($lowercase, $lc_values)) {
      $lc_values[] = $lowercase;
      $unique_values[] = $item;
    }
  }

  if ($max_items > 0) {
    $unique_values = array_slice($uniq_values, 0, $max_items);
  }

  return implode("$separator ", $unique_values);
}

/**
 * Try to guess the $type and $ids by looking at $_GET['q'].
 */
function _nodewords_detect_type_and_ids() {
  $arg = arg();

  if (variable_get('site_offline', 0) && !user_access('administer site configuration')) {
    return array(NODEWORDS_TYPE_NONE, 0);
  }

  $headers = drupal_get_headers();

  if (preg_match('@HTTP/1\.[01]\x20+403@', $headers)) {
    return array(NODEWORDS_TYPE_ERRORPAGE, '403');
  }

  if (preg_match('@HTTP/1\.[01]\x20+404@', $headers)) {
    return array(NODEWORDS_TYPE_ERRORPAGE, '404');
  }

  $bool = (
    !variable_get('nodewords_list_repeat', FALSE) &&
    isset($_REQUEST['page']) &&
    intval($_REQUEST['page']) > 0
  );

  if ($bool) {
    return array(NODEWORDS_TYPE_PAGER, '');
  }

  if (drupal_is_front_page() && variable_get('nodewords_use_frontpage_tags', TRUE)) {
    return array(NODEWORDS_TYPE_FRONTPAGE, '');
  }

  foreach (_nodewords_get_pages_data() as $page) {
    $path = $page->path;

    if (drupal_match_path($_GET['q'], $path)) {
      return array(NODEWORDS_TYPE_PAGE, $path);
    }

    $bool = (
      ($alias = drupal_get_path_alias($_GET['q'])) != $_GET['q'] &&
      drupal_match_path($alias, $path)
    );

    if ($bool) {
      return array(NODEWORDS_TYPE_PAGE, $page->pid);
    }
  }

  if (!isset($arg[0])) {
    return array(NODEWORDS_TYPE_NONE, 0);
  }

  _nodewords_load_all_includes();

  foreach (module_implements('nodewords_type_id') as $module) {
    $result = module_invoke($module, 'nodewords_type_id', $arg);

    if (isset($result) && is_array($result) && count($result) >= 2) {
      return $result;
    }
  }

  return array(NODEWORDS_TYPE_NONE, 0);
}

/**
 * Load the page meta tags data from the cache.
 *
 * @param $id
 *   The ID of the page to load; by default the function loads all the custom
 *   pages data.
 */
function _nodewords_get_pages_data($id = NULL) {
  static $pages;

  if (!isset($pages)) {
    $pages = array();
    $result = db_query("SELECT * FROM {nodewords_custom} ORDER BY weight ASC");

    while ($page = db_fetch_object($result)) {
      $page->tags = nodewords_load_tags(NODEWORDS_TYPE_PAGE, $page->path);

      $pages[$page->pid] = $page;
    }
  }

  return isset($id) ? (isset($pages[$id]) ? $pages[$id] : FALSE) : $pages;
}

/**
 * Load the files in the directory "includes" basing on the modules enabled.
 *
 */
function _nodewords_load_all_includes() {
  $dir = drupal_get_path('module', 'nodewords') . '/includes';

  foreach (file_scan_directory($dir, '.*\.inc', array('.', '..', 'CVS'), 0, FALSE) as $filename => $info) {
    if (module_exists($info->name)) {
      module_load_include('inc', 'nodewords', 'includes/' . $info->name);
    }
  }
}

/**
 * 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_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 '';
}

/**
 * @} End of "addtogroup nodewords".
 */

Other Drupal examples (source code examples)

Here is a short list of links related to this Drupal nodewords.module source code file:

new blog posts

"Drupal" is a registered trademark of Dries Buytaert.

my drupal tutorials and examples  

Copyright 1998-2016 Alvin Alexander, alvinalexander.com
All Rights Reserved.

Beginning in 2016, a portion of the proceeds from pages under the '/drupal-code-examples/' URI will be donated to charity.