PluginProbe
Groups – Memberships and Access Control / 4.7.1
Groups – Memberships and Access Control v4.7.1
4.7.1 4.7.0 4.6.0 4.5.0 4.4.0 4.3.0 trunk 1.0.0-beta-1 1.0.0-beta-2 1.0.0-beta-3 1.0.0-beta-3b 1.0.0-beta-3c 1.0.0-beta-3d 1.1.4 1.1.5 1.10.0 1.10.1 1.10.2 1.10.3 1.11.0 1.11.1 1.11.2 1.11.3 1.12.0 1.13.0 All 131 releases
← All changes | lib/admin/groups-admin-options.php +247 -149 1.10.14.7.1 View file →
@@ -23,21 +23,26 @@
23 23 exit;
24 24 }
25 25
26 26 /**
27 - * @var string options form nonce name
27 + * @var string GROUPS_ADMIN_OPTIONS_NONCE options form nonce name
28 28 */
29 29 define( 'GROUPS_ADMIN_OPTIONS_NONCE', 'groups-admin-nonce' );
30 30
31 31 /**
32 + * @var int GROUPS_SHOW_EXTENSIONS_BOX_INTERVAL 14 days in seconds
33 + */
34 +define( 'GROUPS_SHOW_EXTENSIONS_BOX_INTERVAL', 1209600 );
35 +
36 +/**
32 37 * Options admin screen.
33 38 */
34 39 function groups_admin_options() {
35 40
36 - global $wpdb, $wp_roles;
41 + global $wp_roles, $groups_version;
37 42
38 - if ( !current_user_can( GROUPS_ADMINISTER_OPTIONS ) ) {
39 - wp_die( __( 'Access denied.', GROUPS_PLUGIN_DOMAIN ) );
43 + if ( !Groups_User::current_user_can( GROUPS_ADMINISTER_OPTIONS ) ) {
44 + wp_die( esc_html__( 'Access denied.', 'groups' ) );
40 45 }
41 46
42 47 $is_sitewide_plugin = false;
43 48 if ( is_multisite() ) {
@@ -46,52 +51,32 @@
46 51 $is_sitewide_plugin = in_array( 'groups/groups.php', $active_sitewide_plugins );
47 52 }
48 53
49 54 $caps = array(
50 - GROUPS_ACCESS_GROUPS => __( 'Access Groups', GROUPS_PLUGIN_DOMAIN ),
51 - GROUPS_ADMINISTER_GROUPS => __( 'Administer Groups', GROUPS_PLUGIN_DOMAIN ),
52 - GROUPS_ADMINISTER_OPTIONS => __( 'Administer Groups plugin options', GROUPS_PLUGIN_DOMAIN ),
55 + GROUPS_ACCESS_GROUPS => __( 'Access Groups', 'groups' ),
56 + GROUPS_ADMINISTER_GROUPS => __( 'Administer Groups', 'groups' ),
57 + GROUPS_ADMINISTER_OPTIONS => __( 'Administer Groups plugin options', 'groups' ),
58 + GROUPS_RESTRICT_ACCESS => __( 'Restrict Access', 'groups' )
53 59 );
54 60
61 + $previous_legacy_enable = Groups_Options::get_option( GROUPS_LEGACY_ENABLE, GROUPS_LEGACY_ENABLE_DEFAULT );
62 +
55 63 //
56 64 // handle options form submission
57 65 //
58 - if ( isset( $_POST['submit'] ) ) {
59 - if ( wp_verify_nonce( $_POST[GROUPS_ADMIN_OPTIONS_NONCE], 'admin' ) ) {
66 + if ( isset( $_POST['submit'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
67 + if ( groups_verify_post_nonce( GROUPS_ADMIN_OPTIONS_NONCE, 'admin' ) ) {
60 68
61 - // admin override
62 - if ( empty( $_POST[GROUPS_ADMINISTRATOR_ACCESS_OVERRIDE] ) ) {
63 - $admin_override = false;
64 - } else {
65 - $admin_override = true;
69 + $post_types = get_post_types();
70 + $selected_post_types = groups_sanitize_post( 'add_meta_boxes' ) ?? array();
71 + $handle_post_types = array();
72 + foreach ( $post_types as $post_type ) {
73 + $handle_post_types[$post_type] = in_array( $post_type, $selected_post_types );
66 74 }
67 - // Don't move this to the plugin options, access will be faster
68 - add_option( GROUPS_ADMINISTRATOR_ACCESS_OVERRIDE, $admin_override ); // WP 3.3.1 : update alone wouldn't create the option when value is false
69 - update_option( GROUPS_ADMINISTRATOR_ACCESS_OVERRIDE, $admin_override );
75 + Groups_Post_Access::set_handles_post_types( $handle_post_types );
70 76
71 - $post_types_option = Groups_Options::get_option( Groups_Post_Access::POST_TYPES, array() );
72 - $post_types = get_post_types( array( 'public' => true ) );
73 - $selected_post_types = is_array( $_POST['add_meta_boxes'] ) ? $_POST['add_meta_boxes'] : array();
74 - foreach( $post_types as $post_type ) {
75 - $post_types_option[$post_type]['add_meta_box'] = in_array( $post_type, $selected_post_types );
76 - }
77 - Groups_Options::update_option( Groups_Post_Access::POST_TYPES, $post_types_option );
78 -
79 - $valid_read_caps = array( Groups_Post_Access::READ_POST_CAPABILITY );
80 - if ( !empty( $_POST[GROUPS_READ_POST_CAPABILITIES] ) ) {
81 - $read_caps = $_POST[GROUPS_READ_POST_CAPABILITIES];
82 - foreach( $read_caps as $read_cap ) {
83 - if ( $valid_cap = Groups_Capability::read( $read_cap ) ) {
84 - if ( !in_array( $valid_cap->capability, $valid_read_caps ) ) {
85 - $valid_read_caps[] = $valid_cap->capability;
86 - }
87 - }
88 - }
89 - }
90 - Groups_Options::update_option( Groups_Post_Access::READ_POST_CAPABILITIES, $valid_read_caps );
91 -
92 77 // tree view
93 - if ( !empty( $_POST[GROUPS_SHOW_TREE_VIEW] ) ) {
78 + if ( !empty( $_POST[GROUPS_SHOW_TREE_VIEW] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
94 79 Groups_Options::update_option( GROUPS_SHOW_TREE_VIEW, true );
95 80 } else {
96 81 Groups_Options::update_option( GROUPS_SHOW_TREE_VIEW, false );
97 82 }
@@ -96,9 +81,9 @@
96 81 Groups_Options::update_option( GROUPS_SHOW_TREE_VIEW, false );
97 82 }
98 83
99 84 // show in user profiles
100 - Groups_Options::update_option( GROUPS_SHOW_IN_USER_PROFILE, !empty( $_POST[GROUPS_SHOW_IN_USER_PROFILE] ) );
85 + Groups_Options::update_option( GROUPS_SHOW_IN_USER_PROFILE, !empty( $_POST[GROUPS_SHOW_IN_USER_PROFILE] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
101 86
102 87 // roles & capabilities
103 88 $rolenames = $wp_roles->get_names();
104 89 foreach ( $rolenames as $rolekey => $rolename ) {
@@ -103,10 +88,10 @@
103 88 $rolenames = $wp_roles->get_names();
104 89 foreach ( $rolenames as $rolekey => $rolename ) {
105 90 $role = $wp_roles->get_role( $rolekey );
106 91 foreach ( $caps as $capkey => $capname ) {
107 - $role_cap_id = $rolekey.'-'.$capkey;
108 - if ( !empty($_POST[$role_cap_id] ) ) {
92 + $role_cap_id = $rolekey . '-' . $capkey;
93 + if ( !empty( groups_sanitize_post( $role_cap_id ) ) ) {
109 94 $role->add_cap( $capkey );
110 95 } else {
111 96 $role->remove_cap( $capkey );
112 97 }
@@ -115,29 +100,32 @@
115 100 Groups_Controller::assure_capabilities();
116 101
117 102 if ( !$is_sitewide_plugin ) {
118 103 // delete data
119 - if ( !empty( $_POST['delete-data'] ) ) {
104 + if ( !empty( $_POST['delete-data'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
120 105 Groups_Options::update_option( 'groups_delete_data', true );
121 106 } else {
122 107 Groups_Options::update_option( 'groups_delete_data', false );
123 108 }
124 109 }
125 - Groups_Admin::add_message( __( 'Options saved.', GROUPS_PLUGIN_DOMAIN ) );
110 +
111 + // legacy enable ?
112 + if ( !empty( $_POST[GROUPS_LEGACY_ENABLE] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
113 + Groups_Options::update_option( GROUPS_LEGACY_ENABLE, true );
114 + } else {
115 + Groups_Options::update_option( GROUPS_LEGACY_ENABLE, false );
116 + }
117 +
118 + Groups_Admin::add_message( __( 'Options saved.', 'groups' ) );
126 119 }
127 120 }
128 121
129 122 echo '<div class="groups-options wrap">';
130 123
131 - echo
132 - '<h1>' .
133 - __( 'Groups Options', GROUPS_PLUGIN_DOMAIN ) .
134 - '</h1>';
124 + echo '<h1>' . esc_html__( 'Groups Options', 'groups' ) . '</h1>';
135 125
136 - echo Groups_Admin::render_messages();
126 + echo Groups_Admin::render_messages(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
137 127
138 - $admin_override = get_option( GROUPS_ADMINISTRATOR_ACCESS_OVERRIDE, GROUPS_ADMINISTRATOR_ACCESS_OVERRIDE_DEFAULT );
139 -
140 128 $show_tree_view = Groups_Options::get_option( GROUPS_SHOW_TREE_VIEW, GROUPS_SHOW_TREE_VIEW_DEFAULT );
141 129 $show_in_user_profile = Groups_Options::get_option( GROUPS_SHOW_IN_USER_PROFILE, GROUPS_SHOW_IN_USER_PROFILE_DEFAULT );
142 130
143 131 $rolenames = $wp_roles->get_names();
@@ -144,13 +132,13 @@
144 132 $caps_table = '<table class="groups-permissions">';
145 133 $caps_table .= '<thead>';
146 134 $caps_table .= '<tr>';
147 135 $caps_table .= '<td class="role">';
148 - $caps_table .= __( 'Role', GROUPS_PLUGIN_DOMAIN );
136 + $caps_table .= esc_html__( 'Role', 'groups' );
149 137 $caps_table .= '</td>';
150 138 foreach ( $caps as $cap ) {
151 139 $caps_table .= '<td class="cap">';
152 - $caps_table .= $cap;
140 + $caps_table .= esc_html( $cap );
153 141 $caps_table .= '</td>';
154 142 }
155 143
156 144 $caps_table .= '</tr>';
@@ -159,9 +147,9 @@
159 147 foreach ( $rolenames as $rolekey => $rolename ) {
160 148 $role = $wp_roles->get_role( $rolekey );
161 149 $caps_table .= '<tr>';
162 150 $caps_table .= '<td>';
163 - $caps_table .= translate_user_role( $rolename );
151 + $caps_table .= esc_html( translate_user_role( $rolename ) );
164 152 $caps_table .= '</td>';
165 153 foreach ( $caps as $capkey => $capname ) {
166 154
167 155 if ( $role->has_cap( $capkey ) ) {
@@ -171,9 +159,9 @@
171 159 }
172 160
173 161 $caps_table .= '<td class="checkbox">';
174 162 $role_cap_id = $rolekey.'-'.$capkey;
175 - $caps_table .= '<input type="checkbox" name="' . $role_cap_id . '" id="' . $role_cap_id . '" ' . $checked . '/>';
163 + $caps_table .= '<input type="checkbox" name="' . esc_attr( $role_cap_id ) . '" id="' . esc_attr( $role_cap_id ) . '" ' . $checked . '/>';
176 164 $caps_table .= '</td>';
177 165 }
178 166 $caps_table .= '</tr>';
179 167 }
@@ -181,141 +169,218 @@
181 169 $caps_table .= '</table>';
182 170
183 171 $delete_data = Groups_Options::get_option( 'groups_delete_data', false );
184 172
185 - if ( isset( $_GET['dismiss-groups-extensions-box'] ) && isset( $_GET['groups-extensions-box-nonce'] ) && wp_verify_nonce( $_GET['groups-extensions-box-nonce'], 'dismiss-box' ) ) {
186 - Groups_Options::update_user_option( 'show-extensions-box', false );
173 + if ( groups_sanitize_get( 'dismiss-groups-extensions-box' ) && groups_verify_get_nonce( 'groups-extensions-box-nonce', 'dismiss-box' ) ) {
174 + Groups_Options::update_user_option( 'show-extensions-box', time() );
187 175 }
188 176 $extensions_box = '';
189 - if ( Groups_Options::get_user_option( 'show-extensions-box', true ) ) {
190 - $dismiss_url = wp_nonce_url( add_query_arg( 'dismiss-groups-extensions-box', '1', admin_url( 'admin.php?page=groups-admin-options' ) ), 'dismiss-box', 'groups-extensions-box-nonce' );
191 - $extensions_box =
192 - '<div id="groups-extensions-box">' .
193 - __( 'Enhanced functionality is available via official <a href="http://www.itthinx.com/shop/">Extensions</a> for Groups.', GROUPS_PLUGIN_DOMAIN ) .
194 - sprintf( '<a class="close" href="%s">x</a>', esc_url( $dismiss_url ) ) .
195 - '</div>';
177 + $show_extensions_box = Groups_Options::get_user_option( 'show-extensions-box', 0 );
178 + if ( ( time() - $show_extensions_box ) > GROUPS_SHOW_EXTENSIONS_BOX_INTERVAL ) {
179 + // $dismiss_url = wp_nonce_url( add_query_arg( 'dismiss-groups-extensions-box', '1', admin_url( 'admin.php?page=groups-admin-options' ) ), 'dismiss-box', 'groups-extensions-box-nonce' );
180 + $extensions_box = '<div id="groups-extensions-box">';
181 + // $extensions_box .= sprintf( '<a title="%s" class="close" href="%s"></a>', esc_attr_x( 'Dismiss', 'title of dismiss notice link', 'groups' ), esc_url( $dismiss_url ) );
182 + $extensions_box .= '<h3>';
183 + $extensions_box .= esc_html__( 'Your support matters!', 'groups' );
184 + $extensions_box .= '</h3>';
185 + $extensions_box .= '<p>';
186 + $extensions_box .= sprintf(
187 + /* translators: 1: opening tag 2: closing tag */
188 + esc_html__( 'Enhanced functionality is available via official %1$sExtensions%2$s for Groups.', 'groups' ),
189 + '<a href="https://www.itthinx.com/shop/">',
190 + '</a>'
191 + );
192 + $extensions_box .= '</p>';
193 + $extensions_box .= '<p>';
194 + $extensions_box .= esc_html__( 'By getting an official extension, you fund the work that is necessary to maintain and improve Groups.', 'groups' );
195 + $extensions_box .= '</p>';
196 + $extensions_box .= '</div>';
196 197 }
197 198
199 + require_once GROUPS_ADMIN_LIB . '/class-groups-admin-bitcoin.php';
200 + $bitcoin_box = Groups_Admin_Bitcoin::get_groups_bitcoin_box( array( 'where' => 'options' ) );
201 +
198 202 //
199 203 // print the options form
200 204 //
201 205 echo
202 206 '<form action="" name="options" method="post">' .
207 + '<div>' .
203 208
204 209 '<p>' .
205 - '<input class="button button-primary" type="submit" name="submit" value="' . __( 'Save', GROUPS_PLUGIN_DOMAIN ) . '"/>' .
206 - $extensions_box .
207 - '</p>' .
210 + '<input class="button button-primary" type="submit" name="submit" value="' . esc_attr__( 'Save', 'groups' ) . '"/>' .
211 + $bitcoin_box . // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
212 + $extensions_box . // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
213 + '</p>';
208 214
209 - '<div>' .
210 - '<h2>' . __( 'Administrator Access Override', GROUPS_PLUGIN_DOMAIN ) . '</h2>' .
211 - '<p>' .
212 - '<label>' .
213 - '<input name="' . GROUPS_ADMINISTRATOR_ACCESS_OVERRIDE . '" type="checkbox" ' . ( $admin_override ? 'checked="checked"' : '' ) . '/>' .
214 - __( 'Administrators override all access permissions derived from Groups capabilities.', GROUPS_PLUGIN_DOMAIN ) .
215 - '</label>' .
216 - '</p>';
215 + if ( _groups_admin_override() ) {
216 + echo
217 + '<h2 style="color:red">' .
218 + esc_html__( 'Administrator Access Override', 'groups' ) .
219 + '</h2>' .
220 + '<p>' .
221 + esc_html__( 'Administrators override all access permissions derived from Groups capabilities.', 'groups' ) .
222 + '</p>' .
223 + '<p>' .
224 + wp_kses_post( __( 'To disable, do not define the constant <code>GROUPS_ADMINISTRATOR_OVERRIDE</code> or set it to <code>false</code>.', 'groups' ) ) .
225 + '</p>' .
226 + '<p>' .
227 + wp_kses_post( __( 'Enabling this on production sites is <strong>not</strong> recommended.', 'groups' ) ) .
228 + '</p>';
229 + }
217 230
218 - echo '<h2>' . __( 'Access restricions', GROUPS_PLUGIN_DOMAIN ) . '</h2>';
231 + echo '<h2>';
232 + echo esc_html__( 'Access restricions', 'groups' );
233 + echo '</h2>';
219 234
220 - echo '<h3>' . __( 'Post types', GROUPS_PLUGIN_DOMAIN ) . '</h3>';
235 + echo '<h3>';
236 + echo esc_html__( 'Post types', 'groups' );
237 + echo '</h3>';
221 238
222 - echo
223 - '<p class="description">' . __( 'Show access restrictions for these post types.', GROUPS_PLUGIN_DOMAIN ) . '</p>';
239 + echo '<p class="description">';
240 + echo esc_html__( 'Show access restrictions for these post types.', 'groups' ); // @todo change wording to '...handles access...' ?
241 + echo '</p>';
224 242
225 - $post_types_option = Groups_Options::get_option( Groups_Post_Access::POST_TYPES, array() );
226 - $post_types = get_post_types( array( 'public' => true ) );
243 + $post_type_objects = get_post_types( array(), 'objects' );
244 + uasort( $post_type_objects, 'groups_admin_options_compare_post_types' );
245 +
227 246 echo '<ul>';
228 - foreach( $post_types as $post_type ) {
229 - $post_type_object = get_post_type_object( $post_type );
247 + foreach ( $post_type_objects as $post_type => $post_type_object ) {
230 248 echo '<li>';
231 249 echo '<label>';
232 250 $label = $post_type;
233 251 $labels = isset( $post_type_object->labels ) ? $post_type_object->labels : null;
234 252 if ( ( $labels !== null ) && isset( $labels->singular_name ) ) {
235 - $label = __( $labels->singular_name );
253 + $label = $labels->singular_name; // this is already translated
236 254 }
237 - $checked = ( !isset( $post_types_option[$post_type]['add_meta_box'] ) || $post_types_option[$post_type]['add_meta_box'] ) ? ' checked="checked" ' : '';
238 - echo '<input name="add_meta_boxes[]" type="checkbox" value="' . esc_attr( $post_type ) . '" ' . $checked . '/>';
239 - echo $label;
255 + $checked = Groups_Post_Access::handles_post_type( $post_type ) ? ' checked="checked" ' : '';
256 + echo '<input name="add_meta_boxes[]" type="checkbox" value="' . esc_attr( $post_type ) . '" ' . $checked . '/>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
257 + $is_public = isset( $post_type_object->public ) && $post_type_object->public;
258 + echo $is_public ? '<strong>' : '';
259 + echo esc_html( $label );
260 + echo $is_public ? '</strong>' : '';
261 + if ( $post_type != $label ) {
262 + echo ' ';
263 + echo '<code><small>';
264 + echo esc_html( $post_type );
265 + echo '</small></code>';
266 + }
240 267 echo '</label>';
241 268 echo '</li>';
242 269 }
243 270 echo '<ul>';
244 - echo
245 - '<p class="description">' .
246 - __( 'This determines for which post types access restriction settings are offered.', GROUPS_PLUGIN_DOMAIN ) . '<br/>' .
247 - __( 'Disabling this setting for a post type does not remove existing access restrictions on individual posts of that type.', GROUPS_PLUGIN_DOMAIN ) . '<br/>' .
248 - '</p>';
271 + echo '<p class="description">';
272 + esc_html_e( 'This determines for which post types access restriction settings are offered.', 'groups' );
273 + echo ' ';
274 + esc_html_e( 'Disabling this setting for a post type also disables existing access restrictions on individual posts of that type.', 'groups' );
275 + echo ' ';
276 + esc_html_e( 'Some post types shown may not offer access restrictions even though they appear enabled here.', 'groups' );
277 + echo '</p>';
249 278
250 -
251 - echo '<h3>' . __( 'Capabilities', GROUPS_PLUGIN_DOMAIN ) . '</h3>';
252 -
253 - echo '<p class="description">' .
254 - __( 'Include these capabilities to enforce read access on posts. The selected capabilities will be offered to restrict access to posts.', GROUPS_PLUGIN_DOMAIN ) .
255 - '</p>';
256 -
257 - $capability_table = _groups_get_tablename( "capability" );
258 - $capabilities = $wpdb->get_results( "SELECT * FROM $capability_table ORDER BY capability" );
259 - $applicable_read_caps = Groups_Options::get_option( Groups_Post_Access::READ_POST_CAPABILITIES, array( Groups_Post_Access::READ_POST_CAPABILITY ) );
260 - echo '<div class="select-capability-container" style="width:62%;">';
261 - printf( '<select class="select capability" name="%s" multiple="multiple">', GROUPS_READ_POST_CAPABILITIES . '[]' );
262 - foreach( $capabilities as $capability ) {
263 - $selected = in_array( $capability->capability, $applicable_read_caps ) ? ' selected="selected" ' : '';
264 - if ( $capability->capability == Groups_Post_Access::READ_POST_CAPABILITY ) {
265 - $selected .= ' disabled="disabled" ';
266 - }
267 - printf( '<option value="%s" %s>%s</option>', esc_attr( $capability->capability_id ), $selected, wp_filter_nohtml_kses( $capability->capability ) );
268 - }
269 - echo '</select>';
270 - echo '</div>';
271 -
272 - echo Groups_UIE::render_select( '.select.capability' );
273 -
274 279 echo
275 - '<h2>' . __( 'User profiles', GROUPS_PLUGIN_DOMAIN ) . '</h2>' .
280 + '<h2>' . esc_html__( 'User profiles', 'groups' ) . '</h2>' .
276 281 '<p>' .
277 282 '<label>' .
278 - '<input name="' . GROUPS_SHOW_IN_USER_PROFILE . '" type="checkbox" ' . ( $show_in_user_profile ? 'checked="checked"' : '' ) . '/>' .
279 - __( 'Show groups in user profiles.', GROUPS_PLUGIN_DOMAIN ) .
283 + '<input name="' . GROUPS_SHOW_IN_USER_PROFILE . '" type="checkbox" ' . ( $show_in_user_profile ? 'checked="checked"' : '' ) . '/>' . // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
284 + esc_html__( 'Show groups in user profiles.', 'groups' ) .
280 285 '</label>' .
281 286 '</p>';
282 287
283 288 echo
284 - '<h2>' . __( 'Tree view', GROUPS_PLUGIN_DOMAIN ) . '</h2>' .
289 + '<h2>' . esc_html__( 'Tree view', 'groups' ) . '</h2>' .
285 290 '<p>' .
286 291 '<label>' .
287 - '<input name="' . GROUPS_SHOW_TREE_VIEW . '" type="checkbox" ' . ( $show_tree_view ? 'checked="checked"' : '' ) . '/>' .
288 - __( 'Show the Groups tree view.', GROUPS_PLUGIN_DOMAIN ) .
292 + '<input name="' . GROUPS_SHOW_TREE_VIEW . '" type="checkbox" ' . ( $show_tree_view ? 'checked="checked"' : '' ) . '/>' . // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
293 + esc_html__( 'Show the Groups tree view.', 'groups' ) .
289 294 '</label>' .
290 295 '</p>';
291 296
292 297 echo
293 - '<h2>' . __( 'Permissions', GROUPS_PLUGIN_DOMAIN ) . '</h2>' .
294 - '<p>' . __( 'These permissions apply to Groups management. They do not apply to access permissions derived from Groups capabilities.', GROUPS_PLUGIN_DOMAIN ) . '</p>' .
295 - $caps_table .
298 + '<h2>' . esc_html__( 'Permissions', 'groups' ) . '</h2>' .
299 + '<p>' . esc_html__( 'These permissions apply to Groups management. They do not apply to access permissions derived from Groups capabilities.', 'groups' ) . '</p>' .
300 + $caps_table . // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
296 301 '<p class="description">' .
297 - __( 'A minimum set of permissions will be preserved.', GROUPS_PLUGIN_DOMAIN ) .
302 + esc_html__( 'A minimum set of permissions will be preserved.', 'groups' ) .
298 303 '<br/>' .
299 - __( 'If you lock yourself out, please ask an administrator to help.', GROUPS_PLUGIN_DOMAIN ) .
304 + esc_html__( 'If you lock yourself out, please ask an administrator to help.', 'groups' ) .
300 305 '</p>';
301 306 if ( !$is_sitewide_plugin ) {
302 307 echo
303 - '<h2>' . __( 'Deactivation and data persistence', GROUPS_PLUGIN_DOMAIN ) . '</h2>' .
308 + '<h2>' . esc_html__( 'Deactivation and data persistence', 'groups' ) . '</h2>' .
304 309 '<p>' .
305 310 '<label>' .
306 311 '<input name="delete-data" type="checkbox" ' . ( $delete_data ? 'checked="checked"' : '' ) . '/>' .
307 - __( 'Delete all Groups plugin data on deactivation', GROUPS_PLUGIN_DOMAIN ) .
312 + esc_html__( 'Delete all Groups plugin data on deactivation', 'groups' ) .
308 313 '</label>' .
309 314 '</p>' .
310 315 '<p class="description warning">' .
311 - __( 'CAUTION: If this option is active while the plugin is deactivated, ALL plugin settings and data will be DELETED. If you are going to use this option, now would be a good time to make a backup. By enabling this option you agree to be solely responsible for any loss of data or any other consequences thereof.', GROUPS_PLUGIN_DOMAIN ) .
316 + esc_html__( 'CAUTION: If this option is active while the plugin is deactivated, ALL plugin settings and data will be DELETED. If you are going to use this option, now would be a good time to make a backup. By enabling this option you agree to be solely responsible for any loss of data or any other consequences thereof.', 'groups' ) .
312 317 '</p>';
313 318 }
319 +
320 + $groups_legacy_enable = Groups_Options::get_option( GROUPS_LEGACY_ENABLE, GROUPS_LEGACY_ENABLE_DEFAULT );
321 + if (
322 + defined( 'GROUPS_SHOW_LEGACY_SETTINGS' ) && GROUPS_SHOW_LEGACY_SETTINGS === true || $groups_legacy_enable
323 + ) {
324 + echo '<h2>' . esc_html__( 'Legacy Settings', 'groups' ) . '</h2>';
325 + echo '<p>' .
326 + '<label>' .
327 + '<input name="' . esc_attr( GROUPS_LEGACY_ENABLE ) . '" type="checkbox" ' . ( $groups_legacy_enable ? 'checked="checked"' : '' ) . '/>' . // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
328 + esc_html__( 'Enable legacy access control based on capabilities.', 'groups' ) .
329 + '</label>' .
330 + '</p>';
331 + if ( $groups_legacy_enable ) {
332 + require_once GROUPS_LEGACY_LIB . '/admin/groups-admin-options-legacy.php';
333 + do_action( 'groups_admin_options_legacy', $groups_legacy_enable !== $previous_legacy_enable );
334 + }
335 +
336 + $legacy_enabled = Groups_Options::get_option( GROUPS_LEGACY_ENABLE );
337 + echo '<h3>';
338 + /* translators: version number */
339 + printf( esc_html__( 'Switching to Groups %s', 'groups' ), esc_html( $groups_version ) );
340 + echo '</h3>';
341 + echo '<p>';
342 + /* translators: version number */
343 + printf( esc_html__( 'Groups %s features a simpler model for access restrictions based on groups instead of capabilities used in Groups 1.x.', 'groups' ), esc_html( $groups_version ) );
344 + echo ' ';
345 + esc_html_e( 'To put it simple, previously you would have used capabilities to restrict access to posts and now you simply use groups.', 'groups' );
346 + echo ' ';
347 + esc_html_e( 'To make it easier to transition to the new model for those who migrate from a previous version, we have included legacy access control based on capabilities.', 'groups' );
348 + echo '</p>';
349 + echo '<div class="indent">';
350 + echo '<p>';
351 + esc_html_e( 'The following is only of interest if you have upgraded from Groups 1.x:', 'groups' );
352 + echo '<br/>';
353 + if ( $legacy_enabled ) {
354 + esc_html_e( 'You are running the system with legacy access control based on capabilities enabled.', 'groups' );
355 + echo ' ';
356 + esc_html_e( 'This means that if you had access restrictions in place that were based on capabilities, your entries will still be protected.', 'groups' );
357 + } else {
358 + esc_html_e( 'You are running the system with legacy access control based on capabilities disabled.', 'groups' );
359 + echo ' ';
360 + esc_html_e( 'This could be important!', 'groups' );
361 + echo ' ';
362 + esc_html_e( 'If you had any access restrictions in place based on capabilities, the entries will now be unprotected, unless you enable legacy access restrictions or place appropriate access restrictions based on groups on the desired entries.', 'groups' );
363 + }
364 + echo '</p>';
365 + echo '<p>';
366 + esc_html_e( 'If you would like to switch to access restrictions based on groups (recommended) instead of capabilities, you can easily do so by setting the appropriate groups on your protected posts, pages and other entries to restrict access.', 'groups' );
367 + echo ' ';
368 + esc_html_e( 'Once you have adjusted your access restrictions based on groups, you can disable legacy access control.', 'groups' );
369 + echo ' ';
370 + echo sprintf(
371 + /* translators: documentation pages link */
372 + esc_html__( 'Please refer to the %s for details on how to switch to and use the new access restrictions.', 'groups' ),
373 + sprintf( '<a target="_blank" href="https://docs.itthinx.com/document/groups/">%s</a>', esc_html__( 'Documentation', 'groups' ) )
374 + );
375 + echo '</p>';
376 + echo '</div>'; // .indent
377 + }
378 +
314 379 echo
315 380 '<p>' .
316 - wp_nonce_field( 'admin', GROUPS_ADMIN_OPTIONS_NONCE, true, false ) .
317 - '<input class="button button-primary" type="submit" name="submit" value="' . __( 'Save', GROUPS_PLUGIN_DOMAIN ) . '"/>' .
381 + wp_nonce_field( 'admin', GROUPS_ADMIN_OPTIONS_NONCE, true, false ) . // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
382 + '<input class="button button-primary" type="submit" name="submit" value="' . esc_attr__( 'Save', 'groups' ) . '"/>' .
318 383 '</p>' .
319 384 '</div>' .
320 385 '</form>';
321 386
@@ -321,26 +386,24 @@
321 386
322 387 echo '</div>'; // .groups-options
323 388 }
324 389
390 +/**
391 + * Network administration options.
392 + */
325 393 function groups_network_admin_options() {
326 394
327 - if ( !current_user_can( GROUPS_ADMINISTER_OPTIONS ) ) {
328 - wp_die( __( 'Access denied.', GROUPS_PLUGIN_DOMAIN ) );
395 + if ( !Groups_User::current_user_can( GROUPS_ADMINISTER_OPTIONS ) ) {
396 + wp_die( esc_html__( 'Access denied.', 'groups' ) );
329 397 }
330 398
331 - echo
332 - '<div>' .
333 - '<h1>' .
334 - __( 'Groups network options', GROUPS_PLUGIN_DOMAIN ) .
335 - '</h1>' .
336 - '</div>';
399 + echo '<h1>' . esc_html__( 'Groups network options', 'groups' ) . '</h1>';
337 400
338 401 // handle options form submission
339 - if ( isset( $_POST['submit'] ) ) {
340 - if ( wp_verify_nonce( $_POST[GROUPS_ADMIN_OPTIONS_NONCE], 'admin' ) ) {
402 + if ( isset( $_POST['submit'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
403 + if ( groups_verify_post_nonce( GROUPS_ADMIN_OPTIONS_NONCE, 'admin' ) ) {
341 404 // delete data
342 - if ( !empty( $_POST['delete-data'] ) ) {
405 + if ( !empty( $_POST['delete-data'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
343 406 Groups_Options::update_option( 'groups_network_delete_data', true );
344 407 } else {
345 408 Groups_Options::update_option( 'groups_network_delete_data', false );
346 409 }
@@ -352,19 +415,54 @@
352 415 // options form
353 416 echo
354 417 '<form action="" name="options" method="post">' .
355 418 '<div>' .
356 - '<h2>' . __( 'Network deactivation and data persistence', GROUPS_PLUGIN_DOMAIN ) . '</h2>' .
419 + '<h2>' . esc_html__( 'Network deactivation and data persistence', 'groups' ) . '</h2>' .
357 420 '<p>' .
421 + '<label>' .
358 422 '<input name="delete-data" type="checkbox" ' . ( $delete_data ? 'checked="checked"' : '' ) . '/>' .
359 - '<label for="delete-data">' . __( 'Delete all Groups plugin data for ALL sites on network deactivation', GROUPS_PLUGIN_DOMAIN ) . '</label>' .
423 + ' ' .
424 + esc_html__( 'Delete all Groups plugin data for ALL sites on network deactivation', 'groups' ) .
425 + '</label>' .
360 426 '</p>' .
361 427 '<p class="description warning">' .
362 - __( 'CAUTION: If this option is active while the plugin is deactivated, ALL plugin settings and data will be DELETED for <strong>all sites</strong>. If you are going to use this option, now would be a good time to make a backup. By enabling this option you agree to be solely responsible for any loss of data or any other consequences thereof.', GROUPS_PLUGIN_DOMAIN ) .
428 + wp_kses_post( __( 'CAUTION: If this option is active while the plugin is deactivated, ALL plugin settings and data will be DELETED for <strong>all sites</strong>. If you are going to use this option, now would be a good time to make a backup. By enabling this option you agree to be solely responsible for any loss of data or any other consequences thereof.', 'groups' ) ) .
363 429 '</p>' .
364 430 '<p>' .
365 - wp_nonce_field( 'admin', GROUPS_ADMIN_OPTIONS_NONCE, true, false ) .
366 - '<input type="submit" name="submit" value="' . __( 'Save', GROUPS_PLUGIN_DOMAIN ) . '"/>' .
431 + wp_nonce_field( 'admin', GROUPS_ADMIN_OPTIONS_NONCE, true, false ) . // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
432 + '<input class="button button-primary" type="submit" name="submit" value="' . esc_attr__( 'Save', 'groups' ) . '"/>' .
367 433 '</p>' .
368 434 '</div>' .
369 435 '</form>';
370 -}
436 +}
437 +
438 +/**
439 + * Compare two post types, considering those that have $public and/or $show_ui true as coming first.
440 + *
441 + * @param object $o1
442 + * @param object $o2
443 + *
444 + * @return int
445 + */
446 +function groups_admin_options_compare_post_types( $o1, $o2 ) {
447 + $name_1 = isset( $o1->name ) ? $o1->name : '';
448 + $name_2 = isset( $o2->name ) ? $o2->name : '';
449 + $public_1 = isset( $o1->public ) && $o1->public;
450 + $public_2 = isset( $o2->public ) && $o2->public;
451 + $show_ui_1 = isset( $o1->show_ui ) && $o1->show_ui;
452 + $show_ui_2 = isset( $o2->show_ui ) && $o2->show_ui;
453 + $n1 = 0;
454 + $n2 = 0;
455 + if ( $public_1 ) {
456 + $n1--;
457 + }
458 + if ( $show_ui_1 ) {
459 + $n1--;
460 + }
461 + if ( $public_2 ) {
462 + $n2--;
463 + }
464 + if ( $show_ui_2 ) {
465 + $n2--;
466 + }
467 + return ( $n1 - $n2 ) * 10 + strcmp( $name_1, $name_2 );
468 +}