PluginProbe
Booking Calendar / 11.6.1
Booking Calendar v11.6.1
11.8.3 11.8.2 11.8.1 11.8 11.7 11.6.1 11.6 11.5 11.4.3 11.4.2 11.4.1 11.4 11.3 11.2.1 11.2 11.1 11.0 10.15.7 10.15.6 10.1.3 10.10 10.10.1 10.10.2 10.11 10.11.2 All 203 releases
booking / includes / page-appointment-services / appointment_services__activate.php

appointment_services__activate.php in Booking Calendar 11.6.1, at includes/page-appointment-services/appointment_services__activate.php

390 lines 14.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /** Database schema for Appointment Services. @package Booking Calendar */
3 if ( ! defined( 'ABSPATH' ) ) { exit; }
4
5 if ( ! defined( 'WPBC_APPOINTMENT_SERVICES_DB_VERSION' ) ) {
6 define( 'WPBC_APPOINTMENT_SERVICES_DB_VERSION', '1.0.0' );
7 }
8
9 /**
10 * Return the canonical starter Services used by a new installation.
11 *
12 * Both Services share the existing default Provider and Booking Form. Their
13 * pictures use the configured starter-asset source, so distributions may use
14 * bundled files or the corresponding Booking Calendar website directory.
15 *
16 * @param int $provider_id Existing Booking Resource used as the Provider.
17 * @param int $booking_form_id Optional published Booking Form assigned to the Services.
18 *
19 * @return array<int,array<string,mixed>> Normalized values accepted by the Service repository.
20 */
21 function wpbc_appointment_services_get_starter_services_values( $provider_id, $booking_form_id = 0 ) {
22 $common_values = array(
23 'duration_minutes' => 30,
24 'buffer_before_minutes' => 0,
25 'buffer_after_minutes' => 0,
26 'base_cost' => '0.00',
27 'booking_form_id' => absint( $booking_form_id ),
28 'status' => 'active',
29 'resource_ids' => array( absint( $provider_id ) ),
30 );
31
32 return array(
33 array_merge(
34 $common_values,
35 array(
36 'title' => __( 'Initial Consultation', 'booking' ),
37 'description' => __( 'A focused first meeting to understand your needs and recommend the right next step.', 'booking' ),
38 'metadata' => array(
39 'picture_url' => wpbc_get_starter_asset_url( 'img/services/professional-services-demo_service-initial-consultation.png' ),
40 'quickstart_key' => 'appointment_starter',
41 'schema_version' => 1,
42 ),
43 )
44 ),
45 array_merge(
46 $common_values,
47 array(
48 'title' => __( 'One-to-One Session', 'booking' ),
49 'description' => __( 'Personalized support tailored to your goals, questions, and schedule.', 'booking' ),
50 'metadata' => array(
51 'picture_url' => wpbc_get_starter_asset_url( 'img/services/professional-services-demo_service-one-to-one-session.png' ),
52 'quickstart_key' => 'appointment_starter_one_to_one',
53 'schema_version' => 1,
54 ),
55 )
56 ),
57 );
58 }
59
60 /**
61 * Return the primary starter Service used by Appointment QuickStart.
62 *
63 * QuickStart creates at most one dedicated Service, while fresh activation
64 * seeds the complete starter set returned by
65 * `wpbc_appointment_services_get_starter_services_values()`.
66 *
67 * @param int $provider_id Existing Booking Resource used as the Provider.
68 * @param int $booking_form_id Optional published Booking Form assigned to the Service.
69 *
70 * @return array<string,mixed> Normalized values accepted by the Service repository.
71 */
72 function wpbc_appointment_services_get_starter_service_values( $provider_id, $booking_form_id = 0 ) {
73 $starter_services = wpbc_appointment_services_get_starter_services_values( $provider_id, $booking_form_id );
74
75 return reset( $starter_services );
76 }
77
78 /**
79 * Resolve the published starter form assigned to the default Appointment Service.
80 *
81 * The activation form registry owns the form identity. This resolver reads its
82 * assignment marker so the Service seed does not duplicate a form slug.
83 *
84 * @return int Published Booking Form ID, or zero while form storage is unavailable.
85 */
86 function wpbc_appointment_services_get_starter_booking_form_id() {
87 if (
88 ! function_exists( 'wpbc_get_activation_booking_form_page_configs' )
89 || ! function_exists( 'wpbc_is_table_exists' )
90 || ! wpbc_is_table_exists( 'booking_form_structures' )
91 || ! class_exists( 'WPBC_BFB_Form_Storage' )
92 ) {
93 return 0;
94 }
95
96 $form_configs = wpbc_get_activation_booking_form_page_configs();
97 if ( empty( $form_configs ) || ! is_array( $form_configs ) ) {
98 return 0;
99 }
100
101 foreach ( $form_configs as $form_config ) {
102 if ( empty( $form_config['assign_to_default_appointment_service'] ) ) {
103 continue;
104 }
105
106 $form_slug = isset( $form_config['form_slug'] )
107 ? sanitize_key( (string) $form_config['form_slug'] )
108 : '';
109 if ( '' === $form_slug ) {
110 return 0;
111 }
112
113 $booking_form = WPBC_BFB_Form_Storage::get_current_form_by_key( $form_slug, 0, 'published' );
114
115 return ! empty( $booking_form->booking_form_id )
116 ? absint( $booking_form->booking_form_id )
117 : 0;
118 }
119
120 return 0;
121 }
122
123 /**
124 * Resolve a logical Appointment Services table suffix to its full table name.
125 *
126 * @param string $suffix Logical suffix: services, service_resources, or appointment_details.
127 *
128 * @return string WordPress-prefixed database table name.
129 */
130 function wpbc_appointment_services_table_name( $suffix = 'services' ) {
131 global $wpdb;
132 $tables = array(
133 'services' => 'booking_services',
134 'service_resources' => 'booking_service_resources',
135 'appointment_details' => 'booking_appointment_details',
136 );
137 $suffix = isset( $tables[ $suffix ] ) ? $suffix : 'services';
138 return $wpdb->prefix . $tables[ $suffix ];
139 }
140
141 /**
142 * Determine whether every Appointment Services table is available.
143 *
144 * @return bool True when the Service, assignment, and snapshot tables exist.
145 */
146 function wpbc_appointment_services_tables_exist() {
147 return wpbc_is_table_exists( 'booking_services' )
148 && wpbc_is_table_exists( 'booking_service_resources' )
149 && wpbc_is_table_exists( 'booking_appointment_details' );
150 }
151
152 /**
153 * Create the starter Services after their database tables are installed.
154 *
155 * This runs only for a newly created Services table, or when an earlier seed
156 * attempt was marked for retry. It deliberately does not inspect an existing
157 * empty catalog because administrators may intentionally remove every Service.
158 *
159 * @return bool True when every starter Service was created successfully.
160 */
161 function wpbc_activation__appointment_services__seed_default_service() {
162 global $wpdb;
163
164 if ( ! wpbc_appointment_services_tables_exist() ) {
165 return false;
166 }
167
168 $provider_id = function_exists( 'wpbc_get_default_resource' ) ? absint( wpbc_get_default_resource() ) : 1;
169 if ( ! $provider_id ) {
170 $provider_id = 1;
171 }
172
173 $booking_form_id = wpbc_appointment_services_get_starter_booking_form_id();
174 if ( ! $booking_form_id ) {
175 return false;
176 }
177
178 $starter_services = wpbc_appointment_services_get_starter_services_values( $provider_id, $booking_form_id );
179 $now = current_time( 'mysql' );
180 $current_user_id = get_current_user_id();
181 $owner_user_id = function_exists( 'wpbc_appointment_services_get_owner_user_id' )
182 ? absint( wpbc_appointment_services_get_owner_user_id() )
183 : 0;
184 $created_service_ids = array();
185 $assignment_inserted = true;
186
187 foreach ( $starter_services as $starter_service ) {
188 $metadata = wp_json_encode( $starter_service['metadata'] );
189 $service_inserted = $wpdb->insert(
190 wpbc_appointment_services_table_name( 'services' ),
191 array(
192 'owner_user_id' => $owner_user_id,
193 'title' => $starter_service['title'],
194 'description' => $starter_service['description'],
195 'duration_minutes' => $starter_service['duration_minutes'],
196 'buffer_before_minutes' => $starter_service['buffer_before_minutes'],
197 'buffer_after_minutes' => $starter_service['buffer_after_minutes'],
198 'base_cost' => $starter_service['base_cost'],
199 'booking_form_id' => $starter_service['booking_form_id'],
200 'status' => $starter_service['status'],
201 'metadata' => false === $metadata ? '{}' : $metadata,
202 'created_by' => $current_user_id,
203 'modified_by' => $current_user_id,
204 'creation_date' => $now,
205 'modification_date' => $now,
206 ),
207 array( '%d', '%s', '%s', '%d', '%d', '%d', '%s', '%d', '%s', '%s', '%d', '%d', '%s', '%s' )
208 ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
209 $service_id = absint( $wpdb->insert_id );
210
211 if ( false === $service_inserted || ! $service_id ) {
212 break;
213 }
214
215 $created_service_ids[] = $service_id;
216 $assignment_inserted = $wpdb->insert(
217 wpbc_appointment_services_table_name( 'service_resources' ),
218 array(
219 'service_id' => $service_id,
220 'resource_id' => $provider_id,
221 'priority' => 0,
222 'status' => 'active',
223 ),
224 array( '%d', '%d', '%d', '%s' )
225 ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
226
227 if ( false === $assignment_inserted ) {
228 break;
229 }
230 }
231
232 if ( count( $created_service_ids ) !== count( $starter_services ) || false === $assignment_inserted ) {
233 foreach ( $created_service_ids as $created_service_id ) {
234 $wpdb->delete(
235 wpbc_appointment_services_table_name( 'service_resources' ),
236 array( 'service_id' => $created_service_id ),
237 array( '%d' )
238 ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
239 $wpdb->delete(
240 wpbc_appointment_services_table_name( 'services' ),
241 array( 'service_id' => $created_service_id ),
242 array( '%d' )
243 ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
244 }
245
246 return false;
247 }
248
249 return true;
250 }
251
252 /**
253 * Complete a pending starter Service seed after activation forms are available.
254 *
255 * @return bool True when the pending Service was created; otherwise false.
256 */
257 function wpbc_activation__appointment_services__maybe_seed_default_service() {
258 if ( 'On' !== get_bk_option( 'booking_appointment_services_default_seed_pending' ) ) {
259 return false;
260 }
261
262 if ( ! wpbc_activation__appointment_services__seed_default_service() ) {
263 return false;
264 }
265
266 delete_bk_option( 'booking_appointment_services_default_seed_pending' );
267
268 return true;
269 }
270 add_action(
271 'wpbc_activation_custom_booking_forms_created',
272 'wpbc_activation__appointment_services__maybe_seed_default_service'
273 );
274
275 /**
276 * Create or upgrade all Service, assignment, and Appointment snapshot tables.
277 *
278 * @return void
279 */
280 function wpbc_activation__appointment_services() {
281 global $wpdb;
282 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
283
284 $services_table_existed = wpbc_is_table_exists( 'booking_services' );
285 if ( ! $services_table_existed ) {
286 update_bk_option( 'booking_appointment_services_default_seed_pending', 'On' );
287 }
288
289 $charset_collate = $wpdb->get_charset_collate();
290 $services = wpbc_appointment_services_table_name( 'services' );
291 $assignments = wpbc_appointment_services_table_name( 'service_resources' );
292 $details = wpbc_appointment_services_table_name( 'appointment_details' );
293
294 $sql_services = "CREATE TABLE {$services} (
295 service_id bigint(20) unsigned NOT NULL auto_increment,
296 owner_user_id bigint(20) unsigned NOT NULL default 0,
297 title varchar(200) NOT NULL default '',
298 description text NULL,
299 duration_minutes smallint(5) unsigned NOT NULL default 30,
300 buffer_before_minutes smallint(5) unsigned NOT NULL default 0,
301 buffer_after_minutes smallint(5) unsigned NOT NULL default 0,
302 base_cost decimal(12,2) NOT NULL default 0.00,
303 booking_form_id bigint(20) unsigned NOT NULL default 0,
304 status varchar(20) NOT NULL default 'active',
305 metadata longtext NULL,
306 created_by bigint(20) unsigned NOT NULL default 0,
307 modified_by bigint(20) unsigned NOT NULL default 0,
308 creation_date datetime NOT NULL default '0000-00-00 00:00:00',
309 modification_date datetime NOT NULL default '0000-00-00 00:00:00',
310 PRIMARY KEY (service_id),
311 KEY owner_status (owner_user_id,status),
312 KEY status_title (status,title)
313 ) {$charset_collate};";
314
315 $sql_assignments = "CREATE TABLE {$assignments} (
316 assignment_id bigint(20) unsigned NOT NULL auto_increment,
317 service_id bigint(20) unsigned NOT NULL,
318 resource_id bigint(20) unsigned NOT NULL,
319 duration_override smallint(5) unsigned NULL,
320 cost_override decimal(12,2) NULL,
321 priority int(10) unsigned NOT NULL default 0,
322 status varchar(20) NOT NULL default 'active',
323 PRIMARY KEY (assignment_id),
324 UNIQUE KEY service_resource (service_id,resource_id),
325 KEY resource_status (resource_id,status),
326 KEY service_status (service_id,status)
327 ) {$charset_collate};";
328
329 $sql_details = "CREATE TABLE {$details} (
330 appointment_detail_id bigint(20) unsigned NOT NULL auto_increment,
331 booking_id bigint(20) unsigned NOT NULL,
332 service_id bigint(20) unsigned NOT NULL,
333 resource_id bigint(20) unsigned NOT NULL,
334 service_title varchar(200) NOT NULL default '',
335 duration_minutes smallint(5) unsigned NOT NULL default 0,
336 buffer_before_minutes smallint(5) unsigned NOT NULL default 0,
337 buffer_after_minutes smallint(5) unsigned NOT NULL default 0,
338 base_cost decimal(12,2) NOT NULL default 0.00,
339 booking_form_id bigint(20) unsigned NOT NULL default 0,
340 metadata longtext NULL,
341 creation_date datetime NOT NULL default '0000-00-00 00:00:00',
342 modification_date datetime NOT NULL default '0000-00-00 00:00:00',
343 PRIMARY KEY (appointment_detail_id),
344 UNIQUE KEY booking_id (booking_id),
345 KEY service_id (service_id),
346 KEY resource_id (resource_id)
347 ) {$charset_collate};";
348
349 dbDelta( $sql_services );
350 dbDelta( $sql_assignments );
351 dbDelta( $sql_details );
352 update_bk_option( 'booking_appointment_services_db_version', WPBC_APPOINTMENT_SERVICES_DB_VERSION );
353
354 wpbc_activation__appointment_services__maybe_seed_default_service();
355 }
356 add_bk_action( 'wpbc_free_version_activation', 'wpbc_activation__appointment_services' );
357 add_bk_action( 'wpbc_other_versions_activation', 'wpbc_activation__appointment_services' );
358
359 /**
360 * Upgrade the Appointment Services schema from an authorized admin request.
361 *
362 * @return void
363 */
364 function wpbc_activation__appointment_services__maybe_upgrade() {
365 if ( ! is_admin() || ! current_user_can( 'activate_plugins' ) ) { return; }
366 if (
367 WPBC_APPOINTMENT_SERVICES_DB_VERSION !== get_bk_option( 'booking_appointment_services_db_version' )
368 || ! wpbc_appointment_services_tables_exist()
369 || 'On' === get_bk_option( 'booking_appointment_services_default_seed_pending' )
370 ) {
371 wpbc_activation__appointment_services();
372 }
373 }
374 add_action( 'admin_init', 'wpbc_activation__appointment_services__maybe_upgrade' );
375
376 /**
377 * Remove Appointment Services tables during Booking Calendar's full data removal.
378 *
379 * @return void
380 */
381 function wpbc_deactivation__appointment_services() {
382 global $wpdb;
383 $wpdb->query( 'DROP TABLE IF EXISTS ' . wpbc_appointment_services_table_name( 'appointment_details' ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
384 $wpdb->query( 'DROP TABLE IF EXISTS ' . wpbc_appointment_services_table_name( 'service_resources' ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
385 $wpdb->query( 'DROP TABLE IF EXISTS ' . wpbc_appointment_services_table_name( 'services' ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
386 delete_bk_option( 'booking_appointment_services_default_seed_pending' );
387 }
388 add_bk_action( 'wpbc_free_version_deactivation', 'wpbc_deactivation__appointment_services' );
389 add_bk_action( 'wpbc_other_versions_deactivation', 'wpbc_deactivation__appointment_services' );
390