29 function map_meta_cap( $cap, $user_id ) { |
29 function map_meta_cap( $cap, $user_id ) { |
30 $args = array_slice( func_get_args(), 2 ); |
30 $args = array_slice( func_get_args(), 2 ); |
31 $caps = array(); |
31 $caps = array(); |
32 |
32 |
33 switch ( $cap ) { |
33 switch ( $cap ) { |
34 case 'remove_user': |
34 case 'remove_user': |
35 // In multisite the user must be a super admin to remove themselves. |
35 // In multisite the user must be a super admin to remove themselves. |
36 if ( isset( $args[0] ) && $user_id == $args[0] && ! is_super_admin( $user_id ) ) { |
36 if ( isset( $args[0] ) && $user_id == $args[0] && ! is_super_admin( $user_id ) ) { |
37 $caps[] = 'do_not_allow'; |
37 $caps[] = 'do_not_allow'; |
38 } else { |
38 } else { |
39 $caps[] = 'remove_users'; |
39 $caps[] = 'remove_users'; |
40 } |
40 } |
41 break; |
41 break; |
42 case 'promote_user': |
42 case 'promote_user': |
43 case 'add_users': |
43 case 'add_users': |
44 $caps[] = 'promote_users'; |
44 $caps[] = 'promote_users'; |
45 break; |
45 break; |
46 case 'edit_user': |
46 case 'edit_user': |
47 case 'edit_users': |
47 case 'edit_users': |
48 // Allow user to edit itself |
48 // Allow user to edit itself |
49 if ( 'edit_user' == $cap && isset( $args[0] ) && $user_id == $args[0] ) |
49 if ( 'edit_user' == $cap && isset( $args[0] ) && $user_id == $args[0] ) { |
50 break; |
50 break; |
51 |
51 } |
52 // In multisite the user must have manage_network_users caps. If editing a super admin, the user must be a super admin. |
52 |
53 if ( is_multisite() && ( ( ! is_super_admin( $user_id ) && 'edit_user' === $cap && is_super_admin( $args[0] ) ) || ! user_can( $user_id, 'manage_network_users' ) ) ) { |
53 // In multisite the user must have manage_network_users caps. If editing a super admin, the user must be a super admin. |
54 $caps[] = 'do_not_allow'; |
54 if ( is_multisite() && ( ( ! is_super_admin( $user_id ) && 'edit_user' === $cap && is_super_admin( $args[0] ) ) || ! user_can( $user_id, 'manage_network_users' ) ) ) { |
55 } else { |
55 $caps[] = 'do_not_allow'; |
56 $caps[] = 'edit_users'; // edit_user maps to edit_users. |
56 } else { |
57 } |
57 $caps[] = 'edit_users'; // edit_user maps to edit_users. |
58 break; |
58 } |
59 case 'delete_post': |
59 break; |
60 case 'delete_page': |
60 case 'delete_post': |
61 $post = get_post( $args[0] ); |
61 case 'delete_page': |
62 if ( ! $post ) { |
62 $post = get_post( $args[0] ); |
63 $caps[] = 'do_not_allow'; |
|
64 break; |
|
65 } |
|
66 |
|
67 if ( 'revision' == $post->post_type ) { |
|
68 $post = get_post( $post->post_parent ); |
|
69 if ( ! $post ) { |
63 if ( ! $post ) { |
70 $caps[] = 'do_not_allow'; |
64 $caps[] = 'do_not_allow'; |
71 break; |
65 break; |
72 } |
66 } |
73 } |
67 |
74 |
68 if ( 'revision' == $post->post_type ) { |
75 if ( ( get_option( 'page_for_posts' ) == $post->ID ) || ( get_option( 'page_on_front' ) == $post->ID ) ) { |
69 $post = get_post( $post->post_parent ); |
76 $caps[] = 'manage_options'; |
70 if ( ! $post ) { |
77 break; |
71 $caps[] = 'do_not_allow'; |
78 } |
72 break; |
79 |
73 } |
80 $post_type = get_post_type_object( $post->post_type ); |
74 } |
81 if ( ! $post_type ) { |
75 |
82 /* translators: 1: post type, 2: capability name */ |
76 if ( ( get_option( 'page_for_posts' ) == $post->ID ) || ( get_option( 'page_on_front' ) == $post->ID ) ) { |
83 _doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' ); |
77 $caps[] = 'manage_options'; |
84 $caps[] = 'edit_others_posts'; |
78 break; |
85 break; |
79 } |
86 } |
80 |
87 |
81 $post_type = get_post_type_object( $post->post_type ); |
88 if ( ! $post_type->map_meta_cap ) { |
82 if ( ! $post_type ) { |
89 $caps[] = $post_type->cap->$cap; |
83 /* translators: 1: post type, 2: capability name */ |
90 // Prior to 3.1 we would re-call map_meta_cap here. |
84 _doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' ); |
91 if ( 'delete_post' == $cap ) |
85 $caps[] = 'edit_others_posts'; |
92 $cap = $post_type->cap->$cap; |
86 break; |
93 break; |
87 } |
94 } |
88 |
95 |
89 if ( ! $post_type->map_meta_cap ) { |
96 // If the post author is set and the user is the author... |
90 $caps[] = $post_type->cap->$cap; |
97 if ( $post->post_author && $user_id == $post->post_author ) { |
91 // Prior to 3.1 we would re-call map_meta_cap here. |
98 // If the post is published or scheduled... |
92 if ( 'delete_post' == $cap ) { |
99 if ( in_array( $post->post_status, array( 'publish', 'future' ), true ) ) { |
93 $cap = $post_type->cap->$cap; |
100 $caps[] = $post_type->cap->delete_published_posts; |
94 } |
101 } elseif ( 'trash' == $post->post_status ) { |
95 break; |
102 $status = get_post_meta( $post->ID, '_wp_trash_meta_status', true ); |
96 } |
103 if ( in_array( $status, array( 'publish', 'future' ), true ) ) { |
97 |
|
98 // If the post author is set and the user is the author... |
|
99 if ( $post->post_author && $user_id == $post->post_author ) { |
|
100 // If the post is published or scheduled... |
|
101 if ( in_array( $post->post_status, array( 'publish', 'future' ), true ) ) { |
104 $caps[] = $post_type->cap->delete_published_posts; |
102 $caps[] = $post_type->cap->delete_published_posts; |
|
103 } elseif ( 'trash' == $post->post_status ) { |
|
104 $status = get_post_meta( $post->ID, '_wp_trash_meta_status', true ); |
|
105 if ( in_array( $status, array( 'publish', 'future' ), true ) ) { |
|
106 $caps[] = $post_type->cap->delete_published_posts; |
|
107 } else { |
|
108 $caps[] = $post_type->cap->delete_posts; |
|
109 } |
105 } else { |
110 } else { |
|
111 // If the post is draft... |
106 $caps[] = $post_type->cap->delete_posts; |
112 $caps[] = $post_type->cap->delete_posts; |
107 } |
113 } |
108 } else { |
114 } else { |
109 // If the post is draft... |
115 // The user is trying to edit someone else's post. |
110 $caps[] = $post_type->cap->delete_posts; |
116 $caps[] = $post_type->cap->delete_others_posts; |
111 } |
117 // The post is published or scheduled, extra cap required. |
112 } else { |
118 if ( in_array( $post->post_status, array( 'publish', 'future' ), true ) ) { |
113 // The user is trying to edit someone else's post. |
119 $caps[] = $post_type->cap->delete_published_posts; |
114 $caps[] = $post_type->cap->delete_others_posts; |
120 } elseif ( 'private' == $post->post_status ) { |
115 // The post is published or scheduled, extra cap required. |
121 $caps[] = $post_type->cap->delete_private_posts; |
116 if ( in_array( $post->post_status, array( 'publish', 'future' ), true ) ) { |
122 } |
117 $caps[] = $post_type->cap->delete_published_posts; |
123 } |
118 } elseif ( 'private' == $post->post_status ) { |
124 |
119 $caps[] = $post_type->cap->delete_private_posts; |
125 /* |
120 } |
126 * Setting the privacy policy page requires `manage_privacy_options`, |
121 } |
127 * so deleting it should require that too. |
122 |
128 */ |
123 /* |
129 if ( (int) get_option( 'wp_page_for_privacy_policy' ) === $post->ID ) { |
124 * Setting the privacy policy page requires `manage_privacy_options`, |
130 $caps = array_merge( $caps, map_meta_cap( 'manage_privacy_options', $user_id ) ); |
125 * so deleting it should require that too. |
131 } |
126 */ |
132 |
127 if ( (int) get_option( 'wp_page_for_privacy_policy' ) === $post->ID ) { |
133 break; |
128 $caps = array_merge( $caps, map_meta_cap( 'manage_privacy_options', $user_id ) ); |
|
129 } |
|
130 |
|
131 break; |
|
132 // edit_post breaks down to edit_posts, edit_published_posts, or |
134 // edit_post breaks down to edit_posts, edit_published_posts, or |
133 // edit_others_posts |
135 // edit_others_posts |
134 case 'edit_post': |
136 case 'edit_post': |
135 case 'edit_page': |
137 case 'edit_page': |
136 $post = get_post( $args[0] ); |
138 $post = get_post( $args[0] ); |
137 if ( ! $post ) { |
|
138 $caps[] = 'do_not_allow'; |
|
139 break; |
|
140 } |
|
141 |
|
142 if ( 'revision' == $post->post_type ) { |
|
143 $post = get_post( $post->post_parent ); |
|
144 if ( ! $post ) { |
139 if ( ! $post ) { |
145 $caps[] = 'do_not_allow'; |
140 $caps[] = 'do_not_allow'; |
146 break; |
141 break; |
147 } |
142 } |
148 } |
143 |
149 |
144 if ( 'revision' == $post->post_type ) { |
150 $post_type = get_post_type_object( $post->post_type ); |
145 $post = get_post( $post->post_parent ); |
151 if ( ! $post_type ) { |
146 if ( ! $post ) { |
152 /* translators: 1: post type, 2: capability name */ |
147 $caps[] = 'do_not_allow'; |
153 _doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' ); |
148 break; |
154 $caps[] = 'edit_others_posts'; |
149 } |
155 break; |
150 } |
156 } |
151 |
157 |
152 $post_type = get_post_type_object( $post->post_type ); |
158 if ( ! $post_type->map_meta_cap ) { |
153 if ( ! $post_type ) { |
159 $caps[] = $post_type->cap->$cap; |
154 /* translators: 1: post type, 2: capability name */ |
160 // Prior to 3.1 we would re-call map_meta_cap here. |
155 _doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' ); |
161 if ( 'edit_post' == $cap ) |
156 $caps[] = 'edit_others_posts'; |
162 $cap = $post_type->cap->$cap; |
157 break; |
163 break; |
158 } |
164 } |
159 |
165 |
160 if ( ! $post_type->map_meta_cap ) { |
166 // If the post author is set and the user is the author... |
161 $caps[] = $post_type->cap->$cap; |
167 if ( $post->post_author && $user_id == $post->post_author ) { |
162 // Prior to 3.1 we would re-call map_meta_cap here. |
168 // If the post is published or scheduled... |
163 if ( 'edit_post' == $cap ) { |
169 if ( in_array( $post->post_status, array( 'publish', 'future' ), true ) ) { |
164 $cap = $post_type->cap->$cap; |
170 $caps[] = $post_type->cap->edit_published_posts; |
165 } |
171 } elseif ( 'trash' == $post->post_status ) { |
166 break; |
172 $status = get_post_meta( $post->ID, '_wp_trash_meta_status', true ); |
167 } |
173 if ( in_array( $status, array( 'publish', 'future' ), true ) ) { |
168 |
|
169 // If the post author is set and the user is the author... |
|
170 if ( $post->post_author && $user_id == $post->post_author ) { |
|
171 // If the post is published or scheduled... |
|
172 if ( in_array( $post->post_status, array( 'publish', 'future' ), true ) ) { |
174 $caps[] = $post_type->cap->edit_published_posts; |
173 $caps[] = $post_type->cap->edit_published_posts; |
|
174 } elseif ( 'trash' == $post->post_status ) { |
|
175 $status = get_post_meta( $post->ID, '_wp_trash_meta_status', true ); |
|
176 if ( in_array( $status, array( 'publish', 'future' ), true ) ) { |
|
177 $caps[] = $post_type->cap->edit_published_posts; |
|
178 } else { |
|
179 $caps[] = $post_type->cap->edit_posts; |
|
180 } |
175 } else { |
181 } else { |
|
182 // If the post is draft... |
176 $caps[] = $post_type->cap->edit_posts; |
183 $caps[] = $post_type->cap->edit_posts; |
177 } |
184 } |
178 } else { |
185 } else { |
179 // If the post is draft... |
186 // The user is trying to edit someone else's post. |
180 $caps[] = $post_type->cap->edit_posts; |
187 $caps[] = $post_type->cap->edit_others_posts; |
181 } |
188 // The post is published or scheduled, extra cap required. |
182 } else { |
189 if ( in_array( $post->post_status, array( 'publish', 'future' ), true ) ) { |
183 // The user is trying to edit someone else's post. |
190 $caps[] = $post_type->cap->edit_published_posts; |
184 $caps[] = $post_type->cap->edit_others_posts; |
191 } elseif ( 'private' == $post->post_status ) { |
185 // The post is published or scheduled, extra cap required. |
192 $caps[] = $post_type->cap->edit_private_posts; |
186 if ( in_array( $post->post_status, array( 'publish', 'future' ), true ) ) { |
193 } |
187 $caps[] = $post_type->cap->edit_published_posts; |
194 } |
188 } elseif ( 'private' == $post->post_status ) { |
195 |
189 $caps[] = $post_type->cap->edit_private_posts; |
196 /* |
190 } |
197 * Setting the privacy policy page requires `manage_privacy_options`, |
191 } |
198 * so editing it should require that too. |
192 |
199 */ |
193 /* |
200 if ( (int) get_option( 'wp_page_for_privacy_policy' ) === $post->ID ) { |
194 * Setting the privacy policy page requires `manage_privacy_options`, |
201 $caps = array_merge( $caps, map_meta_cap( 'manage_privacy_options', $user_id ) ); |
195 * so editing it should require that too. |
202 } |
196 */ |
203 |
197 if ( (int) get_option( 'wp_page_for_privacy_policy' ) === $post->ID ) { |
204 break; |
198 $caps = array_merge( $caps, map_meta_cap( 'manage_privacy_options', $user_id ) ); |
205 case 'read_post': |
199 } |
206 case 'read_page': |
200 |
207 $post = get_post( $args[0] ); |
201 break; |
|
202 case 'read_post': |
|
203 case 'read_page': |
|
204 $post = get_post( $args[0] ); |
|
205 if ( ! $post ) { |
|
206 $caps[] = 'do_not_allow'; |
|
207 break; |
|
208 } |
|
209 |
|
210 if ( 'revision' == $post->post_type ) { |
|
211 $post = get_post( $post->post_parent ); |
|
212 if ( ! $post ) { |
208 if ( ! $post ) { |
213 $caps[] = 'do_not_allow'; |
209 $caps[] = 'do_not_allow'; |
214 break; |
210 break; |
215 } |
211 } |
216 } |
212 |
217 |
213 if ( 'revision' == $post->post_type ) { |
218 $post_type = get_post_type_object( $post->post_type ); |
214 $post = get_post( $post->post_parent ); |
219 if ( ! $post_type ) { |
215 if ( ! $post ) { |
220 /* translators: 1: post type, 2: capability name */ |
216 $caps[] = 'do_not_allow'; |
221 _doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' ); |
217 break; |
222 $caps[] = 'edit_others_posts'; |
218 } |
223 break; |
219 } |
224 } |
220 |
225 |
221 $post_type = get_post_type_object( $post->post_type ); |
226 if ( ! $post_type->map_meta_cap ) { |
222 if ( ! $post_type ) { |
227 $caps[] = $post_type->cap->$cap; |
223 /* translators: 1: post type, 2: capability name */ |
228 // Prior to 3.1 we would re-call map_meta_cap here. |
224 _doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' ); |
229 if ( 'read_post' == $cap ) |
225 $caps[] = 'edit_others_posts'; |
230 $cap = $post_type->cap->$cap; |
226 break; |
231 break; |
227 } |
232 } |
228 |
233 |
229 if ( ! $post_type->map_meta_cap ) { |
234 $status_obj = get_post_status_object( $post->post_status ); |
230 $caps[] = $post_type->cap->$cap; |
235 if ( $status_obj->public ) { |
231 // Prior to 3.1 we would re-call map_meta_cap here. |
236 $caps[] = $post_type->cap->read; |
232 if ( 'read_post' == $cap ) { |
237 break; |
233 $cap = $post_type->cap->$cap; |
238 } |
234 } |
239 |
235 break; |
240 if ( $post->post_author && $user_id == $post->post_author ) { |
236 } |
241 $caps[] = $post_type->cap->read; |
237 |
242 } elseif ( $status_obj->private ) { |
238 $status_obj = get_post_status_object( $post->post_status ); |
243 $caps[] = $post_type->cap->read_private_posts; |
239 if ( $status_obj->public ) { |
244 } else { |
240 $caps[] = $post_type->cap->read; |
245 $caps = map_meta_cap( 'edit_post', $user_id, $post->ID ); |
241 break; |
246 } |
242 } |
247 break; |
243 |
248 case 'publish_post': |
244 if ( $post->post_author && $user_id == $post->post_author ) { |
249 $post = get_post( $args[0] ); |
245 $caps[] = $post_type->cap->read; |
250 if ( ! $post ) { |
246 } elseif ( $status_obj->private ) { |
251 $caps[] = 'do_not_allow'; |
247 $caps[] = $post_type->cap->read_private_posts; |
252 break; |
248 } else { |
253 } |
249 $caps = map_meta_cap( 'edit_post', $user_id, $post->ID ); |
254 |
250 } |
255 $post_type = get_post_type_object( $post->post_type ); |
251 break; |
256 if ( ! $post_type ) { |
252 case 'publish_post': |
257 /* translators: 1: post type, 2: capability name */ |
253 $post = get_post( $args[0] ); |
258 _doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' ); |
254 if ( ! $post ) { |
259 $caps[] = 'edit_others_posts'; |
255 $caps[] = 'do_not_allow'; |
260 break; |
256 break; |
261 } |
257 } |
262 |
258 |
263 $caps[] = $post_type->cap->publish_posts; |
259 $post_type = get_post_type_object( $post->post_type ); |
264 break; |
260 if ( ! $post_type ) { |
265 case 'edit_post_meta': |
261 /* translators: 1: post type, 2: capability name */ |
266 case 'delete_post_meta': |
262 _doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' ); |
267 case 'add_post_meta': |
263 $caps[] = 'edit_others_posts'; |
268 case 'edit_comment_meta': |
264 break; |
269 case 'delete_comment_meta': |
265 } |
270 case 'add_comment_meta': |
266 |
271 case 'edit_term_meta': |
267 $caps[] = $post_type->cap->publish_posts; |
272 case 'delete_term_meta': |
268 break; |
273 case 'add_term_meta': |
269 case 'edit_post_meta': |
274 case 'edit_user_meta': |
270 case 'delete_post_meta': |
275 case 'delete_user_meta': |
271 case 'add_post_meta': |
276 case 'add_user_meta': |
272 case 'edit_comment_meta': |
277 list( $_, $object_type, $_ ) = explode( '_', $cap ); |
273 case 'delete_comment_meta': |
278 $object_id = (int) $args[0]; |
274 case 'add_comment_meta': |
279 $object_subtype = get_object_subtype( $object_type, $object_id ); |
275 case 'edit_term_meta': |
280 |
276 case 'delete_term_meta': |
281 if ( empty( $object_subtype ) ) { |
277 case 'add_term_meta': |
282 $caps[] = 'do_not_allow'; |
278 case 'edit_user_meta': |
283 break; |
279 case 'delete_user_meta': |
284 } |
280 case 'add_user_meta': |
285 |
281 list( $_, $object_type, $_ ) = explode( '_', $cap ); |
286 $caps = map_meta_cap( "edit_{$object_type}", $user_id, $object_id ); |
282 $object_id = (int) $args[0]; |
287 |
283 |
288 $meta_key = isset( $args[1] ) ? $args[1] : false; |
284 $object_subtype = get_object_subtype( $object_type, $object_id ); |
289 |
285 |
290 if ( $meta_key ) { |
286 if ( empty( $object_subtype ) ) { |
291 $allowed = ! is_protected_meta( $meta_key, $object_type ); |
287 $caps[] = 'do_not_allow'; |
292 |
288 break; |
293 if ( ! empty( $object_subtype ) && has_filter( "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}" ) ) { |
289 } |
294 |
290 |
295 /** |
291 $caps = map_meta_cap( "edit_{$object_type}", $user_id, $object_id ); |
296 * Filters whether the user is allowed to edit a specific meta key of a specific object type and subtype. |
292 |
297 * |
293 $meta_key = isset( $args[1] ) ? $args[1] : false; |
298 * The dynamic portions of the hook name, `$object_type`, `$meta_key`, |
294 |
299 * and `$object_subtype`, refer to the metadata object type (comment, post, term or user), |
295 if ( $meta_key ) { |
300 * the meta key value, and the object subtype respectively. |
296 $allowed = ! is_protected_meta( $meta_key, $object_type ); |
301 * |
297 |
302 * @since 4.9.8 |
298 if ( ! empty( $object_subtype ) && has_filter( "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}" ) ) { |
303 * |
299 |
304 * @param bool $allowed Whether the user can add the object meta. Default false. |
300 /** |
305 * @param string $meta_key The meta key. |
301 * Filters whether the user is allowed to edit a specific meta key of a specific object type and subtype. |
306 * @param int $object_id Object ID. |
302 * |
307 * @param int $user_id User ID. |
303 * The dynamic portions of the hook name, `$object_type`, `$meta_key`, |
308 * @param string $cap Capability name. |
304 * and `$object_subtype`, refer to the metadata object type (comment, post, term or user), |
309 * @param string[] $caps Array of the user's capabilities. |
305 * the meta key value, and the object subtype respectively. |
310 */ |
306 * |
311 $allowed = apply_filters( "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $allowed, $meta_key, $object_id, $user_id, $cap, $caps ); |
307 * @since 4.9.8 |
312 } else { |
308 * |
313 |
309 * @param bool $allowed Whether the user can add the object meta. Default false. |
314 /** |
310 * @param string $meta_key The meta key. |
315 * Filters whether the user is allowed to edit a specific meta key of a specific object type. |
311 * @param int $object_id Object ID. |
316 * |
312 * @param int $user_id User ID. |
317 * Return true to have the mapped meta caps from `edit_{$object_type}` apply. |
313 * @param string $cap Capability name. |
318 * |
314 * @param string[] $caps Array of the user's capabilities. |
319 * The dynamic portion of the hook name, `$object_type` refers to the object type being filtered. |
315 */ |
320 * The dynamic portion of the hook name, `$meta_key`, refers to the meta key passed to map_meta_cap(). |
316 $allowed = apply_filters( "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $allowed, $meta_key, $object_id, $user_id, $cap, $caps ); |
321 * |
317 } else { |
322 * @since 3.3.0 As `auth_post_meta_{$meta_key}`. |
318 |
323 * @since 4.6.0 |
319 /** |
324 * |
320 * Filters whether the user is allowed to edit a specific meta key of a specific object type. |
325 * @param bool $allowed Whether the user can add the object meta. Default false. |
321 * |
326 * @param string $meta_key The meta key. |
322 * Return true to have the mapped meta caps from `edit_{$object_type}` apply. |
327 * @param int $object_id Object ID. |
323 * |
328 * @param int $user_id User ID. |
324 * The dynamic portion of the hook name, `$object_type` refers to the object type being filtered. |
329 * @param string $cap Capability name. |
325 * The dynamic portion of the hook name, `$meta_key`, refers to the meta key passed to map_meta_cap(). |
330 * @param string[] $caps Array of the user's capabilities. |
326 * |
331 */ |
327 * @since 3.3.0 As `auth_post_meta_{$meta_key}`. |
332 $allowed = apply_filters( "auth_{$object_type}_meta_{$meta_key}", $allowed, $meta_key, $object_id, $user_id, $cap, $caps ); |
328 * @since 4.6.0 |
333 } |
329 * |
334 |
330 * @param bool $allowed Whether the user can add the object meta. Default false. |
335 if ( ! empty( $object_subtype ) ) { |
331 * @param string $meta_key The meta key. |
336 |
332 * @param int $object_id Object ID. |
337 /** |
333 * @param int $user_id User ID. |
338 * Filters whether the user is allowed to edit meta for specific object types/subtypes. |
334 * @param string $cap Capability name. |
339 * |
335 * @param string[] $caps Array of the user's capabilities. |
340 * Return true to have the mapped meta caps from `edit_{$object_type}` apply. |
336 */ |
341 * |
337 $allowed = apply_filters( "auth_{$object_type}_meta_{$meta_key}", $allowed, $meta_key, $object_id, $user_id, $cap, $caps ); |
342 * The dynamic portion of the hook name, `$object_type` refers to the object type being filtered. |
338 } |
343 * The dynamic portion of the hook name, `$object_subtype` refers to the object subtype being filtered. |
339 |
344 * The dynamic portion of the hook name, `$meta_key`, refers to the meta key passed to map_meta_cap(). |
340 if ( ! empty( $object_subtype ) ) { |
345 * |
341 |
346 * @since 4.6.0 As `auth_post_{$post_type}_meta_{$meta_key}`. |
342 /** |
347 * @since 4.7.0 |
343 * Filters whether the user is allowed to edit meta for specific object types/subtypes. |
348 * @deprecated 4.9.8 Use `auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}` |
344 * |
349 * |
345 * Return true to have the mapped meta caps from `edit_{$object_type}` apply. |
350 * @param bool $allowed Whether the user can add the object meta. Default false. |
346 * |
351 * @param string $meta_key The meta key. |
347 * The dynamic portion of the hook name, `$object_type` refers to the object type being filtered. |
352 * @param int $object_id Object ID. |
348 * The dynamic portion of the hook name, `$object_subtype` refers to the object subtype being filtered. |
353 * @param int $user_id User ID. |
349 * The dynamic portion of the hook name, `$meta_key`, refers to the meta key passed to map_meta_cap(). |
354 * @param string $cap Capability name. |
350 * |
355 * @param string[] $caps Array of the user's capabilities. |
351 * @since 4.6.0 As `auth_post_{$post_type}_meta_{$meta_key}`. |
356 */ |
352 * @since 4.7.0 |
357 $allowed = apply_filters_deprecated( "auth_{$object_type}_{$object_subtype}_meta_{$meta_key}", array( $allowed, $meta_key, $object_id, $user_id, $cap, $caps ), '4.9.8', "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}" ); |
353 * @deprecated 4.9.8 Use `auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}` |
358 } |
354 * |
359 |
355 * @param bool $allowed Whether the user can add the object meta. Default false. |
360 if ( ! $allowed ) { |
356 * @param string $meta_key The meta key. |
|
357 * @param int $object_id Object ID. |
|
358 * @param int $user_id User ID. |
|
359 * @param string $cap Capability name. |
|
360 * @param string[] $caps Array of the user's capabilities. |
|
361 */ |
|
362 $allowed = apply_filters_deprecated( "auth_{$object_type}_{$object_subtype}_meta_{$meta_key}", array( $allowed, $meta_key, $object_id, $user_id, $cap, $caps ), '4.9.8', "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}" ); |
|
363 } |
|
364 |
|
365 if ( ! $allowed ) { |
|
366 $caps[] = $cap; |
|
367 } |
|
368 } |
|
369 break; |
|
370 case 'edit_comment': |
|
371 $comment = get_comment( $args[0] ); |
|
372 if ( ! $comment ) { |
|
373 $caps[] = 'do_not_allow'; |
|
374 break; |
|
375 } |
|
376 |
|
377 $post = get_post( $comment->comment_post_ID ); |
|
378 |
|
379 /* |
|
380 * If the post doesn't exist, we have an orphaned comment. |
|
381 * Fall back to the edit_posts capability, instead. |
|
382 */ |
|
383 if ( $post ) { |
|
384 $caps = map_meta_cap( 'edit_post', $user_id, $post->ID ); |
|
385 } else { |
|
386 $caps = map_meta_cap( 'edit_posts', $user_id ); |
|
387 } |
|
388 break; |
|
389 case 'unfiltered_upload': |
|
390 if ( defined( 'ALLOW_UNFILTERED_UPLOADS' ) && ALLOW_UNFILTERED_UPLOADS && ( ! is_multisite() || is_super_admin( $user_id ) ) ) { |
361 $caps[] = $cap; |
391 $caps[] = $cap; |
362 } |
392 } else { |
363 } |
393 $caps[] = 'do_not_allow'; |
364 break; |
394 } |
365 case 'edit_comment': |
395 break; |
366 $comment = get_comment( $args[0] ); |
396 case 'edit_css': |
367 if ( ! $comment ) { |
397 case 'unfiltered_html': |
368 $caps[] = 'do_not_allow'; |
398 // Disallow unfiltered_html for all users, even admins and super admins. |
369 break; |
399 if ( defined( 'DISALLOW_UNFILTERED_HTML' ) && DISALLOW_UNFILTERED_HTML ) { |
370 } |
400 $caps[] = 'do_not_allow'; |
371 |
401 } elseif ( is_multisite() && ! is_super_admin( $user_id ) ) { |
372 $post = get_post( $comment->comment_post_ID ); |
402 $caps[] = 'do_not_allow'; |
373 |
403 } else { |
374 /* |
404 $caps[] = 'unfiltered_html'; |
375 * If the post doesn't exist, we have an orphaned comment. |
405 } |
376 * Fall back to the edit_posts capability, instead. |
406 break; |
377 */ |
407 case 'edit_files': |
378 if ( $post ) { |
408 case 'edit_plugins': |
379 $caps = map_meta_cap( 'edit_post', $user_id, $post->ID ); |
409 case 'edit_themes': |
380 } else { |
410 // Disallow the file editors. |
381 $caps = map_meta_cap( 'edit_posts', $user_id ); |
411 if ( defined( 'DISALLOW_FILE_EDIT' ) && DISALLOW_FILE_EDIT ) { |
382 } |
412 $caps[] = 'do_not_allow'; |
383 break; |
413 } elseif ( ! wp_is_file_mod_allowed( 'capability_edit_themes' ) ) { |
384 case 'unfiltered_upload': |
414 $caps[] = 'do_not_allow'; |
385 if ( defined('ALLOW_UNFILTERED_UPLOADS') && ALLOW_UNFILTERED_UPLOADS && ( !is_multisite() || is_super_admin( $user_id ) ) ) |
415 } elseif ( is_multisite() && ! is_super_admin( $user_id ) ) { |
|
416 $caps[] = 'do_not_allow'; |
|
417 } else { |
|
418 $caps[] = $cap; |
|
419 } |
|
420 break; |
|
421 case 'update_plugins': |
|
422 case 'delete_plugins': |
|
423 case 'install_plugins': |
|
424 case 'upload_plugins': |
|
425 case 'update_themes': |
|
426 case 'delete_themes': |
|
427 case 'install_themes': |
|
428 case 'upload_themes': |
|
429 case 'update_core': |
|
430 // Disallow anything that creates, deletes, or updates core, plugin, or theme files. |
|
431 // Files in uploads are excepted. |
|
432 if ( ! wp_is_file_mod_allowed( 'capability_update_core' ) ) { |
|
433 $caps[] = 'do_not_allow'; |
|
434 } elseif ( is_multisite() && ! is_super_admin( $user_id ) ) { |
|
435 $caps[] = 'do_not_allow'; |
|
436 } elseif ( 'upload_themes' === $cap ) { |
|
437 $caps[] = 'install_themes'; |
|
438 } elseif ( 'upload_plugins' === $cap ) { |
|
439 $caps[] = 'install_plugins'; |
|
440 } else { |
|
441 $caps[] = $cap; |
|
442 } |
|
443 break; |
|
444 case 'install_languages': |
|
445 case 'update_languages': |
|
446 if ( ! wp_is_file_mod_allowed( 'can_install_language_pack' ) ) { |
|
447 $caps[] = 'do_not_allow'; |
|
448 } elseif ( is_multisite() && ! is_super_admin( $user_id ) ) { |
|
449 $caps[] = 'do_not_allow'; |
|
450 } else { |
|
451 $caps[] = 'install_languages'; |
|
452 } |
|
453 break; |
|
454 case 'activate_plugins': |
|
455 case 'deactivate_plugins': |
|
456 case 'activate_plugin': |
|
457 case 'deactivate_plugin': |
|
458 $caps[] = 'activate_plugins'; |
|
459 if ( is_multisite() ) { |
|
460 // update_, install_, and delete_ are handled above with is_super_admin(). |
|
461 $menu_perms = get_site_option( 'menu_items', array() ); |
|
462 if ( empty( $menu_perms['plugins'] ) ) { |
|
463 $caps[] = 'manage_network_plugins'; |
|
464 } |
|
465 } |
|
466 break; |
|
467 case 'resume_plugin': |
|
468 $caps[] = 'resume_plugins'; |
|
469 break; |
|
470 case 'resume_theme': |
|
471 $caps[] = 'resume_themes'; |
|
472 break; |
|
473 case 'delete_user': |
|
474 case 'delete_users': |
|
475 // If multisite only super admins can delete users. |
|
476 if ( is_multisite() && ! is_super_admin( $user_id ) ) { |
|
477 $caps[] = 'do_not_allow'; |
|
478 } else { |
|
479 $caps[] = 'delete_users'; // delete_user maps to delete_users. |
|
480 } |
|
481 break; |
|
482 case 'create_users': |
|
483 if ( ! is_multisite() ) { |
|
484 $caps[] = $cap; |
|
485 } elseif ( is_super_admin( $user_id ) || get_site_option( 'add_new_users' ) ) { |
|
486 $caps[] = $cap; |
|
487 } else { |
|
488 $caps[] = 'do_not_allow'; |
|
489 } |
|
490 break; |
|
491 case 'manage_links': |
|
492 if ( get_option( 'link_manager_enabled' ) ) { |
|
493 $caps[] = $cap; |
|
494 } else { |
|
495 $caps[] = 'do_not_allow'; |
|
496 } |
|
497 break; |
|
498 case 'customize': |
|
499 $caps[] = 'edit_theme_options'; |
|
500 break; |
|
501 case 'delete_site': |
|
502 if ( is_multisite() ) { |
|
503 $caps[] = 'manage_options'; |
|
504 } else { |
|
505 $caps[] = 'do_not_allow'; |
|
506 } |
|
507 break; |
|
508 case 'edit_term': |
|
509 case 'delete_term': |
|
510 case 'assign_term': |
|
511 $term_id = (int) $args[0]; |
|
512 $term = get_term( $term_id ); |
|
513 if ( ! $term || is_wp_error( $term ) ) { |
|
514 $caps[] = 'do_not_allow'; |
|
515 break; |
|
516 } |
|
517 |
|
518 $tax = get_taxonomy( $term->taxonomy ); |
|
519 if ( ! $tax ) { |
|
520 $caps[] = 'do_not_allow'; |
|
521 break; |
|
522 } |
|
523 |
|
524 if ( 'delete_term' === $cap && ( $term->term_id == get_option( 'default_' . $term->taxonomy ) ) ) { |
|
525 $caps[] = 'do_not_allow'; |
|
526 break; |
|
527 } |
|
528 |
|
529 $taxo_cap = $cap . 's'; |
|
530 |
|
531 $caps = map_meta_cap( $tax->cap->$taxo_cap, $user_id, $term_id ); |
|
532 |
|
533 break; |
|
534 case 'manage_post_tags': |
|
535 case 'edit_categories': |
|
536 case 'edit_post_tags': |
|
537 case 'delete_categories': |
|
538 case 'delete_post_tags': |
|
539 $caps[] = 'manage_categories'; |
|
540 break; |
|
541 case 'assign_categories': |
|
542 case 'assign_post_tags': |
|
543 $caps[] = 'edit_posts'; |
|
544 break; |
|
545 case 'create_sites': |
|
546 case 'delete_sites': |
|
547 case 'manage_network': |
|
548 case 'manage_sites': |
|
549 case 'manage_network_users': |
|
550 case 'manage_network_plugins': |
|
551 case 'manage_network_themes': |
|
552 case 'manage_network_options': |
|
553 case 'upgrade_network': |
386 $caps[] = $cap; |
554 $caps[] = $cap; |
387 else |
555 break; |
388 $caps[] = 'do_not_allow'; |
556 case 'setup_network': |
389 break; |
557 if ( is_multisite() ) { |
390 case 'edit_css' : |
558 $caps[] = 'manage_network_options'; |
391 case 'unfiltered_html' : |
559 } else { |
392 // Disallow unfiltered_html for all users, even admins and super admins. |
560 $caps[] = 'manage_options'; |
393 if ( defined( 'DISALLOW_UNFILTERED_HTML' ) && DISALLOW_UNFILTERED_HTML ) |
561 } |
394 $caps[] = 'do_not_allow'; |
562 break; |
395 elseif ( is_multisite() && ! is_super_admin( $user_id ) ) |
563 case 'update_php': |
396 $caps[] = 'do_not_allow'; |
564 if ( is_multisite() && ! is_super_admin( $user_id ) ) { |
397 else |
565 $caps[] = 'do_not_allow'; |
398 $caps[] = 'unfiltered_html'; |
566 } else { |
399 break; |
567 $caps[] = 'update_core'; |
400 case 'edit_files': |
568 } |
401 case 'edit_plugins': |
569 break; |
402 case 'edit_themes': |
570 case 'export_others_personal_data': |
403 // Disallow the file editors. |
571 case 'erase_others_personal_data': |
404 if ( defined( 'DISALLOW_FILE_EDIT' ) && DISALLOW_FILE_EDIT ) |
572 case 'manage_privacy_options': |
405 $caps[] = 'do_not_allow'; |
573 $caps[] = is_multisite() ? 'manage_network' : 'manage_options'; |
406 elseif ( ! wp_is_file_mod_allowed( 'capability_edit_themes' ) ) |
574 break; |
407 $caps[] = 'do_not_allow'; |
575 default: |
408 elseif ( is_multisite() && ! is_super_admin( $user_id ) ) |
576 // Handle meta capabilities for custom post types. |
409 $caps[] = 'do_not_allow'; |
577 global $post_type_meta_caps; |
410 else |
578 if ( isset( $post_type_meta_caps[ $cap ] ) ) { |
|
579 $args = array_merge( array( $post_type_meta_caps[ $cap ], $user_id ), $args ); |
|
580 return call_user_func_array( 'map_meta_cap', $args ); |
|
581 } |
|
582 |
|
583 // Block capabilities map to their post equivalent. |
|
584 $block_caps = array( |
|
585 'edit_blocks', |
|
586 'edit_others_blocks', |
|
587 'publish_blocks', |
|
588 'read_private_blocks', |
|
589 'delete_blocks', |
|
590 'delete_private_blocks', |
|
591 'delete_published_blocks', |
|
592 'delete_others_blocks', |
|
593 'edit_private_blocks', |
|
594 'edit_published_blocks', |
|
595 ); |
|
596 if ( in_array( $cap, $block_caps, true ) ) { |
|
597 $cap = str_replace( '_blocks', '_posts', $cap ); |
|
598 } |
|
599 |
|
600 // If no meta caps match, return the original cap. |
411 $caps[] = $cap; |
601 $caps[] = $cap; |
412 break; |
|
413 case 'update_plugins': |
|
414 case 'delete_plugins': |
|
415 case 'install_plugins': |
|
416 case 'upload_plugins': |
|
417 case 'update_themes': |
|
418 case 'delete_themes': |
|
419 case 'install_themes': |
|
420 case 'upload_themes': |
|
421 case 'update_core': |
|
422 // Disallow anything that creates, deletes, or updates core, plugin, or theme files. |
|
423 // Files in uploads are excepted. |
|
424 if ( ! wp_is_file_mod_allowed( 'capability_update_core' ) ) { |
|
425 $caps[] = 'do_not_allow'; |
|
426 } elseif ( is_multisite() && ! is_super_admin( $user_id ) ) { |
|
427 $caps[] = 'do_not_allow'; |
|
428 } elseif ( 'upload_themes' === $cap ) { |
|
429 $caps[] = 'install_themes'; |
|
430 } elseif ( 'upload_plugins' === $cap ) { |
|
431 $caps[] = 'install_plugins'; |
|
432 } else { |
|
433 $caps[] = $cap; |
|
434 } |
|
435 break; |
|
436 case 'install_languages': |
|
437 case 'update_languages': |
|
438 if ( ! wp_is_file_mod_allowed( 'can_install_language_pack' ) ) { |
|
439 $caps[] = 'do_not_allow'; |
|
440 } elseif ( is_multisite() && ! is_super_admin( $user_id ) ) { |
|
441 $caps[] = 'do_not_allow'; |
|
442 } else { |
|
443 $caps[] = 'install_languages'; |
|
444 } |
|
445 break; |
|
446 case 'activate_plugins': |
|
447 case 'deactivate_plugins': |
|
448 case 'activate_plugin': |
|
449 case 'deactivate_plugin': |
|
450 $caps[] = 'activate_plugins'; |
|
451 if ( is_multisite() ) { |
|
452 // update_, install_, and delete_ are handled above with is_super_admin(). |
|
453 $menu_perms = get_site_option( 'menu_items', array() ); |
|
454 if ( empty( $menu_perms['plugins'] ) ) |
|
455 $caps[] = 'manage_network_plugins'; |
|
456 } |
|
457 break; |
|
458 case 'delete_user': |
|
459 case 'delete_users': |
|
460 // If multisite only super admins can delete users. |
|
461 if ( is_multisite() && ! is_super_admin( $user_id ) ) |
|
462 $caps[] = 'do_not_allow'; |
|
463 else |
|
464 $caps[] = 'delete_users'; // delete_user maps to delete_users. |
|
465 break; |
|
466 case 'create_users': |
|
467 if ( !is_multisite() ) |
|
468 $caps[] = $cap; |
|
469 elseif ( is_super_admin( $user_id ) || get_site_option( 'add_new_users' ) ) |
|
470 $caps[] = $cap; |
|
471 else |
|
472 $caps[] = 'do_not_allow'; |
|
473 break; |
|
474 case 'manage_links' : |
|
475 if ( get_option( 'link_manager_enabled' ) ) |
|
476 $caps[] = $cap; |
|
477 else |
|
478 $caps[] = 'do_not_allow'; |
|
479 break; |
|
480 case 'customize' : |
|
481 $caps[] = 'edit_theme_options'; |
|
482 break; |
|
483 case 'delete_site': |
|
484 if ( is_multisite() ) { |
|
485 $caps[] = 'manage_options'; |
|
486 } else { |
|
487 $caps[] = 'do_not_allow'; |
|
488 } |
|
489 break; |
|
490 case 'edit_term': |
|
491 case 'delete_term': |
|
492 case 'assign_term': |
|
493 $term_id = (int) $args[0]; |
|
494 $term = get_term( $term_id ); |
|
495 if ( ! $term || is_wp_error( $term ) ) { |
|
496 $caps[] = 'do_not_allow'; |
|
497 break; |
|
498 } |
|
499 |
|
500 $tax = get_taxonomy( $term->taxonomy ); |
|
501 if ( ! $tax ) { |
|
502 $caps[] = 'do_not_allow'; |
|
503 break; |
|
504 } |
|
505 |
|
506 if ( 'delete_term' === $cap && ( $term->term_id == get_option( 'default_' . $term->taxonomy ) ) ) { |
|
507 $caps[] = 'do_not_allow'; |
|
508 break; |
|
509 } |
|
510 |
|
511 $taxo_cap = $cap . 's'; |
|
512 |
|
513 $caps = map_meta_cap( $tax->cap->$taxo_cap, $user_id, $term_id ); |
|
514 |
|
515 break; |
|
516 case 'manage_post_tags': |
|
517 case 'edit_categories': |
|
518 case 'edit_post_tags': |
|
519 case 'delete_categories': |
|
520 case 'delete_post_tags': |
|
521 $caps[] = 'manage_categories'; |
|
522 break; |
|
523 case 'assign_categories': |
|
524 case 'assign_post_tags': |
|
525 $caps[] = 'edit_posts'; |
|
526 break; |
|
527 case 'create_sites': |
|
528 case 'delete_sites': |
|
529 case 'manage_network': |
|
530 case 'manage_sites': |
|
531 case 'manage_network_users': |
|
532 case 'manage_network_plugins': |
|
533 case 'manage_network_themes': |
|
534 case 'manage_network_options': |
|
535 case 'upgrade_network': |
|
536 $caps[] = $cap; |
|
537 break; |
|
538 case 'setup_network': |
|
539 if ( is_multisite() ) { |
|
540 $caps[] = 'manage_network_options'; |
|
541 } else { |
|
542 $caps[] = 'manage_options'; |
|
543 } |
|
544 break; |
|
545 case 'export_others_personal_data': |
|
546 case 'erase_others_personal_data': |
|
547 case 'manage_privacy_options': |
|
548 $caps[] = is_multisite() ? 'manage_network' : 'manage_options'; |
|
549 break; |
|
550 default: |
|
551 // Handle meta capabilities for custom post types. |
|
552 global $post_type_meta_caps; |
|
553 if ( isset( $post_type_meta_caps[ $cap ] ) ) { |
|
554 $args = array_merge( array( $post_type_meta_caps[ $cap ], $user_id ), $args ); |
|
555 return call_user_func_array( 'map_meta_cap', $args ); |
|
556 } |
|
557 |
|
558 // If no meta caps match, return the original cap. |
|
559 $caps[] = $cap; |
|
560 } |
602 } |
561 |
603 |
562 /** |
604 /** |
563 * Filters a user's capabilities depending on specific context and/or privilege. |
605 * Filters a user's capabilities depending on specific context and/or privilege. |
564 * |
606 * |
565 * @since 2.8.0 |
607 * @since 2.8.0 |
566 * |
608 * |
567 * @param array $caps Returns the user's actual capabilities. |
609 * @param string[] $caps Array of the user's capabilities. |
568 * @param string $cap Capability name. |
610 * @param string $cap Capability name. |
569 * @param int $user_id The user ID. |
611 * @param int $user_id The user ID. |
570 * @param array $args Adds the context to the cap. Typically the object ID. |
612 * @param array $args Adds the context to the cap. Typically the object ID. |
571 */ |
613 */ |
572 return apply_filters( 'map_meta_cap', $caps, $cap, $user_id, $args ); |
614 return apply_filters( 'map_meta_cap', $caps, $cap, $user_id, $args ); |
573 } |
615 } |
574 |
616 |
575 /** |
617 /** |