diff --git a/includes/tree.inc b/includes/tree.inc
new file mode 100644
index 0000000..7639612
--- /dev/null
+++ b/includes/tree.inc
@@ -0,0 +1,143 @@
+<?php
+/**
+ * @file
+ *   Functions to generate and use the group hierarchy trees
+ */
+
+/**
+ * Get a hierarchy tree of all groups on the site
+ * 
+ * param $reset
+ *   TRUE if the tree should be regenerated. Default to FALSE.
+ */
+function og_subgroups_get_tree($reset = FALSE, $nested = FALSE) {
+  $cache_key = 'og_subgroups:tree';
+  $cache = cache_get($cache_key);
+  
+  // Check if our static cache hasn't yet been populated
+  // or if a reset has been requested
+  if ($reset || !isset($cache->data)) {
+  
+    // Search all top level group entities of each entities types
+    // Meanwhile http://drupal.org/node/1226622 issue is still open, we use db_select instead of EntityFieldQuery
+    $query1 = db_select('field_data_group_group', 'g')->fields('g', array('entity_id'));
+    $query1->join('field_data_group_audience', 'ga', 'ga.entity_id= g.entity_id AND ga.entity_type = g.entity_type');
+    $query1->where('g1.entity_id = g.entity_id');
+    $results = db_select('field_data_group_group', 'g1')->fields('g1', array('entity_id', 'entity_type'))->notExists($query1)->execute()->fetchAll();
+    
+    // Get the tree of each group entities found
+    if ($results)
+      foreach ($results as $result) {          
+        $result = og_get_hierarchy($result->entity_type, $result->entity_id, array('nested' => $nested, 'entity_type' => array($result->entity_type)));
+        if (isset($tree) && is_array($result)) $tree += $result; else $tree = $result;
+      }
+    
+    // Cache this tree in the database
+    cache_set($cache_key, $tree);
+  }
+  else {
+    $tree = $cache->data;
+  }
+  
+  return $tree;
+}
+
+/**
+ * Get hierarchy tree.
+ *
+ * @param $entity_type
+ * @param $etid
+ * @param $options
+ */
+function og_get_hierarchy($entity_type, $etid, $options = array(), &$tree = array(), $depth = 0) { 
+  $options += array(
+    'direction' => 'children',
+    'nested' => TRUE,
+    'sanitize' => TRUE,
+    'entity_type' => array(),
+  );
+
+  $wrapper = entity_metadata_wrapper($entity_type, $etid);
+    
+  if ($group = $wrapper->group->value()) {
+    $tree[$etid]->title = og_label($group->gid, $options['sanitize']);
+    $tree[$etid]->gid = $group->gid;
+    $tree[$etid]->etid = $etid;
+    $tree[$etid]->entity_type = $entity_type;
+    $tree[$etid]->parent = $depth;
+      
+    // Get the first group associated with the entity.
+    if ($options['direction'] == 'children') {
+      $query = db_select('field_data_group_audience', 'ga');
+      $query->fields('ga', array('entity_id', 'entity_type', 'bundle'));
+      if ($options['entity_type']) $query->condition('entity_type', $options['entity_type'], 'IN');
+      $query->condition('group_audience_gid', $group->gid);
+      $children_entity = $query->execute()->fetchAll();
+      if ($children_entity) {
+        foreach ($children_entity as $child_entity) {
+          if (og_is_group_type($child_entity->entity_type, $child_entity->bundle)) {
+            $childgroup = og_get_group($child_entity->entity_type, $child_entity->entity_id);
+            if ($options['nested']) {
+              $tree[$etid]->children[$childgroup->etid] = new stdClass();
+              if ($childgroup->etid <> $etid)
+                og_get_hierarchy($childgroup->entity_type, $childgroup->etid, $options, $tree[$etid]->children, $depth + 1);
+            } 
+            else {
+              $tree[$childgroup->etid] = new stdClass();
+              if ($childgroup->etid <> $etid)
+                og_get_hierarchy($childgroup->entity_type, $childgroup->etid, $options, $tree, $depth + 1);
+            }
+          }
+          else {
+            $info = entity_get_info($child_entity->entity_type);
+            $label = $info['label'];
+            if (isset($info['entity keys']['label'])) {
+              $entity = entity_load($child_entity->entity_type, array($child_entity->entity_id));
+              $label = current($entity)->{$info['entity keys']['label']};
+            }
+            if ($options['nested']) {
+              $tree[$etid]->children[$child_entity->entity_id]->title = $label;
+              $tree[$etid]->children[$child_entity->entity_id]->etid = $child_entity->entity_id;
+              $tree[$etid]->children[$child_entity->entity_id]->entity_type = $child_entity->entity_type;          
+              $tree[$etid]->children[$child_entity->entity_id]->parent = $depth + 1;          
+            }
+            else {
+              $tree[$child_entity->entity_id]->title = $label;
+              $tree[$child_entity->entity_id]->etid = $child_entity->entity_id;
+              $tree[$child_entity->entity_id]->entity_type = $child_entity->entity_type;          
+              $tree[$child_entity->entity_id]->parent = $depth + 1;          
+            }
+          }
+        }
+      }
+    }
+    elseif ($options['direction'] == 'parents') {
+
+      // Get the first group associated with the entity.
+      if (isset($wrapper->og_membership)) {
+        $nb_parents = count($wrapper->og_membership);
+        for ($i = 0;$i < $nb_parents; $i++) {
+          $parent = $wrapper->og_membership->get($i)->group->value();
+          if ($options['nested']) {
+            $tree[$etid]->parents[$parent->gid] = new stdClass();
+            if ($parent->etid <> $etid)
+              og_get_hierarchy($parent->entity_type, $parent->etid, $options, $tree[$group->gid]->parents, $depth - 1);
+          }
+          else {
+            $tree[$etid] = new stdClass();
+            if ($parent->etid <> $etid)      
+              og_get_hierarchy($parent->entity_type, $parent->etid, $options, $tree, $depth - 1);
+          }
+        }
+      }
+    }
+  }
+  else {
+    $tree[$etid]->title = og_label($group->gid, $options['sanitize']);
+    $tree[$etid]->etid = $etid;
+    $tree[$etid]->entity_type = $entity_type;
+    $tree[$etid]->parent = $depth;    
+  }
+
+  return $tree;
+}
diff --git a/modules/og_subgroups_views/includes/og_subgroups_views_handler_argument_etid.inc b/modules/og_subgroups_views/includes/og_subgroups_views_handler_argument_etid.inc
new file mode 100644
index 0000000..08a3f65
--- /dev/null
+++ b/modules/og_subgroups_views/includes/og_subgroups_views_handler_argument_etid.inc
@@ -0,0 +1,90 @@
+<?php
+/**
+ * @file
+ * Contains the numeric argument handler.
+ */
+
+/**
+ * This handle will retrieve other groups in the hierarchy from a entity ID
+ *
+ * @ingroup views_argument_handlers
+ */
+class og_subgroups_views_handler_argument_etid extends views_handler_argument_numeric {
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['build_directions'] = array('default' => array('children'));
+    $options['include_argument'] = array('default' => FALSE);
+
+    return $options;
+  }
+
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    // Remove unwanted options
+    unset($form['not']);
+
+    $form['build_directions'] = array(
+      '#type' => 'checkboxes',
+      '#title' => t('Build Direction'),
+      '#description' => t('Retrieve groups in the direction specified using the argument(s) as a starting point.'),
+      '#required' => TRUE,
+      '#options' => array(
+        'parents' => t('Parents'),
+        'children' => t('Children'),
+      ),
+      '#default_value' => $this->options['build_directions']
+    );
+
+    $form['include_argument'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Include the argument'),
+      '#description' => t('If selected, the group(s) specified in the argument(s) will be added to the output.'),
+      '#default_value' => $this->options['include_argument'],
+    );
+  }
+  
+  function get_subgroup_tree() {
+    $tree = array();
+    $directions = array_filter($this->options['build_directions']);
+    $arguments = explode(',', $this->argument);
+
+    // Get all group IDs that are in the argument's family
+    foreach ($arguments as $argument) {
+      foreach ($directions as $direction) {
+        // Fetch the entities
+        $entities = og_get_hierarchy('node', $entity->{$argument}, array('nested' => FALSE, 'entity_type' => array('node')));
+        
+        // Add the entities to an array
+        foreach ($entities as $entity) {
+          $tree[] = $entity->etid;
+        }
+      }
+    }
+    
+    return !empty($tree) ? $tree : array(-1);
+  }
+
+  function query() {
+    $this->ensure_my_table();
+
+    if (!empty($this->options['break_phrase'])) {
+      views_break_phrase($this->argument, $this);
+    }
+    else {
+      $this->value = array($this->argument);
+    }
+
+    $tree = $this->get_subgroup_tree();
+    $arguments = explode(',', $this->argument);
+
+    if ($this->options['include_argument']) {
+      $tree = array_merge($tree, $arguments);
+    }
+
+    $placeholders = implode(', ', array_fill(0, sizeof($tree), '%d'));
+    $base_table = $this->query->base_table;
+    $base_field = $this->query->base_field;
+    $this->query->add_where(0, "$base_table.$base_field IN ($placeholders)", $tree);
+  }
+}
diff --git a/modules/og_subgroups_views/includes/og_subgroups_views_handler_sort_hierarchy.inc b/modules/og_subgroups_views/includes/og_subgroups_views_handler_sort_hierarchy.inc
new file mode 100644
index 0000000..983f7b6
--- /dev/null
+++ b/modules/og_subgroups_views/includes/og_subgroups_views_handler_sort_hierarchy.inc
@@ -0,0 +1,32 @@
+<?php
+/**
+ * @file
+ * Sort by OG group audiences
+ */
+
+/**
+ * This handler will sort all content groups by their parents
+ * to retrieve the hierarchy
+ *
+ * @ingroup views_sort_handlers
+ */
+class og_subgroups_views_handler_sort_hierarchy extends views_handler_sort {
+  /**
+   * The sort cannot be exposed
+   */
+  function can_expose() { return FALSE; }
+
+  function query() {
+    $groups = og_subgroups_get_tree();
+
+    if (!empty($groups)) {
+      foreach ($groups as $group) $keys[] = $group->etid;      
+      $sort_order = implode(',', $keys);
+      $base_table = $this->query->base_table;
+      $base_field = $this->query->base_field;
+      $formula = "FIELD($base_table.$base_field, $sort_order)";
+
+      $this->query->add_orderby(NULL, $formula, $this->options['order'], '_' . $this->field);
+    }
+  }
+}
\ No newline at end of file
diff --git a/modules/og_subgroups_views/og_subgroups_views.info b/modules/og_subgroups_views/og_subgroups_views.info
new file mode 100644
index 0000000..58b88a0
--- /dev/null
+++ b/modules/og_subgroups_views/og_subgroups_views.info
@@ -0,0 +1,11 @@
+name = OG subgroups views integration
+description = "Views integration for subgroups"
+core = 7.x
+
+files[] = og_subgroups.module
+files[] = og_subgroups.views.inc
+files[] = includes/og_subgroups_views_handler_sort_hierarchy.inc
+
+package = Organic groups
+dependencies[] = views
+dependencies[] = og_subgroups
diff --git a/modules/og_subgroups_views/og_subgroups_views.module b/modules/og_subgroups_views/og_subgroups_views.module
new file mode 100644
index 0000000..638f98a
--- /dev/null
+++ b/modules/og_subgroups_views/og_subgroups_views.module
@@ -0,0 +1,16 @@
+<?php
+/**
+ * @file
+ * Declare module using Views 3
+ */
+
+/**
+ * Implementation of hook_views_api().
+ */
+function og_subgroups_views_views_api() {
+  return array(
+    'api' => 3,
+    'path' => drupal_get_path('module', 'og_subgroups_views'),
+  );
+}
+
diff --git a/modules/og_subgroups_views/og_subgroups_views.views.inc b/modules/og_subgroups_views/og_subgroups_views.views.inc
new file mode 100644
index 0000000..feb0d54
--- /dev/null
+++ b/modules/og_subgroups_views/og_subgroups_views.views.inc
@@ -0,0 +1,52 @@
+<?php
+/**
+ * @file
+ * Define all OG subgroups views
+ */
+
+/**
+* Implementation of hook_views_data() to register all of the basic handlers
+* views uses.
+*/
+function og_subgroups_views_views_data() {
+  $data['field_data_group_audience']['table']['group']  = t('OG subgroups');
+
+  $data['field_data_group_audience']['entity_id'] = array(
+    'title' => t('Entity id'),
+    'help' => t('Use the etid of a group content as a starting point to retrieve other groups in the hierarchy.'),
+    'argument' => array(
+      'handler' => 'og_subgroups_views_handler_argument_etid',
+    ),
+    'sort' => array(
+      'title' => t('Hierarchy order'),
+      'help' => t('Sort the group'),
+      'handler' => 'og_subgroups_views_handler_sort_hierarchy',
+    ),
+
+  );
+  
+  return $data;
+}
+
+
+/**
+ * Implementation of hook_views_handlers().
+ */
+function og_subgroups_views_views_handlers() {
+  return array(
+    'info' => array(
+        'path' => drupal_get_path('module', 'og_subgroups_views') . '/includes',
+    ),
+    'handlers' => array(
+      // arguments
+      'og_subgroups_views_handler_argument_etid' => array(
+        'parent' => 'views_handler_argument_numeric',
+      ),
+      // sorts
+      'og_subgroups_views_handler_sort_hierarchy' => array(
+        'parent' => 'views_handler_sort',
+      ),
+    ),
+  );
+}
+
diff --git a/og_subgroups.admin.inc b/og_subgroups.admin.inc
new file mode 100644
index 0000000..bff96e3
--- /dev/null
+++ b/og_subgroups.admin.inc
@@ -0,0 +1,108 @@
+<?php
+
+/**
+ * @file
+ *   Functions to define the administration of the module
+ */
+
+/**
+ * Menu callback for admin settings form
+ */
+function og_subgroups_settings($form, &$form_state) {
+  $form = array();
+  $option_group = array();
+  $option_group_content = array();  
+
+  // Group content selection
+  $form['entity_types'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Enable subgroups for group contents'),
+    '#description' => t('Select which available group contents can have subgroups enabled. If a certain group content already has subgroups and you deselect it, it will not remove the hierarchy of those entities. They must be manually edited.'),
+  );
+  foreach (entity_get_info() as $entity_type => $entity) {
+    // TODO : For the time being, OG group only works with nodes, check node_access_acquire_grants() and hook_node_access_records_alter()
+    if ($entity_type == 'node')
+      foreach ($entity['bundles'] as $bundle_name => $bundle) {
+        if (og_is_group_content_type($entity_type, $bundle_name)) {
+          $option_group_content[$entity_type . '|' . $bundle_name] = $bundle['label'];
+        }
+      }
+  }
+  if ($option_group_content) {
+    $form['entity_types']["og_subgroups_group_content_enabled"] = array(
+      '#type' => 'checkboxes',
+      '#title' => 'Groupe content',
+      '#options' => $option_group_content,
+      '#default_value' => variable_get("og_subgroups_group_content_enabled", array()),
+      '#ajax' => array(
+        'callback' => 'og_subgroups_ajax_propagate_content_callback',
+        'wrapper' => 'propagate-content-div',
+        'method' => 'replace',
+        'effect' => 'fade',
+      ),
+    );
+  }  
+
+  // Default group posts propagation for each group contents
+  $form['propagate_content'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Group contents propagation'),
+    '#description' => t('Content can be propagated through the subgroups tree.'),
+    '#collapsible' => TRUE,
+    '#prefix' => '<div id="propagate-content-div">',
+    '#suffix' => '</div>',
+  );
+  $group_contents_selected = !empty($form_state['values']['og_subgroups_group_content_enabled']) ? $form_state['values']['og_subgroups_group_content_enabled'] : variable_get("og_subgroups_group_content_enabled", array());
+  if ($group_contents_selected)
+    foreach ($group_contents_selected as $keygroup_content => $group_content) {
+      if ($group_content <> '0') {
+        $entity_bundle = explode("|", $keygroup_content);
+      
+        $form['propagate_content']['og_subgroups_propagate_content_' . $keygroup_content] = array(
+          '#type' => 'checkboxes',
+          '#title' => t('Default content propagation for ' . $entity_bundle[0] . ' entity "' . $entity_bundle[1] . '" type.'),
+          '#description' => t('Determine the propagation path content will take if posted inside a group. For example, if children is selected, a post inside a group will also be propagated to all the children, so the entity appears in those groups too.'),
+          '#options' => array(
+            'parents' => t('Parents'),
+            'children' => t('Children'),
+          ),
+          '#default_value' => variable_get('og_subgroups_propagate_content_' . $keygroup_content, array()),
+        );      
+        $form['propagate_content']['og_subgroups_rebuild_access_' . $keygroup_content] = array(
+          '#type' => 'checkbox',
+          '#title' => t('Rebuild access for all ' . $entity_bundle[0] . ' entity "' . $entity_bundle[1] . '" type.'),
+        );      
+      }
+      else {
+        variable_set('og_subgroups_propagate_content_' . $keygroup_content, array());
+      }
+    }
+  $form['#submit'][] = 'og_subgroups_settings_submit';  
+
+  return system_settings_form($form);
+}
+
+/**
+ * Ajax callback for group content selection
+ */
+function og_subgroups_ajax_propagate_content_callback($form, $form_state) {
+  return $form['propagate_content'];
+}
+
+/**
+ * Rebuild access for all entity bundles selected
+ */
+function og_subgroups_settings_submit($form, $form_state) {
+  foreach ($form_state['values']['og_subgroups_group_content_enabled'] as $element)
+    if ($element <> '0' && isset($form_state['values']['og_subgroups_propagate_content_' . $element]) && isset($form_state['values']['og_subgroups_rebuild_access_' . $element]) && $form_state['values']['og_subgroups_rebuild_access_' . $element] == 1) {
+      $entity_bundle = explode("|", $element);
+      variable_set('og_subgroups_propagate_content_' . $entity_bundle[0] . '|' . $entity_bundle[1], $form_state['values']['og_subgroups_propagate_content_' . $element]);
+      $result = db_query("SELECT nid FROM {node} WHERE type = '" . $entity_bundle[1] . "'");
+      $records = $result->fetchAll();
+      foreach ($records as $record) {
+        $node = node_load($record->nid);
+        node_save($node);
+      }
+      //og_subgroups_node_access_rebuild($entity_bundle[1]);
+    }
+}
\ No newline at end of file
diff --git a/og_subgroups.info b/og_subgroups.info
old mode 100755
new mode 100644
index d2e8e93..7b5ed5e
--- a/og_subgroups.info
+++ b/og_subgroups.info
@@ -3,9 +3,7 @@ name = Organic groups subgroups
 description = "Enable the permission system to be aware of the group hierarchy."
 package = "Organic groups"
 dependencies[] = og
