diff --git a/sites/all/modules/og/README.txt b/sites/all/modules/og/README.txt
index fb54ccb7273b135cae1027efc342fc784127a287..94f3e6d0ff65cce295a22677313ffb7d5fce04d7 100644
--- a/sites/all/modules/og/README.txt
+++ b/sites/all/modules/og/README.txt
@@ -112,6 +112,15 @@ DEVELOPERS & SITE BUILDERS
   http://drupal.org/project/entityreference_prepopulate
   and configuring the correct settings in the field UI. Read more about
   it in Entity reference prepopulate's README file.
+  Further more, when Entity reference prepopulate module is enabled the node
+  "create" permissions will be enabled even for non-members. In order to allow
+  a non member to create a node to a group they don't belong to, you should
+  craft the URL in the same way. OG will recognize this situation and add the
+  group as a valid option under the "My groups" widget.
+- When deleting groups, it is possible to delete orphan group-content, or move
+  it under another group. In order to do it in a scalable way, enable the
+  "Use queue" option, and process it using for example:
+  drush queue-run og_membership_orphans
 
 FAQ
 ----
diff --git a/sites/all/modules/og/includes/actions/user_roles.action.inc b/sites/all/modules/og/includes/actions/user_roles.action.inc
index 20c33a12b08bd4b7aa29a4fc4d04e7f1e69b70f2..d436d1566951129c9ece12b70ae11ed37c00fcb3 100644
--- a/sites/all/modules/og/includes/actions/user_roles.action.inc
+++ b/sites/all/modules/og/includes/actions/user_roles.action.inc
@@ -9,11 +9,20 @@ function og_user_roles_action_info() {
 }
 
 function og_user_roles_action_form($context) {
-  // Get the group type and group ID from the Views arguments.
-  list($group_type, $gid) = $context['view']->args;
+  $gid = '';
+  $group_type = '';
 
-  if(empty($group_type) || empty($gid)) {
-    return;
+  if (module_exists('og_context') && $og_context = og_context()) {
+    // Get the group type and group ID from OG context.
+    $gid = $og_context['gid'];
+    $group_type = $og_context['group_type'];
+  }
+  elseif (empty($gid) || empty($group_type)) {
+    // Get the group type and group ID from the Views arguments if they exist.
+    list($group_type, $gid) = $context['view']->args;
+    if (empty($group_type) || empty($gid)) {
+      return;
+    }
   }
 
   if (!entity_get_info($group_type)) {
diff --git a/sites/all/modules/og/includes/migrate/7000/og_add_fields.inc b/sites/all/modules/og/includes/migrate/7000/og_add_fields.inc
index d9ba0421eca4866835769e1b4667561267ffb524..53b84c9a25f8c7473c9f94a920d4348ecf7f84f5 100644
--- a/sites/all/modules/og/includes/migrate/7000/og_add_fields.inc
+++ b/sites/all/modules/og/includes/migrate/7000/og_add_fields.inc
@@ -5,8 +5,6 @@
  * Add OG related fields to group and group-content node-types.
  */
 
-if (db_table_exists('d6_og')) {
-
 class OgMigrateAddFields extends MigrationBase {
 
   public function __construct() {
@@ -92,5 +90,3 @@ class OgMigrateAddFields extends MigrationBase {
     return MigrationBase::RESULT_COMPLETED;
   }
 }
-
-}
diff --git a/sites/all/modules/og/includes/migrate/7000/og_content.inc b/sites/all/modules/og/includes/migrate/7000/og_content.inc
index cb463e3a6fd32fdc4a1d4c6b757518582c936490..ef837bff7f32654a8b0d59810df07737399ca827 100644
--- a/sites/all/modules/og/includes/migrate/7000/og_content.inc
+++ b/sites/all/modules/og/includes/migrate/7000/og_content.inc
@@ -6,8 +6,6 @@
  * value.
  */
 
-if (db_table_exists('d6_og')) {
-
 class OgMigrateContent extends Migration {
 
   public function __construct() {
@@ -58,5 +56,3 @@ class OgMigrateContent extends Migration {
     $this->addFieldMapping('etid', 'nid');
   }
 }
-
-}
diff --git a/sites/all/modules/og/includes/migrate/7000/og_group.inc b/sites/all/modules/og/includes/migrate/7000/og_group.inc
index 9d17ecf8586c468e655f0dfae44ebabe4d833adf..0af03c1cd66ad91d526075055006cfc9b671306d 100644
--- a/sites/all/modules/og/includes/migrate/7000/og_group.inc
+++ b/sites/all/modules/og/includes/migrate/7000/og_group.inc
@@ -5,8 +5,6 @@
  * Upgrade nodes that are groups, by settings the correct field value.
  */
 
-if (db_table_exists('d6_og')) {
-
 class OgMigrateGroup extends DynamicMigration {
 
   /**
@@ -54,5 +52,3 @@ class OgMigrateGroup extends DynamicMigration {
     return drupal_strtolower('OgMigrateGroup' . ucfirst($this->arguments['bundle']));
   }
 }
-
-}
diff --git a/sites/all/modules/og/includes/migrate/7000/og_user.inc b/sites/all/modules/og/includes/migrate/7000/og_user.inc
index 0755f469845cecca5cf1dca65e2ab1f057ac762c..19e02d6dd041d11f466a81912858fa29f2eb437f 100644
--- a/sites/all/modules/og/includes/migrate/7000/og_user.inc
+++ b/sites/all/modules/og/includes/migrate/7000/og_user.inc
@@ -5,8 +5,6 @@
  * Create user relation to group.
  */
 
-if (db_table_exists('d6_og')) {
-
 class OgMigrateUser extends Migration {
 
   public function __construct() {
@@ -64,5 +62,3 @@ class OgMigrateUser extends Migration {
     parent::prepareRow($row);
   }
 }
-
-}
diff --git a/sites/all/modules/og/includes/migrate/7200/og_og_membership.migrate.inc b/sites/all/modules/og/includes/migrate/7200/og_og_membership.migrate.inc
index d60e31dfb836850ce066160da22da6267997b91e..6137ba56239673f01648c7fb9ea5d8dd9f1c49d4 100644
--- a/sites/all/modules/og/includes/migrate/7200/og_og_membership.migrate.inc
+++ b/sites/all/modules/og/includes/migrate/7200/og_og_membership.migrate.inc
@@ -8,8 +8,6 @@
  * to branch 7.x-2.x
  */
 
-if (db_field_exists('og_membership', 'group_type') && db_table_exists('og') && !db_table_exists('d6_og')) {
-
 class OgMigrateMembership extends OgEntityMigration {
 
   /**
@@ -50,7 +48,10 @@ class OgMigrateMembership extends OgEntityMigration {
     }
   }
 
-  public function prepare($entity, $row) {
+  /**
+   * Reject the source row if the group or group content are missing.
+   */
+  public function prepareRow($row) {
     $entity_type = $row->entity_type;
     $etid = $row->etid;
     $group_type = $row->group_type;
@@ -59,27 +60,46 @@ class OgMigrateMembership extends OgEntityMigration {
     if (!$group_content = entity_load_single($entity_type, $etid)) {
       // The OG membership was somehow not deleted when the entity
       // was deleted.
-      return;
+      return FALSE;
     }
 
     if (!$group = entity_load_single($group_type, $gid)) {
-      return;
+      return FALSE;
     }
+    return parent::prepareRow($row);
+  }
+
+  public function prepare($entity, $row) {
+    $entity_type = $row->entity_type;
+    $etid = $row->etid;
+    $group_type = $row->group_type;
+    $gid = $row->gid;
+
+    $group_content = entity_load_single($entity_type, $etid);
+    $group = entity_load_single($group_type, $gid);
 
     list(,, $group_bundle) = entity_extract_ids($group_type, $group);
     if (!$field_name = og_get_best_group_audience_field($entity_type, $group_content, $group_type, $group_bundle)) {
-      // Create a new field. Pick an unused name.
-      $field_name = substr("og_$group_type", 0, 32);
+      // Create a new field. Pick an unused name, if the settings don't match.
+      // To maintain some backwards compatibility, if the group type is a node,
+      // we try to set its name to OG_AUDIENCE FIELD.
+      $field_name = $group_type == 'node' ? OG_AUDIENCE_FIELD : substr("og_$group_type", 0, 32);
       $i = 1;
-      while (field_info_field($field_name)) {
-        $field_name = substr("og_$group_type", 0, 32 - strlen($i)) . $i;
-        ++$i;
-      }
 
       $og_field = og_fields_info(OG_AUDIENCE_FIELD);
       $og_field['field']['settings']['target_type'] = $group_type;
-
       list(,, $bundle) = entity_extract_ids($entity_type, $group_content);
+
+      while ($field = field_info_field($field_name)) {
+        if ($field['settings']['target_type'] == $group_type && empty($field['settings']['handler_settings']['target_bundles']) || in_array($bundle, $field['settings']['handler_settings']['target_bundles'])) {
+          // An existing field.
+          $field_name = $field['field_name'];
+          break;
+        }
+        $field_name = substr("og_$group_type", 0, 32 - strlen($i)) . $i;
+        ++$i;
+      }
+
       og_create_field($field_name, $entity_type, $bundle, $og_field);
     }
     $entity->field_name = $field_name;
@@ -88,8 +108,7 @@ class OgMigrateMembership extends OgEntityMigration {
   /**
    * Override Migration::postImport().
    *
-   * Remove OG-memberships that should hae been deleted.
-   *
+   * Remove OG-memberships that should have been deleted.
    */
   protected function postImport() {
     if (!$this->isComplete()) {
@@ -100,5 +119,3 @@ class OgMigrateMembership extends OgEntityMigration {
       ->execute();
   }
 }
-
-}
diff --git a/sites/all/modules/og/includes/migrate/7200/og_roles.migrate.inc b/sites/all/modules/og/includes/migrate/7200/og_roles.migrate.inc
index cdc40b11a7a7c2fa392c1ac15aa49c97e38cc9c6..fae9b32b9c8590601e95b6b9cf361ad11b2733bd 100644
--- a/sites/all/modules/og/includes/migrate/7200/og_roles.migrate.inc
+++ b/sites/all/modules/og/includes/migrate/7200/og_roles.migrate.inc
@@ -9,16 +9,12 @@
  */
 
 
-if (db_field_exists('og_membership', 'group_type') && db_table_exists('og') && !db_table_exists('d6_og')) {
-
 class OgMigrateRoles extends OgEntityMigration {
 
   public $tableName = 'og_role';
 
   public $keyName = 'rid';
 
-  protected $dependencies = array('OgMigrateMembership');
-
   /**
    * Indicate we are updating existing data.
    */
@@ -106,5 +102,3 @@ class OgMigrateRoles extends OgEntityMigration {
     $entity->group_bundle = $bundle;
   }
 }
-
-}
\ No newline at end of file
diff --git a/sites/all/modules/og/includes/migrate/7200/og_user_roles.migrate.inc b/sites/all/modules/og/includes/migrate/7200/og_user_roles.migrate.inc
index 067bc9a113de0f272704bfc1eb1ba2d2e48b7d85..44e40f6bf995e82353b7153819324087396f2ea2 100644
--- a/sites/all/modules/og/includes/migrate/7200/og_user_roles.migrate.inc
+++ b/sites/all/modules/og/includes/migrate/7200/og_user_roles.migrate.inc
@@ -8,8 +8,6 @@
  * to branch 7.x-2.x
  */
 
-if (db_field_exists('og_membership', 'group_type') && db_table_exists('og') && !db_table_exists('d6_og')) {
-
 class OgMigrateUserRoles extends OgEntityMigration {
 
   public $tableName = 'og_users_roles';
@@ -108,5 +106,3 @@ class OgMigrateUserRoles extends OgEntityMigration {
     }
   }
 }
-
-}
diff --git a/sites/all/modules/og/includes/migrate/plugins/destinations/og_membership.inc b/sites/all/modules/og/includes/migrate/plugins/destinations/og_membership.inc
index ffd33350886241036ae2859aba5345bf70993753..3af3b704cd821a8414946418255542b50ef8b5f8 100644
--- a/sites/all/modules/og/includes/migrate/plugins/destinations/og_membership.inc
+++ b/sites/all/modules/og/includes/migrate/plugins/destinations/og_membership.inc
@@ -64,10 +64,10 @@ class MigrateDestinationOGMembership extends MigrateDestination {
       throw new MigrateException('Missing group ID.');
     }
     if (empty($entity->entity_type)) {
-      throw new MigrateException('Missing enity type.');
+      throw new MigrateException('Missing entity type.');
     }
     if (empty($entity->etid)) {
-      throw new MigrateException('Missing enity ID.');
+      throw new MigrateException('Missing entity ID.');
     }
 
      // Set state, make sure legacy states from OG6 are converted to
@@ -78,13 +78,12 @@ class MigrateDestinationOGMembership extends MigrateDestination {
     else {
       $state = OG_STATE_ACTIVE;
     }
-
-    $values = array(
-      'entity_type' => $entity->entity_type,
-      'entity' => $entity->etid,
-      'state' => $state,
-      'created' => isset($entity->created) ? $entity->created : REQUEST_TIME,
-    );
+    $this->prepare($entity, $row);
+    // Allow passing OG-membership fields via og_group().
+    $values = (array) $entity;
+    $values['entity'] = $entity->etid;
+    $values['state'] = $state;
+    $values['created'] = isset($entity->created) ? $entity->created : REQUEST_TIME;
 
     $og_membership = og_group($entity->group_type, $entity->gid, $values);
 
@@ -109,9 +108,60 @@ class MigrateDestinationOGMembership extends MigrateDestination {
       }
     }
 
+    $this->complete($entity, $row);
+
     return array($og_membership->id);
   }
 
+  /**
+   * Give handlers a shot at modifying the object before saving it.
+   *
+   * @param $entity
+   *   OGMembership object to build. Prefilled with any fields mapped in
+   *   the Migration.
+   * @param $source_row
+   *   Raw source data object - passed through to prepare handlers.
+   */
+  public function prepare($entity, stdClass $row) {
+    // We do nothing here but allow child classes to act.
+    $migration = Migration::currentMigration();
+    $entity->migrate = array(
+      'machineName' => $migration->getMachineName(),
+    );
+
+    // Call any general handlers.
+    migrate_handler_invoke_all('og_membership', 'prepare', $entity, $row);
+    // Then call any prepare handler for this specific Migration.
+    if (method_exists($migration, 'prepare')) {
+      $migration->prepare($entity, $row);
+    }
+  }
+
+  /**
+   * Give handlers a shot at modifying the object (or taking additional action)
+   * after saving it.
+   *
+   * @param $entity
+   *   OGMembership object to build. This is the complete object after
+   *   saving.
+   * @param $source_row
+   *   Raw source data object - passed through to complete handlers.
+   */
+  public function complete($entity, stdClass $row) {
+    // We do nothing here but allow child classes to act.
+    $migration = Migration::currentMigration();
+    $entity->migrate = array(
+      'machineName' => $migration->getMachineName(),
+    );
+
+    // Call any general handlers.
+    migrate_handler_invoke_all('og_membership', 'complete', $entity, $row);
+    // Then call any complete handler for this specific Migration.
+    if (method_exists($migration, 'complete')) {
+      $migration->complete($entity, $row);
+    }
+  }
+
   public function fields() {
     return array(
       'group_type' => 'Group entity type',
diff --git a/sites/all/modules/og/includes/og.field.inc b/sites/all/modules/og/includes/og.field.inc
index 189afd5b365f23366ece54bd6780b6c4904adcb2..7f419ded31e3a96c1a6c829f6f0c63e4e5aadb92 100644
--- a/sites/all/modules/og/includes/og.field.inc
+++ b/sites/all/modules/og/includes/og.field.inc
@@ -31,7 +31,7 @@ function og_field_widget_form(&$form, &$form_state, $field, $instance, $langcode
     return;
   }
 
-  if ($field['settings']['handler'] != 'og') {
+  if ($field['settings']['handler'] != 'og' && strpos($field['settings']['handler'], 'og_') !== 0) {
     $params = array('%label' => $instance['label']);
     form_error($form, t('Field %label is a group-audience but its Entity selection mode is not defined as "Organic groups" in the field settings page.', $params));
     return;
@@ -42,7 +42,7 @@ function og_field_widget_form(&$form, &$form_state, $field, $instance, $langcode
   list($id,, $bundle) = entity_extract_ids($entity_type, $entity);
   $field_name = $field['field_name'];
 
-  $identifier = $field_name . ':' . $entity_type . ':' . $id;
+  $identifier = $field_name . ':' . $entity_type . ':' . $bundle . ':' . $id;
   if (isset($cache[$identifier])) {
     return array();
   }
@@ -63,18 +63,19 @@ function og_field_widget_form(&$form, &$form_state, $field, $instance, $langcode
     $field_modes[] = 'admin';
   }
 
-  // Get the "Other group" group IDs.
-  $target_type = $field['settings']['target_type'];
-  $other_groups_ids = array();
-  if ($id) {
-    $entity_gids = og_get_entity_groups($entity_type, $entity);
-    $entity_gids = !empty($entity_gids[$target_type]) ? $entity_gids[$target_type] : array();
+  // Build an array of entity IDs. Field's $items are loaded
+  // in OgBehaviorHandler::load().
+  $entity_gids = array();
+  foreach ($items as $item) {
+    $entity_gids[] = $item['target_id'];
+  }
 
-    $user_gids = og_get_entity_groups();
-    $user_gids = !empty($user_gids[$target_type]) ? $user_gids[$target_type] : array();
+  $target_type = $field['settings']['target_type'];
+  $user_gids = og_get_entity_groups();
+  $user_gids = !empty($user_gids[$target_type]) ? $user_gids[$target_type] : array();
 
-    $other_groups_ids = array_diff($entity_gids, $user_gids);
-  }
+  // Get the "Other group" group IDs.
+  $other_groups_ids = array_diff($entity_gids, $user_gids);
 
   foreach ($field_modes as $field_mode) {
     $mocked_instance = og_get_mocked_instance($instance, $field_mode);
@@ -135,7 +136,6 @@ function og_field_widget_form(&$form, &$form_state, $field, $instance, $langcode
 
     $new_element = ctools_field_invoke_field($mocked_instance, 'form', $entity_type, $dummy_entity, $form, $dummy_form_state, array('default' => TRUE));
     $element[$field_mode] = $new_element[$field_name][LANGUAGE_NONE];
-
     if (in_array($mocked_instance['widget']['type'], array('entityreference_autocomplete', 'entityreference_autocomplete_tags'))) {
       // Change the "Add more" button name so it adds only the needed
       // element.
@@ -143,30 +143,21 @@ function og_field_widget_form(&$form, &$form_state, $field, $instance, $langcode
         $element[$field_mode]['add_more']['#name'] .= '__' . $field_mode;
       }
 
-      foreach (array_keys($element[$field_mode]) as $delta) {
-        if (!is_numeric($delta)) {
-          continue;
-        }
-
-        $sub_element = &$element[$field_mode][$delta]['target_id'];
-
-        // Rebuild the autocomplete path.
-        $path = explode('/', $sub_element['#autocomplete_path']);
-        $sub_element['#autocomplete_path'] = 'og/autocomplete';
-
-        // Add autocomplete type
-        $sub_element['#autocomplete_path'] .= "/$path[2]/$path[3]/$path[4]/$path[5]";
+      if ($mocked_instance['widget']['type'] == 'entityreference_autocomplete') {
+        foreach (array_keys($element[$field_mode]) as $delta) {
+          if (!is_numeric($delta)) {
+            continue;
+          }
 
-        // Add field mode.
-        $sub_element['#autocomplete_path'] .= "/$field_mode";
+          $sub_element = &$element[$field_mode][$delta]['target_id'];
+          _og_field_widget_replace_autocomplete_path($sub_element, $field_mode);
 
-        // Add the entity ID.
-        $sub_element['#autocomplete_path'] .= "/$path[6]";
-        if (!empty($path[7])) {
-          // Add the text.
-          $sub_element['#autocomplete_path'] .= "/$path[7]";
         }
       }
+      else {
+        // Tags widget, there's no delta, we can pass the element itself.
+        _og_field_widget_replace_autocomplete_path($element[$field_mode], $field_mode);
+      }
     }
   }
 
@@ -175,6 +166,34 @@ function og_field_widget_form(&$form, &$form_state, $field, $instance, $langcode
   return $element;
 }
 
+/**
+ * Replace Entity-reference's autocomplete path with our own.
+ *
+ * @param $element
+ *   The form element, passed by reference.
+ * @param $field_mode
+ *   The field mode.
+ *
+ */
+function _og_field_widget_replace_autocomplete_path(&$element, $field_mode) {
+  // Rebuild the autocomplete path.
+  $path = explode('/', $element['#autocomplete_path']);
+  $element['#autocomplete_path'] = 'og/autocomplete';
+
+  // Add autocomplete type
+  $element['#autocomplete_path'] .= "/$path[2]/$path[3]/$path[4]/$path[5]";
+
+  // Add field mode.
+  $element['#autocomplete_path'] .= "/$field_mode";
+
+  // Add the entity ID.
+  $element['#autocomplete_path'] .= "/$path[6]";
+  if (!empty($path[7])) {
+    // Add the text.
+    $element['#autocomplete_path'] .= "/$path[7]";
+  }
+}
+
 /**
  * Property info alter; Change mocked field to be non-required.
  */
diff --git a/sites/all/modules/og/includes/og.membership.inc b/sites/all/modules/og/includes/og.membership.inc
index 2d4d10557d96e6c21dd25cf94aa202798088fee8..23464e5f6f37978f16c766c6d9ee700c899ee192 100644
--- a/sites/all/modules/og/includes/og.membership.inc
+++ b/sites/all/modules/og/includes/og.membership.inc
@@ -18,6 +18,11 @@ class OgMembership extends Entity {
   public function save() {
     $entity_type = $this->entity_type;
     $etid = $this->etid;
+
+    if ($entity_type == 'user' && !$etid) {
+      throw new OgException('OG membership can not be created for anonymous user.');
+    }
+
     $wrapper = entity_metadata_wrapper($entity_type, $etid);
     $bundle = $wrapper->getBundle();
 
@@ -27,7 +32,6 @@ class OgMembership extends Entity {
     list(,,$group_bundle) = entity_extract_ids($group_type, $group);
 
     $field_name = $this->field_name;
-    $state = !empty($this->state) ? $this->state : OG_STATE_ACTIVE;
 
     // Placeholder for exceptions, in case we need to throw one.
     $params = array(
diff --git a/sites/all/modules/og/includes/og_features_permission.features.inc b/sites/all/modules/og/includes/og_features_permission.features.inc
old mode 100644
new mode 100755
index a299642ce5e4dbd0af7ed4af00e8c108b46a18ed..4fc758fe71d20ad1432de1077ec4b31b14922845
--- a/sites/all/modules/og/includes/og_features_permission.features.inc
+++ b/sites/all/modules/og/includes/og_features_permission.features.inc
@@ -90,6 +90,9 @@ function og_features_permission_features_export_render($module, $data) {
       $permission['roles'] = array();
     }
 
+    // Ensure consistent ordering of roles on output to avoid extraneious diffs.
+    asort($permission['roles']);
+
     $perm_identifier = features_var_export($key);
     $perm_export = features_var_export($permission, '  ');
     $code[] = "  // Exported og permission: {$perm_identifier}";
diff --git a/sites/all/modules/og/includes/views/handlers/og_handler_field_og_membership_link_edit.inc b/sites/all/modules/og/includes/views/handlers/og_handler_field_og_membership_link_edit.inc
new file mode 100644
index 0000000000000000000000000000000000000000..6b93a667536bef3746a7c508bfa699fba81f68ea
--- /dev/null
+++ b/sites/all/modules/og/includes/views/handlers/og_handler_field_og_membership_link_edit.inc
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * @file
+ * Definition of og_handler_field_og_membership_link_edit.
+ */
+
+/**
+ * Field handler to present a link to edit membership.
+ *
+ * @ingroup views_field_handlers
+ */
+class og_handler_field_og_membership_link_edit extends views_handler_field_entity {
+
+  function construct() {
+    parent::construct();
+  }
+
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['text'] = array('default' => '', 'translatable' => TRUE);
+    $options['destination'] = array('default' => FALSE, 'bool' => TRUE);
+    return $options;
+  }
+
+  function options_form(&$form, &$form_state) {
+    $form['text'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Text to display'),
+      '#default_value' => $this->options['text'],
+    );
+    $form['destination'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Use destination'),
+      '#description' => t('Add destination to the link'),
+      '#default_value' => $this->options['destination'],
+      '#fieldset' => 'more',
+    );
+    parent::options_form($form, $form_state);
+  }
+
+  function query() {
+    $this->ensure_my_table();
+    $this->add_additional_fields();
+  }
+
+  function render($values) {
+    $value = $this->get_value($values, 'id');
+    return $this->render_link($this->sanitize_value($value), $values);
+  }
+
+  function render_link($data, $values) {
+    $this->options['alter']['make_link'] = TRUE;
+    $this->options['alter']['html'] = TRUE;
+
+    // Ensure user has access to edit this membership.
+    $og_membership = $this->get_value($values);
+    $group_type = $og_membership->group_type;
+    $gid = $og_membership->gid;
+    if (!og_ui_user_access_group('manage members', $group_type, $gid)) {
+      return;
+    }
+
+    $text = !empty($this->options['text']) ? $this->options['text'] : t('edit');
+    unset($this->options['alter']['fragment']);
+
+    if (!empty($this->options['destination'])) {
+      $this->options['alter']['query'] = drupal_get_destination();
+    }
+
+    $this->options['alter']['path'] = "group/" . $group_type . "/" . $gid  . "/admin/people/edit-membership/" . $og_membership->id;
+
+    return $text;
+  }
+}
diff --git a/sites/all/modules/og/includes/views/handlers/og_handler_filter_user_roles.inc b/sites/all/modules/og/includes/views/handlers/og_handler_filter_user_roles.inc
new file mode 100644
index 0000000000000000000000000000000000000000..c0573eebf0c6a88fd62cfb6a358e2c2640ba890f
--- /dev/null
+++ b/sites/all/modules/og/includes/views/handlers/og_handler_filter_user_roles.inc
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * Field handler to provide a list of OG roles of a user.
+ */
+class og_handler_filter_user_roles extends views_handler_filter_many_to_one {
+
+  function get_value_options() {
+    $this->value_options = array();
+    // Get all role names.
+    $results = db_select('og_role', 'r')
+      ->fields('r')
+      ->groupBy('r.name')
+      ->execute();
+    foreach ($results as $result) {
+      $this->value_options[$result->name] = $result->name;
+    }
+  }
+
+  function query() {
+    // Get the og_membership table from relations.
+    foreach ($this->query->relationships as $alias => $info) {
+      if ($info['table'] == 'og_membership') {
+        // If there is a og_membership table present. Add some conditions.
+        $rel = $this->relationship;
+        $this->query->add_where_expression(NULL, $alias . '.gid = ' . $rel . '.gid');
+        $this->query->add_where_expression(NULL, $alias . '.group_type = ' . $rel . '.group_type');
+        break;
+      }
+    }
+
+    parent::query();
+  }
+}
diff --git a/sites/all/modules/og/includes/views/handlers/og_handler_relationship.inc b/sites/all/modules/og/includes/views/handlers/og_handler_relationship.inc
index 03e23a13304028b6b92be81528dc5ce2d775923e..a6cbde38dc29751eef4099388c79b1ea1187e5b4 100644
--- a/sites/all/modules/og/includes/views/handlers/og_handler_relationship.inc
+++ b/sites/all/modules/og/includes/views/handlers/og_handler_relationship.inc
@@ -17,12 +17,46 @@ class og_handler_relationship extends views_handler_relationship {
    * Called to implement a relationship in a query.
    */
   function query() {
-    $entity = $this->definition['entity'];
 
-    $this->definition['extra'][] = array(
-      'field' => 'entity_type',
-      'value' => $this->definition['entity'],
-    );
+    // If the entity type is specific for the og_membership
+    // filter the join to select membership of those entity types.
+    if (isset($this->definition['entity'])) {
+      $extra = array(
+        'field' => 'entity_type',
+        'value' => $this->definition['entity'],
+      );
+
+      // Only add the table if og_membership is the left table since when the
+      // table is specified to views_join, it only translates the table alias
+      // of tables in the left position, however if no table is specified,
+      // then views_join correctly inserts the alias of the table in the right
+      // position of the join.
+      if ($this->definition['base'] != 'og_membership') {
+        $extra['table'] = 'og_membership';
+      }
+
+      $this->definition['extra'][] = $extra;
+    }
+
+    // If the group type is specific for the og_membership
+    // filter the join to select membership of those group types.
+    if (isset($this->definition['group_type'])) {
+      $extra = array(
+        'field' => 'group_type',
+        'value' => $this->definition['group_type'],
+      );
+
+      // Only add the table if og_membership is the left table since when the
+      // table is specified to views_join, it only translates the table alias
+      // of tables in the left position, however if no table is specified,
+      // then views_join correctly inserts the alias of the table in the right
+      // position of the join.
+      if ($this->definition['base'] != 'og_membership') {
+        $extra['table'] = 'og_membership';
+      }
+
+      $this->definition['extra'][] = $extra;
+    }
     parent::query();
   }
-}
\ No newline at end of file
+}
diff --git a/sites/all/modules/og/includes/views/handlers/og_plugin_argument_default_user_groups.inc b/sites/all/modules/og/includes/views/handlers/og_plugin_argument_default_user_groups.inc
index 6c73ca7180aef2dd027a8e9ee56cc29b27de3da7..85c63608e1d21c641da43642e1d14be98e9f593e 100644
--- a/sites/all/modules/og/includes/views/handlers/og_plugin_argument_default_user_groups.inc
+++ b/sites/all/modules/og/includes/views/handlers/og_plugin_argument_default_user_groups.inc
@@ -33,7 +33,7 @@ class og_plugin_argument_default_user_groups extends views_plugin_argument_defau
       '#description' => t('Select the group type.'),
       '#options' => og_get_all_group_entity(),
       '#default_value' => $this->options['group_type'],
-      '#required' => TRUE,
+      '#required' => og_get_all_group_entity(),
     );
     $form['glue'] = array(
       '#type' => 'select',
diff --git a/sites/all/modules/og/includes/views/handlers/og_plugin_argument_validate_group.inc b/sites/all/modules/og/includes/views/handlers/og_plugin_argument_validate_group.inc
index 6eb027d8e8f13a80b57d561ed525c7b8b155219a..a987e8bdd7ae9d5422992b33cbaa81400c9e6912 100644
--- a/sites/all/modules/og/includes/views/handlers/og_plugin_argument_validate_group.inc
+++ b/sites/all/modules/og/includes/views/handlers/og_plugin_argument_validate_group.inc
@@ -30,7 +30,7 @@ class og_plugin_argument_validate_group extends views_plugin_argument_validate {
       '#description' => t('Select the group type.'),
       '#options' => og_get_all_group_entity(),
       '#default_value' => $this->options['group_type'],
-      '#required' => TRUE,
+      '#required' => og_get_all_group_entity(),
     );
   }
 
diff --git a/sites/all/modules/og/includes/views/og.views.inc b/sites/all/modules/og/includes/views/og.views.inc
index 8ae1b963be3c56ef0c22497df57b41cb5679b2ed..0def1f54333db4ab267b74dd3ca1b8db3ec42bac 100644
--- a/sites/all/modules/og/includes/views/og.views.inc
+++ b/sites/all/modules/og/includes/views/og.views.inc
@@ -43,8 +43,6 @@ class OgMembershipViewsController extends EntityDefaultViewsController {
     $data['og_membership']['gid']['title'] = t('Group ID');
     $data['og_membership']['gid']['help'] = t('Og membership "gid" property.');
 
-
-
     $data['og_membership']['og_roles'] = array(
       'title' => t('OG user roles in group'),
       'help' => t('Show all the roles a user belongs to in a group. Requires a relationship to users to be present.'),
@@ -56,6 +54,47 @@ class OgMembershipViewsController extends EntityDefaultViewsController {
       ),
     );
 
+    $data['og_membership']['og_users_roles'] = array(
+      'title' => t('OG Roles from membership'),
+      'help' => t('The OG Roles associated with the OG membership'),
+      // Provide a possible relationship to roles through uid.
+      'relationship' => array(
+        'label' => t('OG Roles from OG membership'),
+        'base' => 'og_users_roles',
+        'base field' => 'uid',
+        'relationship field' => 'etid',
+      ),
+    );
+
+    $data['og_role'] = array(
+      'table' => array(
+        'group' => t('OG user roles'),
+        'join' => array(
+          // Attach automatically to og_users_roles relations.
+          'og_users_roles' => array(
+            'left_field' => 'rid',
+            'field' => 'rid',
+          ),
+        )
+      )
+    );
+    $data['og_role']['name'] = array(
+      'title' => t('Role Name'),
+      'help' => t('The OG role name.'),
+      'filter' => array(
+        'handler' => 'og_handler_filter_user_roles',
+      ),
+    );
+
+    // Link to edit membership
+    $data['og_membership']['edit_membership'] = array(
+      'field' => array(
+        'title' => t('Edit link'),
+        'help' => t('Provide a simple link to edit the membership.'),
+        'handler' => 'og_handler_field_og_membership_link_edit',
+      ),
+    );
+
     return $data;
   }
 }
@@ -65,9 +104,10 @@ class OgMembershipViewsController extends EntityDefaultViewsController {
  */
 function og_views_data_alter(&$data) {
   $group_content_entities = og_get_all_group_content_entity();
+  $group_entities = og_get_all_group_entity();
 
   foreach (entity_get_info() as $entity_type => $info) {
-    if (empty($group_content_entities[$entity_type])) {
+    if (empty($group_content_entities[$entity_type]) && empty($group_entities[$entity_type])) {
       continue;
     }
 
@@ -93,8 +133,8 @@ function og_views_data_alter(&$data) {
       'title' => t('OG membership from @entity group', array('@entity' => ucfirst($info['label']))),
       'help' => t('The OG membership associated with the @entity group', array('@entity' => ucfirst($info['label']))),
       'relationship' => array(
-        'entity' => $entity_type,
-        'handler' => 'views_handler_relationship',
+        'group_type' => $entity_type,
+        'handler' => 'og_handler_relationship',
         'label' => t('OG membership from @entity group', array('@entity' => $entity_type)),
         'base' => 'og_membership',
         'base field' => 'gid',
@@ -108,7 +148,8 @@ function og_views_data_alter(&$data) {
       'title' => t('@entity from OG membership', array('@entity' => ucfirst($info['label']))),
       'help' => t('The @entity entity that is associated with the OG membership.', array('@entity' => $info['label'])),
       'relationship' => array(
-        'handler' => 'views_handler_relationship',
+        'entity' => $entity_type,
+        'handler' => 'og_handler_relationship',
         'label' => t('@entity from OG membership', array('@entity' => $entity_type)),
         'base' => $info['base table'],
         'base field' => $info['entity keys']['id'],
@@ -122,7 +163,8 @@ function og_views_data_alter(&$data) {
       'title' => t('Group @entity from OG membership', array('@entity' => ucfirst($info['label']))),
       'help' => t('The @entity group that is associated with the OG membership.', array('@entity' => $info['label'])),
       'relationship' => array(
-        'handler' => 'views_handler_relationship',
+        'group_type' => $entity_type,
+        'handler' => 'og_handler_relationship',
         'label' => t('Group @entity from OG membership', array('@entity' => $entity_type)),
         'base' => $info['base table'],
         'base field' => $info['entity keys']['id'],
diff --git a/sites/all/modules/og/includes/views/og.views_default.inc b/sites/all/modules/og/includes/views/og.views_default.inc
index 248a6b8d553c6edfdfdd56ca5c5c3069fade8bdd..57784c85d44cdf1dd9b5abc19cf5f9bd1fd73ac2 100644
--- a/sites/all/modules/og/includes/views/og.views_default.inc
+++ b/sites/all/modules/og/includes/views/og.views_default.inc
@@ -334,7 +334,7 @@ function og_views_default_views() {
   $handler->display->display_options['arguments']['etid']['id'] = 'etid';
   $handler->display->display_options['arguments']['etid']['table'] = 'og_membership';
   $handler->display->display_options['arguments']['etid']['field'] = 'etid';
-  $handler->display->display_options['arguments']['etid']['ui_name'] = 'We pass to the "Entity ID" the User ID.';
+  $handler->display->display_options['arguments']['etid']['ui_name'] = 'We pass the user ID as the Entity ID.';
   $handler->display->display_options['arguments']['etid']['default_action'] = 'default';
   $handler->display->display_options['arguments']['etid']['title_enable'] = 1;
   $handler->display->display_options['arguments']['etid']['title'] = '%1 groups';
diff --git a/sites/all/modules/og/og.api.php b/sites/all/modules/og/og.api.php
index 9a7ba62aed6aa7b38c85f07e732c8cf3c5440f5f..d6d73fd8977bace9c9a41f9104c78beb914a2f12 100644
--- a/sites/all/modules/og/og.api.php
+++ b/sites/all/modules/og/og.api.php
@@ -19,7 +19,12 @@ function hook_og_permission() {
     'subscribe' => array(
       'title' => t('Subscribe user to group'),
       'description' => t("Allow user to be a member of a group (approval required)."),
+      // Determine to which role to limit the permission. For example the
+      // "subscribe" can't be assigned only to a non-member, as a member doesn't
+      // need it.
       'roles' => array(OG_ANONYMOUS_ROLE),
+      // Determine to which roles the permissions will be enabled by default.
+      'default role' => array(OG_ANONYMOUS_ROLE),
     ),
   );
 }
diff --git a/sites/all/modules/og/og.info b/sites/all/modules/og/og.info
index 9895e4e94b7aa5d853772360b7a0108b989d4558..011b9a8c17dc747ca968221cb00258b4a89249f2 100644
--- a/sites/all/modules/og/og.info
+++ b/sites/all/modules/og/og.info
@@ -29,9 +29,11 @@ files[] = includes/views/handlers/og_handler_field_group_audience_state.inc
 files[] = includes/views/handlers/og_handler_field_prerender_list.inc
 files[] = includes/views/handlers/og_handler_field_user_roles.inc
 files[] = includes/views/handlers/og_handler_field_group_permissions.inc
+files[] = includes/views/handlers/og_handler_field_og_membership_link_edit.inc
 
 ; Views filters
 files[] = includes/views/handlers/og_handler_filter_group_audience_state.inc
+files[] = includes/views/handlers/og_handler_filter_user_roles.inc
 
 ; Views relationships
 files[] = includes/views/handlers/og_handler_relationship.inc
@@ -48,16 +50,14 @@ files[] = includes/migrate/7000/og_user.inc
 ; Migrate from 7.x-1.x to 7.x-2.x
 files[] = includes/migrate/og.migrate.inc
 files[] = includes/migrate/7200/og_og_membership.migrate.inc
-files[] = includes/migrate/7200/og_ogur_permissions.migrate.inc
-files[] = includes/migrate/7200/og_ogur.migrate.inc
 files[] = includes/migrate/7200/og_roles.migrate.inc
 files[] = includes/migrate/7200/og_user_roles.migrate.inc
 
 
 
-; Information added by drupal.org packaging script on 2012-11-25
-version = "7.x-2.0-beta3+6-dev"
+; Information added by drupal.org packaging script on 2013-04-22
+version = "7.x-2.2"
 core = "7.x"
 project = "og"
-datestamp = "1353849566"
+datestamp = "1366630883"
 
diff --git a/sites/all/modules/og/og.install b/sites/all/modules/og/og.install
index 6ca234a2cf1393db8b07848a775a97fa5bacb39e..d956d924e6081b239ac6f9e57c924624ffc011d1 100644
--- a/sites/all/modules/og/og.install
+++ b/sites/all/modules/og/og.install
@@ -52,6 +52,7 @@ function og_uninstall() {
     'og_update_batch_size',
     'og_upgrade_7001',
     'og_node_access_strict',
+    'og_features_ignore_og_fields',
   );
   foreach ($vars as $var) {
     variable_del($var);
@@ -72,7 +73,7 @@ function og_uninstall() {
         }
         else {
           $field = field_info_field($instance['field_name']);
-          if ($field['type'] == 'entityreference' && $field['settings']['handler'] == 'og') {
+          if ($field['type'] == 'entityreference' && ($field['settings']['handler'] == 'og' || strpos($field['settings']['handler'], 'og_') === 0)) {
             // Last instance will take care also of deleting the field itself.
             field_delete_instance($instance);
           }
@@ -354,6 +355,18 @@ function og_schema() {
     ),
   );
 
+  // Cache bins for Entity-cache module.
+  $cache_schema = drupal_get_schema_unprocessed('system', 'cache');
+  $types = array(
+    'og_membership_type',
+    'og_membership',
+  );
+
+  foreach ($types as $type) {
+    $schema["cache_entity_$type"] = $cache_schema;
+    $schema["cache_entity_$type"]['description'] = "Cache table used to store $type entity records.";
+  }
+
   return $schema;
 }
 
@@ -1139,3 +1152,23 @@ function og_update_7203() {
 
   return $output;
 }
+
+/**
+ * Create cache bins for Entity-cache module.
+ */
+function og_update_7204() {
+  $cache_schema = drupal_get_schema_unprocessed('system', 'cache');
+  $types = array(
+    'og_membership_type',
+    'og_membership',
+  );
+
+  foreach ($types as $type) {
+    $schema["cache_entity_$type"] = $cache_schema;
+    $schema["cache_entity_$type"]['description'] = "Cache table used to store $type entity records.";
+  }
+
+  foreach ($schema as $name => $table) {
+    db_create_table($name, $table);
+  }
+}
diff --git a/sites/all/modules/og/og.module b/sites/all/modules/og/og.module
index 049b1a26d36f742ecc70e7ae1da3059207d65370..e6ebeae430d90726a57cfa78547154fbecf35fc2 100644
--- a/sites/all/modules/og/og.module
+++ b/sites/all/modules/og/og.module
@@ -6,7 +6,7 @@
  */
 
 // Add field widget related code.
-require drupal_get_path('module', 'og') . '/includes/og.field.inc';
+require DRUPAL_ROOT . '/' . drupal_get_path('module', 'og') . '/includes/og.field.inc';
 
 /**
  * Define active group content states.
@@ -137,6 +137,7 @@ function og_entity_info() {
     'metadata controller class' => 'EntityDefaultMetadataController',
     'views controller class' => 'EntityDefaultViewsController',
     'access callback' => 'og_membership_type_access',
+    'entity cache' => module_exists('entitycache'),
   );
 
   if (class_exists('OgMembershipTypeUIController')) {
@@ -172,6 +173,7 @@ function og_entity_info() {
     'metadata controller class' => 'OgMembershipMetadataController',
     'views controller class' => 'OgMembershipViewsController',
     'access callback' => 'og_membership_access',
+    'entity cache' => module_exists('entitycache'),
   );
 
   // Add bundle info but bypass entity_load() as we cannot use it here.
@@ -506,7 +508,7 @@ function og_node_access($node, $op, $account) {
   $type = is_string($node) ? $node : (is_array($node) ? $node['type'] : $node->type);
 
   if ($op == 'create' && og_is_group_content_type('node', $type) && variable_get('og_node_access_strict', TRUE)) {
-    if (user_access('administer group')) {
+    if (user_access('administer group', $account)) {
       return NODE_ACCESS_ALLOW;
     }
     // We can't check if user has create permissions using og_user_access(), as
@@ -672,7 +674,13 @@ function og_field_create_instance($instance) {
   $og_field = og_fields_info(OG_AUDIENCE_FIELD);
   $og_field['field']['settings']['target_type'] = $entity_type;
   $og_field['instance']['label'] = t('Group membership');
-  og_create_field($field_name, 'user', 'user', $og_field);
+
+  // If the user entity type has multiple bundles, make sure to attach a field
+  // instance to all of them.
+  $entity_info = entity_get_info('user');
+  foreach (array_keys($entity_info['bundles']) as $user_bundle) {
+    og_create_field($field_name, 'user', $user_bundle, $og_field);
+  }
 }
 
 /**
@@ -896,7 +904,7 @@ function og_entity_delete($entity, $entity_type) {
   list($id, , $bundle) = entity_extract_ids($entity_type, $entity);
   if (og_is_group($entity_type, $entity)) {
     og_delete_user_roles_by_group($entity_type, $entity);
-    og_membership_delete_by_group($entity_type, $id);
+    og_membership_delete_by_group($entity_type, $entity);
   }
   if (og_is_group_content_type($entity_type, $bundle)) {
     // As the field attachers are called after hook_entity_presave() we
@@ -1029,7 +1037,7 @@ function og_og_fields_info() {
   );
 
   $items[OG_AUDIENCE_FIELD] = array(
-    'no ui' => TRUE,
+    'multiple' => TRUE,
     'type' => array('group content'),
     'description' => t('Determine to which groups this group content is assigned to.'),
     'field' => array(
@@ -1185,12 +1193,16 @@ function og_membership_invalidate_cache() {
  *
  * If a group membership already exists, an exception will be thrown.
  *
+ * @param $group_type
+ *   The entity type of the group.
  * @param $gid
- *   The group ID
+ *   The group ID.
  * @param $entity_type
  *   The entity type of the group content.
  * @param $etid
  *   The entity ID of the group content.
+ * @param $field_name
+ *   The group audience field name.
  * @param $values
  *   Optional; Array of fields values to be attached to the OG membership, that
  *   will be processed using entity-metadata wrapper.
@@ -1316,7 +1328,7 @@ function og_entity_query_alter(EntityFieldQuery $query) {
 function og_query_og_membership_alter(QueryAlterableInterface $query) {
   $tables = &$query->getTables();
   $fields = &$query->getFields();
-  $conditions =  &$query->conditions();
+  $conditions = &$query->conditions();
 
   // Find the group-audience fields.
   $field_names = array();
@@ -1361,28 +1373,49 @@ function og_query_og_membership_alter(QueryAlterableInterface $query) {
     }
   }
 
-  if ($base_table) {
-    // Point the revision ID and bundle to the base entity.
-    $entity_type = $query->alterMetaData['entity_field_query']->entityConditions['entity_type']['value'];
-    $entity_type = is_array($entity_type) ? $entity_type[0] : $entity_type;
-    $entity_info = entity_get_info($entity_type);
+  $entity_type = $query->alterMetaData['entity_field_query']->entityConditions['entity_type']['value'];
+  $entity_type = is_array($entity_type) ? $entity_type[0] : $entity_type;
+  $entity_info = entity_get_info($entity_type);
+  $id = $entity_info['entity keys']['id'];
 
+  if ($base_table) {
     // If the table of the base entity does not exist (e.g. there is no
     // property condition), we need to add it, as we don't have the
     // revision ID and bundle in {og_membership} table.
     $base_table = $entity_info['base table'];
     if (strpos($base_table_alias, 'field_data') === 0) {
-      $id = $entity_info['entity keys']['id'];
-      $query->innerJoin($base_table, $base_table, "$base_table.$id = ogm.etid");
+      // Check if the entity base table already exists.
+      $base_table_alias = FALSE;
+      foreach ($tables as $table) {
+        if ($table['table'] == $base_table) {
+          $base_table_alias = $table['alias'];
+          break;
+        }
+      }
+      if (!$base_table_alias) {
+        $base_table_alias = $query->innerJoin($base_table, NULL, "$base_table.$id = ogm.etid");
+      }
     }
 
+    // Point the revision ID and bundle to the base entity.
     $fields['revision_id']['table'] = $base_table;
     // If there is no revision table, use the bundle.
-    $fields['revision_id']['field'] = !empty($entity_info['entity keys']['revision']) ? $entity_info['entity keys']['revision'] : $entity_info['entity keys']['bundle'];
+    if (!empty($entity_info['entity keys']['revision'])) {
+      // Entity doesn't support revisions.
+      $fields['revision_id']['field'] = $entity_info['entity keys']['revision'];
 
-    $fields['bundle']['table'] = $base_table;
-    $fields['bundle']['field'] = $entity_info['entity keys']['bundle'];
+    }
+    elseif (!empty($entity_info['entity keys']['bundle'])) {
+      $fields['revision_id']['field'] = $entity_info['entity keys']['bundle'];
+
+    }
+    else {
+      // Entity doesn't have bundles (e.g. user).
+      $fields['revision_id']['field'] = $id;
+    }
 
+    $fields['bundle']['table'] = $base_table;
+    $fields['bundle']['field'] = !empty($entity_info['entity keys']['bundle']) ? $entity_info['entity keys']['bundle'] : $id;
     $fields['entity_type']['table'] = 'ogm';
     $fields['entity_id']['table'] = 'ogm';
     $fields['entity_id']['field'] = 'etid';
@@ -1401,29 +1434,69 @@ function og_query_og_membership_alter(QueryAlterableInterface $query) {
     $query->join('og_membership', 'ogm', "ogm.etid = $base_table_alias.entity_id");
   }
 
+  _og_query_og_membership_alter_conditions($conditions, $aliases, $base_table_alias, $entity_info);
+}
+
+/**
+ * Recursively replace the fields to their aliases in the query's conditions.
+ *
+ * See og_query_og_membership_alter().
+ */
+function _og_query_og_membership_alter_conditions(&$conditions, $aliases, $base_table_alias, $entity_info) {
   foreach ($conditions as $delta => $values) {
     if (!is_array($values)) {
       continue;
     }
+
+    // Handle conditions in a sub-query.
+    if (is_object($values['value'])) {
+      _og_query_og_membership_alter_conditions($values['value']->conditions(), $aliases, $base_table_alias, $entity_info);
+    }
+
+    // Handle sub-conditions.
+    if (is_object($values['field'])) {
+      _og_query_og_membership_alter_conditions($values['field']->conditions(), $aliases, $base_table_alias, $entity_info);
+      continue;
+    }
+
     if (strpos($values['field'], 'field_data_') !== 0) {
       continue;
     }
 
-    $args = explode('.', $values['field']);
+    // Explode spaces on the fiels, for handling only the first part in values
+    // such as "foo.nid = bar.nid".
+    $field_parts = explode(' ', $values['field'], 2);
+    list($table, $column) = explode('.', $field_parts[0]);
 
-    if (empty($aliases[$args[0]])) {
+    if (empty($aliases[$table])) {
       continue;
     }
-    $field_name = $aliases[$args[0]];
+    $table = 'ogm';
 
-    if ($args[1] == 'deleted') {
+    // Replace entity_id or any other primary id (e.g. nid for the node
+    // entity).
+    $id_columns = array('entity_id', $entity_info['entity keys']['id']);
+    if (in_array($column, $id_columns)) {
+      $column = 'etid';
+    }
+
+    if ($column == 'deleted') {
       unset($conditions[$delta]);
+      continue;
     }
-    elseif (strpos($args[1], 'target_id')) {
-      $conditions[$delta]['field'] = 'ogm.gid';
+    elseif (strpos($column, 'target_id')) {
+       $column = 'gid';
     }
-    else {
-      $conditions[$delta]['field'] = 'ogm.' . $args[1];
+    elseif ($column == 'bundle') {
+      // Add the bundle of the base entity type.
+      $table = $base_table_alias;
+      $column = $entity_info['entity keys']['bundle'];
+    }
+
+    $conditions[$delta]['field'] = "$table.$column";
+    // Add the second part if it exists.
+    if (!empty($field_parts[1])) {
+      $conditions[$delta]['field'] .= ' ' . $field_parts[1];
     }
   }
 }
@@ -1468,21 +1541,176 @@ function og_membership_delete_multiple($ids = array()) {
 }
 
 /**
- * Delete all OG memberships by group.
+ * Implements hook_cron_queue_info().
  */
-function og_membership_delete_by_group($group_type, $gid) {
+function og_cron_queue_info() {
+  $items['og_membership_orphans'] = array(
+    'title' => t('OG orphans'),
+    'worker callback' => 'og_membership_orphans_worker',
+    'time' => 60,
+  );
+  return $items;
+}
+
+/**
+ * Queue worker; Process a queue item.
+ *
+ * Delete memberships, and if needed all related group-content.
+ */
+function og_membership_orphans_worker($data) {
+  $group_type = $data['group_type'];
+  $gid = $data['gid'];
+
   $query = new EntityFieldQuery();
   $result = $query
     ->entityCondition('entity_type', 'og_membership')
     ->propertyCondition('group_type', $group_type, '=')
     ->propertyCondition('gid', $gid, '=')
+    ->propertyOrderBy('id')
+    ->range(0, 10)
     ->execute();
 
-  if (!empty($result['og_membership'])) {
-    og_membership_delete_multiple(array_keys($result['og_membership']));
+  if (empty($result['og_membership'])) {
+    return;
+  }
+
+  $ids = array_keys($result['og_membership']);
+  if ($data['orphans']['move']) {
+    _og_orphans_move($ids, $data['orphans']['move']['group_type'], $data['orphans']['move']['gid']);
+    $queue = DrupalQueue::get('og_membership_orphans');
+    return $queue->createItem($data);
+  }
+  elseif ($data['orphans']['delete']) {
+    _og_orphans_delete($ids);
+    // Create a new item.
+    $queue = DrupalQueue::get('og_membership_orphans');
+    return $queue->createItem($data);
+  }
+}
+
+/**
+ * Helper function to delete orphan group-content.
+ *
+ * @param $ids
+ *   Array of OG membership IDs.
+ *
+ * @see og_membership_delete_by_group_worker()
+ */
+function _og_orphans_delete($ids) {
+  // Get all the group-content that is now orphan.
+  $orphans = array();
+  $og_memberships = og_membership_load_multiple($ids);
+
+  foreach ($og_memberships as $og_membership) {
+    $entity_type = $og_membership->entity_type;
+    $id = $og_membership->etid;
+    // Don't delete users.
+    if ($entity_type == 'user') {
+      continue;
+    }
+    $entity_groups = og_get_entity_groups($entity_type, $id);
+    // Orphan node can be relate to only one type of entity group.
+    if (count($entity_groups) == 1) {
+      $gids = reset($entity_groups);
+      // Orphan node can be relate to only one node.
+      if (count($gids) > 1) {
+        continue;
+      }
+    }
+    $orphans[$entity_type][] = $id;
+  }
+
+  if ($orphans) {
+    foreach ($orphans as $entity_type => $ids) {
+      entity_delete_multiple($entity_type, $ids);
+    }
+  }
+
+  // Delete the OG memberships.
+  og_membership_delete_multiple($ids);
+}
+
+/**
+ * Helper function to move orphan group-content to another group.
+ *
+ * @param $ids
+ *   Array of OG membership IDs.
+ *
+ * @see og_membership_delete_by_group_worker()
+ */
+function _og_orphans_move($ids, $group_type, $gid) {
+  if (!og_is_group($group_type, $gid)) {
+    $params = array(
+      '@group-type' => $group_type,
+      '@gid' => $gid,
+    );
+    throw new OgException(format_string('Cannot move orphan group-content to @group-type - @gid, as it is not a valid group.', $params));
+  }
+
+  $og_memberships = og_membership_load_multiple($ids);
+  foreach ($og_memberships as $og_membership) {
+    $entity_type = $og_membership->entity_type;
+    $id = $og_membership->etid;
+    if (count(og_get_entity_groups($entity_type, $id)) > 1) {
+      continue;
+    }
+    $og_membership->group_type = $group_type;
+    $og_membership->gid = $gid;
+    $og_membership->save();
   }
 }
 
+/**
+ * Register memberships for deletion.
+ *
+ * if the property "skip_og_membership_delete_by_group" exists on the
+ * entity, this function will return early, and allow other implementing
+ * modules to deal with the deletion logic.
+ *
+ * @param $entity_type
+ *   The group type.
+ * @param $entity
+ *   The group entity object.
+ */
+function og_membership_delete_by_group($entity_type, $entity) {
+  if (!empty($entity->skip_og_membership_delete_by_group)) {
+    return;
+  }
+
+  list($gid) = entity_extract_ids($entity_type, $entity);
+  $query = new EntityFieldQuery();
+  $result = $query
+    ->entityCondition('entity_type', 'og_membership')
+    ->propertyCondition('group_type', $entity_type, '=')
+    ->propertyCondition('gid', $gid, '=')
+    ->execute();
+
+  if (empty($result['og_membership'])) {
+    return;
+  }
+
+  if (variable_get('og_use_queue', FALSE)) {
+    $queue = DrupalQueue::get('og_membership_orphans');
+    // Add item to the queue.
+    $data = array(
+      'group_type' => $entity_type,
+      'gid' => $gid,
+      // Allow implementing modules to determine the disposition (e.g. delete
+      // orphan group content).
+      'orphans' => array(
+        'delete' => isset($entity->og_orphans['delete']) ? $entity->og_orphans['delete'] : variable_get('og_orphans_delete', FALSE),
+        'move' => isset($entity->og_orphans['move']) ? $entity->og_orphans['move'] : array(),
+      ),
+    );
+
+    // Exit now, as the task will be processed via queue.
+    return $queue->createItem($data);
+  }
+
+  // No scalable solution was chosen, so just delete OG memberships.
+  og_membership_delete_multiple(array_keys($result['og_membership']));
+}
+
 /**
  * Label callback; Return the label of OG membership entity.
  */
@@ -1579,8 +1807,7 @@ function og_get_all_group($group_type = 'node') {
  *   Defaults to FALSE.
  */
 function og_get_best_group_audience_field($entity_type, $entity, $group_type, $group_bundle, $skip_access = FALSE) {
-  $entity_wrapper = entity_metadata_wrapper($entity_type, $entity);
-  $bundle = $entity_wrapper->getBundle();
+  list(,, $bundle) = entity_extract_ids($entity_type, $entity);
 
   $field_names = og_get_group_audience_fields($entity_type, $bundle);
   if (!$field_names) {
@@ -1598,11 +1825,13 @@ function og_get_best_group_audience_field($entity_type, $entity, $group_type, $g
       continue;
     }
 
+
     if (!og_check_field_cardinality($entity_type, $entity, $field_name)) {
       // Field reached maximum.
       continue;
     }
-    if (!$skip_access && !$entity_wrapper->{$field_name}->access('view')) {
+
+    if (!$skip_access && !field_access('view', $field, $entity_type, $entity)) {
       // User can't access field.
       continue;
     }
@@ -1612,7 +1841,7 @@ function og_get_best_group_audience_field($entity_type, $entity, $group_type, $g
 }
 
 /**
- * Return TRUE if a field can be used and has not reached maxium values.
+ * Return TRUE if a field can be used and has not reached maximum values.
  *
  * @param $entity_type
  *   The entity type.
@@ -1824,9 +2053,9 @@ function og_user_access($group_type, $gid, $string, $account = NULL, $skip_alter
     return TRUE;
   }
 
-  $group = entity_load_single($group_type, $gid);
   // Group manager has all privileges (if variable is TRUE).
-  if (variable_get('og_group_manager_full_access', TRUE)) {
+  if (!empty($account->uid) && variable_get('og_group_manager_full_access', TRUE)) {
+    $group = entity_load_single($group_type, $gid);
     if (!empty($group->uid) && $group->uid == $account->uid) {
       return TRUE;
     }
@@ -1848,8 +2077,9 @@ function og_user_access($group_type, $gid, $string, $account = NULL, $skip_alter
   }
 
   if (!$skip_alter && empty($perm_alter[$identifier][$account->uid][$string])) {
-    // Let modules alter the permissions. since $perm is static we create a
-    // clone of it.
+    // Let modules alter the permissions. since $perm is static we create
+    // a clone of it.
+    $group = !empty($group) ? $group : entity_load_single($group_type, $gid);
     $temp_perm = $perm[$identifier][$account->uid];
     $context = array(
       'string' => $string,
@@ -2021,7 +2251,7 @@ function og_get_entity_groups($entity_type = 'user', $entity = NULL, $states = a
  */
 function og_is_group_audience_field($field_name) {
   $field = field_info_field($field_name);
-  return $field['type'] == 'entityreference' && $field['settings']['handler'] == 'og';
+  return $field['type'] == 'entityreference' && ($field['settings']['handler'] == 'og' || strpos($field['settings']['handler'], 'og_') === 0);
 }
 
 /**
@@ -2042,23 +2272,12 @@ function og_get_group_audience_fields($entity_type = 'user', $bundle_name = 'use
     return $return[$identifier];
   }
   $return[$identifier] = array();
-  // field_info_instances() doesn't give the field type, so we have to use
-  // field_info_fields().
-  foreach (field_info_fields() as $field_name => $field_info) {
-    if (!og_is_group_audience_field($field_name)) {
-      continue;
-    }
 
-    if (empty($field_info['bundles'][$entity_type])) {
+  foreach (field_info_instances($entity_type, $bundle_name) as $field_name => $instance) {
+    if (!og_is_group_audience_field($field_name)) {
       continue;
     }
-
-    foreach ($field_info['bundles'][$entity_type] as $field_bundle) {
-      if ($field_bundle == $bundle_name) {
-        $instance_info = field_info_instance($entity_type, $field_name, $bundle_name);
-        $return[$identifier][$field_name] = $instance_info['label'];
-      }
-    }
+    $return[$identifier][$field_name] = $instance['label'];
   }
   return $return[$identifier];
 }
@@ -2103,15 +2322,15 @@ function og_is_group_type($entity_type, $bundle_name) {
  *
  * This is a wrapper function around og_get_group_type().
  *
- * @param $node_type
- *   The node type to be checked.
+ * @param $entity_type
+ *   The entity type to be checked.
  */
 function og_is_group_content_type($entity_type, $bundle_name) {
   return og_get_group_type($entity_type, $bundle_name, 'group content');
 }
 
 /**
- * Return all the enteties that are a group.
+ * Return all the entities that are a group.
  *
  * @return
  *   Array keyed with the entity type machine name and the entity human readable
@@ -2154,7 +2373,7 @@ function og_get_all_group_bundle() {
  *
  * @return
  *   Array keyed with the entity type machine name and the entity human readable
- *   name as the value, or an empty array if no enteties are defined as group
+ *   name as the value, or an empty array if no entities are defined as group
  *   content.
  */
 function og_get_all_group_content_entity() {
@@ -2218,13 +2437,21 @@ function og_is_member($group_type, $gid, $entity_type = 'user', $entity = NULL,
 /**
  * Check if group should use default roles and permissions.
  *
+ * @param $group_type
+ *   The entity type of the group.
  * @param $gid
- *   The group ID.
+ *   The group ID or the group entity.
+ *
  * @return
  *   TRUE if group should use default roles and permissions.
  */
-function og_is_group_default_access($entity_type, $entity) {
-  $wrapper = entity_metadata_wrapper($entity_type, $entity);
+function og_is_group_default_access($group_type, $gid) {
+  if (!field_info_field(OG_DEFAULT_ACCESS_FIELD)) {
+    // Don't bother loading entity if field does not exist.
+    return TRUE;
+  }
+
+  $wrapper = entity_metadata_wrapper($group_type, $gid);
   if (empty($wrapper->{OG_DEFAULT_ACCESS_FIELD})) {
     return TRUE;
   }
@@ -2293,6 +2520,9 @@ function og_role_permissions($roles = array()) {
  *   The group might be set to "Default access" but infact there are inactive
  *   group roles. Thus, we are forcing the function to return the overriden
  *   roles. see og_delete_user_roles_by_group().
+ * @param $include_all
+ *   Optional; If TRUE then the anonymous and authenticated default roles will
+ *   be included.
  *
  * @return
  *   An associative array with the role id as the key and the role name as
@@ -2334,6 +2564,8 @@ function og_roles($group_type, $bundle, $gid = 0, $force_group = FALSE, $include
  * Get array of default roles, keyed by their declaring module.
  *
  * @param $include
+ *   (optional) If TRUE also anonymous and authenticated roles will be returned.
+ *   Defaults to TRUE.
  *
  * @return
  *   Array of default roles, grouped by module name.
@@ -2359,13 +2591,16 @@ function og_get_default_roles($include = TRUE) {
 /**
  * Get all roles of a user in a certain group.
  *
+ * @param $group_type
+ *   The entity type of the group.
  * @param $gid
  *   The group ID.
  * @param $uid
- *   The user ID.
+ *   (optional) Integer specifying the user ID. By default an ID of current
+ *   logged in user will be used.
  * @param $include
- *   Optional; If TRUE also anonymous or authenticated role ID will be returned.
- *   Defaults to TRUE.
+ *   (optional) If TRUE also anonymous or authenticated role ID will be
+ *   returned. Defaults to TRUE.
  *
  * @return
  *   Array with the role IDs of the user as the key, and the role name as
@@ -2427,9 +2662,16 @@ function og_get_user_roles($group_type, $gid, $uid = NULL, $include = TRUE) {
  * Create a stub OG role object.
  *
  * @param $name
- * @param $gid
+ *   A name of the role.
  * @param $group_type
+ *   (optional) The entity type of the group.
+ * @param $gid
+ *   (optional) The group ID.
  * @param $group_bundle
+ *   (optional) The bundle of the group.
+ *
+ * @return
+ *   A stub OG role object.
  */
 function og_role_create($name, $group_type = '', $gid = 0, $group_bundle = '') {
   $role = new stdClass;
@@ -2443,11 +2685,12 @@ function og_role_create($name, $group_type = '', $gid = 0, $group_bundle = '') {
 /**
  * Fetch a user role from database.
  *
- * @param $role
+ * @param $rid
  *   An integer with the role ID.
+ *
  * @return
- *   A fully-loaded role object if a role with the given name or ID
- *   exists, FALSE otherwise.
+ *   A fully-loaded role object if a role with the given ID exists,
+ *   FALSE otherwise.
  */
 function og_role_load($rid) {
   return db_select('og_role', 'r')
@@ -2463,6 +2706,7 @@ function og_role_load($rid) {
  * @param $role
  *   A role object to modify or add. If $role->rid is not specified, a new
  *   role will be created.
+ *
  * @return
  *   Status constant indicating if role was created or updated.
  *   Failure to write the user role record will return FALSE. Otherwise.
@@ -2490,7 +2734,7 @@ function og_role_save($role) {
 /**
  * Delete a user role from database.
  *
- * @param $role
+ * @param $rid
  *   An integer with the role ID.
  */
 function og_role_delete($rid) {
@@ -2548,13 +2792,13 @@ function og_get_user_roles_name($rids = array()) {
  *
  * @see og_modules_uninstalled()
  *
- * @param $module
- *   Array with the modules name.
+ * @param $modules
+ *   Array with the module names.
  */
 function og_permissions_delete_by_module($modules = array()) {
-   db_delete('og_role_permission')
-     ->condition('module', $modules, 'IN')
-     ->execute();
+  db_delete('og_role_permission')
+    ->condition('module', $modules, 'IN')
+    ->execute();
 }
 
 /**
@@ -2566,6 +2810,7 @@ function og_permissions_delete_by_module($modules = array()) {
  *   The bundle type.
  * @param $gid
  *   The group ID.
+ *
  * @return
  *   The newly created roles keyed by role ID and role name as the value. Or
  *   FALSE if no roles were created.
@@ -2613,6 +2858,10 @@ function og_roles_override($group_type, $bundle, $gid) {
 /**
  * Grant a group role to a user.
  *
+ * @param $group_type
+ *   The entity type of the group.
+ * @param $gid
+ *   The group ID.
  * @param $uid
  *   The user ID.
  * @param $rid
@@ -2646,6 +2895,10 @@ function og_role_grant($group_type, $gid, $uid, $rid) {
 /**
  * Revoke a group role from a user.
  *
+ * @param $group_type
+ *   The entity type of the group.
+ * @param $gid
+ *   The group ID.
  * @param $uid
  *   The user ID.
  * @param $rid
@@ -2818,7 +3071,14 @@ function og_get_default_permissions() {
 }
 
 /**
- * Get all the modules fields that can be assigned to fieldable enteties.
+ * Get all the modules fields that can be assigned to fieldable entities.
+ *
+ * @param $field_name
+ *   The field name that was registered for the definition.
+ *
+ * @return
+ *   An array with the field and instance definitions, or FALSE if not
+ *   found.
  */
 function og_fields_info($field_name = NULL) {
   $return = &drupal_static(__FUNCTION__, array());
@@ -2828,7 +3088,11 @@ function og_fields_info($field_name = NULL) {
       if ($fields = module_invoke($module, 'og_fields_info')) {
         foreach ($fields as $key => $field) {
           // Add default values.
-          $field += array('entity type' => array());
+          $field += array(
+            'entity type' => array(),
+            'multiple' => FALSE,
+            'description' => '',
+          );
 
           // Add the module information.
           $return[$key] = array_merge($field, array('module' => $module));
@@ -2840,7 +3104,11 @@ function og_fields_info($field_name = NULL) {
     drupal_alter('og_fields_info', $return);
   }
 
-  return empty($field_name) ? $return : $return[$field_name];
+  if (!empty($field_name)) {
+    return !empty($return[$field_name]) ?  $return[$field_name] : FALSE;
+  }
+
+  return $return;
 }
 
 /**
@@ -2946,6 +3214,7 @@ function og_get_fieldable_entity_list() {
  *
  * @param $type
  *   The machine-readable name of the node type.
+ *
  * @return array
  *   An array of permission names and descriptions.
  */
@@ -2960,10 +3229,7 @@ function og_list_permissions($type) {
     $perms += array(
       "create $type content" => array(
         'title' => t('Create %type_name content', array('%type_name' => $info->name)),
-        // We allow the create permission only on members, as otherwise we would
-        // have to iterate over every single group to decide if the user has
-        // permissions for it.
-        'roles' => array(OG_AUTHENTICATED_ROLE),
+
       ),
       "update own $type content" => array(
         'title' => t('Edit own %type_name content', array('%type_name' => $info->name)),
@@ -2979,6 +3245,13 @@ function og_list_permissions($type) {
       ),
     );
 
+    if (!module_exists('entityreference_prepopulate')) {
+      // We allow the create permission only on members, as otherwise we would
+      // have to iterate over every single group to decide if the user has
+      // permissions for it.
+      $perms["create $type content"]['roles'] = array(OG_AUTHENTICATED_ROLE);
+    }
+
     // Add default permissions.
     foreach ($perms as $key => $value) {
       $perms[$key]['default role'] = array(OG_AUTHENTICATED_ROLE);
@@ -2990,8 +3263,12 @@ function og_list_permissions($type) {
 /**
  * Return a form element with crafted links to create nodes for a group.
  *
+ * @param $group_type
+ *   The entity type of the group.
  * @param $gid
  *   The group ID.
+ * @param $field_name
+ *   The group audience field name.
  * @param $destination
  *   Optional; The destiantion after a node is created. Defaults to the
  *   destination passed in the URL if exists, otherwise back to the current
@@ -3060,6 +3337,9 @@ function og_node_create_links($group_type, $gid, $field_name, $destination = NUL
  * @param $account
  *   Optional; The user object to fetch group memberships for. Defaults to the
  *   acting user.
+ * @param $group_type
+ *   Optional; The entity type of the groups to fetch. By default all group
+ *   types will be fetched.
  *
  * @return
  *   An array with the group IDs or an empty array.
@@ -3166,6 +3446,25 @@ function og_features_api() {
   );
 }
 
+/**
+ * Implements hook_features_pipe_alter().
+ *
+ * Prevent OG related fields from being piped in features, when a content
+ * type that has them is selected.
+ */
+function og_features_pipe_alter(&$pipe, $data, $export) {
+  if (!variable_get('og_features_ignore_og_fields', FALSE) || empty($pipe['field'])) {
+    return;
+  }
+  foreach ($pipe['field'] as $delta => $value) {
+    $args = explode('-', $value);
+    $field_name = $args[2];
+    if (og_fields_info($field_name) || og_is_group_audience_field($field_name)) {
+      unset($pipe['field'][$delta]);
+    }
+  }
+}
+
 /**
  * Implements hook_migrate_api().
  */
@@ -3175,6 +3474,14 @@ function og_migrate_api() {
     $migrations['OgMigrateAddFields'] = array('class_name' => 'OgMigrateAddFields');
     $migrations['OgMigrateContent'] = array('class_name' => 'OgMigrateContent');
     $migrations['OgMigrateUser'] = array('class_name' => 'OgMigrateUser');
+
+    foreach (node_type_get_names() as $bundle => $value) {
+      $machine_name = 'OgMigrateGroup' . ucfirst($bundle);
+      $migrations[$machine_name] = array(
+        'class_name' => 'OgMigrateGroup',
+        'bundle' => $bundle,
+      );
+    }
   }
   elseif (db_field_exists('og_membership', 'group_type') && db_table_exists('og') && !db_table_exists('d6_og')) {
     $migrations['OgMigrateMembership'] = array('class_name' => 'OgMigrateMembership');
@@ -3185,29 +3492,17 @@ function og_migrate_api() {
   $api = array(
     'api' => 2,
     'migrations' => $migrations,
-    'destination handlers' => array(
-      'MigrateDestinationOGMembership',
-    ),
   );
   return $api;
 }
 
 /**
- * Implements hook_modules_enabled().
- *
- * Register dynamic migrate plugins for upgrading from OG6.
+ * Implements hook_flush_caches().
  */
-function og_modules_enabled($modules) {
-  if (!db_table_exists('d6_og')) {
-    return;
-  }
-
-  if (!in_array('migrate', $modules) && !module_exists('migrate')) {
-    return;
-  }
-
-  foreach (node_type_get_names() as $bundle => $value) {
-    // Register a dynamic migration.
-    Migration::registerMigration('OgMigrateGroup', 'OgMigrateGroup' . ucfirst($bundle), array('bundle' => $bundle));
-  }
+function og_flush_caches() {
+  $bins = array(
+    'cache_entity_og_membership',
+    'cache_entity_og_membership_type',
+  );
+  return $bins;
 }
diff --git a/sites/all/modules/og/og.test b/sites/all/modules/og/og.test
index f64b08942af0aa101b7436e71bde59a94cfecaf9..b9fe5c0ea6768b883f61da65714f6c015d34dbc1 100644
--- a/sites/all/modules/og/og.test
+++ b/sites/all/modules/og/og.test
@@ -364,7 +364,7 @@ class OgMetaData extends DrupalWebTestCase {
     $settings = array();
     $settings['type'] = 'article';
 
-    // Create group enteties.
+    // Create group entities.
     foreach (og_group_content_states() as $state => $value) {
       $node = $this->drupalCreateNode($settings);
 
@@ -458,6 +458,15 @@ class OgGroupAndUngroup extends DrupalWebTestCase {
     $settings['uid'] = $user2->uid;
     $node = $this->drupalCreateNode($settings);
 
+    // Exception on OG membership for anonymous user.
+    try {
+      og_membership_create('entity_test', $entity1->pid, 'user', 0, OG_AUDIENCE_FIELD)->save();
+      $this->fail('OG membership can be created for anonymous user.');
+    }
+    catch (OgException $e) {
+      $this->pass('OG membership can not be created for anonymous user.');
+    }
+
     $this->assertFalse(og_is_member('entity_test', $entity1->pid, 'node', $node), t('Node is not assigned to group1.'));
     $values = array('entity_type' => 'node', 'entity' => $node);
     og_group('entity_test', $entity1->pid, $values);
@@ -928,7 +937,6 @@ class OgComplexWidgetTestCase extends DrupalWebTestCase {
     og_create_field(OG_AUDIENCE_FIELD, 'node', 'post', $og_field);
   }
 
-
   /**
    * Test "field modes" of the OG reference widget.
    */
@@ -1017,8 +1025,6 @@ class OgComplexWidgetTestCase extends DrupalWebTestCase {
     $user1 = $this->drupalCreateUser();
     $user2 = $this->drupalCreateUser();
 
-    $type = $this->drupalCreateContentType();
-
     $settings = array(
       'type' => 'group',
       OG_GROUP_FIELD . '[und][0][value]' => 1,
@@ -1033,6 +1039,43 @@ class OgComplexWidgetTestCase extends DrupalWebTestCase {
 
     $this->assertTrue(og_get_entity_groups('user', $user2, array(OG_STATE_PENDING)), 'User membership was retained after user save.');
   }
+
+  /**
+   * Test multiple group-audience fields.
+   */
+  function testMultipleFields() {
+    // Add another group-audience field.
+    $og_field = og_fields_info(OG_AUDIENCE_FIELD);
+    og_create_field('another_field', 'node', 'post', $og_field);
+
+    $user1 = $this->drupalCreateUser();
+
+    // Create a group.
+    $settings = array(
+      'type' => 'group',
+      OG_GROUP_FIELD . '[und][0][value]' => 1,
+      'uid' => $user1->uid,
+    );
+    $group1 = $this->drupalCreateNode($settings);
+    $group2 = $this->drupalCreateNode($settings);
+
+    // Create group content.
+    $settings = array(
+      'type' => 'post',
+      'uid' => $user1->uid,
+    );
+    $post1 = $this->drupalCreateNode($settings);
+
+    og_group('node', $group1->nid, array('entity_type' => 'node', 'entity' => $post1, 'field_name' => OG_AUDIENCE_FIELD));
+    og_group('node', $group2->nid, array('entity_type' => 'node', 'entity' => $post1, 'field_name' => 'another_field'));
+
+    $this->drupalLogin($user1);
+    $this->drupalGet("node/$post1->nid/edit");
+
+    // Assert correct selection in both fields.
+    $this->assertOptionSelected('edit-og-group-ref-und-0-default', $group1->nid);
+    $this->assertOptionSelected('edit-another-field-und-0-default', $group2->nid);
+  }
 }
 
 /**
@@ -1191,6 +1234,7 @@ class OgEntityFieldQueryTestCase extends DrupalWebTestCase {
     parent::setUp('og', 'entity_feature');
 
     $user1 = $this->drupalCreateUser();
+    $user2 = $this->drupalCreateUser();
     $type = $this->drupalCreateContentType();
     $group_type = $type->type;
 
@@ -1273,10 +1317,17 @@ class OgEntityFieldQueryTestCase extends DrupalWebTestCase {
     );
     og_group('node', $group2, $values);
 
+    $values = array(
+      'entity_type' => 'user',
+      'entity' => $user2,
+    );
+    og_group('node', $group2, $values);
+
     $this->group1 = $group1;
     $this->group2 = $group2;
     $this->node = $node;
     $this->user1 = $user1;
+    $this->user2 = $user2;
     $this->entity_test = $entity_test;
   }
 
@@ -1289,7 +1340,8 @@ class OgEntityFieldQueryTestCase extends DrupalWebTestCase {
    * - Non-audience field first, with single group audience.
    * - Multiple entity types in entityCondition().
    * - No entity property.
-   * - Non-node entity without revision table.
+   * - Non-node entity without revision table (e.g. entity_test).
+   * - Non-node entity without revision table and without bundles (e.g. user).
    * - Count query.
    */
   function testEntityFieldQuery()  {
@@ -1370,6 +1422,19 @@ class OgEntityFieldQueryTestCase extends DrupalWebTestCase {
 
     $this->assertEqual(array_keys($result['entity_test']), array($entity_test->pid), 'Non-node entity without revision table query is correct.');
 
+    // Non-node entity without revision table and without bundles.
+    $query = new EntityFieldQuery();
+    $result = $query
+      ->entityCondition('entity_type', 'user')
+      ->fieldCondition('og_entity_test', 'target_id', $group2->nid)
+      ->execute();
+
+    $expected_values = array(
+      $this->user1->uid,
+      $this->user2->uid,
+    );
+    $this->assertEqual(array_keys($result['user']), $expected_values, 'Non-node entity without revision table and without bundles query is correct.');
+
     // Count query.
     $query = new EntityFieldQuery();
     $result = $query
@@ -1440,10 +1505,10 @@ class OgBehaviorHandlerTestCase  extends DrupalWebTestCase {
     // Add OG group field to the entity_test's "main" bundle.
     og_create_field(OG_GROUP_FIELD, 'entity_test', 'main');
 
-    $type = $this->drupalCreateContentType();
+    $type = $this->drupalCreateContentType(array('type' => 'behavior'));
     $this->group_content = $type->type;
 
-    // Add OG audience field to the node's "article" bundle.
+    // Add OG audience field to the new bundle.
     $og_field = og_fields_info(OG_AUDIENCE_FIELD);
     $og_field['field']['settings']['target_type'] = 'entity_test';
     og_create_field(OG_AUDIENCE_FIELD, 'node', $type->type, $og_field);
@@ -1511,4 +1576,155 @@ class OgBehaviorHandlerTestCase  extends DrupalWebTestCase {
     $gids = og_get_entity_groups('node', $node);
     $this->assertEqual(array_values($gids['entity_test']), array($entity1->pid), 'Widget behavior was skipped and removed group association as expected.');
   }
+
+  /**
+   * Test settings the OG membership state via field values, when associating
+   * a new group-content to a group.
+   */
+  function testSetStateOnInsert() {
+    module_enable(array('og_test'));
+    $permissions = array(
+      'access content',
+      "create $this->group_content content",
+      'administer group',
+    );
+    $user1 = $this->drupalCreateUser();
+    $user2 = $this->drupalCreateUser($permissions);
+    $user3 = $this->drupalCreateUser($permissions);
+
+    // Create a group.
+    $entity1 = entity_create('entity_test', array('name' => 'main', 'uid' => $user1->uid));
+    $wrapper = entity_metadata_wrapper('entity_test', $entity1);
+    $wrapper->{OG_GROUP_FIELD}->set(1);
+    $wrapper->save();
+
+    og_group('entity_test', $entity1, array('entity_type' => 'user', 'entity' => $user2));
+    og_group('entity_test', $entity1, array('entity_type' => 'user', 'entity' => $user3));
+
+    // Post a node, state should be active.
+    $type = str_replace('_', '-', $this->group_content);
+    $edit = array(
+      'title' => 'state-active',
+      'og_group_ref[und][0][default][]' => array($entity1->pid),
+    );
+
+    $this->drupalLogin($user2);
+    $this->drupalPost('node/add/' . $type, $edit, t('Save'));
+
+    $gids = og_get_entity_groups('node', 1);
+    $id = key($gids['entity_test']);
+    $og_membership = og_membership_load($id);
+    $this->assertEqual($og_membership->state, OG_STATE_ACTIVE, 'Memebership status is Active');
+
+
+    // Post a node, state should be pending.
+    $this->drupalLogin($user3);
+    $edit['title'] = 'state-pending';
+    $this->drupalPost('node/add/' . $type, $edit, t('Save'));
+    $gids = og_get_entity_groups('node', 2, array(OG_STATE_PENDING));
+    $id = key($gids['entity_test']);
+    $og_membership = og_membership_load($id);
+    $this->assertEqual($og_membership->state, OG_STATE_PENDING, 'Memebership status is Active');
+  }
+}
+
+/**
+ * Testing for deleting orphans group content.
+ */
+class OgDeleteOrphansTestCase extends DrupalWebTestCase {
+
+  public $group_type;
+  public $node_type;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'OG orphan delete',
+      'description' => 'Verifying for deleting orphan group content.',
+      'group' => 'Organic groups',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('og_test');
+
+    // Create a group content type.
+    $group = $this->drupalCreateContentType();
+    og_create_field(OG_GROUP_FIELD, 'node', $group->type);
+    $this->group_type = $group->type;
+
+    // Create group audience content type.
+    $type = $this->drupalCreateContentType();
+    $this->node_type = $type->type;
+
+    // Add OG audience field to the audience content type.
+    $og_field = og_fields_info(OG_AUDIENCE_FIELD);
+    $og_field['field']['settings']['target_type'] = 'node';
+    og_create_field(OG_AUDIENCE_FIELD, 'node', $type->type, $og_field);
+
+    // Set the setting for delete a group content when deleting group.
+    variable_set('og_orphans_delete', TRUE);
+    variable_set('og_use_queue', TRUE);
+  }
+
+  /**
+   * Testing two things:
+   *  When deleting a group, the node of the group will be deleted.
+   *  Associated node with the deleted group and another group won't be deleted.
+   */
+  function testDeleteGroup() {
+    // Creating two groups.
+    $first_group = $this->drupalCreateNode(array('type' => $this->group_type));
+    $second_group = $this->drupalCreateNode(array('type' => $this->group_type));
+
+    // Create two nodes.
+    $first_node = $this->drupalCreateNode(array('type' => $this->node_type));
+    og_group('node', $first_group, array('entity_type' => 'node', 'entity' => $first_node));
+    og_group('node', $second_group, array('entity_type' => 'node', 'entity' => $first_node));
+
+    $second_node = $this->drupalCreateNode(array('type' => $this->node_type));
+    og_group('node', $first_group, array('entity_type' => 'node', 'entity' => $second_node));
+
+    // Delete the group.
+    node_delete($first_group->nid);
+
+    // Execute manually the queue worker.
+    $queue = DrupalQueue::get('og_membership_orphans');
+    $item = $queue->claimItem();
+    og_membership_orphans_worker($item->data);
+
+    // Load the nodes we used during the test.
+    $first_node = node_load($first_node->nid);
+    $second_node = node_load($second_node->nid);
+
+    // Verify the none orphan node wasn't deleted.
+    $this->assertTrue($first_node, "The second node is realted to another group and deleted.");
+    // Verify the orphan node deleted.
+    $this->assertFalse($second_node, "The orphan node deleted.");
+  }
+
+  /**
+   * Testing the moving of the node to another group when deleting a group.
+   */
+  function testMoveOrphans() {
+    // Creating two groups.
+    $first_group = $this->drupalCreateNode(array('type' => $this->group_type, 'title' => 'move'));
+    $second_group = $this->drupalCreateNode(array('type' => $this->group_type));
+
+    // Create a group and relate it to the first group.
+    $first_node = $this->drupalCreateNode(array('type' => $this->node_type));
+    og_group('node', $first_group, array('entity_type' => 'node', 'entity' => $first_node));
+
+    // Delete the group.
+    node_delete($first_group->nid);
+
+    // Execute manually the queue worker.
+    $queue = DrupalQueue::get('og_membership_orphans');
+    $item = $queue->claimItem();
+    og_membership_orphans_worker($item->data);
+
+    // Load the node into a wrapper and verify we moved him to another group.
+    $wrapper = entity_metadata_wrapper('node', $first_node->nid);
+
+    $this->assertTrue($wrapper->{OG_AUDIENCE_FIELD}->get(0)->getIdentifier() == $second_group->nid, "The node of the group moved to another group.");
+  }
 }
diff --git a/sites/all/modules/og/og_access/og_access.info b/sites/all/modules/og/og_access/og_access.info
index 21b4fd7b5c77e0fb4f319b3fdbc60c336ffea027..b410cadb2ac016e85e35d23208aef2c9b53cd093 100644
--- a/sites/all/modules/og/og_access/og_access.info
+++ b/sites/all/modules/og/og_access/og_access.info
@@ -9,9 +9,9 @@ files[] = og_access.install
 
 ; Tests
 files[] = og_access.test
-; Information added by drupal.org packaging script on 2012-11-25
-version = "7.x-2.0-beta3+6-dev"
+; Information added by drupal.org packaging script on 2013-04-22
+version = "7.x-2.2"
 core = "7.x"
 project = "og"
-datestamp = "1353849566"
+datestamp = "1366630883"
 
diff --git a/sites/all/modules/og/og_access/og_access.module b/sites/all/modules/og/og_access/og_access.module
index 7160144addb8208abf9f00e3860232ed26de2cd8..0666581d8e107d3e4a8d87d12662b0ea80d80fee 100644
--- a/sites/all/modules/og/og_access/og_access.module
+++ b/sites/all/modules/og/og_access/og_access.module
@@ -140,7 +140,7 @@ function og_access_og_fields_info() {
   );
   $items[OG_ACCESS_FIELD] = array(
     'type' => array('group'),
-    'description' => t('Add Group access field to group types.'),
+    'description' => t('Determine access to the group.'),
     // Private access can be done only on node entity.
     'entity' => array('node'),
     'field' => array(
@@ -177,7 +177,7 @@ function og_access_og_fields_info() {
   );
   $items[OG_CONTENT_ACCESS_FIELD] = array(
     'type' => array('group content'),
-    'description' => t('Add Group access field to group-content types, that may override the group settings.'),
+    'description' => t('Determine access to the group content, which may override the group settings.'),
     // Private access can be done only on node entity.
     'entity' => array('node'),
     'field' => array(
diff --git a/sites/all/modules/og/og_context/includes/views/handlers/og_context_plugin_access_og_perm.inc b/sites/all/modules/og/og_context/includes/views/handlers/og_context_plugin_access_og_perm.inc
index 5ace9a1d28a139060a9157503230b8b235734c24..6ba0d4f51d0cbd561745b3cab08dcdf8cc0d3e9d 100644
--- a/sites/all/modules/og/og_context/includes/views/handlers/og_context_plugin_access_og_perm.inc
+++ b/sites/all/modules/og/og_context/includes/views/handlers/og_context_plugin_access_og_perm.inc
@@ -10,35 +10,6 @@
  * current group.
  */
 class og_context_plugin_access_og_perm extends views_plugin_access {
-  /**
-   * Determine if the current user has access or not.
-   */
-  function access($account) {
-    // Attempt to get the group from the current context and determine if the
-    // user has the appropriate permission within the group
-    if ($group = og_context($this->options['group_type'])) {
-      return og_user_access($group['group_type'], $group['gid'], $this->options['perm'], $account);
-    }
-    return FALSE;
-  }
-
-  /**
-   * Determine the access callback and arguments.
-   */
-  function get_access_callback() {
-    if ($group = og_context($this->options['group_type'])) {
-      return array('og_user_access', array($group['group_type'], $group['gid'], $this->options['perm']));
-    }
-    return FALSE;
-  }
-
-  /**
-   * Return a string to display as the clickable title for the
-   * access control.
-   */
-  function summary_title() {
-    return $this->options['perm'];
-  }
 
   /**
    * Retrieve the options when this is a new access
@@ -48,6 +19,7 @@ class og_context_plugin_access_og_perm extends views_plugin_access {
     $options = parent::option_definition();
     $options['perm'] = array('default' => 'edit group');
     $options['group_type'] = array('default' => 'node');
+    $options['group_id_arg'] = array('default' => FALSE);
 
     return $options;
   }
@@ -78,5 +50,54 @@ class og_context_plugin_access_og_perm extends views_plugin_access {
       '#default_value' => $this->options['group_type'],
       '#description' => t('Determine what entity type that group should be of.')
     );
+
+    $current_display = $this->view->current_display;
+    if ($this->view->display[$current_display]->handler->has_path()) {
+      // Show the group ID argument position only for "Page" displays.
+      $form['group_id_arg'] = array(
+        '#type' => 'select',
+        '#title' => t('Argument position for group ID'),
+        '#default_value' => $this->options['group_id_arg'],
+        '#options' => array(NULL => t('None')) + range(0, 9),
+        '#description' => t('Group ID argument position with arg() function. e.g. if your dynamic path is "node/%/group/%/overview" and you are using the second "%" for group IDs you have to choose "3" like "arg(3)".'),
+      );
+    }
+  }
+
+  /**
+   * Return a string to display as the clickable title for the
+   * access control.
+   */
+  function summary_title() {
+    $current_display = $this->view->current_display;
+    if ($this->options['group_id_arg'] === FALSE || $this->view->display[$current_display]->display_plugin != 'page') {
+      return $this->options['perm'];
+    }
+
+    $params = array(
+      '@perm' => $this->options['perm'],
+      '@arg' => $this->options['group_id_arg'],
+    );
+
+    return t('@perm, getting the group ID from argument position @arg', $params);
+  }
+
+  /**
+   * Determine if the current user has access or not.
+   */
+  function access($account) {
+    // Attempt to get the group from the current context and determine if the
+    // user has the appropriate permission within the group
+    if ($group = og_context($this->options['group_type'])) {
+      return og_user_access($group['group_type'], $group['gid'], $this->options['perm'], $account);
+    }
+    return FALSE;
+  }
+
+  /**
+   * Determine the access callback and arguments.
+   */
+  function get_access_callback() {
+    return array('_og_context_views_page_access', array($this->options['group_type'], $this->options['perm'], $this->options['group_id_arg']));
   }
 }
diff --git a/sites/all/modules/og/og_context/og_context.api.php b/sites/all/modules/og/og_context/og_context.api.php
index 1576a6c87420246d60dc9d0300d5fa696383f0e6..6738ca6a11107f7f391c83dd18c5e9b941386cdd 100644
--- a/sites/all/modules/og/og_context/og_context.api.php
+++ b/sites/all/modules/og/og_context/og_context.api.php
@@ -17,8 +17,7 @@
  * Define context "handlers".
  * - name: The human readable name of the context handler.
  * - Description: The description of the context handler.
- * - callback: The callback function that will evaluate and return the group IDs
- *   that it finds.
+ * - callback: The name of an implementation of callback_og_context_handler().
  * - menu path: Optional; The menu path as retrieved from menu_get_item() that
  *   is required for the context handler to be invoked.
  */
@@ -38,4 +37,28 @@ function hook_og_context_negotiation_info() {
 
 /**
  * @} End of "addtgrouproup hooks".
- */
\ No newline at end of file
+ */
+
+/**
+ * @addtgrouproup callbacks
+ * @{
+ */
+
+/**
+ * Evaluates and return group IDs to provide group context.
+ *
+ * Callback for hook_og_context_negotiation_info().
+ *
+ * @return
+ *  A nested array of group IDs, grouped first by entity type. Each value is
+ *  a flat array of group IDs.
+ */
+function callback_og_context_handler() {
+  return array(
+    'node' => array(1, 2, 3),
+  );
+}
+
+/**
+ * @} End of "addtgrouproup callbacks".
+ */
diff --git a/sites/all/modules/og/og_context/og_context.info b/sites/all/modules/og/og_context/og_context.info
index 706d6d92ed1a034dd418fcdc273e36ccea7b2dfa..692650d2fef0d15d6c235bcf4238dc7d79289ee9 100644
--- a/sites/all/modules/og/og_context/og_context.info
+++ b/sites/all/modules/og/og_context/og_context.info
@@ -12,9 +12,9 @@ files[] = includes/views/handlers/og_context_plugin_argument_default_group_conte
 ; Views access plugin
 files[] = includes/views/handlers/og_context_plugin_access_og_perm.inc
 
-; Information added by drupal.org packaging script on 2012-11-25
-version = "7.x-2.0-beta3+6-dev"
+; Information added by drupal.org packaging script on 2013-04-22
+version = "7.x-2.2"
 core = "7.x"
 project = "og"
-datestamp = "1353849566"
+datestamp = "1366630883"
 
diff --git a/sites/all/modules/og/og_context/og_context.module b/sites/all/modules/og/og_context/og_context.module
index a1f8a5f6be4c647705e58e75912886c92a277559..65cd3a5bc881b61c3ab9964a035b88561f7e6ba9 100644
--- a/sites/all/modules/og/og_context/og_context.module
+++ b/sites/all/modules/og/og_context/og_context.module
@@ -121,7 +121,7 @@ function og_context_og_context_negotiation_info() {
     'name' => t('Node'),
     'description' => t("Determine context by checking if a node is a group or a group content."),
     'callback' => 'og_context_handler_node',
-    'menu path' => array('node/%', 'node/%/edit'),
+    'menu path' => array('node/%', 'group/%/%/admin'),
   );
 
   $providers['user-view'] = array(
@@ -138,6 +138,13 @@ function og_context_og_context_negotiation_info() {
     'menu path' => array('user/%/edit'),
   );
 
+  $providers['comment'] = array(
+    'name' => t('Comment'),
+    'description' => t("Determine context by checking if the parent content of the comment belongs to a group"),
+    'callback' => 'og_context_handler_comment',
+    'menu path' => array('comment/reply/%', 'comment/%'),
+  );
+
   return $providers;
 }
 
@@ -187,10 +194,14 @@ function og_context($group_type = 'node', $group = NULL) {
   global $user;
   $context = &drupal_static(__FUNCTION__, FALSE);
 
-  if (empty($group) && !empty($context) && $context['group_type'] == $group_type) {
+  if (empty($group) && $context !== FALSE && (empty($context)) || (!empty($context['group_type']) && $context['group_type'] == $group_type)) {
     return $context;
   }
 
+  // Set the context to array, so we can now this function has been already
+  // executed.
+  $context = array();
+
   if (!empty($group)) {
     // Set the group.
     list($id) = entity_extract_ids($group_type, $group);
@@ -311,9 +322,14 @@ function og_context_provider_weight($provider) {
 /**
  * Determine the best matching context of a viewed page.
  *
+ * @param $group_type
+ *   The entity type of the group. For example, "node" or "user".
  * @param $item
  *   Optional; A menu item that context should be extracted from. If empty
  *   defaults to the current menu item by using menu_get_item().
+ *
+ * @return
+ *   The group ID for the current context.
  */
 function og_context_determine_context($group_type, $item = NULL) {
   // Enable url and node context handlers by default.
@@ -404,9 +420,30 @@ function og_context_handler_url() {
 
 /**
  * Context handler; Get groups from existing node or ctools context.
+ *
+ * @param $node
+ *  Optional; A node. If empty a node object will attempted to be loaded via
+ *  menu_get_object().
  */
-function og_context_handler_node() {
-  $node = menu_get_object('node');
+function og_context_handler_node($node = NULL) {
+  if (empty($node) && $node = menu_get_object()) {
+    return _group_context_handler_entity('node', $node);
+  }
+
+  $item = menu_get_item();
+
+  if (empty($item['map'])) {
+    // User has no access to the menu item.
+    return;
+  }
+
+  if ($item['path'] == 'node/%/group') {
+    $node = node_load($item['map'][1]);
+  }
+  elseif (strpos($item['path'], 'group/%/%/admin') === 0 && !empty($item['map'][1]) && $item['map'][1] == 'node') {
+    $node = node_load($item['map'][2]);
+  }
+
   if ($node) {
     return _group_context_handler_entity('node', $node);
   }
@@ -445,6 +482,29 @@ function og_context_handler_user_edit() {
   return _group_context_handler_entity('user');
 }
 
+/**
+ * Context handler; Get groups from parent of comment being added to it.
+ */
+function og_context_handler_comment() {
+  $item = menu_get_item();
+  // Check if we are in comment/reply/%nid. No need to load the comment.
+  if (isset($item['original_map'][2]) && is_numeric($item['original_map'][2])) {
+    $node = node_load($item['original_map'][2]);
+  }
+  // Use the comment ID.
+  elseif (isset($item['original_map'][1]) && is_numeric($item['original_map'][1])) {
+    $cid = $item['original_map'][1];
+    if (!$comment = comment_load($cid)) {
+      return;
+    }
+    $node = node_load($comment->nid);
+  }
+  else {
+    return;
+  }
+  return og_context_handler_node($node);
+}
+
 /**
  * Helper function to get group context from an entity.
  *
@@ -481,3 +541,29 @@ function _group_context_handler_entity($entity_type = 'node', $entity = NULL, $p
 
   return $contexts;
 }
+
+/**
+ * Helper function to handle views page access.
+ *
+ * @param $group_type
+ *   The group type.
+ * @param $perm
+ *   The group permission to search for.
+ * @param $group_id_arg
+ *   Optional; The position in arg() where the group ID can be found.
+ *
+ * @return
+ *   TRUE if user is allowed access to the page.
+ */
+function _og_context_views_page_access($group_type, $perm, $group_id_arg = FALSE) {
+  if ($group_id_arg !== '') {
+    $gid = arg($group_id_arg);
+    if (is_numeric($gid)) {
+      return og_user_access($group_type, $gid, $perm);
+    }
+  }
+  elseif ($group = og_context($group_type)) {
+    // Try to get context.
+    return og_user_access($group_type, $group['gid'], $perm);
+  }
+}
diff --git a/sites/all/modules/og/og_example/og_example.info b/sites/all/modules/og/og_example/og_example.info
index 02ac8feabb1da90dcff5036f965e2d54731bf36d..92b9a12bd35ff1be3cc97fc4a75693edfd3071cd 100644
--- a/sites/all/modules/og/og_example/og_example.info
+++ b/sites/all/modules/og/og_example/og_example.info
@@ -27,9 +27,9 @@ name = "OG example"
 package = "Features"
 php = "5.2.4"
 
-; Information added by drupal.org packaging script on 2012-11-25
-version = "7.x-2.0-beta3+6-dev"
+; Information added by drupal.org packaging script on 2013-04-22
+version = "7.x-2.2"
 core = "7.x"
 project = "og"
-datestamp = "1353849566"
+datestamp = "1366630883"
 
diff --git a/sites/all/modules/og/og_example/og_example.module b/sites/all/modules/og/og_example/og_example.module
index c6d58f6e4e1aef96c7dbf59c2684114da47ffde4..1fd302413207682da17068caf2f929df32184439 100644
--- a/sites/all/modules/og/og_example/og_example.module
+++ b/sites/all/modules/og/og_example/og_example.module
@@ -1,3 +1,12 @@
 <?php
 
 include_once('og_example.features.inc');
+
+/**
+ * Implements hook_ctools_plugin_directory().
+ */
+function og_example_ctools_plugin_directory($module, $plugin) {
+  if ($module == 'entityreference') {
+    return "plugins/entityreference/$plugin";
+  }
+}
diff --git a/sites/all/modules/og/og_example/plugins/entityreference/selection/OgExampleSelectionHandler.class.php b/sites/all/modules/og/og_example/plugins/entityreference/selection/OgExampleSelectionHandler.class.php
new file mode 100644
index 0000000000000000000000000000000000000000..52ac0ddb031d1db37b8a5a3b3407b84242e6c15a
--- /dev/null
+++ b/sites/all/modules/og/og_example/plugins/entityreference/selection/OgExampleSelectionHandler.class.php
@@ -0,0 +1,62 @@
+<?php
+
+
+/**
+ * @file
+ * OG example selection handler.
+ */
+
+class OgExampleSelectionHandler extends OgSelectionHandler {
+
+  /**
+   * Overrides OgSelectionHandler::getInstance().
+   */
+  public static function getInstance($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
+    return new OgExampleSelectionHandler($field, $instance, $entity_type, $entity);
+  }
+
+  /**
+   * Overrides OgSelectionHandler::buildEntityFieldQuery().
+   *
+   * This is an example of "subgroups" (but without getting into the logic of
+   * sub-grouping).
+   * The idea here is to show we can set "My groups" and "Other groups" to
+   * reference different groups by different
+   * logic. In this example, all group nodes below node ID 5, will appear under
+   * "My groups", and the rest will appear under "Other groups",
+   * for administrators.
+   */
+  public function buildEntityFieldQuery($match = NULL, $match_operator = 'CONTAINS') {
+    $group_type = $this->field['settings']['target_type'];
+
+
+    if (empty($this->instance['field_mode']) || $group_type != 'node') {
+      return parent::buildEntityFieldQuery($match, $match_operator);
+    }
+
+    $field_mode = $this->instance['field_mode'];
+    $handler = EntityReference_SelectionHandler_Generic::getInstance($this->field, $this->instance, $this->entity_type, $this->entity);
+    $query = $handler->buildEntityFieldQuery($match, $match_operator);
+
+    // Show only the entities that are active groups.
+    $query->fieldCondition(OG_GROUP_FIELD, 'value', 1, '=');
+
+    if ($field_mode == 'default') {
+      $query->propertyCondition('nid', '5', '<=');
+    }
+    else {
+      $query->propertyCondition('nid', '5', '>');
+    }
+
+    // FIXME: http://drupal.org/node/1325628
+    unset($query->tags['node_access']);
+
+    // FIXME: drupal.org/node/1413108
+    unset($query->tags['entityreference']);
+
+    $query->addTag('entity_field_access');
+    $query->addTag('og');
+
+    return $query;
+  }
+}
diff --git a/sites/all/modules/og/og_example/plugins/entityreference/selection/og_example.inc b/sites/all/modules/og/og_example/plugins/entityreference/selection/og_example.inc
new file mode 100644
index 0000000000000000000000000000000000000000..5f6e37c5f895a13214b59a004e915006e5cb6fbb
--- /dev/null
+++ b/sites/all/modules/og/og_example/plugins/entityreference/selection/og_example.inc
@@ -0,0 +1,7 @@
+<?php
+
+$plugin = array(
+  'title' => t('Organic groups example'),
+  'class' => 'OgExampleSelectionHandler',
+);
+
diff --git a/sites/all/modules/og/og_field_access/og_field_access.info b/sites/all/modules/og/og_field_access/og_field_access.info
index c3c53efb4611df88f0fd2e238476205b23a7ec73..4d78c0659f0b71201524f16adf53da8fbb6575f5 100644
--- a/sites/all/modules/og/og_field_access/og_field_access.info
+++ b/sites/all/modules/og/og_field_access/og_field_access.info
@@ -8,9 +8,9 @@ files[] = og_field_access.module
 ; Tests
 files[] = og_field_access.test
 
-; Information added by drupal.org packaging script on 2012-11-25
-version = "7.x-2.0-beta3+6-dev"
+; Information added by drupal.org packaging script on 2013-04-22
+version = "7.x-2.2"
 core = "7.x"
 project = "og"
-datestamp = "1353849566"
+datestamp = "1366630883"
 
diff --git a/sites/all/modules/og/og_register/og_register.info b/sites/all/modules/og/og_register/og_register.info
index f0a964699dbac7f917618e26d473039eaf6d1fa8..383c4a6bc9c3bb568c3d811ed69a40a6ef0c0d85 100644
--- a/sites/all/modules/og/og_register/og_register.info
+++ b/sites/all/modules/og/og_register/og_register.info
@@ -6,9 +6,9 @@ dependencies[] = og
 core = 7.x
 files[] = og_register.module
 files[] = og_register.install
-; Information added by drupal.org packaging script on 2012-11-25
-version = "7.x-2.0-beta3+6-dev"
+; Information added by drupal.org packaging script on 2013-04-22
+version = "7.x-2.2"
 core = "7.x"
 project = "og"
-datestamp = "1353849566"
+datestamp = "1366630883"
 
diff --git a/sites/all/modules/og/og_register/og_register.module b/sites/all/modules/og/og_register/og_register.module
index ca7c23a5346a77f16a39ab2b74207b43dbe047f3..e547a0e56b65190b24015d7e9f0f15ee904a7a32 100644
--- a/sites/all/modules/og/og_register/og_register.module
+++ b/sites/all/modules/og/og_register/og_register.module
@@ -13,7 +13,9 @@ define('OG_REGISTER_FIELD', 'group_register');
 
 
 /**
- * Implements hook_query_TAG_alter().
+ * Implements hook_query_og_alter().
+ *
+ * @todo: Filter out groups that don't allow to subscribe, if OG-UI is enabled.
  */
 function og_register_query_og_alter(QueryAlterableInterface $query) {
   global $user;
@@ -45,7 +47,7 @@ function og_register_query_og_alter(QueryAlterableInterface $query) {
   // Search the condition that falsified the query.
   // @see OgHandler_base::buildEntityFieldQuery
   foreach ($conditions as $key => $condition) {
-    if (!is_array($condition)) {
+    if (!is_array($condition) || !is_string($condition['field'])) {
       continue;
     }
     if ($condition['field'] != $group_type . '.' . $entity_info['entity keys']['id']) {
@@ -76,6 +78,61 @@ function og_register_query_og_alter(QueryAlterableInterface $query) {
   }
 }
 
+/**
+ * Implements hook_field_attach_form().
+ *
+ * Mark the group-audience fields as ones that are used i registration. This is used
+ * to later on make sure the user is registered according to the allowed permissions (i.e. with or
+ * without administrator approval).
+ */
+function og_register_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {
+  global $user;
+  if ($user->uid || $entity_type != 'user') {
+    return;
+  }
+
+  if (!module_exists('og_ui')) {
+    return;
+  }
+
+  if (!$fields = og_get_group_audience_fields()) {
+    return;
+  }
+
+  foreach (array_keys($fields) as $field_name) {
+    if (empty($form[$field_name])) {
+      continue;
+    }
+    $form[$field_name]['#element_validate'][] = 'og_register_og_membership_state_validate';
+  }
+}
+
+/**
+ * Validate handler; Set the state according to the "subscribe" permissions of the group.
+ */
+function og_register_og_membership_state_validate($element, &$form_state) {
+  $langcode = $element['#language'];
+  $field_name = $element[$langcode]['#field_name'];
+
+  if (empty($form_state['values'][$field_name][$langcode])) {
+    return;
+  }
+
+  $field = field_info_field($field_name);
+  $group_type = $field['settings']['target_type'];
+
+  $values = $form_state['values'][$field_name][$langcode];
+  foreach ($values as &$value) {
+    $og_roles = og_roles($group_type, NULL, $value['target_id']);
+    $rid = array_search(OG_ANONYMOUS_ROLE, $og_roles);
+    $og_permissions = og_role_permissions(array($rid => $rid));
+    // State should be pending if "subscribe without approval" is not enabled.
+    $value['state'] = !empty($og_permissions[$rid]['subscribe without approval']) ? OG_STATE_ACTIVE : OG_STATE_PENDING;
+  }
+
+  form_set_value($element, array($langcode => $values), $form_state);
+}
+
 /**
  * Implements og_fields_info().
  */
diff --git a/sites/all/modules/og/og_ui/includes/migrate/7000/add_field.inc b/sites/all/modules/og/og_ui/includes/migrate/7000/add_field.inc
index a11f6dbed4daf63a898305dba38046305f3a7afb..a50b331b66732f0cd36b2944e0c1b140dd1a2a5b 100644
--- a/sites/all/modules/og/og_ui/includes/migrate/7000/add_field.inc
+++ b/sites/all/modules/og/og_ui/includes/migrate/7000/add_field.inc
@@ -5,8 +5,6 @@
  * Add OG UI related fields to group node-types.
  */
 
-if (db_table_exists('d6_og')) {
-
 class OgUiMigrateAddField extends MigrationBase {
 
   public function __construct() {
@@ -45,5 +43,3 @@ class OgUiMigrateAddField extends MigrationBase {
     return MigrationBase::RESULT_COMPLETED;
   }
 }
-
-}
diff --git a/sites/all/modules/og/og_ui/includes/migrate/7000/populate_field.inc b/sites/all/modules/og/og_ui/includes/migrate/7000/populate_field.inc
index 6b75155db369a852caf16092a435d3918289f797..13ed128aae1900dfda7b447b452985fd4503bb81 100644
--- a/sites/all/modules/og/og_ui/includes/migrate/7000/populate_field.inc
+++ b/sites/all/modules/og/og_ui/includes/migrate/7000/populate_field.inc
@@ -5,8 +5,6 @@
  * Upgrade group visibility (e.g. open, moderated, closed) from OG6.
  */
 
-if (db_table_exists('d6_og')) {
-
 class OgUiPopulateField extends DynamicMigration {
 
   /**
@@ -53,6 +51,3 @@ class OgUiPopulateField extends DynamicMigration {
     return drupal_strtolower('OgUiPopulateField' . ucfirst($this->arguments['bundle']));
   }
 }
-
-}
-
diff --git a/sites/all/modules/og/og_ui/includes/migrate/7000/set_roles.inc b/sites/all/modules/og/og_ui/includes/migrate/7000/set_roles.inc
index 3f8bb01f0ebffe5db1df88c6ff5feb77cf336992..6423fb89181c826b79859564216c953f241a0cc0 100644
--- a/sites/all/modules/og/og_ui/includes/migrate/7000/set_roles.inc
+++ b/sites/all/modules/og/og_ui/includes/migrate/7000/set_roles.inc
@@ -5,8 +5,6 @@
  * Set permissions on group to upgrade group visibility.
  */
 
-if (db_table_exists('d6_og')) {
-
 class OgUiSetRoles extends Migration {
 
   /**
@@ -102,6 +100,3 @@ class OgUiSetRoles extends Migration {
     return TRUE;
   }
 }
-
-}
-
diff --git a/sites/all/modules/og/og_ui/includes/views/og_ui.views_default.inc b/sites/all/modules/og/og_ui/includes/views/og_ui.views_default.inc
index bb6cc3a54bf179cea7dcb8b57455ca7d60abe29d..fbf56f41ccdfa80675675927c477ef803dd22d45 100644
--- a/sites/all/modules/og/og_ui/includes/views/og_ui.views_default.inc
+++ b/sites/all/modules/og/og_ui/includes/views/og_ui.views_default.inc
@@ -209,6 +209,14 @@ function og_ui_views_default_views() {
   $handler->display->display_options['fields']['og_membership_request']['table'] = 'field_data_og_membership_request';
   $handler->display->display_options['fields']['og_membership_request']['field'] = 'og_membership_request';
   $handler->display->display_options['fields']['og_membership_request']['relationship'] = 'og_membership_rel';
+  /* Field: OG membership: Edit link */
+  $handler->display->display_options['fields']['edit_membership']['id'] = 'edit_membership';
+  $handler->display->display_options['fields']['edit_membership']['table'] = 'og_membership';
+  $handler->display->display_options['fields']['edit_membership']['field'] = 'edit_membership';
+  $handler->display->display_options['fields']['edit_membership']['relationship'] = 'og_membership_rel';
+  $handler->display->display_options['fields']['edit_membership']['label'] = '';
+  $handler->display->display_options['fields']['edit_membership']['element_label_colon'] = FALSE;
+  $handler->display->display_options['fields']['edit_membership']['destination'] = TRUE;
   /* Sort criterion: User: Name */
   $handler->display->display_options['sorts']['name']['id'] = 'name';
   $handler->display->display_options['sorts']['name']['table'] = 'users';
@@ -265,4 +273,4 @@ function og_ui_views_default_views() {
   $views[$view->name] = $view;
 
   return $views;
-}
\ No newline at end of file
+}
diff --git a/sites/all/modules/og/og_ui/og_ui.admin.inc b/sites/all/modules/og/og_ui/og_ui.admin.inc
index e32c148895004f5715bc6f0cb1bd9b04861933cd..506f66382bef25535279be4fa2035e2b9e8d28bc 100644
--- a/sites/all/modules/og/og_ui/og_ui.admin.inc
+++ b/sites/all/modules/og/og_ui/og_ui.admin.inc
@@ -65,6 +65,38 @@ function og_ui_admin_settings($form_state) {
     }
   }
 
+  $form['og_features_ignore_og_fields'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Prevent "Features" export piping'),
+    '#description' => t('When exporting using Features module a content-type, this will prevent from OG related fields to be exported.'),
+    '#default_value' => variable_get('og_features_ignore_og_fields', FALSE),
+    '#access' => module_exists('features'),
+  );
+
+  $form['og_use_queue'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Use queue'),
+    '#description' => t("Use the core's queue process to operations such as deleting memberships when groups are deleted."),
+    '#default_value' => variable_get('og_use_queue', FALSE),
+  );
+
+  $form['og_orphans_delete'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Delete orphans'),
+    '#description' => t('Delete "Orphan" group-content (not including useres), when the group is deleted.'),
+    '#default_value' => variable_get('og_orphans_delete', FALSE),
+    '#states' => array(
+      'visible' => array(
+        ':input[name="og_use_queue"]' => array('checked' => TRUE),
+      ),
+    ),
+    '#attributes' => array(
+      'class' => array('entityreference-settings'),
+    ),
+  );
+
+  // Re-use Entity-reference CSS for indentation.
+  $form['#attached']['css'][] = drupal_get_path('module', 'entityreference') . '/entityreference.admin.css';
   return system_settings_form($form);
 }
 
@@ -100,6 +132,7 @@ function og_ui_add_users($form, &$form_state, $group_type, $gid) {
   og_set_breadcrumb($group_type, $gid, array(l(t('Group'), "$group_type/$gid/group")));
   $group = entity_load_single($group_type, $gid);
   $label = entity_label($group_type, $group);
+  list(,, $bundle) = entity_extract_ids($group_type, $group);
 
   $form['group_type'] = array('#type' => 'value', '#value' => $group_type);
   $form['gid'] = array('#type' => 'value', '#value' => $gid);
@@ -120,6 +153,15 @@ function og_ui_add_users($form, &$form_state, $group_type, $gid) {
     '#value' => OG_STATE_ACTIVE,
   );
 
+  // Get all the non-default roles.
+  if ($og_roles = og_roles($group_type, $bundle, $gid, FALSE, FALSE)) {
+    $form['og_user']['roles'] = array(
+      '#type' => 'checkboxes',
+      '#options' => $og_roles,
+      '#title' => t('Roles'),
+    );
+  }
+
   $field_names = og_get_group_audience_fields();
   $field_name = !empty($form_state['values']['field_name']) ? $form_state['values']['field_name'] : key($field_names);
 
@@ -220,10 +262,106 @@ function og_ui_add_users_submit($form, &$form_state) {
   $og_membership->etid = $account->uid;
   $og_membership->state = $state;
   $og_membership->save();
+  // Assign roles.
+  if (!empty($form_state['values']['roles'])) {
+    foreach ($form_state['values']['roles'] as $rid) {
+      og_role_grant($group_type, $gid, $og_membership->etid, $rid);
+    }
+  }
+
+  $group = entity_load_single($group_type, $gid);
+  drupal_set_message(t('%user has been added to the group %group-title.', array('%user' => format_username($account), '%group-title' => entity_label($group_type, $group))));
+}
+
+/**
+ * Add Edit membership form.
+ */
+function og_ui_edit_membership($form, &$form_state, $group_type, $gid, $og_membership) {
+  og_set_breadcrumb($group_type, $gid, array(l(t('Group'), "$group_type/$gid/group")));
+  $group = entity_load_single($group_type, $gid);
+  $label = entity_label($group_type, $group);
+  $account = user_load($og_membership->etid);
+  list(,, $bundle) = entity_extract_ids($group_type, $group);
+  // Get all the non-default roles.
+  $og_roles = og_roles($group_type, $bundle, $gid, FALSE, FALSE);
+
+  $form['group_type'] = array('#type' => 'value', '#value' => $group_type);
+  $form['gid'] = array('#type' => 'value', '#value' => $gid);
+  $form['id'] = array('#type' => 'value', '#value' => $og_membership->id);
+
+  $form['og_user'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Edit a group membership in %group', array('%group' => $label)),
+  );
+  $form['og_user']['name'] = array(
+    '#type' => 'markup',
+    '#title' => t('User name'),
+    '#markup' => $account->name,
+  );
+  if ($og_roles) {
+    $form['og_user']['roles'] = array(
+      '#type' => 'checkboxes',
+      '#options' => $og_roles,
+      '#title' => t('Roles'),
+      '#default_value' => array_keys(og_get_user_roles($group_type, $gid, $account->uid)),
+    );
+  }
+
+ // Add group membership form.
+  $values = array();
+
+  // Add group membership form. We still don't have the user or state.
+  $form_state['og_membership'] = $og_membership;
+
+  $form['membership_fields'] = array(
+    '#prefix' => '<div id="og-ui-field-name">',
+    '#suffix' => '</div>',
+    '#tree' => TRUE,
+    '#parents' => array('membership_fields'),
+  );
+  field_attach_form('og_membership', $og_membership, $form['membership_fields'], $form_state);
+
+  $form['actions'] = array('#type' => 'actions');
+  $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Update membership'));
+
+  return $form;
+}
 
-  drupal_set_message(t('%user has been added to group.', array('%user' => format_username($account))));
+/**
+ * Validate handler; Edit membership in group.
+ */
+function og_ui_edit_membership_validate($form, &$form_state) {
+  $og_membership = $form_state['og_membership'];
+  field_attach_form_validate('og_membership', $og_membership, $form['membership_fields'], $form_state);
+}
+
+/**
+ * Submit handler; Edit membership in group.
+ */
+function og_ui_edit_membership_submit($form, &$form_state) {
+  $group_type = $form_state['values']['group_type'];
+  $gid = $form_state['values']['gid'];
+  $og_membership = $form_state['og_membership'];
+  field_attach_submit('og_membership', $og_membership, $form['membership_fields'], $form_state);
+  $og_membership->save();
+  $account = user_load($og_membership->etid);
+  // Assign roles.
+  $og_roles = og_get_user_roles($group_type, $gid, $account->uid);
+  foreach (array_keys($og_roles) as $rid) {
+    if (!in_array($rid, $form_state['values']['roles'])) {
+      og_role_revoke($group_type, $gid, $account->uid, $rid);
+    }
+  }
+  if (!empty($form_state['values']['roles'])) {
+    foreach ($form_state['values']['roles'] as $rid) {
+      og_role_grant($group_type, $gid, $og_membership->etid, $rid);
+    }
+  }
+  drupal_set_message(t('The membership has been updated.'));
 }
 
+
+
 /**
  * Form builder; OG user administration page.
  */
@@ -717,23 +855,25 @@ function theme_og_ui_admin_permissions($variables) {
 }
 
 /**
- * Allow site admin to add or remove group fields from fieldable enteies.
+ * Allow site admin to add or remove group fields from fieldable entities.
  */
 function og_ui_field_settings($form, &$form_state) {
   $form = array();
   $options = array();
 
   $options = array();
-  foreach (entity_get_info() as $entity_type => $entity) {
-    if (!empty($entity['fieldable']) && $entity_type != 'group') {
-      foreach($entity['bundles'] as $bundle_name => $bundle) {
-        // Prefix the bundle name with the entity type.
-        $options[$entity_type][$entity_type . '__' .$bundle_name] = check_plain($bundle['label']);
-      }
+  foreach (entity_get_info() as $entity_type => $entity_info) {
+    if (empty($entity_info['fieldable'])) {
+      continue;
+    }
+    foreach($entity_info['bundles'] as $bundle_name => $bundle) {
+      // Prefix the bundle name with the entity type.
+      $entity_name = check_plain("$entity_info[label] ($entity_type)");
+      $options[$entity_name][$entity_type . ':' . $bundle_name] = filter_xss($bundle['label']);
     }
   }
 
-  $form['bundles'] = array(
+  $form['bundle'] = array(
     '#title' => t('Bundles'),
     '#type' => 'select',
     '#options' => $options,
@@ -742,27 +882,65 @@ function og_ui_field_settings($form, &$form_state) {
   $options = array();
   foreach (og_fields_info() as $field_name => $field) {
     foreach ($field['type'] as $type) {
-      $options[$type][$field_name] = filter_xss($field['instance']['label']);
+      $type_name = $type == 'group' ? t('Group') : t('Group content');
+      $options[$type_name][$field_name] = filter_xss($field['instance']['label']);
     }
   }
 
-  $form['fields'] = array(
+  $selected_field_name = !empty($form_state['values']['field_type']) ? $form_state['values']['field_type'] : OG_AUDIENCE_FIELD;
+  $selected_og_info = og_fields_info($selected_field_name);
+
+  $form['field_info_wrapper'] = array(
+    '#prefix' => '<div id="field-info-wrapper">',
+    '#suffix' => '</div>',
+    '#parents' => array('field_info_wrapper'),
+    '#type' => 'fieldset',
+  );
+
+  $form['field_info_wrapper']['field_type'] = array(
     '#title' => t('Fields'),
     '#type' => 'select',
     '#options' => $options,
+    '#required' => TRUE,
+    '#default_value' => $selected_field_name,
+    '#ajax' => array(
+      'callback' => 'og_ui_admin_fields_ajax_callback',
+      'wrapper' => 'field-info-wrapper',
+    ),
   );
 
-  $field_enabled = array();
+  $form['field_info_wrapper']['description'] = array(
+    '#markup' => $selected_og_info['description'],
+  );
 
-  $group_fields = og_fields_info();
+  if (!empty($selected_og_info['multiple'])) {
+    $form['field_info_wrapper']['field_name'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Field name'),
+      '#description' => t('This field type supports adding multiple instances on the same bundle (i.e. the field name is not hardcoded).'),
+      '#required' => TRUE,
+      '#maxlength' => 32,
+      '#default_value' => $selected_field_name,
+    );
+  }
+  else {
+    // Pass the field name as a value.
+    $form['field_name_wrapper']['field_name'] = array(
+      '#type' => 'value',
+      '#value' => $selected_field_name,
+    );
+  }
+
+  $field_enabled = array();
+  $og_fields = og_fields_info();
 
-  $group_fields_name = array_keys($group_fields);
+  $og_fields_name = array_keys($og_fields);
 
   $entity_info = entity_get_info();
 
   // Get the fields that exist in the bundle.
   foreach (field_info_fields() as $field_name => $field) {
-    if (in_array($field_name, $group_fields_name) && !empty($field['bundles'])) {
+    if (in_array($field_name, $og_fields_name) && !empty($field['bundles'])) {
       foreach ($field['bundles'] as $entity_type => $bundles) {
         foreach ($bundles as $bundle) {
           $field_enabled[$entity_type][$bundle][] = $field_name;
@@ -790,8 +968,8 @@ function og_ui_field_settings($form, &$form_state) {
         );
         foreach ($fields as $field_name) {
           $options[] = array(
-            check_plain($group_fields[$field_name]['instance']['label']),
-            filter_xss($group_fields[$field_name]['description']),
+            check_plain($og_fields[$field_name]['instance']['label']),
+            filter_xss($og_fields[$field_name]['description']),
             l(t('Delete'), "admin/config/group/fields/$entity_type/$bundle/$field_name/delete"),
           );
         }
@@ -819,34 +997,39 @@ function og_ui_field_settings($form, &$form_state) {
   return $form;
 }
 
+/**
+ * AJAX callback to to return the field name if the field supports "mulitple"
+ * instances, on the same bundle (e.g. OG_AUDIENCE_FIELD).
+ */
+function og_ui_admin_fields_ajax_callback($form, &$form_state) {
+  return $form['field_info_wrapper'];
+}
+
+/**
+ * Validate handler; Check if field can be attached to bundle.
+ */
 function og_ui_field_settings_validate($form, &$form_state) {
-  $bundle = preg_replace('/^.*__/i', '', $form_state['values']['bundles']);
-  $entity_type = str_replace('__' . $bundle, '', $form_state['values']['bundles']);
+  list($entity_type, $bundle) = explode(':', $form_state['values']['bundle']);
+  $field_name = $form_state['values']['field_name'];
 
-  // Check if field can be attached to entity.
-  $group_field = og_fields_info($form_state['values']['fields']);
+  $og_field = og_fields_info($form_state['values']['field_type']);
   $bundles = field_info_bundles($entity_type);
   $entity_info = entity_get_info($entity_type);
 
   $params = array(
-    '%field' => $group_field['instance']['label'],
+    '%field' => $og_field['instance']['label'],
     '%bundle' => $bundles[$bundle]['label'],
     '%entity' => $entity_info['label'],
   );
 
-  if ($form_state['values']['fields'] == OG_GROUP_FIELD && $entity_type == 'group') {
-    form_set_error('bundles', t('It is not allowed to add the group field to the group entity.'));
-  }
-
-  // Check if field doesn't exist already.
-  if (($field = field_info_field($form_state['values']['fields'])) && !empty($field['bundles'][$entity_type]) && in_array($bundle, drupal_map_assoc($field['bundles'][$entity_type]))) {
+  if (field_info_instance($entity_type, $field_name, $bundle)) {
     form_set_error('bundles', t('Field %field already exists in %bundle.', $params));
   }
 
   // Check field can be attached to entity type.
-  if (!empty($group_field['entity']) && !in_array($entity_type, $group_field['entity'])) {
+  if (!empty($og_field['entity']) && !in_array($entity_type, $og_field['entity'])) {
     $items = array();
-    foreach ($group_field['entity'] as $entity_type) {
+    foreach ($og_field['entity'] as $entity_type) {
       $info = entity_get_info($entity_type);
       $items[] = $info['label'];
     }
@@ -855,22 +1038,30 @@ function og_ui_field_settings_validate($form, &$form_state) {
 
 }
 
+/**
+ * Submit handler; Attach field can to bundle.
+ */
 function og_ui_field_settings_submit($form, &$form_state) {
-  $bundle = preg_replace('/^.*__/i', '', $form_state['values']['bundles']);
-  $entity_type = str_replace('__' . $bundle, '', $form_state['values']['bundles']);
-  $field_name = $form_state['values']['fields'];
+  list($entity_type, $bundle) = explode(':', $form_state['values']['bundle']);
+  $field_name = $form_state['values']['field_name'];
+  $field_type = $form_state['values']['field_type'];
 
-  og_create_field($field_name, $entity_type, $bundle);
+  $og_field = og_fields_info($field_type);
 
-  $group_field = og_fields_info($field_name);
-  $bundles = field_info_bundles($entity_type);
+  og_create_field($field_name, $entity_type, $bundle, $og_field);
 
   $params = array(
-    '%field' => $group_field['instance']['label'],
-    '%bundle' => $bundles[$bundle]['label'],
+    '@field-type' => $og_field['instance']['label'],
+    '@field-name' => $field_name,
+    '@bundle' => $bundle,
   );
 
-  drupal_set_message(t('Added field %field to %bundle.', $params));
+  if ($field_name == $field_type) {
+    drupal_set_message(t('Added field @field-type to @bundle.', $params));
+  }
+  else {
+    drupal_set_message(t('Added field @field-type (@field-name) to @bundle.', $params));
+  }
 }
 
 
diff --git a/sites/all/modules/og/og_ui/og_ui.info b/sites/all/modules/og/og_ui/og_ui.info
index c539790e77ffa2eb6ce6cc525a064f865f4930d0..4bf39f6daad4ccaf8e2f81e307f15554afd20096 100644
--- a/sites/all/modules/og/og_ui/og_ui.info
+++ b/sites/all/modules/og/og_ui/og_ui.info
@@ -16,9 +16,9 @@ files[] = includes/migrate/7000/add_field.inc
 files[] = includes/migrate/7000/populate_field.inc
 files[] = includes/migrate/7000/set_roles.inc
 
-; Information added by drupal.org packaging script on 2012-11-25
-version = "7.x-2.0-beta3+6-dev"
+; Information added by drupal.org packaging script on 2013-04-22
+version = "7.x-2.2"
 core = "7.x"
 project = "og"
-datestamp = "1353849566"
+datestamp = "1366630883"
 
diff --git a/sites/all/modules/og/og_ui/og_ui.module b/sites/all/modules/og/og_ui/og_ui.module
index 677ecb66dc496bf7ebf0abe80b4d8c41eabcd155..cb830a7838ba4ca29c1b7c4b0b5bc6ff75f3cd51 100644
--- a/sites/all/modules/og/og_ui/og_ui.module
+++ b/sites/all/modules/og/og_ui/og_ui.module
@@ -58,6 +58,18 @@ function og_ui_menu() {
     'file' => 'og_ui.admin.inc',
   );
 
+  // User listing pages.
+  $items['group/%/%/admin/people/edit-membership/%og_membership'] = array(
+    'title callback' => 'og_ui_menu_title_callback',
+    'title arguments' => array('Edit membership in group @group', 1, 2),
+    'type' => MENU_CALLBACK,
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('og_ui_edit_membership', 1, 2, 6),
+    'access callback' => 'og_ui_user_access_group',
+    'access arguments' => array('manage members', 1, 2),
+    'file' => 'og_ui.admin.inc',
+  );
+
   // Permission administration pages.
   $items['group/%/%/admin/roles'] = array(
     'title callback' => 'og_ui_menu_title_callback',
@@ -574,7 +586,7 @@ function og_ui_field_formatter_view($entity_type, $entity, $field, $instance, $l
         return;
       }
 
-      if (!empty($entity->uid) && ($entity->uid == $user->uid)) {
+      if (!empty($entity->uid) && ($entity->uid == $account->uid)) {
         // User is the group manager.
         $element[0] = array('#markup' => t('You are the group manager'));
         return $element;
@@ -595,7 +607,7 @@ function og_ui_field_formatter_view($entity_type, $entity, $field, $instance, $l
         }
 
         // Check if user can subscribe to the field.
-        if (empty($settings['field_name']) && $audience_field_name = og_get_best_group_audience_field('user', $user->uid, $entity_type, $bundle)) {
+        if (empty($settings['field_name']) && $audience_field_name = og_get_best_group_audience_field('user', $account, $entity_type, $bundle)) {
           $settings['field_name'] = $audience_field_name;
         }
         if (!$settings['field_name']) {
@@ -614,7 +626,7 @@ function og_ui_field_formatter_view($entity_type, $entity, $field, $instance, $l
           return;
         }
 
-        if (!og_check_field_cardinality('user', $user->uid, $settings['field_name'])) {
+        if (!og_check_field_cardinality('user', $account, $settings['field_name'])) {
           $element[0] = array('#markup' => format_plural($field_info['cardinality'], 'You are already registered to another group', 'You are already registered to @count groups'));
           return $element;
         }
@@ -668,6 +680,9 @@ function og_ui_field_formatter_view($entity_type, $entity, $field, $instance, $l
       $private = FALSE;
       $wrapper = entity_metadata_wrapper($entity_type, $entity);
       $field_name = $field['field_name'];
+      if (!$wrapper->{$field_name}->value()) {
+        return;
+      }
       if ($field['cardinality'] == 1) {
         // Single-value field.
         if ($wrapper->{$field_name}->entityAccess('view')) {
@@ -709,6 +724,10 @@ function og_ui_field_formatter_view($entity_type, $entity, $field, $instance, $l
             '#type' => 'link',
             '#title' => $wrapper->label(),
             '#href' => $wrapper->url->value(),
+            // Add the group type and group ID, so it's easier for implementing
+            // modules to extend the formatter.
+            '#group_type' => $group_type,
+            '#gid' => $wrapper->getIdentifier(),
           );
         }
       }
@@ -1123,6 +1142,14 @@ function og_ui_migrate_api() {
   if (db_table_exists('d6_og')) {
     $migrations['OgUiMigrateAddField'] = array('class_name' => 'OgUiMigrateAddField');
     $migrations['OgUiSetRoles'] = array('class_name' => 'OgUiSetRoles');
+
+    foreach (node_type_get_names() as $bundle => $value) {
+      $machine_name = 'OgUiPopulateField' . ucfirst($bundle);
+      $migrations[$machine_name] = array(
+        'class_name' => 'OgUiPopulateField',
+        'bundle' => $bundle,
+      );
+    }
   }
   $api = array(
     'api' => 2,
@@ -1130,23 +1157,3 @@ function og_ui_migrate_api() {
   );
   return $api;
 }
-
-/**
- * Implements hook_modules_enabled().
- *
- * Register dynamic migrate plugins for upgrading from OG6.
- */
-function og_ui_modules_enabled($modules) {
-  if (!db_table_exists('d6_og')) {
-    return;
-  }
-
-  if (!in_array('migrate', $modules) && !module_exists('migrate')) {
-    return;
-  }
-
-  foreach (node_type_get_names() as $bundle => $value) {
-    // Register dynamic migrations.
-    Migration::registerMigration('OgUiPopulateField', 'OgUiPopulateField' . ucfirst($bundle), array('bundle' => $bundle));
-  }
-}
diff --git a/sites/all/modules/og/og_ui/og_ui.pages.inc b/sites/all/modules/og/og_ui/og_ui.pages.inc
index c415a5d3165a11c1d510df7d8e1cb4df761c1250..db30d4f44a387b1c3f2abae4a00e4c22ed79b651 100644
--- a/sites/all/modules/og/og_ui/og_ui.pages.inc
+++ b/sites/all/modules/og/og_ui/og_ui.pages.inc
@@ -41,10 +41,11 @@ function og_ui_subscribe($entity_type, $etid, $field_name = NULL) {
     }
   }
 
-  $wrapper = entity_metadata_wrapper('user', $user->uid);
+  $field = field_info_field($field_name);
+  $instance = field_info_instance('user', $field_name, 'user');
+  $account = user_load($user->uid);
 
-  $field_info = field_info_field($field_name);
-  if (empty($field_info) || empty($wrapper->{$field_name}) || !$wrapper->{$field_name}->access('view')) {
+  if (empty($instance) || !field_access('view', $field, 'user', $account)) {
     // Field name given is incorrect, or user doesn't have access to the field.
     drupal_not_found();
     return;
@@ -63,6 +64,7 @@ function og_ui_subscribe($entity_type, $etid, $field_name = NULL) {
   }
 
   $redirect = FALSE;
+  $message = '';
 
   $params = array();
   $params['@user'] = format_username($user);
@@ -86,8 +88,24 @@ function og_ui_subscribe($entity_type, $etid, $field_name = NULL) {
     $redirect = TRUE;
   }
 
+  if (!$message && $field['cardinality'] != FIELD_CARDINALITY_UNLIMITED) {
+    // Check if user is already registered as active or pending in the maximum
+    // allowed values.
+    $wrapper = entity_metadata_wrapper('user', $account->uid);
+    if ($field['cardinality'] == 1) {
+      $count = $wrapper->{$field_name}->value() ? 1 : 0;
+    }
+    else {
+      $count = $wrapper->{$field_name}->count();
+    }
+    if ($count >= $field['cardinality']) {
+      $message = t('You cannot register to this group, as you have reached your maximum allowed subscriptions.');
+      $redirect = TRUE;
+    }
+  }
+
   if ($redirect) {
-    drupal_set_message($message);
+    drupal_set_message($message, 'warning');
     $url = entity_uri($entity_type, $entity);
     drupal_goto($url['path'], $url['options']);
   }
@@ -96,6 +114,7 @@ function og_ui_subscribe($entity_type, $etid, $field_name = NULL) {
     // Show the user a subscription confirmation.
     return drupal_get_form('og_ui_confirm_subscribe', $entity_type, $id, $user, $field_name);
   }
+  drupal_access_denied();
 }
 
 /**
@@ -211,4 +230,4 @@ function og_ui_confirm_unsubscribe_submit($form, &$form_state) {
   if (entity_access('view', $group_type, $group)) {
     $form_state['redirect'] = entity_uri($group_type, $group);
   }
-}
\ No newline at end of file
+}
diff --git a/sites/all/modules/og/og_ui/og_ui.test b/sites/all/modules/og/og_ui/og_ui.test
index 728b089a85d489ad5799f25bf5017ee25c1c313a..2198e8a1b33f22cbeb3833888fde204012079dae 100644
--- a/sites/all/modules/og/og_ui/og_ui.test
+++ b/sites/all/modules/og/og_ui/og_ui.test
@@ -298,10 +298,6 @@ class OgUiMigrate7000TestCase extends UpgradePathTestCase {
 
     module_enable(array('og_ui', 'migrate'));
 
-    Migration::registerMigration('OgMigrateAddFields');
-    Migration::registerMigration('OgUiMigrateAddField');
-    Migration::registerMigration('OgUiSetRoles');
-
     foreach (migrate_migrations() as $migration) {
       $machine_name = $migration->getMachineName();
       $result = $migration->processImport();
diff --git a/sites/all/modules/og/plugins/entityreference/behavior/OgBehaviorHandler.class.php b/sites/all/modules/og/plugins/entityreference/behavior/OgBehaviorHandler.class.php
index 9c1499b0566c3f33640054363b75b61b2023cfff..4d6780136d6769dae793f49ace5927e17d2667ae 100644
--- a/sites/all/modules/og/plugins/entityreference/behavior/OgBehaviorHandler.class.php
+++ b/sites/all/modules/og/plugins/entityreference/behavior/OgBehaviorHandler.class.php
@@ -9,7 +9,7 @@ class OgBehaviorHandler extends EntityReference_BehaviorHandler_Abstract {
    * Implements EntityReference_BehaviorHandler_Abstract::access().
    */
   public function access($field, $instance) {
-    return $field['settings']['handler'] == 'og';
+    return $field['settings']['handler'] == 'og' || strpos($field['settings']['handler'], 'og_') === 0;
   }
 
   /**
@@ -91,8 +91,7 @@ class OgBehaviorHandler extends EntityReference_BehaviorHandler_Abstract {
       // User has no access to field.
       return;
     }
-    $diff = $this->groupAudiencegetDiff($entity_type, $entity, $field, $instance, $langcode, $items);
-    if (!$diff) {
+    if (!$diff = $this->groupAudiencegetDiff($entity_type, $entity, $field, $instance, $langcode, $items)) {
       return;
     }
 
@@ -106,6 +105,21 @@ class OgBehaviorHandler extends EntityReference_BehaviorHandler_Abstract {
       og_membership_delete_multiple($diff['delete']);
     }
 
+    if (!$diff['insert']) {
+      return;
+    }
+
+    // Prepare an array with the membership state, if it was provided in the widget.
+    $states = array();
+    foreach ($items as $item) {
+      $gid = $item['target_id'];
+      if (empty($item['state']) || !in_array($gid, $diff['insert'])) {
+        // State isn't provided, or not an "insert" operation.
+        continue;
+      }
+      $states[$gid] = $item['state'];
+    }
+
     foreach ($diff['insert'] as $gid) {
       $values = array(
         'entity_type' => $entity_type,
@@ -113,6 +127,10 @@ class OgBehaviorHandler extends EntityReference_BehaviorHandler_Abstract {
         'field_name' => $field_name,
       );
 
+      if (!empty($states[$gid])) {
+        $values['state'] = $states[$gid];
+      }
+
       og_group($group_type, $gid, $values);
     }
   }
@@ -162,4 +180,51 @@ class OgBehaviorHandler extends EntityReference_BehaviorHandler_Abstract {
 
     return $return;
   }
+
+  /**
+   * Implements EntityReference_BehaviorHandler_Abstract::views_data_alter().
+   */
+  public function views_data_alter(&$data, $field) {
+    // We need to override the default EntityReference table settings when OG
+    // behavior is being used.
+    if (og_is_group_audience_field($field['field_name'])) {
+      $entity_types = array_keys($field['bundles']);
+      // We need to join the base table for the entities
+      // that this field is attached to.
+      foreach ($entity_types as $entity_type) {
+        $entity_info = entity_get_info($entity_type);
+        $data['og_membership'] = array(
+          'table' => array(
+            'join' => array(
+              $entity_info['base table'] => array(
+                // Join entity base table on its id field with left_field.
+                'left_field' => $entity_info['entity keys']['id'],
+                'field' => 'etid',
+                'extra' => array(
+                  0 => array(
+                    'field' => 'entity_type',
+                    'value' => $entity_type,
+                  ),
+                ),
+              ),
+            ),
+          ),
+          // Copy the original config from the table definition.
+          $field['field_name'] => $data['field_data_' . $field['field_name']][$field['field_name']],
+          $field['field_name'] . '_target_id' => $data['field_data_' . $field['field_name']][$field['field_name'] . '_target_id'],
+        );
+
+        // Change config with settings from og_membership table.
+        foreach (array('filter', 'argument', 'sort') as $op) {
+          $data['og_membership'][$field['field_name'] . '_target_id'][$op]['field'] = 'gid';
+          $data['og_membership'][$field['field_name'] . '_target_id'][$op]['table'] = 'og_membership';
+          unset($data['og_membership'][$field['field_name'] . '_target_id'][$op]['additional fields']);
+        }
+      }
+
+      // Get rid of the original table configs.
+      unset($data['field_data_' . $field['field_name']]);
+      unset($data['field_revision_' . $field['field_name']]);
+    }
+  }
 }
diff --git a/sites/all/modules/og/plugins/entityreference/behavior/OgWidgetHandler.class.php b/sites/all/modules/og/plugins/entityreference/behavior/OgWidgetHandler.class.php
index dcd04c33ce6532c427256d89f4985c5695bc3a06..85c2659d4de4692e3bf1329265835969fee8622a 100644
--- a/sites/all/modules/og/plugins/entityreference/behavior/OgWidgetHandler.class.php
+++ b/sites/all/modules/og/plugins/entityreference/behavior/OgWidgetHandler.class.php
@@ -6,7 +6,7 @@
 class OgWidgetHandler extends EntityReference_BehaviorHandler_Abstract {
 
   public function access($field, $instance) {
-    return $field['settings']['handler'] == 'og' && $instance['widget']['type'] == 'og_complex';
+    return ($field['settings']['handler'] == 'og' || strpos($field['settings']['handler'], 'og_') === 0) && $instance['widget']['type'] == 'og_complex';
   }
 
   /**
diff --git a/sites/all/modules/og/plugins/entityreference/selection/OgSelectionHandler.class.php b/sites/all/modules/og/plugins/entityreference/selection/OgSelectionHandler.class.php
index b84037e9af7c607cee8ec5039b88d9ddcc3eb61f..651f6402d02f0fe07cb6af6cce3b96e2194ec071 100644
--- a/sites/all/modules/og/plugins/entityreference/selection/OgSelectionHandler.class.php
+++ b/sites/all/modules/og/plugins/entityreference/selection/OgSelectionHandler.class.php
@@ -105,6 +105,10 @@ class OgSelectionHandler extends EntityReference_SelectionHandler_Generic {
 
     $field_mode = $this->instance['field_mode'];
     $user_groups = og_get_groups_by_user(NULL, $group_type);
+    $user_groups = $user_groups ? $user_groups : array();
+    $user_groups = array_merge($user_groups, $this->getGidsForCreate());
+
+
     // Show the user only the groups they belong to.
     if ($field_mode == 'default') {
       if ($user_groups && !empty($this->instance) && $this->instance['entity_type'] == 'node') {
@@ -165,4 +169,33 @@ class OgSelectionHandler extends EntityReference_SelectionHandler_Generic {
     // FIXME: Allow altering, after fixing http://drupal.org/node/1413108
     // $handler->entityFieldQueryAlter($query);
   }
+
+  /**
+   * Get group IDs from URL or OG-context, with access to create group-content.
+   *
+   * @return
+   *   Array with group IDs a user (member or non-member) is allowed to
+   * create, or empty array.
+   */
+  private function getGidsForCreate() {
+    if ($this->instance['entity_type'] != 'node') {
+      return array();
+    }
+
+    if (!module_exists('entityreference_prepopulate') || empty($this->instance['settings']['behaviors']['prepopulate'])) {
+      return array();
+    }
+
+    // Don't try to validate the IDs.
+    if (!$ids = entityreference_prepopulate_get_values($this->field, $this->instance, FALSE)) {
+      return array();
+    }
+    $node_type = $this->instance['bundle'];
+    foreach ($ids as $delta => $id) {
+      if (!is_numeric($id) || !$id || !og_user_access('node', $id, "create $node_type content")) {
+        unset($ids[$delta]);
+      }
+    }
+    return $ids;
+  }
 }
diff --git a/sites/all/modules/og/tests/og_test.info b/sites/all/modules/og/tests/og_test.info
index f82ddb3a9b4766f5eafe4e1d5f78fd7fddd5f559..e814e91816158c223415ec49259c2be0c8480747 100644
--- a/sites/all/modules/og/tests/og_test.info
+++ b/sites/all/modules/og/tests/og_test.info
@@ -4,9 +4,9 @@ core = 7.x
 dependencies[] = og
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2012-11-25
-version = "7.x-2.0-beta3+6-dev"
+; Information added by drupal.org packaging script on 2013-04-22
+version = "7.x-2.2"
 core = "7.x"
 project = "og"
-datestamp = "1353849566"
+datestamp = "1366630883"
 
diff --git a/sites/all/modules/og/tests/og_test.module b/sites/all/modules/og/tests/og_test.module
index 2908aada38176324b08126885e468cdc5dbc2354..0db5f3dce077cf2755c8d49cec70def5ca46fa8b 100644
--- a/sites/all/modules/og/tests/og_test.module
+++ b/sites/all/modules/og/tests/og_test.module
@@ -8,9 +8,84 @@
 /**
  * Implements hook_node_presave().
  */
-function og_node_presave($node) {
+function og_test_node_presave($node) {
   if (!empty($node->nid) && !empty($node->og_group_on_save)) {
     $values = $node->og_group_on_save;
     og_group($values['group_type'], $values['gid'], array('entity_type' => 'node', 'entity' => $node));
   }
 }
+
+/**
+ * Implements hook_module_implements_alter().
+ */
+function og_test_module_implements_alter(&$implementations, $hook) {
+  if ($hook != 'entity_delete') {
+    return;
+  }
+
+  // Switch the orders of the implementations.
+  $og = $implementations['og'];
+  $og_test = $implementations['og_test'];
+
+  unset($implementations['og'], $implementations['og_test']);
+
+  $implementations['og_test'] = $og_test;
+  $implementations['og'] = $og;
+}
+
+/**
+ * Implements hook_entity_delete().
+ */
+function og_test_entity_delete($entity, $type) {
+  if (!og_is_group($type, $entity) || $entity->title != 'move' ) {
+    return;
+  }
+
+  // The children nodes of the deleted group need another group to be associated
+  // with. Using entity field query for getting the NID of another group.
+  $query = new EntityFieldQuery();
+  $result = $query
+    ->entityCondition('entity_type', 'node')
+    ->propertyCondition('nid', $entity->nid, '<>')
+    ->execute();
+
+  if (empty($result['node'])) {
+    return;
+  }
+
+  $nid = reset(array_keys($result['node']));
+
+  $entity->og_orphans = array(
+    'move' => array(
+      'group_type' => 'node',
+      'gid' => $nid,
+    ),
+  );
+}
+
+/**
+ * Implements hook_form_alter().
+ *
+ * @see OgBehaviorHandlerTestCase::testSetStateOnInsert()
+ */
+function og_test_form_alter(&$form, $form_state) {
+  if (empty($form['#node_edit_form']) || $form['#bundle'] != 'behavior') {
+    return;
+  }
+
+  $form[OG_AUDIENCE_FIELD]['#element_validate'][] = 'og_test_form_behavior_validate';
+}
+
+/**
+ * Validate handler; Add state to the field values, if title is "state-pending".
+. */
+function og_test_form_behavior_validate($element, &$form_state) {
+  if ($form_state['values']['title'] != 'state-pending') {
+    return;
+  }
+
+  $value = $form_state['values'][OG_AUDIENCE_FIELD];
+  $value[LANGUAGE_NONE][0]['state'] = OG_STATE_PENDING;
+
+  form_set_value($element, $value, $form_state);
+}