| @@ -16,8 +16,18 @@ | ||
| 16 | 16 | { |
| 17 | 17 | private const UPGRADE_TO_PRO_URL = 'https://wpyatra.com/pricing'; |
| 18 | 18 | |
| 19 | 19 | /** |
| 20 | + * Guard so bootstrapMenuCapability() is idempotent across the two | |
| 21 | + * call sites (AppServiceProvider::register() — always-loaded path — | |
| 22 | + * and registerAdminMenu() — admin-only). add_filter() with anonymous | |
| 23 | + * closures does NOT dedupe, because each call creates a new closure | |
| 24 | + * with a distinct object identity, so without this guard the filters | |
| 25 | + * would run twice per cap check on admin pageviews. | |
| 26 | + */ | |
| 27 | + private static bool $capabilityFiltersInstalled = false; | |
| 28 | + | |
| 29 | + /** | |
| 20 | 30 | * Register services |
| 21 | 31 | */ |
| 22 | 32 | public function register(): void |
| 23 | 33 | { |
| @@ -483,8 +493,13 @@ | ||
| 483 | 493 | * Idempotent — adding the same filter callback twice is a no-op in WP. |
| 484 | 494 | */ |
| 485 | 495 | public static function bootstrapMenuCapability(): void |
| 486 | 496 | { |
| 497 | + if (self::$capabilityFiltersInstalled) { | |
| 498 | + return; | |
| 499 | + } | |
| 500 | + self::$capabilityFiltersInstalled = true; | |
| 501 | + | |
| 487 | 502 | add_filter('user_has_cap', static function (array $allcaps, array $caps, array $args, \WP_User $user): array { |
| 488 | 503 | if (empty($allcaps['manage_options'])) return $allcaps; |
| 489 | 504 | // Only set if the cap was asked-about (avoids polluting |
| 490 | 505 | // unrelated cap checks with a key we don't need to answer). |