+dependencies[] = og_ui
 core = 7.x
 version = VERSION
-files[] = og_subgroups.module
-
-; Test files.
-files[] = og_subgroups.test
\ No newline at end of file
+files[] = includes/tree.inc
\ No newline at end of file
diff --git a/og_subgroups.install b/og_subgroups.install
new file mode 100644
index 0000000..ea1dfb8
--- /dev/null
+++ b/og_subgroups.install
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * @file
+ *   Functions that will clean the module when uninstall
+ */
+
+/**
+ * Implements hook_uninstall().
+ *
+ * @ingroup og_subgroup
+ */
+function og_subgroups_uninstall() {
+  // Delete all instances of the field, their data, and the field itself.
+  field_delete_field('group_subgroup');
+  
+  // Delete all instances of the field, their data, and the field itself.
+  if (variable_get("og_subgroups_group_content_enabled", array())) {
+    foreach (variable_get("og_subgroups_group_content_enabled", array()) as $k => $v)    
+      variable_del("og_subgroups_propagate_content_" . $k);
+    variable_del("og_subgroups_group_content_enabled");
+  }
+
+  // Purge all field information
+  field_purge_batch(2000);
+}
diff --git a/og_subgroups.module b/og_subgroups.module
old mode 100755
new mode 100644
index f55ba1b..e3f0af2
--- a/og_subgroups.module
+++ b/og_subgroups.module
@@ -1,23 +1,144 @@
 <?php
 
