From 1b92474dd13ef81d90f725e09efcc681cba1c335 Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Thu, 17 Oct 2013 15:51:54 +0300
Subject: [PATCH] Issue #1973770 by robinvdvleuten, k0teg, dubois, mikeharty,
 claudiu.cristea: Added Integration with users, entityreference, taxonomy term
 references, field collections and nodequeue items.

---
 includes/modules/entityreference.inc               |  90 +++++++++
 includes/modules/field_collection.inc              |  54 +++++
 includes/modules/taxonomy.inc                      |  62 +++---
 includes/modules/user.inc                          |  35 ++++
 .../uuid_current_search_configuration.features.inc |  90 +++++++++
 includes/uuid_field_collection.features.inc        | 151 ++++++++++++++
 includes/uuid_node.features.inc                    |  89 ++++++---
 includes/uuid_nodequeue_item.features.inc          | 123 ++++++++++++
 includes/uuid_term.features.inc                    |  23 ++-
 includes/uuid_user.features.inc                    | 159 +++++++++++++++
 uuid_features.module                               | 222 +++++++++++++++++++--
 11 files changed, 1014 insertions(+), 84 deletions(-)
 create mode 100644 includes/modules/entityreference.inc
 create mode 100644 includes/modules/field_collection.inc
 create mode 100644 includes/modules/user.inc
 create mode 100644 includes/uuid_current_search_configuration.features.inc
 create mode 100644 includes/uuid_field_collection.features.inc
 mode change 100755 => 100644 includes/uuid_node.features.inc
 create mode 100644 includes/uuid_nodequeue_item.features.inc
 create mode 100644 includes/uuid_user.features.inc

