PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 2.5.0
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v2.5.0
2.5.0 2.4.0 2.3.0 2.2.5 2.2.0 2.1.2 2.1.1 trunk 1.10.0 1.10.01 1.10.02 1.5.0 1.5.01 1.5.02 1.5.1 1.5.10 1.5.20 1.5.21 1.5.22 1.5.23 1.5.24 1.5.25 1.6.0 1.7.0 1.7.1 All 34 releases
fluent-booking / app / Http / Controllers / SettingsController.php

SettingsController.php in Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution 2.5.0, at app/Http/Controllers/SettingsController.php

406 lines 15.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentBooking\App\Http\Controllers;
4
5 use FluentBooking\App\App;
6 use FluentBooking\App\Services\GlobalModules\GlobalModules;
7 use FluentBooking\App\Hooks\Handlers\AdminMenuHandler;
8 use FluentBooking\App\Services\Helper;
9 use FluentBooking\App\Services\CurrenciesHelper;
10 use FluentBooking\App\Services\Libs\Countries;
11 use FluentBooking\App\Services\OnboardingService;
12 use FluentBooking\Framework\Http\Request\Request;
13 use FluentBooking\Framework\Support\Arr;
14
15 class SettingsController extends Controller
16 {
17 public function getSettingsMenu()
18 {
19 return [
20 'menu_items' => AdminMenuHandler::settingsMenuItems()
21 ];
22 }
23
24 public function getGeneralSettings()
25 {
26 $settings = Helper::getGlobalSettings();
27
28 $settings['emailingFields'] = [
29 'from_name' => [
30 'wrapper_class' => 'fc_item_half',
31 'type' => 'input-text',
32 'placeholder' => __('From Name for emails', 'fluent-booking'),
33 'label' => __('From Name', 'fluent-booking'),
34 'help' => __('Default Name that will be used to send email)', 'fluent-booking')
35 ],
36 'from_email' => [
37 'wrapper_class' => 'fc_item_half',
38 'type' => 'input-or-select',
39 'placeholder' => '[email protected]',
40 'data_type' => 'email',
41 'options' => Helper::getVerifiedSenders(),
42 'label' => __('From Email Address', 'fluent-booking'),
43 'help' => __('Provide Valid Email Address that will be used to send emails', 'fluent-booking'),
44 'inline_help' => __('email as per your domain/SMTP settings', 'fluent-booking')
45 ],
46 'reply_to_name' => [
47 'wrapper_class' => 'fc_item_half',
48 'type' => 'input-text',
49 'placeholder' => __('Reply to Name', 'fluent-booking'),
50 'label' => __('Reply to Name (Optional)', 'fluent-booking'),
51 'help' => __('Default Reply to Name (Optional)', 'fluent-booking')
52 ],
53 'reply_to_email' => [
54 'wrapper_class' => 'fc_item_half',
55 'type' => 'input-text',
56 'placeholder' => '[email protected]',
57 'data_type' => 'email',
58 'label' => __('Reply to Email (Optional)', 'fluent-booking'),
59 'help' => __('Default Reply to Email (Optional)', 'fluent-booking')
60 ],
61 'use_host_name' => [
62 'wrapper_class' => 'fc_full_width fc_mb_0',
63 'type' => 'inline-checkbox',
64 'checkbox_label' => __('Use host name as From Name for booking emails to guests', 'fluent-booking'),
65 'true_label' => 'yes',
66 'false_label' => 'no',
67 ],
68 'use_host_email_on_reply' => [
69 'wrapper_class' => 'fc_full_width fc_mb_0',
70 'type' => 'inline-checkbox',
71 'checkbox_label' => __('Use host email for reply-to value for booking emails to guests', 'fluent-booking'),
72 'true_label' => 'yes',
73 'false_label' => 'no',
74 ],
75 'attach_ics_on_confirmation' => [
76 'wrapper_class' => 'fc_full_width fc_mb_0',
77 'type' => 'inline-checkbox',
78 'checkbox_label' => __('Include ICS file attachment in booking confirmation emails', 'fluent-booking'),
79 'true_label' => 'yes',
80 'false_label' => 'no',
81 ],
82 'email_footer' => [
83 'wrapper_class' => 'fc_full_width fc_mb_0 fc_wp_editor',
84 'type' => 'wp-editor-field',
85 'label' => __('Email Footer for Booking related emails (Optional)', 'fluent-booking'),
86 'inline_help' => __('You may include your business name, address, etc. here. For example: <br />You have received this email because you signed up for an event or made a booking on our website.', 'fluent-booking')
87 ]
88 ];
89
90 $settings['all_countries'] = Countries::get();
91 $settings['share_stats'] = Arr::get((array) Helper::getMeta('option', 0, 'optin'), 'share_stats', '');
92
93 return apply_filters('fluent_booking/general_settings', $settings);
94 }
95
96 public function updateGeneralSettings(Request $request)
97 {
98 $settings = [
99 'emailing' => $request->get('emailing', []),
100 'administration' => $request->get('administration', []),
101 ];
102
103 $formattedSettings = [];
104
105 foreach ($settings as $settingKey => $setting) {
106 $santizedSettings = array_map('sanitize_text_field', $setting);
107 if ($settingKey == 'emailing') {
108 $santizedSettings['email_footer'] = wp_kses_post($setting['email_footer']);
109 }
110 $formattedSettings[$settingKey] = $santizedSettings;
111 }
112 $formattedSettings['time_format'] = sanitize_text_field($request->get('timeFormat'));
113
114 // The option also holds keys saved elsewhere, e.g. theme from updateThemeSettings().
115 update_option('_fluent_booking_settings', array_merge((array) get_option('_fluent_booking_settings', []), $formattedSettings), 'no');
116
117 return [
118 'message' => __('Settings updated successfully', 'fluent-booking'),
119 'settings' => $formattedSettings
120 ];
121 }
122
123 public function updatePaymentSettings(Request $request)
124 {
125 $paymentSettings = $request->get('payments', []);
126
127 $currency = Arr::get($paymentSettings, 'currency', 'USD');
128 $isActive = Arr::get($paymentSettings, 'is_active', 'no');
129 $numberFormat = Arr::get($paymentSettings, 'number_format', 'comma_separated');
130 $currencyPosition = Arr::get($paymentSettings, 'currency_position', 'left');
131
132 update_option('fluent_booking_global_payment_settings', [
133 'currency' => sanitize_text_field($currency),
134 'is_active' => $isActive == 'yes' ? 'yes' : 'no',
135 'number_format' => $numberFormat == 'comma_separated' ? 'comma_separated' : 'dot_separated',
136 'currency_position' => sanitize_text_field($currencyPosition)
137 ], 'no');
138
139 CurrenciesHelper::getGlobalCurrencySettings(true);
140
141 return [
142 'message' => __('Settings updated successfully', 'fluent-booking')
143 ];
144 }
145
146 public function updateThemeSettings(Request $request)
147 {
148 $themeSettings = sanitize_text_field($request->get('theme'));
149
150 $bookingOption = get_option('_fluent_booking_settings', []);
151
152 $bookingOption['theme'] = $themeSettings;
153
154 update_option('_fluent_booking_settings', $bookingOption, 'no');
155
156 return [
157 'message' => __('Settings updated successfully', 'fluent-booking')
158 ];
159 }
160
161 public function getGlobalModules(Request $request)
162 {
163 $settings = Helper::getGlobalModuleSettings();
164
165
166 if (!$settings) {
167 $settings = (object)[];
168 }
169
170 $featuresPrefs = Helper::getPrefSettings(false);
171
172 if (empty($featuresPrefs['frontend']['render_type'])) {
173 $featuresPrefs['frontend']['render_type'] = 'standalone';
174 }
175
176 $featuresPrefs['panel_url'] = Helper::getAppBaseUrl();
177
178 return [
179 'settings' => $settings,
180 'modules' => (new GlobalModules())->getAllModules(),
181 'featureModules' => $featuresPrefs
182 ];
183 }
184
185 public function updateGlobalModules(Request $request)
186 {
187 $settings = $request->get('settings', []);
188
189 $modules = (new GlobalModules())->getAllModules();
190
191 $formattedModules = [];
192
193 foreach ($settings as $settingKey => $value) {
194 if (!isset($modules[$settingKey])) {
195 continue;
196 }
197 $formattedModules[$settingKey] = $value == 'yes' ? 'yes' : 'no';
198 }
199
200 Helper::updateGlobalModuleSettings($formattedModules);
201
202 return [
203 'message' => __('Settings updated successfully', 'fluent-booking'),
204 ];
205 }
206
207 public function getPages(Request $request)
208 {
209 $db = App::getInstance('db');
210
211 $allPages = $db->table('posts')->where('post_type', 'page')
212 ->where('post_status', 'publish')
213 ->select(['ID', 'post_title', 'post_name'])
214 ->orderBy('post_title', 'ASC')
215 ->get();
216
217 $pages = [];
218 foreach ($allPages as $page) {
219 $pages[] = [
220 'id' => $page->ID,
221 'name' => $page->post_name,
222 'title' => $page->post_title ? $page->post_title : __('(no title)', 'fluent-booking')
223 ];
224 }
225
226 return [
227 'pages' => $pages
228 ];
229 }
230
231 public function saveAddonsSettings(Request $request)
232 {
233 if (!defined('FLUENT_BOOKING_PRO_DIR_FILE')) {
234 return $this->sendError([
235 'message' => __('This feature is only available in FluentBooking Pro', 'fluent-booking')
236 ]);
237 }
238
239 $settings = $request->get('settings', []);
240
241 $prefSettings = Helper::getPrefSettings(false);
242
243 $settings = wp_parse_args($settings, $prefSettings);
244
245 $settings = Arr::only($settings, array_keys($prefSettings));
246 $settings['frontend']['slug'] = sanitize_title($settings['frontend']['slug']);
247
248 if (empty($settings['frontend']['slug'])) {
249 $settings['frontend']['slug'] = 'projects';
250 }
251
252 if (defined('FLUENT_BOOKING_ADMIN_SLUG') && FLUENT_BOOKING_FRONT_SLUG) {
253 $settings['frontend']['slug'] = FLUENT_BOOKING_FRONT_SLUG;
254 }
255
256 do_action('fluent_booking/saving_addons', $settings, $prefSettings);
257
258 update_option('fluent_booking_modules', $settings, 'yes');
259
260 return $this->sendSuccess([
261 'message' => __('Settings are saved', 'fluent-booking'),
262 'featureModules' => $settings
263 ]);
264 }
265
266 public function updateOptin(Request $request)
267 {
268 // Validated before sanitizing: sanitize_email() turns a typo into '', which would pass
269 // `nullable` and drop the address without telling anyone.
270 $this->validate([
271 'share_stats' => sanitize_text_field($request->get('share_stats', '')),
272 'optin_email' => trim((string) $request->get('optin_email', ''))
273 ], [
274 'share_stats' => 'nullable|in:yes,no',
275 'optin_email' => 'nullable|email'
276 ], [
277 'optin_email.email' => __('Please enter a valid email address', 'fluent-booking')
278 ]);
279
280 $data = [
281 'share_stats' => sanitize_text_field($request->get('share_stats', '')),
282 'optin_email' => sanitize_email($request->get('optin_email', '')),
283 'optin_name' => sanitize_text_field($request->get('optin_name', ''))
284 ];
285
286 // One record: the stats decision, the opt-in email, when the prompt was dismissed and
287 // when stats were last sent.
288 $optin = (array) Helper::getMeta('option', 0, 'optin');
289
290 if ($data['share_stats']) {
291 $optin['share_stats'] = $data['share_stats'];
292
293 // Opting back in sends straight away rather than waiting out the old interval.
294 if ($data['share_stats'] === 'no') {
295 unset($optin['last_sent_at']);
296 }
297 }
298
299 // Closing the prompt only snoozes it; it says nothing about stats.
300 // See AdminMenuHandler::showOptinPrompt().
301 if ($request->get('dismiss') === 'yes') {
302 $optin['dismissed_at'] = time();
303 }
304
305 $optinStatus = '';
306 if ($data['optin_email']) {
307 // Reported with the usage data instead of the site's admin email.
308 $optin['email'] = $data['optin_email'];
309 $optinStatus = $this->subscribeToNewsletter($data['optin_email'], $data['optin_name']);
310 }
311
312 Helper::updateMeta('option', 0, 'optin', $optin);
313
314 return [
315 'message' => __('Settings updated successfully', 'fluent-booking'),
316 'share_stats' => Arr::get($optin, 'share_stats', ''),
317 'optin_status' => $optinStatus
318 ];
319 }
320
321 /**
322 * Hands the admin's name and email to the licensing Worker, which forwards them to
323 * fluentbooking.com's FluentCRM. Pro is matched later by site url, so it must be home_url().
324 *
325 * @return string 'confirm_email', 'subscribed' or 'queued'
326 */
327 private function subscribeToNewsletter($email, $name)
328 {
329 $response = wp_remote_post('https://fluentapi.wpmanageninja.com/subscribe', [
330 'timeout' => 15,
331 'headers' => ['Content-Type' => 'application/json'],
332 'cookies' => [],
333 'body' => wp_json_encode([
334 'product' => 'fluent-booking',
335 'product_version' => FLUENT_BOOKING_VERSION,
336 'site_url' => home_url(),
337 'email' => $email,
338 'full_name' => $name,
339 'consent_version' => '2026-09-a',
340 'locale' => get_user_locale()
341 ])
342 ]);
343
344 $body = json_decode(wp_remote_retrieve_body($response), true);
345 $status = is_array($body) ? Arr::get($body, 'status') : '';
346
347 return in_array($status, ['confirm_email', 'subscribed'], true) ? $status : 'queued';
348 }
349
350 public function installPlugin(Request $request)
351 {
352 if (!current_user_can('install_plugins')) {
353 return $this->sendError([
354 'message' => __('You do not have permission to install plugins', 'fluent-booking')
355 ]);
356 }
357
358 $pluginId = $request->get('plugin_id');
359
360 $allowedPlugins = [
361 'fluent-smtp' => [
362 'name' => 'FluentSMTP',
363 'repo-slug' => 'fluent-smtp',
364 'file' => 'fluent-smtp.php',
365 ],
366 'fluent-booking' => [
367 'name' => 'FluentBooking',
368 'repo-slug' => 'fluent-booking',
369 'file' => 'fluent-booking.php',
370 ],
371 'fluentform' => [
372 'name' => 'FluentForm',
373 'repo-slug' => 'fluentform',
374 'file' => 'fluentform.php',
375 ],
376 'fluent-crm' => [
377 'name' => 'FluentCRM',
378 'repo-slug' => 'fluent-crm',
379 'file' => 'fluent-crm.php',
380 ],
381 'fluent-boards' => [
382 'name' => 'FluentBoards',
383 'repo-slug' => 'fluent-boards',
384 'file' => 'fluent-boards.php',
385 ],
386 'fluent-cart' => [
387 'name' => 'FluentCart',
388 'repo-slug' => 'fluent-cart',
389 'file' => 'fluent-cart.php',
390 ]
391 ];
392
393 if (!isset($allowedPlugins[$pluginId])) {
394 return $this->sendError([
395 'message' => __('This action is not allowed', 'fluent-booking')
396 ]);
397 }
398
399 OnboardingService::backgroundInstaller($allowedPlugins[$pluginId]);
400
401 return $this->sendSuccess([
402 'message' => __('Plugin has been installed Successfully', 'fluent-booking')
403 ]);
404 }
405 }
406