Index: includes/forum.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/nodewords/includes/forum.inc,v
retrieving revision 1.1.2.3
diff -u -p -r1.1.2.3 forum.inc
--- includes/forum.inc	13 Nov 2009 10:05:11 -0000	1.1.2.3
+++ includes/forum.inc	30 Nov 2009 22:59:33 -0000
@@ -15,14 +15,17 @@
  * Drupal hooks.
  ****************************************************************************/
 
+/**
+ * Implementation of hook_nodewords_type_id().
+ */
 function forum_nodewords_type_id($arg) {
   if ($arg[0] == 'forum') {
     // Forum paths: forum/$tid , forum/
     if (!isset($arg[1])) {
-      return array(NODEWORDS_MT_TYPE_VOCABULARY, variable_get('forum_nav_vocabulary', 0));
+      return array(NODEWORDS_TYPE_VOCABULARY, variable_get('forum_nav_vocabulary', 0));
     }
     elseif (is_numeric($arg[1])) {
-      return array(NODEWORDS_MT_TYPE_TERM, $arg[1]);
+      return array(NODEWORDS_TYPE_TERM, $arg[1]);
     }
   }
 }
Index: includes/image.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/nodewords/includes/image.inc,v
retrieving revision 1.1.2.4
diff -u -p -r1.1.2.4 image.inc
--- includes/image.inc	13 Nov 2009 10:05:11 -0000	1.1.2.4
+++ includes/image.inc	30 Nov 2009 22:59:33 -0000
@@ -15,14 +15,17 @@
  * Drupal hooks.
  ****************************************************************************/
 
+/**
+ * Implementation of hook_nodewords_type_id().
+ */
 function image_nodewords_type_id($arg) {
   if ($arg[0] == 'image') {
     // Image gallery paths: image/ , image/???/$tid
     if (!isset($arg[1])) {
-      return array(NODEWORDS_MT_TYPE_VOCABULARY, variable_get('image_gallery_nav_vocabulary', 0));
+      return array(NODEWORDS_TYPE_VOCABULARY, variable_get('image_gallery_nav_vocabulary', 0));
     }
     elseif (isset($arg[2]) && is_numeric($arg[2])) {
-      return array(NODEWORDS_MT_TYPE_TERM, $arg[2]);
+      return array(NODEWORDS_TYPE_TERM, $arg[2]);
     }
   }
 }
Index: includes/node.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/nodewords/includes/node.inc,v
retrieving revision 1.1.2.5
diff -u -p -r1.1.2.5 node.inc
--- includes/node.inc	13 Nov 2009 10:05:11 -0000	1.1.2.5
+++ includes/node.inc	30 Nov 2009 22:59:33 -0000
@@ -15,17 +15,20 @@
  * Drupal hooks.
  ****************************************************************************/
 
