# easy-invoice/2.4.0/includes/Helpers/CapabilityHelper.php

Easy Invoice – Invoice Generator, PDF Quotes &amp; Payments, version 2.4.0. 70 lines.

- Page: https://pluginprobe.com/plugins/easy-invoice/2.4.0/code/includes/Helpers/CapabilityHelper.php
- Raw: https://pluginprobe.com/plugins/easy-invoice/2.4.0/raw/includes/Helpers/CapabilityHelper.php
- Modified: 2026-05-21T08:29:24+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/easy-invoice/2.4.0/code/includes/Helpers/CapabilityHelper.php#L10-L20`.

```php
<?php
/**
 * Capability helper — bridges WordPress's `current_user_can()` with the
 * fine-grained capabilities defined by the Team Roles addon, while preserving
 * the existing "administrator-only" default for sites that aren't using the
 * addon at all.
 *
 * Resolution order for `easy_invoice_user_can($cap)`:
 *   1. If the user has WordPress's `manage_options` → true. Administrators
 *      and Super Admins always pass; behavior identical to the legacy checks.
 *   2. If the user has the explicit EI capability ($cap, e.g. `ei_create_invoice`)
 *      → true. This is the path the Team Roles addon enables.
 *   3. Otherwise → false.
 *
 * Why both checks?
 *   • Sites without the Team Roles addon never grant any `ei_*` capability —
 *     so every meaningful action only resolves via `manage_options`, exactly
 *     as before. No behavior change for those installs.
 *   • Sites WITH the addon get a real role system: an EI Sales user (no
 *     `manage_options`) creating an invoice now succeeds via `ei_create_invoice`,
 *     where it previously failed.
 *
 * Filterable via `easy_invoice_user_can` so addons / custom code can layer
 * stricter rules (IP allowlist, MFA-step-up, approval workflow gates).
 */

if (!defined('ABSPATH')) {
    exit;
}

if (!function_exists('easy_invoice_user_can')) {
    /**
     * @param string  $cap   Fine-grained EI capability (e.g. `ei_create_invoice`).
     * @param int|null $user_id  Optional — defaults to the current user.
     * @param mixed   ...$args  Forwarded to WP's user_can() / current_user_can() for object caps.
     * @return bool
     */
    function easy_invoice_user_can(string $cap, $user_id = null, ...$args): bool {
        $check = static function (string $c, $args) use ($user_id) {
            if ($user_id === null) {
                return $args
                    ? call_user_func_array('current_user_can', array_merge([$c], $args))
                    : current_user_can($c);
            }
            return $args
                ? call_user_func_array('user_can', array_merge([$user_id, $c], $args))
                : user_can($user_id, $c);
        };

        // Administrators (and Super Admins via the WP cap-map) always pass —
        // they implicitly hold every meta-capability via `manage_options`.
        $allowed = $check('manage_options', []);

        // If not an admin, fall back to the explicit fine-grained cap.
        if (!$allowed && $cap !== '' && $cap !== 'manage_options') {
            $allowed = $check($cap, $args);
        }

        /**
         * Filter the final allow/deny decision.
         *
         * @param bool   $allowed   Resolution from the cascade above.
         * @param string $cap       The fine-grained EI capability.
         * @param int|null $user_id  Resolved user id (null = current).
         * @param array  $args      Object-cap args forwarded from caller.
         */
        return (bool) apply_filters('easy_invoice_user_can', $allowed, $cap, $user_id, $args);
    }
}

```
