Index: bp-themes/bp-default/groups/groups-loop.php
===================================================================
--- bp-themes/bp-default/groups/groups-loop.php	(revision 7354)
+++ bp-themes/bp-default/groups/groups-loop.php	(working copy)
@@ -37,7 +37,7 @@
 
 	<?php while ( bp_groups() ) : bp_the_group(); ?>
 
-		<li>
+		<li <?php bp_groups_group_class();?>>
 			<div class="item-avatar">
 				<a href="<?php bp_group_permalink(); ?>"><?php bp_group_avatar( 'type=thumb&width=50&height=50' ); ?></a>
 			</div>
Index: bp-themes/bp-default/_inc/css/default.css
===================================================================
--- bp-themes/bp-default/_inc/css/default.css	(revision 7354)
+++ bp-themes/bp-default/_inc/css/default.css	(working copy)
@@ -2208,6 +2208,13 @@
 	right: 0;
 	text-align: right;
 }
+ul.item-list li.sticky {
+	background:#fff9db;
+	padding:5px;
+}
+ul.item-list li.sticky div.action{
+	right:5px;
+}
 ul.item-list li div.meta {
 	color: #888;
 	font-size: 11px;
@@ -2434,4 +2441,4 @@
 .field-visibility-settings legend,
 .field-visibility-settings-toggle {
 	font-style: italic;
-}
\ No newline at end of file
+}
Index: bp-core/admin/bp-core-settings.php
===================================================================
--- bp-core/admin/bp-core-settings.php	(revision 7354)
+++ bp-core/admin/bp-core-settings.php	(working copy)
@@ -197,6 +197,33 @@
 <?php
 }
 
+/**
+ * Allow Administrators to stick a group to front of Groups Directory
+ *
+ *
+ * @uses checked() To display the checked attribute
+ */
+function bp_admin_setting_callback_group_sticky() {
+?>
+
+	<input id="bp_allow_sticky_group" name="bp_allow_sticky_group" type="checkbox" value="1" <?php checked( bp_allow_sticky_group( false ) ); ?> />
+	<label for="bp_allow_sticky_group"><?php _e( 'Enable sticky groups in Groups Directory', 'buddypress' ); ?></label>
+	<p class="description"><?php _e( 'Administrators can set groups as sticky, regardless of this setting.', 'buddypress' ); ?></p>
+
+<?php
+}
+
+/**
+ * Sanitization for bp_allow_sticky_group setting
+ *
+ * In the UI, a checkbox asks whether you'd like to *enable* sticky groups. For
+ * legacy reasons, the option that we store is 1 if these comments are *disabled*. So we use this
+ * function to flip the boolean before saving the intval.
+ */
+function bp_admin_sanitize_callback_sticky_group( $value = false ) {
+	return $value ? 0 : 1;
+}
+
 /** Forums Section ************************************************************/
 
 /**
@@ -302,6 +329,7 @@
 			'bp_disable_blogforum_comments',
 			'bp-disable-profile-sync',
 			'bp_restrict_group_creation',
+			'bp_allow_sticky_group',
 			'hide-loggedout-adminbar',
 		);
 
Index: bp-core/bp-core-admin.php
===================================================================
--- bp-core/bp-core-admin.php	(revision 7354)
+++ bp-core/bp-core-admin.php	(working copy)
@@ -275,9 +275,13 @@
 			// Add the main section
 			add_settings_section( 'bp_groups',        __( 'Groups Settings',  'buddypress' ), 'bp_admin_setting_callback_groups_section',   'buddypress'              );
 
-			// Allow subscriptions setting
+			// Allow group creation for non admin
 			add_settings_field( 'bp_restrict_group_creation', __( 'Group Creation',   'buddypress' ), 'bp_admin_setting_callback_group_creation',   'buddypress', 'bp_groups' );
 			register_setting  ( 'buddypress',         'bp_restrict_group_creation',   'intval'                                                                                );
+
+			// Allow admin to stick groups to front of Groups Directory
+			add_settings_field( 'bp_allow_sticky_group', __( 'Sticky Groups',   'buddypress' ), 'bp_admin_setting_callback_group_sticky',   'buddypress', 'bp_groups' );
+			register_setting  ( 'buddypress',         'bp_allow_sticky_group',   'bp_admin_sanitize_callback_sticky_group'                                                                                );
 		}
 
 		/** Forums ************************************************************/
