73 |
74 |
8 | * @copyright Copyright (c) 2009 - 2018, Justin Tadlock
9 | * @link https://themehybrid.com/plugins/members
10 | * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
11 | */
12 |
13 | namespace Members\Admin;
14 |
15 | /**
16 | * Settings view base class.
17 | *
18 | * @since 2.0.0
19 | * @access public
20 | */
21 | abstract class View {
22 |
23 | /**
24 | * Name/ID for the group.
25 | *
26 | * @since 2.0.0
27 | * @access protected
28 | * @var string
29 | */
30 | public $name = '';
31 |
32 | /**
33 | * Internationalized text label for the group.
34 | *
35 | * @since 2.0.0
36 | * @access protected
37 | * @var string
38 | */
39 | public $label = '';
40 |
41 | /**
42 | * Priority (order) the control should be output.
43 | *
44 | * @since 2.0.0
45 | * @access public
46 | * @var int
47 | */
48 | public $priority = 10;
49 |
50 | /**
51 | * A user role capability required to show the control.
52 | *
53 | * @since 2.0.0
54 | * @access public
55 | * @var string|array
56 | */
57 | public $capability = 'manage_options';
58 |
59 | /**
60 | * Magic method to use in case someone tries to output the object as a string.
61 | * We'll just return the name.
62 | *
63 | * @since 2.0.0
64 | * @access public
65 | * @return string
66 | */
67 | public function __toString() {
68 | return $this->name;
69 | }
70 |
71 | /**
72 | * Register a new object.
73 | *
74 | * @since 2.0.0
75 | * @access public
76 | * @param string $name
77 | * @param array $args {
78 | * @type string $label Internationalized text label.
79 | * @type string $icon Dashicon icon in the form of `dashicons-icon-name`.
80 | * @type string $callback Callback function for outputting the content for the view.
81 | * }
82 | * @return void
83 | */
84 | public function __construct( $name, $args = array() ) {
85 |
86 | foreach ( array_keys( get_object_vars( $this ) ) as $key ) {
87 |
88 | if ( isset( $args[ $key ] ) )
89 | $this->$key = $args[ $key ];
90 | }
91 |
92 | $this->name = sanitize_key( $name );
93 | }
94 |
95 | /**
96 | * Runs on the `load-{$page}` hook
97 | *
98 | * @since 2.0.0
99 | * @access public
100 | * @return void
101 | */
102 | public function load() {}
103 |
104 | /**
105 | * Enqueue scripts/styles for the control.
106 | *
107 | * @since 2.0.0
108 | * @access public
109 | * @return void
110 | */
111 | public function enqueue() {}
112 |
113 | /**
114 | * Register settings for the view.
115 | *
116 | * @since 2.0.0
117 | * @access public
118 | * @return void
119 | */
120 | public function register_settings() {}
121 |
122 | /**
123 | * Add help tabs for the view.
124 | *
125 | * @since 2.0.0
126 | * @access public
127 | * @return void
128 | */
129 | public function add_help_tabs() {}
130 |
131 | /**
132 | * Output the content for the view.
133 | *
134 | * @since 2.0.0
135 | * @access public
136 | * @return void
137 | */
138 | public function template() {}
139 |
140 | /**
141 | * Checks if the control should be allowed at all.
142 | *
143 | * @since 2.0.0
144 | * @access public
145 | * @return bool
146 | */
147 | public function check_capabilities() {
148 |
149 | if ( $this->capability && ! call_user_func_array( 'current_user_can', (array) $this->capability ) )
150 | return false;
151 |
152 | return true;
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "justintadlock/members",
3 | "description" : "A user and role management plugin that puts you in full control of your site's permissions. This plugin allows you to edit your roles and their capabilities, clone existing roles, assign multiple roles per user, block post content, or even make your site completely private.",
4 | "keywords" : ["wordpress"],
5 | "homepage" : "https://themehybrid.com/plugins/members",
6 | "license" : "GPL-2.0+",
7 | "type" : "wordpress-plugin",
8 | "authors" : [
9 | {
10 | "name" : "Justin Tadlock",
11 | "email" : "justintadlock@gmail.com",
12 | "homepage" : "http://justintadlock.com"
13 | }
14 | ],
15 | "require" : {
16 | "composer/installers" : "^1.0",
17 | "php" : ">=5.3.0"
18 | },
19 | "support" : {
20 | "issues": "https://github.com/justintadlock/members/issues",
21 | "forum" : "https://themehybrid.com/board/topics"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/contributing.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | The code for the project is handled via its [GitHub Repository](https://github.com/justintadlock/members). You can open tickets, create patches, and send pull requests there.
4 |
5 | ## Pull requests
6 |
7 | Problem first. Solution second.
8 |
9 | Pull requests should have a ticket open for discussion first. I rarely accept pull requests that aren't for a specific issue for various reasons. It's far better to post an issue and let me or the community provide feedback prior to creating a pull request.
10 |
11 | Please don't make pull requests against the `master` branch. This is the latest, stable code. You can make a pull request against one of the point branches or the `dev` (future release) branch.
12 |
13 | ## Coding standards
14 |
15 | In general, the project follows all WordPress [coding standards](https://make.wordpress.org/core/handbook/best-practices/coding-standards). There are instances where it doesn't, opting for personal choices of my own, but in terms of contributing, following the WordPress standards is best practice.
16 |
17 | ## Script and style files
18 |
19 | The project consists of several script and style files. When making patches or pull requests with changes to these files, only do so to the primary file. Don't create patches for the minified (`.min`) versions of the files. Those will be minified after a patch is merged into the code base.
20 |
21 | ## Language
22 |
23 | All text strings follow U.S. English by default. While such guides are generally unneeded, in cases where style considerations are necessary, these will typically follow conventions laid out in *Elements of Style* or the *AP Stylebook*.
24 |
25 | ## Licensing
26 |
27 | Any code contributed to the project via patches, pull requests, or other means will be licensed under the [GPL version 2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html) or later. By contributing code to the project, you provide consent to use such code under this license. The exception to this rule is when bringing in third-party code with an alternate open source license.
28 |
29 | ## Versioning
30 |
31 | The project uses [semantic versioning](http://semver.org). Version numbers will look like `3.2.1` where `3` is the "major" release, `2` is the minor release, and `1` is the patch release.
--------------------------------------------------------------------------------
/css/admin.css:
--------------------------------------------------------------------------------
1 | /* ====== Members Settings Screen. ====== */
2 |
3 | .settings_page_members-settings .welcome-panel {
4 | margin-top: 0;
5 | padding: 40px 20px;
6 | }
7 |
8 | .settings_page_members-settings .welcome-panel .about-description {
9 | margin: 20px 0;
10 | }
11 |
12 | .settings_page_members-settings .welcome-panel-content {
13 | margin: 0;
14 | }
15 |
16 | @media screen and (min-width: 870px) {
17 |
18 | .settings_page_members-settings .members-short-p {
19 | max-width: 612px;
20 | margin-left: auto;
21 | margin-right: auto;
22 | }
23 |
24 | .settings_page_members-settings .welcome-panel-content {
25 | text-align: center;
26 | }
27 | }
28 |
29 | .settings_page_members-settings .welcome-panel .button.button-hero {
30 | margin-left: auto;
31 | margin-right: auto;
32 | }
33 |
34 | .settings_page_members-settings .members-svg-wrap {
35 | display: inline-block;
36 | margin: 0 auto 20px;
37 | }
38 |
39 | @media screen and (max-width: 870px) {
40 | .settings_page_members-settings .welcome-panel {
41 | padding: 20px;
42 | }
43 |
44 | .settings_page_members-settings .members-svg-wrap {
45 | float: left;
46 | margin-right: 28px;
47 | }
48 |
49 | .settings_page_members-settings.rtl .members-svg-wrap {
50 | float: right;
51 | margin-right: 0;
52 | margin-left: 28px;
53 | }
54 | }
55 |
56 | .settings_page_members-settings .members-svg-link {
57 | display: table-cell;
58 | text-align: center;
59 | width: 128px;
60 | height: 128px;
61 | background: #363b3f;
62 | color: #fff;
63 | padding: 24px 16px 16px;
64 | border-radius: 50%;
65 | box-sizing: border-box;
66 | border: 4px solid #ffffff;
67 | box-shadow: 0 0 0 4px #363b3f;
68 | }
69 |
70 | .settings_page_members-settings .members-svg-link svg {
71 | max-width: 84px;
72 | max-height: 64px;
73 | width: auto;
74 | height: auto;
75 | }
76 |
77 | /* ====== Manage Roles Screen. ====== */
78 |
79 | @media only screen and ( min-width: 783px ) {
80 |
81 | .users_page_roles .column-users,
82 | .users_page_roles .column-granted_caps,
83 | .users_page_roles .column-denied_caps {
84 | width: 100px;
85 | text-align: center;
86 | }
87 | }
88 |
89 | /* ====== Edit/New Role Screen. ====== */
90 |
91 | /* === Role and Role Name === */
92 |
93 | .members-title-div #titlewrap input {
94 | padding: 0 8px;
95 | font-size: 1.7em;
96 | line-height: normal;
97 | height: 1.7em;
98 | width: 100%;
99 | outline: none;
100 | margin: 0 0 3px;
101 | background-color: #fff;
102 | }
103 |
104 | .members-title-div input[name="role"] {
105 | font-size: 13px;
106 | height: 22px;
107 | margin: 0;
108 | width: 16em;
109 | }
110 |
111 | /* === Edit Capabilities Tabs === */
112 |
113 | /* Wrapper box */
114 |
115 | #tabcapsdiv { margin-top: 1em; }
116 |
117 | #tabcapsdiv > .hndle {
118 | padding: 10px;
119 | border-bottom: 1px solid #eee;
120 | }
121 |
122 | #tabcapsdiv .inside,
123 | #members-cp .inside {
124 | margin: 0;
125 | padding: 0;
126 | }
127 |
128 | /* Tabs wrapper. */
129 |
130 | .members-cap-tabs,
131 | .members-tabs {
132 | overflow: hidden;
133 | background: #fff;
134 | background: linear-gradient( 90deg, #fafafa 0%, #fafafa 20%, #fff 20%, #fff 100% );
135 | }
136 |
137 | @media only screen and ( max-width: 782px ) {
138 |
139 | .members-cap-tabs,
140 | .members-tabs {
141 | background: linear-gradient( 90deg, #fafafa 0%, #fafafa 48px, #fff 48px, #fff 100% );
142 | }
143 | }
144 |
145 | /* Tab nav. */
146 |
147 | .members-cap-tabs .members-tab-nav,
148 | .members-tabs .members-tab-nav {
149 | position: relative;
150 | float: left;
151 | list-style: none;
152 | width: 20%;
153 | line-height: 1em;
154 | margin: 0 0 -1px 0;
155 | padding: 0;
156 | background-color: #fafafa;
157 | border-right: 1px solid #eee;
158 | box-sizing: border-box;
159 | }
160 |
161 | .members-cap-tabs .members-tab-nav li,
162 | .members-tabs .members-tab-nav li {
163 | display: block;
164 | position: relative;
165 | margin: 0;
166 | padding: 0;
167 | line-height: 20px;
168 | }
169 |
170 | .members-cap-tabs .members-tab-nav li a,
171 | .members-tabs .members-tab-nav li a {
172 | display: block;
173 | margin: 0;
174 | padding: 10px;
175 | line-height: 20px !important;
176 | text-decoration: none;
177 | border-bottom: 1px solid #eee;
178 | box-shadow: none;
179 | }
180 |
181 | .members-cap-tabs .members-tab-nav li a .dashicons,
182 | .members-tabs .members-tab-nav li a .dashicons {
183 | line-height: 20px;
184 | margin-right: 3px;
185 | }
186 |
187 | .members-cap-tabs .members-tab-nav li[aria-selected="true"] a,
188 | .members-tabs .members-tab-nav li[aria-selected="true"] a {
189 | position: relative;
190 | font-weight: bold;
191 | color: #555;
192 | background-color: #e0e0e0;
193 | }
194 |
195 | @media only screen and ( max-width: 782px ) {
196 |
197 | .members-cap-tabs .members-tab-nav,
198 | .members-tabs .members-tab-nav { width: 48px; }
199 |
200 | .members-cap-tabs .members-tab-nav li a .dashicons,
201 | .members-tabs .members-tab-nav li a .dashicons {
202 | width: 24px;
203 | height: 24px;
204 | font-size: 24px;
205 | line-height: 24px;
206 | }
207 |
208 | .members-tab-nav li .dashicons::before,
209 | .members-tab-nav li .dashicons::before {
210 | width: 24px;
211 | height: 24px;
212 | }
213 |
214 | .members-tab-nav li .label {
215 | overflow: hidden;
216 | position: absolute;
217 | top: -1000em;
218 | left: -1000em;
219 | width: 1px;
220 | height: 1px;
221 | }
222 | }
223 |
224 | /* Tab content wrapper */
225 |
226 | .members-cap-tabs .members-tab-wrap,
227 | .members-tabs .members-tab-wrap {
228 | float: left;
229 | width: 80%;
230 | margin-left: -1px;
231 | }
232 |
233 | @media only screen and ( max-width: 782px ) {
234 |
235 | .members-cap-tabs .members-tab-wrap,
236 | .members-tabs .members-tab-wrap {
237 | width: calc( 100% - 48px );
238 | }
239 | }
240 |
241 | #members-cp .members-tab-content {
242 | padding: 10px;
243 | border-left: 1px solid #e5e5e5;
244 | }
245 |
246 | /* === Manager when in the side meta box. === */
247 |
248 | @media only screen and ( min-width: 850px ) {
249 |
250 | #side-sortables .members-tabs { background: #fff; }
251 |
252 | #side-sortables .members-tabs .members-tab-wrap { width: 100%; }
253 |
254 | #side-sortables .members-tabs .members-tab-nav {
255 | display: table;
256 | width: 100%;
257 | }
258 |
259 | #side-sortables .members-tabs .members-tab-nav li {
260 | display: table-cell;
261 | text-align: center;
262 | border-right: 1px solid #eee;
263 | }
264 |
265 | #side-sortables .members-tabs .members-tab-nav li:last-of-type { border-right: none; }
266 |
267 | #side-sortables .members-tabs .members-tab-nav li a {
268 | padding: 10px 0;
269 | }
270 |
271 | #side-sortables .members-tabs .members-tab-nav .dashicons {
272 | width: 24px;
273 | height: 24px;
274 | font-size: 24px;
275 | line-height: 24px;
276 | }
277 |
278 | #side-sortables .members-tabs .members-tab-nav .dashicons::before {
279 | width: 24px;
280 | height: 24px;
281 | }
282 |
283 | #side-sortables .members-tabs .members-tab-nav .label {
284 | overflow: hidden;
285 | position: absolute;
286 | top: -1000em;
287 | left: -1000em;
288 | width: 1px;
289 | height: 1px;
290 | }
291 | }
292 |
293 |
294 | .members-tabs .members-tabs-label {
295 | display : block !important;
296 | font-weight : bold;
297 | display : inline-block;
298 | margin-bottom : 4px;
299 | }
300 |
301 | .members-tabs .butterbean-control-checkbox .members-tabs-label {
302 | display: inline !important;
303 | }
304 |
305 | .members-tabs .members-tabs-description {
306 | display : block;
307 | font-style : italic;
308 | margin-top : 4px;
309 | }
310 |
311 | .members-tabs .members-tabs-label + .members-tabs-description {
312 | margin-top : 0;
313 | margin-bottom : 4px;
314 | }
315 |
316 | /* Tab tables. */
317 |
318 | #tabcapsdiv table {
319 | border-right: none;
320 | border-top: none;
321 | border-bottom: none;
322 | }
323 |
324 | /* Tabs table columns. */
325 |
326 | #tabcapsdiv table td,
327 | #tabcapsdiv table th {
328 | padding: 10px;
329 | padding-bottom: 10px;
330 | border-bottom: 1px solid #eee;
331 | font-size: 13px;
332 | line-height: 20px;
333 | }
334 |
335 | #tabcapsdiv table td { padding: 9px; }
336 |
337 | #tabcapsdiv tbody tr:last-of-type td { border-bottom: none; }
338 |
339 | #tabcapsdiv tfoot th { border-color: #eee; }
340 |
341 | @media only screen and ( max-width: 782px ) {
342 |
343 | #tabcapsdiv table td,
344 | #tabcapsdiv table th {
345 | line-height: 24px;
346 | }
347 | }
348 |
349 | /* Grant/Deny columns. */
350 |
351 | .members-roles-select .column-grant,
352 | .members-roles-select .column-deny {
353 | width: 70px !important;
354 | text-align: center;
355 | display: table-cell !important;
356 | clear: none !important;
357 | }
358 |
359 | /* Cap grant/deny button. */
360 |
361 | .members-cap-tabs button {
362 | display: inline;
363 | margin: -4px;
364 | line-height: inherit;
365 | padding: 4px 8px;
366 | border: 1px solid transparent;
367 | background: transparent;
368 | border-radius: 0;
369 | outline: none;
370 |
371 | -webkit-transition: all 0.25s ease-out;
372 | -moz-transition: all 0.25s ease-out;
373 | -o-transition: all 0.25s ease-out;
374 | transition: all 0.25s ease-out;
375 | }
376 |
377 | .members-cap-tabs button:hover,
378 | .members-cap-tabs button:focus {
379 | border-color: #eee;
380 | background: #fafafa;
381 | cursor: pointer;
382 | }
383 |
384 | .members-cap-tabs button:active {
385 | color: #0073aa;
386 | border-color: #0073aa;
387 | }
388 |
389 | .members-cap-tabs button + .dashicons {
390 | display: none;
391 | margin-top: 1px;
392 | margin-bottom: -1px;
393 | line-height: inherit;
394 | }
395 |
396 | .members-cap-tabs button:hover + .dashicons,
397 | .members-cap-tabs button:focus + .dashicons {
398 | display: inline-block;
399 | }
400 |
401 |
402 | /* New cap highlight */
403 |
404 | .members-tab-content .members-highlight {
405 | background-color: rgba( 0, 115, 170, 0.05 );
406 | }
407 |
408 | .members-tab-content tbody {
409 | -webkit-transition: all 2s ease-in-out;
410 | -moz-transition: all 2s ease-in-out;
411 | -o-transition: all 2s ease-in-out;
412 | transition: all 2s ease-in-out;
413 | }
414 |
415 | /* ====== Edit Post ====== */
416 |
417 | /* Role checkboxes in the Content Permissions meta box. */
418 |
419 | .members-cp-role-list-wrap {
420 | overflow: auto;
421 | min-height: 42px;
422 | max-height: 200px;
423 | padding: 0 0.9em;
424 | border: solid 1px rgb(223, 223, 223);
425 | background-color: rgb(253, 253, 253);
426 | }
427 |
--------------------------------------------------------------------------------
/css/admin.min.css:
--------------------------------------------------------------------------------
1 | .settings_page_members-settings .welcome-panel{margin-top:0;padding:40px 20px}.settings_page_members-settings .welcome-panel .about-description{margin:20px 0}.settings_page_members-settings .welcome-panel-content{margin:0}@media screen and (min-width:870px){.settings_page_members-settings .members-short-p{max-width:612px;margin-left:auto;margin-right:auto}.settings_page_members-settings .welcome-panel-content{text-align:center}}.settings_page_members-settings .welcome-panel .button.button-hero{margin-left:auto;margin-right:auto}.settings_page_members-settings .members-svg-wrap{display:inline-block;margin:0 auto 20px}@media screen and (max-width:870px){.settings_page_members-settings .welcome-panel{padding:20px}.settings_page_members-settings .members-svg-wrap{float:left;margin-right:28px}.settings_page_members-settings.rtl .members-svg-wrap{float:right;margin-right:0;margin-left:28px}}.settings_page_members-settings .members-svg-link{display:table-cell;text-align:center;width:128px;height:128px;background:#363b3f;color:#fff;padding:24px 16px 16px;border-radius:50%;box-sizing:border-box;border:4px solid #fff;box-shadow:0 0 0 4px #363b3f}.settings_page_members-settings .members-svg-link svg{max-width:84px;max-height:64px;width:auto;height:auto}@media only screen and (min-width:783px){.users_page_roles .column-users,.users_page_roles .column-granted_caps,.users_page_roles .column-denied_caps{width:100px;text-align:center}}.members-title-div #titlewrap input{padding:0 8px;font-size:1.7em;line-height:normal;height:1.7em;width:100%;outline:none;margin:0 0 3px;background-color:#fff}.members-title-div input[name="role"]{font-size:13px;height:22px;margin:0;width:16em}#tabcapsdiv{margin-top:1em}#tabcapsdiv>.hndle{padding:10px;border-bottom:1px solid #eee}#tabcapsdiv .inside,#members-cp .inside{margin:0;padding:0}.members-cap-tabs,.members-tabs{overflow:hidden;background:#fff;background:linear-gradient(90deg,#fafafa 0%,#fafafa 20%,#fff 20%,#fff 100%)}@media only screen and (max-width:782px){.members-cap-tabs,.members-tabs{background:linear-gradient(90deg,#fafafa 0%,#fafafa 48px,#fff 48px,#fff 100%)}}.members-cap-tabs .members-tab-nav,.members-tabs .members-tab-nav{position:relative;float:left;list-style:none;width:20%;line-height:1em;margin:0 0 -1px 0;padding:0;background-color:#fafafa;border-right:1px solid #eee;box-sizing:border-box}.members-cap-tabs .members-tab-nav li,.members-tabs .members-tab-nav li{display:block;position:relative;margin:0;padding:0;line-height:20px}.members-cap-tabs .members-tab-nav li a,.members-tabs .members-tab-nav li a{display:block;margin:0;padding:10px;line-height:20px!important;text-decoration:none;border-bottom:1px solid #eee;box-shadow:none}.members-cap-tabs .members-tab-nav li a .dashicons,.members-tabs .members-tab-nav li a .dashicons{line-height:20px;margin-right:3px}.members-cap-tabs .members-tab-nav li[aria-selected="true"] a,.members-tabs .members-tab-nav li[aria-selected="true"] a{position:relative;font-weight:700;color:#555;background-color:#e0e0e0}@media only screen and (max-width:782px){.members-cap-tabs .members-tab-nav,.members-tabs .members-tab-nav{width:48px}.members-cap-tabs .members-tab-nav li a .dashicons,.members-tabs .members-tab-nav li a .dashicons{width:24px;height:24px;font-size:24px;line-height:24px}.members-tab-nav li .dashicons::before,.members-tab-nav li .dashicons::before{width:24px;height:24px}.members-tab-nav li .label{overflow:hidden;position:absolute;top:-1000em;left:-1000em;width:1px;height:1px}}.members-cap-tabs .members-tab-wrap,.members-tabs .members-tab-wrap{float:left;width:80%;margin-left:-1px}@media only screen and (max-width:782px){.members-cap-tabs .members-tab-wrap,.members-tabs .members-tab-wrap{width:calc(100% - 48px)}}#members-cp .members-tab-content{padding:10px;border-left:1px solid #e5e5e5}@media only screen and (min-width:850px){#side-sortables .members-tabs{background:#fff}#side-sortables .members-tabs .members-tab-wrap{width:100%}#side-sortables .members-tabs .members-tab-nav{display:table;width:100%}#side-sortables .members-tabs .members-tab-nav li{display:table-cell;text-align:center;border-right:1px solid #eee}#side-sortables .members-tabs .members-tab-nav li:last-of-type{border-right:none}#side-sortables .members-tabs .members-tab-nav li a{padding:10px 0}#side-sortables .members-tabs .members-tab-nav .dashicons{width:24px;height:24px;font-size:24px;line-height:24px}#side-sortables .members-tabs .members-tab-nav .dashicons::before{width:24px;height:24px}#side-sortables .members-tabs .members-tab-nav .label{overflow:hidden;position:absolute;top:-1000em;left:-1000em;width:1px;height:1px}}.members-tabs .members-tabs-label{display:block!important;font-weight:700;display:inline-block;margin-bottom:4px}.members-tabs .butterbean-control-checkbox .members-tabs-label{display:inline!important}.members-tabs .members-tabs-description{display:block;font-style:italic;margin-top:4px}.members-tabs .members-tabs-label + .members-tabs-description{margin-top:0;margin-bottom:4px}#tabcapsdiv table{border-right:none;border-top:none;border-bottom:none}#tabcapsdiv table td,#tabcapsdiv table th{padding:10px;padding-bottom:10px;border-bottom:1px solid #eee;font-size:13px;line-height:20px}#tabcapsdiv table td{padding:9px}#tabcapsdiv tbody tr:last-of-type td{border-bottom:none}#tabcapsdiv tfoot th{border-color:#eee}@media only screen and (max-width:782px){#tabcapsdiv table td,#tabcapsdiv table th{line-height:24px}}.members-roles-select .column-grant,.members-roles-select .column-deny{width:70px!important;text-align:center;display:table-cell!important;clear:none!important}.members-cap-tabs button{display:inline;margin:-4px;line-height:inherit;padding:4px 8px;border:1px solid transparent;background:transparent;border-radius:0;outline:none;-webkit-transition:all 0.25s ease-out;-moz-transition:all 0.25s ease-out;-o-transition:all 0.25s ease-out;transition:all 0.25s ease-out}.members-cap-tabs button:hover,.members-cap-tabs button:focus{border-color:#eee;background:#fafafa;cursor:pointer}.members-cap-tabs button:active{color:#0073aa;border-color:#0073aa}.members-cap-tabs button + .dashicons{display:none;margin-top:1px;margin-bottom:-1px;line-height:inherit}.members-cap-tabs button:hover + .dashicons,.members-cap-tabs button:focus + .dashicons{display:inline-block}.members-tab-content .members-highlight{background-color:rgba(0,115,170,.05)}.members-tab-content tbody{-webkit-transition:all 2s ease-in-out;-moz-transition:all 2s ease-in-out;-o-transition:all 2s ease-in-out;transition:all 2s ease-in-out}.members-cp-role-list-wrap{overflow:auto;min-height:42px;max-height:200px;padding:0 .9em;border:solid 1px rgb(223,223,223);background-color:rgb(253,253,253)}
2 |
--------------------------------------------------------------------------------
/img/icon-addon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/justintadlock/members/07a1eeebdb1efee61534885f4e087ac167d46736/img/icon-addon.png
--------------------------------------------------------------------------------
/img/members-admin-access.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/members-block-permissions.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/members-core-create-caps.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/members-privacy-caps.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/members-role-hierarchy.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/members-role-levels.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/members.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/inc/class-cap-group.php:
--------------------------------------------------------------------------------
1 |
8 | * @copyright Copyright (c) 2009 - 2018, Justin Tadlock
9 | * @link https://themehybrid.com/plugins/members
10 | * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
11 | */
12 |
13 | namespace Members;
14 |
15 | /**
16 | * Capability group object class.
17 | *
18 | * @since 2.0.0
19 | * @access public
20 | */
21 | final class Cap_Group {
22 |
23 | /**
24 | * Name/ID for the group.
25 | *
26 | * @since 2.0.0
27 | * @access public
28 | * @var string
29 | */
30 | public $name = '';
31 |
32 | /**
33 | * Internationalized text label for the group.
34 | *
35 | * @since 2.0.0
36 | * @access public
37 | * @var string
38 | */
39 | public $label = '';
40 |
41 | /**
42 | * Icon for the group. This can be a dashicons class or a custom class.
43 | *
44 | * @since 2.0.0
45 | * @access public
46 | * @var string
47 | */
48 | public $icon = 'dashicons-admin-generic';
49 |
50 | /**
51 | * Capabilities for the group.
52 | *
53 | * @since 2.0.0
54 | * @access public
55 | * @var array
56 | */
57 | public $caps = array();
58 |
59 | /**
60 | * Sort order priority.
61 | *
62 | * @since 2.0.0
63 | * @access public
64 | * @var int
65 | */
66 | public $priority = 10;
67 |
68 | /**
69 | * Whether to remove previously-added caps from this group's caps.
70 | *
71 | * @since 2.0.0
72 | * @access public
73 | * @var bool
74 | */
75 | public $diff_added = false;
76 |
77 | /**
78 | * Magic method to use in case someone tries to output the object as a string.
79 | * We'll just return the name.
80 | *
81 | * @since 2.0.0
82 | * @access public
83 | * @return string
84 | */
85 | public function __toString() {
86 | return $this->name;
87 | }
88 |
89 | /**
90 | * Register a new object.
91 | *
92 | * @since 2.0.0
93 | * @access public
94 | * @param string $name
95 | * @param array $args {
96 | * @type string $label Internationalized text label.
97 | * @type string $icon Dashicon icon in the form of `dashicons-icon-name`.
98 | * @type array $caps Array of capabilities in the group.
99 | * @type bool $merge_added Whether to merge this caps into the added caps array.
100 | * @type bool $diff_added Whether to remove previously-added caps from this group.
101 | * }
102 | * @return void
103 | */
104 | public function __construct( $name, $args = array() ) {
105 |
106 | foreach ( array_keys( get_object_vars( $this ) ) as $key ) {
107 |
108 | if ( isset( $args[ $key ] ) )
109 | $this->$key = $args[ $key ];
110 | }
111 |
112 | $this->name = sanitize_key( $name );
113 |
114 | $registered_caps = array_keys( wp_list_filter( members_get_caps(), array( 'group' => $this->name ) ) );
115 |
116 | $this->caps = array_unique( array_merge( $this->caps, $registered_caps ) );
117 |
118 | $this->caps = members_remove_hidden_caps( $this->caps );
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/inc/class-capability.php:
--------------------------------------------------------------------------------
1 |
8 | * @copyright Copyright (c) 2009 - 2018, Justin Tadlock
9 | * @link https://themehybrid.com/plugins/members
10 | * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
11 | */
12 |
13 | namespace Members;
14 |
15 | /**
16 | * Capability class.
17 | *
18 | * @since 2.0.0
19 | * @access public
20 | */
21 | class Capability {
22 |
23 | /**
24 | * The capability name.
25 | *
26 | * @since 2.0.0
27 | * @access public
28 | * @var string
29 | */
30 | public $name = '';
31 |
32 | /**
33 | * The capability label.
34 | *
35 | * @since 2.0.0
36 | * @access public
37 | * @var string
38 | */
39 | public $label = '';
40 |
41 | /**
42 | * The group the capability belongs to.
43 | *
44 | * @see Members_Cap_Group
45 | * @since 2.0.0
46 | * @access public
47 | * @var string
48 | */
49 | public $group = '';
50 |
51 | /**
52 | * Return the role string in attempts to use the object as a string.
53 | *
54 | * @since 2.0.0
55 | * @access public
56 | * @return string
57 | */
58 | public function __toString() {
59 | return $this->name;
60 | }
61 |
62 | /**
63 | * Creates a new role object.
64 | *
65 | * @since 2.0.0
66 | * @access public
67 | * @global object $wp_roles
68 | * @param string $role
69 | * @return void
70 | */
71 | public function __construct( $name, $args = array() ) {
72 |
73 | foreach ( array_keys( get_object_vars( $this ) ) as $key ) {
74 |
75 | if ( isset( $args[ $key ] ) )
76 | $this->$key = $args[ $key ];
77 | }
78 |
79 | $this->name = sanitize_key( $name );
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/inc/class-registry.php:
--------------------------------------------------------------------------------
1 |
8 | * @copyright Copyright (c) 2009 - 2018, Justin Tadlock
9 | * @link https://themehybrid.com/plugins/members
10 | * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
11 | */
12 |
13 | namespace Members;
14 |
15 | /**
16 | * Base registry class.
17 | *
18 | * @since 2.0.0
19 | * @access public
20 | */
21 | class Registry {
22 |
23 | /**
24 | * Registry instances.
25 | *
26 | * @since 2.0.0
27 | * @access private
28 | * @var array
29 | */
30 | private static $instances = array();
31 |
32 | /**
33 | * Array of items in the collection.
34 | *
35 | * @since 2.0.0
36 | * @access protected
37 | * @var array
38 | */
39 | protected $collection = array();
40 |
41 | /**
42 | * Constructor method.
43 | *
44 | * @since 2.0.0
45 | * @access protected
46 | * @return void
47 | */
48 | protected function __construct() {}
49 |
50 | /**
51 | * Lock down `__clone()`.
52 | *
53 | * @since 2.0.0
54 | * @access private
55 | * @return void
56 | */
57 | private function __clone() {}
58 |
59 | /**
60 | * Lock down `__wakeup()`.
61 | *
62 | * @since 2.0.0
63 | * @access private
64 | * @return void
65 | */
66 | private function __wakeup() {}
67 |
68 | /**
69 | * Register an item.
70 | *
71 | * @since 2.0.0
72 | * @access public
73 | * @param string $name
74 | * @param mixed $value
75 | * @return void
76 | */
77 | public function register( $name, $value ) {
78 |
79 | if ( ! $this->exists( $name ) )
80 | $this->collection[ $name ] = $value;
81 | }
82 |
83 | /**
84 | * Unregisters an item.
85 | *
86 | * @since 2.0.0
87 | * @access public
88 | * @param string $name
89 | * @return void
90 | */
91 | public function unregister( $name ) {
92 |
93 | if ( $this->exists( $name ) )
94 | unset( $this->collection[ $name ] );
95 | }
96 |
97 | /**
98 | * Checks if an item exists.
99 | *
100 | * @since 2.0.0
101 | * @access public
102 | * @param string $name
103 | * @return bool
104 | */
105 | public function exists( $name ) {
106 |
107 | return isset( $this->collection[ $name ] );
108 | }
109 |
110 | /**
111 | * Returns an item.
112 | *
113 | * @since 2.0.0
114 | * @access public
115 | * @param string $name
116 | * @return mixed
117 | */
118 | public function get( $name ) {
119 |
120 | return $this->exists( $name ) ? $this->collection[ $name ] : false;
121 | }
122 |
123 | /**
124 | * Returns the entire collection.
125 | *
126 | * @since 2.0.0
127 | * @access public
128 | * @return array
129 | */
130 | public function get_collection() {
131 |
132 | return $this->collection;
133 | }
134 |
135 | /**
136 | * Returns the instance.
137 | *
138 | * @since 2.0.0
139 | * @access public
140 | * @return object
141 | */
142 | final public static function get_instance( $name = '' ) {
143 |
144 | if ( ! isset( self::$instances[ $name ] ) )
145 | self::$instances[ $name ] = new static();
146 |
147 | return self::$instances[ $name ];
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/inc/class-role-group.php:
--------------------------------------------------------------------------------
1 |
8 | * @copyright Copyright (c) 2009 - 2018, Justin Tadlock
9 | * @link https://themehybrid.com/plugins/members
10 | * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
11 | */
12 |
13 | namespace Members;
14 |
15 | /**
16 | * Role group object class.
17 | *
18 | * @since 2.0.0
19 | * @access public
20 | */
21 | final class Role_Group {
22 |
23 | /**
24 | * Name/ID for the group.
25 | *
26 | * @since 2.0.0
27 | * @access public
28 | * @var string
29 | */
30 | public $name = '';
31 |
32 | /**
33 | * Internationalized text label for the group.
34 | *
35 | * @since 2.0.0
36 | * @access public
37 | * @var string
38 | */
39 | public $label = '';
40 |
41 | /**
42 | * Internationalized text label for the group + the count in the form of
43 | * `_n_noop( 'Singular Name %s', 'Plural Name %s', $textdomain )`
44 | *
45 | * @since 2.0.0
46 | * @access public
47 | * @var string
48 | */
49 | public $label_count = '';
50 |
51 | /**
52 | * Array of roles that belong to the group.
53 | *
54 | * @since 2.0.0
55 | * @access public
56 | * @var array
57 | */
58 | public $roles = array();
59 |
60 | /**
61 | * Whether to create a view for the group on the Manage Roles screen.
62 | *
63 | * @since 2.0.0
64 | * @access public
65 | * @var bool
66 | */
67 | public $show_in_view_list = true;
68 |
69 | /**
70 | * Magic method to use in case someone tries to output the object as a string.
71 | * We'll just return the name.
72 | *
73 | * @since 2.0.0
74 | * @access public
75 | * @return string
76 | */
77 | public function __toString() {
78 | return $this->name;
79 | }
80 |
81 | /**
82 | * Register a new object.
83 | *
84 | * @since 2.0.0
85 | * @access public
86 | * @param string $name
87 | * @param array $args
88 | * @return void
89 | */
90 | public function __construct( $name, $args = array() ) {
91 |
92 | foreach ( array_keys( get_object_vars( $this ) ) as $key ) {
93 |
94 | if ( isset( $args[ $key ] ) )
95 | $this->$key = $args[ $key ];
96 | }
97 |
98 | $this->name = sanitize_key( $name );
99 |
100 | $registered_roles = array_keys( wp_list_filter( members_get_roles(), array( 'group' => $this->name ) ) );
101 |
102 | $this->roles = array_unique( array_merge( $this->roles, $registered_roles ) );
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/inc/class-role.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright Copyright (c) 2009 - 2018, Justin Tadlock
10 | * @link https://themehybrid.com/plugins/members
11 | * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
12 | */
13 |
14 | namespace Members;
15 |
16 | /**
17 | * Role class.
18 | *
19 | * @since 2.0.0
20 | * @access public
21 | */
22 | class Role {
23 |
24 | /**
25 | * The role name.
26 | *
27 | * @since 2.0.0
28 | * @access public
29 | * @var string
30 | */
31 | public $name = '';
32 |
33 | /**
34 | * The role label.
35 | *
36 | * @since 2.0.0
37 | * @access public
38 | * @var string
39 | */
40 | public $label = '';
41 |
42 | /**
43 | * The group the role belongs to.
44 | *
45 | * @see Members\Role_Group
46 | * @since 2.0.0
47 | * @access public
48 | * @var string
49 | */
50 | public $group = '';
51 |
52 | /**
53 | * Whether the role has caps (granted).
54 | *
55 | * @since 2.0.0
56 | * @access public
57 | * @var bool
58 | */
59 | public $has_caps = false;
60 |
61 | /**
62 | * Capability count for the role.
63 | *
64 | * @since 2.0.0
65 | * @access public
66 | * @var int
67 | */
68 | public $granted_cap_count = 0;
69 |
70 | /**
71 | * Capability count for the role.
72 | *
73 | * @since 2.0.0
74 | * @access public
75 | * @var int
76 | */
77 | public $denied_cap_count = 0;
78 |
79 | /**
80 | * Array of capabilities that the role has in the form of `array( $cap => $bool )`.
81 | *
82 | * @since 2.0.0
83 | * @access public
84 | * @var array
85 | */
86 | public $caps = array();
87 |
88 | /**
89 | * Array of granted capabilities that the role has.
90 | *
91 | * @since 2.0.0
92 | * @access public
93 | * @var array
94 | */
95 | public $granted_caps = array();
96 |
97 | /**
98 | * Array of denied capabilities that the role has.
99 | *
100 | * @since 2.0.0
101 | * @access public
102 | * @var array
103 | */
104 | public $denied_caps = array();
105 |
106 | /**
107 | * Return the role string in attempts to use the object as a string.
108 | *
109 | * @since 2.0.0
110 | * @access public
111 | * @return string
112 | */
113 | public function __toString() {
114 | return $this->name;
115 | }
116 |
117 | /**
118 | * Creates a new role object.
119 | *
120 | * @since 2.0.0
121 | * @access public
122 | * @param string $role
123 | * @param array $args
124 | * @return void
125 | */
126 | public function __construct( $name, $args = array() ) {
127 |
128 | foreach ( array_keys( get_object_vars( $this ) ) as $key ) {
129 |
130 | if ( isset( $args[ $key ] ) )
131 | $this->$key = $args[ $key ];
132 | }
133 |
134 | $this->name = members_sanitize_role( $name );
135 |
136 | if ( $this->caps ) {
137 |
138 | // Validate cap values as booleans in case they are stored as strings.
139 | $this->caps = array_map( 'members_validate_boolean', $this->caps );
140 |
141 | // Get granted and denied caps.
142 | $this->granted_caps = array_keys( $this->caps, true );
143 | $this->denied_caps = array_keys( $this->caps, false );
144 |
145 | // Remove user levels from granted/denied caps.
146 | $this->granted_caps = members_remove_old_levels( $this->granted_caps );
147 | $this->denied_caps = members_remove_old_levels( $this->denied_caps );
148 |
149 | // Remove hidden caps from granted/denied caps.
150 | $this->granted_caps = members_remove_hidden_caps( $this->granted_caps );
151 | $this->denied_caps = members_remove_hidden_caps( $this->denied_caps );
152 |
153 | // Set the cap count.
154 | $this->granted_cap_count = count( $this->granted_caps );
155 | $this->denied_cap_count = count( $this->denied_caps );
156 |
157 | // Check if we have caps.
158 | $this->has_caps = 0 < $this->granted_cap_count;
159 | }
160 | }
161 |
162 | /**
163 | * Magic method for getting media object properties. Let's keep from failing if a theme
164 | * author attempts to access a property that doesn't exist.
165 | *
166 | * @since 2.0.2
167 | * @access public
168 | * @param string $property
169 | * @return mixed
170 | */
171 | public function get( $property ) {
172 |
173 | if ( 'label' === $property )
174 | return members_translate_role( $this->name );
175 |
176 | return isset( $this->$property ) ? $this->$property : false;
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/inc/functions-admin-bar.php:
--------------------------------------------------------------------------------
1 |
8 | * @copyright Copyright (c) 2009 - 2018, Justin Tadlock
9 | * @link https://themehybrid.com/plugins/members
10 | * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
11 | */
12 |
13 | # Hook the members admin bar to 'wp_before_admin_bar_render'.
14 | add_action( 'wp_before_admin_bar_render', 'members_admin_bar' );
15 |
16 | /**
17 | * Adds new menu items to the WordPress admin bar.
18 | *
19 | * @since 0.2.0
20 | * @access public
21 | * @global object $wp_admin_bar
22 | * @return void
23 | */
24 | function members_admin_bar() {
25 | global $wp_admin_bar;
26 |
27 | // Check if the current user can 'create_roles'.
28 | if ( current_user_can( 'create_roles' ) ) {
29 |
30 | // Add a 'Role' menu item as a sub-menu item of the new content menu.
31 | $wp_admin_bar->add_menu(
32 | array(
33 | 'id' => 'members-new-role',
34 | 'parent' => 'new-content',
35 | 'title' => esc_attr__( 'Role', 'members' ),
36 | 'href' => esc_url( members_get_new_role_url() )
37 | )
38 | );
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/inc/functions-cap-groups.php:
--------------------------------------------------------------------------------
1 |
8 | * @copyright Copyright (c) 2009 - 2018, Justin Tadlock
9 | * @link https://themehybrid.com/plugins/members
10 | * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
11 | */
12 |
13 | # Registers default groups.
14 | add_action( 'init', 'members_register_cap_groups', 95 );
15 | add_action( 'members_register_cap_groups', 'members_register_default_cap_groups', 5 );
16 |
17 | /**
18 | * Fires the cap group registration action hook.
19 | *
20 | * @since 1.0.0
21 | * @access public
22 | * @return void
23 | */
24 | function members_register_cap_groups() {
25 |
26 | // Hook for registering cap groups. Plugins should always register on this hook.
27 | do_action( 'members_register_cap_groups' );
28 | }
29 |
30 | /**
31 | * Registers the default cap groups.
32 | *
33 | * @since 2.0.0
34 | * @access public
35 | * @return void
36 | */
37 | function members_register_default_cap_groups() {
38 |
39 | // Registers the general group.
40 | members_register_cap_group( 'general',
41 | array(
42 | 'label' => esc_html__( 'General', 'members' ),
43 | 'icon' => 'dashicons-wordpress',
44 | 'priority' => 5
45 | )
46 | );
47 |
48 | // Loop through every custom post type.
49 | foreach ( get_post_types( array(), 'objects' ) as $type ) {
50 |
51 | // Skip revisions and nave menu items.
52 | if ( in_array( $type->name, array( 'revision', 'nav_menu_item', 'custom_css', 'customize_changeset' ) ) )
53 | continue;
54 |
55 | // Get the caps for the post type.
56 | $has_caps = members_get_post_type_group_caps( $type->name );
57 |
58 | // Skip if the post type doesn't have caps.
59 | if ( empty( $has_caps ) )
60 | continue;
61 |
62 | // Set the default post type icon.
63 | $icon = $type->hierarchical ? 'dashicons-admin-page' : 'dashicons-admin-post';
64 |
65 | // Get the post type icon.
66 | if ( is_string( $type->menu_icon ) && preg_match( '/dashicons-/i', $type->menu_icon ) )
67 | $icon = $type->menu_icon;
68 |
69 | else if ( 'attachment' === $type->name )
70 | $icon = 'dashicons-admin-media';
71 |
72 | else if ( 'download' === $type->name )
73 | $icon = 'dashicons-download'; // EDD
74 |
75 | else if ( 'product' === $type->name )
76 | $icon = 'dashicons-cart';
77 |
78 | // Register the post type cap group.
79 | members_register_cap_group( "type-{$type->name}",
80 | array(
81 | 'label' => $type->labels->name,
82 | 'caps' => $has_caps,
83 | 'icon' => $icon,
84 | 'priority' => 10
85 | )
86 | );
87 | }
88 |
89 | // Register the taxonomy group.
90 | members_register_cap_group( 'taxonomy',
91 | array(
92 | 'label' => esc_html__( 'Taxonomies', 'members' ),
93 | 'caps' => members_get_taxonomy_group_caps(),
94 | 'icon' => 'dashicons-tag',
95 | 'diff_added' => true,
96 | 'priority' => 15
97 | )
98 | );
99 |
100 | // Register the theme group.
101 | members_register_cap_group( 'theme',
102 | array(
103 | 'label' => esc_html__( 'Appearance', 'members' ),
104 | 'icon' => 'dashicons-admin-appearance',
105 | 'priority' => 20
106 | )
107 | );
108 |
109 | // Register the plugin group.
110 | members_register_cap_group( 'plugin',
111 | array(
112 | 'label' => esc_html__( 'Plugins', 'members' ),
113 | 'icon' => 'dashicons-admin-plugins',
114 | 'priority' => 25
115 | )
116 | );
117 |
118 | // Register the user group.
119 | members_register_cap_group( 'user',
120 | array(
121 | 'label' => esc_html__( 'Users', 'members' ),
122 | 'icon' => 'dashicons-admin-users',
123 | 'priority' => 30
124 | )
125 | );
126 |
127 | // Register the custom group.
128 | members_register_cap_group( 'custom',
129 | array(
130 | 'label' => esc_html__( 'Custom', 'members' ),
131 | 'caps' => members_get_capabilities(),
132 | 'icon' => 'dashicons-admin-generic',
133 | 'diff_added' => true,
134 | 'priority' => 995
135 | )
136 | );
137 | }
138 |
139 | /**
140 | * Returns the instance of cap group registry.
141 | *
142 | * @since 2.0.0
143 | * @access public
144 | * @return object
145 | */
146 | function members_cap_group_registry() {
147 |
148 | return \Members\Registry::get_instance( 'cap_group' );
149 | }
150 |
151 | /**
152 | * Function for registering a cap group.
153 | *
154 | * @since 1.0.0
155 | * @access public
156 | * @param string $name
157 | * @param array $args
158 | * @return void
159 | */
160 | function members_register_cap_group( $name, $args = array() ) {
161 |
162 | members_cap_group_registry()->register( $name, new \Members\Cap_Group( $name, $args ) );
163 | }
164 |
165 | /**
166 | * Unregisters a group.
167 | *
168 | * @since 1.0.0
169 | * @access public
170 | * @param string $name
171 | * @return void
172 | */
173 | function members_unregister_cap_group( $name ) {
174 |
175 | members_cap_group_registry()->unregister( $name );
176 | }
177 |
178 | /**
179 | * Checks if a group exists.
180 | *
181 | * @since 1.0.0
182 | * @access public
183 | * @param string $name
184 | * @return bool
185 | */
186 | function members_cap_group_exists( $name ) {
187 |
188 | return members_cap_group_registry()->exists( $name );
189 | }
190 |
191 | /**
192 | * Returns an array of registered group objects.
193 | *
194 | * @since 1.0.0
195 | * @access public
196 | * @return array
197 | */
198 | function members_get_cap_groups() {
199 |
200 | return members_cap_group_registry()->get_collection();
201 | }
202 |
203 | /**
204 | * Returns a group object if it exists. Otherwise, `FALSE`.
205 | *
206 | * @since 1.0.0
207 | * @access public
208 | * @param string $name
209 | * @return object|bool
210 | */
211 | function members_get_cap_group( $name ) {
212 |
213 | return members_cap_group_registry()->get( $name );
214 | }
215 |
216 | /**
217 | * Returns the caps for a specific post type capability group.
218 | *
219 | * @since 1.0.0
220 | * @access public
221 | * @return array
222 | */
223 | function members_get_post_type_group_caps( $post_type = 'post' ) {
224 |
225 | // Get the post type caps.
226 | $caps = (array) get_post_type_object( $post_type )->cap;
227 |
228 | // remove meta caps.
229 | unset( $caps['edit_post'] );
230 | unset( $caps['read_post'] );
231 | unset( $caps['delete_post'] );
232 |
233 | // Get the cap names only.
234 | $caps = array_values( $caps );
235 |
236 | // If this is not a core post/page post type.
237 | if ( ! in_array( $post_type, array( 'post', 'page' ) ) ) {
238 |
239 | // Get the post and page caps.
240 | $post_caps = array_values( (array) get_post_type_object( 'post' )->cap );
241 | $page_caps = array_values( (array) get_post_type_object( 'page' )->cap );
242 |
243 | // Remove post/page caps from the current post type caps.
244 | $caps = array_diff( $caps, $post_caps, $page_caps );
245 | }
246 |
247 | // If attachment post type, add the `unfiltered_upload` cap.
248 | if ( 'attachment' === $post_type )
249 | $caps[] = 'unfiltered_upload';
250 |
251 | $registered_caps = array_keys( wp_list_filter( members_get_caps(), array( 'group' => "type-{$post_type}" ) ) );
252 |
253 | if ( $registered_caps )
254 | array_merge( $caps, $registered_caps );
255 |
256 | // Make sure there are no duplicates and return.
257 | return array_unique( $caps );
258 | }
259 |
260 | /**
261 | * Returns the caps for the taxonomy capability group.
262 | *
263 | * @since 1.0.0
264 | * @access public
265 | * @return array
266 | */
267 | function members_get_taxonomy_group_caps() {
268 |
269 | $do_not_add = array(
270 | 'assign_categories',
271 | 'edit_categories',
272 | 'delete_categories',
273 | 'assign_post_tags',
274 | 'edit_post_tags',
275 | 'delete_post_tags',
276 | 'manage_post_tags'
277 | );
278 |
279 | $taxi = get_taxonomies( array(), 'objects' );
280 |
281 | $caps = array();
282 |
283 | foreach ( $taxi as $tax )
284 | $caps = array_merge( $caps, array_values( (array) $tax->cap ) );
285 |
286 | $registered_caps = array_keys( wp_list_filter( members_get_caps(), array( 'group' => 'taxonomy' ) ) );
287 |
288 | if ( $registered_caps )
289 | array_merge( $caps, $registered_caps );
290 |
291 | return array_diff( array_unique( $caps ), $do_not_add );
292 | }
293 |
294 | /**
295 | * Returns the caps for the custom capability group.
296 | *
297 | * @since 1.0.0
298 | * @access public
299 | * @return array
300 | */
301 | function members_get_custom_group_caps() {
302 |
303 | $caps = members_get_capabilities();
304 |
305 | $registered_caps = array_keys( wp_list_filter( members_get_caps(), array( 'group' => 'custom' ) ) );
306 |
307 | if ( $registered_caps )
308 | array_merge( $caps, $registered_caps );
309 |
310 | return array_unique( $caps );
311 | }
312 |
--------------------------------------------------------------------------------
/inc/functions-content-permissions.php:
--------------------------------------------------------------------------------
1 | role_names as $role => $name ) {
111 |
112 | // If the WP role is one of the current roles but not a new role, remove it.
113 | if ( ! in_array( $role, $roles ) && in_array( $role, $current_roles ) )
114 | members_remove_post_role( $post_id, $role );
115 | }
116 | }
117 |
118 | /**
119 | * Deletes all of a post's access roles.
120 | *
121 | * @since 1.0.0
122 | * @access public
123 | * @param int $post_id
124 | * @return bool
125 | */
126 | function members_delete_post_roles( $post_id ) {
127 |
128 | return delete_post_meta( $post_id, '_members_access_role' );
129 | }
130 |
131 | /**
132 | * Adds required filters for the content permissions feature if it is active.
133 | *
134 | * @since 0.2.0
135 | * @access public
136 | * @global object $wp_embed
137 | * @return void
138 | */
139 | function members_enable_content_permissions() {
140 | global $wp_embed;
141 |
142 | // Only add filters if the content permissions feature is enabled and we're not in the admin.
143 | if ( members_content_permissions_enabled() && !is_admin() ) {
144 |
145 | // Filter the content and exerpts.
146 | add_filter( 'the_content', 'members_content_permissions_protect', 95 );
147 | add_filter( 'get_the_excerpt', 'members_content_permissions_protect', 95 );
148 | add_filter( 'the_excerpt', 'members_content_permissions_protect', 95 );
149 | add_filter( 'the_content_feed', 'members_content_permissions_protect', 95 );
150 | add_filter( 'get_comment_text', 'members_content_permissions_protect', 95 );
151 |
152 | // Filter the comments template to make sure comments aren't shown to users without access.
153 | add_filter( 'comments_template', 'members_content_permissions_comments', 95 );
154 |
155 | // Use WP formatting filters on the post error message.
156 | add_filter( 'members_post_error_message', array( $wp_embed, 'run_shortcode' ), 5 );
157 | add_filter( 'members_post_error_message', array( $wp_embed, 'autoembed' ), 5 );
158 | add_filter( 'members_post_error_message', 'wptexturize', 10 );
159 | add_filter( 'members_post_error_message', 'convert_smilies', 15 );
160 | add_filter( 'members_post_error_message', 'convert_chars', 20 );
161 | add_filter( 'members_post_error_message', 'wpautop', 25 );
162 | add_filter( 'members_post_error_message', 'do_shortcode', 30 );
163 | add_filter( 'members_post_error_message', 'shortcode_unautop', 35 );
164 | }
165 | }
166 |
167 | /**
168 | * Denies/Allows access to view post content depending on whether a user has permission to
169 | * view the content.
170 | *
171 | * @since 0.1.0
172 | * @access public
173 | * @param string $content
174 | * @return string
175 | */
176 | function members_content_permissions_protect( $content ) {
177 |
178 | $post_id = get_the_ID();
179 |
180 | return members_can_current_user_view_post( $post_id ) ? $content : members_get_post_error_message( $post_id );
181 | }
182 |
183 | /**
184 | * Disables the comments template if a user doesn't have permission to view the post the
185 | * comments are associated with.
186 | *
187 | * @since 0.1.0
188 | * @param string $template
189 | * @return string
190 | */
191 | function members_content_permissions_comments( $template ) {
192 |
193 | // Check if the current user has permission to view the comments' post.
194 | if ( ! members_can_current_user_view_post( get_the_ID() ) ) {
195 |
196 | // Look for a 'comments-no-access.php' template in the parent and child theme.
197 | $has_template = locate_template( array( 'comments-no-access.php' ) );
198 |
199 | // If the template was found, use it. Otherwise, fall back to the Members comments.php template.
200 | $template = $has_template ? $has_template : members_plugin()->dir . 'templates/comments.php';
201 |
202 | // Allow devs to overwrite the comments template.
203 | $template = apply_filters( 'members_comments_template', $template );
204 | }
205 |
206 | // Return the comments template filename.
207 | return $template;
208 | }
209 |
210 | /**
211 | * Gets the error message to display for users who do not have access to view the given post.
212 | * The function first checks to see if a custom error message has been written for the
213 | * specific post. If not, it loads the error message set on the plugins settings page.
214 | *
215 | * @since 0.2.0
216 | * @access public
217 | * @param int $post_id
218 | * @return string
219 | */
220 | function members_get_post_error_message( $post_id ) {
221 |
222 | // Get the error message for the specific post.
223 | $message = members_get_post_access_message( $post_id );
224 |
225 | // Use default error message if we don't have one for the post.
226 | if ( ! $message )
227 | $message = members_get_setting( 'content_permissions_error' );
228 |
229 | // Return the error message.
230 | return apply_filters( 'members_post_error_message', sprintf( '
%s
', $message ) );
231 | }
232 |
233 | /**
234 | * Returns the post access message.
235 | *
236 | * @since 1.0.0
237 | * @access public
238 | * @param int $post_id
239 | * @return string
240 | */
241 | function members_get_post_access_message( $post_id ) {
242 |
243 | return get_post_meta( $post_id, '_members_access_error', true );
244 | }
245 |
246 | /**
247 | * Sets the post access message.
248 | *
249 | * @since 1.0.0
250 | * @access public
251 | * @param int $post_id
252 | * @param string $message
253 | * @return bool
254 | */
255 | function members_set_post_access_message( $post_id, $message ) {
256 |
257 | return update_post_meta( $post_id, '_members_access_error', $message );
258 | }
259 |
260 | /**
261 | * Deletes the post access message.
262 | *
263 | * @since 1.0.0
264 | * @access public
265 | * @param int $post_id
266 | * @return bool
267 | */
268 | function members_delete_post_access_message( $post_id ) {
269 |
270 | return delete_post_meta( $post_id, '_members_access_error' );
271 | }
272 |
273 | /**
274 | * Converts the meta values of the old '_role' post meta key to the newer '_members_access_role' meta
275 | * key. The reason for this change is to avoid any potential conflicts with other plugins/themes. We're
276 | * now using a meta key that is extremely specific to the Members plugin.
277 | *
278 | * @since 0.2.0
279 | * @access public
280 | * @param int $post_id
281 | * @return array|bool
282 | */
283 | function members_convert_old_post_meta( $post_id ) {
284 |
285 | // Check if there are any meta values for the '_role' meta key.
286 | $old_roles = get_post_meta( $post_id, '_role', false );
287 |
288 | // If roles were found, let's convert them.
289 | if ( !empty( $old_roles ) ) {
290 |
291 | // Delete the old '_role' post meta.
292 | delete_post_meta( $post_id, '_role' );
293 |
294 | // Check if there are any roles for the '_members_access_role' meta key.
295 | $new_roles = get_post_meta( $post_id, '_members_access_role', false );
296 |
297 | // If new roles were found, don't do any conversion.
298 | if ( empty( $new_roles ) ) {
299 |
300 | // Loop through the old meta values for '_role' and add them to the new '_members_access_role' meta key.
301 | foreach ( $old_roles as $role )
302 | add_post_meta( $post_id, '_members_access_role', $role, false );
303 |
304 | // Return the array of roles.
305 | return $old_roles;
306 | }
307 | }
308 |
309 | // Return false if we get to this point.
310 | return false;
311 | }
312 |
--------------------------------------------------------------------------------
/inc/functions-options.php:
--------------------------------------------------------------------------------
1 |
8 | * @copyright Copyright (c) 2009 - 2018, Justin Tadlock
9 | * @link https://themehybrid.com/plugins/members
10 | * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
11 | */
12 |
13 | /**
14 | * Conditional check to see if the role manager is enabled.
15 | *
16 | * @since 1.0.0
17 | * @access public
18 | * @return bool
19 | */
20 | function members_role_manager_enabled() {
21 |
22 | return apply_filters( 'members_role_manager_enabled', members_get_setting( 'role_manager' ) );
23 | }
24 |
25 | /**
26 | * Conditional check to see if denied capabilities should overrule granted capabilities when
27 | * a user has multiple roles with conflicting cap definitions.
28 | *
29 | * @since 1.0.0
30 | * @access public
31 | * @return bool
32 | */
33 | function members_explicitly_deny_caps() {
34 |
35 | return apply_filters( 'members_explicitly_deny_caps', members_get_setting( 'explicit_denied_caps' ) );
36 | }
37 |
38 | /**
39 | * Whether to show human-readable caps.
40 | *
41 | * @since 2.0.0
42 | * @access public
43 | * @return bool
44 | */
45 | function members_show_human_caps() {
46 |
47 | return apply_filters( 'members_show_human_caps', members_get_setting( 'show_human_caps' ) );
48 | }
49 |
50 | /**
51 | * Conditional check to see if the role manager is enabled.
52 | *
53 | * @since 1.0.0
54 | * @access public
55 | * @return bool
56 | */
57 | function members_multiple_user_roles_enabled() {
58 |
59 | return apply_filters( 'members_multiple_roles_enabled', members_get_setting( 'multi_roles' ) );
60 | }
61 |
62 | /**
63 | * Conditional check to see if content permissions are enabled.
64 | *
65 | * @since 1.0.0
66 | * @access public
67 | * @return bool
68 | */
69 | function members_content_permissions_enabled() {
70 |
71 | return apply_filters( 'members_content_permissions_enabled', members_get_setting( 'content_permissions' ) );
72 | }
73 |
74 | /**
75 | * Conditional check to see if login widget is enabled.
76 | *
77 | * @since 1.0.0
78 | * @access public
79 | * @return bool
80 | */
81 | function members_login_widget_enabled() {
82 |
83 | return apply_filters( 'members_login_widget_enabled', members_get_setting( 'login_form_widget' ) );
84 | }
85 |
86 | /**
87 | * Conditional check to see if users widget is enabled.
88 | *
89 | * @since 1.0.0
90 | * @access public
91 | * @return bool
92 | */
93 | function members_users_widget_enabled() {
94 |
95 | return apply_filters( 'members_users_widget_enabled', members_get_setting( 'users_widget' ) );
96 | }
97 |
98 | /**
99 | * Gets a setting from from the plugin settings in the database.
100 | *
101 | * @since 0.2.0
102 | * @access public
103 | * @return mixed
104 | */
105 | function members_get_setting( $option = '' ) {
106 |
107 | $defaults = members_get_default_settings();
108 |
109 | $settings = wp_parse_args( get_option( 'members_settings', $defaults ), $defaults );
110 |
111 | return isset( $settings[ $option ] ) ? $settings[ $option ] : false;
112 | }
113 |
114 | /**
115 | * Returns an array of the default plugin settings.
116 | *
117 | * @since 0.2.0
118 | * @access public
119 | * @return array
120 | */
121 | function members_get_default_settings() {
122 |
123 | return array(
124 |
125 | // @since 0.1.0
126 | 'role_manager' => 1,
127 | 'content_permissions' => 1,
128 | 'private_blog' => 0,
129 |
130 | // @since 0.2.0
131 | 'private_feed' => 0,
132 | 'login_form_widget' => 0,
133 | 'users_widget' => 0,
134 | 'content_permissions_error' => esc_html__( 'Sorry, but you do not have permission to view this content.', 'members' ),
135 | 'private_feed_error' => esc_html__( 'You must be logged into the site to view this content.', 'members' ),
136 |
137 | // @since 1.0.0
138 | 'explicit_denied_caps' => true,
139 | 'multi_roles' => true,
140 |
141 | // @since 2.0.0
142 | 'show_human_caps' => true,
143 | 'private_rest_api' => false,
144 | );
145 | }
146 |
--------------------------------------------------------------------------------
/inc/functions-private-site.php:
--------------------------------------------------------------------------------
1 |
10 | * @copyright Copyright (c) 2009 - 2018, Justin Tadlock
11 | * @link https://themehybrid.com/plugins/members
12 | * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
13 | */
14 |
15 | # Redirects users to the login page.
16 | add_action( 'template_redirect', 'members_please_log_in', 0 );
17 |
18 | # Disable content in feeds if the feed should be private.
19 | add_filter( 'the_content_feed', 'members_private_feed', 95 );
20 | add_filter( 'the_excerpt_rss', 'members_private_feed', 95 );
21 | add_filter( 'comment_text_rss', 'members_private_feed', 95 );
22 |
23 | # Filters for the feed error message.
24 | add_filter( 'members_feed_error_message', array( $GLOBALS['wp_embed'], 'run_shortcode' ), 5 );
25 | add_filter( 'members_feed_error_message', array( $GLOBALS['wp_embed'], 'autoembed' ), 5 );
26 | add_filter( 'members_feed_error_message', 'wptexturize', 10 );
27 | add_filter( 'members_feed_error_message', 'convert_smilies', 15 );
28 | add_filter( 'members_feed_error_message', 'convert_chars', 20 );
29 | add_filter( 'members_feed_error_message', 'wpautop', 25 );
30 | add_filter( 'members_feed_error_message', 'do_shortcode', 30 );
31 | add_filter( 'members_feed_error_message', 'shortcode_unautop', 35 );
32 |
33 | # Authenticate when accessing the REST API.
34 | add_filter( 'rest_authentication_errors', 'members_private_rest_api', 95 );
35 |
36 | /**
37 | * Conditional tag to see if we have a private blog.
38 | *
39 | * @since 1.0.0
40 | * @access public
41 | * @return bool
42 | */
43 | function members_is_private_blog() {
44 |
45 | return apply_filters( 'members_is_private_blog', members_get_setting( 'private_blog' ) );
46 | }
47 |
48 | /**
49 | * Conditional tag to see if we have a private feed.
50 | *
51 | * @since 1.0.0
52 | * @access public
53 | * @return bool
54 | */
55 | function members_is_private_feed() {
56 |
57 | return apply_filters( 'members_is_private_feed', members_get_setting( 'private_feed' ) );
58 | }
59 |
60 | /**
61 | * Conditional tag to see if we have a private REST API
62 | *
63 | * @since 2.0.0
64 | * @access public
65 | * @return bool
66 | */
67 | function members_is_private_rest_api() {
68 |
69 | return apply_filters( 'members_is_private_rest_api', members_get_setting( 'private_rest_api' ) );
70 | }
71 |
72 | /**
73 | * Redirects users that are not logged in to the 'wp-login.php' page.
74 | *
75 | * @since 0.1.0
76 | * @access public
77 | * @return void
78 | */
79 | function members_please_log_in() {
80 |
81 | // If private blog is not enabled, bail.
82 | if ( ! members_is_private_blog() )
83 | return;
84 |
85 | // If this is a multisite instance and the user is logged into the network.
86 | if ( is_multisite() && is_user_logged_in() && ! is_user_member_of_blog() && ! is_super_admin() ) {
87 | members_ms_private_blog_die();
88 | }
89 |
90 | // Check if the private blog feature is active and if the user is not logged in.
91 | if ( ! is_user_logged_in() && members_is_private_page() ) {
92 |
93 | auth_redirect();
94 | exit;
95 | }
96 | }
97 |
98 | /**
99 | * Function for determining whether a page should be public even though we're in private
100 | * site mode. Plugin devs can filter this to make specific pages public.
101 | *
102 | * @since 2.0.0
103 | * @access public
104 | * @return bool
105 | */
106 | function members_is_private_page() {
107 |
108 | $is_private = true;
109 |
110 | if ( function_exists( 'bp_is_current_component' ) && ( bp_is_current_component( 'register' ) || bp_is_current_component( 'activate' ) ) )
111 | $is_private = false;
112 |
113 | // WooCommerce support.
114 | if ( class_exists( 'WooCommerce' ) ) {
115 | $page_id = get_option( 'woocommerce_myaccount_page_id' );
116 |
117 | if ( $page_id && is_page( $page_id ) )
118 | $is_private = false;
119 | }
120 |
121 | return apply_filters( 'members_is_private_page', $is_private );
122 | }
123 |
124 | /**
125 | * Blocks feed items if the user has selected the private feed feature.
126 | *
127 | * @since 0.2.0
128 | * @access public
129 | * @param string $content
130 | * @return string
131 | */
132 | function members_private_feed( $content ) {
133 |
134 | return members_is_private_feed() ? members_get_private_feed_message() : $content;
135 | }
136 |
137 | /**
138 | * Returns the private feed error message.
139 | *
140 | * @since 1.0.0
141 | * @access public
142 | * @return string
143 | */
144 | function members_get_private_feed_message() {
145 |
146 | return apply_filters( 'members_feed_error_message', members_get_setting( 'private_feed_error' ) );
147 | }
148 |
149 | /**
150 | * Returns an error if the REST API is accessed by an unauthenticated user.
151 | *
152 | * @link https://developer.wordpress.org/rest-api/using-the-rest-api/frequently-asked-questions/#require-authentication-for-all-requests
153 | * @since 2.0.0
154 | * @access public
155 | * @param object $result
156 | * @return object
157 | */
158 | function members_private_rest_api( $result ) {
159 |
160 | if ( empty( $result ) && members_is_private_rest_api() && ! is_user_logged_in() ) {
161 |
162 | return new WP_Error(
163 | 'rest_not_logged_in',
164 | esc_html(
165 | apply_filters(
166 | 'members_rest_api_error_message',
167 | __( 'You are not currently logged in.', 'members' )
168 | )
169 | ),
170 | array( 'status' => 401 )
171 | );
172 | }
173 |
174 | return $result;
175 | }
176 |
177 | /**
178 | * Outputs an error message if a user attempts to access a site that they do not have
179 | * access to on multisite.
180 | *
181 | * @since 2.0.0
182 | * @access public
183 | * @return void
184 | */
185 | function members_ms_private_blog_die() {
186 |
187 | $blogs = get_blogs_of_user( get_current_user_id() );
188 |
189 | $blogname = get_bloginfo( 'name' );
190 |
191 | $message = __( 'You do not currently have access to the "%s" site. If you believe you should have access, please contact your network administrator.', 'members' );
192 |
193 | if ( empty( $blogs ) )
194 | wp_die( sprintf( $message, $blogname ), 403 );
195 |
196 | $output = '
' . sprintf( $message, $blogname ) . '
';
197 |
198 | $output .= sprintf( '
%s
', __( 'If you reached this page by accident and meant to visit one of your own sites, try one of the following links.', 'members' ) );
199 |
200 | $output .= '
', $output );
154 | }
155 |
156 | $output = apply_filters( 'members_list_users', $output );
157 |
158 | if ( empty( $args['echo'] ) )
159 | return $output;
160 |
161 | echo $output;
162 | }
163 |
--------------------------------------------------------------------------------
/js/edit-post.js:
--------------------------------------------------------------------------------
1 | ( function() {
2 |
3 | /* ====== Tabs ====== */
4 |
5 | // Hides the tab content.
6 | jQuery( '.members-tabs .members-tab-content' ).hide();
7 |
8 | // Shows the first tab's content.
9 | jQuery( '.members-tabs .members-tab-content:first-child' ).show();
10 |
11 | // Makes the 'aria-selected' attribute true for the first tab nav item.
12 | jQuery( '.members-tab-nav :first-child' ).attr( 'aria-selected', 'true' );
13 |
14 | // When a tab nav item is clicked.
15 | jQuery( '.members-tab-nav li a' ).click(
16 | function( j ) {
17 |
18 | // Prevent the default browser action when a link is clicked.
19 | j.preventDefault();
20 |
21 | // Get the `href` attribute of the item.
22 | var href = jQuery( this ).attr( 'href' );
23 |
24 | // Hide all tab content.
25 | jQuery( this ).parents( '.members-tabs' ).find( '.members-tab-content' ).hide();
26 |
27 | // Find the tab content that matches the tab nav item and show it.
28 | jQuery( this ).parents( '.members-tabs' ).find( href ).show();
29 |
30 | // Set the `aria-selected` attribute to false for all tab nav items.
31 | jQuery( this ).parents( '.members-tabs' ).find( '.members-tab-title' ).attr( 'aria-selected', 'false' );
32 |
33 | // Set the `aria-selected` attribute to true for this tab nav item.
34 | jQuery( this ).parent().attr( 'aria-selected', 'true' );
35 | }
36 | ); // click()
37 |
38 | }() );
39 |
--------------------------------------------------------------------------------
/js/edit-post.min.js:
--------------------------------------------------------------------------------
1 | !function(){jQuery(".members-tabs .members-tab-content").hide(),jQuery(".members-tabs .members-tab-content:first-child").show(),jQuery(".members-tab-nav :first-child").attr("aria-selected","true"),jQuery(".members-tab-nav li a").click(function(e){e.preventDefault();var t=jQuery(this).attr("href");jQuery(this).parents(".members-tabs").find(".members-tab-content").hide(),jQuery(this).parents(".members-tabs").find(t).show(),jQuery(this).parents(".members-tabs").find(".members-tab-title").attr("aria-selected","false"),jQuery(this).parent().attr("aria-selected","true")})}();
--------------------------------------------------------------------------------
/js/edit-role.min.js:
--------------------------------------------------------------------------------
1 | jQuery(document).ready(function(){function e(e){e=e.toLowerCase().trim().replace(/<.*?>/g,"").replace(/\s/g,"_").replace(/[^a-zA-Z0-9_]/g,""),jQuery(".role-slug").text(e)}function r(){var e=jQuery("#members-tab-all input[data-grant-cap]:checked").length,r=jQuery("#members-tab-all input[data-deny-cap]:checked").length,t=jQuery('#members-tab-custom input[name="grant-new-caps[]"]:checked').length,a=jQuery('#members-tab-custom input[name="deny-new-caps[]"]:checked').length;jQuery("#submitdiv .granted-count").text(e+t),jQuery("#submitdiv .denied-count").text(r+a)}function t(e){var r="grant",t="deny";jQuery(e).attr("data-deny-cap")&&(r="deny",t="grant");var a=jQuery(e).attr("data-"+r+"-cap");jQuery(e).prop("checked")?(jQuery("input[data-"+r+'-cap="'+a+'"]').not(e).prop("checked",!0),jQuery("input[data-"+t+'-cap="'+a+'"]').prop("checked",!1)):jQuery("input[data-"+r+'-cap="'+a+'"]').not(e).prop("checked",!1)}jQuery(".members-delete-role-link").click(function(){return window.confirm(members_i18n.ays_delete_role)}),jQuery('input[name="role_name"]').keyup(function(){jQuery('input[name="role"]').val()||e(this.value)}),jQuery('input[name="role"], .role-ok-button').hide(),jQuery(document).on("click",".role-edit-button.closed",function(){jQuery(this).removeClass("closed").addClass("open").text(members_i18n.button_role_ok),jQuery('input[name="role"]').show(),jQuery('input[name="role"]').trigger("focus"),jQuery('input[name="role"]').attr("value",jQuery(".role-slug").text())}),jQuery(document).on("click",".role-edit-button.open",function(){jQuery(this).removeClass("open").addClass("closed").text(members_i18n.button_role_edit),jQuery('input[name="role"]').hide();var r=jQuery('input[name="role"]').val();e(r?r:jQuery('input[name="role_name"]').val())}),jQuery('input[name="role"]').keypress(function(e){if(13===e.keyCode)return jQuery(".role-edit-button").click().trigger("focus"),e.preventDefault(),!1}),jQuery('.users_page_role-new input[name="role_name"]').val()||jQuery(".users_page_role-new #publish").prop("disabled",!0),jQuery('.users_page_role-new input[name="role_name"]').on("input",function(){jQuery(this).val()?jQuery(".users_page_role-new #publish").prop("disabled",!1):jQuery(".users_page_role-new #publish").prop("disabled",!0)});var a=wp.template("members-cap-section"),n=wp.template("members-cap-control");"undefined"!=typeof members_sections&&"undefined"!=typeof members_controls&&(_.each(members_sections,function(e){jQuery(".members-tab-wrap").append(a(e))}),_.each(members_controls,function(e){jQuery("#members-tab-"+e.section+" tbody").append(n(e))})),jQuery(".members-cap-tabs .members-tab-content").hide(),jQuery(".members-cap-tabs .members-tab-content:first-child").show(),jQuery(".members-tab-nav :first-child").attr("aria-selected","true"),jQuery(".members-which-tab").text(jQuery(".members-tab-nav :first-child a").text()),jQuery(".members-tab-nav li a").click(function(e){e.preventDefault();var r=jQuery(this).attr("href");jQuery(this).parents(".members-cap-tabs").find(".members-tab-content").hide(),jQuery(this).parents(".members-cap-tabs").find(r).show(),jQuery(this).parents(".members-cap-tabs").find(".members-tab-title").attr("aria-selected","false"),jQuery(this).parent().attr("aria-selected","true"),jQuery(".members-which-tab").text(jQuery(this).text())}),r(),jQuery(document).on("change",".members-cap-checklist input[data-grant-cap], .members-cap-checklist input[data-deny-cap]",function(){t(this),r()}),jQuery(document).on("click",".editable-role .members-cap-checklist button",function(){var e=jQuery(this).closest(".members-cap-checklist"),r=jQuery(e).find("input[data-grant-cap]"),t=jQuery(e).find("input[data-deny-cap]");jQuery(r).prop("checked")?(jQuery(r).prop("checked",!1),jQuery(t).prop("checked",!0).change()):jQuery(t).prop("checked")?(jQuery(r).prop("checked",!1),jQuery(t).prop("checked",!1).change()):jQuery(r).prop("checked",!0).change()}),jQuery(document).on("hover",".editable-role .members-cap-checklist button",function(){jQuery(".members-cap-checklist button:focus").not(this).blur()}),postboxes.add_postbox_toggles(pagenow),jQuery("#newcapdiv button.handlediv").attr("type","button"),jQuery("#members-add-new-cap").prop("disabled",!0),jQuery("#members-new-cap-field").on("input",function(){-1===jQuery.inArray(jQuery(this).val(),members_i18n.hidden_caps)?jQuery("#members-add-new-cap").prop("disabled",!1):jQuery("#members-add-new-cap").prop("disabled",!0)}),jQuery("#members-new-cap-field").keypress(function(e){if(13===e.keyCode)return jQuery("#members-add-new-cap").click(),e.preventDefault(),!1}),jQuery("#members-add-new-cap").click(function(){var e=jQuery("#members-new-cap-field").val();if(e=e.trim().replace(/<.*?>/g,"").replace(/\s/g,"_").replace(/[^a-zA-Z0-9_]/g,"")){if(-1!==jQuery.inArray(jQuery(this).val(),members_i18n.hidden_caps))return;jQuery('a[href="#members-tab-custom"]').trigger("click"),members_i18n.label_grant_cap=members_i18n.label_grant_cap.replace(/%s/g,""+e+""),members_i18n.label_deny_cap=members_i18n.label_deny_cap.replace(/%s/g,""+e+"");var r={cap:e,readonly:"",name:{grant:"grant-new-caps[]",deny:"deny-new-caps[]"},is_granted_cap:!0,is_denied_cap:!1,label:{cap:e,grant:members_i18n.label_grant_cap,deny:members_i18n.label_deny_cap}};jQuery("#members-tab-custom tbody").prepend(n(r));var t=jQuery('[data-grant-cap="'+e+'"]').parents(".members-cap-checklist");jQuery(t).addClass("members-highlight"),setTimeout(function(){jQuery(t).removeClass("members-highlight")},500),jQuery("#members-new-cap-field").val(""),jQuery("#members-add-new-cap").prop("disabled",!0),jQuery('.members-cap-checklist input[data-grant-cap="'+e+'"]').trigger("change")}})});
--------------------------------------------------------------------------------
/js/settings.js:
--------------------------------------------------------------------------------
1 | jQuery( document ).ready( function() {
2 |
3 | /* ====== Plugin Settings ====== */
4 |
5 | // Hide content permissions message if disabled.
6 | if ( false === jQuery( '[name="members_settings[content_permissions]"]' ).prop( 'checked' ) ) {
7 |
8 | jQuery( '[name="members_settings[content_permissions]"]' ).parents( 'tr' ).next( 'tr' ).hide();
9 | }
10 |
11 | // Hide private feed message if private feed disabled.
12 | if ( false === jQuery( '[name="members_settings[private_feed]"]' ).prop( 'checked' ) ) {
13 |
14 | jQuery( '[name="members_settings[private_feed]"]' ).parents( 'tr' ).next( 'tr' ).hide();
15 | }
16 |
17 | // Show above hidden items if feature becomes enabled.
18 | jQuery( '[name="members_settings[content_permissions]"], [name="members_settings[private_feed]"]' ).on( 'change',
19 | function() {
20 |
21 | if ( jQuery( this ).prop( 'checked' ) ) {
22 |
23 | jQuery( this ).parents( 'tr' ).next( 'tr' ).show( 'slow' );
24 | } else {
25 |
26 | jQuery( this ).parents( 'tr' ).next( 'tr' ).hide( 'slow' );
27 | }
28 | }
29 | );
30 | } );
31 |
--------------------------------------------------------------------------------
/js/settings.min.js:
--------------------------------------------------------------------------------
1 | jQuery(document).ready(function(){!1===jQuery('[name="members_settings[content_permissions]"]').prop("checked")&&jQuery('[name="members_settings[content_permissions]"]').parents("tr").next("tr").hide(),!1===jQuery('[name="members_settings[private_feed]"]').prop("checked")&&jQuery('[name="members_settings[private_feed]"]').parents("tr").next("tr").hide(),jQuery('[name="members_settings[content_permissions]"], [name="members_settings[private_feed]"]').on("change",function(){jQuery(this).prop("checked")?jQuery(this).parents("tr").next("tr").show("slow"):jQuery(this).parents("tr").next("tr").hide("slow")})});
--------------------------------------------------------------------------------
/readme.txt:
--------------------------------------------------------------------------------
1 | === Members ===
2 |
3 | Contributors: greenshady
4 | Donate link: https://themehybrid.com/plugins/members#donate
5 | Tags: capabilities, roles, members, users
6 | Requires at least: 4.7
7 | Tested up to: 5.2
8 | Requires PHP: 5.6
9 | Stable tag: 2.2.0
10 | License: GPLv2 or later
11 | License URI: http://www.gnu.org/licenses/gpl-2.0.html
12 |
13 | The most powerful user, role, and capability management plugin for WordPress.
14 |
15 | == Description ==
16 |
17 | Members is a plugin that extends your control over your blog. It's a user, role, and capability editor plugin that was created to make WordPress a more powerful CMS.
18 |
19 | It puts you in control over permissions on your site by providing a user interface (UI) for WordPress' powerful role and cap system, which is traditionally only available to developers who know how to code this by hand.
20 |
21 | ### Plugin Features
22 |
23 | * **Role Editor:** Allows you to edit, create, and delete roles as well as capabilities for these roles.
24 | * **Multiple User Roles:** Give one, two, or even more roles to any user.
25 | * **Explicitly Deny Capabilities:** Deny specific caps to specific user roles.
26 | * **Clone Roles:** Build a new role by cloning an existing role.
27 | * **Content Permissions:** Gives you control over which users (by role) have access to post content.
28 | * **Shortcodes:** Shortcodes to control who has access to content.
29 | * **Widgets:** A login form widget and users widget to show in your theme's sidebars.
30 | * **Private Site:** You can make your site and its feed completely private if you want.
31 | * **Plugin Integration:** Members is highly recommended by other WordPress developers. Many existing plugins integrate their custom roles and caps directly into it.
32 |
33 | For more info, visit the [Members plugin home page](https://themehybrid.com/plugins/members).
34 |
35 | ### Like this plugin?
36 |
37 | The Members plugin is a massive project with 1,000s of lines of code to maintain. A major update can take weeks or months of work. I don't make any money directly from this plugin while other, similar plugins charge substantial fees to even download them or get updates. Please consider helping the cause by:
38 |
39 | * [Making a donation](https://themehybrid.com/plugins/members#donate).
40 | * [Signing up at my site](https://themehybrid.com/plugins/members).
41 | * [Rating the plugin](https://wordpress.org/support/view/plugin-reviews/members?rate=5#postform).
42 |
43 | ### Professional Support
44 |
45 | If you need professional plugin support from me, the plugin author, you can access the support forums at [Theme Hybrid](https://themehybrid.com/board/topics), which is a professional WordPress help/support site where I handle support for all my plugins and themes for a community of 75,000+ users (and growing).
46 |
47 | ### Plugin Development
48 |
49 | If you're a theme author, plugin author, or just a code hobbyist, you can follow the development of this plugin on it's [GitHub repository](https://github.com/justintadlock/members).
50 |
51 | == Installation ==
52 |
53 | 1. Upload `members` to the `/wp-content/plugins/` directory.
54 | 2. Activate the plugin through the 'Plugins' menu in WordPress.
55 | 3. Go to "Settings > Members" to select which settings you'd like to use.
56 |
57 | More detailed instructions are included in the plugin's `readme.html` file.
58 |
59 | == Frequently Asked Questions ==
60 |
61 | ### Why was this plugin created?
62 |
63 | I wasn't satisfied with the current user, role, and permissions plugins available. Yes, some of them are good, but nothing fit what I had in mind perfectly. Some offered few features. Some worked completely outside of the WordPress APIs. Others lacked the GPL license.
64 |
65 | So, I just built something I actually enjoyed using.
66 |
67 | ### How do I use it?
68 |
69 | Most things should be fairly straightforward, but I've included an in-depth guide in the plugin download. It's a file called `readme.md` in the plugin folder.
70 |
71 | You can also [view the readme](https://github.com/justintadlock/members/blob/master/readme.md) online.
72 |
73 | ### Minimum PHP requirements.
74 |
75 | Since version 2.1.0 of Members, PHP 5.6+ is a soft requirement to use the plugin. The plugin will still work on PHP 5.3+, but it is not recommended.
76 |
77 | When Members version 3.0.0 is released, PHP 5.6+ will be a hard requirement and won't work on older versions of PHP.
78 |
79 | ### I can't access the "Role Manager" features.
80 |
81 | When the plugin is first activated, it runs a script that sets specific capabilities to the "Administrator" role on your site that grants you access to this feature. So, you must be logged in with the administrator account to access the role manager.
82 |
83 | If, for some reason, you do have the administrator role and the role manager is still inaccessible to you, deactivate the plugin. Then, reactivate it.
84 |
85 | ### On multisite, why can't administrators cannot manage roles?
86 |
87 | If you have a multisite installation, only Super Admins can create, edit, and delete roles by default. This is a security measure to make sure that you absolutely trust sub-site admins to make these types of changes to roles. If you're certain you want to allow this, add the Create Roles (`create_roles`), Edit Roles (`edit_roles`), and/or Delete Roles (`delete_roles`) capabilities to the role on each sub-site where you want to allow this.
88 |
89 | _Note: This change was made in version 2.0.2 and has no effect on existing installs of Members on existing sub-sites._
90 |
91 | ### Help! I've locked myself out of my site!
92 |
93 | Please read the documentation for the plugin before actually using it, especially a plugin that controls permissions for your site. I cannot stress this enough. This is a powerful plugin that allows you to make direct changes to roles and capabilities in the database.
94 |
95 | You'll need to stop by my [support forums](https://themehybrid.com/board/topics) to see if we can get your site fixed if you managed to lock yourself out. I know that this can be a bit can be a bit scary, but it's not that tough to fix with a little custom code.
96 |
97 | == Screenshots ==
98 |
99 | 1. Role management screen
100 | 2. Edit role screen
101 | 3. Content permissions meta box (edit post/page screen)
102 | 4. Plugin settings screen
103 | 5. Select multiple roles per user (edit user screen)
104 |
105 | == Upgrade Notice ==
106 |
107 | If upgrading from a version prior to 2.0.0, please note that the plugin now requires PHP 5.3.0 or later.
108 |
109 | == Changelog ==
110 |
111 | The change log is located in the `changelog.md` file in the plugin folder. You may also [view the change log](https://github.com/justintadlock/members/blob/master/changelog.md) online.
112 |
--------------------------------------------------------------------------------
/screenshot-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/justintadlock/members/07a1eeebdb1efee61534885f4e087ac167d46736/screenshot-1.png
--------------------------------------------------------------------------------
/screenshot-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/justintadlock/members/07a1eeebdb1efee61534885f4e087ac167d46736/screenshot-2.png
--------------------------------------------------------------------------------
/screenshot-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/justintadlock/members/07a1eeebdb1efee61534885f4e087ac167d46736/screenshot-3.png
--------------------------------------------------------------------------------
/screenshot-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/justintadlock/members/07a1eeebdb1efee61534885f4e087ac167d46736/screenshot-4.png
--------------------------------------------------------------------------------
/screenshot-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/justintadlock/members/07a1eeebdb1efee61534885f4e087ac167d46736/screenshot-5.png
--------------------------------------------------------------------------------
/templates/comments.php:
--------------------------------------------------------------------------------
1 |