diff --git a/includes/modules/entityreference.inc b/includes/modules/entityreference.inc
new file mode 100644
index 0000000..3c7ee6a
--- /dev/null
+++ b/includes/modules/entityreference.inc
@@ -0,0 +1,90 @@
+<?php
+
+/**
+ * Implements hook_uuid_node_features_export_render_alter().
+ *
+ * @param $export
+ * @param $node
+ * @param $module
+ */
+function entityreference_uuid_node_features_export_render_alter(&$export, &$node, $module) {
+  $fields = uuid_features_get_field_items_iterator($export, 'node', 'entityreference');
+  _entity_reference_uuid_entity_features_export_set_uuid_references($fields);
+}
+
+/**
+ * Implements hook_uuid_user_features_export_render_alter().
+ *
+ * @param $export
+ * @param $node
+ * @param $module
+ */
+function entityreference_uuid_user_features_export_render_alter(&$export, &$user, $module) {
+  $fields = uuid_features_get_field_items_iterator($export, 'user', 'entityreference');
+  _entity_reference_uuid_entity_features_export_set_uuid_references($fields);
+}
+
+/**
+ * Implements hook_uuid_node_features_rebuild_alter().
+ *
+ * @param $node
+ * @param $module
+ */
+function entityreference_uuid_node_features_rebuild_alter(&$node, $module) {
+  $fields = uuid_features_get_field_items_iterator($node, 'node', 'entityreference');
+  _entity_reference_uuid_entity_features_rebuild_fetch_uuid_references($fields);
+}
+
+/**
+ * Implements hook_uuid_user_features_rebuild_alter().
+ *
+ * @param $node
+ * @param $module
+ */
+function entityreference_uuid_user_features_rebuild_alter(&$user, $module) {
+  $fields = uuid_features_get_field_items_iterator($user, 'user', 'entityreference');
+  _entity_reference_uuid_entity_features_rebuild_fetch_uuid_references($fields);
+}
+
+/**
+ * Helper function to fetch uuid references in case of different fields types.
+ *
+ * @param $fields
+ */
+function _entity_reference_uuid_entity_features_rebuild_fetch_uuid_references(&$fields) {
+  // Entityreference fields may have different targets (nodes, users, etc.).
+  // So we process them one by one.
+  foreach ($fields as $field_name => $field) {
+    $field_info = field_info_field($field_name);
+    $entity_info = entity_get_info($field_info['settings']['target_type']);
+
+    // uuid_features_fetch_uuid_references accepts only references to array as the first parameter.
+    $tmp_fields = array(
+      $field_name => &$field,
+    );
+
+    uuid_features_fetch_uuid_references($tmp_fields, $field_info['settings']['target_type'], array(
+      $entity_info['entity keys']['id'] => 'target_id',
+    ));
+  }
+}
+
+/**
+ * Helper function to set uuid references in case of different fields types.
+ *
+ * @param $fields
+ */
+function _entity_reference_uuid_entity_features_export_set_uuid_references(&$fields) {
+  // Entityreference fields may have different targets (nodes, users, etc.).
+  // So we process them one by one.
+  foreach ($fields as $field_name => &$field) {
+    $field_info = field_info_field($field_name);
+
+    // uuid_features_fetch_uuid_references accepts only references to array as the first parameter.
+    $tmp_fields = array(
+      $field_name => &$field,
+    );
+
+    uuid_features_set_uuid_references($tmp_fields, $field_info['settings']['target_type']);
+  }
+}
diff --git a/includes/modules/field_collection.inc b/includes/modules/field_collection.inc
new file mode 100644
index 0000000..622046f
--- /dev/null
+++ b/includes/modules/field_collection.inc
@@ -0,0 +1,54 @@
+<?php
+
+
+/**
+ * Implements hook_uuid_node_features_export_render_alter().
+ *
+ * @param $export
+ * @param $node
+ * @param $module
+ */
+function field_collection_uuid_node_features_export_render_alter(&$export, &$node, $module) {
+  $fields = uuid_features_get_field_items_iterator($export, 'node', 'field_collection');
+  uuid_features_set_uuid_references($fields, 'field_collection_item');
+}
+
+/**
+ * Implements hook_uuid_user_features_export_render_alter().
+ *
+ * @param $export
+ * @param $node
+ * @param $module
+ */
+function field_collection_uuid_user_features_export_render_alter(&$export, &$user, $module) {
+  $fields = uuid_features_get_field_items_iterator($export, 'user', 'field_collection');
+  uuid_features_set_uuid_references($fields, 'field_collection_item');
+}
+
+/**
+ * Implements hook_uuid_node_features_rebuild_alter().
+ *
+ * @param $node
+ * @param $module
+ */
+function field_collection_uuid_node_features_rebuild_alter(&$node, $module) {
+  $fields = uuid_features_get_field_items_iterator($node, 'node', 'field_collection');
+  uuid_features_fetch_uuid_references($fields, 'field_collection_item', array(
+    'item_id' => 'value',
+    'revision_id' => 'revision_id',
+  ));
+}
+
+/**
+ * Implements hook_uuid_user_features_rebuild_alter().
+ *
+ * @param $node
+ * @param $module
+ */
+function field_collection_uuid_user_features_rebuild_alter(&$user, $module) {
+  $fields = uuid_features_get_field_items_iterator($user, 'user', 'field_collection');
+  uuid_features_fetch_uuid_references($fields, 'field_collection_item', array(
+    'item_id' => 'value',
+    'revision_id' => 'revision_id',
+  ));
+}
diff --git a/includes/modules/taxonomy.inc b/includes/modules/taxonomy.inc
index d7fdd7e..2a440f5 100644
--- a/includes/modules/taxonomy.inc
+++ b/includes/modules/taxonomy.inc
@@ -22,40 +22,48 @@ function taxonomy_uuid_node_features_export_alter(&$export, &$pipe, $node) {
 
 /**
  * Implements hook_uuid_node_features_export_render_alter().
+ *
+ * @param $export
+ * @param $node
+ * @param $module
  */
 function taxonomy_uuid_node_features_export_render_alter(&$export, &$node, $module) {
-  if (!empty($node->taxonomy)) {
-    $export->uuid_term = array();
-    foreach ($node->taxonomy as $term) {
-      $export->uuid_term[] = $term->uuid;
-    }
-  }
+  $fields = uuid_features_get_field_items_iterator($export, 'node', 'taxonomy_term_reference');
+  uuid_features_set_uuid_references($fields, 'taxonomy_term');
 }
 
 /**
+ * Implements hook_uuid_user_features_export_render_alter().
+ *
+ * @param $export
+ * @param $node
+ * @param $module
+ */
+function taxonomy_uuid_user_features_export_render_alter(&$export, &$user, $module) {
+  $fields = uuid_features_get_field_items_iterator($export, 'user', 'taxonomy_term_reference');
+  uuid_features_set_uuid_references($fields, 'taxonomy_term');
+}
+
+
+/**
  * Implements hook_uuid_node_features_rebuild_alter().
- * Build a taxonomy array suitable for node_save() from the uuid_term array.
  */
 function taxonomy_uuid_node_features_rebuild_alter(&$node, $module) {
-  if (!empty($node->uuid_term)) {
-    $node->taxonomy = array();
-    foreach ($node->uuid_term as $uuid) {
-      $tid = uuid_taxonomy_term_find($uuid);
-      if (empty($tid)) {
-        // If no tid was found, then the term doesn't exist, and most likely
-        // the uuid_term rebuild needs to run first.
-        // TODO: figure out how to weight feature components.
-        uuid_term_features_rebuild($module);
-
-        // Now try again.
-        $tid = uuid_taxonomy_term_find($uuid);
-        if (empty($tid)) {
-          watchdog('uuid_features', 'The term specified by %uuid could not be found.', array('%uuid' => $uuid));
-          continue;
-        }
-      }
+  $fields = uuid_features_get_field_items_iterator($node, 'node', 'taxonomy_term_reference');
+  uuid_features_fetch_uuid_references($fields, 'taxonomy_term', array(
+    'tid' => 'tid',
+  ));
+}
 
-      $node->taxonomy[] = $tid;
-    }
-  }
+/**
+ * Implements hook_uuid_user_features_rebuild_alter().
+ *
+ * @param $node
+ * @param $module
+ */
+function taxonomy_uuid_user_features_rebuild_alter(&$user, $module) {
+  $fields = uuid_features_get_field_items_iterator($user, 'user', 'taxonomy_term_reference');
+  uuid_features_fetch_uuid_references($fields, 'taxonomy_term', array(
+    'tid' => 'tid',
+  ));
 }
diff --git a/includes/modules/user.inc b/includes/modules/user.inc
new file mode 100644
index 0000000..bc91ead
--- /dev/null
+++ b/includes/modules/user.inc
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * Implements hook_uuid_node_features_export_render_alter().
+ *
+ * @param $export
+ * @param $node
+ * @param $module
+ */
+function user_uuid_node_features_export_render_alter(&$export, &$node, $module) {
+  $uuids = entity_get_uuid_by_id('user', array($node->uid));
+  $uuid = reset($uuids);
+  if ($uuid) {
+    $export->user_uuid = $uuid;
+  }
+}
+
+/**
+ * Implements hook_uuid_node_features_rebuild_alter().
+ *
+ * @param $node
+ * @param $module
+ */
+function user_uuid_node_features_rebuild_alter(&$node, $module) {
+  if (isset($node->user_uuid) && uuid_is_valid($node->user_uuid)) {
+    $uid = reset(entity_get_id_by_uuid('user', array($node->user_uuid)));
+    if ($uid) {
+      $node->uid = $uid;
+    } else {
+      $node->uid = 1;
+    }
+  } else {
+    $node->uid = 1;
+  }
+}
diff --git a/includes/uuid_current_search_configuration.features.inc b/includes/uuid_current_search_configuration.features.inc
new file mode 100644
index 0000000..bcdc755
--- /dev/null
+++ b/includes/uuid_current_search_configuration.features.inc
@@ -0,0 +1,90 @@
+<?php
+/**
+ * @file
+ * Features hooks for the uuid_current_search features component.
+ */
+
+/**
+ * Implements hook_features_export_options().
+ */
+function uuid_current_search_configuration_features_export_options() {
+  $options = array();
+
+  $current_search_items = db_select('block_current_search', 'b')
+    ->fields('b', array('delta', 'searcher'))
+    ->execute()
+    ->fetchAllAssoc('delta');
+
+  foreach ($current_search_items as $config) {
+    $options[$config->delta] = $config->delta;
+  }
+
+  drupal_alter('uuid_current_search_configuration_features_export_options', $options);
+
+  return $options;
+}
+
+/**
+ * Implements hook_features_export().
+ */
+function uuid_current_search_configuration_features_export($data, &$export, $module_name = '') {
+  $export['dependencies']['current_search'] = 'current_search';
+
+  foreach ($data as $uuid) {
+    $export['features']['uuid_current_search_configuration'][$uuid] = $uuid;
+  }
+  return array();
+}
+
+/**
+ * Implements hook_features_export_render().
+ */
+function uuid_current_search_configuration_features_export_render($module = 'foo', $data) {
+  $translatables = $code = array();
+
+  $code[] = '  $current_search_configurations = array();';
+  $code[] = '';
+  foreach ($data as $uuid) {
+    $block_config = db_select('block_current_search', 'b')
+      ->fields('b', array('delta', 'searcher'))
+      ->condition('b.delta', $uuid)
+      ->execute()
+      ->fetchAssoc();
+
+    if ($block_config) {
+      $code[] = '  $current_search_configurations[] = ' . features_var_export($block_config, '  ') . ';';
+    }
+  }
+
+  if (!empty($translatables)) {
+    $code[] = features_translatables_export($translatables, '  ');
+  }
+  $code[] = '  return $current_search_configurations;';
+  $code = implode("\n", $code);
+  return array('uuid_features_default_current_search_configurations' => $code);
+}
+
+/**
+ * Implements hook_features_revert().
+ */
+function uuid_current_search_configuration_features_revert($module) {
+  uuid_current_search_configuration_features_rebuild($module);
+}
+
+/**
+ * Implements hook_features_rebuild().
+ */
+function uuid_current_search_configuration_features_rebuild($module) {
+  $block_current_search_configurations = module_invoke($module, 'uuid_features_default_current_search_configurations');
+  if (!empty($block_current_search_configurations)) {
+    foreach ($block_current_search_configurations as $block_current_search_configuration) {
+      db_delete('block_current_search')
+        ->condition('delta', $block_current_search_configuration['delta'])
+        ->execute();
+      $record = new stdClass;
+      $record->delta = $block_current_search_configuration['delta'];
+      $record->searcher = $block_current_search_configuration['searcher'];
+      drupal_write_record('block_current_search', $record);
+    }
+  }
+}
diff --git a/includes/uuid_field_collection.features.inc b/includes/uuid_field_collection.features.inc
new file mode 100644
index 0000000..8148b79
--- /dev/null
+++ b/includes/uuid_field_collection.features.inc
@@ -0,0 +1,151 @@
+<?php
+/**
+ * @file
+ * Features hooks for the uuid_field_collection features component.
+ */
+
+/**
+ * Implements hook_features_export_options().
+ */
+function uuid_field_collection_features_export_options() {
+  $options = array();
+
+  $all_ids = array();
+
+  $efq_field_collection_items = new EntityFieldQuery();
+  $efq_field_collection_items->entityCondition('entity_type', 'field_collection_item');
+  $result = $efq_field_collection_items->execute();
+
+  if (!empty($result['field_collection_item'])) {
+    $all_ids = array_keys($result['field_collection_item']);
+  }
+
+  $items = entity_load('field_collection_item', $all_ids);
+
+  foreach ($items as $item) {
+    $info = $item->instanceInfo();
+
+    $options[$item->uuid] = t('@type: @title', array(
+      '@type' => $info['label'],
+      '@title' => $item->defaultLabel(),
+    ));
+  }
+
+  drupal_alter('uuid_field_collection_features_export_options', $options);
+
+  return $options;
+}
+
+/**
+ * Implements hook_features_export().
+ */
+function uuid_field_collection_features_export($data, &$export, $module_name = '') {
+  $export['dependencies']['field_collection'] = 'field_collection';
+  $export['dependencies']['uuid'] = 'uuid';
+  $export['dependencies']['uuid_features'] = 'uuid_features';
+
+  foreach ($data as $uuid) {
+    $export['features']['uuid_field_collection'][$uuid] = $uuid;
+  }
+  return array();
+}
+
+/**
+ * Implements hook_features_export_render().
+ */
+function uuid_field_collection_features_export_render($module = 'foo', $data) {
+  $translatables = $code = array();
+
+  $code[] = '  $field_collections = array();';
+  $code[] = '';
+  foreach ($data as $uuid) {
+    $field_collections = entity_uuid_load('field_collection_item', array($uuid), array(), TRUE);
+    if (!count($field_collections)) {
+      continue;
+    }
+
+    $export = reset($field_collections);
+
+    // Do not export ids.
+    unset($export->item_id);
+    unset($export->revision_id);
+
+    uuid_features_file_field_export($export, 'field_collection_item');
+
+    $export_output = features_var_export($export, '  ');
+    $export_output = str_replace("entity_import('field_collection_item', '", "", $export_output);
+    $export_output = str_replace("}')", "}", $export_output);
+    $export_output = json_decode($export_output, TRUE);
+
+    $code[] = '  $field_collections[] = ' . features_var_export($export_output, '  ') . ';';
+  }
+
+  if (!empty($translatables)) {
+    $code[] = features_translatables_export($translatables, '  ');
+  }
+  $code[] = '  return $field_collections;';
+  $code = implode("\n", $code);
+
+  return array('uuid_features_default_field_collections' => $code);
+}
+
+/**
+ * Implements hook_features_revert().
+ */
+function uuid_field_collection_features_revert($module) {
+  uuid_field_collection_features_rebuild($module);
+}
+
+/**
+ * Implements hook_features_rebuild().
+ */
+function uuid_field_collection_features_rebuild($module) {
+  // Make sure all referenced entities exist.
+  taxonomy_features_rebuild($module);
+  field_features_rebuild($module);
+  uuid_node_features_rebuild($module);
+  cache_clear_all();
+
+  $field_collections = module_invoke($module, 'uuid_features_default_field_collections');
+  if (!empty($field_collections)) {
+    foreach ($field_collections as $field_collection_item) {
+      try {
+        $fields = field_info_instances('field_collection_item', $field_collection_item['field_name']);
+        foreach ($fields as $field_name => $field_instance_config) {
+          $field_config = field_info_field($field_name);
+          if (isset($field_collection_item[$field_name])) {
+            foreach ($field_collection_item[$field_name] as $lang => $field_data) {
+              foreach ($field_data as $delta => $value) {
+                if ($field_config['type'] == 'entityreference' || $field_config['type'] == 'taxonomy_term_reference') {
+                  $columns = array_keys($field_config['columns']);
+                  $first_column = reset($columns);
+                  if (isset($field_config['settings']['target_type'])) {
+                    $target_entity = $field_config['settings']['target_type'];
+                  } elseif ($field_config['type'] == 'taxonomy_term_reference') {
+                    $target_entity = 'taxonomy_term';
+                  } else {
+                    throw new Exception('Unknown target.');
+                  }
+                  $ids = entity_get_id_by_uuid($target_entity, array($value[$first_column]));
+                  $field_collection_item[$field_name][$lang][$delta][$first_column] = $ids ? reset($ids) : UUID_FEATURES_DEFAULT_FALLBACK_ID;
+                }
+              }
+            }
+          }
+        }
+
+        $field_collection_item['original'] = TRUE;
+        $entity = entity_import('field_collection_item', json_encode($field_collection_item));
+        /* @var FieldCollectionItemEntity $entity */
+        $entity->is_new = FALSE; // Hack to ignore missing host entities.
+
+        uuid_features_file_field_export($entity, 'field_collection_item');
+
+        $entity->save(TRUE);
+      } catch (Exception $e) {
+
+      }
+    }
+  }
+  uuid_node_features_rebuild($module);
+}
diff --git a/includes/uuid_node.features.inc b/includes/uuid_node.features.inc
old mode 100755
new mode 100644
index 17f931b..de3472a
--- a/includes/uuid_node.features.inc
+++ b/includes/uuid_node.features.inc
@@ -12,16 +12,19 @@ function uuid_node_features_export_options() {
 
   $types = node_type_get_names();
 
-  $query = 'SELECT n.nid, n.title, n.type, n.uuid
-    FROM {node} n ORDER BY n.type, n.title ASC';
+  $query = 'SELECT n.nid, n.title, n.type, n.uuid FROM {node} n ORDER BY n.type, n.title ASC';
   $results = db_query($query);
   foreach ($results as $node) {
-    $options[$node->uuid] = t('@type: @title', array(
-      '@type' => $types[$node->type],
-      '@title' => $node->title,
-    ));
+    $options[$node->uuid] = t('@type: @title',
+      array(
+        '@type' => $types[$node->type],
+        '@title' => $node->title,
+      )
+    );
   }
 
+  drupal_alter('uuid_node_features_export_options', $options);
+
   return $options;
 }
 
@@ -86,16 +89,24 @@ function uuid_node_features_export_render($module, $data) {
     $export->date = format_date($export->created, 'custom', 'Y-m-d H:i:s O');
 
     // Don't cause conflicts with nid/vid/revision_timestamp/changed fields.
-    unset($export->nid);
-    unset($export->vid);
-    unset($export->revision_timestamp);
-    unset($export->changed);
-    unset($export->last_comment_timestamp);
     uuid_features_file_field_export($export, 'node');
     // The hook_alter signature is:
     // hook_uuid_node_features_export_render_alter(&$export, $node, $module);
+
     drupal_alter('uuid_node_features_export_render', $export, $node, $module);
 
+    unset($export->revision_uid);
+    unset($export->revision_timestamp);
+    unset($export->nid);
+    unset($export->vid);
+    unset($export->vuuid);
+    unset($export->changed);
+    unset($export->last_comment_timestamp);
+    unset($export->last_comment_id);
+    unset($export->last_comment_name);
+    unset($export->cid);
+    unset($node->name);
+
     $code[] = '  $nodes[] = ' . features_var_export($export) . ';';
   }
 
@@ -123,28 +134,46 @@ function uuid_node_features_rebuild($module) {
   if (!empty($nodes)) {
     module_load_include('inc', 'node', 'node.pages');
 
-    foreach ($nodes as $data) {
-      $node = (object) $data;
-      node_object_prepare($node);
-
-      // Find the matching UUID, with a fresh cache.
-      $nids = entity_get_id_by_uuid('node', array($node->uuid));
-      if (isset($nids[$node->uuid])) {
-          $nid = array_key_exists($node->uuid, $nids) ? $nids[$node->uuid] : FALSE;
-          $existing = node_load($nid, NULL, TRUE);
-          if (!empty($existing)) {
-            $node->nid = $existing->nid;
-            $node->vid = $existing->vid;
-          }
+    $rebuild = FALSE;
+    $tmp = array();
+    foreach ($nodes as $key => $data) {
+      if (isset($data['og_group_ref'])) {
+        $tmp[] = $data;
+        unset($nodes[$key]);
       }
+    }
 
-      // The hook_alter signature is:
-      // hook_uuid_node_features_rebuild_alter(&node, $module);
-      drupal_alter('uuid_node_features_rebuild', $node, $module);
+    $nodes = array_merge($nodes, $tmp);
 
-      $node = node_submit($node);
-      uuid_features_file_field_import($node, 'node');
-      node_save($node);
+    $second_run_nodes = array();
+    foreach ($nodes as $data) {
+      try {
+        $node = (object) $data;
+        $node->uid = 0;
+        node_object_prepare($node);
+
+        // Find the matching UUID, with a fresh cache.
+        $nids = entity_get_id_by_uuid('node', array($node->uuid));
+        if (isset($nids[$node->uuid])) {
+            $nid = array_key_exists($node->uuid, $nids) ? $nids[$node->uuid] : FALSE;
+            $existing = node_load($nid, NULL, TRUE);
+            if (!empty($existing)) {
+              $node->nid = $existing->nid;
+              $node->vid = $existing->vid;
+            }
+        }
+
+        // The hook_alter signature is:
+        // hook_uuid_node_features_rebuild_alter(&node, $module);
+        drupal_alter('uuid_node_features_rebuild', $node, $module);
+
+        $node = node_submit($node);
+        uuid_features_file_field_import($node, 'node');
+        node_save($node);
+      } catch (Exception $e) {
+        $second_run_nodes[] = $data;
+      }
     }
   }
+  return TRUE;
 }
diff --git a/includes/uuid_nodequeue_item.features.inc b/includes/uuid_nodequeue_item.features.inc
new file mode 100644
index 0000000..fe2e518
--- /dev/null
+++ b/includes/uuid_nodequeue_item.features.inc
@@ -0,0 +1,123 @@
+<?php
+/**
+ * @file
+ * Features hooks for the uuid_nodequeue_item features component.
+ */
+
+/**
+ * Implements hook_features_export_options().
+ */
+function uuid_nodequeue_item_features_export_options() {
+  $options = array();
+  $result = db_select('nodequeue_nodes', 'qn')
+    ->fields('qn', array('qid', 'sqid', 'nid', 'position', ))
+    ->orderBy('position', 'ASC')
+    ->execute();
+  while ($row = $result->fetchAssoc()) {
+    $queue = nodequeue_load($row['qid']);
+    $uuids = entity_get_uuid_by_id('node', array($row['nid'], ));
+    $uuid = reset($uuids);
+    if ($uuid) {
+      $item_name = $queue->name . ' - ' . $uuid;
+      $options[$item_name] = $item_name;
+    }
+  }
+  return $options;
+}
+
+/**
+ * Implements hook_features_export().
+ */
+function uuid_nodequeue_item_features_export($data, &$export, $module_name = '') {
+  $export['dependencies']['nodequeue'] = 'nodequeue';
+  $export['dependencies']['uuid'] = 'uuid';
+  $export['dependencies']['uuid_features'] = 'uuid_features';
+
+  foreach ($data as $item_id) {
+    $export['features']['uuid_nodequeue_item'][$item_id] = $item_id;
+  }
+  return array();
+}
+
+/**
+ * Implements hook_features_export_render().
+ */
+function uuid_nodequeue_item_features_export_render($module = 'foo', $data) {
+  $translatables = $code = array();
+  $code[] = '  $nodequeue_items = array();';
+  $code[] = '';
+
+  if (!empty($data)) {
+    foreach ($data as $item_id) {
+      list($queue_name, $uuid) = explode(' - ', $item_id);
+      $nodequeue = nodequeue_load_queue_by_name($queue_name);
+      if ($nodequeue) {
+
+        $nids = entity_get_id_by_uuid('node', array($uuid));
+        $nid = reset($nids);
+        if ($nid) {
+          // We need to check if record exists to perform overriden state check.
+          $result = db_select('nodequeue_nodes', 'qn')
+            ->fields('qn', array('qid', 'sqid', 'nid'))
+            ->condition('qn.nid', $nid)
+            ->condition('qn.qid', $nodequeue->qid)
+            ->range(0, 1)
+            ->execute()
+            ->rowCount();
+
+          if (!$result) {
+            continue;
+          }
+        } else {
+          continue;
+        }
+
+        $uuids = entity_get_uuid_by_id('node', array($nid));
+        $uuid = reset($uuids);
+        if ($uuid) {
+          $export = array(
+            'queue_name' => $queue_name,
+            'node_uuid' => $uuid,
+          );
+          $code[] = '  $nodequeue_items[] = ' . features_var_export($export, '  ') . ';';
+        }
+      }
+    }
+  }
+  if (!empty($translatables)) {
+    $code[] = features_translatables_export($translatables, '  ');
+  }
+  $code[] = '  return $nodequeue_items;';
+  $code = implode("\n", $code);
+
+  return array('uuid_features_default_nodequeue_items' => $code);
+
+}
+
+/**
+ * Implements hook_features_revert().
+ */
+function uuid_nodequeue_item_features_revert($module) {
+  uuid_nodequeue_item_features_rebuild($module);
+}
+
+/**
+ * Implements hook_features_rebuild().
+ */
+function uuid_nodequeue_item_features_rebuild($module) {
+  $nodequeue_items = module_invoke($module, 'uuid_features_default_nodequeue_items');
+  if (!empty($nodequeue_items)) {
+    foreach ($nodequeue_items as $nodequeue_item) {
+      $queue = nodequeue_load_queue_by_name($nodequeue_item['queue_name']);
+      $subqueue = reset(nodequeue_load_subqueues_by_queue($queue->qid));
+      $nid = reset(entity_get_id_by_uuid('node', array($nodequeue_item['node_uuid'])));
+      if ($nid && !empty($queue->qid) && !empty($subqueue->sqid)) {
+        db_delete('nodequeue_nodes')
+          ->condition('qid', $queue->qid)
+          ->condition('sqid', $queue->sqid)
+          ->condition('nid', $nid);
+        nodequeue_subqueue_add($queue, $subqueue, $nid);
+      }
+    }
+  }
+}
diff --git a/includes/uuid_term.features.inc b/includes/uuid_term.features.inc
index 40acb13..b0deb6e 100644
--- a/includes/uuid_term.features.inc
+++ b/includes/uuid_term.features.inc
@@ -10,15 +10,27 @@
 function uuid_term_features_export_options() {
   $options = array();
 
-  $query = 'SELECT t.tid, t.name, v.name AS vname, t.uuid
-    FROM {taxonomy_term_data} t
-    INNER JOIN {taxonomy_vocabulary} v ON t.vid = v.vid
-    ORDER BY v.name ASC, t.name ASC';
-  $results = db_query($query);
+  $vocabs = variable_get('uuid_features_entity_taxonomy_term_vocabularies', array_fill_keys(array_keys(taxonomy_vocabulary_get_names()),0)); // Could just leave this empty.
+  $vocabs = array_filter($vocabs); // Only include vocabs that user has selected (ie. set a non zero value).
+  if (empty($vocabs)) {
+    return $options;
+  }
+
+  $query = db_select('taxonomy_term_data', 't');
+  $query->innerJoin('taxonomy_vocabulary', 'v', 't.vid = v.vid');
+  $query->condition('v.machine_name', array_keys($vocabs))
+    ->fields('t', array('tid', 'name', 'uuid'))
+    ->addField('v', 'name', 'vname');
+  $query->orderBy('v.name', 'ASC');
+  $query->orderBy('t.name', 'ASC');
+  $results = $query->execute()->fetchAll();
+
   foreach ($results as $term) {
     $options[$term->uuid] = $term->vname . ' - ' . $term->name;
   }
 
+  drupal_alter('uuid_term_features_export_options', $options);
+
   return $options;
 }
 
@@ -168,4 +180,3 @@ function uuid_term_features_rebuild($module) {
     }
   }
 }
-
diff --git a/includes/uuid_user.features.inc b/includes/uuid_user.features.inc
new file mode 100644
index 0000000..e847bf9
--- /dev/null
+++ b/includes/uuid_user.features.inc
@@ -0,0 +1,159 @@
+<?php
+
+/**
+ * Implements hook_features_export_options().
+ */
+function uuid_user_features_export_options() {
+  $options = array();
+
+  $query = 'SELECT u.uid, u.name, u.mail, u.uuid
+    FROM {users} u WHERE uid > 0 ORDER BY u.name ASC';
+  $results = db_query($query);
+  foreach ($results as $user) {
+    $options[$user->uuid] = t('@name: @mail', array(
+      '@name' => $user->name,
+      '@mail' => $user->mail,
+    ));
+  }
+
+  return $options;
+}
+
+/**
+ * Implements hook_features_export().
+ */
+function uuid_user_features_export($data, &$export, $module_name = '') {
+  $pipe = array();
+
+  $export['dependencies']['uuid_features'] = 'uuid_features';
+
+  uuid_features_load_module_includes();
+
+  $uids = entity_get_id_by_uuid('user', $data);
+  foreach ($uids as $uuid => $uid) {
+    // Load the existing user.
+    $user = user_load($uid, TRUE);
+
+    $export['features']['uuid_user'][$uuid] = $uuid;
+
+    $data = &$export;
+    drupal_alter('uuid_user_features_export', $data, $user);
+  }
+
+  return $pipe;
+}
+
+/**
+ * Implements hook_features_export_render().
+ */
+function uuid_user_features_export_render($module, $data) {
+  $translatables = $code = array();
+
+  uuid_features_load_module_includes();
+
+  $code[] = '  $users = array();';
+  $code[] = '';
+  $uids = entity_get_id_by_uuid('user', $data);
+  foreach ($uids as $uuid => $uid) {
+    // Only export the user if it exists.
+    if ($uid === FALSE) {
+      continue;
+    }
+    // Attempt to load the user, using a fresh cache.
+    $account = user_load($uid, TRUE);
+    if (empty($account)) {
+      continue;
+    }
+    $export = $account;
+
+    // Use date instead of created, in the same format used by node_object_prepare.
+    $export->date = format_date($export->created, 'custom', 'Y-m-d H:i:s O');
+    unset($export->uid);
+    $export->pass = user_password(10);
+
+    // The hook_alter signature is:
+    // hook_uuid_node_features_export_render_alter(&$export, $user, $module);
+    drupal_alter('uuid_user_features_export_render', $export, $user, $module);
+
+    $code[] = '  $users[] = ' . features_var_export($export) . ';';
+  }
+
+  if (!empty($translatables)) {
+    $code[] = features_translatables_export($translatables, '  ');
+  }
+
+  $code[] = '  return $users;';
+  $code = implode("\n", $code);
+  return array('uuid_features_default_users' => $code);
+}
+
+/**
+ * Implements hook_features_revert().
+ */
+function uuid_user_features_revert($module) {
+  uuid_user_features_rebuild($module);
+}
+
+/**
+ * Implements hook_features_rebuild().
+ * Rebuilds users based on UUID from code defaults.
+ */
+function uuid_user_features_rebuild($module) {
+  $users = module_invoke($module, 'uuid_features_default_users');
+  uuid_node_features_rebuild($module);
+  cache_clear_all();
+
+  if (!empty($users)) {
+    module_load_include('inc', 'user', 'user.pages');
+
+    foreach ($users as $data) {
+      $account = (object) $data;
+      $existing = new stdClass();
+
+      // Find the matching uid
+      $efq = new EntityFieldQuery();
+      $efq->entityCondition('entity_type', 'user');
+      $efq->propertyCondition('name', $account->name);
+      $result = $efq->execute();
+
+      if (isset($result['user'])) {
+        $uid = reset(array_keys($result['user']));
+      }
+
+      if (!empty($uid)) {
+        if ($uid == 1) {
+          global $user;
+          if (!empty($user->uid) && $user->uid == 1) {
+            $existing = $user;
+          } else {
+            $existing = user_load(1);
+          }
+        } else {
+          // Find the matching user by name with a fresh cache
+          $existing = user_load($uid, TRUE);
+          $existing->uid = $uid;
+        }
+        $account->uid = $uid;
+      }
+      else {
+        $existing->uid = NULL;
+      }
+
+      // The hook_alter signature is:
+      // hook_uuid_user_features_rebuild_alter(&user, $module);
+      drupal_alter('uuid_user_features_rebuild', $account, $module);
+
+      if($existing->uid === NULL) {
+        $account = user_save(NULL, (array) $account);
+      }
+      else {
+        // Dont' reset password.
+        unset($account->pass);
+        $account = user_save($existing, (array) $account);
+      }
+      // Clear out previously loaded user account if one was found
+      unset($existing);
+    }
+  }
+  uuid_node_features_rebuild($module);
+}
diff --git a/uuid_features.module b/uuid_features.module
index ca6a94c..e756bdc 100644
--- a/uuid_features.module
+++ b/uuid_features.module
@@ -1,5 +1,7 @@
 <?php
 
+define ('UUID_FEATURES_DEFAULT_FALLBACK_ID', 1);
+
 /**
  * Implements hook_menu().
  */
@@ -28,6 +30,14 @@ function uuid_features_features_api() {
     'file' => drupal_get_path('module', 'uuid_features') . '/includes/uuid_node.features.inc',
   );
 
+  $components['uuid_user'] = array(
+    'name' => t('Users'),
+    'feature_source' => TRUE,
+    'default_hook' => 'uuid_features_default_users',
+    'default_file' => FEATURES_DEFAULTS_INCLUDED,
+    'file' => drupal_get_path('module', 'uuid_features') . '/includes/uuid_user.features.inc',
+  );
+
   if (module_exists('taxonomy')) {
     $components['uuid_term'] = array(
       'name' => t('Taxonomy Term'),
@@ -56,6 +66,36 @@ function uuid_features_features_api() {
     'file' => drupal_get_path('module', 'uuid_features') . '/includes/uuid_bean.features.inc',
   );
 
+  if (module_exists('field_collection')) {
+    $components['uuid_field_collection'] = array(
+      'name' => t('Field collection'),
+      'feature_source' => TRUE,
+      'default_hook' => 'uuid_features_default_field_collections',
+      'default_file' => FEATURES_DEFAULTS_INCLUDED,
+      'file' => drupal_get_path('module', 'uuid_features') . '/includes/uuid_field_collection.features.inc',
+    );
+  }
+
+  if (module_exists('nodequeue')) {
+    $components['uuid_nodequeue_item'] = array(
+      'name' => t('Nodequeue item'),
+      'feature_source' => TRUE,
+      'default_hook' => 'uuid_features_default_nodequeue_items',
+      'default_file' => FEATURES_DEFAULTS_INCLUDED,
+      'file' => drupal_get_path('module', 'uuid_features') . '/includes/uuid_nodequeue_item.features.inc',
+    );
+  }
+
+  if (module_exists('current_search')) {
+    $components['uuid_current_search_configuration'] = array(
+      'name' => t('Current search block configuration'),
+      'feature_source' => TRUE,
+      'default_hook' => 'uuid_features_default_current_search_configurations',
+      'default_file' => FEATURES_DEFAULTS_INCLUDED,
+      'file' => drupal_get_path('module', 'uuid_features') . '/includes/uuid_current_search_configuration.features.inc',
+    );
+  }
+
   return $components;
 }
 
@@ -123,6 +163,22 @@ function uuid_features_settings($form, &$form_state) {
     }
   }
 
+  $form['entity']['uuid_features_entity_node_types'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Exportable node types'),
+    '#description' => t('Which content types should be exportable?'),
+    '#default_value' => variable_get('uuid_features_entity_node_types', array()),
+    '#options' => $bundles['node'],
+  );
+
+  $form['entity']['uuid_features_entity_taxonomy_term_vocabularies'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Exportable term vocabularies'),
+    '#description' => t("Which taxonomy vocabulary's terms should be exportable?"),
+    '#default_value' => variable_get('uuid_features_entity_taxonomy_term_vocabularies', array()),
+    '#options' => $bundles['taxonomy_term'],
+  );
+
   $form['file']['uuid_features_file_node_types'] = array(
     '#type' => 'checkboxes',
     '#title' => t('Files exported for nodes'),
@@ -139,6 +195,14 @@ function uuid_features_settings($form, &$form_state) {
     '#options' => $bundles['taxonomy_term'],
   );
 
+  $form['file']['uuid_features_file_field_collection_item_types'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Files exported for field collections item'),
+    '#description' => t('Which content types should export file fields?'),
+    '#default_value' => variable_get('uuid_features_file_field_collection_item_types', array()),
+    '#options' => $bundles['field_collection_item'],
+  );
+
   $form['file']['uuid_features_file_mode'] = array(
     '#type' => 'radios',
     '#title' => t('File export mode'),
@@ -181,6 +245,13 @@ function uuid_features_settings($form, &$form_state) {
     '#description' => t('Comma seperated list of file field types to detect for export/import.'),
   );
 
+  $form['settings']['uuid_features_vocabulary_terms'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Auto detect uuid terms'),
+    '#description' => t('When exporting a vocabulary, include its terms.'),
+    '#default_value' => variable_get('uuid_features_vocabulary_terms', FALSE),
+  );
+
   return system_settings_form($form);
 }
 
@@ -195,6 +266,8 @@ function uuid_features_file_field_export(&$export, $entity_type) {
     case "node":
       $export_bundle = $export->type;
       break;
+    case "field_collection_item":
+      $export_bundle = $export->field_name;
   }
   $bundles = array_filter(variable_get('uuid_features_file_' . $entity_type . '_types', array()));
   $fields = field_info_instances($entity_type, $export_bundle);
@@ -265,7 +338,7 @@ function uuid_features_file_field_export(&$export, $entity_type) {
 
               // Check the file
               if (!isset($file->uri) || !is_file($file->uri)) {
-                drupal_set_message(t("File field found on term, but file doesn't exist on disk? '!path'", array('!path' => $file->uri)), 'error');
+                drupal_set_message(t("File field found on term, but file doesn't exist on disk? '!path'", array('!path' => $file->uri)), 'warning');
                 continue;
               }
 
@@ -318,31 +391,35 @@ function uuid_features_file_field_import(&$import, $entity_type) {
     case "node":
       $import_bundle = $import->type;
       break;
+    case "field_collection_item":
+      $import_bundle = $import->field_name;
   }
   // Get all fields from this bundle.
   $fields = field_info_instances($entity_type, $import_bundle);
 
   foreach($fields as $field_instance) {
-    // Load field info to check the type.
-    $field = &$import->{$field_instance['field_name']};
-    $info = field_info_field($field_instance['field_name']);
-    $supported_fields = array_map('trim', explode(',', variable_get('uuid_features_file_supported_fields', 'file, image')));
-    // Check if this field should implement file import/export system.
-    if (in_array($info['type'], $supported_fields)) {
-      // We need to loop into each language because i18n translation can build
-      // fields with different language than the term one.
-      foreach($field as $language => $files) {
-        if (is_array($files)) {
-          foreach($files as $i => $file) {
-            // Convert file to array to stay into the default uuid_features_file format.
-            $file = (object)$file;
-            $result = _uuid_features_file_field_import_file($file);
-            // The file was saved successfully, update the file field (by reference).
-            if ($result == TRUE && isset($file->fid)) {
-              $field[$language][$i] = (array)$file;
-            }
-            else {
-              $field[$language][$i] = array();
+    if (isset($import->{$field_instance['field_name']})) {
+      // Load field info to check the type.
+      $field = &$import->{$field_instance['field_name']};
+      $info = field_info_field($field_instance['field_name']);
+      $supported_fields = array_map('trim', explode(',', variable_get('uuid_features_file_supported_fields', 'file, image')));
+      // Check if this field should implement file import/export system.
+      if (in_array($info['type'], $supported_fields)) {
+        // We need to loop into each language because i18n translation can build
+        // fields with different language than the term one.
+        foreach($field as $language => $files) {
+          if (is_array($files)) {
+            foreach($files as $i => $file) {
+              // Convert file to array to stay into the default uuid_features_file format.
+              $file = (object)$file;
+              $result = _uuid_features_file_field_import_file($file);
+              // The file was saved successfully, update the file field (by reference).
+              if ($result == TRUE && isset($file->fid)) {
+                $field[$language][$i] = (array)$file;
+              }
+              else {
+                $field[$language][$i] = array();
+              }
             }
           }
         }
@@ -473,3 +550,106 @@ function _uuid_features_file_field_import_file(&$file) {
 
   return TRUE;
 }
+
+/**
+ * Helper function to get a filtered list of fields of the same type.
+ *
+ * @param $export
+ *   Example: node object
+ * @param $bundle_type
+ *   Example: 'node'
+ * @param $field_type
+ *   Example: 'field_collection', 'taxonomy_term_reference'
+ *
+ * @return array
+ *   A filtered list of fields of the same type.
+ */
+function uuid_features_get_field_items_iterator(&$export, $bundle_type, $field_type) {
+  $fields = field_info_instances($bundle_type, isset($export->type) ? $export->type : NULL);
+  if (!isset($export->type)) {
+    $fields = reset($fields);
+  }
+  $return = array();
+  foreach ($fields as $field_instance) {
+    $info = field_info_field($field_instance['field_name']);
+    if (isset($export->{$info['field_name']})) {
+      $field = &$export->{$info['field_name']};
+      if ($info['type'] == $field_type) {
+        foreach ($field as $language => &$field_items) {
+          $return[$field_instance['field_name']] = array(
+            $language => &$field_items,
+          );
+        }
+      }
+    }
+  }
+  return $return;
+}
+
+/**
+ * Walks through a filtered list of fields and sets UUID property using entities' ids.
+ *
+ * @param $fields
+ *   Filtered array of fields of the same type.
+ * @param $entity_type
+ */
+function uuid_features_set_uuid_references(&$fields, $entity_type) {
+  foreach ($fields as $field_name => &$field_languages) {
+    foreach ($field_languages as &$field_values) {
+      foreach ($field_values as &$field_value) {
+        $field_info = field_info_field($field_name);
+        $columns = array_keys($field_info['columns']);
+        $id_column = $columns[0];
+        $entities = entity_get_uuid_by_id($entity_type, array($field_value[$id_column]));
+        $field_reference_uuid = reset($entities);
+        if ($field_reference_uuid) {
+          $field_value['uuid'] = $field_reference_uuid;
+          foreach ($columns as $column) {
+            $field_value[$column] = $field_reference_uuid;
+          }
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Walks through a filtered list of fields and updates entity references using UUID property.
+ *
+ * @param $fields
+ *   Filtered array of fields of the same type.
+ * @param $entity_type
+ * @param $map
+ *   Mapping from entity to reference fields properties.
+ *   Example:
+ *     Taxonomy term:
+ *     array(
+ *       'tid' => 'tid',
+ *     )
+ *
+ *     Field collection:
+ *     array(
+ *       'item_id' => 'value',
+ *       'revision_id' => 'revision_id',
+ *     )
+ */
+function uuid_features_fetch_uuid_references(&$fields, $entity_type, $map) {
+  foreach ($fields as $field_name => &$field_languages) {
+    foreach ($field_languages as &$field_values) {
+      if (is_array($field_values)) {
+        foreach ($field_values as &$field_value) {
+          $entities = entity_uuid_load($entity_type, array($field_value['uuid']), array(), TRUE);
+          $referenced_entity = reset($entities);
+          foreach ($map as $source => $destination) {
+            if ($referenced_entity) {
+              $field_value[$destination] = $referenced_entity->{$source};
+            } else {
+              // fallback
+              $field_value[$destination] = UUID_FEATURES_DEFAULT_FALLBACK_ID;
+            }
+          }
+        }
+      }
+    }
+  }
+}
-- 
1.8.3.1

