PluginProbe
The Innovative Form Builder – IvyForms / 1.5
The Innovative Form Builder – IvyForms v1.5
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/MenuService.php +112 -25 0.5 → 1.5 View file →
@@ -1,15 +1,14 @@
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 -
10 5 use IvyForms\Routes\Routes;
6 +use IvyForms\Services\Ai\AiAvailability;
7 +use IvyForms\Services\Payment\PaymentsFeature;
11 8 use IvyForms\Services\Settings\SettingsService;
9 +use IvyForms\Services\Permissions\IvyFormsAccess;
10 +use IvyForms\Services\Permissions\RoutePermissionService;
12 11 use IvyForms\Services\Translations\BackendStrings;
13 12
14 13 /**
15 14 * Renders menu pages
@@ -15,9 +14,65 @@
15 14 * Renders menu pages
16 15 */
17 16 class MenuService
18 17 {
18 + private ?RoutePermissionService $routePermissionService;
19 +
20 + public function __construct(?RoutePermissionService $routePermissionService = null)
21 + {
22 + $this->routePermissionService = $routePermissionService;
23 + }
24 +
19 25 /**
26 + * Effective IvyForms permissions for the current user, keyed by permission key.
27 + *
28 + * Exposed to the frontend so the UI can gate actions (hide "+ Form", etc.) to match
29 + * the backend permission checks. Backend validation always remains the source of truth.
30 + *
31 + * @return array<string, bool>
32 + */
33 + private function currentUserPermissions(): array
34 + {
35 + $perm = $this->routePermissionService;
36 + if ($perm === null) {
37 + return [];
38 + }
39 +
40 + return [
41 + 'view_forms_list' => $perm->canViewForms(),
42 + 'add_edit_forms' => $perm->canEditForms(),
43 + 'delete_forms' => $perm->canDeleteForms(),
44 + 'view_entries_admin' => $perm->canViewEntries(),
45 + 'delete_entries_admin' => $perm->canDeleteEntries(),
46 + 'access_settings_page' => $perm->canAccessSettings(),
47 + ];
48 + }
49 +
50 + /**
51 + * @return array{available: bool, status: string, actionUrl: string, connectorsUrl: string}
52 + */
53 + private function currentAiAvailability(): array
54 + {
55 + $status = AiAvailability::getStatus();
56 + $actionUrl = '';
57 +
58 + if ($status === AiAvailability::STATUS_WORDPRESS_UPDATE_REQUIRED) {
59 + $actionUrl = AiAvailability::getWordPressUpdateUrl();
60 + } elseif ($status === AiAvailability::STATUS_AI_CLIENT_MISSING) {
61 + $actionUrl = AiAvailability::getAiPluginInstallUrl();
62 + } elseif ($status === AiAvailability::STATUS_TEXT_GENERATION_UNAVAILABLE) {
63 + $actionUrl = AiAvailability::getConnectorsSettingsUrl();
64 + }
65 +
66 + return [
67 + 'available' => $status === AiAvailability::STATUS_AVAILABLE,
68 + 'status' => $status,
69 + 'actionUrl' => $actionUrl,
70 + 'connectorsUrl' => AiAvailability::getConnectorsSettingsUrl(),
71 + ];
72 + }
73 +
74 + /**
20 75 * Submenu page render function
21 76 * @param string $page
22 77 */
23 78 public function render(string $page): void
@@ -22,14 +77,14 @@
22 77 */
23 78 public function render(string $page): void
24 79 {
25 80 $page = trim($page);
26 - $scriptId = IVYFORMS_DEV ? 'ivyforms_scripts_dev_vite' : 'ivyforms_script_index'; // @phpstan-ignore-line
27 - $scriptSrc = IVYFORMS_DEV ? // @phpstan-ignore-line
81 + $scriptId = IVYFORMS_DEV ? 'ivyforms_scripts_dev_vite' : 'ivyforms_script_index';
82 + $scriptSrc = IVYFORMS_DEV ?
28 83 'http://localhost:5173/src/assets/js/admin/admin.ts' :
29 84 IVYFORMS_URL . 'frontend/dist/admin.js';
30 - $styleSrc = IVYFORMS_DEV ? '' : IVYFORMS_URL . 'frontend/dist/index.css';// @phpstan-ignore-line
31 - $scriptVersion = IVYFORMS_DEV ? null : IVYFORMS_VERSION;// @phpstan-ignore-line
85 + $styleSrc = IVYFORMS_DEV ? '' : IVYFORMS_URL . 'frontend/dist/index.css';
86 + $scriptVersion = IVYFORMS_DEV ? null : IVYFORMS_VERSION;
32 87
33 88 wp_enqueue_script(
34 89 $scriptId,
35 90 $scriptSrc,
@@ -90,9 +145,35 @@
90 145 // $scriptVersion
91 146 // );
92 147 }
93 148
94 - // Localize scripts
149 + $this->localizeScripts($scriptId);
150 +
151 + /**
152 + * Hook to enqueue additional scripts and styles in admin area
153 + * @since 0.1.0
154 + *
155 + * Arguments:
156 + * - string $scriptId The main script handle ID (for dependencies)
157 + * - string $page WordPress admin menu slug (e.g. ivyforms-builder)
158 + */
159 + do_action('ivyforms/admin/enqueue_scripts', $scriptId, $page);
160 +
161 + if ($page === 'ivyforms-builder') {
162 + // FormBuilder.vue welcome-page image picker (Pro); not needed on other admin pages
163 + wp_enqueue_media();
164 + }
165 +
166 + include IVYFORMS_PATH . '/view/backend/view.php';
167 + }
168 +
169 + /**
170 + * Localize all admin data required by the frontend app.
171 + *
172 + * @param string $scriptId Main script handle used as the localization target.
173 + */
174 + private function localizeScripts(string $scriptId): void
175 + {
95 176 $settingsStorage = new SettingsService();
96 177
97 178 wp_localize_script(
98 179 $scriptId,
@@ -101,9 +182,11 @@
101 182 );
102 183
103 184 $backendLabels = array_merge(
104 185 BackendStrings::getNewFormStrings(),
186 + BackendStrings::getStylesFormBuilderStrings(),
105 187 BackendStrings::getSettingsFormBuilderStrings(),
188 + BackendStrings::getWelcomePageStrings(),
106 189 BackendStrings::getResultsFormBuilderStrings(),
107 190 BackendStrings::getEmptyStatesStrings(),
108 191 BackendStrings::getEntityFormStrings(),
109 192 BackendStrings::getAllFormsStrings(),
@@ -113,11 +196,15 @@
113 196 BackendStrings::getEntriesStrings(),
114 197 BackendStrings::getIntegrationsStrings(),
115 198 BackendStrings::getExceptionStrings(),
116 199 BackendStrings::getTemplateStrings(),
200 + BackendStrings::getAiStrings(),
117 201 BackendStrings::getSettingsStrings(),
118 202 BackendStrings::getSecurityStrings(),
119 - BackendStrings::getChangelogStrings()
203 + BackendStrings::getPermissionsStrings(),
204 + BackendStrings::getProUpgradeDialogStrings(),
205 + BackendStrings::getChangelogStrings(),
206 + BackendStrings::getPaymentStrings()
120 207 );
121 208
122 209 /**
123 210 * Filter backend labels before localizing
@@ -141,17 +228,28 @@
141 228 'pluginURL' => IVYFORMS_URL,
142 229 'siteURL' => esc_url_raw(site_url()),
143 230 ]
144 231 );
232 +
233 + $aiAvailability = $this->currentAiAvailability();
234 +
145 235 wp_localize_script(
146 236 $scriptId,
147 237 'wpIvyApiSettings',
148 238 [
149 - 'root' => esc_url_raw(rest_url()),
150 - 'nonce' => wp_create_nonce('wp_rest'),
151 - 'namespace' => Routes::$routeNamespace,
239 + 'root' => esc_url_raw(rest_url()),
240 + 'nonce' => wp_create_nonce('wp_rest'),
241 + 'namespace' => Routes::$routeNamespace,
242 + 'isAdministrator' => IvyFormsAccess::currentUserCanAccessPermissionsSettings(),
243 + 'permissions' => $this->currentUserPermissions(),
244 + 'aiAvailable' => $aiAvailability['available'],
245 + 'aiStatus' => $aiAvailability['status'],
246 + 'aiActionUrl' => $aiAvailability['actionUrl'],
247 + 'aiConnectorsUrl' => $aiAvailability['connectorsUrl'],
248 + 'paymentsEnabled' => PaymentsFeature::isEnabled(),
152 249 ]
153 250 );
251 +
154 252 wp_localize_script(
155 253 $scriptId,
156 254 'wpIvyDateFormat',
157 255 [
@@ -160,17 +258,6 @@
160 258 'dateTimeFormat' => get_option('date_format') . ' ' . get_option('time_format'),
161 259 'locale' => get_locale(),
162 260 ]
163 261 );
164 -
165 - /**
166 - * Hook to enqueue additional scripts and styles in admin area
167 - * @since 0.1.0
168 - *
169 - * Arguments:
170 - * - string $scriptId The main script handle ID (for dependencies)
171 - */
172 - do_action('ivyforms/admin/enqueue_scripts', $scriptId);
173 -
174 - include IVYFORMS_PATH . '/view/backend/view.php';
175 262 }
176 263 }