Index: bp-core/bp-core-options.php
===================================================================
--- bp-core/bp-core-options.php	(revision 7354)
+++ bp-core/bp-core-options.php	(working copy)
@@ -458,6 +458,20 @@
 }
 
 /**
+ * can we stick groups?
+ *
+ *
+ * @param bool $default Optional. Default value true
+ *
+ * @todo Move into groups component
+ * @uses bp_get_option() To get the group creation
+ * @return bool Allow sticky groups?
+ */
+function bp_allow_sticky_group( $default = false ) {
+	return (bool) apply_filters( 'bp_allow_sticky_group', (bool) bp_get_option( 'bp_allow_sticky_group', $default ) );
+}
+
+/**
  * Have we migrated to using the WordPress Toolbar?
  *
  * @since BuddyPress (1.6)
Index: bp-templates/bp-legacy/buddypress/groups/groups-loop.php
===================================================================
--- bp-templates/bp-legacy/buddypress/groups/groups-loop.php	(revision 7354)
+++ bp-templates/bp-legacy/buddypress/groups/groups-loop.php	(working copy)
@@ -37,7 +37,7 @@
 
 	<?php while ( bp_groups() ) : bp_the_group(); ?>
 
-		<li>
+		<li <?php bp_groups_group_class();?>>
 			<div class="item-avatar">
 				<a href="<?php bp_group_permalink(); ?>"><?php bp_group_avatar( 'type=thumb&width=50&height=50' ); ?></a>
 			</div>
Index: bp-templates/bp-legacy/css/buddypress.css
===================================================================
--- bp-templates/bp-legacy/css/buddypress.css	(revision 7354)
+++ bp-templates/bp-legacy/css/buddypress.css	(working copy)
@@ -1173,6 +1173,15 @@
 	right: 0;
 	text-align: right;
 }
+
+#buddypress ul.item-list li.sticky {
+	background:#fff9db;
+	padding:5px;
+}
+
+#buddypress ul.item-list li.sticky div.action{
+	right:5px;
+}
 #buddypress ul.item-list li div.meta {
 	color: #888;
 	font-size: 80%;
Index: bp-groups/admin/css/admin.css
===================================================================
--- bp-groups/admin/css/admin.css	(revision 7354)
+++ bp-groups/admin/css/admin.css	(working copy)
@@ -55,3 +55,7 @@
 	white-space: nowrap;
 	padding-left: 15px;
 }
+
+body.toplevel_page_bp-groups table.groups tr.sticky {
+	background:#fff9db;
+}
Index: bp-groups/admin/css/admin.min.css
===================================================================
--- bp-groups/admin/css/admin.min.css	(revision 7354)
+++ bp-groups/admin/css/admin.min.css	(working copy)
@@ -1 +1 @@
-body.toplevel_page_bp-groups table.groups th#status,body.toplevel_page_bp-groups table.groups th#members{width:10%}body.toplevel_page_bp-groups table.groups th#last_active{width:15%}#bp-groups-edit-form input{outline:medium none;padding:3px 8px}#bp-groups-edit-form input#bp-groups-name{font-size:1.7em;width:100%}#bp-groups-edit-form input#bp-groups-new-members{width:100%;max-width:90%;border:0}.bp-groups-settings-section{margin-bottom:15px}.bp-groups-member-type{position:relative;padding-bottom:1.7em}.bp-groups-member-type>h4{margin-bottom:.5em}ul.bp-group-delete-list{list-style-type:disc;margin:4px 26px}.bp-group-admin-pagination{position:absolute;text-align:right;width:100%}.bp-group-admin-pagination.table-top{top:0}.bp-group-admin-pagination.table-bottom{bottom:0}.bp-group-admin-pagination-viewing{font-family:Georgia,"Times New Roman","Bitstream Charter",Times,serif;color:#777;font-size:12px;font-style:italic}.bp-group-admin-pagination-links{white-space:nowrap;padding-left:15px}
\ No newline at end of file
+body.toplevel_page_bp-groups table.groups th#status,body.toplevel_page_bp-groups table.groups th#members{width:10%}body.toplevel_page_bp-groups table.groups th#last_active{width:15%}#bp-groups-edit-form input{outline:medium none;padding:3px 8px}#bp-groups-edit-form input#bp-groups-name{font-size:1.7em;width:100%}#bp-groups-edit-form input#bp-groups-new-members{width:100%;max-width:90%;border:0}.bp-groups-settings-section{margin-bottom:15px}.bp-groups-member-type{position:relative;padding-bottom:1.7em}.bp-groups-member-type>h4{margin-bottom:.5em}ul.bp-group-delete-list{list-style-type:disc;margin:4px 26px}.bp-group-admin-pagination{position:absolute;text-align:right;width:100%}.bp-group-admin-pagination.table-top{top:0}.bp-group-admin-pagination.table-bottom{bottom:0}.bp-group-admin-pagination-viewing{font-family:Georgia,"Times New Roman","Bitstream Charter",Times,serif;color:#777;font-size:12px;font-style:italic}.bp-group-admin-pagination-links{white-space:nowrap;padding-left:15px}body.toplevel_page_bp-groups table.groups tr.sticky{background:#fff9db;}
Index: bp-groups/bp-groups-admin.php
===================================================================
--- bp-groups/bp-groups-admin.php	(revision 7354)
+++ bp-groups/bp-groups-admin.php	(working copy)
@@ -215,6 +215,14 @@
 			$error = $group_id;
 		}
 
+		// Stick group to front
+		$sticky_group   = ( isset( $_POST['group-stick-group'] ) ) ? 1 : 0;
+
+		if( !empty( $sticky_group ) )
+			groups_update_groupmeta( $group_id, 'sticky', 1 );
+		else
+			groups_delete_groupmeta( $group_id, 'sticky' );
+
 		// Process new members
 		$user_names = array();
 
@@ -663,6 +671,12 @@
 		</div>
 	<?php endif; ?>
 
+	<?php if ( groups_can_stick_group( $item ) ) : ?>
+		<div class="bp-groups-settings-section" id="bp-groups-settings-section-sticky">
+			<label for="group-stick-group"><input type="checkbox" name="group-stick-group" id="group-stick-group" <?php checked( groups_get_groupmeta( $item->id, 'sticky' ) ); ?> /> <?php _e( 'Stick to front of Groups Directory', 'buddypress' ) ?><br />
+		</div>
+	<?php endif; ?>
+
 	<div class="bp-groups-settings-section" id="bp-groups-settings-section-status">
 		<label for="group-status"><?php _e( 'Privacy', 'buddypress' ); ?></label>
 
@@ -1193,15 +1207,25 @@
 	function single_row( $item = array() ) {
 		static $row_class = '';
 
+		$row_classes = array();
+
 		if ( empty( $row_class ) ) {
-			$row_class = ' class="alternate odd"';
+			$row_classes[] = 'alternate odd';
 		} else {
-			$row_class = ' class="even"';
+			$row_classes[] = 'even';
 		}
 
+		if( groups_get_groupmeta(  $item['id'], 'sticky' ) && bp_allow_sticky_group() )
+			$row_classes[] = 'sticky';
+
+		$row_class = ' class="' .implode( ' ', $row_classes ) .'"';
+
 		echo '<tr' . $row_class . ' id="group-' . esc_attr( $item['id'] ) . '" data-parent_id="' . esc_attr( $item['id'] ) . '" data-root_id="' . esc_attr( $item['id'] ) . '">';
 		echo $this->single_row_columns( $item );
 		echo '</tr>';
+
+		if( in_array( 'even', $row_classes ) )
+			$row_class = '';
 	}
 
 	/**
Index: bp-groups/bp-groups-classes.php
===================================================================
--- bp-groups/bp-groups-classes.php	(revision 7354)
+++ bp-groups/bp-groups-classes.php	(working copy)
@@ -346,12 +346,14 @@
 			'populate_extras' => true,
 			'exclude'         => false,
 			'show_hidden'     => false,
+			'sticky'          => false,
 		);
 
 		$r = wp_parse_args( $args, $defaults );
 
 		$sql       = array();
 		$total_sql = array();
+		$stickies = false;
 
 		$sql['select'] = "SELECT DISTINCT g.id, g.*, gm1.meta_value AS total_member_count, gm2.meta_value AS last_activity";
 		$sql['from']   = " FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2,";
@@ -429,6 +431,37 @@
 		// Convert 'orderby' into the proper ORDER BY term
 		$orderby = self::convert_orderby_to_order_by_term( $orderby );
 
+		// sticky groups
+		if( !empty( $r['sticky'] ) ) {
+			$sper_page = $r['per_page'];
+			$spage = $r['page'];
+
+			$stickies = self::get_stickies( $sql, $meta_query_sql, $r['per_page'], $order, $orderby );
+			$sticky_num = is_array( $stickies ) ? count( $stickies ) : false;
+
+			if( !empty( $sticky_num ) ) {
+				
+				// We use the exclude arguments to avoid duplicate display of sticky groups
+				$exclude_stickies = array();
+
+				foreach( $stickies as $stick ) {
+					$exclude_stickies[] = $stick->id;
+				}
+
+				// if exclude argument is set, merge it with exclude stickies one
+				$group_excluded = !empty( $exclude ) ? array_merge( $exclude_stickies, explode( ',', $exclude  ) ) : $exclude_stickies;
+				$group_excluded = implode( ',', $group_excluded );
+
+				$sql['exclude'] = " AND g.id NOT IN ({$group_excluded})";
+
+				if( $r['page'] <= 1 )
+					$r['per_page'] -= $sticky_num;
+				else
+					$r['page'] =  $r['page'] - ( $sticky_num / $r['per_page'] ) ;
+			}
+
+		}
+
 		// Random order is a special case
 		if ( 'rand()' === $orderby ) {
 			$sql[] = "ORDER BY rand()";
@@ -436,14 +469,23 @@
 			$sql[] = "ORDER BY {$orderby} {$order}";
 		}
 
-		if ( ! empty( $r['per_page'] ) && ! empty( $r['page'] ) ) {
-			$sql['pagination'] = $wpdb->prepare( "LIMIT %d, %d", intval( ( $r['page'] - 1 ) * $r['per_page']), intval( $r['per_page'] ) );
+		/* 
+		If Number of stickies is equal to the per page argument, and we're on first page
+		A new query with a null offset is not necessary ;)
+		*/
+		if( empty( $sticky_num ) || $sticky_num < $sper_page || $spage > 1 ) {
+
+			// we need to use the round function as for instance intval( (1.4 - 1) * 5 ) == 1 instead of 2 ?!
+			if ( ! empty( $r['per_page'] ) && ! empty( $r['page'] ) ) {
+				$sql['pagination'] = $wpdb->prepare( "LIMIT %d, %d", intval( round( ( $r['page'] - 1 ) * $r['per_page'] ) ), intval( $r['per_page'] ) );
+			}
+
+			// Get paginated results
+			$paged_groups_sql = apply_filters( 'bp_groups_get_paged_groups_sql', join( ' ', (array) $sql ), $sql );
+			$paged_groups     = $wpdb->get_results( $paged_groups_sql );
+
 		}
 
