| @@ -12,9 +12,9 @@ | ||
| 12 | 12 | public static $role = ''; |
| 13 | 13 | |
| 14 | 14 | public static function normalizeFormId($formId) |
| 15 | 15 | { |
| 16 | - if ($formId === null || $formId === false || $formId === '') { | |
| 16 | + if (null === $formId || false === $formId || '' === $formId) { | |
| 17 | 17 | return null; |
| 18 | 18 | } |
| 19 | 19 | |
| 20 | 20 | if (is_string($formId)) { |
| @@ -61,13 +61,13 @@ | ||
| 61 | 61 | 'fluentform_manage_payments', |
| 62 | 62 | 'fluentform_settings_manager', |
| 63 | 63 | 'fluentform_full_access', |
| 64 | 64 | ]; |
| 65 | - | |
| 65 | + | |
| 66 | 66 | $data = apply_filters_deprecated( |
| 67 | 67 | 'fluentform_permission_set', |
| 68 | 68 | [ |
| 69 | - $data | |
| 69 | + $data, | |
| 70 | 70 | ], |
| 71 | 71 | FLUENTFORM_FRAMEWORK_UPGRADE, |
| 72 | 72 | 'fluentform/permission_set', |
| 73 | 73 | 'Use fluentform/permission_set instead of fluentform_permission_set.' |
| @@ -164,9 +164,10 @@ | ||
| 164 | 164 | if (static::hasExplicitFullAccess()) { |
| 165 | 165 | return true; |
| 166 | 166 | } |
| 167 | 167 | |
| 168 | - $grantedRole = static::getCurrentUserCapability(); | |
| 168 | + // Skip the role fallback for explicit managers, else a limited manager escalates. | |
| 169 | + $grantedRole = self::isExplicitManager() ? false : static::getCurrentUserCapability(); | |
| 169 | 170 | |
| 170 | 171 | foreach ((array) $permissions as $permission) { |
| 171 | 172 | $allowed = current_user_can($permission); |
| 172 | 173 | |
| @@ -189,8 +190,35 @@ | ||
| 189 | 190 | { |
| 190 | 191 | return current_user_can('fluentform_full_access') || current_user_can('manage_options'); |
| 191 | 192 | } |
| 192 | 193 | |
| 194 | + // Is the CURRENT user a Manager added by name (per-user), not just someone riding a delegated role? | |
| 195 | + private static function isExplicitManager() | |
| 196 | + { | |
| 197 | + $userId = get_current_user_id(); | |
| 198 | + | |
| 199 | + return (bool) ($userId && self::userHasDirectGrant($userId, wp_get_current_user())); | |
| 200 | + } | |
| 201 | + | |
| 202 | + // "Direct grant" = permissions attached to the USER themselves (per-user Manager), | |
| 203 | + // as opposed to access inherited from a delegated WordPress role. | |
| 204 | + private static function userHasDirectGrant($userId, $user) | |
| 205 | + { | |
| 206 | + // Flag set when an admin adds the user via Settings -> Managers. | |
| 207 | + if (get_user_meta($userId, '_fluent_forms_has_role', true)) { | |
| 208 | + return true; | |
| 209 | + } | |
| 210 | + | |
| 211 | + // Legacy fallback: caps stored on the user itself ($user->caps), not merged in from a role. | |
| 212 | + foreach (static::getPermissionSet() as $permission) { | |
| 213 | + if ($user && !empty($user->caps[$permission])) { | |
| 214 | + return true; | |
| 215 | + } | |
| 216 | + } | |
| 217 | + | |
| 218 | + return false; | |
| 219 | + } | |
| 220 | + | |
| 193 | 221 | private static function filterPermissionCheck($permission, $allowed, $formId) |
| 194 | 222 | { |
| 195 | 223 | $allowed = apply_filters_deprecated( |
| 196 | 224 | 'fluentform_verify_user_permission_' . $permission, |
| @@ -195,9 +223,9 @@ | ||
| 195 | 223 | $allowed = apply_filters_deprecated( |
| 196 | 224 | 'fluentform_verify_user_permission_' . $permission, |
| 197 | 225 | [ |
| 198 | 226 | $allowed, |
| 199 | - $formId | |
| 227 | + $formId, | |
| 200 | 228 | ], |
| 201 | 229 | FLUENTFORM_FRAMEWORK_UPGRADE, |
| 202 | 230 | 'fluentform/verify_user_permission_' . $permission, |
| 203 | 231 | 'Use fluentform/verify_user_permission_' . $permission . ' instead of fluentform_verify_user_permission_' . $permission |
| @@ -350,18 +378,22 @@ | ||
| 350 | 378 | $permissionSet = static::getPermissionSet(); |
| 351 | 379 | $isSuperMan = static::isSuperMan($user); |
| 352 | 380 | $capability = static::findUserCapability($user); |
| 353 | 381 | |
| 354 | - if ($isSuperMan || $capability) { | |
| 355 | - if ($isSuperMan) { | |
| 356 | - // $permissionSet[] = 'administrator'; | |
| 357 | - } | |
| 382 | + $isManager = self::userHasDirectGrant($user->ID, $user); | |
| 358 | 383 | |
| 384 | + if ($isSuperMan) { | |
| 359 | 385 | return $permissionSet; |
| 360 | 386 | } |
| 361 | 387 | |
| 362 | 388 | $userPermissions = array_values(array_intersect(array_keys($user->allcaps), $permissionSet)); |
| 363 | 389 | |
| 390 | + // Delegated-role users still return before the filter (unchanged boundary); | |
| 391 | + // a manager just reports their own scoped caps instead of the full set. | |
| 392 | + if ($capability) { | |
| 393 | + return $isManager ? $userPermissions : $permissionSet; | |
| 394 | + } | |
| 395 | + | |
| 364 | 396 | return apply_filters('fluentform/current_user_permissions', $userPermissions); |
| 365 | 397 | } |
| 366 | 398 | |
| 367 | 399 | public static function isSuperMan($user = false) |
| @@ -402,8 +434,23 @@ | ||
| 402 | 434 | |
| 403 | 435 | foreach ($permissions as $permission) { |
| 404 | 436 | $user->add_cap($permission); |
| 405 | 437 | } |
| 438 | + | |
| 439 | + /** | |
| 440 | + * Fires after per-user FluentForm permissions are attached. | |
| 441 | + * | |
| 442 | + * Role-level changes already announce themselves via | |
| 443 | + * fluentform/after_permission_set_assignment; this is the per-user | |
| 444 | + * equivalent, so caches keyed on a user's effective permissions can be | |
| 445 | + * invalidated when an individual manager is granted or revoked. | |
| 446 | + * | |
| 447 | + * @since 6.2.5 | |
| 448 | + * | |
| 449 | + * @param \WP_User $user The user whose permissions changed. | |
| 450 | + * @param array $permissions The permissions now attached. | |
| 451 | + */ | |
| 452 | + do_action('fluentform/after_user_permissions_attached', $user, $permissions); | |
| 406 | 453 | |
| 407 | 454 | return $user; |
| 408 | 455 | } |
| 409 | 456 | } |