WordPress Access Control - Version 2.0

Version Description

  • Added the ability to mark pages as non-members only
  • Added the ability to restrict pages to specific roles
  • Added the ability to set the redirect URL for users with incorrect permissions
Download this release

Release Info

Developer brandon.wamboldt
Plugin Icon wp plugin WordPress Access Control
Version 2.0
Comparing to
See all releases

Version 2.0

Files changed (4) hide show
  1. readme.txt +100 -0
  2. screenshot-1.png +0 -0
  3. screenshot-2.png +0 -0
  4. wordpress-access-control.php +396 -0
readme.txt ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === WordPress Access Control ===
2
+ Contributors: brandon.wamboldt
3
+ Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=Y398QNA6FM9TA
4
+ Tags: members, only, plugin, restricted, access, menus, 3.0, wp_nav_menu, nonmembers
5
+ Requires at least: 2.9
6
+ Tested up to: 3.1
7
+ Stable tag: 2.0
8
+
9
+ Restrict pages to members, nonmembers or specific roles and still add to navigation
10
+
11
+ == Description ==
12
+
13
+ **Fully supports PHP4, wp_nav_menu, wp_page_menu, wp_list_pages and much more automatically!**
14
+
15
+ This plugin allows you to mark a page as "Members Only" or "Non-members Only", restrict pages to specific user roles, redirect users without proper permissions to a specific URL and you can add these pages to WordPress navigation menus. They will only appear to users with the correct access. This allows you to have a members only section for your logged in users and still have it in your navigation.
16
+
17
+ This plugin is designed for people using WordPress as a CMS. It's extremely easy to use. You install the plugin, and activate it. Whenever you create or edit a page there is are controls in the right sidebar
18
+
19
+ This plugin now fully supports wp_nav_menu and wp_page_menu for older sites, so it should be compatible with older versions of WordPress, as well as wp_list_pages for certain themes.
20
+
21
+ It automatically sets the walker class to the one we custom made so theme developers don't need to do anything
22
+
23
+ == Installation ==
24
+
25
+ Installation is very simple:
26
+
27
+ 1. Upload `wordpress-access-control/` to the `/wp-content/plugins/` directory
28
+ 2. Activate the plugin through the 'Plugins' menu in WordPress
29
+ 3. You can now go to a page and use the controls.
30
+
31
+ == Frequently Asked Questions ==
32
+
33
+ **I get a PHP error when I try to activate your plugin**
34
+
35
+ This was caused by PHP4, which is now supported in version 1.4
36
+
37
+ == Screenshots ==
38
+
39
+ 1. The meta box added by this plugin
40
+ 2. The members only expanded dialog
41
+
42
+ == Changelog ==
43
+
44
+ = 2.0 =
45
+ * Added the ability to mark pages as non-members only
46
+ * Added the ability to restrict pages to specific roles
47
+ * Added the ability to set the redirect URL for users with incorrect permissions
48
+
49
+ = 1.6.4 =
50
+ * Fixed a problem with certain themes that use wp_list_pages as my plugin didn't affect that function. It does now, as we hook into get_pages. Also updated some of the code to better reflect WordPress coding standards
51
+
52
+ = 1.6.3 =
53
+ * Fixed a problem in pre WordPress 3 instances where a PHP error is generated due to lack of the Walker_Nav_Menu class
54
+
55
+ = 1.6.2 =
56
+ * Fixed (X)HTML validation errors caused by an empty ul which could occur if all items in a submenu were members only but the parent element was not.
57
+
58
+ = 1.6 =
59
+ * Fixed a bug where third level menu items with members only attributes would break the HTML/menu
60
+
61
+ = 1.5 =
62
+ * Fixed an error where submenus would still be generated if the parent was marked as members only. This has been fixed.
63
+
64
+ = 1.4 =
65
+ * Added support for PHP4
66
+
67
+ = 1.3 =
68
+ * Added support for wp_page_menu
69
+
70
+ = 1.2 =
71
+ * Added a filter which catches a fallback to wp_page_menu and removes our walker class from the arguments list
72
+
73
+ = 1.1 =
74
+ * Added a filter which removed the need to change the wp_nav_menu commands
75
+
76
+ = 1.0 =
77
+ * Initial Version
78
+
79
+ == Upgrade Notice ==
80
+
81
+ = 1.6.4 =
82
+ * Fixed several bugs including adding support for wp_list_pages
83
+
84
+ = 1.6 =
85
+ * Fixed a bug with third level menu items
86
+
87
+ = 1.5 =
88
+ * Fixed a bug with submenus and the parent being members only
89
+
90
+ = 1.4 =
91
+ Now supports PHP 4
92
+
93
+ = 1.3 =
94
+ Full support for wp_page_menu!
95
+
96
+ = 1.2 =
97
+ Fixes the code so it no longer degrades terribly when no nav menu is available
98
+
99
+ = 1.1 =
100
+ Increases compatibility and ease of use by removing the need to change theme file
screenshot-1.png ADDED
Binary file
screenshot-2.png ADDED
Binary file
wordpress-access-control.php ADDED
@@ -0,0 +1,396 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Plugin Name: WordPress Access Control
4
+ * Plugin URI: http://brandonwamboldt.ca/plugins/members-only-menu-plugin/
5
+ * Author: Brandon Wamboldt
6
+ * Author URI: http://brandonwamboldt.ca/
7
+ * Version: 2.0
8
+ * Description: Allows you to limit access to pages to members, non-members or specific roles, having unauthorized users redirected to the login page or a specified URL. Pages can still be added to WordPress navigation menus and will only show up for users with the required access.
9
+ */
10
+
11
+ add_action( 'wp', array( 'WordPressAccessControl', 'check_for_members_only' ) );
12
+ add_action( 'wp', array( 'WordPressAccessControl', 'check_for_nonmembers_only' ) );
13
+ add_action( 'add_meta_boxes', array( 'WordPressAccessControl', 'add_wp_access_meta_boxes' ) );
14
+ add_action( 'save_post', array( 'WordPressAccessControl', 'save_postdata' ) );
15
+
16
+ add_filter( 'get_pages', array( 'WordPressAccessControl', 'get_pages' ) );
17
+
18
+ // We check to see if the class exists because it isn't part of pre WordPress 3 systems
19
+ if ( class_exists( 'Walker_Nav_Menu' ) ) {
20
+ add_filter( 'wp_nav_menu_args', array( 'WordPressAccessControl', 'wp_nav_menu_args' ) );
21
+
22
+ /**
23
+ * A custom walker that checks our conditions to make sure the user has
24
+ * permission to view the page linked to from the menu item
25
+ *
26
+ * @author Brandon Wamboldt
27
+ * @package WordPress
28
+ * @subpackage WordPressAccessControl
29
+ */
30
+ class WPAC_Nav_Menu_Walker extends Walker_Nav_Menu
31
+ {
32
+ var $in_private = false;
33
+ var $private_lvl = 0;
34
+
35
+ function start_lvl( & $output, $depth )
36
+ {
37
+ if ( ! $this->in_private ) {
38
+ $indent = str_repeat( ' ', $depth );
39
+ $output .= "\n$indent<ul class=\"sub-menu\"><li style='display:none;'></li>\n";
40
+ }
41
+ }
42
+
43
+ function end_lvl( & $output, $depth )
44
+ {
45
+ if ( ! $this->in_private ) {
46
+ $indent = str_repeat( ' ', $depth );
47
+ $output .= "$indent</ul>\n";
48
+ }
49
+ }
50
+
51
+ function start_el( & $output, $item, $depth, $args )
52
+ {
53
+ global $wp_query;
54
+
55
+ if ( WordPressAccessControl::check_conditions( $item->object_id ) ) {
56
+ if ( ! $this->in_private ) {
57
+ $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
58
+
59
+ $class_names = $value = '';
60
+
61
+ $classes = empty( $item->classes ) ? array() : (array) $item->classes;
62
+
63
+ $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) );
64
+ $class_names = ' class="' . esc_attr( $class_names ) . '"';
65
+
66
+ $output .= $indent . '<li id="menu-item-'. $item->ID . '"' . $value . $class_names .'>';
67
+
68
+ $attributes = ! empty( $item->attr_title ) ? ' title="' . esc_attr( $item->attr_title ) .'"' : '';
69
+ $attributes .= ! empty( $item->target ) ? ' target="' . esc_attr( $item->target ) .'"' : '';
70
+ $attributes .= ! empty( $item->xfn ) ? ' rel="' . esc_attr( $item->xfn ) .'"' : '';
71
+ $attributes .= ! empty( $item->url ) ? ' href="' . esc_attr( $item->url ) .'"' : '';
72
+
73
+ $item_output = $args->before;
74
+ $item_output .= '<a'. $attributes .'>';
75
+ $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
76
+ $item_output .= '</a>';
77
+ $item_output .= $args->after;
78
+
79
+ $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
80
+ }
81
+ } else {
82
+ $this->in_private = true;
83
+ $this->private_lvl++;
84
+ }
85
+ }
86
+
87
+ function end_el( & $output, $item, $depth )
88
+ {
89
+ if ( WordPressAccessControl::check_conditions( $item->object_id ) ) {
90
+ if ( ! $this->in_private ) {
91
+ $output .= "</li>\n";
92
+ }
93
+ } else {
94
+ $this->private_lvl--;
95
+
96
+ if ( $this->private_lvl == 0 ) {
97
+ $this->in_private = false;
98
+ }
99
+ }
100
+ }
101
+ }
102
+ }
103
+
104
+ // We check to see if the class exists because it may get removed in the future
105
+ if ( class_exists( 'Walker_Page' ) ) {
106
+ add_filter( 'wp_page_menu_args', array( 'WordPressAccessControl' , 'wp_page_menu_args' ) );
107
+
108
+ /**
109
+ * A custom walker that checks our conditions to make sure the user has
110
+ * permission to view the page linked to from the menu item
111
+ *
112
+ * @author Brandon Wamboldt
113
+ * @package WordPress
114
+ * @subpackage WordPressAccessControl
115
+ */
116
+ class WPAC_Page_Walker extends Walker_Page
117
+ {
118
+ var $in_private = false;
119
+ var $private_lvl = 0;
120
+
121
+ function start_lvl( & $output, $depth )
122
+ {
123
+ if ( ! $this->in_private ) {
124
+ $indent = str_repeat( ' ', $depth );
125
+ $output .= "\n$indent<ul class=\"sub-menu\"><li style='display:none;'></li>\n";
126
+ }
127
+ }
128
+
129
+ function end_lvl( & $output, $depth )
130
+ {
131
+ if ( ! $this->in_private ) {
132
+ $indent = str_repeat( ' ', $depth );
133
+ $output .= "$indent</ul>\n";
134
+ }
135
+ }
136
+
137
+ function start_el( & $output, $page, $depth, $args, $current_page )
138
+ {
139
+ global $wp_query;
140
+
141
+ if ( WordPressAccessControl::check_conditions( $page->ID ) ) {
142
+ if ( ! $this->in_private ) {
143
+ $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
144
+
145
+ extract( $args, EXTR_SKIP );
146
+
147
+ $css_class = array( 'page_item', 'page-item-' . $page->ID );
148
+
149
+ if ( $current_page != '' ) {
150
+ $_current_page = get_page( $current_page );
151
+
152
+ if ( isset( $_current_page->ancestors ) && in_array( $page->ID, (array) $_current_page->ancestors ) ) {
153
+ $css_class[] = 'current_page_ancestor';
154
+ }
155
+
156
+ if ( $page->ID == $current_page ) {
157
+ $css_class[] = 'current_page_item';
158
+ } elseif ( $_current_page && $page->ID == $_current_page->post_parent ) {
159
+ $css_class[] = 'current_page_parent';
160
+ }
161
+ } elseif ( $page->ID == get_option('page_for_posts') ) {
162
+ $css_class[] = 'current_page_parent';
163
+ }
164
+
165
+ $css_class = implode( ' ', apply_filters( 'page_css_class', $css_class, $page ) );
166
+
167
+ $output .= $indent . '<li class="' . $css_class . '"><a href="' . get_page_link( $page->ID ) . '" title="' . esc_attr( wp_strip_all_tags( apply_filters( 'the_title', $page->post_title, $page->ID ) ) ) . '">' . $link_before . apply_filters( 'the_title', $page->post_title, $page->ID ) . $link_after . '</a>';
168
+
169
+ if ( ! empty( $show_date ) ) {
170
+ if ( 'modified' == $show_date ) {
171
+ $time = $page->post_modified;
172
+ } else {
173
+ $time = $page->post_date;
174
+ }
175
+
176
+ $output .= ' ' . mysql2date( $date_format, $time );
177
+ }
178
+ }
179
+ } else {
180
+ $this->in_private = true;
181
+ $this->private_lvl++;
182
+ }
183
+ }
184
+
185
+ function end_el( & $output, $page, $depth )
186
+ {
187
+ if ( WordPressAccessControl::check_conditions( $page->ID ) ) {
188
+ if ( ! $this->in_private ) {
189
+ $output .= "</li>\n";
190
+ }
191
+ } else {
192
+ $this->private_lvl--;
193
+
194
+ if ( $this->private_lvl == 0 ) {
195
+ $this->in_private = false;
196
+ }
197
+ }
198
+ }
199
+ }
200
+ }
201
+
202
+ /**
203
+ * The main plugin
204
+ *
205
+ * @author Brandon Wamboldt
206
+ * @package WordPress
207
+ * @subpackage WordPressAccessControl
208
+ */
209
+ class WordPressAccessControl
210
+ {
211
+ function check_conditions( $page_id )
212
+ {
213
+ global $wp_roles, $current_user;
214
+
215
+ if ( is_user_logged_in() ) {
216
+ get_currentuserinfo();
217
+
218
+ $allowed_roles = maybe_unserialize( get_post_meta( $page_id, '_wpac_restricted_to', true ) );
219
+
220
+ if ( empty( $allowed_roles ) ) {
221
+ $allowed_roles_tmp = $wp_roles->get_names();
222
+ $allowed_roles = array();
223
+
224
+ foreach ( $allowed_roles_tmp as $role => $garbage ) {
225
+ $allowed_roles[] = $role;
226
+ }
227
+ }
228
+
229
+ $intersections = array_intersect( $current_user->roles, $allowed_roles );
230
+
231
+ if ( empty( $intersections ) ) {
232
+ $role = false;
233
+ } else {
234
+ $role = true;
235
+ }
236
+ } else {
237
+ $role = true;
238
+ }
239
+
240
+ $is_members_only = get_post_meta( $page_id, '_wpac_is_members_only', true );
241
+ $is_nonmembers_only = get_post_meta( $page_id, '_wpac_is_nonmembers_only', true );
242
+
243
+ if ( ( is_user_logged_in() && $is_members_only && $role ) || ( ! is_user_logged_in() && $is_nonmembers_only ) || ( ! $is_members_only && ! $is_nonmembers_only ) ) {
244
+ return true;
245
+ } else {
246
+ return false;
247
+ }
248
+ }
249
+
250
+ function check_for_members_only()
251
+ {
252
+ global $post;
253
+
254
+ if ( get_post_meta( $post->ID, '_wpac_is_members_only', true ) && !self::check_conditions( $post->ID ) ) {
255
+ $redirect_to = get_post_meta( $post->ID, '_wpac_members_redirect_to', true );
256
+
257
+ if ( empty( $redirect_to ) ) {
258
+ header( 'Location: ' . get_bloginfo( 'wpurl' ) . '/wp-login.php' );
259
+ } else {
260
+ header( 'Location: ' . $redirect_to );
261
+ }
262
+
263
+ exit();
264
+ }
265
+ }
266
+
267
+ function check_for_nonmembers_only()
268
+ {
269
+ global $post;
270
+
271
+ if ( get_post_meta( $post->ID, '_wpac_is_nonmembers_only', true ) && ! self::check_conditions( $post->ID ) ) {
272
+ $redirect_to = get_post_meta( $post->ID, '_wpac_nonmembers_redirect_to', true );
273
+
274
+ if ( empty( $redirect_to ) ) {
275
+ header( 'Location: ' . get_bloginfo( 'wpurl' ) . '/index.php' );
276
+ } else {
277
+ header( 'Location: ' . $redirect_to );
278
+ }
279
+
280
+ exit();
281
+ }
282
+ }
283
+
284
+ function add_wp_access_meta_boxes()
285
+ {
286
+ $supported_pages = apply_filters( 'wp_access_supported_pages', array( 'page' ) );
287
+
288
+ foreach ( $supported_pages as $page_type ) {
289
+ add_meta_box( 'wpac_controls_meta', 'WordPress Access Control', array( 'WordPressAccessControl', 'add_wpac_meta_box' ), $page_type, 'side', 'high' );
290
+ }
291
+ }
292
+
293
+ function add_wpac_meta_box()
294
+ {
295
+ global $post;
296
+
297
+ $is_members_only = get_post_meta( $post->ID, '_wpac_is_members_only', true );
298
+ $is_nonmembers_only = get_post_meta( $post->ID, '_wpac_is_nonmembers_only', true );
299
+
300
+ if ( $is_members_only == 'true' ) {
301
+ $is_members_only = 'checked="checked"';
302
+ }
303
+
304
+ if ( $is_nonmembers_only == 'true' ) {
305
+ $is_nonmembers_only = 'checked="checked"';
306
+ }
307
+
308
+ include( dirname( __FILE__ ) . '/templates/meta_box.php' );
309
+ }
310
+
311
+ function save_postdata( $post_id )
312
+ {
313
+ if ( ! isset($_POST['members_only_nonce'] ) ) {
314
+ return $post_id;
315
+ }
316
+
317
+ if ( ! wp_verify_nonce( $_POST['members_only_nonce'], 'members_only' ) ) {
318
+ return $post_id;
319
+ }
320
+
321
+ if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
322
+ return $post_id;
323
+ }
324
+
325
+ if ( isset( $_POST['members_only'] ) && $_POST['members_only'] == 'true' ) {
326
+ update_post_meta( $post_id, '_wpac_is_members_only', 'true' );
327
+
328
+ if ( isset( $_POST['wpac_restricted_to'] ) && ! empty( $_POST['wpac_restricted_to'] ) ) {
329
+ update_post_meta( $post_id, '_wpac_restricted_to', serialize( $_POST['wpac_restricted_to'] ) );
330
+ } else {
331
+ delete_post_meta( $post_id, '_wpac_restricted_to' );
332
+ }
333
+ } else {
334
+ delete_post_meta( $post_id, '_wpac_is_members_only' );
335
+ }
336
+
337
+ if ( isset( $_POST['nonmembers_only'] ) && $_POST['nonmembers_only'] == 'true' ) {
338
+ update_post_meta( $post_id, '_wpac_is_nonmembers_only', 'true' );
339
+ } else {
340
+ delete_post_meta( $post_id, '_wpac_is_nonmembers_only' );
341
+ }
342
+
343
+ if ( isset( $_POST['wpac_members_redirect_to'] ) ) {
344
+ update_post_meta( $post_id, '_wpac_members_redirect_to', $_POST['wpac_members_redirect_to'] );
345
+ }
346
+
347
+ if ( isset( $_POST['wpac_nonmembers_redirect_to'] ) ) {
348
+ update_post_meta( $post_id, '_wpac_nonmembers_redirect_to', $_POST['wpac_nonmembers_redirect_to'] );
349
+ }
350
+
351
+ return $post_id;
352
+ }
353
+
354
+ function wp_nav_menu_args( $args )
355
+ {
356
+ $args['walker'] = new WPAC_Nav_Menu_Walker();
357
+ return $args;
358
+ }
359
+
360
+ function wp_page_menu_args( $args )
361
+ {
362
+ // Only remove the walker if it is ours
363
+ if ( isset( $args['walker'] ) && get_class( $args['walker']) == 'WPAC_Nav_Menu_Walker' ) {
364
+ $args['walker'] = new WPAC_Page_Walker();
365
+ }
366
+
367
+ return $args;
368
+ }
369
+
370
+ /**
371
+ * This hooks in at a higher level to make sure functions like
372
+ * wp_list_pages won't return members only pages.
373
+ *
374
+ * @param $pages
375
+ * @return array
376
+ */
377
+ function get_pages( $pages )
378
+ {
379
+ $auth = is_user_logged_in();
380
+
381
+ foreach ( $pages as $key => $page ) {
382
+ $is_members_only = get_post_meta( $page->ID, '_wpac_is_members_only', true );
383
+ $is_nonmembers_only = get_post_meta( $page->ID, '_wpac_is_nonmembers_only', true );
384
+
385
+ if ( $is_members_only && ! $auth ) {
386
+ unset( $pages[$key] );
387
+ }
388
+
389
+ if ( $is_nonmembers_only && $auth ) {
390
+ unset( $pages[$key] );
391
+ }
392
+ }
393
+
394
+ return $pages;
395
+ }
396
+ }