Groups - Version 1.3.11

Version Description

  • Fix: Access restriction capabilities must be disjunctive.
  • Added: List of groups can be shown in user profiles on the back end and group assignments can be edited by group admins.
  • Improvement: Groups shown for users on the Users screen are sorted by name.
Download this release

Release Info

Developer itthinx
Plugin Icon 128x128 Groups
Version 1.3.11
Comparing to
See all releases

Code changes from version 1.3.10 to 1.3.11

groups.php CHANGED
@@ -21,13 +21,13 @@
21
  * Plugin Name: Groups
22
  * Plugin URI: http://www.itthinx.com/plugins/groups
23
  * Description: Groups provides group-based user membership management, group-based capabilities and content access control.
24
- * Version: 1.3.10
25
  * Author: itthinx
26
  * Author URI: http://www.itthinx.com
27
  * Donate-Link: http://www.itthinx.com
28
  * License: GPLv3
29
  */
30
- define( 'GROUPS_CORE_VERSION', '1.3.10' );
31
  define( 'GROUPS_FILE', __FILE__ );
32
  if ( !defined( 'GROUPS_CORE_DIR' ) ) {
33
  define( 'GROUPS_CORE_DIR', WP_PLUGIN_DIR . '/groups' );
21
  * Plugin Name: Groups
22
  * Plugin URI: http://www.itthinx.com/plugins/groups
23
  * Description: Groups provides group-based user membership management, group-based capabilities and content access control.
24
+ * Version: 1.3.11
25
  * Author: itthinx
26
  * Author URI: http://www.itthinx.com
27
  * Donate-Link: http://www.itthinx.com
28
  * License: GPLv3
29
  */
30
+ define( 'GROUPS_CORE_VERSION', '1.3.11' );
31
  define( 'GROUPS_FILE', __FILE__ );
32
  if ( !defined( 'GROUPS_CORE_DIR' ) ) {
33
  define( 'GROUPS_CORE_DIR', WP_PLUGIN_DIR . '/groups' );
lib/access/class-groups-post-access.php CHANGED
@@ -138,8 +138,24 @@ class Groups_Post_Access {
138
 
139
  // 2. Filter the posts that require a capability that the user doesn't
140
  // have, or in other words: exclude posts that the user must NOT access:
 
 
 
 
 
 
 
 
 
 
141
  $where .= sprintf(
142
- " AND {$wpdb->posts}.ID NOT IN (SELECT DISTINCT ID FROM $wpdb->posts LEFT JOIN $wpdb->postmeta on {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id WHERE {$wpdb->postmeta}.meta_key = '%s' AND {$wpdb->postmeta}.meta_value NOT IN (%s) ) ",
 
 
 
 
 
 
143
  self::POSTMETA_PREFIX . self::READ_POST_CAPABILITY,
144
  $caps
145
  );
138
 
139
  // 2. Filter the posts that require a capability that the user doesn't
140
  // have, or in other words: exclude posts that the user must NOT access:
141
+
142
+ // The following is not correct in that it requires the user to have ALL capabilities:
143
+ // $where .= sprintf(
144
+ // " AND {$wpdb->posts}.ID NOT IN (SELECT DISTINCT ID FROM $wpdb->posts LEFT JOIN $wpdb->postmeta on {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id WHERE {$wpdb->postmeta}.meta_key = '%s' AND {$wpdb->postmeta}.meta_value NOT IN (%s) ) ",
145
+ // self::POSTMETA_PREFIX . self::READ_POST_CAPABILITY,
146
+ // $caps
147
+ // );
148
+
149
+ // This allows the user to access posts where the posts are not restricted or where
150
+ // the user has ANY of the capabilities:
151
  $where .= sprintf(
152
+ " AND {$wpdb->posts}.ID IN " .
153
+ " ( " .
154
+ " SELECT ID FROM $wpdb->posts WHERE ID NOT IN ( SELECT post_id FROM $wpdb->postmeta WHERE {$wpdb->postmeta}.meta_key = '%s' ) " . // posts without access restriction
155
+ " UNION ALL " . // we don't care about duplicates here, just make it quick
156
+ " SELECT post_id AS ID FROM $wpdb->postmeta WHERE {$wpdb->postmeta}.meta_key = '%s' AND {$wpdb->postmeta}.meta_value IN (%s) " . // posts that require any capability the user has
157
+ " ) ",
158
+ self::POSTMETA_PREFIX . self::READ_POST_CAPABILITY,
159
  self::POSTMETA_PREFIX . self::READ_POST_CAPABILITY,
160
  $caps
161
  );
lib/admin/class-groups-admin-user-profile.php ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * class-groups-admin-user-profile.php
4
+ *
5
+ * Copyright (c) 2013 "kento" Karim Rahimpur www.itthinx.com
6
+ *
7
+ * This code is released under the GNU General Public License.
8
+ * See COPYRIGHT.txt and LICENSE.txt.
9
+ *
10
+ * This code is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ * GNU General Public License for more details.
14
+ *
15
+ * This header and all notices must be kept intact.
16
+ *
17
+ * @author Karim Rahimpur
18
+ * @package groups
19
+ * @since groups 1.3.11
20
+ */
21
+
22
+ /**
23
+ * Show group info on user profile pages and let admins edit group membership.
24
+ */
25
+ class Groups_Admin_User_Profile {
26
+
27
+ /**
28
+ * Adds user profile actions.
29
+ */
30
+ public static function init() {
31
+ add_action( 'show_user_profile', array( __CLASS__, 'show_user_profile' ) );
32
+ add_action( 'edit_user_profile', array( __CLASS__, 'edit_user_profile' ) );
33
+ add_action( 'personal_options_update', array( __CLASS__, 'personal_options_update' ) );
34
+ add_action( 'edit_user_profile_update', array( __CLASS__, 'edit_user_profile_update' ) );
35
+ }
36
+
37
+ /**
38
+ * Own profile.
39
+ * @param WP_User $user
40
+ */
41
+ public static function show_user_profile( $user ) {
42
+ if ( current_user_can( GROUPS_ADMINISTER_GROUPS ) ) {
43
+ self::edit_user_profile( $user );
44
+ } else {
45
+ $output = '<h3>' . __( 'Groups', GROUPS_PLUGIN_DOMAIN ) . '</h3>';
46
+ $user = new Groups_User( $user->ID );
47
+ $groups = $user->groups;
48
+ if ( is_array( $groups ) ) {
49
+ if ( count( $groups ) > 0 ) {
50
+ usort( $groups, array( __CLASS__, 'by_group_name' ) );
51
+ $output .= '<ul>';
52
+ foreach( $groups as $group ) {
53
+ $output .= '<li>' . wp_filter_nohtml_kses( $group->name ) . '</li>';
54
+ }
55
+ $output .= '<ul>';
56
+ }
57
+ }
58
+ echo $output;
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Editing a user profile.
64
+ * @param WP_User $user
65
+ */
66
+ public static function edit_user_profile( $user ) {
67
+ global $wpdb;
68
+ if ( current_user_can( GROUPS_ADMINISTER_GROUPS ) ) {
69
+ $output = '<h3>' . __( 'Groups', GROUPS_PLUGIN_DOMAIN ) . '</h3>';
70
+ $user = new Groups_User( $user->ID );
71
+ $user_groups = $user->groups;
72
+ $groups_table = _groups_get_tablename( 'group' );
73
+ if ( $groups = $wpdb->get_results( "SELECT * FROM $groups_table ORDER BY name" ) ) {
74
+ $output .= '<ul>';
75
+ foreach( $groups as $group ) {
76
+ $is_member = Groups_User_Group::read( $user->ID, $group->group_id ) ? true : false;
77
+ $output .= '<li>';
78
+ $output .= '<label>';
79
+ $output .= sprintf( '<input type="checkbox" name="group_ids[]" value="%d" %s />', Groups_Utility::id( $group->group_id ), $is_member ? ' checked="checked" ' : '' );
80
+ $output .= ' ';
81
+ $output .= wp_filter_nohtml_kses( $group->name );
82
+ $output .= '</label>';
83
+ $output .= '</li>';
84
+ }
85
+ $output .= '</ul>';
86
+ }
87
+ }
88
+ echo $output;
89
+ }
90
+
91
+ /**
92
+ * Updates the group membership when a user's own profile is saved - but
93
+ * for group admins on their own profile page only.
94
+ *
95
+ * @param int $user_id
96
+ * @see Groups_Admin_User_Profile::edit_user_profile_update()
97
+ */
98
+ public static function personal_options_update( $user_id ) {
99
+ // We're using the same method as for editing another user's profile,
100
+ // but let's check for group admin here as well.
101
+ if ( current_user_can( GROUPS_ADMINISTER_GROUPS ) ) {
102
+ self::edit_user_profile_update( $user_id );
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Updates the group membership.
108
+ * @param int $user_id
109
+ */
110
+ public static function edit_user_profile_update( $user_id ) {
111
+ global $wpdb;
112
+ if ( current_user_can( GROUPS_ADMINISTER_GROUPS ) ) {
113
+ $groups_table = _groups_get_tablename( 'group' );
114
+ if ( $groups = $wpdb->get_results( "SELECT * FROM $groups_table" ) ) {
115
+ $user_group_ids = isset( $_POST['group_ids'] ) && is_array( $_POST['group_ids'] ) ? $_POST['group_ids'] : array();
116
+ foreach( $groups as $group ) {
117
+ if ( in_array( $group->group_id, $user_group_ids) ) {
118
+ if ( !Groups_User_Group::read( $user_id, $group->group_id ) ) {
119
+ Groups_User_Group::create( array( 'user_id' => $user_id, 'group_id' => $group->group_id ) );
120
+ }
121
+ } else {
122
+ if ( Groups_User_Group::read( $user_id, $group->group_id ) ) {
123
+ Groups_User_Group::delete( $user_id, $group->group_id );
124
+ }
125
+ }
126
+ }
127
+ }
128
+ }
129
+ }
130
+
131
+ /**
132
+ * usort helper
133
+ * @param Groups_Group $o1
134
+ * @param Groups_Group $o2
135
+ * @return int strcmp result for group names
136
+ */
137
+ public static function by_group_name( $o1, $o2 ) {
138
+ return strcmp( $o1->name, $o2->name );
139
+ }
140
+
141
+ }
142
+ Groups_Admin_User_Profile::init();
lib/admin/class-groups-admin-users.php CHANGED
@@ -243,6 +243,7 @@ class Groups_Admin_Users {
243
  $groups_user = new Groups_User( $user_id );
244
  $groups = $groups_user->groups;
245
  if ( count( $groups ) > 0 ) {
 
246
  $output = '<ul>';
247
  foreach( $groups as $group ) {
248
  $output .= '<li>';
@@ -258,5 +259,14 @@ class Groups_Admin_Users {
258
  return $output;
259
  }
260
 
 
 
 
 
 
 
 
 
 
261
  }
262
  Groups_Admin_Users::init();
243
  $groups_user = new Groups_User( $user_id );
244
  $groups = $groups_user->groups;
245
  if ( count( $groups ) > 0 ) {
246
+ usort( $groups, array( __CLASS__, 'by_group_name' ) );
247
  $output = '<ul>';
248
  foreach( $groups as $group ) {
249
  $output .= '<li>';
259
  return $output;
260
  }
261
 
262
+ /**
263
+ * usort helper
264
+ * @param Groups_Group $o1
265
+ * @param Groups_Group $o2
266
+ * @return int strcmp result for group names
267
+ */
268
+ public static function by_group_name( $o1, $o2 ) {
269
+ return strcmp( $o1->name, $o2->name );
270
+ }
271
  }
272
  Groups_Admin_Users::init();
lib/admin/groups-admin-options.php CHANGED
@@ -98,6 +98,9 @@ function groups_admin_options() {
98
  Groups_Options::update_option( GROUPS_SHOW_TREE_VIEW, false );
99
  }
100
 
 
 
 
101
  // roles & capabilities
102
  $rolenames = $wp_roles->get_names();
103
  foreach ( $rolenames as $rolekey => $rolename ) {
@@ -127,6 +130,7 @@ function groups_admin_options() {
127
  $admin_override = get_option( GROUPS_ADMINISTRATOR_ACCESS_OVERRIDE, GROUPS_ADMINISTRATOR_ACCESS_OVERRIDE_DEFAULT );
128
 
129
  $show_tree_view = Groups_Options::get_option( GROUPS_SHOW_TREE_VIEW, GROUPS_SHOW_TREE_VIEW_DEFAULT );
 
130
 
131
  $rolenames = $wp_roles->get_names();
132
  $caps_table = '<table class="groups-permissions">';
@@ -245,6 +249,15 @@ function groups_admin_options() {
245
  echo '<br/>';
246
  }
247
 
 
 
 
 
 
 
 
 
 
248
  echo
249
  '<h3>' . __( 'Tree view', GROUPS_PLUGIN_DOMAIN ) . '</h3>' .
250
  '<p>' .
@@ -252,7 +265,8 @@ function groups_admin_options() {
252
  '<input name="' . GROUPS_SHOW_TREE_VIEW . '" type="checkbox" ' . ( $show_tree_view ? 'checked="checked"' : '' ) . '/>' .
253
  __( 'Show the Groups tree view.', GROUPS_PLUGIN_DOMAIN ) .
254
  '</label>' .
255
- '</p>';
 
256
  echo
257
  '<h3>' . __( 'Permissions', GROUPS_PLUGIN_DOMAIN ) . '</h3>' .
258
  '<p>' . __( 'These permissions apply to Groups management. They do not apply to access permissions derived from Groups capabilities.', GROUPS_PLUGIN_DOMAIN ) . '</p>' .
98
  Groups_Options::update_option( GROUPS_SHOW_TREE_VIEW, false );
99
  }
100
 
101
+ // show in user profiles
102
+ Groups_Options::update_option( GROUPS_SHOW_IN_USER_PROFILE, !empty( $_POST[GROUPS_SHOW_IN_USER_PROFILE] ) );
103
+
104
  // roles & capabilities
105
  $rolenames = $wp_roles->get_names();
106
  foreach ( $rolenames as $rolekey => $rolename ) {
130
  $admin_override = get_option( GROUPS_ADMINISTRATOR_ACCESS_OVERRIDE, GROUPS_ADMINISTRATOR_ACCESS_OVERRIDE_DEFAULT );
131
 
132
  $show_tree_view = Groups_Options::get_option( GROUPS_SHOW_TREE_VIEW, GROUPS_SHOW_TREE_VIEW_DEFAULT );
133
+ $show_in_user_profile = Groups_Options::get_option( GROUPS_SHOW_IN_USER_PROFILE, GROUPS_SHOW_IN_USER_PROFILE_DEFAULT );
134
 
135
  $rolenames = $wp_roles->get_names();
136
  $caps_table = '<table class="groups-permissions">';
249
  echo '<br/>';
250
  }
251
 
252
+ echo
253
+ '<h3>' . __( 'User profiles', GROUPS_PLUGIN_DOMAIN ) . '</h3>' .
254
+ '<p>' .
255
+ '<label>' .
256
+ '<input name="' . GROUPS_SHOW_IN_USER_PROFILE . '" type="checkbox" ' . ( $show_in_user_profile ? 'checked="checked"' : '' ) . '/>' .
257
+ __( 'Show groups in user profiles.', GROUPS_PLUGIN_DOMAIN ) .
258
+ '</label>' .
259
+ '</p>';
260
+
261
  echo
262
  '<h3>' . __( 'Tree view', GROUPS_PLUGIN_DOMAIN ) . '</h3>' .
263
  '<p>' .
265
  '<input name="' . GROUPS_SHOW_TREE_VIEW . '" type="checkbox" ' . ( $show_tree_view ? 'checked="checked"' : '' ) . '/>' .
266
  __( 'Show the Groups tree view.', GROUPS_PLUGIN_DOMAIN ) .
267
  '</label>' .
268
+ '</p>';
269
+
270
  echo
271
  '<h3>' . __( 'Permissions', GROUPS_PLUGIN_DOMAIN ) . '</h3>' .
272
  '<p>' . __( 'These permissions apply to Groups management. They do not apply to access permissions derived from Groups capabilities.', GROUPS_PLUGIN_DOMAIN ) . '</p>' .
lib/core/constants.php CHANGED
@@ -93,3 +93,15 @@ define( 'GROUPS_SHOW_TREE_VIEW', 'groups-show-tree-view' );
93
  * @var boolean
94
  */
95
  define( 'GROUPS_SHOW_TREE_VIEW_DEFAULT', false );
 
 
 
 
 
 
 
 
 
 
 
 
93
  * @var boolean
94
  */
95
  define( 'GROUPS_SHOW_TREE_VIEW_DEFAULT', false );
96
+
97
+ /**
98
+ * Option to show groups info in the user profile.
99
+ * @var string
100
+ */
101
+ define( 'GROUPS_SHOW_IN_USER_PROFILE', 'groups-show-in-user-profile' );
102
+
103
+ /**
104
+ * Default for showing groups in user profiles.
105
+ * @var boolean
106
+ */
107
+ define( 'GROUPS_SHOW_IN_USER_PROFILE_DEFAULT', false );
lib/core/wp-init.php CHANGED
@@ -52,6 +52,9 @@ require_once( GROUPS_CORE_LIB . '/class-groups-controller.php' );
52
  // admin
53
  if ( is_admin() ) {
54
  require_once( GROUPS_ADMIN_LIB . '/class-groups-admin.php' );
 
 
 
55
  require_once( GROUPS_ADMIN_LIB . '/class-groups-admin-users.php' );
56
  }
57
 
52
  // admin
53
  if ( is_admin() ) {
54
  require_once( GROUPS_ADMIN_LIB . '/class-groups-admin.php' );
55
+ if ( Groups_Options::get_option( GROUPS_SHOW_IN_USER_PROFILE, GROUPS_SHOW_IN_USER_PROFILE_DEFAULT ) ) {
56
+ require_once( GROUPS_ADMIN_LIB . '/class-groups-admin-user-profile.php' );
57
+ }
58
  require_once( GROUPS_ADMIN_LIB . '/class-groups-admin-users.php' );
59
  }
60
 
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: http://www.itthinx.com/plugins/groups
4
  Tags: access, access control, capability, capabilities, content, download, downloads, file, file access, files, group, groups, member, members, membership, memberships, paypal, permission, permissions, subscription, subscriptions, woocommerce
5
  Requires at least: 3.3
6
  Tested up to: 3.5.1
7
- Stable tag: 1.3.10
8
  License: GPLv3
9
 
10
  Groups provides group-based user membership management, group-based capabilities and content access control.
@@ -151,6 +151,12 @@ You can see this only if you have the edit_posts capability.
151
  Users - group membership is managed from the standard Users admin view.
152
  Users are automatically added to the _Registered_ group. You can add multiple users to other groups here and also remove them.
153
 
 
 
 
 
 
 
154
  ### Sections in the 'Groups' menu: ###
155
 
156
  #### Groups ####
@@ -169,11 +175,13 @@ Capabilities can be assigned to groups and users (1). These capabilities include
169
  the *standard WordPress capabilities* but you can also define additional
170
  capabilities for your web-application.
171
 
172
- Groups defines the *groups_read_post* capability by default which can be
173
  used to restrict access to certain posts or pages to groups (and users)
174
  with that capability only. Additional capabilities can be identified on the
175
  *Groups > Options* admin screen that may be used to limit access.
176
 
 
 
177
  (1) Assigning capabilities to users is not integrated in the user interface yet but can be done through API calls.
178
 
179
  #### Options ####
@@ -182,6 +190,21 @@ with that capability only. Additional capabilities can be identified on the
182
 
183
  Administrator overrides can be turned off.
184
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  ##### Permissions #####
186
 
187
  For each role these permissions can be set:
@@ -312,6 +335,14 @@ Example: Green and Red members
312
  6. Create another post for *Red Members* and tick the *red* checkbox for that post.
313
  7. Assign a test user to any of the above groups, log in as that user and the post will be accessible.
314
 
 
 
 
 
 
 
 
 
315
  == Screenshots ==
316
 
317
  See also [Groups](http://www.itthinx.com/plugins/groups/)
@@ -327,6 +358,11 @@ See also [Groups](http://www.itthinx.com/plugins/groups/)
327
 
328
  == Changelog ==
329
 
 
 
 
 
 
330
  = 1.3.10 =
331
  * Fix: Under certain conditions with caching involved, capabilities were not correctly retrieved. Thanks to Jason Kadlec who [reported the issue](http://wordpress.org/support/topic/nasty-error-with-latest-version).
332
  * Improvement: Related to the above fix, improved the way how *_deep properties are retrieved on cache misses, resulting in slightly better performance.
@@ -455,6 +491,9 @@ Some installations wouldn't work correctly, showing no capabilities and making i
455
 
456
  == Upgrade Notice ==
457
 
 
 
 
458
  = 1.3.10 =
459
  * Improves performance slightly more and fixes potential issues with caching.
460
 
4
  Tags: access, access control, capability, capabilities, content, download, downloads, file, file access, files, group, groups, member, members, membership, memberships, paypal, permission, permissions, subscription, subscriptions, woocommerce
5
  Requires at least: 3.3
6
  Tested up to: 3.5.1
7
+ Stable tag: 1.3.11
8
  License: GPLv3
9
 
10
  Groups provides group-based user membership management, group-based capabilities and content access control.
151
  Users - group membership is managed from the standard Users admin view.
152
  Users are automatically added to the _Registered_ group. You can add multiple users to other groups here and also remove them.
153
 
154
+ ### Integration in user profiles: ###
155
+
156
+ Group memberships can be shown on the user profile page and edited by users who can *Administer groups*.
157
+
158
+ This option is disabled by default and can be enabled under *Groups > Options > User profiles*.
159
+
160
  ### Sections in the 'Groups' menu: ###
161
 
162
  #### Groups ####
175
  the *standard WordPress capabilities* but you can also define additional
176
  capabilities for your web-application.
177
 
178
+ Groups defines the `groups_read_post` capability by default which can be
179
  used to restrict access to certain posts or pages to groups (and users)
180
  with that capability only. Additional capabilities can be identified on the
181
  *Groups > Options* admin screen that may be used to limit access.
182
 
183
+ A user *must* be a member of a group that has the desired capability to restrict access. For example, in order to apply the `groups_read_post` capability, the user must belong to a group which has that capability assigned.
184
+
185
  (1) Assigning capabilities to users is not integrated in the user interface yet but can be done through API calls.
186
 
187
  #### Options ####
190
 
191
  Administrator overrides can be turned off.
192
 
193
+ ##### Access restrictions #####
194
+
195
+ Post types : Access restrictions can be enabled or disabled for standard (Post, Page and Media) and custom post types.
196
+ Capabilities : Here specific capabilities can be enabled or disabled to restrict access to posts. The standard `groups_read_post` capability is enabled by default.
197
+
198
+ Note that to apply an access restriction on a post, the user must belong to a group which has that capability.
199
+
200
+ ##### User profiles #####
201
+
202
+ Groups can be shown in user profiles, users who can *Administer groups* can edit group memberships on a user's profile page.
203
+
204
+ ##### Tree view #####
205
+
206
+ The tree view adds a menu item to the Groups menu which shows the group hierarchy.
207
+
208
  ##### Permissions #####
209
 
210
  For each role these permissions can be set:
335
  6. Create another post for *Red Members* and tick the *red* checkbox for that post.
336
  7. Assign a test user to any of the above groups, log in as that user and the post will be accessible.
337
 
338
+ = Are access restrictions for Custom Post Types supported? =
339
+
340
+ Yes. Access restrictions can be turned on or off for specific CPTs on the *Groups > Options* page.
341
+
342
+ = How can I show groups that users belong to on their profile page in the admin section? =
343
+
344
+ Go to *Groups > Options* and enable the option under *User profiles*.
345
+
346
  == Screenshots ==
347
 
348
  See also [Groups](http://www.itthinx.com/plugins/groups/)
358
 
359
  == Changelog ==
360
 
361
+ = 1.3.11 =
362
+ * Fix: Access restriction capabilities must be disjunctive.
363
+ * Added: List of groups can be shown in user profiles on the back end and group assignments can be edited by group admins.
364
+ * Improvement: Groups shown for users on the Users screen are sorted by name.
365
+
366
  = 1.3.10 =
367
  * Fix: Under certain conditions with caching involved, capabilities were not correctly retrieved. Thanks to Jason Kadlec who [reported the issue](http://wordpress.org/support/topic/nasty-error-with-latest-version).
368
  * Improvement: Related to the above fix, improved the way how *_deep properties are retrieved on cache misses, resulting in slightly better performance.
491
 
492
  == Upgrade Notice ==
493
 
494
+ = 1.3.11 =
495
+ * Fixes too restrictive access: the capabilities used to restrict access to posts should be disjunctive. Adds the option to show and edit group memberships in user profiles.
496
+
497
  = 1.3.10 =
498
  * Improves performance slightly more and fixes potential issues with caching.
499