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 +151 -35 0.1.2 → 1.5 View file →
@@ -1,14 +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 -
5 +use IvyForms\Routes\Routes;
6 +use IvyForms\Services\Ai\AiAvailability;
7 +use IvyForms\Services\Payment\PaymentsFeature;
10 8 use IvyForms\Services\Settings\SettingsService;
9 +use IvyForms\Services\Permissions\IvyFormsAccess;
10 +use IvyForms\Services\Permissions\RoutePermissionService;
11 11 use IvyForms\Services\Translations\BackendStrings;
12 12
13 13 /**
14 14 * Renders menu pages
@@ -14,9 +14,65 @@
14 14 * Renders menu pages
15 15 */
16 16 class MenuService
17 17 {
18 + private ?RoutePermissionService $routePermissionService;
19 +
20 + public function __construct(?RoutePermissionService $routePermissionService = null)
21 + {
22 + $this->routePermissionService = $routePermissionService;
23 + }
24 +
18 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 + /**
19 75 * Submenu page render function
20 76 * @param string $page
21 77 */
22 78 public function render(string $page): void
@@ -21,14 +77,14 @@
21 77 */
22 78 public function render(string $page): void
23 79 {
24 80 $page = trim($page);
25 - $scriptId = IVYFORMS_DEV ? 'ivyforms_scripts_dev_vite' : 'ivyforms_script_index'; // @phpstan-ignore-line
26 - $scriptSrc = IVYFORMS_DEV ? // @phpstan-ignore-line
81 + $scriptId = IVYFORMS_DEV ? 'ivyforms_scripts_dev_vite' : 'ivyforms_script_index';
82 + $scriptSrc = IVYFORMS_DEV ?
27 83 'http://localhost:5173/src/assets/js/admin/admin.ts' :
28 84 IVYFORMS_URL . 'frontend/dist/admin.js';
29 - $styleSrc = IVYFORMS_DEV ? '' : IVYFORMS_URL . 'frontend/dist/index.css';// @phpstan-ignore-line
30 - $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;
31 87
32 88 wp_enqueue_script(
33 89 $scriptId,
34 90 $scriptSrc,
@@ -89,42 +145,81 @@
89 145 // $scriptVersion
90 146 // );
91 147 }
92 148
93 - // Localize scripts
94 - wp_localize_script($scriptId, 'wpIvyPluginURL', [
95 - 'wpIvyPluginURL' => IVYFORMS_URL,
96 - ]);
149 + $this->localizeScripts($scriptId);
97 150
98 - wp_localize_script($scriptId, 'wpIvyApiSettings', [
99 - 'root' => esc_url_raw(rest_url()),
100 - 'nonce' => wp_create_nonce('wp_rest'),
101 - ]);
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);
102 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 + {
103 176 $settingsStorage = new SettingsService();
104 - wp_localize_script($scriptId, 'wpIvySettings', $settingsStorage->getAllSettings());
105 177
106 178 wp_localize_script(
107 179 $scriptId,
108 180 'wpIvySettings',
109 - $settingsStorage->getAllSettings()
181 + $settingsStorage->getFrontendSettings()
110 182 );
111 183
184 + $backendLabels = array_merge(
185 + BackendStrings::getNewFormStrings(),
186 + BackendStrings::getStylesFormBuilderStrings(),
187 + BackendStrings::getSettingsFormBuilderStrings(),
188 + BackendStrings::getWelcomePageStrings(),
189 + BackendStrings::getResultsFormBuilderStrings(),
190 + BackendStrings::getEmptyStatesStrings(),
191 + BackendStrings::getEntityFormStrings(),
192 + BackendStrings::getAllFormsStrings(),
193 + BackendStrings::getDashboardStrings(),
194 + BackendStrings::getCommonStrings(),
195 + BackendStrings::getComponentsStrings(),
196 + BackendStrings::getEntriesStrings(),
197 + BackendStrings::getIntegrationsStrings(),
198 + BackendStrings::getExceptionStrings(),
199 + BackendStrings::getTemplateStrings(),
200 + BackendStrings::getAiStrings(),
201 + BackendStrings::getSettingsStrings(),
202 + BackendStrings::getSecurityStrings(),
203 + BackendStrings::getPermissionsStrings(),
204 + BackendStrings::getProUpgradeDialogStrings(),
205 + BackendStrings::getChangelogStrings(),
206 + BackendStrings::getPaymentStrings()
207 + );
208 +
209 + /**
210 + * Filter backend labels before localizing
211 + * Allows Pro version to merge additional strings
212 + *
213 + * @since 0.1.0
214 + * @param array $backendLabels Array of backend label strings
215 + */
216 + $backendLabels = apply_filters('ivyforms/admin/backend_labels', $backendLabels);
217 +
112 218 wp_localize_script(
113 219 $scriptId,
114 220 'wpIvyLabels',
115 - array_merge(
116 - BackendStrings::getNewFormStrings(),
117 - BackendStrings::getSettingsFormBuilderStrings(),
118 - BackendStrings::getEmptyStatesStrings(),
119 - BackendStrings::getEntityFormStrings(),
120 - BackendStrings::getAllFormsStrings(),
121 - BackendStrings::getDashboardStrings(),
122 - BackendStrings::getCommonStrings(),
123 - BackendStrings::getComponentsStrings(),
124 - BackendStrings::getEntriesStrings(),
125 - BackendStrings::getIntegrationsStrings(),
126 - )
221 + $backendLabels
127 222 );
128 223
129 224 wp_localize_script(
130 225 $scriptId,
@@ -129,19 +224,40 @@
129 224 wp_localize_script(
130 225 $scriptId,
131 226 'wpIvyUrls',
132 227 [
133 - 'wpIvyPluginURL' => IVYFORMS_URL,
228 + 'pluginURL' => IVYFORMS_URL,
229 + 'siteURL' => esc_url_raw(site_url()),
134 230 ]
135 231 );
232 +
233 + $aiAvailability = $this->currentAiAvailability();
234 +
136 235 wp_localize_script(
137 236 $scriptId,
138 237 'wpIvyApiSettings',
139 238 [
140 - 'root' => esc_url_raw(rest_url()),
141 - 'nonce' => wp_create_nonce('wp_rest')
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(),
142 249 ]
143 250 );
144 251
145 - include IVYFORMS_PATH . '/view/backend/view.php';
252 + wp_localize_script(
253 + $scriptId,
254 + 'wpIvyDateFormat',
255 + [
256 + 'dateFormat' => get_option('date_format'),
257 + 'timeFormat' => get_option('time_format'),
258 + 'dateTimeFormat' => get_option('date_format') . ' ' . get_option('time_format'),
259 + 'locale' => get_locale(),
260 + ]
261 + );
146 262 }
147 263 }