+define('OG_SUBGROUP_DIRECTION', 'group_subgroup_direction');
+
+module_load_include('inc', 'og_subgroups', 'includes/tree');
+
 /**
- * @file
- * Enable defining hierarchy of groups for organic groups.
+ * Implementation of hook_permission().
  */
+function og_subgroups_permission() {
+  return array(
+    'administer groups hierarchy' => array(
+      'title' => t('Administer groups hierarchy'),
+      'description' => t('Maintains a hierarchy of groups created by the orgainc groups module')
+    ),
+  );
+}
 
 /**
- * Implementation of hook_ctools_plugin_directory().
+ * Implementation of hook_menu().
  */
-function og_subgroups_ctools_plugin_directory($module, $plugin) {
-  // Safety: go away if CTools is not at an appropriate version.
-  if (!module_invoke('ctools', 'api_version', OG_REQUIRED_CTOOLS_API)) {
-    return;
+function og_subgroups_menu() {
+  $items['admin/config/group/subgroups'] = array(
+    'title' => 'Organic groups subgroups configuration',
+    'description' => 'Enable and configure groups to be posted inside groups',
+    'page callback' => 'drupal_get_form', 
+    'page arguments' => array('og_subgroups_settings'),
+    'access arguments' => array('Administer groups hierarchy'),
+    'weight' => 0,
+    'file' => 'og_subgroups.admin.inc',
+  );
+  $items['admin/config/group/subgroups/settings'] = array(
+    'title' => 'Settings',
+    'weight' => 0,
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+  );
+
+  return $items;
+}
+
+/**
+ * Implements hook_og_fields_info().
+ */
+function og_subgroups_og_fields_info() {
+  $items[OG_SUBGROUP_DIRECTION] = array(
+    'type' => array('group content'),
+    'description' => t('Determine the subgroups content behaviour'),
+    'field' => array(
+      'field_name' => OG_SUBGROUP_DIRECTION,
+      'no_ui' => TRUE,
+      'type' => 'list_text',
+      'cardinality' => -1,
+      'settings' => array(
+        'allowed_values' => array('children' => 'children', 'parents' => 'parents'),
+        'allowed_values_function' => '',
+      ),
+    ),
+    'instance' => array(
+      'label' => t('Subgroup behaviour'),
+      'widget_type' => 'options_buttons',
+      'required' => FALSE,
+      'view modes' => array(
+        'full' => array(
+          'label' => t('Full'),
+          'type' => 'og_group_subscribe',
+          'custom settings' => FALSE,
+        ),
+        'teaser' => array(
+          'label' => t('Teaser'),
+          'type' => 'og_group_subscribe',
+          'custom settings' => FALSE,
+        ),
+      ),
+    ),
+  );
+
+  return $items;
+}
+
+/**
+ * Check if a user has access permission in one of the children groups
+ * and return the tree structure of the group hierarchy.
+ *
+ * @param $entity_groups
+ *    Array of group id to check and start moving up in the hierarchy.
+ * @param $account
+ *    Optional; The account to check
+ * @param $string
+ *    Optional; The permission string, if empty return the full tree structure in
+ *    $structure, otherwise stops when the permission is grant.
+ * @param $structure
+ *     Optional; This is the array that you should send by refeference to get back
+ *     all the tree structure of the given groups.
+ *    Array contain 2 keys ['gid'] - group id, and ['level'] the depth of the
+ *    parent.
+ * @param $level
+ *     Optional; Level of tree to start counting from, normally there is no need
+ *    to change this. Default to 0 being the entity given.
+ *
+ *  @return
+ *    TRUE if user has access grant with the given perm to one of the enstertors
+ *    groups.
+ */
+function og_subgroups_get_hierarchy_tree_perm($entity_groups, $string = '', $account = NULL, &$structure = array(), $level = 0) {
+  
+  // Check if user has the permission in children group.
+  foreach ($entity_groups as $gid) {
+
+    // Save the hierarchy structure.
+    $structure[$gid] = array();
+    $structure[$gid]['gid'] = $gid;
+    $structure[$gid]['level'] = $level;
+
+    // Check access permission.
+    if ($string) {
+      if (og_user_access($gid, $string, $account, TRUE)) {
+        return TRUE;
+      }
+    }
   }
 
-  if ($module == 'ctools') {
-    return 'plugins/' . $plugin;
+  // Get all groups that are content of user_groups (as an array of group ids).
+  $children_groups = array();  
+  foreach ($entity_groups as $gid) {
+
+    // Get all groups that are associated with passed group.
+    $group = og_load($gid);
+    $group_entity = og_load_entity_from_group($group->gid);
+    $children = og_subgroups_get_all_subgroups($group->entity_type, $group_entity->type, $group->gid);
+    if ($children)
+      foreach ($children as $child)
+        if ($gid != $child) $children_groups[] = $child;
   }
+  if ($children_groups)
+    // Recurssion call of the function.
+    return og_subgroups_get_hierarchy_tree_perm($children_groups, $string, $account, $structure, --$level);
+  else
+    // Reached a dead end, return false.
+    return FALSE;
 }
+
 /**
  * Check if a user has access permission in one of the ancestors groups
  * and return the tree structure of the group hierarchy.
@@ -42,19 +163,16 @@ function og_subgroups_ctools_plugin_directory($module, $plugin) {
  *    TRUE if user has access grant with the given perm to one of the enstertors
  *    groups.
  */
-function og_subgroups_get_reverse_hierarchy_tree_perm($entity_groups, $string = '', $account = NULL, &$structure = array(), &$graph = FALSE , $level = 0) {
+function og_subgroups_get_reverse_hierarchy_tree_perm($entity_groups, $string = '', $account = NULL, &$structure = array(), $level = 0) {
+  
   // Check if user has the permission in a parent group.
-  foreach($entity_groups as $gid) {
+  foreach ($entity_groups as $gid) {
+
     // Save the hierarchy structure.
     $structure[$gid] = array();
     $structure[$gid]['gid'] = $gid;
     $structure[$gid]['level'] = $level;
 
-    // Build a graph with graph api
-    if (is_array($graph) && module_exists('graphapi')) {
-      $group = og_load($gid);
-      graphapi_set_node_title($graph, $gid,  $group->label);
-    }
     // Check access permission.
     if ($string) {
       if (og_user_access($gid, $string, $account, TRUE)) {
@@ -62,44 +180,27 @@ function og_subgroups_get_reverse_hierarchy_tree_perm($entity_groups, $string =
       }
     }
   }
+
   // Get all groups that are content of user_groups (as an array of group ids).
   $groups = og_load_multiple($entity_groups);
   $parent_groups = array();
   foreach ($groups as $group) {
+
     // Load the entity associated with the group.
     $entity = og_load_entity_from_group($group->gid);
+
     // Get all groups that are associated with passed group.
     $parents = og_get_entity_groups($group->entity_type, $entity);
     $parent_groups += $parents;
-    // Build a graph path with graph api
-    if (is_array($graph) && module_exists('graphapi')) {
-      foreach ($parents as $parent) {
-        graphapi_set_node_title($graph, $parent,  $parent);
-        graphapi_set_link_data($graph, $group->gid, $parent, array('color' => '#018FE2'));
-      }
-    }
   }
-  if ($parent_groups) {
+  if ($parent_groups && !array_intersect_key($structure, $parent_groups))
     // Recurssion call of the function.
-    return og_subgroups_get_reverse_hierarchy_tree_perm($parent_groups, $string, $account, $structure, $graph, ++$level);
-  }
-  else {
+    return og_subgroups_get_reverse_hierarchy_tree_perm($parent_groups, $string, $account, $structure, ++$level);
+  else
     // Reached a dead end, return false.
     return FALSE;
-  }
-}
-
-/**
- * Implements hook_og_user_access_alter()
- */
-function og_subgroups_og_user_access_alter(&$perm, $context) {
-  // Update the permission for a user that tries to access a sub group.
-  // This gives to any users his og group permission to all his subgroups,
-  // without the -need for him to be a member in the groups.
-  $perm[$context['string']] = og_subgroups_get_reverse_hierarchy_tree_perm(array($context['group']->gid),  $context['string'], $context['account']);
 }
 
-
 /**
  * Implements hook_node_access_records_alter().
  *
@@ -108,22 +209,27 @@ function og_subgroups_og_user_access_alter(&$perm, $context) {
  * groups.
  */
 function og_subgroups_node_access_records_alter(&$grants, $node) {
+
   // Relevant only for private groups.
   if (module_exists('og_access')) {
+
     // The group IDs, that in case access is granted, will be recorded.
     $gids = array();
     $private = FALSE;
     $groups = array();
+
     // Dealing with a node group that is private.
     if (!empty($node->{OG_ACCESS_FIELD}[LANGUAGE_NONE][0]['value'])) {
-      $group = og_get_group('node', $node->nid);
+      $group = og_get_group('node', $node->nid);      
       if ($group) {
         $groups[] = $group->gid;
         $private = TRUE;
       }
     }
+
     // Dealing with a group content.
     elseif (isset($node->{OG_CONTENT_ACCESS_FIELD}[LANGUAGE_NONE][0]['value'])) {
+
       // If no groups with og realm are defined, this means it's a public group
       //  then do nothing, otherwise treat as a private group.
       if (($node->{OG_CONTENT_ACCESS_FIELD}[LANGUAGE_NONE][0]['value'] == OG_CONTENT_ACCESS_PRIVATE) ||
@@ -131,19 +237,32 @@ function og_subgroups_node_access_records_alter(&$grants, $node) {
         $groups = og_get_entity_groups('node', $node);
         $private = TRUE;
       }
-    }
+    }    
+
+    // Get node behaviour
+    $subgroup_behaviour = variable_get('og_subgroups_propagate_content_node|' . $node->type, array());
+    if (isset($node->{OG_SUBGROUP_DIRECTION}[LANGUAGE_NONE]) && count($node->{OG_SUBGROUP_DIRECTION}[LANGUAGE_NONE]) > 0 && $subgroup_behaviour)
+      foreach ($node->{OG_SUBGROUP_DIRECTION}[LANGUAGE_NONE] as $value)
+        $subgroup_behaviour[$value['value']] = $value['value'];      
+
     // If group is private, then grant permissions for parent groups.
-    if ($private) {
-      og_subgroups_get_reverse_hierarchy_tree_perm($groups, '', NULL, $gids);
+    if ($private) {    
+
+      // Get all parents or children depending the chosen behaviour
+      $gids_children = array();
+      if (isset($subgroup_behaviour['children']) && $subgroup_behaviour['children'] != '0') og_subgroups_get_hierarchy_tree_perm($groups, '', NULL, $gids_children);
+      $gids_parents = array();
+      if (isset($subgroup_behaviour['parents']) && $subgroup_behaviour['parents'] != '0') og_subgroups_get_reverse_hierarchy_tree_perm($groups, '', NULL, $gids_parents);      
+      $gids = $gids_children + $gids_parents;      
+
       // Check existing grant and remove from gids[], to avoid duplication.
-      foreach ($grants as $granted) {
-        if (isset($gids[$granted['gid']])) {
+      foreach ($grants as $granted)
+        if (isset($gids[$granted['gid']]))
           unset($gids[$granted['gid']]);
-        }
-      }
+          
       // Build the new access Grant array.
-      foreach ($gids as $gid) {
-        $grants[] = array (
+      foreach ($gids as $gid)
+        $grants[] = array(
         'realm' => OG_ACCESS_AUTHENTICATED_REALM,
         'gid' => $gid['gid'],
         'grant_view' => 1,
@@ -151,12 +270,23 @@ function og_subgroups_node_access_records_alter(&$grants, $node) {
         'grant_delete' => 0,
         'priority' => 0,
         );
-      }
     }
   }
 }
 
 /**
+ * Rebuild all node access
+ */
+function og_subgroups_node_access_rebuild($nodetype) {
+  $nids = db_select('node', 'n')->fields('n', array('nid'))->condition('type', $nodetype)->execute()->fetchAll();
+  foreach ($nids as $nid) {
+    $node = node_load($nid->nid, NULL, TRUE);
+    if (!empty($node))
+      node_access_acquire_grants($node);
+  }
+}
+
+/**
  * Return TRUE if $grants contain an OG realm
  */
 function og_subgroups_grants_has_og_realm($grants) {
@@ -165,43 +295,30 @@ function og_subgroups_grants_has_og_realm($grants) {
       return TRUE;
     }
   }
+
   return FALSE;
 }
 
 /**
- * Get hierarchy tree.
+ * Get all content groups related to a group
  *
- * @param $entity_type
- * @param $etid
- * @param $options
+ * @param $gid
  */
-function og_get_hierarchy($entity_type, $etid, $options = array(), &$tree = array(), $depth = 0) {
-  $options += array(
-    'direction' => 'up',
-    'type' => 'single',
-    'sanitize' => TRUE,
-  );
-
-  $wrapper = entity_metadata_wrapper($entity_type, $etid);
+function og_subgroups_get_all_subgroups($entity_type, $bundle_name, $gid) {
+  $group_ids = NULL;
 
-  if ($depth == 0 && $group = $wrapper->group->value()) {
-    if ($options['type'] == 'single') {
-      $tree[$group->gid] = og_label($group->gid, $options['sanitize']);
-    }
-    else {
-      $tree[$depth][$group->gid] = og_label($group->gid, $options['sanitize']);
-    }
-  }
+  // Get all group content entities
+  $query = new EntityFieldQuery();
+  $entities = $query->entityCondition('entity_type', $entity_type)
+                    ->entityCondition('bundle', $bundle_name)
+                    ->propertyCondition('status', 1)                    
+                    ->fieldCondition('group_audience', 'gid', $gid, '=')
+                    ->execute();  
 
-  if ($options['direction'] == 'up' && $options['type'] == 'single') {
-    $group = FALSE;
-    // Get the first group associated with the entity.
-    if ($wrapper->og_membership->get(0)->value()) {
-      $group = $wrapper->og_membership->get(0)->group->value();
-      $tree[$group->gid] = og_label($group->gid, $options['sanitize']);
-      og_get_hierarchy($group->entity_type, $group->etid, $options, $tree, $depth + 1);
-    }
-  }
+  // Fetch the gid of each entities found
+  if (isset($entities['node']))
+    $group_ids = og_get_group_ids($entity_type, array_keys($entities['node']));
 
-  return $tree;
+  return $group_ids;  
 }
+
diff --git a/og_subgroups.test b/og_subgroups.test
deleted file mode 100644
index 31129d4..0000000
--- a/og_subgroups.test
+++ /dev/null
@@ -1,186 +0,0 @@
-<?php
-// $Id$
-
-/**
- * Test the Organic groups subgroups API.
- */
-class OgSubgroupsAccessFromDescendanceTestCase extends DrupalWebTestCase {
-  public static function getInfo() {
-    return array(
-      'name' => 'Organic groups Subgroups permissions inheritance',
-      'description' => 'Test the access of users to subgroups.',
-      'group' => 'Organic groups subgroups'
-    );
-  }
-
-  function setUp() {
-    parent::setUp('og_subgroups', 'entity_test','og_access');
-    // Add OG group field to the entity_test's "main" bundle.
-    og_create_field(OG_GROUP_FIELD, 'entity_test', 'main');
-    og_create_field(OG_AUDIENCE_FIELD, 'entity_test', 'main');
-    og_create_field(OG_AUDIENCE_FIELD, 'article', 'main');
-  }
-  
-  
-
-  /**
-   * Use cases:
-   * - Check that parent user has access to all permission he has on groups he 
-   * is not memberof but that are descandents of his group
-   */
-  function testOgSubgroupsGetReverseHierarchyTreePerm() {
-    // Create user.
-    $user1 = $this->drupalCreateUser();
-    $user2 = $this->drupalCreateUser();
-    $user3 = $this->drupalCreateUser();
-    $user4 = $this->drupalCreateUser();
-    $web_user = $this->drupalCreateUser(array('create article content', 'create page content'));
-    $this->drupalLogin($web_user);
-    
-    $groups = array();
-
-    // Create an entity that is a group.
-    $entity = entity_create('entity_test', array('name' => 'main', 'uid' => $user1->uid));
-    $entity->{OG_GROUP_FIELD}[LANGUAGE_NONE][0]['value'] = 1;
-    $entity->save();
-    $groups[0] = og_get_group('entity_test', $entity->pid);
-    
-   // Create a private entity group that is a child group of the group above.
-    $entity = entity_create('entity_test', array('name' => 'first_child', 'uid' => $user2->uid));
-    $entity->{OG_GROUP_FIELD}[LANGUAGE_NONE][0]['value'] = 1;
-    $entity->{OG_AUDIENCE_FIELD}[LANGUAGE_NONE][0]['gid'] =  $groups[0]->gid;
-    $entity->save();
-    $groups[1] = og_get_group('entity_test', $entity->pid);
-    
-    // Create an entity that is a child group of the group above.
-    $entity = entity_create('entity_test', array('name' => 'second_child', 'uid' => $user3->uid));
-    $entity->{OG_GROUP_FIELD}[LANGUAGE_NONE][0]['value'] = 1;
-    $entity->{OG_AUDIENCE_FIELD}[LANGUAGE_NONE][0]['gid'] =  $groups[1]->gid;
-    $entity->save();
-    $groups[2] = og_get_group('entity_test', $entity->pid);
-    
-    // Create an entity that is a group content of group ID 2.
-  
-    $node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1));
-    $node->{OG_AUDIENCE_FIELD}[LANGUAGE_NONE][0]['gid'] = $groups[2]->gid;
-    node_save($node);    
-    $groups[3] = $node;
-    
-    $group_content[0] = $entity;
-
-    // Associate user4 to the group[2].
-    og_group($group[2]->gid, 'user', $user4);
-
-    // Assert the user is registered to the new group.
-    $string = 'administer group';
-    // Check user1 has adminster perm on parent group [0]
-    debug($groups);
-    $this->assertTrue(og_user_access($groups[0]->gid, $string, $user1, TRUE) , t('User1 have admister group permission to parent group 0'));
-    // Check user has admin perm on sub group that is he not member of.
-    $access_res = og_subgroups_get_reverse_hierarchy_tree_perm(array($groups[2]->gid), $string, $user1);
-    $this->assertTrue($access_res, t('User1 have admister group permission to subgroup 2'));
-
-    // Check permission.
-    $this->assertFalse(og_user_access($groups[0]->gid, $string, $user3), t('User3 does not have "Administer group" permission.'));
-    // Check user3 has no adminster perm on parent group [0]
-    $access_res = og_subgroups_get_reverse_hierarchy_tree_perm(array($groups[0]->gid), $string, $user1);
-    $this->assertFalse($access_res, t('User3 does not have admister group permission to group 0'));
-
-    // Change permissions to authenticated member.
-    //$roles = array_flip(og_get_global_roles());
-    // Authenticated role ID.
-   // $rid = $roles[OG_AUTHENTICATED_ROLE];
-
-   // $permissions = array(
-  //    'delete own article content' => 1,
-  ///    'administer group' => 1,
-  //  );
-  //  og_role_change_permissions($rid, $permissions);
-
-    // Verify proper permission changes.
-   // $this->assertFalse(og_user_access($group->gid, 'update own article content', $user2), t('User still does not have "update own article content" permission.'));
-   // $this->assertTrue(og_user_access($group->gid, 'delete own article content', $user2), t('User now has "delete own article content" permission.'));
-  //  $this->assertTrue(og_user_access($group->gid, 'administer group', $user2), t('User now has "administer group" permission.'));
-
-   // $permissions = array(
-   //   'delete own article content' => 1,
-   //   'administer group' => 0,
-  //  );
- //  og_role_change_permissions($rid, $permissions);
-
-  //  $this->assertTrue(og_user_access($group->gid, 'delete own article content', $user2), t('User still has "delete own article content" permission.'));
-  //  $this->assertFalse(og_user_access($group->gid, 'administer group', $user2), t('User no longer has "administer group" permission.'));
-
-  }
-  
-  
-  /**
-   * Test the view access of child node.
-   * Use cases:
-   * 1. grand parent group user tries to view private child groups node (with default
-   *  access), that he is not part of.
-   * 2. Anonymous user tries to view private child groups node (with public
-   *  access).
-   * 
-   */
-  function testOgSubgroupsNodeAccessRecordsAlter() {
-    // Create user.
-    $user1 = $this->drupalCreateUser();
-    $user2 = $this->drupalCreateUser();
-    $user3 = $this->drupalCreateUser();
-    $user4 = $this->drupalCreateUser();
-    $web_user = $this->drupalCreateUser(array('create article content', 'create page content'));
-    $this->drupalLogin($web_user);
-    
-    $groups = array();
-
-    // Create an entity that is a group.
-    $entity = entity_create('entity_test', array('name' => 'main', 'uid' => $user1->uid));
-    $entity->{OG_GROUP_FIELD}[LANGUAGE_NONE][0]['value'] = 1;
-    $entity->save();
-    $groups[0]['group'] = og_get_group('entity_test', $entity->pid);
-    $groups[0]['entity'] = $entity;
-    
-   // Create an entity that is a child group of the group above (0).
-    $entity = entity_create('entity_test', array('name' => 'first_child', 'uid' => $user2->uid));
-    $entity->{OG_GROUP_FIELD}[LANGUAGE_NONE][0]['value'] = 1;
-    $entity->{OG_AUDIENCE_FIELD}[LANGUAGE_NONE][0]['gid'] =  $groups[0]['group']->gid;
-    $entity->save();
-    $groups[1]['group'] = og_get_group('entity_test', $entity->pid);
-    $groups[1]['entity'] = $entity;
-    
-    // Create a private entity group that is a child group of the group above. (1).
-    $entity = entity_create('entity_test', array('name' => 'second_child', 'uid' => $user3->uid));
-    $entity->{OG_GROUP_FIELD}[LANGUAGE_NONE][0]['value'] = 1;
-    $entity->{OG_AUDIENCE_FIELD}[LANGUAGE_NONE][0]['gid'] =  $groups[1]['group']->gid;
-    $entity->{OG_ACCESS_FIELD}[LANGUAGE_NONE][0]['gid'] =  1;
-    $entity->save();
-    $groups[2]['group'] = og_get_group('entity_test', $entity->pid);
-    $groups[2]['entity'] = $entity;
-    
-    // Create an entity that is a group content of group ID 2.
-    $node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1));
-    $node->{OG_AUDIENCE_FIELD}[LANGUAGE_NONE][0]['gid'] = $groups[2]['group']->gid;
-    node_save($node); 
-    $groups[3]['node'] = $node;
-    
-    
-
-    $this->drupalLogout();
-    // Assert the anonymous can't view the node.
-    $this->drupalGet('node/' . $groups[3]['node']->nid);
-    $this->assertResponse('403', t('Annonymous cannot view private node.'));
-    
-    $this->drupalLogin($user4);
-    $this->drupalGet('node/' . $groups[3]['node']->nid);
-    $this->assertResponse('403', t('Not group member or parrent cannot view private node.'));
-    
-
-    // Assert another user is not a group member.
-    $this->drupalLogin($user1);
-    $this->drupalGet('node/' . $groups[3]['node']->nid);
-    $this->assertResponse('200', t('Parent group user can view the node'));
-
-  }
-  
-}
diff --git a/plugins/content_types/graph/graph.inc b/plugins/content_types/graph/graph.inc
deleted file mode 100755
index 94dfb16..0000000
--- a/plugins/content_types/graph/graph.inc
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php
-
-/**
- * Plugin defenition
- */
-if (module_exists('graphapi')) {
-  $plugin = array (
-    'title' => t('OG Group hierarchy graph'),
-    'description' => t('Display a graph of group hierarchy starting from a given group.'),
-    'required context' => new ctools_context_required(t('Group'), 'entity:group'),
-    'category' => t('OG subrgoups'),
-  );
-}
-
-function og_subgroups_graph_content_type_render($subtype, $conf, $args, $context) {
-  if (empty($context)) {
-    return;
-  }
-
-  $block = new stdClass();
-  $block->module = 'og_subgroups';
-  $block->title = t('OG Group hierarchy graph');
-
-  $group = clone $context->data;
-  $graph = graphapi_new_graph();
-
-  og_subgroups_get_reverse_hierarchy_tree_perm(array($group->gid), '' , NULL, $structure, $graph);
-
-
-  // TODO: Add settings for the options.
-  $options = array(
-    'width' => 550,
-    'height' => 400,
-    'item-width' => 50,
-  );
-  $block->content = graphapi_container($graph, $options);
-
-  return $block;
-}
-
-function og_subgroups_graph_content_type_edit_form($form, &$form_state) {
-  // provide a blank form so we have a place to have context setting.
-  return $form;
-}
