PluginProbe
The Innovative Form Builder – IvyForms / 1.5.1
The Innovative Form Builder – IvyForms v1.5.1
1.5.1 1.5 1.4.1 1.4 trunk 0.1.2 0.2 0.2.1 0.3 0.3.1 0.4 0.5 0.6 0.6.1 0.6.1-backup 0.6.1.1 0.7 0.8 0.8.1 0.8.2 0.9 0.9.1 1.0 1.1 1.1.1 All 27 releases
← All changes | backend/src/Services/Menu/MenuMapper.php +129 -44 0.2.1 → 1.5.1 View file →
@@ -1,13 +1,12 @@
1 1 <?php
2 2
3 3 namespace IvyForms\Services\Menu;
4 4
5 -// phpcs:disable PSR1.Files.SideEffects
6 -if (!defined('ABSPATH')) {
7 - exit; // Exit if accessed directly
8 -}
9 -
5 +use IvyForms\Services\API\IvyFormsAPI;
6 +use IvyForms\Services\Payment\PaymentsFeature;
7 +use IvyForms\Services\Permissions\IvyFormsAccess;
8 +use IvyForms\Services\Permissions\PermissionResolver;
10 9 use IvyForms\Services\Translations\BackendStrings;
11 10
12 11 /**
13 12 * Class Menu
@@ -13,21 +12,28 @@
13 12 * Class Menu
14 13 */
15 14 class MenuMapper
16 15 {
16 + private ?PermissionResolver $permissionResolver;
17 +
18 + public function __construct(
19 + ?PermissionResolver $permissionResolver = null
20 + ) {
21 + $this->permissionResolver = $permissionResolver;
22 + }
23 +
17 24 /**
18 25 * @return mixed[]
19 26 */
20 27 public function __invoke(): array
21 28 {
22 - return
29 + $menus =
23 30 [
24 31 // [
25 32 // 'parentSlug' => 'ivyforms',
26 33 // 'pageTitle' => 'Dashboard',
27 34 // 'menuTitle' => BackendStrings::getDashboardStrings()['dashboard'],
28 -// // TODO - Add IvyForms capability
29 -// 'capability' => 'read',
35 +// 'capability' => 'manage_options',
30 36 // 'menuSlug' => 'ivyforms-dashboard',
31 37 // ],
32 38 [
33 39 'parentSlug' => 'ivyforms',
@@ -32,10 +38,10 @@
32 38 [
33 39 'parentSlug' => 'ivyforms',
34 40 'pageTitle' => 'All Forms',
35 41 'menuTitle' => BackendStrings::getCommonStrings()['all_forms'],
36 - // TODO - Add IvyForms capability
37 - 'capability' => 'read',
42 + // WP checks this cap on the admin menu row; fine-grained access uses PermissionResolver below.
43 + 'capability' => IvyFormsAccess::CAP_ACCESS_PLUGIN,
38 44 'menuSlug' => 'ivyforms-forms',
39 45 ],
40 46 [
41 47 'parentSlug' => 'ivyforms',
@@ -40,44 +46,123 @@
40 46 [
41 47 'parentSlug' => 'ivyforms',
42 48 'pageTitle' => 'New form',
43 49 'menuTitle' => BackendStrings::getCommonStrings()['new_form'],
44 - // TODO - Add IvyForms capability
45 - 'capability' => 'read',
50 + 'capability' => IvyFormsAccess::CAP_ACCESS_PLUGIN,
46 51 'menuSlug' => 'ivyforms-builder',
47 52 ],
48 -// [
49 -// 'parentSlug' => 'ivyforms',
50 -// 'pageTitle' => 'Entries',
51 -// 'menuTitle' => BackendStrings::getEntriesStrings()['entries'],
52 -// // TODO - Add IvyForms capability
53 -// 'capability' => 'read',
54 -// 'menuSlug' => 'ivyforms-entries',
55 -// ],
56 -// // TODO Add Settings page
57 -// [
58 -// 'parentSlug' => 'ivyforms',
59 -// 'pageTitle' => 'Settings',
60 -// 'menuTitle' => BackendStrings::getSettingsStrings()['settings'],
61 -// // TODO - Add IvyForms capability
62 -// 'capability' => 'read',
63 -// 'menuSlug' => 'ivyforms-settings',
64 -// ],
65 -// [
66 -// 'parentSlug' => 'ivyforms',
67 -// 'pageTitle' => 'Integrations',
68 -// 'menuTitle' => BackendStrings::getIntegrationsStrings()['integrations'],
69 -// // TODO - Add IvyForms capability
70 -// 'capability' => 'read',
71 -// 'menuSlug' => 'ivyforms-integrations',
72 -// ],
53 + [
54 + 'parentSlug' => 'ivyforms',
55 + 'pageTitle' => 'Entries',
56 + 'menuTitle' => BackendStrings::getEntriesStrings()['entries'],
57 + 'capability' => IvyFormsAccess::CAP_ACCESS_PLUGIN,
58 + 'menuSlug' => 'ivyforms-entries',
59 + ],
60 + [
61 + 'parentSlug' => 'ivyforms',
62 + 'pageTitle' => 'Payments',
63 + 'menuTitle' => BackendStrings::getPaymentStrings()['payments'],
64 + 'capability' => 'manage_options',
65 + 'menuSlug' => 'ivyforms-payments',
66 + ],
67 + [
68 + 'parentSlug' => 'ivyforms',
69 + 'pageTitle' => 'Settings',
70 + 'menuTitle' => BackendStrings::getCommonStrings()['settings'],
71 + 'capability' => IvyFormsAccess::CAP_ACCESS_PLUGIN,
72 + 'menuSlug' => 'ivyforms-settings',
73 + ],
74 + [
75 + 'parentSlug' => 'ivyforms',
76 + 'pageTitle' => 'Integrations',
77 + 'menuTitle' => BackendStrings::getIntegrationsStrings()['integrations'],
78 + 'capability' => IvyFormsAccess::CAP_ACCESS_PLUGIN,
79 + 'menuSlug' => 'ivyforms-integrations',
80 + ],
81 + ];
73 82
74 -// [
75 -// 'parentSlug' => 'ivyforms',
76 -// 'pageTitle' => 'Testing',
77 -// 'menuTitle' => 'Testing',
78 -// 'capability' => 'read',
79 -// 'menuSlug' => 'ivyforms-testing',
80 -// ],
83 + // Payments page stays hidden while Stripe and PayPal are turned off
84 + if (!PaymentsFeature::isEnabled()) {
85 + $menus = array_values(array_filter(
86 + $menus,
87 + static fn(array $menu): bool => $menu['menuSlug'] !== 'ivyforms-payments'
88 + ));
89 + }
90 +
91 + // Add "Upgrade to PRO" menu only if Pro plugin is not installed/activated
92 + if (!IvyFormsAPI::isProPluginActive()) {
93 + $menus[] = [
94 + 'parentSlug' => 'ivyforms',
95 + 'pageTitle' => 'Upgrade to PRO',
96 + // phpcs:ignore Generic.Files.LineLength.TooLong
97 + 'menuTitle' => '<span class="ivyforms-upgrade-to-pro">' . __('Upgrade to PRO', 'ivyforms') . '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M3.30739 5.78346L5.09363 3.36669C6.24826 1.80449 6.82558 1.02339 7.3642 1.18846C7.90283 1.35352 7.90283 2.31153 7.90283 4.22757V4.40823C7.90283 5.0993 7.90283 5.44483 8.12364 5.66157L8.13533 5.6728C8.36091 5.88496 8.72054 5.88496 9.4398 5.88496C10.7341 5.88496 11.3813 5.88496 11.6 6.27751C11.6037 6.28401 11.6072 6.29056 11.6106 6.29716C11.8171 6.69579 11.4424 7.20277 10.6929 8.21673L8.90667 10.6335C7.75202 12.1957 7.1747 12.9768 6.63607 12.8117C6.09744 12.6466 6.09746 11.6886 6.09748 9.77256L6.09749 9.59198C6.0975 8.9009 6.0975 8.55536 5.87669 8.33861L5.865 8.32739C5.63942 8.11522 5.27979 8.11522 4.56052 8.11522C3.26618 8.11522 2.61901 8.11522 2.40029 7.72267C2.39666 7.71617 2.39314 7.70962 2.38973 7.70302C2.18325 7.3044 2.55796 6.79742 3.30739 5.78346Z" fill="white"/></svg></span>',
98 + 'capability' => IvyFormsAccess::CAP_ACCESS_PLUGIN,
99 + // phpcs:ignore Generic.Files.LineLength.TooLong
100 + 'menuSlug' => 'https://ivyforms.com/pricing?utm_source=ivy-lite&utm_medium=lite-upgrade&utm_content=ivy&utm_campaign=ivy',
101 + 'isExternal' => true,
81 102 ];
103 + }
104 +
105 + $visibleMenus = [];
106 + foreach ($menus as $menu) {
107 + if (!$this->canAccessMenu($menu)) {
108 + continue;
109 + }
110 + $visibleMenus[] = $menu;
111 + }
112 +
113 + return $visibleMenus;
114 + }
115 +
116 + /**
117 + * @param mixed[] $menu
118 + */
119 + private function canAccessMenu(array $menu): bool
120 + {
121 + if (IvyFormsAccess::hasImplicitElevatedAccess()) {
122 + return true;
123 + }
124 +
125 + $resolver = $this->permissionResolver;
126 + $user = wp_get_current_user();
127 + if (!$resolver || !$user instanceof \WP_User || (int) $user->ID <= 0) {
128 + return false;
129 + }
130 +
131 + $slug = (string) ($menu['menuSlug'] ?? '');
132 + if ($slug === '' || strpos($slug, 'http') === 0) {
133 + return true;
134 + }
135 +
136 + return $this->canAccessBySlug($slug, $resolver, $user);
137 + }
138 +
139 + /**
140 + * @param list<string> $permissionKeys
141 + */
142 + private function userCanAnyOf(PermissionResolver $resolver, \WP_User $user, array $permissionKeys): bool
143 + {
144 + return $resolver->userCanAnyOf($user, $permissionKeys);
145 + }
146 +
147 + private function canAccessBySlug(string $slug, PermissionResolver $resolver, \WP_User $user): bool
148 + {
149 + if ($slug === 'ivyforms-forms') {
150 + return $this->userCanAnyOf($resolver, $user, [
151 + 'view_forms_list',
152 + 'add_edit_forms',
153 + 'delete_forms',
154 + ]);
155 + }
156 + if ($slug === 'ivyforms-builder') {
157 + return $resolver->userCanIncludingFormScoped('add_edit_forms', $user, null);
158 + }
159 + if ($slug === 'ivyforms-entries') {
160 + return $this->userCanAnyOf($resolver, $user, ['view_entries_admin', 'delete_entries_admin']);
161 + }
162 + if (in_array($slug, ['ivyforms-settings', 'ivyforms-integrations'], true)) {
163 + return $resolver->userCanIncludingFormScoped('access_settings_page', $user, null);
164 + }
165 +
166 + return true;
82 167 }
83 168 }