+/**
+ * Implementation of hook_nodewords_type_id().
+ */
 function node_nodewords_type_id($arg) {
   if ($arg[0] == 'node') {
     // Node paths: node/$nid
     if (isset($arg[1]) && is_numeric($arg[1])) {
       if (!($node = menu_get_object())) {
-        return array(NODEWORDS_MT_TYPE_NONE, 0);
+        return array(NODEWORDS_TYPE_NONE, '');
       }
 
       // If the meta tags for the content type are disabled, don't show them.
       if (!variable_get('nodewords_edit_metatags_' . $node->type, TRUE)) {
-        return array(NODEWORDS_MT_TYPE_NONE, 0);
+        return array(NODEWORDS_TYPE_NONE, '');
       }
 
       $bool = (
@@ -38,7 +41,7 @@ function node_nodewords_type_id($arg) {
       );
 
       if ($bool) {
-        return array(NODEWORDS_MT_TYPE_NODE, $node->vid);
+        return array(NODEWORDS_TYPE_NODE, $node->vid);
       }
     }
   }
Index: includes/taxonomy.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/nodewords/includes/taxonomy.inc,v
retrieving revision 1.1.2.6
diff -u -p -r1.1.2.6 taxonomy.inc
--- includes/taxonomy.inc	13 Nov 2009 10:05:11 -0000	1.1.2.6
+++ includes/taxonomy.inc	30 Nov 2009 22:59:33 -0000
@@ -15,6 +15,9 @@
  * Drupal hooks.
  ****************************************************************************/
 
+/**
+ * Implementation of hook_nodewords_type_id().
+ */
 function taxonomy_nodewords_type_id($arg) {
   if ($arg[0] == 'taxonomy') {
     // Taxonomy paths: taxonomy/term/$tid , taxonomy/term/$tid1+$tid2
@@ -25,11 +28,11 @@ function taxonomy_nodewords_type_id($arg
         // Take the first ID that is numeric.
         foreach ($ids as $id) {
           if (is_numeric($id)) {
-            return array(NODEWORDS_MT_TYPE_TERM, $id);
+            return array(NODEWORDS_TYPE_TERM, $id);
           }
         }
 
-        return array(NODEWORDS_MT_TYPE_NONE, 0);
+        return array(NODEWORDS_TYPE_NONE, '');
       }
     }
   }
Index: includes/taxonomy_menu.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/nodewords/includes/taxonomy_menu.inc,v
retrieving revision 1.1.2.4
diff -u -p -r1.1.2.4 taxonomy_menu.inc
--- includes/taxonomy_menu.inc	13 Nov 2009 10:05:11 -0000	1.1.2.4
+++ includes/taxonomy_menu.inc	30 Nov 2009 22:59:33 -0000
@@ -15,14 +15,17 @@
  * Drupal hooks.
  ****************************************************************************/
 
+/**
+ * Implementation of hook_nodewords_type_id().
+ */
 function taxonomy_menu_nodewords_type_id($arg) {
   if ($arg[0] == 'taxonomy_menu') {
     // Taxonomy menu paths: taxonomy_menu/$vid, taxonomy_menu/$vid/$tid
     if (isset($arg[2]) && is_numeric($arg[2])) {
-      return array(NODEWORDS_MT_TYPE_TERM, $arg[2]);
+      return array(NODEWORDS_TYPE_TERM, $arg[2]);
     }
     elseif (isset($arg[1]) && is_numeric($arg[1])) {
-      return array(NODEWORDS_MT_TYPE_VOCABULARY, $arg[1]);
+      return array(NODEWORDS_TYPE_VOCABULARY, $arg[1]);
     }
   }
 }
Index: includes/tracker.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/nodewords/includes/tracker.inc,v
retrieving revision 1.1.2.4
diff -u -p -r1.1.2.4 tracker.inc
--- includes/tracker.inc	13 Nov 2009 10:05:11 -0000	1.1.2.4
+++ includes/tracker.inc	30 Nov 2009 22:59:33 -0000
@@ -15,10 +15,13 @@
  * Drupal hooks.
  ****************************************************************************/
 
+/**
+ * Implementation of hook_nodewords_type_id().
+ */
 function tracker_nodewords_type_id($arg) {
   if ($arg[0] == 'tracker') {
     return array(
-      NODEWORDS_MT_TYPE_TRACKER, array(
+      NODEWORDS_TYPE_TRACKER, array(
         isset($arg[1]) && is_numeric($arg[1]) ? $arg[1] : -1
       )
     );
Index: includes/user.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/nodewords/includes/user.inc,v
retrieving revision 1.1.2.4
diff -u -p -r1.1.2.4 user.inc
--- includes/user.inc	13 Nov 2009 10:05:11 -0000	1.1.2.4
+++ includes/user.inc	30 Nov 2009 22:59:33 -0000
@@ -15,14 +15,17 @@
  * Drupal hooks.
  ****************************************************************************/
 
+/**
+ * Implementation of hook_nodewords_type_id().
+ */
 function user_nodewords_type_id($arg) {
   if ($arg[0] == 'user') {
     // User page paths: user/$uid.
     if (isset($arg[1]) && is_numeric($arg[1])) {
       if (isset($arg[2]) && $arg[2] == 'track') {
-        return array(NODEWORDS_MT_TYPE_TRACKER, $arg[1]);
+        return array(NODEWORDS_TYPE_TRACKER, $arg[1]);
       }
-      return array(NODEWORDS_MT_TYPE_USER, $arg[1]);
+      return array(NODEWORDS_TYPE_USER, $arg[1]);
     }
   }
 }
Index: nodewords_basic/nodewords_basic.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/nodewords/nodewords_basic/nodewords_basic.module,v
retrieving revision 1.8.2.23
diff -u -p -r1.8.2.23 nodewords_basic.module
--- nodewords_basic/nodewords_basic.module	12 Nov 2009 14:33:19 -0000	1.8.2.23
+++ nodewords_basic/nodewords_basic.module	30 Nov 2009 22:59:34 -0000
@@ -38,11 +38,19 @@ function nodewords_basic_nodewords_tags_
       'widget:permission' => 'edit meta tag ABSTRACT',
     ),
     'canonical' => array(
-      'tag:context:allowed' => array(NODEWORDS_MT_TYPE_FRONTPAGE,
-        NODEWORDS_MT_TYPE_PAGER, NODEWORDS_MT_TYPE_NODE, NODEWORDS_MT_TYPE_TERM,
-        NODEWORDS_MT_TYPE_USER, NODEWORDS_MT_TYPE_VOCABULARY
+      'tag:context:allowed' => array(
+        NODEWORDS_TYPE_FRONTPAGE,
+        NODEWORDS_TYPE_NODE,
+        NODEWORDS_TYPE_PAGE,
+        NODEWORDS_TYPE_PAGER,
+        NODEWORDS_TYPE_TERM,
+        NODEWORDS_TYPE_USER,NODEWORDS_TYPE_VOCABULARY
+      ),
+      'tag:context:denied' => array(
+        NODEWORDS_TYPE_DEFAULT,
+        NODEWORDS_TYPE_ERRORPAGE,
+        NODEWORDS_TYPE_TRACKER
       ),
-      'tag:context:denied' => array(NODEWORDS_MT_TYPE_DEFAULT, NODEWORDS_MT_TYPE_ERRORPAGE, NODEWORDS_MT_TYPE_TRACKER),
       'tag:db:type' => 'string',
       'tag:function:prefix' => 'nodewords_basic_canonical',
       'tag:template' => array('canonical' => NODEWORDS_LINK_REL),
@@ -54,7 +62,7 @@ function nodewords_basic_nodewords_tags_
       'tag:db:type' => 'string',
       'tag:function:prefix' => 'nodewords_basic_copyright',
       'tag:template' => array('copyright' => NODEWORDS_META),
-      'tag:template:index' => '<h3>%content</h3>',
+      'tag:template:index' => array('copyright' => '<h3>%content</h3>'),
       'tag:tokens' => TRUE,
       'tag:weight' => array('copyright' => -7),
       'widget:label' => t('Copyright'),
@@ -64,7 +72,7 @@ function nodewords_basic_nodewords_tags_
       'tag:db:type' => 'string',
       'tag:function:prefix' => 'nodewords_basic_description',
       'tag:template' => array('description' => NODEWORDS_META),
-      'tag:template:index' => '<h3>%content</h3>',
+      'tag:template:index' => array('description' => '<h3>%content</h3>'),
       'tag:tokens' => TRUE,
       'tag:weight' => array('description' => -6),
       'widget:label' => t('Description'),
@@ -74,7 +82,7 @@ function nodewords_basic_nodewords_tags_
       'tag:db:type' => 'string',
       'tag:function:prefix' => 'nodewords_basic_keywords',
       'tag:template' => array('keywords' => NODEWORDS_META),
-      'tag:template:index' => '<h2>%content</h2>',
+      'tag:template:index' => array('keywords' => '<h2>%content</h2>'),
       'tag:tokens' => TRUE,
       'tag:weight' => array('keywords' => -8),
       'widget:label' => t('Keywords'),
@@ -88,11 +96,6 @@ function nodewords_basic_nodewords_tags_
       'widget:permission' => 'edit meta tag REVISIT-AFTER',
     ),
     'robots' => array(
-      'tag:context:allowed' => array(NODEWORDS_MT_TYPE_DEFAULT,
-        NODEWORDS_MT_TYPE_ERRORPAGE, NODEWORDS_MT_TYPE_FRONTPAGE,
-        NODEWORDS_MT_TYPE_PAGER, NODEWORDS_MT_TYPE_NODE, NODEWORDS_MT_TYPE_TERM,
-        NODEWORDS_MT_TYPE_TRACKER, NODEWORDS_MT_TYPE_USER, NODEWORDS_MT_TYPE_VOCABULARY
-      ),
       'tag:db:type' => 'array',
       'tag:function:prefix' => 'nodewords_basic_robots',
       'tag:template' => array('robots' => NODEWORDS_META),
@@ -146,7 +149,7 @@ function nodewords_basic_abstract_form(&
  */
 function nodewords_basic_abstract_prepare(&$tags, $content, $options) {
   $value = empty($content['value']) ? (!empty($options['default']['abstract']['value']) ? $options['default']['abstract']['value'] : '') : $content['value'];
-  $tags['abstract'] = nodewords_replace_tokens($options['type'], $options['id'], $value);
+  $tags['abstract'] = nodewords_replace_tokens($value, $options['id'], $options['sid']);
 }
 
 /**
@@ -182,25 +185,19 @@ function nodewords_basic_canonical_prepa
     $path = '';
 
     switch ($options['type']) {
-      case NODEWORDS_MT_TYPE_FRONTPAGE:
+      case NODEWORDS_TYPE_FRONTPAGE:
         $content['value'] = '<front>';
         break;
 
-      case NODEWORDS_MT_TYPE_NODE:
+      case NODEWORDS_TYPE_NODE:
         $path = 'node/' . $options['id'];
         break;
 
-      case NODEWORDS_MT_TYPE_PAGE:
-        if (!empty($options['id'])) {
-          $path = $options['id'];
-        }
-        break;
-
-      case NODEWORDS_MT_TYPE_TERM:
+      case NODEWORDS_TYPE_TERM:
         $path = 'taxonomy/term/' . $options['id'];
         break;
 
-      case NODEWORDS_MT_TYPE_TRACKER:
+      case NODEWORDS_TYPE_TRACKER:
         if ($options['id'] == -1) {
           $path = 'tracker';
         }
@@ -209,7 +206,7 @@ function nodewords_basic_canonical_prepa
         }
         break;
 
-      case NODEWORDS_MT_TYPE_USER:
+      case NODEWORDS_TYPE_USER:
         $path = 'user/' . $options['id'];
         break;
 
@@ -243,8 +240,8 @@ function nodewords_basic_canonical_form_
 }
 
 function nodewords_basic_canonical_settings_form(&$form, $form_id, $options) {
-  if ($form_id == '<advanced_settings>') {
-    $form['advanced']['nodewords_base_url'] = array(
+  if ($form_id == 'nodewords_settings_form') {
+    $form['metatags_creation']['nodewords_base_url'] = array(
       '#type' => 'textfield',
       '#title' => t('Base URL'),
       '#description' => t('Enter the base URL that will be used for canonical URLs.'),
@@ -286,7 +283,7 @@ function nodewords_basic_copyright_form(
  */
 function nodewords_basic_copyright_prepare(&$tags, $content, $options) {
   $value = empty($content['value']) ? (!empty($options['default']['copyright']['value']) ? $options['default']['copyright']['value'] : '') : $content['value'];
-  $tags['copyright'] = nodewords_replace_tokens($options['type'], $options['id'], $value);
+  $tags['copyright'] = nodewords_replace_tokens($value, $options['type'], $options['id'], $options['sid']);
 }
 
 /**
@@ -312,25 +309,22 @@ function nodewords_basic_description_for
  */
 function nodewords_basic_description_prepare(&$tags, $content, $options) {
   switch ($options['type']) {
-    case NODEWORDS_MT_TYPE_NODE:
+    case NODEWORDS_TYPE_NODE:
       $bool = (
         empty($content['value']) &&
-        ($node = node_load($options['id'])) &&
+        ($node = node_load(array('nid' => $options['id'], 'vid' => $options['sid']))) &&
         variable_get('nodewords_use_teaser_' . $node->type, variable_get('nodewords_use_teaser', FALSE)) &&
         !empty($node->teaser)
       );
 
       if ($bool) {
         $content['value'] = nodewords_metatag_from_teaser($node->teaser,
-          $node->format,
-          array(
-            'alt_attribute' => variable_get('nodewords_use_alt_attribute', FALSE),
-          )
+          $node->format
         );
       }
       break;
 
-    case NODEWORDS_MT_TYPE_TERM:
+    case NODEWORDS_TYPE_TERM:
       if (empty($content['value'])) {
         $term = nodewords_get_term($options['id']);
         if ($term) {
@@ -339,7 +333,7 @@ function nodewords_basic_description_pre
       }
         break;
 
-    case NODEWORDS_MT_TYPE_VOCABULARY:
+    case NODEWORDS_TYPE_VOCABULARY:
       // TODO: probably we have to do a db_rewrite_sql() query here so access is restricted
       $bool = (
         empty($content['value']) &&
@@ -357,19 +351,13 @@ function nodewords_basic_description_pre
 
 function nodewords_basic_description_settings_form(&$form, $form_id, $options) {
   switch ($form_id) {
-    case '<advanced_settings>':
-      $form['advanced']['nodewords_basic_use_teaser'] = array(
+    case 'nodewords_settings_form':
+      $form['meta_tags']['node_teaser']['nodewords_use_teaser'] = array(
         '#type' => 'checkbox',
         '#title' => t('Use the node teaser if the description meta tag is not set'),
         '#description' => t('Using the node teaser to populate the meta tag DESCRIPTION can cause problems with some content types; rather than enabling this option globally, it would be better to enable it separately for each content type (when it has been verified that enabling it for a specific content type does not create problems). This option is overwritten from the similar option for the content type.'),
         '#default_value' => variable_get('nodewords_use_teaser', FALSE),
       );
-
-      $form['advanced']['nodewords_basic_use_alt_attribute'] = array(
-        '#type' => 'checkbox',
-        '#title' => t('Include the attribute ALT of images in the description meta tag created from the node teaser'),
-        '#default_value' => variable_get('nodewords_use_alt_attribute', TRUE),
-      );
       break;
 
     case 'node_type_form':
@@ -415,15 +403,15 @@ function nodewords_basic_keywords_prepar
     $value .= ',' . $content['value'];
   }
 
-  if ($options['type'] == NODEWORDS_MT_TYPE_NODE && module_exists('taxonomy')) {
-    $node = node_load(array('vid' => $options['id']));
+  if ($options['type'] == NODEWORDS_TYPE_NODE && module_exists('taxonomy')) {
+    $node = node_load(array('nid' => $options['id'], 'vid' => $options['id']));
     foreach (taxonomy_node_get_terms($node) as $term) {
       if (in_array($term->vid, variable_get('nodewords_keyword_vids', array()))) {
         $value .= ',' . $term->name;
       }
     }
   }
-  elseif ($options['type'] == NODEWORDS_MT_TYPE_TERM) {
+  elseif ($options['type'] == NODEWORDS_TYPE_TERM) {
     $terms = array();
 
     if ($term = nodewords_get_term($options['id'])) {
@@ -431,8 +419,8 @@ function nodewords_basic_keywords_prepar
     }
   }
 
-  $value = nodewords_unique($value);
-  $tags['keywords'] = nodewords_replace_tokens($options['type'], $options['id'], $value);
+  $value = nodewords_unique_values($value);
+  $tags['keywords'] = nodewords_replace_tokens($value, $options['type'], $options['id'], $options['sid']);
 }
 
 /**
@@ -445,8 +433,54 @@ function nodewords_basic_keywords_form_v
 }
 
 function nodewords_basic_keywords_settings_form(&$form, $form_id, $options) {
-  if ($form_id == '<advanced_settings>') {
-    $form['advanced']['nodewords_global_keywords'] = array(
+  if ($form_id == 'nodewords_settings_form') {
+    $form['metatags_creation']['taxonomy'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Taxonomy'),
+      '#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['metatags_creation']['taxonomy']['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. The terms of these vocabularies are added before the global keywords but after the page-specific keywords.'),
+          '#default_value' => variable_get('nodewords_keyword_vids', array()),
+          '#options' => $options,
+          '#multiple' => TRUE,
+        );
+
+        if ($count > 10) {
+          $form['metatags_creation']['taxonomy']['nodewords_keyword_vids']['#multiple'] = TRUE;
+        }
+        elseif ($count > 2) {
+          // Add support for Check All if the checkboxes are more than two.
+          $form['metatags_creation']['nodewords_keyword_vids']['#checkall'] = TRUE;
+        }
+      }
+    }
+
+    if (empty($options)) {
+      $form['metatags_creation']['taxonomy']['nodewords_keyword_vids'] = array(
+        '#type' => 'value',
+        '#default_value' => variable_get('nodewords_keyword_vids', array()),
+      );
+
+      $form['metatags_creation']['taxonomy']['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>',
+        '#suffix' => '</div>',
+      );
+    }
+
+    $form['metatags_creation']['nodewords_global_keywords'] = array(
       '#type' => 'textfield',
       '#title' => t('Global keywords'),
       '#description' => t('Enter a comma separated list of keywords. Global keywords will be always added to each page.'),
@@ -526,7 +560,7 @@ function nodewords_basic_robots_form(&$f
     '#checkall' => variable_get('nodewords_enable_checkall', FALSE),
   );
 
-  if ($options['type'] != NODEWORDS_MT_TYPE_DEFAULT) {
+  if ($options['type'] != NODEWORDS_TYPE_DEFAULT) {
     $form['robots']['use_default'] = array(
       '#type' => 'checkbox',
       '#title' => t('Use the default value'),
@@ -555,7 +589,7 @@ function nodewords_basic_robots_form(&$f
  * Set the meta tag content.
  */
 function nodewords_basic_robots_prepare(&$tags, $content, $options) {
-  if ($options['type'] == NODEWORDS_MT_TYPE_PAGER) {
+  if ($options['type'] == NODEWORDS_TYPE_PAGER) {
     $value = variable_get('nodewords_list_robots', array());
   }
   else {
@@ -577,7 +611,7 @@ function nodewords_basic_robots_prepare(
 
 function nodewords_basic_robots_settings_form(&$form, $form_id, $options) {
   switch ($form_id) {
-    case '<advanced_settings>':
+    case 'nodewords_settings_form':
       $field_options = array(
         'noarchive' => t('NOARCHIVE'),
         'nofollow' => t('NOFOLLOW'),
Index: nodewords_custom/nodewords_custom.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/nodewords/nodewords_custom/nodewords_custom.module,v
retrieving revision 1.2
diff -u -p -r1.2 nodewords_custom.module
--- nodewords_custom/nodewords_custom.module	23 Oct 2009 10:44:43 -0000	1.2
+++ nodewords_custom/nodewords_custom.module	30 Nov 2009 22:59:34 -0000
@@ -33,13 +33,6 @@ function nodewords_custom_nodewords_tags
   return $tags;
 }
 
-/**
- * Implementation of hook_perm().
- */
-function nodewords_custom_perm() {
-  return array();
-}
-
 /*****************************************************************************
  * Meta tags implementation functions.
  ****************************************************************************/
Index: nodewords_extra/nodewords_extra.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/nodewords/nodewords_extra/nodewords_extra.module,v
retrieving revision 1.7.2.9
diff -u -p -r1.7.2.9 nodewords_extra.module
--- nodewords_extra/nodewords_extra.module	14 Nov 2009 09:24:02 -0000	1.7.2.9
+++ nodewords_extra/nodewords_extra.module	30 Nov 2009 22:59:34 -0000
@@ -15,6 +15,17 @@
  * Drupal hooks.
  ****************************************************************************/
 
+/*
+ * Implementation of hook_form_FORM_ID_alter().
+ */
+function nodewords_extra_form_nodewords_settings_form_alter(&$form, &$form_state) {
+  $form['metatags_creation']['nodewords_add_dc_schema'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Add the Dublin Core schema meta tag'),
+    '#default_value' => variable_get('nodewords_add_dc_schema', FALSE),
+  );
+}
+
 /**
  * Implementation of hook_menu().
  */
@@ -46,7 +57,11 @@ function nodewords_extra_nodewords_api()
 function nodewords_extra_nodewords_tags_info() {
   $tags = array(
     'dc.contributor' => array(
-      'tag:context:allowed' => array(NODEWORDS_MT_TYPE_DEFAULT, NODEWORDS_MT_TYPE_NODE),
+      'tag:context:allowed' => array(
+        NODEWORDS_TYPE_DEFAULT,
+        NODEWORDS_TYPE_NODE,
+        NODEWORDS_TYPE_PAGE,
+      ),
       'tag:db:type' => 'string',
       'tag:function:prefix' => 'nodewords_extra_dc_contributor',
       'tag:template' => array('dc.contributor' => NODEWORDS_META),
@@ -55,7 +70,11 @@ function nodewords_extra_nodewords_tags_
       'widget:permission' => 'edit meta tag Dublin Core CONTRIBUTOR',
     ),
     'dc.creator' => array(
-      'tag:context:allowed' => array(NODEWORDS_MT_TYPE_DEFAULT, NODEWORDS_MT_TYPE_NODE),
+      'tag:context:allowed' => array(
+        NODEWORDS_TYPE_DEFAULT,
+        NODEWORDS_TYPE_NODE,
+        NODEWORDS_TYPE_PAGE,
+      ),
       'tag:db:type' => 'string',
       'tag:function:prefix' => 'nodewords_extra_dc_creator',
       'tag:template' => array('dc.creator' => NODEWORDS_META),
@@ -63,7 +82,10 @@ function nodewords_extra_nodewords_tags_
       'widget:label' => t('Dublin Core creator'),
     ),
     'dc.date' => array(
-      'tag:context:allowed' => array(NODEWORDS_MT_TYPE_NODE),
+      'tag:context:allowed' => array(
+        NODEWORDS_TYPE_NODE,
+        NODEWORDS_TYPE_PAGE,
+      ),
       'tag:db:type' => 'array',
       'tag:function:prefix' => 'nodewords_extra_dc_date',
       'tag:template' => array('dc.date' => NODEWORDS_META),
@@ -78,7 +100,10 @@ function nodewords_extra_nodewords_tags_
       'widget:label' => t('Dublin Core description'),
     ),
     'dc.publisher' => array(
-      'tag:context:allowed' => array(NODEWORDS_MT_TYPE_DEFAULT),
+      'tag:context:allowed' => array(
+        NODEWORDS_TYPE_DEFAULT,
+        NODEWORDS_TYPE_PAGE,
+      ),
       'tag:db:type' => 'string',
       'tag:function:prefix' => 'nodewords_extra_dc_publisher',
       'tag:template' => array('dc.publisher' => NODEWORDS_META),
@@ -87,7 +112,7 @@ function nodewords_extra_nodewords_tags_
       'widget:permission' => 'edit meta tag Dublin Core PUBLISHER',
     ),
     'dc.title' => array(
-      'tag:context:denied' => array(NODEWORDS_MT_TYPE_DEFAULT),
+      'tag:context:denied' => array(NODEWORDS_TYPE_DEFAULT),
       'tag:db:type' => 'string',
       'tag:function:prefix' => 'nodewords_extra_dc_title',
       'tag:template' => array('dc.title' => NODEWORDS_META),
@@ -106,7 +131,11 @@ function nodewords_extra_nodewords_tags_
       'widget:permission' => 'edit location meta tags',
     ),
     'pics-label' => array(
-      'tag:context:allowed' => array(NODEWORDS_MT_TYPE_DEFAULT, NODEWORDS_MT_TYPE_NODE),
+      'tag:context:allowed' => array(
+        NODEWORDS_TYPE_DEFAULT,
+        NODEWORDS_TYPE_NODE,
+        NODEWORDS_TYPE_PAGE,
+      ),
       'tag:db:type' => 'string',
       'tag:attributes' => array(
         'meta' => array(
@@ -123,20 +152,30 @@ function nodewords_extra_nodewords_tags_
       'widget:label' => t('PICS labels'),
       'widget:permission' => 'edit meta tag PICS-LABEL',
     ),
-    'schema.dc' => array(
-      'tag:context:allowed' => array(NODEWORDS_MT_TYPE_NONE),
-      'tag:db:type' => 'string',
-      'tag:function:prefix' => 'nodewords_extra_dc_schema',
-      'tag:template' => array('schema.dc' => NODEWORDS_LINK_REL),
-      'tag:weight' => array('schema.dc' => -20),
-      'widget:label' => t('Dublin Core schema'),
-    ),
   );
 
   return $tags;
 }
 
 /**
+ * Implementation of hook_nodewords_tags_output_alter().
+ */
+function nodewords_extra_nodewords_tags_output_alter(&$output, $parameters) {
+  $bool = array(
+    variable_get('nodewords_add_dc_schema', FALSE) &&
+    isset($parameters['output']) &&
+    $parameters['ouput'] == 'head'
+  );
+
+  if ($bool) {
+    $output = (
+      '<link rel="schema.dc" href="http://purl.org/dc/elements/1.1/" />' . "\n" .
+      $output
+    );
+  }
+}
+
+/**
  * Implementation of hook_perm().
  */
 function nodewords_extra_perm() {
@@ -171,16 +210,13 @@ function nodewords_extra_perm() {
  */
 function nodewords_extra_dc_contributor_form(&$form, $content, $options) {
   $form['dc.contributor'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Dublin Core contributor'),
-    '#description' => t('Enter the name of an entity responsible for making contributions to the resource. Examples of a contributor include a person, an organization, or a service.'),
-    '#collapsible' => TRUE,
-    '#collapsed' => !(empty($content['value']) && empty($options['default']['dc.contributor']['value'])),
     '#tree' => TRUE,
   );
 
   $form['dc.contributor']['value'] = array(
     '#type' => 'textfield',
+    '#title' => t('Dublin Core contributor'),
+    '#description' => t('Enter the name of an entity responsible for making contributions to the resource. Examples of a contributor include a person, an organization, or a service.'),
     '#default_value' => empty($content['value']) ? (!empty($options['default']['dc.contributor']['value']) ? $options['default']['dc.contributor']['value'] : '') : $content['value'],
     '#size' => 60,
     '#maxlength' => variable_get('nodewords_max_size', 350),
@@ -192,7 +228,7 @@ function nodewords_extra_dc_contributor_
  */
 function nodewords_extra_dc_contributor_prepare(&$tags, $content, $options) {
   $value = empty($content['value']) ? (!empty($options['default']['dc.contributor']['value']) ? $options['default']['dc.contributor']['value'] : '') : $content['value'];
-  $tags['dc.contributor'] = nodewords_replace_tokens($options['type'], $options['id'], $value);
+  $tags['dc.contributor'] = nodewords_replace_tokens($value, $options['id'], $options['sid']);
 }
 
 /**
@@ -200,16 +236,13 @@ function nodewords_extra_dc_contributor_
  */
 function nodewords_extra_dc_creator_form(&$form, $content, $options) {
   $form['dc.creator'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Dublin Core creator'),
-    '#description' => t('Enter the name of an entity primarily responsible for making the resource. Examples of a creator include a person, an organization, or a service. This field supports tokens.'),
-    '#collapsible' => TRUE,
-    '#collapsed' => !(empty($content['value']) && empty($options['default']['dc.creator']['value'])),
     '#tree' => TRUE,
   );
 
   $form['dc.creator']['value'] = array(
     '#type' => 'textfield',
+    '#title' => t('Dublin Core creator'),
+    '#description' => t('Enter the name of an entity primarily responsible for making the resource. Examples of a creator include a person, an organization, or a service. This field supports tokens.'),
     '#default_value' => empty($content['value']) ? (!empty($options['default']['dc.creator']['value']) ? $options['default']['dc.creator']['value'] : '') : $content['value'],
     '#size' => 60,
     '#maxlength' => variable_get('nodewords_max_size', 350),
@@ -221,7 +254,7 @@ function nodewords_extra_dc_creator_form
  */
 function nodewords_extra_dc_creator_prepare(&$tags, $content, $options) {
   $value = empty($content['value']) ? (!empty($options['default']['dc.creator']['value']) ? $options['default']['dc.creator']['value'] : '') : $content['value'];
-  $tags['dc.creator'] = nodewords_replace_tokens($options['type'], $options['id'], $value);
+  $tags['dc.creator'] = nodewords_replace_tokens($value, $options['type'], $options['id'], $options['sid']);
 }
 
 /**
@@ -229,16 +262,13 @@ function nodewords_extra_dc_creator_prep
  */
 function nodewords_extra_dc_date_form(&$form, $content, $options) {
   $form['dc.date'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Dublin Core date'),
-    '#description' => t('A point or period of time associated with an event in the lifecycle of the resource. The date should be relative to UTC.'),
-    '#collapsible' => TRUE,
-    '#collapsed' => !empty($content['value']),
     '#tree' => TRUE,
   );
 
   $form['dc.date']['value'] = array(
     '#type' => 'date',
+    '#title' => t('Dublin Core date'),
+    '#description' => t('A point or period of time associated with an event in the lifecycle of the resource. The date should be relative to UTC.'),
     '#default_value' => empty($content['value']) ? array() : $content['value'],
   );
 }
@@ -338,14 +368,7 @@ function nodewords_extra_dc_publisher_fo
  */
 function nodewords_extra_dc_publisher_prepare(&$tags, $content, $options) {
   $value = empty($options['default']['dc.publisher']['value']) ? '' : $options['default']['dc.publisher']['value'];
-  $tags['dc.publisher'] = nodewords_replace_tokens($options['type'], $options['id'], $value);
-}
-
-/**
- * Set the meta tag content.
- */
-function nodewords_extra_dc_schema_prepare(&$tags, $content, $options) {
-  $tags['schema.dc'] = 'http://purl.org/dc/elements/1.1/';
+  $tags['dc.publisher'] = nodewords_replace_tokens($value, $options['type'], $options['id'], $options['sid']);
 }
 
 /**
@@ -374,7 +397,7 @@ function nodewords_extra_dc_title_form(&
  */
 function nodewords_extra_dc_title_prepare(&$tags, $content, $options) {
   $value = empty($content['value']) ? '' : $content['value'];
-  $tags['dc.title'] = nodewords_replace_tokens($options['type'], $options['id'], $value);
+  $tags['dc.title'] = nodewords_replace_tokens($value, $options['type'], $options['id'], $options['sid']);
 }
 
 /**
@@ -411,8 +434,8 @@ function nodewords_extra_location_form(&
  * Set the meta tag content.
  */
 function nodewords_extra_location_prepare(&$tags, $content, $options) {
-  if ((empty($content['longitude']) || empty($content['longitude'])) && $options['type'] == NODEWORDS_MT_TYPE_NODE && module_exists('location')) {
-    $node = node_load(array('vid' => $options['id']));
+  if ((empty($content['longitude']) || empty($content['longitude'])) && $options['type'] == NODEWORDS_TYPE_NODE && module_exists('location')) {
+    $node = node_load(array('nid' => $options['id'], 'vid' => $options['id']));
     if ($node && isset($node->locations[0]['latitude']) && isset($node->locations[0]['longitude'])) {
       $content['latitude'] = $node->locations[0]['latitude'];
       $content['longitude'] = $node->locations[0]['longitude'];
@@ -473,7 +496,7 @@ function nodewords_extra_pics_prepare(&$
   }
 
   if (!empty($content['value'])) {
-    if ($options['type'] == NODEWORDS_MT_TYPE_NODE) {
+    if ($options['type'] == NODEWORDS_TYPE_NODE) {
       $tags['pics-label'] = strtr(
         '(pics-1.1 "http://www.icra.org/pics/vocabularyv03/" l gen true for %url r (%pics))',
         array(
@@ -490,11 +513,11 @@ function nodewords_extra_pics_prepare(&$
 }
 
 function nodewords_extra_pics_settings_form(&$form, $form_id, $options) {
-  if ($form_id == '<advanced_settings>') {
-    $form['advanced']['nodewords_icra_validation_content'] = array(
+  if ($form_id == 'nodewords_settings_form') {
+    $form['metatags_creation']['nodewords_icra_validation_content'] = array(
       '#type' => 'textarea',
-      '#title' => t('IRCA validation content'),
-      '#description' => t('Enter the validation content IRCA sent you. Leave this field empty if you do not know what a IRCA validation file is. For more information, see <a href="@irca-url">The Family Online Safety Institute: Protecting your online future</a>.', array('@irca-url' => 'http://www.icra.org/support/')),
+      '#title' => t('ICRA validation content'),
+      '#description' => t('Enter the validation content ICRA sent you. Leave this field empty if you do not know what a ICRA validation file is. For more information, see <a href="@irca-url">The Family Online Safety Institute: Protecting your online future</a>.', array('@irca-url' => 'http://www.icra.org/support/')),
       '#default_value' => variable_get('nodewords_icra_validation_content', ''),
       '#size' => 60,
     );
Index: API.txt
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/nodewords/Attic/API.txt,v
retrieving revision 1.1.4.2
diff -u -p -r1.1.4.2 API.txt
--- API.txt	14 Nov 2009 07:34:43 -0000	1.1.4.2
+++ API.txt	30 Nov 2009 22:59:34 -0000
@@ -1,36 +1,61 @@
 ; $Id: API.txt,v 1.1.4.2 2009/11/14 07:34:43 kiam Exp $
 ; This file contains a log of changes to the API.
 
-API version 1.1
-
-* The module uses hook_nodewords_tags_info(), and hook_nodewords_api().
-
-* Functions that before were private are now public.
+API version 2.7
 
-API version 1.3
+* The function nodewords_load_tags() has been changed from
+  nodewords_load_tags($type = NODEWORDS_TYPE_DEFAULT, $id = '') to
+  nodewords_load_tags($type = NODEWORDS_TYPE_DEFAULT, $id = '', $language = '').
 
-* The module uses also hook_nodewords_type_id().
+* The function nodewords_metatag_from_teaser() has been changed from
+  nodewords_metatag_from_teaser($text, $format, $alt_attribute, $size = 0) to
+  nodewords_metatag_from_teaser($text, $format, $options = array()).
 
-* The definition of nodewords_output_tags() is changed from
+* The function nodewords_output_tags() has been changed from
   nodewords_output_tags($tags) to
   nodewords_output_tags($tags, $output_type = 'head').
 
-* The definiton of nodewords_unique() is changed from
-  nodewords_unique($text, $max_items = 0, $separator = ',') to
-  nodewords_unique($text, $separator = ',', $max_items = -1).
+* The function nodewords_replace_tokens($type, $id, $content) has been added.
 
-API version 2.7
+* The function nodewords_save_tags() has been changed from
+  nodewords_save_tags($type, $id, $tags, $log_message = FALSE) to
+  nodewords_save_tags($type, $id, $tags, $options = array()).
 
-* The definition of nodewords_load_tags() is changed from
-  nodewords_load_tags($type = NODEWORDS_MT_TYPE_DEFAULT, $id = '') to
-  nodewords_load_tags($type = NODEWORDS_MT_TYPE_DEFAULT, $id = '', $language = '').
+API version 2.8
 
-* The definition of nodewords_metatag_from_teaser() is changed from
-  nodewords_metatag_from_teaser($text, $format, $alt_attribute, $size = 0) to
-  nodewords_metatag_from_teaser($text, $format, $options = array()).
+* Changed the name of the constants from NODEWORDS_MT_TYPE_* to
+  NODEWORDS_TYPE_*.
 
-* The function nodewords_replace_tokens($type, $id, $content) has been added.
+* The function nodewords_delete_tags() has been changed from
+  nodewords_delete_tags($type, $id) to
+  nodewords_delete_tags($type, $id, $options = array()).
 
-* The definition of nodewords_save_tags() is changed from
-  nodewords_save_tags($type, $id, $tags, $log_message = FALSE) to
-  nodewords_save_tags($type, $id, $tags, $options = array()).
+* The function nodewords_get_tags() has been changed from
+  nodewords_get_tags($type, $ids = array(''), $filtered = TRUE) to
+  nodewords_get_tags($type, $id = '', $options = array()).
+
+* The function nodewords_load_tags() has been changed from
+  nodewords_load_tags($type = NODEWORDS_TYPE_DEFAULT, $id = '', $language = '') to
+  nodewords_load_tags($type = NODEWORDS_TYPE_DEFAULT, $id = '', $options = array()).
+
+* The function nodewords_replace_tokens() has been changed from
+  nodewords_replace_tokens($type, $id, $content) to
+  nodewords_replace_tokens($content, $type, $id, $sid = 0).
+
+* The function nodewords_save_tags() has been changed from
+  nodewords_save_tags($type, $id, $tags, $options = array()) to
+  nodewords_save_tags($tags, $type, $id, $options = array()).
+
+* The function nodewords_tags_form() has been changed from
+  nodewords_tags_form(&$form_state, $type = NODEWORDS_TYPE_DEFAULT, $id = 0) to
+  nodewords_tags_form(&$form_state, $type = NODEWORDS_TYPE_DEFAULT, $id = '', $options = array()).
+
+* The function nodewords_unique() has been changed from
+  nodewords_unique($text, $separator = ',', $max_items = -1) to
+  nodewords_unique_values($text, $options =  array()).
+
+* The identifier passed to <meta_tag_hander>_settings_form() for the meta tags
+  settings form is now the form identifier as used by Drupal
+  (nodewords_settings_form).
+
+* The module uses also hook_nodewords_tags_output_alter().
Index: CHANGELOG.txt
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/nodewords/CHANGELOG.txt,v
retrieving revision 1.9.2.18
diff -u -p -r1.9.2.18 CHANGELOG.txt
--- CHANGELOG.txt	15 Nov 2009 00:53:53 -0000	1.9.2.18
+++ CHANGELOG.txt	30 Nov 2009 22:59:34 -0000
@@ -1,6 +1,26 @@
 ; $Id: CHANGELOG.txt,v 1.9.2.18 2009/11/15 00:53:53 kiam Exp $
 ; All the dates reported here are referred to UTC.
 
+Nodewords 6.x-1 2009-11-30
+--------------------------
+#640716 by ilo, kiamlaluno: Admin settings when no tags module is enabled.
+#628868 by kiamlaluno: Meta tags content is not indexed from the search module.
+#640906 by ilo: Readme.txt file is completely outdated.
+#646996 by kiamlaluno: Hook implemented in nodewords_extra.module doesn't have the correct name.
+#646966 by kiamlaluno: nodewords_pages_edit_validate() reports the error for the wrong form field.
+#640278 by KiamLaLuno: Change the order the settings for other pages are used.
+#646710 by kiamlaluno: Incorrect database schema when updating from a previous version.
+#639392 by KiamLaLuno: Wildcards not working in "Other Pages".
+#638962 by KiamLaLuno: Unsupported operand types.
+#646656 by kiamlaluno: When there are no vocabularies, the option for the meta tag KEYWORDS to populate it with taxonomy terms doesn't appear.
+#637396 by maximpodorov: Meta tags don't appear because a bug in the function that detects the page being viewed.
+#636798 by KiamLaLuno: Re-add the call to drupal_alter('nodewords_tags').
+#636978 by KiamLaLuno: Ubercart catalog page support.
+
+Nodewords 6.x-1 2009-11-17
+--------------------------
+#635386 by KiamLaLuno: Add more options to filter the text present in the node teaser used as meta tag content.
+
 Nodewords 6.x-3 2009-11-15
 --------------------------
 #632856 by dkruglyak: Error with version_compare().
Index: nodewords.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/nodewords/nodewords.admin.inc,v
retrieving revision 1.6.2.10
diff -u -p -r1.6.2.10 nodewords.admin.inc
--- nodewords.admin.inc	12 Nov 2009 14:33:14 -0000	1.6.2.10
+++ nodewords.admin.inc	30 Nov 2009 22:59:34 -0000
@@ -3,7 +3,7 @@
 
 /**
  * @file
- * Assign META tags to nodes, vocabularies, terms and pages.
+ * Assign meta tags to nodes, vocabularies, terms and pages.
  */
 
 /**
@@ -38,7 +38,7 @@ function nodewords_pages_confirm_delete(
  */
 function nodewords_pages_confirm_delete_submit($form, &$form_state) {
   if ($form_state['values']['confirm']) {
-    nodewords_delete_tags(NODEWORDS_MT_TYPE_PAGE, $form_state['values']['path']);
+    nodewords_delete_tags(NODEWORDS_TYPE_PAGE, $form_state['values']['path']);
   }
 
   if (db_affected_rows()) {
@@ -56,8 +56,6 @@ function nodewords_pages_overview() {
   $form = array('#tree' => TRUE);
   $pages = array();
 
-  _nodewords_check_enabled_modules();
-
   foreach (_nodewords_get_pages_data() as $pid => $page) {
     $pages[$pid] = '';
 
@@ -65,6 +63,10 @@ function nodewords_pages_overview() {
       $enabled[] = $pid;
     }
 
+    $form['name'][$pid] = array(
+      '#value' => $page->name,
+    );
+
     $form['path'][$pid] = array(
       '#type' => 'hidden',
       '#value' => $page->path,
@@ -135,53 +137,15 @@ function nodewords_pages_overview_submit
  *
  */
 function nodewords_pages_edit($form_state, $page = NULL) {
-  if (!isset($page)) {
-    $page = new stdClass();
-    $page->path = '';
-    $page->weight = 0;
-    $page->enabled = 1;
-    $page->tags = array();
-  }
-  else {
-    $form['pid'] = array(
-      '#type' => 'value',
-      '#value' => $page->pid,
-    );
-  }
-
-  $form['path'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Path'),
-    '#description' => t("Enter the Drupal path of the page. The '*' character is a wildcard. Example paths are <em>blog</em> for the blog page and <em>blog/*</em> for every personal blog."),
-    '#default_value' => $page->path,
-    '#size' => 60,
-    '#maxlength' => 255,
-    '#required' => TRUE,
-  );
-
-  $form['weight'] = array(
-    '#type' => 'weight',
-    '#title' => t('Weight'),
-    '#description' => t('Pages with lower weight will be considered first. Only the first matching page will be used.'),
-    '#delta' => 10,
-    '#default_value' => $page->weight,
-  );
-
-  $form['enabled'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Enabled'),
-    '#default_value' => $page->enabled,
-  );
-
-  $form['nodewords'] = nodewords_form(
-    NODEWORDS_MT_TYPE_PAGE,
+  $form = array();
+  $nodewords_form = nodewords_form(
+    NODEWORDS_TYPE_PAGE,
     $page->tags,
     array(
       'fieldset' => FALSE,
     )
   );
-
-  if (empty($form['nodewords'])) {
+  if (empty($nodewords_form)) {
     if (!count(array_filter(variable_get('nodewords_edit', array())))) {
       drupal_set_message(
         t(
@@ -191,9 +155,59 @@ function nodewords_pages_edit($form_stat
       );
     }
 
-    return array();
+    return $form;
   }
   else {
+    if (!isset($page)) {
+      $page = (object) array(
+        'name' => t('Custom page'),
+        'path' => '',
+        'weight' => 0,
+        'enabled' => 1,
+        'tags' => array(),
+      );
+    }
+    else {
+      $form['pid'] = array(
+        '#type' => 'value',
+        '#value' => $page->pid,
+      );
+    }
+
+    $form['name'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Name'),
+      '#description' => t("A name to better identify the page in the list of custom pages. The name must contains at least one alpha-numeric character."),
+      '#default_value' => $page->name,
+      '#size' => 60,
+      '#maxlength' => 60,
+      '#required' => TRUE,
+    );
+
+    $form['path'] = array(
+      '#type' => 'textarea',
+      '#title' => t('Path'),
+      '#description' => t("Enter the Drupal paths associated with the page. The character <q>*</q> is a wildcard. Example paths are <em>blog</em> for the blog page and <em>blog/*</em> for every personal blog. The list must contain at least one path."),
+      '#default_value' => $page->path,
+      '#size' => 60,
+      '#required' => TRUE,
+    );
+
+    $form['weight'] = array(
+      '#type' => 'weight',
+      '#title' => t('Weight'),
+      '#description' => t('Pages with lower weight will be considered first. Only the first matching page will be used.'),
+      '#delta' => 10,
+      '#default_value' => $page->weight,
+    );
+
+    $form['enabled'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Enabled'),
+      '#default_value' => $page->enabled,
+    );
+
+    $form['nodewords'] = $nodeword_form;
     $form['nodewords']['#tree'] = TRUE;
 
     $form['submit'] = array(
@@ -210,12 +224,11 @@ function nodewords_pages_edit($form_stat
  * Validate function for the meta tags edit page.
  */
 function nodewords_pages_edit_validate($form, &$form_state) {
-  if ($path = trim($form_state['values']['path'])) {
-    if ($path[0] == '/') {
-      form_set_error('path', t('The path must not start with a slash.'));
-      return;
-    }
+  if (trim($form_state['values']['name']) == '') {
+    form_set_error('name', t('The name contains only spaces, and other not printable characters.'));
+  }
 
+  if (($path = trim($form_state['values']['path'])) != '') {
     $bool = db_result(
       db_query("SELECT 1 FROM {nodewords_custom} WHERE path = '%s' AND pid <> %d",
         $path,
@@ -228,7 +241,7 @@ function nodewords_pages_edit_validate($
     }
   }
   else {
-    form_set_error('path', t('The path must not contain only spaces.'));
+    form_set_error('path', t('The path contains only spaces, and other not printable characters.'));
   }
 }
 
@@ -238,10 +251,11 @@ function nodewords_pages_edit_validate($
 function nodewords_pages_edit_submit($form, &$form_state) {
   $form_state['values']['path'] = trim($form_state['values']['path']);
 
-  nodewords_save_tags(NODEWORDS_MT_TYPE_PAGE, $form_state['values']['path'], $form_state['values']['nodewords']);
-  drupal_write_record('nodewords_custom', $form_state['values'], isset($form_state['values']['pid']) ? 'pid' : NULL);
+  nodewords_save_tags(NODEWORDS_TYPE_PAGE, $form_state['values']['path'], $form_state['values']['nodewords'], TRUE);
+  drupal_write_record('nodewords_custom', $form_state['values'], isset($form_state['values']['pid']) ? 'pid' : array());
 
   drupal_set_message(t('The configuration options have been saved.'));
+
   $form_state['redirect'] = 'admin/content/nodewords/meta-tags/other';
 }
 
@@ -249,44 +263,39 @@ function nodewords_pages_edit_submit($fo
  * Menu callback: settings form.
  */
 function nodewords_settings_form() {
-  $edit_options = array();
-  $edit_tags = variable_get('nodewords_edit', array());
-  $form = array();
-  $head_options = array();
-  $head_tags = variable_get('nodewords_head', array());
-  $tags_info = nodewords_get_possible_tags();
-
-  _nodewords_check_enabled_modules();
-
-  foreach ($tags_info as $name => $info) {
-    $bool = (
-      isset($info['tag:context:allowed']) &&
-      in_array(NODEWORDS_MT_TYPE_NONE, $info['tag:context:allowed'])
-    );
-
-    if (!$bool) {
-      $edit_options[$name] = $info['widget:label'];
+  if (!empty($tags_info)) {
+    foreach ($tags_info as $name => $info) {
+      $edit_options[$name] = $head_options[$name] = $info['widget:label'];
     }
 
-    $head_options[$name] = $info['widget:label'];
+    uasort($edit_options, 'strnatcmp');
+    uasort($head_options, 'strnatcmp');
+  }
+  else {
+    drupal_set_message(t('There are no modules that implement meta tags. You need to enable at least one module between nodewords_basic.module, nodewords_extra.module, and nodewords_verification_tags.module that are listed under <em>Meta tags</em> in the <a href="@modules-page">modules page</a>.', array('@modules-page' => url('admin/build/modules'))), 'error');
   }
-
-  uasort($edit_options, 'strnatcmp');
-  uasort($head_options, 'strnatcmp');
 
   $form['edit'] = array(
     '#type' => 'fieldset',
     '#title' => t('Meta tags to show on edit forms'),
-    '#description' => t('Select the meta tags you want to be able to edit; the meta tag edit fields will always be shown in the administration settings pages. The meta tags that appear only in the list of the meta tags output in HTML, are automatically set by a module.'),
+    '#description' => t('Select the meta tags you want to be able to edit.'),
     '#collapsible' => TRUE,
   );
 
-  $form['edit']['nodewords_edit'] = array(
-    '#type' => 'checkboxes',
-    '#options' => $edit_options,
-    '#default_value' => $edit_tags,
-    '#checkall' => variable_get('nodewords_enable_checkall', FALSE),
-  );
+  if (!empty($tags_info)) {
+    $form['edit']['nodewords_edit'] = array(
+      '#type' => 'checkboxes',
+      '#options' => $edit_options,
+      '#default_value' => $edit_tags,
+      '#checkall' => TRUE,
+    );
+  }
+  else {
+    $form['edit']['nodewords_edit'] = array(
+      '#type' => 'value',
+      '#value' => $edit_tags,
+    );
+  }
 
   $form['head'] = array(
     '#type' => 'fieldset',
@@ -295,53 +304,110 @@ function nodewords_settings_form() {
     '#collapsible' => TRUE,
   );
 
-  $form['head']['nodewords_head'] = array(
-    '#type' => 'checkboxes',
-    '#options' => $head_options,
-    '#default_value' => $head_tags,
-    '#checkall' => variable_get('nodewords_enable_checkall', FALSE),
+  if (!empty($tags_info)) {
+    $form['head']['nodewords_head'] = array(
+      '#type' => 'checkboxes',
+      '#options' => $head_options,
+      '#default_value' => $head_tags,
+      '#checkall' => TRUE,
+    );
+  }
+  else {
+    $form['head']['nodewords_head'] = array(
+      '#type' => 'value',
+      '#value' => $head_tags,
+    );
+  }
+
+  $form['metatags_creation'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Meta tags creation options'),
+    '#description' => t('These options change the way the meta tags are generated.'),
+    '#collapsible' => TRUE,
   );
 
-  if (function_exists('taxonomy_get_vocabularies')) {
-    $options = array();
+  $form['metatags_creation']['nodewords_enable_user_metatags'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Enable the user profile meta tags'),
+    '#default_value' => variable_get('nodewords_enable_user_metatags', TRUE),
+  );
 
-    foreach (taxonomy_get_vocabularies() as $vocabulary) {
-      $options[$vocabulary->vid] = check_plain($vocabulary->name);
-    }
+  $form['metatags_creation']['nodewords_list_repeat'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Repeat meta tags for lists'),
+    '#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.'),
+    '#default_value' => variable_get('nodewords_list_repeat', FALSE),
+  );
 
-    if ($count = count($options)) {
-      $form['taxonomy'] = array(
-        '#type' => 'fieldset',
-        '#title' => t('Taxonomy'),
-        '#collapsible' => TRUE,
-      );
-      $form['taxonomy']['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. The terms of these vocabularies are added before the global keywords but after the page-specific keywords.'),
-        '#default_value' => variable_get('nodewords_keyword_vids', array()),
-        '#options' => $options,
-        '#multiple' => TRUE,
-      );
+  $form['metatags_creation']['nodewords_use_frontpage_tags'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Use front page meta tags'),
+    '#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/meta-tags/frontpage'), '@site-settings-url' => url('admin/settings/site-information'))),
+    '#default_value' => variable_get('nodewords_use_frontpage_tags', TRUE),
+  );
 
-      if ($count > 10) {
-        $form['taxonomy']['nodewords_keyword_vids']['#multiple'] = TRUE;
-      }
-      elseif ($count > 2) {
-        // Add support for Check All if the checkboxes are more than two.
-        $form['taxonomy']['nodewords_keyword_vids']['#checkall'] = variable_get('nodewords_enable_checkall', FALSE);
-      }
-    }
+  $default_size = variable_get('nodewords_max_size', 350);
+
+  $form['metatags_creation']['nodewords_max_size'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Maximum meta tags length'),
+    '#description' => t('The maximum length to use for the meta tags form fields.'),
+    '#default_value' => $default_size,
+    '#required' => TRUE,
+    '#element_validate' => array('nodewords_max_size_validate'),
+    '#size' => 6,
+    '#maxlength' => 6,
+  );
+
+  if ($default_size < 350) {
+    $form['metatags_creation']['nodewords_max_size']['#description'] .= ' ' . t('Most of the search engines are now indexing 350 characters, which is not the maximum length actually set for the meta tags. See <a href="@google-blog">Official Google Blog: Two new improvements to Google results pages</a> for more information.', array('@google-blog' => 'http://googleblog.blogspot.com/2009/03/two-new-improvements-to-google-results.html'));
   }
 
-  $form['advanced'] = array(
+  $form['metatags_creation']['node_teaser'] = array(
     '#type' => 'fieldset',
-    '#title' => t('Advanced options'),
-    '#description' => t('These options are for advanced uses. The average user should not change the value set by default from the module.'),
+    '#title' => t('Node teaser options'),
+    '#description' => t('These options are for the generation of meta tags content from the node teaser.'),
     '#collapsible' => TRUE,
   );
 
-  $form['advanced']['nodewords_enable_checkall'] = array(
+  $form['metatags_creation']['node_teaser']['nodewords_use_alt_attribute'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Include the attribute ALT of images in the description meta tag created from the node teaser'),
+    '#default_value' => variable_get('nodewords_use_alt_attribute', TRUE),
+  );
+
+  $options = array(
+    'imagebrowser' => 'imagebrowser.module',
+    'img_assist' => 'img_assist.module',
+  );
+
+  $form['metatags_creation']['node_teaser']['nodewords_filter_modules_output'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Filter the text added by third-party modules'),
+    '#options' => $options,
+    '#default_value' => variable_get('nodewords_filter_modules_output', array()),
+    '#checkall' => TRUE,
+  );
+
+  $form['metatags_creation']['node_teaser']['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', ''),
+    '#size' => 60,
+  );
+
+  $form['metatags_creation']['taxonomy'] = array();
+
+  $form['third_party_integration'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Third party modules integration'),
+    '#description' => t('These options enable the integration between Nodewords and other modules.'),
+    '#collapsible' => TRUE,
+  );
+
+  $form['third_party_integration']['nodewords_enable_checkall'] = array(
     '#type' => 'checkbox',
     '#title' => t(
       'Enable the integration with <a href="@checkall">checkall.module</a>',
@@ -351,16 +417,16 @@ function nodewords_settings_form() {
   );
 
   if (!module_exists('checkall')) {
-    $form['advanced']['nodewords_enable_checkall']['#description'] = t(
+    $form['third_party_integration']['nodewords_enable_checkall']['#description'] = t(
       'The module checkall.module is not enabled, or installed.'
     );
 
     if (!variable_get('nodewords_enable_checkall', FALSE)) {
-      $form['advanced']['nodewords_enable_checkall']['#disabled'] = TRUE;
+      $form['third_party_integration']['nodewords_enable_checkall']['#disabled'] = TRUE;
     }
   }
 
-  $form['advanced']['nodewords_enable_tokens'] = array(
+  $form['third_party_integration']['nodewords_enable_tokens'] = array(
     '#type' => 'checkbox',
     '#title' => t(
       'Enable the integration with <a href="@token">token.module</a>',
@@ -373,16 +439,14 @@ function nodewords_settings_form() {
   );
 
   if (!module_exists('token')) {
-    $form['advanced']['nodewords_enable_tokens']['#description'] .=  ' ' . t(
-      'The module token.module is not enabled, or installed.'
-    );
+    $form['third_party_integration']['nodewords_enable_tokens']['#description'] .=  ' ' . t('The module token.module is not enabled, or installed.');
 
     if (!variable_get('nodewords_enable_tokens', TRUE)) {
-      $form['advanced']['nodewords_enable_tokens']['#disabled'] = TRUE;
+      $form['third_party_integration']['nodewords_enable_tokens']['#disabled'] = TRUE;
     }
   }
 
-  $form['advanced']['nodewords_enable_vertical_tabs'] = array(
+  $form['third_party_integration']['nodewords_enable_vertical_tabs'] = array(
     '#type' => 'checkbox',
     '#title' => t(
       'Enable the integration with <a href="@vertical_tabs">vertical_tabs.module</a>',
@@ -392,58 +456,15 @@ function nodewords_settings_form() {
   );
 
   if (!module_exists('vertical_tabs')) {
-    $form['advanced']['nodewords_enable_vertical_tabs']['#description'] = t(
+    $form['third_party_integration']['nodewords_enable_vertical_tabs']['#description'] = t(
       'The module vertical_tabs.module is not enabled, or installed.'
     );
 
     if (!variable_get('nodewords_enable_vertical_tabs', FALSE)) {
-      $form['advanced']['nodewords_enable_vertical_tabs']['#disabled'] = TRUE;
+      $form['third_party_integration']['nodewords_enable_vertical_tabs']['#disabled'] = TRUE;
     }
   }
 
-  $form['advanced']['nodewords_enable_user_metatags'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Enable the user profile meta tags'),
-    '#default_value' => variable_get('nodewords_enable_user_metatags', TRUE),
-  );
-
-  $form['advanced']['nodewords_list_repeat'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Repeat meta tags for lists'),
-    '#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.'),
-    '#default_value' => variable_get('nodewords_list_repeat', FALSE),
-  );
-
-  $form['advanced']['nodewords_use_frontpage_tags'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Use front page meta tags'),
-    '#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/meta-tags/frontpage'), '@site-settings-url' => url('admin/settings/site-information'))),
-    '#default_value' => variable_get('nodewords_use_frontpage_tags', TRUE),
-  );
-
-  $form['advanced']['nodewords_collapse_fieldset'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Show the meta tags fieldset as collapsed'),
-    '#default_value' => variable_get('nodewords_collapse_fieldset', FALSE),
-  );
-
-  $default_size = variable_get('nodewords_max_size', 350);
-
-  $form['advanced']['nodewords_max_size'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Maximum meta tags length'),
-    '#description' => t('The maximum length to use for the meta tags form fields.'),
-    '#default_value' => $default_size,
-    '#required' => TRUE,
-    '#element_validate' => array('nodewords_max_size_validate'),
-    '#size' => 6,
-    '#maxlength' => 6,
-  );
-
-  if ($default_size < 350) {
-    $form['advanced']['nodewords_max_size']['#description'] .= ' ' . t('Most of the search engines are now indexing 350 characters, which is not the maximum length actually set for the meta tags. See <a href="@google-blog">Official Google Blog: Two new improvements to Google results pages</a> for more information.', array('@google-blog' => 'http://googleblog.blogspot.com/2009/03/two-new-improvements-to-google-results.html'));
-  }
-
   foreach ($tags_info as $name => $info) {
     $function = $info['tag:function:prefix'] . '_settings_form';
     $options = array(
@@ -451,7 +472,7 @@ function nodewords_settings_form() {
     );
 
     if (function_exists($function)) {
-      $function($form, '<advanced_settings>', $options);
+      $function($form, 'nodewords_settings_form', $options);
     }
   }
 
@@ -462,6 +483,21 @@ function nodewords_settings_form() {
 }
 
 /**
+ * Function to validate the regular expression.
+ *
+ */
+function nodewords_filter_regexpr_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.'));
+    }
+  }
+}
+
+/**
  * Function to validate the value entered for the maximum meta tags length.
  *
  */
@@ -479,17 +515,20 @@ function nodewords_max_size_validate($el
 /**
  * Front page settings form.
  */
-function nodewords_tags_form(&$form_state, $type = NODEWORDS_MT_TYPE_DEFAULT, $id = 0) {
+function nodewords_tags_form(&$form_state, $type = NODEWORDS_TYPE_DEFAULT, $id = '', $options = array()) {
+  $default_options = array(
+    'sid' => 0,
+    'language' => '',
+  );
   $form = array();
+  $options += $default_options;
 
   $form['#nodewords_type'] = $type;
   $form['#nodewords_id'] = $id;
-
-  _nodewords_check_enabled_modules();
-
+  $form['#nodewords_options'] = $options;
   $form['nodewords'] = nodewords_form(
     $type,
-    nodewords_load_tags($type, $id),
+    nodewords_load_tags($type, $id, $options),
     array(
       'fieldset' => FALSE,
     )
@@ -539,7 +578,12 @@ function nodewords_tags_form_reset($form
  * Submission function for the meta tags edit page.
  */
 function nodewords_tags_form_submit($form, &$form_state) {
-  nodewords_save_tags($form['#nodewords_type'], $form['#nodewords_id'], $form_state['values']['nodewords']);
+  nodewords_save_tags(
+    $form_state['values']['nodewords'],
+    $form['#nodewords_type'],
+    $form['#nodewords_id'],
+    $form['#nodewords_options']
+  );
   drupal_set_message(t('The configuration options have been saved.'));
 }
 
@@ -551,13 +595,13 @@ function nodewords_tags_form_submit($for
  * Render the list of pages with meta tags.
  */
 function theme_nodewords_pages_overview($form) {
-  $has_pages = isset($form['path']) && is_array($form['path']);
+  $has_pages = isset($form['name']) && is_array($form['name']);
   $rows = array();
 
   if ($has_pages) {
-    foreach (element_children($form['path']) as $key) {
+    foreach (element_children($form['name']) as $key) {
       $row = array();
-      $row[] = drupal_render($form['path'][$key]);
+      $row[] = drupal_render($form['name'][$key]);
 
       $form['weight'][$key]['#attributes']['class'] = 'page-weight';
 
@@ -582,7 +626,7 @@ function theme_nodewords_pages_overview(
     );
   }
 
-  $header[] = t('Drupal path');
+  $header[] = t('Name');
   $header[] = t('Weight');
 
   if (!empty($rows)) {
Index: nodewords.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/nodewords/nodewords.install,v
retrieving revision 1.18.2.14
diff -u -p -r1.18.2.14 nodewords.install
--- nodewords.install	11 Nov 2009 12:37:01 -0000	1.18.2.14
+++ nodewords.install	30 Nov 2009 22:59:35 -0000
@@ -7,19 +7,6 @@
  */
 
 /**
- * Installation constants.
- */
-define('NODEWORDS_INSTALL_MT_TYPE_DEFAULT',    1);
-define('NODEWORDS_INSTALL_MT_TYPE_ERRORPAGE',  2);
-define('NODEWORDS_INSTALL_MT_TYPE_FRONTPAGE',  3);
-define('NODEWORDS_INSTALL_MT_TYPE_PAGER',      4);
-define('NODEWORDS_INSTALL_MT_TYPE_NODE',       5);
-define('NODEWORDS_INSTALL_MT_TYPE_TERM',       6);
-define('NODEWORDS_INSTALL_MT_TYPE_TRACKER',    7);
-define('NODEWORDS_INSTALL_MT_TYPE_USER',       8);
-define('NODEWORDS_INSTALL_MT_TYPE_VOCABULARY', 9);
-
-/**
  * Implementation of hook_requirements().
  */
 function nodewords_requirements($phase) {
@@ -29,7 +16,7 @@ function nodewords_requirements($phase) 
     if (!count(module_implements('nodewords_api'))) {
       $requirements['nodewords'] = array(
         'title' => t('Nodewords'),
-        'description' => t('Nodewords does not create meta tags anymore; it is just a module that implements a public API used from the modules that create meta tags. You need to enable at least one module between nodewords_basic.module, nodewords_extra.module, and nodewords_verification_tags.module that are listed under <em>Meta tags</em> in the modules page.'),
+        'description' => t('There are no modules that implement meta tags. You need to enable at least one module between nodewords_basic.module, nodewords_extra.module, and nodewords_verification_tags.module that are listed under <em>Meta tags</em> in the <a href="@modules-page">modules page</a>.', array('@modules-page' => url('admin/build/modules'))),
         'severity' => REQUIREMENT_ERROR,
         'value' => t('Enable the <a href="@url">meta tags modules</a>.', array('@url' => url('admin/build/modules'))),
       );
@@ -77,6 +64,13 @@ function nodewords_schema() {
         'not null' => TRUE,
         'default' => '',
       ),
+      'sid' => array(
+        'description' => 'The secondary ID (i.e., the node revision ID).',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
       'name' => array(
         'description' => 'The meta tag name.',
         'type' => 'varchar',
@@ -105,9 +99,10 @@ function nodewords_schema() {
         'type',
         array('id', 6),
       ),
+      'nodewords_sid' => array('sid'),
     ),
     'unique keys' => array(
-      'nodewords_type_id_name_lang' => array('type', 'id', 'name', 'language'),
+      'nodewords_type_ids_name_lang' => array('type', 'id', 'sid', 'name', 'language'),
     ),
     'primary key' => array('mtid'),
   );
@@ -121,10 +116,17 @@ function nodewords_schema() {
         'unsigned' => TRUE,
         'not null' => TRUE,
       ),
+      'name' => array(
+        'description' => 'The page name as shown in the list of custom pages.',
+        'type' => 'varchar',
+        'length' => 60,
+        'not null' => TRUE,
+        'default' => '',
+      ),
       'path' => array(
         'description' => 'The page path.',
-        'type' => 'varchar',
-        'length' => 255,
+        'type' => 'text',
+        'size' => 'medium',
         'not null' => TRUE,
         'default' => '',
       ),
@@ -143,9 +145,6 @@ function nodewords_schema() {
         'default' => 1,
       ),
     ),
-    'unique keys' => array(
-      'path' => array('path'),
-    ),
     'primary key' => array('pid'),
   );
 
@@ -164,17 +163,19 @@ function nodewords_install() {
  * Implementation of hook_update_N().
  */
 function nodewords_update_6300() {
+  drupal_load('module', 'nodewords');
+
   $ret = array();
   $types = array(
-    'default' => NODEWORDS_INSTALL_MT_TYPE_DEFAULT,
-    'errorpage' => NODEWORDS_INSTALL_MT_TYPE_ERRORPAGE,
-    'frontpage' => NODEWORDS_INSTALL_MT_TYPE_FRONTPAGE,
-    'pager' => NODEWORDS_INSTALL_MT_TYPE_PAGER,
-    'node' => NODEWORDS_INSTALL_MT_TYPE_NODE,
-    'term' => NODEWORDS_INSTALL_MT_TYPE_TERM,
-    'tracker' => NODEWORDS_INSTALL_MT_TYPE_TRACKER,
-    'user' => NODEWORDS_INSTALL_MT_TYPE_USER,
-    'vocabulary' => NODEWORDS_INSTALL_MT_TYPE_VOCABULARY,
+    'default' => NODEWORDS_TYPE_DEFAULT,
+    'errorpage' => NODEWORDS_TYPE_ERRORPAGE,
+    'frontpage' => NODEWORDS_TYPE_FRONTPAGE,
+    'pager' => NODEWORDS_TYPE_PAGER,
+    'node' => NODEWORDS_TYPE_NODE,
+    'term' => NODEWORDS_TYPE_TERM,
+    'tracker' => NODEWORDS_TYPE_TRACKER,
+    'user' => NODEWORDS_TYPE_USER,
+    'vocabulary' => NODEWORDS_TYPE_VOCABULARY,
   );
 
   if (variable_get('nodewords_update_6139', FALSE)) {
@@ -224,17 +225,6 @@ function nodewords_update_6300() {
 /**
  * Implementation of hook_update_N().
  */
-function nodewords_update_6301() {
-  $ret = array();
-
-  $ret[] = update_sql("UPDATE {nodewords} nw SET nw.id = (SELECT n.vid FROM {node} n WHERE n.nid = nw.id) WHERE type = " . NODEWORDS_INSTALL_MT_TYPE_NODE);
-
-  return $ret;
-}
-
-/**
- * Implementation of hook_update_N().
- */
 function nodewords_update_6302() {
   $node_types = array_keys(node_get_types('names'));
   $ret = array();
@@ -361,11 +351,15 @@ function nodewords_update_6307() {
  * Implementation of hook_update_N().
  */
 function nodewords_update_6308() {
-  $ret = array();
+  drupal_load('module', 'nodewords');
 
   $content = db_select(
-    db_query("SELECT content FROM {nodewords} WHERE type = 'pager' AND id = '' AND name = 'robots'")
+    db_query(
+      "SELECT content FROM {nodewords} WHERE type = '%s' AND id = '' AND name = 'robots'",
+      NODEWORDS_TYPE_PAGER
+    )
   );
+  $ret = array();
 
   if ($content !== FALSE) {
     variable_set('nodewords_list_robots', unserialize($content));
@@ -378,7 +372,7 @@ function nodewords_update_6308() {
     drupal_set_message(t('The previous value for the meta tag ROBOTS used in list pages has been restored. Check it is the desired value.'));
   }
 
-  $ret[] = update_sql("DELETE FROM {nodewords} WHERE type = 'pager'");
+  $ret[] = update_sql("DELETE FROM {nodewords} WHERE type = '" . NODEWORDS_TYPE_PAGER . "'");
 
   return $ret;
 }
@@ -420,6 +414,9 @@ function nodewords_update_6309() {
   return $ret;
 }
 
+/**
+ * Implementation of hook_update_N().
+ */
 function nodewords_update_6310() {
   $ret = array();
 
@@ -434,6 +431,195 @@ function nodewords_update_6310() {
 }
 
 /**
+ * Implementation of hook_update_N().
+ */
+function nodewords_update_6311() {
+  $ret = array();
+
+  if (!db_column_exists('nodewords', 'sid')) {
+    db_add_field($ret, 'nodewords', 'sid',
+      array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      array('nodewords_sid' => array('sid'))
+    );
+  }
+
+  return $ret;
+}
+
+/**
+ * Implementation of hook_update_N().
+ */
+function nodewords_update_6312() {
+  $ret = array();
+
+  if (!variable_get('nodewords_update_6312', FALSE)) {
+    db_drop_unique_key($ret, 'nodewords', 'nodewords_type_id_name_lang');
+    db_add_unique_key($ret, 'nodewords', 'nodewords_type_ids_name_lang',
+      array(
+        'type', 'id', 'sid', 'name', 'language'
+      )
+    );
+
+    variable_set('nodewords_update_6312', TRUE);
+  }
+
+  return $ret;
+}
+
+/**
+ * Implementation of hook_update_N().
+ */
+function nodewords_update_6313() {
+  drupal_load('module', 'nodewords');
+
+  $ret = array();
+  $ret[] = update_sql("UPDATE {nodewords} nw SET nw.sid = (SELECT n.vid FROM {node} n WHERE n.nid = nw.id) WHERE type = " . NODEWORDS_TYPE_NODE);
+
+  return $ret;
+}
+
+/**
+ * Implementation of hook_update_N().
+ */
+function nodewords_update_6314() {
+  $ret = array();
+  $value = variable_get('nodewords_collapse_fieldset', NULL);
+
+  if (isset($value)) {
+    variable_del('nodewords_collapse_fieldset');
+
+    $ret[] = array(
+      'success' => TRUE,
+      'query' => 'UPDATE MODULE SETTINGS',
+    );
+  }
+}
+
+function nodewords_update_6315() {
+  $ret = array();
+
+  if (!db_column_exists('nodewords_custom', 'name')) {
+    db_add_field($ret, 'nodewords_custom', 'name',
+      array(
+        'type' => 'varchar',
+        'length' => 60,
+        'not null' => TRUE,
+        'default' => '',
+      )
+    );
+  }
+
+  return $ret;
+}
+
+/**
+ * Implementation of hook_update_N().
+ */
+function nodewords_update_6316(&$sandbox) {
+  $ret = array();
+
+  if (!isset($sandbox['progress'])) {
+    $sandbox['progress'] = 0;
+    $sandbox['max'] = db_result(db_query("SELECT COUNT(*) FROM {nodewords_custom} WHERE name = ''"));
+  }
+
+  if ($sandbox['max']) {
+    $pages = db_query_range("SELECT * FROM {nodewords_custom} WHERE name = '' ORDER BY pid ASC", $sandbox['progress'], 10);
+
+    while ($page = db_fetch_object($pages)) {
+      db_query(
+        "UPDATE {nodewords_custom} SET name = '%s' WHERE pid = %d",
+        "Custom page #{$sandbox['progress']}", $page->pid
+      );
+
+      $sandbox['progress']++;
+    }
+  }
+
+  $ret['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['progress'] / $sandbox['max']);
+
+  return $ret;
+}
+
+/**
+ * Implementation of hook_update_N().
+ */
+function nodewords_update_6317() {
+  $ret = array();
+  $schema['nodewords_custom'] = array(
+    'description' => 'The table containing data for custom pages.',
+    'fields' => array(
+      'pid' => array(
+        'description' => 'The primary key.',
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'name' => array(
+        'description' => 'The page name as shown in the list of custom pages.',
+        'type' => 'varchar',
+        'length' => 60,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'path' => array(
+        'description' => 'The page path.',
+        'type' => 'text',
+        'size' => 'medium',
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'weight' => array(
+        'description' => 'The weight of the page.',
+        'type' => 'int',
+        'size' => 'tiny',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'enabled' => array(
+        'description' => 'A flag set when the page is enabled.',
+        'type' => 'int',
+        'size' => 'tiny',
+        'not null' => TRUE,
+        'default' => 1,
+      ),
+    ),
+    'primary key' => array('pid'),
+  );
+
+  if (db_table_exists('nodewords_custom')) {
+    db_drop_unique_key($ret, 'nodewords_custom', 'path');
+
+    db_change_field($ret, 'nodewords_custom', 'name', 'name',
+      array(
+        'type' => 'varchar',
+        'length' => 60,
+        'not null' => TRUE,
+        'default' => '',
+      )
+    );
+
+    db_change_field($ret, 'nodewords_custom', 'path', 'path',
+      array(
+        'type' => 'text',
+        'size' => 'medium',
+        'not null' => TRUE,
+      )
+    );
+  }
+  else {
+    db_create_table($ret, 'nodewords_custom', $schema['nodewords_custom']);
+  }
+
+  return $ret;
+}
+
+/**
  * Implementation of hook_uninstall().
  */
 function nodewords_uninstall() {
@@ -460,6 +646,7 @@ function nodewords_uninstall() {
   variable_del('nodewords_update_6139');
   variable_del('nodewords_update_6145');
   variable_del('nodewords_update_6147');
+  variable_del('nodewords_update_6312');
   variable_del('nodewords_use_alt_attribute');
   variable_del('nodewords_use_frontpage_tags');
   variable_del('nodewords_use_teaser');
Index: nodewords.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/nodewords/nodewords.module,v
retrieving revision 1.66.2.36
diff -u -p -r1.66.2.36 nodewords.module
--- nodewords.module	15 Nov 2009 00:53:53 -0000	1.66.2.36
+++ nodewords.module	30 Nov 2009 22:59:36 -0000
@@ -18,17 +18,17 @@
 /**
  * The type of objects to which the meta tags are associated.
  */
-define('NODEWORDS_MT_TYPE_DEFAULT',    1);
-define('NODEWORDS_MT_TYPE_ERRORPAGE',  2);
-define('NODEWORDS_MT_TYPE_FRONTPAGE',  3);
-define('NODEWORDS_MT_TYPE_NONE',       0);
-define('NODEWORDS_MT_TYPE_NODE',       5);
-define('NODEWORDS_MT_TYPE_PAGE',      10);
-define('NODEWORDS_MT_TYPE_PAGER',      4);
-define('NODEWORDS_MT_TYPE_TERM',       6);
-define('NODEWORDS_MT_TYPE_TRACKER',    7);
-define('NODEWORDS_MT_TYPE_USER',       8);
-define('NODEWORDS_MT_TYPE_VOCABULARY', 9);
+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.
@@ -46,7 +46,7 @@ define('NODEWORDS_MINIMUM_API_VERSION', 
 /**
  * The current API version implemented.
  */
-define('NODEWORDS_API_VERSION', '2.7');
+define('NODEWORDS_API_VERSION', '2.8');
 
 /*****************************************************************************
  * Drupal hooks.
@@ -96,14 +96,14 @@ function nodewords_form_alter(&$form, &$
       $tags = $form_state['values']['nodewords'];
     }
     elseif (isset($id) && is_numeric($id)) {
-      $tags = nodewords_load_tags(NODEWORDS_MT_TYPE_NODE, $id);
+      $tags = nodewords_load_tags(NODEWORDS_TYPE_NODE, $id);
     }
     else {
       $tags = array();
     }
 
     $form['nodewords'] = nodewords_form(
-      NODEWORDS_MT_TYPE_NODE,
+      NODEWORDS_TYPE_NODE,
       $tags,
       array(
         'page:permissions:additional' => 'administer nodes',
@@ -198,14 +198,14 @@ function nodewords_form_taxonomy_form_te
       $tags = $form_state['values']['nodewords'];
     }
     elseif (isset($id) && is_numeric($id)) {
-      $tags = nodewords_load_tags(NODEWORDS_MT_TYPE_TERM, $id);
+      $tags = nodewords_load_tags(NODEWORDS_TYPE_TERM, $id);
     }
     else {
       $tags = array();
     }
 
     $form['nodewords'] = nodewords_form(
-      NODEWORDS_MT_TYPE_TERM,
+      NODEWORDS_TYPE_TERM,
       $tags,
       array()
     );
@@ -226,14 +226,14 @@ function nodewords_form_taxonomy_form_vo
       $tags = $form_state['values']['nodewords'];
     }
     elseif (isset($id) && is_numeric($id)) {
-      $tags = nodewords_load_tags(NODEWORDS_MT_TYPE_VOCABULARY, $id);
+      $tags = nodewords_load_tags(NODEWORDS_TYPE_VOCABULARY, $id);
     }
     else {
       $tags = array();
     }
 
     $form['nodewords'] = nodewords_form(
-      NODEWORDS_MT_TYPE_VOCABULARY,
+      NODEWORDS_TYPE_VOCABULARY,
       $tags,
       array()
     );
@@ -265,7 +265,7 @@ function nodewords_help($path, $arg) {
       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.') . '</p>';
+      $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':
@@ -324,7 +324,7 @@ function nodewords_menu() {
   $items['admin/content/nodewords/meta-tags/errorpage_403'] = array(
     'title' => 'Error 403 page',
     'page callback' => 'drupal_get_form',
-    'page arguments' => array('nodewords_tags_form', NODEWORDS_MT_TYPE_ERRORPAGE, '403'),
+    'page arguments' => array('nodewords_tags_form', NODEWORDS_TYPE_ERRORPAGE, '403'),
     'access arguments' => $admin_access,
     'type' => MENU_LOCAL_TASK,
     'file' => 'nodewords.admin.inc',
@@ -333,7 +333,7 @@ function nodewords_menu() {
   $items['admin/content/nodewords/meta-tags/errorpage_404'] = array(
     'title' => 'Error 404 page',
     'page callback' => 'drupal_get_form',
-    'page arguments' => array('nodewords_tags_form', NODEWORDS_MT_TYPE_ERRORPAGE, '404'),
+    'page arguments' => array('nodewords_tags_form', NODEWORDS_TYPE_ERRORPAGE, '404'),
     'access arguments' => $admin_access,
     'type' => MENU_LOCAL_TASK,
     'file' => 'nodewords.admin.inc',
@@ -342,7 +342,7 @@ function nodewords_menu() {
   $items['admin/content/nodewords/meta-tags/frontpage'] = array(
     'title' => 'Front page',
     'page callback' => 'drupal_get_form',
-    'page arguments' => array('nodewords_tags_form', NODEWORDS_MT_TYPE_FRONTPAGE),
+    'page arguments' => array('nodewords_tags_form', NODEWORDS_TYPE_FRONTPAGE),
     'access arguments' => $admin_access,
     'type' => MENU_LOCAL_TASK,
     'file' => 'nodewords.admin.inc',
@@ -351,7 +351,7 @@ function nodewords_menu() {
   $items['admin/content/nodewords/meta-tags/tracker'] = array(
     'title' => 'Tracker pages',
     'page callback' => 'drupal_get_form',
-    'page arguments' => array('nodewords_tags_form', NODEWORDS_MT_TYPE_TRACKER),
+    'page arguments' => array('nodewords_tags_form', NODEWORDS_TYPE_TRACKER),
     'access arguments' => $admin_access,
     'type' => MENU_LOCAL_TASK,
     'file' => 'nodewords.admin.inc',
@@ -407,7 +407,7 @@ function nodewords_node_operations() {
     'delete_metatags' => array(
       'label' => t('Delete meta tags'),
       'callback' => 'nodewords_mass_delete_tags',
-      'callback arguments' => array('type' => NODEWORDS_MT_TYPE_NODE),
+      'callback arguments' => array('type' => NODEWORDS_TYPE_NODE),
     ),
   );
 
@@ -420,26 +420,44 @@ function nodewords_node_operations() {
 function nodewords_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
   switch ($op) {
     case 'delete':
-      nodewords_delete_tags(NODEWORDS_MT_TYPE_NODE, $node->nid);
+      nodewords_delete_tags(
+        NODEWORDS_TYPE_NODE, $node->nid, array('sid' => '*')
+      );
       break;
 
     case 'insert':
     case 'update':
       if (isset($node->nodewords)) {
-        nodewords_save_tags(NODEWORDS_MT_TYPE_NODE, $node->nid, $node->nodewords);
+        nodewords_save_tags(
+          $node->nodewords,
+          NODEWORDS_TYPE_NODE,
+          $node->nid,
+          array(
+            'sid' => $node->vid,
+            'language' =>$node->language,
+          )
+        );
       }
       break;
 
     case 'load':
       return array(
-        'nodewords' => nodewords_load_tags(NODEWORDS_MT_TYPE_NODE, $node->nid),
+        'nodewords' => nodewords_load_tags(
+          NODEWORDS_TYPE_NODE, $node->nid,
+          array(
+            'sid' => $node->vid,
+            'language' => $node->language,
+          )
+        ),
       );
 
     case 'update index':
-      $tags = array();
+      $output_tags = array();
       $tag_options = array(
-        'type' => NODEWORDS_MT_TYPE_NODE,
+        'type' => NODEWORDS_TYPE_NODE,
         'id' => $node->nid,
+        'sid' => $node->vid,
+        'language' => $node->language,
       );
 
       if (isset($node->nodewords)) {
@@ -461,7 +479,11 @@ function nodewords_nodeapi(&$node, $op, 
           }
         }
 
-        return nodewords_output_tags($tags, 'update index');
+        $output = nodewords_output_tags($output_tags, 'update index');
+        $tag_options['output'] = 'update index';
+
+        drupal_alter('nodewords_tags_output', $output, $tag_options);
+        return $output;
       }
 
       return '';
@@ -479,8 +501,18 @@ function nodewords_perm() {
  * Implementation of hook_preprocess_page().
  */
 function nodewords_preprocess_page(&$variables) {
-  list($type, $id) = _nodewords_detect_type_and_id();
-  drupal_set_html_head(nodewords_output_tags(nodewords_get_tags($type, $id)));
+  $parameters = array();
+  $result = _nodewords_detect_type_and_id();
+  $tags = nodewords_get_tags($result[0], $result[1]);
+
+  $output = nodewords_output_tags($tags);
+  $parameters['type'] = $result[0];
+  $parameters['id'] = $result[1];
+  $parameters['sid'] = isset($result[2]) ? $result[2] : 0;
+  $parameters['output'] = 'head';
+
+  drupal_alter('nodewords_tags_output', $output, $parameters);
+  drupal_set_html_head($output);
 
   $variables['head'] = drupal_get_html_head();
 }
@@ -491,11 +523,11 @@ function nodewords_preprocess_page(&$var
 function nodewords_taxonomy($op, $type, $object = NULL) {
   if ($type == 'term') {
     $id = $object['tid'];
-    $type = NODEWORDS_MT_TYPE_TERM;
+    $type = NODEWORDS_TYPE_TERM;
   }
   elseif ($type == 'vocabulary') {
     $id = $object['vid'];
-    $type = NODEWORDS_MT_TYPE_VOCABULARY;
+    $type = NODEWORDS_TYPE_VOCABULARY;
   }
   else {
     return;
@@ -509,7 +541,7 @@ function nodewords_taxonomy($op, $type, 
     case 'insert':
     case 'update':
       if (isset($object['nodewords'])) {
-        nodewords_save_tags($type, $id, $object['nodewords']);
+        nodewords_save_tags($object['nodewords'], $type, $id);
       }
       break;
   }
@@ -533,27 +565,27 @@ function nodewords_user($op, &$edit, &$a
   switch ($op) {
     case 'load':
       if (variable_get('nodewords_enable_user_metatags', TRUE)) {
-        $account->nodewords = nodewords_load_tags(NODEWORDS_MT_TYPE_USER, $account->uid);
+        $account->nodewords = nodewords_load_tags(NODEWORDS_TYPE_USER, $account->uid);
       }
       break;
 
     case 'delete':
-      nodewords_delete_tags(NODEWORDS_MT_TYPE_USER, $account->uid);
+      nodewords_delete_tags(NODEWORDS_TYPE_USER, $account->uid);
       break;
 
     case 'insert':
     case 'update':
       if (isset($edit['nodewords'])) {
-        nodewords_save_tags(NODEWORDS_MT_TYPE_USER, $account->uid, $edit['nodewords']);
+        nodewords_save_tags($edit['nodewords'], NODEWORDS_TYPE_USER, $account->uid);
       }
       break;
 
     case 'form':
       if ($category == 'account') {
         if (variable_get('nodewords_enable_user_metatags', TRUE)) {
-          $tags = nodewords_load_tags(NODEWORDS_MT_TYPE_USER, $account->uid);
+          $tags = nodewords_load_tags(NODEWORDS_TYPE_USER, $account->uid);
           $form['nodewords'] = nodewords_form(
-            NODEWORDS_MT_TYPE_USER,
+            NODEWORDS_TYPE_USER,
             $tags,
             array(
               'page:permissions:additional' => 'administer users',
@@ -575,7 +607,7 @@ function nodewords_user_operations() {
     'delete_metatags' => array(
       'label' => t('Delete meta tags'),
       'callback' => 'nodewords_mass_delete_tags',
-      'callback arguments' => array('type' => NODEWORDS_MT_TYPE_USER),
+      'callback arguments' => array('type' => NODEWORDS_TYPE_USER),
     ),
   );
 
@@ -589,10 +621,28 @@ function nodewords_user_operations() {
 /**
  * Delete tags from table.
  */
-function nodewords_delete_tags($type, $id) {
-  db_query("DELETE FROM {nodewords} WHERE type = %d AND id = '%s'", $type, $id);
+function nodewords_delete_tags($type, $id, $options = array()) {
+  $default_options = array(
+    'sid' => 0,
+    'language' => '*',
+  );
+  $options += $default_options;
+
+  $args = array($type);
+  $query = "DELETE FROM {nodewords} WHERE type = %d AND id = '%s'";
 
-  if ($type == NODEWORDS_MT_TYPE_PAGE) {
+  if ($options['sid'] != '*') {
+    $args[] = $options['sid'];
+    $query .= ' AND sid = %d';
+  }
+  if ($options['language'] != '*') {
+    $args[] = $options['language'];
+    $query .= " AND language = '%s'";
+  }
+
+  db_query($query, $args);
+
+  if ($type == NODEWORDS_TYPE_PAGE) {
     db_query("DELETE FROM {nodewords_custom} WHERE path = '%s'", $id);
   }
 }
@@ -609,6 +659,7 @@ function nodewords_delete_tags($type, $i
  * @return
  *   An array as requested by the form API.
  */
+// TODO: Add the language option.
 function nodewords_form($type, $tags, $options = array()) {
   $default_options = array(
     'fieldset' => TRUE,
@@ -635,7 +686,7 @@ function nodewords_form($type, $tags, $o
   $tokens_support = FALSE;
 
   foreach ($tags_info as $name => $info) {
-    if ($type == NODEWORDS_MT_TYPE_DEFAULT) {
+    if ($type == NODEWORDS_TYPE_DEFAULT) {
       if (empty($edit_tags[$name]) && empty($head_tags[$name])) {
         continue;
       }
@@ -646,7 +697,7 @@ function nodewords_form($type, $tags, $o
 
     if (!empty($info['tag:context:allowed'])) {
       $bool = (
-        in_array(NODEWORDS_MT_TYPE_NONE, $info['tag:context:allowed']) ||
+        in_array(NODEWORDS_TYPE_NONE, $info['tag:context:allowed']) ||
         !in_array($type, $info['tag:context:allowed'])
       );
 
@@ -690,24 +741,24 @@ function nodewords_form($type, $tags, $o
       $form['#title'] = $options['fieldset:title'];
       $form['#tree'] = TRUE;
       $form['#collapsible'] = TRUE;
-      $form['#collapsed'] = variable_get('nodewords_collapse_fieldset', FALSE) || $collapsed;
+      $form['#collapsed'] = TRUE;
       $form['#weight'] = $options['fieldset:weight'];
     }
 
     if ($tokens_enabled && $tokens_support) {
       switch ($type) {
-        case NODEWORDS_MT_TYPE_ERRORPAGE:
-        case NODEWORDS_MT_TYPE_FRONTPAGE:
-        case NODEWORDS_MT_TYPE_PAGER:
-        case NODEWORDS_MT_TYPE_TRACKER:
+        case NODEWORDS_TYPE_ERRORPAGE:
+        case NODEWORDS_TYPE_FRONTPAGE:
+        case NODEWORDS_TYPE_PAGER:
+        case NODEWORDS_TYPE_TRACKER:
           $token_type = 'global';
           break;
 
-        case NODEWORDS_MT_TYPE_NODE:
+        case NODEWORDS_TYPE_NODE:
           $token_type = 'node';
           break;
 
-        case NODEWORDS_MT_TYPE_USER:
+        case NODEWORDS_TYPE_USER:
           $token_type = 'user';
           break;
 
@@ -791,53 +842,57 @@ function nodewords_get_possible_tags() {
  *
  * @param $type
  *     Realm of the object the meta tags are associated with.
- *     This is one of the following: NODEWORDS_MT_TYPE_ERRORPAGE,
-       NODEWORDS_MT_TYPE_FRONTPAGE, NODEWORDS_MT_TYPE_NODE,
- *     NODEWORDS_MT_TYPE_PAGE, NODEWORDS_MT_TYPE_TERM,
-       NODEWORDS_MT_TYPE_TRACKER, NODEWORDS_MT_TYPE_VOCABULARY.
+ *     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 $id
  *     ID of the object to get the meta tags from.
  *     This is one of the following:
- *     - NODEWORDS_MT_TYPE_ERRORPAGE => the HTML error code (403 or 404).
- *     - NODEWORDS_MT_TYPE_FRONTPAGE => 0.
- *     - NODEWORDS_MT_TYPE_NODE => the node ID.
- *     - NODEWORDS_MT_TYPE_PAGE => the page path.
- *     - NODEWORDS_MT_TYPE_PAGER => 0.
- *     - NODEWORDS_MT_TYPE_TERM => the term ID.
- *     - NODEWORDS_MT_TYPE_USER => the user ID.
- *     - NODEWORDS_MT_TYPE_VOCABULARY => the vocabulary ID.
- * @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.
+ *     - NODEWORDS_TYPE_ERRORPAGE => the HTML error code (403 or 404).
+ *     - NODEWORDS_TYPE_FRONTPAGE => 0.
+ *     - NODEWORDS_TYPE_NODE => the node ID.
+ *     - NODEWORDS_TYPE_PAGE => the page path.
+ *     - NODEWORDS_TYPE_PAGER => 0.
+ *     - NODEWORDS_TYPE_TERM => the term ID.
+ *     - NODEWORDS_TYPE_USER => the user ID.
+ *     - NODEWORDS_TYPE_VOCABULARY => the vocabulary ID.
+ * @param $options
+ *   An array of options.
  *
  * @return
  *   An associative array of the defined meta tags.
  */
-function nodewords_get_tags($type, $ids = array(''), $filtered = TRUE) {
+function nodewords_get_tags($type, $id = '', $options = array()) {
+  global $language;
+
+  $default_options = array(
+    'sid' => 0,
+    'filter' => TRUE,
+    'language' => $language->language,
+  );
   $head_tags = variable_get('nodewords_head', array());
   $output_tags = array();
-
-  if (!is_array($ids)) {
-    $ids = array($ids);
-  }
+  $options += $default_options;
 
   $tag_options = array(
-    'default' => nodewords_load_tags(),
-    'ids' => $ids,
     'type' => $type,
+    'id' => $id,
+    'sid' => $options['sid'],
+    'default' => nodewords_load_tags(),
+    'language' => $options['language'],
   );
 
-  if ($type == NODEWORDS_MT_TYPE_PAGER) {
+  if ($type == NODEWORDS_TYPE_PAGER) {
     foreach (nodewords_get_possible_tags() as $name => $info) {
       // Filter out tags the user has chosen not to see
-      if ($filtered && empty($head_tags[$name])) {
+      if ($options['filter'] && empty($head_tags[$name])) {
         continue;
       }
 
       $bool = (
         !empty($info['tag:context:allowed']) &&
-        in_array(NODEWORDS_MT_TYPE_PAGER, $info['tag:context:allowed']) &&
+        in_array(NODEWORDS_TYPE_PAGER, $info['tag:context:allowed']) &&
         function_exists($function = $info['tag:function:prefix'] . '_prepare')
       );
 
@@ -850,12 +905,12 @@ function nodewords_get_tags($type, $ids 
   }
   else {
     // User profiles meta tags are not enabled.
-    if ($type == NODEWORDS_MT_TYPE_USER && !variable_get('nodewords_enable_user_metatags', TRUE)) {
+    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_MT_TYPE_NODE || node_access('view', node_load($ids[0])))) {
-      $tags = nodewords_load_tags($type, $ids[0]);
+    elseif ($type != NODEWORDS_TYPE_NODE || node_access('view', node_load($id))) {
+      $tags = nodewords_load_tags($type, $id, $options);
     }
     else {
       $tags = array();
@@ -864,7 +919,7 @@ function nodewords_get_tags($type, $ids 
     // Prepare the tags.
     foreach (nodewords_get_possible_tags() as $name => $info) {
       // Filter out tags the user has chosen not to see
-      if ($filtered && empty($head_tags[$name])) {
+      if ($options['filter'] && empty($head_tags[$name])) {
         continue;
       }
 
@@ -875,8 +930,6 @@ function nodewords_get_tags($type, $ids 
       }
     }
   }
-
-  return $output_tags;
 }
 
 /**
@@ -912,25 +965,42 @@ function nodewords_get_term($tid) {
 
 /**
  * Load tags from table.
+ *
+ * @param $type
+ *  The type of object associated with the meta tags.
+ * @param $id
+ *  The object ID.
+ * @param $options
+ *  An array of options.
+ *
+ * @return
+ *  An array of meta tags data as saved in the database table.
  */
-function nodewords_load_tags($type = NODEWORDS_MT_TYPE_DEFAULT, $id = '', $language = '') {
+
+
+function nodewords_load_tags($type = NODEWORDS_TYPE_DEFAULT, $id = '', $options = array()) {
+  $default_options = array(
+    'sid' => 0,
+    'language' => '',
+  );
+  $options += $default_options;
   $tags = array();
   $tags_info = nodewords_get_possible_tags();
 
   $count = db_result(
     db_query(
-      "SELECT COUNT(*) FROM {nodewords} WHERE type = '%s' AND id = '%s' AND language = '%s'",
-      $type, $id, $language
+      "SELECT COUNT(*) FROM {nodewords} WHERE type = '%s' AND id = '%s' AND sid = %d AND language = '%s'",
+      $type, $id, $options['sid'], $options['language']
     )
   );
 
-  if (!$count && !empty($language)) {
-    $language = '';
+  if (!$count && !empty($options['language'])) {
+    $options['language'] = '';
   }
 
   $result = db_query(
-    "SELECT COUNT(*) FROM {nodewords} WHERE type = '%s' AND id = '%s' AND language = '%s'",
-    $type, $id, $language
+    "SELECT * FROM {nodewords} WHERE type = '%s' AND id = '%s' AND sid = %d AND language = '%s'",
+    $type, $id, $options['sid'], $options['language']
   );
 
   while ($row = db_fetch_object($result)) {
@@ -939,8 +1009,8 @@ function nodewords_load_tags($type = NOD
     }
   }
 
-  if (empty($tags) && $type == NODEWORDS_MT_TYPE_TERM) {
-    return nodewords_load_tags(NODEWORDS_MT_TYPE_VOCABULARY, db_result(db_query('SELECT vid FROM {term_data} WHERE tid = %d', $id)), $language);
+  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)), $options);
   }
 
   return $tags;
@@ -952,15 +1022,15 @@ function nodewords_load_tags($type = NOD
  * @param $ids
  *  An array of IDs.
  * @param $type
- *  The type of the object associated with the IDs (NODEWORDS_MT_TYPE_NODE,
- *  NODEWORDS_MT_TYPE_USER, ...).
+ *  The type of the object associated with the IDs (NODEWORDS_TYPE_NODE,
+ *  NODEWORDS_TYPE_USER, ...).
  */
 function nodewords_mass_delete_tags($ids, $type) {
   db_query("DELETE FROM {nodewords} WHERE id IN (" . db_placeholders($ids, 'varchar') . ") AND type = %d",
     array_merge($ids, array($type))
   );
 
-  if ($type == NODEWORDS_MT_TYPE_PAGE) {
+  if ($type == NODEWORDS_TYPE_PAGE) {
     db_query("DELETE FROM {nodewords_custom} WHERE path IN (" . db_placeholders($ids, 'varchar') . ")",
       $ids
     );
@@ -977,19 +1047,14 @@ function nodewords_mass_delete_tags($ids
  * @param $format
  *   The format set for the node.
  * @param $options
- *   An array of options. The currently defined are:
- *     'alt_attribute'
-          If TRUE, any tag img will be replaced with its attribute alt.
- *      size'
- *        The maximum allowed size; if it is zero, then the function will use
-          the value of the Drupal variable "nodewords_max_size".
+ *  An array of options; currently, the only used is the maximum allowed
+ *  length.
  *
  * @return
  *   The string to use to populate the meta tag.
  */
 function nodewords_metatag_from_teaser($text, $format, $options = array()) {
   $default_options = array(
-    'alt_attribute' => FALSE,
     'size' => variable_get('nodewords_max_size', 350),
   );
   $options += $default_options;
@@ -1004,12 +1069,6 @@ function nodewords_metatag_from_teaser($
     }
   }
 
-  // Remove the string added from Image Assist.
-  $text = preg_replace('/\[img_assist.*\]/i', '', $text);
-
-  // Initialize the helper function used for preg_replace_callback.
-  _nodewords_teaser_match_callback($alt_attribute, TRUE);
-
   // Replace the meta tag img with the attribute alt, and strip off all the
   // HTML tags.
   $text = strip_tags(
@@ -1019,8 +1078,23 @@ function nodewords_metatag_from_teaser($
     )
   );
 
+  // Remove the strings added from third-party modules.
+  $modules = array_filter(variable_get('nodewords_filter_modules_output', array()));
+
+  if (isset($modules['imagebrowser'])) {
+    $text = preg_replace("/\[ibimage[^[\]*\]/i", '', $text);
+  }
+  if (isset($modules['img_assist'])) {
+    $text = preg_replace("/\[img_assist[^[\]*\]/i", '', $text);
+  }
+
+  // Remove the text matching the regular expression.
+  if ($regexp = trim(variable_get('nodewords_filter_regexp', ''))) {
+    $text = preg_replace("/" . $regexp . "/i", '', $text);
+  }
+
   // Truncate the string at last space within the given size.
-  return truncate_utf8($text, $size, TRUE);
+  return truncate_utf8($text, $options['size'], TRUE);
 }
 
 /**
@@ -1132,7 +1206,7 @@ function nodewords_page_load($pid) {
   return _nodewords_get_pages_data($pid);
 }
 
-function nodewords_replace_tokens($type, $id, $content) {
+function nodewords_replace_tokens($content, $type, $id, $sid = 0) {
   $bool = (
     empty($content) || !module_exists('token')
   );
@@ -1142,20 +1216,20 @@ function nodewords_replace_tokens($type,
   }
 
   switch ($type) {
-    case NODEWORDS_MT_TYPE_ERRORPAGE:
-    case NODEWORDS_MT_TYPE_FRONTPAGE:
-    case NODEWORDS_MT_TYPE_PAGER:
-    case NODEWORDS_MT_TYPE_TRACKER:
+    case NODEWORDS_TYPE_ERRORPAGE:
+    case NODEWORDS_TYPE_FRONTPAGE:
+    case NODEWORDS_TYPE_PAGER:
+    case NODEWORDS_TYPE_TRACKER:
       $token_type = 'global';
       $token_object = NULL;
       break;
 
-    case NODEWORDS_MT_TYPE_NODE:
+    case NODEWORDS_TYPE_NODE:
       $token_type = 'node';
-      $token_object = node_load(array('vid' => $id));
+      $token_object = node_load(array('vid' => $sid));
       break;
 
-    case NODEWORDS_MT_TYPE_USER:
+    case NODEWORDS_TYPE_USER:
       $token_type = 'user';
       $token_object = user_load($id);
       break;
@@ -1170,16 +1244,18 @@ function nodewords_replace_tokens($type,
 /**
  * Update or insert tags in the table.
  */
-function nodewords_save_tags($type, $id, $tags, $options = array()) {
+function nodewords_save_tags($tags, $type, $id, $options = array()) {
   global $user;
   static $tags_info;
 
   $default_options = array(
+    'sid => 0',
     'language' => '',
     'log_message' => TRUE,
   );
   $done = FALSE;
   $options += $default_options;
+  $sid = $options['sid'];
 
   if (!isset($tags_info)) {
     $tags_info = nodewords_get_possible_tags();
@@ -1194,12 +1270,18 @@ function nodewords_save_tags($type, $id,
         $content = $content['value'];
       }
 
-      $result = db_fetch_object(db_query("SELECT * FROM {nodewords} WHERE type = %d AND id = '%s' AND name = '%s' AND language = '%s'", $type, $id, $name, $language));
+      $result = db_fetch_object(
+        db_query(
+          "SELECT * FROM {nodewords} WHERE type = %d AND id = '%s' AND sid = %d AND name = '%s' AND language = '%s'",
+          $type, $id, $sid, $name, $language
+        )
+      );
 
       if ($result === FALSE) {
         $row = new stdClass();
         $row->type = $type;
         $row->id = $id;
+        $row->sid = $sid;
         $row->name = $name;
       }
       else {
@@ -1208,10 +1290,16 @@ function nodewords_save_tags($type, $id,
 
       $row->content = $content;
 
-      drupal_write_record('nodewords', $row, $result !== FALSE ? 'mtid' : NULL);
+      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));
+        watchdog(
+          'nodewords',
+          'User %name changed the meta tags for type %type (%id - %sid).',
+          array(
+            '%name' => $user->name, '%type' => $type, '%id' => $id, '%sid' => $sid
+          )
+        );
         $done = TRUE;
       }
     }
@@ -1235,15 +1323,20 @@ function nodewords_save_tags($type, $id,
  *   A string containing only unique items present in the string of concatenated
  *   items.
  */
-function nodewords_unique($text, $separator = ',', $max_items = -1) {
+function nodewords_unique_values($text, $options =  array()) {
+  $default_options = array(
+    'separator' => ',',
+    'max_items' => -1,
+  );
   $lc_values = array();
+  $options += $default_options;
   $unique_values = array();
 
   if (empty($text)) {
     return '';
   }
 
-  foreach (array_filter(array_map('trim', explode($separator, $text))) as $item) {
+  foreach (array_filter(array_map('trim', explode($options['separator'], $text))) as $item) {
     $lowercase = drupal_strtolower($item);
 
     if (!in_array($lowercase, $lc_values)) {
@@ -1252,11 +1345,11 @@ function nodewords_unique($text, $separa
     }
   }
 
-  if ($max_items > 0) {
-    $unique_values = array_slice($uniq_values, 0, $max_items);
+  if ($options['max_items'] > 0) {
+    $unique_values = array_slice($uniq_values, 0, $options['max_items']);
   }
 
-  return implode("$separator ", $unique_values);
+  return implode($options['separator'] . " ", $unique_values);
 }
 
 /*****************************************************************************
@@ -1264,51 +1357,23 @@ function nodewords_unique($text, $separa
  ****************************************************************************/
 
 /**
- * Show the requirement errors reported from nodewords_requirements().
- * The function is an adaption of drupal_check_module(), and it is called in
- * the module settings pages.
- */
-function _nodewords_check_enabled_modules() {
-  if (user_access('administer site configuration')) {
-    if (!count(module_implements('nodewords_api'))) {
-      drupal_set_message(
-        t(
-          'Nodewords does not create meta tags anymore; it is just a module that implements a public API used from the modules that create meta tags. You need to <a href="@url">enable</a> at least one module between nodewords_basic.module, nodewords_extra.module, and nodewords_verification_tags.module that are listed under <em>Meta tags</em> in the <a href="@url">modules page</a>.',
-          array('@url' => url('admin/build/modules'))
-        ),
-        'error'
-      );
-    }
-
-    if (module_exists('nodewords_bypath')) {
-      drupal_set_message(
-        t(
-          'The feature implemented in <q>Meta Tags by Path</q> is now included in Nodewords; there is not need to use <q>Meta Tags by Path</q>, and the module should be disabled to avoid possible conflicts. Disable the module in the<a href="@url">modules page</a>.',
-          array('@url' => url('admin/build/modules'))
-        )
-      );
-    }
-  }
-}
-
-/**
  * Try to guess the $type and $id by looking at $_GET['q'].
  */
 function _nodewords_detect_type_and_id() {
   $arg = arg();
 
   if (variable_get('site_offline', 0) && !user_access('administer site configuration')) {
-    return array(NODEWORDS_MT_TYPE_NONE, 0);
+    return array(NODEWORDS_TYPE_NONE, '');
   }
 
   $headers = drupal_get_headers();
 
   if (preg_match('@HTTP/1\.[01]\x20+403@', $headers)) {
-    return array(NODEWORDS_MT_TYPE_ERRORPAGE, 403);
+    return array(NODEWORDS_TYPE_ERRORPAGE, 403);
   }
 
   if (preg_match('@HTTP/1\.[01]\x20+404@', $headers)) {
-    return array(NODEWORDS_MT_TYPE_ERRORPAGE, 404);
+    return array(NODEWORDS_TYPE_ERRORPAGE, 404);
   }
 
   $bool = (
@@ -1318,15 +1383,32 @@ function _nodewords_detect_type_and_id()
   );
 
   if ($bool) {
-    return array('pager', 0);
+    return array(NODEWORDS_TYPE_PAGER, '');
   }
 
   if (drupal_is_front_page() && variable_get('nodewords_use_frontpage_tags', TRUE)) {
-    return array(NODEWORDS_MT_TYPE_FRONTPAGE, 0);
+    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, $path);
+    }
   }
 
   if (!isset($arg[0])) {
-    return array(NODEWORDS_MT_TYPE_NONE, 0);
+    return array(NODEWORDS_TYPE_NONE, '');
   }
 
   _nodewords_load_all_includes();
@@ -1334,18 +1416,12 @@ function _nodewords_detect_type_and_id()
   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) {
+    if (isset($result) && is_array($result) && count($result) >= 2) {
       return $result;
     }
   }
 
-  foreach (_nodewords_get_pages_data() as $page) {
-    if (preg_match($page->regexp, $_GET['q'])) {
-      return array(NODEWORDS_MT_TYPE_PAGE, $page->path);
-    }
-  }
-
-  return array(NODEWORDS_MT_TYPE_NONE, 0);
+  return array(NODEWORDS_TYPE_NONE, '');
 }
 
 /**
@@ -1363,8 +1439,7 @@ function _nodewords_get_pages_data($id =
     $result = db_query("SELECT * FROM {nodewords_custom} ORDER BY weight ASC");
 
     while ($page = db_fetch_object($result)) {
-      $page->regexp = '/^('. preg_replace('/\\\\\*/', '.*', preg_quote($page->path, '/')) .')$/';
-      $page->tags = nodewords_load_tags(NODEWORDS_MT_TYPE_PAGE, $page->path);
+      $page->tags = nodewords_load_tags(NODEWORDS_TYPE_PAGE, $page->path);
 
       $pages[$page->pid] = $page;
     }
@@ -1391,11 +1466,11 @@ function _nodewords_load_all_includes() 
  * 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_teaser_match_callback($matches, $init = FALSE) {
+function _nodewords_teaser_match_callback($matches) {
   static $bool;
 
-  if ($init) {
-    $bool = $matches;
+  if (!isset($bool)) {
+    $bool = variable_get('nodewords_use_alt_attribute', FALSE);
   }
 
   if ($bool && !empty($matches[1])) {
Index: README.txt
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/nodewords/README.txt,v
retrieving revision 1.30.2.2
diff -u -p -r1.30.2.2 README.txt
--- README.txt	17 Nov 2009 05:25:34 -0000	1.30.2.2
+++ README.txt	30 Nov 2009 22:59:36 -0000
@@ -1,62 +1,112 @@
 ; $Id: README.txt,v 1.30.2.2 2009/11/17 05:25:34 kiam Exp $
 
-This module allows you to set some meta tags for each node.
-
-Giving more attention to the important keywords and/or description on some of
-your nodes allows you to get better search engine positioning (given that you
-really only provide the keywords which exist in the node body itself, and do
-not try to lie).
+This module allows you to set some meta tags for the different resources exposed
+by your site: nodes, users, views, taxonomy filters and error pages are some
+examples.
+
+Giving more attention to the important keywords and/or description on your site
+allows you to get better search engine positioning (given that you really only
+provide the keywords which exist in the content itself, and do not try to lie).
 
 This version of the module only works with Drupal 6.x.
 
 Features
 ------------------------------------------------------------------------------
-Some features include:
-
-* The current supported meta tags are ABSTRACT, CANONICAL, COPYRIGHT,
-  GEO.POSITION, DESCRIPTION, ICBM, KEYWORDS, PICS-LABEL, REVISIT-AFTER, ROBOTS
-  and the site verification meta tags used by Google Webmaster Tools,
-  Microsoft Bing Webmaster Center, Yahoo! Site Explorer.
-
-* You can tell "nodewords" to add all terms of some specified vocabularies
-  to the KEYWORDS meta tag.
-
-* You can specify a default meta tag ROBOTS value to use for all pages. You can
-  override it on each page.
-
-* On taxonomy pages, the term description is used as the DESCRIPTION
-  tag. The term itself is added to the list of KEYWORDS. You can override
-  the description to use if you wish.
+This is a brief of features provided by this module:
 
 * You can seperately specify the meta tags to show on some specific pages of
-  your site (in example, the front page, the error 403 page, the error 404
-  page, the tracker page), or to use in specific situations (in example, when
-  the site is offline).
-
-* The support for Views, and Panels has been removed from Nodewords
-  6.x-1.x on August 15, 2009; successive versions for Drupal 6 replaced it with
-  a more generic support for third-party module pages.
-
-* You can select which of these tags you want to output on each page. You
-  can also remove the edit box for these tags from the node edit page if
-  you don't like using it.
+  your site (the front page, the error 403 page, the error 404 page, the tracker
+  page), or to use in specific situations, when the site is offline for example.
+
+* A pluggable system allow the inclusion of new meta tags appart from the ones
+  provided by this module.
+
+* The current supported basic meta tags are ABSTRACT, CANONICAL, COPYRIGHT,
+  GEO.POSITION, DESCRIPTION, ICBM, KEYWORDS, PICS-LABEL, REVISIT-AFTER, ROBOTS.
+  These meta tags are provided by the module: nodewords_basic.
+
+* Additionally, you may include site verification meta tags used by external
+  sources: Google Webmaster Tools, Microsoft Bing Webmaster Center, Yahoo! Site
+  Explorer.
+  These meta tags are provided by the module: nodewords_verification.
+
+* Additionally you may include the Dublin Core meta tag schema.
+  These meta tags are provided by the module: nodewords_extra.
+
+* You can select which of the available tags will be available for edition, and
+  which will be exposed in the html of your site.
+
+* You can specify a default meta tag ROBOTS value used for all pages, but easily
+  overide it for every page.
 
 * All text of the DESCRIPTION and KEYWORDS meta tags are added to the search
   system so they are searable too; other meta tags could be added to the search
   system too (depending on the code implemented from the module).
 
+Other modules integration
+-------------------------
+Nodewords integrates other modules for automatic selection of meta tags.
+
+* You can tell "nodewords" to add all terms of some specified vocabularies to
+  the KEYWORDS meta tag, integrating taxonomy vocabularies and nodewords.
+
+* On taxonomy pages, the term description is used as the DESCRIPTION tag. The
+  term itself is added to the list of KEYWORDS. You can override the description
+  to use if you wish.
+
+* Previous versions of this module provided support for Views and Panels. This
+  feature has been removed from Nodewords 6.x-1.x since August 15, 2009; as the
+  module provides an API allowing other modules to integrate with nodewords.
+
+* This module may also integrate taggadelic, cck, and other resources.
+
 Installing Nodewords (aka Meta tags) (first time installation)
 ------------------------------------------------------------------------------
 1. Backup your database.
 
-2. Copy the complete 'nodewords/' directory into the 'modules/' directory of
-   your Drupal site.
+2. Copy the complete 'nodewords/' directory into the 'sites/all/modules/',
+   'sites/default/modules' or 'sites/name_of_your_site/modules' folder of your
+   Drupal setup. More information about installing contributed modules could be
+   found at "Install contributed modules" (http://drupal.org/node/70151)
 
 3. Enable the "Nodewords" module from the module administration page
    (Administer >> Site configuration >> Modules).
 
 4. Configure the module (see "Configuration" below).
 
+5. You should enable other modules providing meta tags. The nodewords module
+   includes three meta tags modules:
+   - nodewords basic: for typical DESCRIPTION, ABSTRACT, COPYRIGHT meta tags.
+   - nodewords extra: for Dublin meta tag Schema
+   - nodewords verification tags: for especific API meta tags by search engines.
+
+Updating Nodewords (aka Meta tags) (module version upgrade)
+------------------------------------------------------------------------------
+1. Verify that the version you are going to upgrade contains all the features
+   your are using in your Drupal setup. Some features could have been removed
+   or replaced by others.
+
+2. Read carefully in the project issue tracking about upgrade paths problems
+   before you start the upgrade process. Some versions don't support a clean
+   upgrade path that may left your site meta tags unusable.
+
+3. Backup your database.
+
+4. Update current module code with latest recommended version. Previous versions
+   could have bugs already reported and fixed in the last version.
+
+4. Complete the update process, set maintenance mode, call the update.php script
+   and finish the update operation. For more information please go to:
+   http://groups.drupal.org/node/19513
+
+4. Verify your module configuration and check that the features you are using
+   work as expected. Also verify that all required modules are enabled, and
+   permissions are set as desired.
+
+Note: whenever you have the chance, try an update in a local or development
+      copy of your site.
+
+
 Configuration
 ------------------------------------------------------------------------------
 1. On the access control administration page ("Administer >> User management
@@ -72,76 +122,54 @@ Configuration
 
    All users will be able to see the assigned meta tags.
 
-2. On the settings page ("Administer >> Content management >>
-   Nodewords") you can specify the default settings for the module.
-   Users need the "administer nodewords" permission to do this.
-
-3. The front page is an important page for each website. Therefor you can
-   specifically set the meta tags to use on the front page meta tags
-   settings page ("Administer >> Content management >> Nodewords >>
-   Front page").
-   Users need the "administer nodewords" permission to do this.
-
-   Alternatively, you can opt not to set the meta tags for the front page
-   on this page, but to use the meta tags of the view, panel or node the
-   front page points to. To do this, you need to uncheck the "Use front
-   page meta tags" option on the settings page.
-
-   Note that, in contrast to previous versions of this module, the site
-   mission and/or site slogan are no longer used as DESCRIPTION or ABSTRACT
-   on the front page!
-
-4. You can completely disable the possibility to edit meta tags for each
-   individual content type by editing the content type workflow options
+2. On the settings page ("Administer >> Content management >> Nodewords") you
+   can specify the default settings for the module. To access this page users
+   need the "administer nodewords" permission.
+
+3. You should enable meta tags for editing before they are available for use.
+   The same operation should be done for meta tag output. Only allowed Meta tags
+   are available for editing or exposed in the HTML of your site.
+
+4. The front page is an important page for each website. Therefor you can
+   specifically set the meta tags to use on the front page meta tags settings
+   page ("Administer >> Content management >> Nodewords >> Front page").
+   Users need the "administer nodewords" permission to do this. When there are
+   resources providing meta tags promoted in the front page, you may Force the
+   usage of "Front page" meta tags superseeding all of them.
+
+   Alternatively, you can opt not to set the meta tags for the front page on
+   this page, but to use the meta tags of the view, panel or node the front page
+   points to. To do this, you need to uncheck the "Use front page meta tags"
+   option on the settings page.
+
+   Note that, in contrast to previous versions of this module, the site mission
+   and/or site slogan are no longer used as DESCRIPTION or ABSTRACT on the front
+   page!
+
+5. You can completely disable the possibility to edit meta tags for each
+   individual content type by editing the content type workflow options, by
+   default meta tags are enabled for all content types.
    ("Administer >> Content management >> Content types").
 
-   Note that this will still output the default values for the meta tags.
-
-Using Nodewords and Tagadelic
-------------------------------------------------------------------------------
-The Tagadelic module (http://drupal.org/project/tagadelic) allows one to
-create a cloud of all terms used. The keywords you assign to nodes with
-the Nodewords module will not appear in these clouds.
+   Note: this will still output the default values for the meta tags.
 
-If you want to use tagclouds and have the same terms in the KEYWORDS meta
-tag, you can configure nodewords as follows:
-
-1. Create a "Free tagging" vocabulary at "Administer >> Content management
-   >> Categories". For example, call this vocabulary "Keywords".
-
-2. On the meta tags settings page ("Administer >> Content management >>
-   Nodewords"), select the "Keywords" vocabulary as one of the "Auto-keywords
-   vocabularies". This will make sure that all terms you assign to nodes
-   will appear in the KEYWORDS meta tag.
-
-3. On the same page, deselect the checkbox "Keywords" in the "Tags to
-   show on edit form" fieldset. This will remove the meta tag KEYWORDS
-   input box on all node edit forms. The only way to assign KEYWORDS then
-   is to enter them in the vocabulary "Keywords" input box (which will
-   appear in the "Categories" box instead of the "Meta tags" one).
-
-The result is that the meta tag KEYWORDS will only contain the keywords
-assigned to nodes by entering them in the free-tagging input box of the
-"Keywords" vocabulary. Nodewords will add them to the KEYWORDS meta tag
-and you can use a tagcloud to show all keywords too.
-
-Auto-generated meta DESCRIPTION for CCK content types
-------------------------------------------------------------------------------
-It is recommended to use the contemplate (Content Template) module to
-create a nicer looking node teaser that can also be used as auto-generated
-DESCRIPTION.
 
 Bugs and shortcomings
 ------------------------------------------------------------------------------
-* See the list of issues at http://drupal.org/project/issues/nodewords.
+* See the list of project issues[1].
 
 Credits / Contact
 ------------------------------------------------------------------------------
-The original author of this module is Andras Barthazi.
-Mike Carter (http://drupal.org/user/13164) and Gabor Hojtsy
-(http://drupal.org/user/4166) provided some feature enhancements.
-Robrecht Jacques (http://drupal.org/user/22598) is the current maintainer;
-Alberto Paderno (http://drupal.org/user/55077) is the current co-maintainer.
-
-Best way to contact the authors is to submit a (support/feature/bug) issue at
-the projects issue page at http://drupal.org/project/issues/nodewords.
+Original author of this module is Andras Barthazi. Mike Carter[2]
+and Gabor Hojtsy[3]
+provided some feature enhancements. Robrecht Jacques[4] is current maintainer,
+and Alberto Paderno[5] is the current co-maintainer.
+
+Best way to contact the authors is to submit a (support/feature/bug) issue in
+the project issue queue at http://drupal.org/project/issues/nodewords.
+
+[1]    http://drupal.org/project/issues/nodewords
+[2]    http://drupal.org/user/13164
+[3]    http://drupal.org/user/4166
+[4]    http://drupal.org/user/22598
+[5]    http://drupal.org/user/55077