-		// Get paginated results
-		$paged_groups_sql = apply_filters( 'bp_groups_get_paged_groups_sql', join( ' ', (array) $sql ), $sql );
-		$paged_groups     = $wpdb->get_results( $paged_groups_sql );
-
 		$total_sql['select'] = "SELECT COUNT(DISTINCT g.id) FROM {$bp->groups->table_name} g, {$bp->groups->table_name_members} gm1, {$bp->groups->table_name_groupmeta} gm2";
 
 		if ( ! empty( $r['user_id'] ) ) {
@@ -498,6 +540,11 @@
 		$total_groups     = $wpdb->get_var( $total_groups_sql );
 
 		$group_ids = array();
+
+		// merging if we still have regular groups
+		if( !empty( $sticky_num ) && $spage <= 1 )
+			$paged_groups = !empty( $paged_groups ) ? array_merge( $stickies, (array) $paged_groups ) : $stickies ;
+
 		foreach ( (array) $paged_groups as $group ) {
 			$group_ids[] = $group->id;
 		}
@@ -517,7 +564,7 @@
 	}
 
 	/**
-	 * Get the SQL for the 'meta_query' param in BP_Activity_Activity::get()
+	 * Get the SQL for the 'meta_query' param in BP_Groups_Group::get()
 	 *
 	 * We use WP_Meta_Query to do the heavy lifting of parsing the
 	 * meta_query array and creating the necessary SQL clauses. However,
@@ -577,6 +624,71 @@
 	}
 
 	/**
+	 * Gets the stickies to add to the groups queried in BP_Groups_Group::get()
+	 *
+	 * @access protected
+	 *
+	 * @global $wpdb the WordPress DB API
+	 * @param  array $sticky_sql the sql array calculated by BP_Groups_Group::get()
+	 * @param  array $meta_query_sql the sql array of an eventual meta query
+	 * @param  integer $per_page the query offset
+	 * @param  string $order DESC or ASC ? 
+	 * @param  string $orderby how to order the sticky query
+	 * @uses   buddypress() to get main instance of the plugin
+	 * @return array the sticky groups found
+	 */
+	protected static function get_stickies( $sticky_sql = array(), $meta_query_sql = array(), $per_page = 0, $order = '', $orderby = '' ) {
+		global $wpdb;
+		$bp = buddypress();
+
+		if( empty( $sticky_sql ) || !is_array( $sticky_sql ) )
+			return false;
+
+		// When searching a group, stickies would be annoying..
+		if ( ! empty($sticky_sql['search'] ) )
+			return false;
+
+		// In case of restricting the group query to limited groups, we don't need stickies
+		if ( ! empty( $sticky_sql['include'] ) )
+			return false;
+
+		// We only play in Group Directory so a user id tells us we're no on groups directory
+		if ( ! empty( $sticky_sql['members_from'] ) )
+			return false;
+
+		// hidden can't be sticky
+		$sticky_sql['hidden'] = " AND g.status != 'hidden'";
+
+		// If a meta query, don't apply it on stickies
+		if( !empty( $meta_query_sql['join'] ) )
+			$sticky_sql['from'] = str_replace( $meta_query_sql['join'], '', $sticky_sql['from'] );
+
+		if ( ! empty( $meta_query_sql['where'] ) )
+			unset( $sticky_sql['meta'] );
+
+		// Adding this will spread in global $groups_template ( $groups_template->group->sticky )
+		$sticky_sql['select'] .= ", 1 as sticky";
+
+		// Adding the specific sticky part for the group query
+		$sticky_sql['from'] .= "{$bp->groups->table_name_groupmeta} gms,";
+		$sticky_sql['where'] .= " AND g.id = gms.group_id AND gms.meta_key = 'sticky'";
+
+		if( !empty( $orderby ) && !empty( $order ) )
+			$sticky_sql[] = "ORDER BY {$orderby} {$order}";
+
+		/* max is per_page, after it's no more a sticky group... */ 
+		if ( ! empty( $per_page ) ) {
+			$sticky_sql['pagination'] = $wpdb->prepare( "LIMIT %d", intval( $per_page ) );
+		}
+
+		// Plugin authors can modify the query if they need to
+		$sticky_query = apply_filters( 'bp_groups_get_stickies_sql', join( ' ', (array) $sticky_sql ), $sticky_sql );
+
+		// returning the found stickies.
+		return (array) $wpdb->get_results( $sticky_query );
+	}
+
+	/**
 	 * Convert the 'type' parameter to 'order' and 'orderby'
 	 *
 	 * @since BuddyPress (1.8)
Index: bp-groups/bp-groups-functions.php
===================================================================
--- bp-groups/bp-groups-functions.php	(revision 7354)
+++ bp-groups/bp-groups-functions.php	(working copy)
@@ -465,6 +465,7 @@
 		'per_page'        => 20,       // The number of results to return per page
 		'page'            => 1,        // The page to return if limiting per page
 		'populate_extras' => true,     // Fetch meta such as is_banned and is_member
+		'sticky'          => false
 	);
 
 	$r = wp_parse_args( $args, $defaults );
@@ -480,8 +481,9 @@
 		'per_page'        => $r['per_page'],
 		'page'            => $r['page'],
 		'populate_extras' => $r['populate_extras'],
+		'sticky'          => $r['sticky'],
 		'order'           => $r['order'],
-		'orderby'         => $r['orderby'],
+		'orderby'         => $r['orderby']
 	) );
 
 	return apply_filters_ref_array( 'groups_get_groups', array( &$groups, &$r ) );
@@ -1078,3 +1080,25 @@
 add_action( 'wpmu_delete_user',  'groups_remove_data_for_user' );
 add_action( 'delete_user',       'groups_remove_data_for_user' );
 add_action( 'bp_make_spam_user', 'groups_remove_data_for_user' );
+
+
+/*** Sticky group *****/
+
+/**
+ * Checks if a group can be sticky according to blog settings and group status
+ * 
+ * @param  BP_Groups_Group $group the group object
+ * @uses   groups_get_current_group() if the argument is not defined to try to find current group
+ * @uses   bp_allow_sticky_group() to get blog settings for the stick to front group setting
+ * @return boolean true||false
+ */
+function groups_can_stick_group( $group = false ) {
+	if( empty( $group ) )
+		$group = groups_get_current_group();
+
+	if( $group->status != 'hidden' )
+		return bp_allow_sticky_group();
+	else
+		return false;
+
+}
Index: bp-groups/bp-groups-template.php
===================================================================
--- bp-groups/bp-groups-template.php	(revision 7354)
+++ bp-groups/bp-groups-template.php	(working copy)
@@ -145,7 +145,8 @@
 			'exclude'         => false,
 			'search_terms'    => '',
 			'meta_query'      => false,
