PluginProbe
Timetics – Appointment Booking Calendar & Scheduling / 1.0.64
Timetics – Appointment Booking Calendar & Scheduling v1.0.64
1.0.64 1.0.62 1.0.63 1.0.61 1.0.60 1.0.59 1.0.58 1.0.57 1.0.56 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.17 1.0.18 1.0.19 1.0.2 1.0.20 1.0.21 All 65 releases
← All changes | core/settings/api-settings.php +101 -68 1.0.60 → 1.0.64 View file →
@@ -5,8 +5,10 @@
5 5 * @package Timetics
6 6 */
7 7 namespace Timetics\Core\Settings;
8 8
9 +defined( 'ABSPATH' ) || exit;
10 +
9 11 use Timetics\Base\Api;
10 12 use Timetics\Core\Admin\Hooks;
11 13 use Timetics\Utils\Singleton;
12 14
@@ -38,8 +40,10 @@
38 40 [
39 41 'methods' => \WP_REST_Server::READABLE,
40 42 'callback' => [$this, 'get_settings'],
41 43 'permission_callback' => function () {
44 + // The public booking app needs a small, explicitly safe
45 + // settings payload. get_settings() filters it by role.
42 46 return true;
43 47 },
44 48 ],
45 49 [
@@ -83,19 +87,15 @@
83 87 * @return JSON
84 88 */
85 89 public function get_settings() {
86 90 $settings = apply_filters( 'timetics_settings', timetics_get_settings() );
87 - $is_admin = current_user_can( 'manage_timetics' );
88 - //only run for non user capabilities
89 - if ( ! $is_admin ) {
90 - $exclude_settings = $this->exclude_settings_for_customer();
91 - foreach($settings as $key => $setting){
92 - if( in_array( $key, $exclude_settings )){
93 - unset( $settings[$key] );
94 - }
95 - }
91 +
92 + // The booking and staff interfaces need non-sensitive display and scheduling
93 + // settings. Never send credentials or webhook URLs to non-administrators.
94 + if ( ! current_user_can( 'manage_options' ) ) {
95 + $settings = $this->get_staff_safe_settings( $settings );
96 96 }
97 -
97 +
98 98 $data = [
99 99 'status_code' => 200,
100 100 'success' => 1,
101 101 'message' => esc_html__( 'Get all settings', 'timetics' ),
@@ -105,8 +105,47 @@
105 105 return rest_ensure_response( $settings );
106 106 }
107 107
108 108 /**
109 + * Return only settings that staff need to use the admin interface.
110 + *
111 + * This is deliberately an allow-list. New settings remain private until they
112 + * have been reviewed and explicitly added here.
113 + *
114 + * @param array $settings Plugin settings.
115 + *
116 + * @return array
117 + */
118 + private function get_staff_safe_settings( $settings ) {
119 + $safe_keys = [
120 + 'availability',
121 + 'apple_calendar',
122 + 'blocked_days',
123 + 'busyness_category',
124 + 'calendar_locale',
125 + 'currency',
126 + 'custom_fields',
127 + 'default_booking_status',
128 + 'guest_enabled',
129 + 'guest_limit',
130 + 'google_calendar',
131 + 'locale_timezone',
132 + 'paypal_status',
133 + 'primary_color',
134 + 'remainder_time',
135 + 'secondary_color',
136 + 'slot_interval',
137 + 'stripe_status',
138 + 'outlook_calendar',
139 + 'wc_integration',
140 + 'wc_checkout_url',
141 + 'zoom_connection_type',
142 + ];
143 +
144 + return array_intersect_key( (array) $settings, array_flip( $safe_keys ) );
145 + }
146 +
147 + /**
109 148 * Update settings
110 149 *
111 150 * @param WP_Rest_Request $request
112 151 *
@@ -114,9 +153,33 @@
114 153 */
115 154 public function update_settings( $request ) {
116 155 $options = json_decode( $request->get_body(), true );
117 156
157 + if ( ! is_array( $options ) ) {
158 + return new \WP_Error(
159 + 'timetics_invalid_settings',
160 + __( 'Settings must be sent as a JSON object.', 'timetics' ),
161 + [ 'status' => 400 ]
162 + );
163 + }
164 +
118 165 /**
166 + * Filter the settings payload before any of it is checked or saved.
167 + *
168 + * Runs before the checks below, so a listener's result passes through
169 + * them like the raw request does. Add-ons use it to clean their own
170 + * keys. It is an extension point, not the sanitization for core keys.
171 + *
172 + * @since 1.0.63
173 + *
174 + * @param array $options Settings payload from the request body.
175 + */
176 + $filtered = apply_filters( 'timetics_settings_update_params', $options );
177 +
178 + // A listener returning a non-array must not make the save below write nothing.
179 + $options = is_array( $filtered ) ? $filtered : $options;
180 +
181 + /**
119 182 * Added temporary for leagacy sass. It will remove in future.
120 183 */
121 184 $data = [
122 185 'status_code' => 200,
@@ -166,8 +229,12 @@
166 229 if ( ! empty( $options['zapier_webhook'] ) && $options['zapier_webhook'] && apply_filters( 'timetics/admin/settings/zapier_webhook', false ) ) {
167 230 return rest_ensure_response( apply_filters( 'timetics/admin/settings/error_data', $data, 'zapier', timetics_get_settings() ) );
168 231 }
169 232
233 + if ( ! empty( $options['flowmattic_webhook'] ) && $options['flowmattic_webhook'] && apply_filters( 'timetics/admin/settings/flowmattic_webhook', false ) ) {
234 + return rest_ensure_response( apply_filters( 'timetics/admin/settings/error_data', $data, 'flowmattic', timetics_get_settings() ) );
235 + }
236 +
170 237 if (!empty($options['google_app_client_id']) && $options['google_app_client_id'] && apply_filters('timetics/admin/settings/google_calendar', false)) {
171 238 return rest_ensure_response(apply_filters('timetics/admin/settings/error_data', $data, 'google-calendar', timetics_get_settings()));
172 239 }
173 240
@@ -182,8 +249,12 @@
182 249 if ( ! empty( $options['apple_calendar'] ) && $options['apple_calendar'] && apply_filters( 'timetics/admin/settings/apple_calendar', false ) ) {
183 250 return rest_ensure_response( apply_filters( 'timetics/admin/settings/error_data', $data, 'paypal', timetics_get_settings() ) );
184 251 }
185 252
253 + if ( ! empty( $options['uncanny_automator'] ) && $options['uncanny_automator'] && apply_filters( 'timetics/admin/settings/uncanny_automator', false ) ) {
254 + return rest_ensure_response( apply_filters( 'timetics/admin/settings/error_data', $data, 'uncanny_automator', timetics_get_settings() ) );
255 + }
256 +
186 257 if (!empty($options['twillo_message']) && $options['twillo_message'] && apply_filters('timetics/admin/settings/twillo_messaging', false)) {
187 258 return rest_ensure_response(apply_filters('timetics/admin/settings/error_data', $data, 'twillo_messaging', timetics_get_settings()));
188 259 }
189 260
@@ -188,8 +259,28 @@
188 259 }
189 260
190 261 if ( $options ) {
191 262 foreach ( $options as $key => $value ) {
263 + // Webhook URLs are pasted from FlowMattic, so keep them a URL.
264 + if ( 'flowmattic_webhook' === $key ) {
265 + $value = esc_url_raw( $value );
266 + }
267 +
268 + // Stored as the strings `yes`/`no`: this
269 + // option defaults to on, and timetics_get_option() treats an
270 + // empty value as "unset" and hands back the default, so a
271 + // boolean false could never switch it off.
272 + if ( 'uncanny_automator' === $key ) {
273 + $value = $value && 'no' !== $value ? 'yes' : 'no';
274 + }
275 +
276 + // Clamp: the cleanup cron only runs every 5 minutes, so a
277 + // lower value would silently do nothing and 0/negative would
278 + // expire bookings instantly.
279 + if ( 'unpaid_booking_expiry_minutes' === $key ) {
280 + $value = max( 5, absint( $value ) );
281 + }
282 +
192 283 timetics_update_option( $key, $value );
193 284 }
194 285 }
195 286
@@ -243,63 +334,5 @@
243 334
244 335 return rest_ensure_response( $response );
245 336 }
246 337
247 - public function exclude_settings_for_customer() {
248 - $allowed_keys = [
249 - "booking_created_customer_email_from",
250 - "booking_created_customer_email_title",
251 - "booking_created_customer_email_body",
252 - "booking_created_host_email_from",
253 - "booking_created_host_email_title",
254 - "booking_created_host_email_body",
255 - "booking_canceled_customer_email_from",
256 - "booking_canceled_customer_email_title",
257 - "booking_canceled_customer_email_body",
258 - "booking_canceled_host_email_from",
259 - "booking_canceled_host_email_title",
260 - "booking_canceled_host_email_body",
261 - "booking_rescheduled_customer_email_from",
262 - "booking_rescheduled_customer_email_title",
263 - "booking_rescheduled_customer_email_body",
264 - "booking_rescheduled_host_email_from",
265 - "booking_rescheduled_host_email_title",
266 - "booking_rescheduled_host_email_body",
267 - "booking_reminder_customer_email_from",
268 - "booking_reminder_customer_email_title",
269 - "booking_reminder_customer_email_body",
270 - "booking_reminder_host_email_from",
271 - "booking_reminder_host_email_title",
272 - "booking_reminder_host_email_body",
273 - "google_auth_redirect_uri",
274 - "google_app_client_id",
275 - "google_app_client_secret",
276 - "zoom_client_id",
277 - "zoom_client_secret",
278 - "zoom_auth_redirect_uri",
279 - "fluentcrm_webhook",
280 - "zapier_webhook",
281 - "pabbly_webhook",
282 - "twillo_account_id",
283 - "twillo_token",
284 - "twillo_phone_number",
285 - "booking_created_customer",
286 - "booking_created_host",
287 - "booking_canceled_customer",
288 - "booking_canceled_host",
289 - "booking_rescheduled_customer",
290 - "booking_rescheduled_host",
291 - "booking_reminder_customer",
292 - "booking_reminder_host",
293 - "stripe_pub_key",
294 - "stripe_secret_key",
295 - "paypal_client_id",
296 - "paypal_client_secret",
297 - "outlook_app_client_id",
298 - "outlook_app_client_secret",
299 - "outlook_auth_redirect_uri",
300 - ];
301 -
302 -
303 - return $allowed_keys;
304 - }
305 338 }