diff --git a/includes/tree.inc b/includes/tree.inc
new file mode 100644
index 0000000..9f86754
--- /dev/null
+++ b/includes/tree.inc
@@ -0,0 +1,110 @@
+<?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) {
+  $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' => FALSE));
+        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,
+  );
+
+  $wrapper = entity_metadata_wrapper($entity_type, $etid);
+    
+  if ($group = $wrapper->group->value()) {
+    $tree[$group->gid]->title = og_label($group->gid, $options['sanitize']);
+    $tree[$group->gid]->gid = $group->gid;
+    $tree[$group->gid]->etid = $etid;
+    $tree[$group->gid]->parent = $depth;
+      
+    // Get the first group associated with the entity.
+    if ($options['direction'] == 'children') {
+      $children = og_subgroups_get_all_contentgroups($entity_type, $wrapper->type->value(), $group->gid);
+      if ($children)
+        foreach ($children as $child)
+          if ($group->gid) {
+            $childgroup = og_load($child);
+            if ($options['nested']) {
+              $tree[$group->gid]->children[$child] = new stdClass();
+              if ($childgroup->etid <> $etid)
+                og_get_hierarchy($childgroup->entity_type, $childgroup->etid, $options, $tree[$group->gid]->children, $depth + 1);
+            } 
+            else {
+              $tree[$child] = new stdClass();
+              if ($childgroup->etid <> $etid)
+                og_get_hierarchy($childgroup->entity_type, $childgroup->etid, $options, $tree, $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[$group->gid]->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[$parent->gid] = new stdClass();
+            if ($parent->etid <> $etid)      
+              og_get_hierarchy($parent->entity_type, $parent->etid, $options, $tree, $depth - 1);
+          }
+        }
+      }
+    }
+  }
+
+  return $tree;
+}
\ No newline at end of file
diff --git a/modules/og_subgroups_views/includes/og_subgroups_views_handler_argument_content.inc b/modules/og_subgroups_views/includes/og_subgroups_views_handler_argument_content.inc
new file mode 100644
index 0000000..a116681
--- /dev/null
+++ b/modules/og_subgroups_views/includes/og_subgroups_views_handler_argument_content.inc
@@ -0,0 +1,23 @@
+<?php
+class og_subgroups_views_handler_argument_content extends og_subgroups_views_handler_argument_gid {
+  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'));
+    $this->query->add_where(0, "$this->table_alias.$this->real_field IN ($placeholders)", $tree);
+  }
+}
\ No newline at end of file
diff --git a/modules/og_subgroups_views/includes/og_subgroups_views_handler_argument_gid.inc b/modules/og_subgroups_views/includes/og_subgroups_views_handler_argument_gid.inc
new file mode 100644
index 0000000..aa6efa4
--- /dev/null
+++ b/modules/og_subgroups_views/includes/og_subgroups_views_handler_argument_gid.inc
@@ -0,0 +1,85 @@
+<?php
+class og_subgroups_views_handler_argument_gid 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) {
+        $group = og_load($argument);        
+        
+        // Decide the function to use based on the direction
+        $func = "og_get_hierarchy{$direction}";
+        
+        // Fetch the groups
+        $groups = $func($group->entity_type, $group->gid, ($direction == 'children') ? FALSE : NULL);
+        
+        // Add the groups to an array
+        foreach ($groups as $group) {
+          $tree[] = $group->gid;
+        }
+      }
+    }
+    
+    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..5d9c8fc
--- /dev/null
+++ b/modules/og_subgroups_views/includes/og_subgroups_views_handler_sort_hierarchy.inc
@@ -0,0 +1,21 @@
+<?php
+
+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)) {
+      $sort_order = implode(',', array_keys($groups));
+      $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..b51e6bf
--- /dev/null
+++ b/modules/og_subgroups_views/og_subgroups_views.module
@@ -0,0 +1,12 @@
+<?php
+
+/**
+ * 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..e6dc5af
--- /dev/null
+++ b/modules/og_subgroups_views/og_subgroups_views.views.inc
@@ -0,0 +1,75 @@
+<?php
+
+/**
+* Implementation of hook_views_data() to register all of the basic handlers
+* views uses.
+*/
+function og_subgroups_views_views_data() {
+  $data['og_subgroups']['table']['group']  = t('OG subgroups');
+  $data['og_subgroups']['table']['join']['node'] = array(
+    'left_field' => 'nid',
+    'field' => 'gid',
+    'type' => 'left',
+  );
+
+  $data['og_subgroups']['gid'] = array(
+    'title' => t('Group ID'),
+    'help' => t('Use the nid of a group as a starting point to retrieve other groups in the hierarchy.'),
+    'argument' => array(
+      'handler' => 'og_subgroups_views_handler_argument_gid',
+    ),
+    'sort' => array(
+      'title' => t('Hierarchy order'),
+      'help' => t('Sort the group'),
+      'sort' => array(
+        'handler' => 'og_subgroups_views_handler_sort_hierarchy',
+      ),
+    ),
+  );
+  
+  $data['og_subgroups']['has_parent'] = array(
+    'title' => t('Has parent'),
+    'help' => t('This item is currently not exposed. If you expose it, users will be able to change the filter as they view it.'),
+    'filter' => array(
+      'handler' => 'views_handler_filter_string',
+    ),
+  );
+
+  $data['og_subgroups_posts']['content'] = array(
+    'title' => t('Group ID'),
+    'help' => t('<strong>Posts</strong> are filtered for specified branches of the subgroup tree'),
+    'argument' => array(
+      'handler' => 'og_subgroups_views_handler_argument_content',
+      'field' => 'group_nid',
+      'numeric' => TRUE,
+    ),
+  );
+
+  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_gid' => array(
+        'parent' => 'views_handler_argument_numeric',
+      ),
+      'og_subgroups_views_handler_argument_content' => array(
+        'parent' => 'og_subgroups_views_handler_argument_gid',
+      ),
+      // 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..62f635a
--- /dev/null
+++ b/og_subgroups.admin.inc
@@ -0,0 +1,101 @@
+<?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_rebuild_access_' . $element]) && $form_state['values']['og_subgroups_rebuild_access_' . $element] == 1) {
+      $entity_bundle = explode("|", $element);
+      og_subgroups_node_access_rebuild($entity_bundle[1]);
+    }
+}
\ No newline at end of file
