-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathclasses.capabilities.php
291 lines (228 loc) · 7.57 KB
/
classes.capabilities.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
<?php
class BU_Section_Capabilities {
/**
* Get all Section Editing caps for the registered post types.
*
* @return array $caps
**/
public function get_caps() {
$caps = array( 'edit_in_section' );
$operations = array( 'edit', 'delete', 'publish' );
$post_types = $this->get_post_types();
foreach ( $post_types as $post_type ) {
if ( $post_type->public != true || in_array( $post_type->name, array( 'attachment' ) ) ) {
continue;
}
foreach ( $operations as $op ) {
$caps[] = $this->get_section_cap( $op, $post_type->name );
}
}
return $caps;
}
/**
* Add (edit|publish|delete)_*_in_section caps to the given role.
*
* @param mixed $role a WP_Role object, or string representation of a role name
*/
public function add_caps( $role ) {
if ( is_string( $role ) ) {
$role = get_role( $role );
}
if ( empty( $role ) || ! is_object( $role ) ) {
error_log( __METHOD__ . ' - Invalid role!' );
return false;
}
foreach ( $this->get_caps() as $cap ) {
$role->add_cap( $cap );
}
}
/**
* Filter that modifies the caps needing to take certain actions in cases
* where the user ($user_id) does not have the capabilities that WordPress
* has mapped to the meta capability. The mapping is based on which post is
* being edited, the Section Groups granted access to the post, and the
* membership of the user in those groups.
*
* @param array $caps
* @param string $cap
* @param int $user_id
* @param mixed $args
* @return array
*/
public function map_meta_cap( $caps, $cap, $user_id, $args ) {
global $post_ID;
$user = new WP_User( intval( $user_id ) );
// if user already has the caps as passed by map_meta_cap() pre-filter or
// the user doesn't have the main "section editing" cap
if ( $this->user_has_caps( $user, $caps ) || ! $this->user_has_cap( $user, 'edit_in_section' ) ) {
return $caps; // bail early
}
if ( $this->is_post_cap( $cap, 'edit_post' ) ) {
$caps = $this->_override_edit_caps( $user, $args[0], $caps );
}
if ( $this->is_post_cap( $cap, 'delete_post' ) ) {
$caps = $this->_override_delete_caps( $user, $args[0], $caps );
}
// As publish_posts does not come tied to a post ID, relying on the global $post_ID is fragile
// For instance, the "Quick Edit" interface of the edit posts page does not populate this
// global, and therefore the "Published" status is unavailable with this meta_cap check in place
if ( $this->is_post_cap( $cap, 'publish_posts' ) ) {
$caps = $this->_override_publish_caps( $user, $post_ID, $caps );
}
return $caps;
}
/**
* Check some $_POST variables to see if the posted data matches the post
* we are checking permissions against
**/
private function is_parent_changing( $post ) {
return isset( $_POST['post_ID'] ) && $post->ID == $_POST['post_ID'] && isset( $_POST['parent_id'] ) && $post->post_parent != $_POST['parent_id'];
}
private function get_new_parent() {
return (int) $_POST['parent_id'];
}
/**
* When working with revisions, check for parent post's permissions.
* Returns the parent post ID if `$post_id` points to a revision.
*
* @param int $post_id
* @return int
*/
private function switch_revision_to_parent( $post_id ) {
$post = get_post( $post_id );
if ( 'revision' == $post->post_type ) {
$post_id = $post->post_parent;
}
return $post_id;
}
private function _override_edit_caps( $user, $post_id, $caps ) {
if ( empty( $post_id ) ) {
return $caps;
}
$parent_id = null;
$post_id = $this->switch_revision_to_parent( $post_id );
$post = get_post( $post_id );
$post_type = get_post_type_object( $post->post_type );
if ( $post_type->hierarchical != true ) {
if ( BU_Group_Permissions::can_edit_section( $user, $post_id ) ) {
$caps = array( $this->get_section_cap( 'edit', $post->post_type ) );
}
} else {
if ( $this->is_parent_changing( $post ) ) {
$parent_id = $this->get_new_parent( $post );
if ( $post->post_status == 'publish' && BU_Group_Permissions::can_edit_section( $user, $parent_id ) ) {
$caps = array( $this->get_section_cap( 'edit', $post->post_type ) );
}
}
if ( $post_id && $post->post_status == 'publish' && BU_Group_Permissions::can_edit_section( $user, $post_id ) ) {
$caps = array( $this->get_section_cap( 'edit', $post->post_type ) );
}
}
return $caps;
}
private function _override_delete_caps( $user, $post_id, $caps ) {
$post = get_post( $post_id );
$post_type = get_post_type_object( $post->post_type );
if ( $post_type->hierarchical != true ) {
if ( BU_Group_Permissions::can_edit_section( $user, $post_id ) ) {
$caps = array( $this->get_section_cap( 'delete', $post->post_type ) );
}
} else {
if ( $post_id && in_array( $post->post_status, array( 'publish', 'trash' ) ) && BU_Group_Permissions::can_edit_section( $user, $post_id ) ) {
$caps = array( $this->get_section_cap( 'delete', $post->post_type ) );
}
}
return $caps;
}
private function _override_publish_caps( $user, $post_id, $caps ) {
if ( ! isset( $post_id ) ) {
return $caps;
}
$parent_id = null;
$post = get_post( $post_id );
$post_type = get_post_type_object( $post->post_type );
$is_alt = false;
// BU Versions uses the post_parent to relate the alternate version
// to the original
if ( class_exists( 'BU_Version_Workflow' ) ) {
$is_alt = BU_Version_Workflow::$v_factory->is_alt( $post->post_type );
}
if ( $post_type->hierarchical != true && $is_alt != true ) {
if ( BU_Group_Permissions::can_edit_section( $user, $post_id ) ) {
$caps = array( $this->get_section_cap( 'publish', $post->post_type ) );
}
} else {
// User is attempting to switch post parent while publishing
if ( $this->is_parent_changing( $post ) ) {
$parent_id = $this->get_new_parent( $post );
// Can't move published posts under sections they can't edit
if ( BU_Group_Permissions::can_edit_section( $user, $parent_id ) ) {
$caps = array( $this->get_section_cap( 'publish', $post->post_type ) );
}
} else {
if ( isset( $post_id ) && BU_Group_Permissions::can_edit_section( $user, $post->post_parent ) ) {
$caps = array( $this->get_section_cap( 'publish', $post->post_type ) );
}
}
}
return $caps;
}
public function get_section_cap( $type, $post_type ) {
$cap = '';
switch ( $type ) {
case 'edit':
$cap = 'edit_' . $post_type . '_in_section';
break;
case 'publish':
$cap = 'publish_' . $post_type . '_in_section';
break;
case 'delete':
$cap = 'delete_' . $post_type . '_in_section';
break;
default:
$cap = 'edit_in_section';
}
return $cap;
}
public function user_has_caps( WP_User $user, $caps ) {
foreach ( $caps as $cap ) {
if ( ! $this->user_has_cap( $user, $cap ) ) {
return false;
}
}
return true;
}
public function user_has_cap( WP_User $user, $cap ) {
if ( isset( $user->allcaps[ $cap ] ) && $user->allcaps[ $cap ] ) {
return true;
}
return false;
}
/**
* Get post types and store them in a property.
*
* @return Array
**/
public function get_post_types() {
if ( ! isset( $this->post_types ) ) {
$this->post_types = get_post_types( null, 'objects' );
}
return $this->post_types;
}
/**
* Whether or not the $cap is a meta cap for one of the registered post types.
*
* @param $cap
* @param $meta_cap
* @return bool
**/
public function is_post_cap( $cap, $map_cap ) {
$caps = array();
foreach ( $this->get_post_types() as $post_type ) {
if ( isset( $post_type->cap->$map_cap ) ) {
$caps[] = $post_type->cap->$map_cap;
}
}
return in_array( $cap, $caps );
}
}