-			'populate_extras' => true
+			'populate_extras' => true,
+			'sticky'          => false,
 		);
 
 		$r = wp_parse_args( $args, $defaults );
@@ -176,7 +177,8 @@
 				'include'         => $include,
 				'exclude'         => $exclude,
 				'populate_extras' => $populate_extras,
-				'show_hidden'     => $show_hidden
+				'show_hidden'     => $show_hidden,
+				'sticky'          => $sticky
 			) );
 		}
 
@@ -291,6 +293,7 @@
 	$type    = '';
 	$user_id = 0;
 	$order   = '';
+	$sticky  = false; 
 
 	// User filtering
 	if ( bp_displayed_user_id() )
@@ -342,6 +345,9 @@
 		else
 			$r['search_terms'] = false;
 	}
+	
+	if ( bp_is_groups_component() && !bp_current_action() && !bp_current_item() && empty( $r['search_terms'] ) )
+		$sticky = bp_allow_sticky_group();
 
 	$groups_template = new BP_Groups_Template( array(
 		'type'            => $r['type'],
@@ -358,7 +364,8 @@
 		'meta_query'      => $r['meta_query'],
 		'include'         => $r['include'],
 		'exclude'         => $r['exclude'],
-		'populate_extras' => (bool) $r['populate_extras']
+		'populate_extras' => (bool) $r['populate_extras'],
+		'sticky'          => (bool) $sticky
 	) );
 
 	return apply_filters( 'bp_has_groups', $groups_template->has_groups(), $groups_template, $r );
@@ -407,6 +414,33 @@
 	}
 
 /**
+ * Output the row class of a group in the groups loop
+ */
+function bp_groups_group_class() {
+	echo bp_get_groups_group_class();
+}
+	/**
+	 * Return the row class of a group in the groups loop
+	 *
+	 * @global BP_Groups_Template $groups_template
+	 * @uses   apply_filters() to let plugins add their classes
+	 * @return string Row class of the group
+	 */
+	function bp_get_groups_group_class() {
+		global $groups_template;
+
+		$classes = array();
+
+		if( !empty( $groups_template->group->sticky ) )
+			$classes[] = 'sticky';
+
+		$classes = apply_filters( 'bp_get_groups_class', $classes );
+		$classes = array_merge( $classes, array() );
+		$retval = 'class="' . join( ' ', $classes ) . '"';
+		return $retval;
+	}
+
+/**
  * Output the row class of a group
  *
  * @since BuddyPress (1.7)
