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 +263 -0 0.6.1 → 1.5 View file →
@@ -1,0 +1,263 @@
1 +<?php
2 +
3 +namespace IvyForms\Services\Menu;
4 +
5 +use IvyForms\Routes\Routes;
6 +use IvyForms\Services\Ai\AiAvailability;
7 +use IvyForms\Services\Payment\PaymentsFeature;
8 +use IvyForms\Services\Settings\SettingsService;
9 +use IvyForms\Services\Permissions\IvyFormsAccess;
10 +use IvyForms\Services\Permissions\RoutePermissionService;
11 +use IvyForms\Services\Translations\BackendStrings;
12 +
13 +/**
14 + * Renders menu pages
15 + */
16 +class MenuService
17 +{
18 + private ?RoutePermissionService $routePermissionService;
19 +
20 + public function __construct(?RoutePermissionService $routePermissionService = null)
21 + {
22 + $this->routePermissionService = $routePermissionService;
23 + }
24 +
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 + /**
75 + * Submenu page render function
76 + * @param string $page
77 + */
78 + public function render(string $page): void
79 + {
80 + $page = trim($page);
81 + $scriptId = IVYFORMS_DEV ? 'ivyforms_scripts_dev_vite' : 'ivyforms_script_index';
82 + $scriptSrc = IVYFORMS_DEV ?
83 + 'http://localhost:5173/src/assets/js/admin/admin.ts' :
84 + IVYFORMS_URL . 'frontend/dist/admin.js';
85 + $styleSrc = IVYFORMS_DEV ? '' : IVYFORMS_URL . 'frontend/dist/index.css';
86 + $scriptVersion = IVYFORMS_DEV ? null : IVYFORMS_VERSION;
87 +
88 + wp_enqueue_script(
89 + $scriptId,
90 + $scriptSrc,
91 + [],
92 + $scriptVersion,
93 + true
94 + );
95 +
96 + // TODO: Check including fonts on build
97 + // @phpstan-ignore-next-line
98 + if ($styleSrc) {
99 + wp_enqueue_style(
100 + 'ivyforms_style_admin',
101 + IVYFORMS_URL . 'frontend/dist/admin.css',
102 + [],
103 + $scriptVersion
104 + );
105 + wp_enqueue_style(
106 + 'ivyforms_style_index',
107 + $styleSrc,
108 + [],
109 + $scriptVersion
110 + );
111 +// wp_enqueue_style(
112 +// 'ivyforms_font_roboto_regular_woff2',
113 +// IVYFORMS_URL . 'frontend/dist/Roboto-Regular.woff2',
114 +// [],
115 +// $scriptVersion
116 +// );
117 +// wp_enqueue_style(
118 +// 'ivyforms_font_roboto_regular_woff',
119 +// IVYFORMS_URL . 'frontend/dist/Roboto-Regular.woff',
120 +// [],
121 +// $scriptVersion
122 +// );
123 +// wp_enqueue_style(
124 +// 'ivyforms_font_roboto_medium_woff2',
125 +// IVYFORMS_URL . 'frontend/dist/Roboto-Medium.woff2',
126 +// [],
127 +// $scriptVersion
128 +// );
129 +// wp_enqueue_style(
130 +// 'ivyforms_font_roboto_medium_woff',
131 +// IVYFORMS_URL . 'frontend/dist/Roboto-Medium.woff',
132 +// [],
133 +// $scriptVersion
134 +// );
135 +// wp_enqueue_style(
136 +// 'ivyforms_font_roboto_bold_woff2',
137 +// IVYFORMS_URL . 'frontend/dist/Roboto-Bold.woff2',
138 +// [],
139 +// $scriptVersion
140 +// );
141 +// wp_enqueue_style(
142 +// 'ivyforms_font_roboto_bold_woff',
143 +// IVYFORMS_URL . 'frontend/dist/Roboto-Bold.woff',
144 +// [],
145 +// $scriptVersion
146 +// );
147 + }
148 +
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 + {
176 + $settingsStorage = new SettingsService();
177 +
178 + wp_localize_script(
179 + $scriptId,
180 + 'wpIvySettings',
181 + $settingsStorage->getFrontendSettings()
182 + );
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 +
218 + wp_localize_script(
219 + $scriptId,
220 + 'wpIvyLabels',
221 + $backendLabels
222 + );
223 +
224 + wp_localize_script(
225 + $scriptId,
226 + 'wpIvyUrls',
227 + [
228 + 'pluginURL' => IVYFORMS_URL,
229 + 'siteURL' => esc_url_raw(site_url()),
230 + ]
231 + );
232 +
233 + $aiAvailability = $this->currentAiAvailability();
234 +
235 + wp_localize_script(
236 + $scriptId,
237 + 'wpIvyApiSettings',
238 + [
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(),
249 + ]
250 + );
251 +
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 + );
262 + }
263 +}