PluginProbe
Booktics – Appointment Booking Calendar for Service Businesses / 1.0.29
Booktics – Appointment Booking Calendar for Service Businesses v1.0.29
1.0.29 1.0.28 1.0.27 1.0.26 1.0.25 1.0.24 1.0.23 1.0.22 1.0.21 1.0.20 1.0.19 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.2 1.0.3 All 31 releases
← All changes | core/service/controllers/service-controller.php +255 -183 1.0.0 → 1.0.29 View file →
@@ -7,8 +7,9 @@
7 7 use Booktics\Models\Team_Member_Model;
8 8 use Booktics\Services\Schedule_Manager;
9 9 use Booktics\Services\Schedule_Record;
10 10 use Booktics\Taxonomy\Category;
11 +use Booktics\Service\Helpers\Service_Helper;
11 12 use Exception;
12 13 use WP_Error;
13 14 use WP_HTTP_Response;
14 15 use WP_REST_Server;
@@ -40,94 +41,94 @@
40 41 */
41 42 public function register_routes(): void {
42 43 register_rest_route(
43 44 $this->namespace, $this->base, array(
44 - array(
45 - 'methods' => WP_REST_Server::CREATABLE,
46 - 'callback' => array( $this, 'create_item' ),
47 - 'permission_callback' => array(
48 - $this,
49 - 'create_item_permissions_check',
50 - ),
51 - ),
45 + array(
46 + 'methods' => WP_REST_Server::CREATABLE,
47 + 'callback' => array( $this, 'create_item' ),
48 + 'permission_callback' => array(
49 + $this,
50 + 'create_item_permissions_check',
51 + ),
52 + ),
52 53 )
53 54 );
54 55
55 56 register_rest_route(
56 57 $this->namespace, $this->base, array(
57 - array(
58 - 'methods' => WP_REST_Server::READABLE,
59 - 'callback' => array( $this, 'get_items' ),
60 - 'permission_callback' => array(
61 - $this,
62 - 'get_items_permissions_check',
63 - ),
64 - ),
58 + array(
59 + 'methods' => WP_REST_Server::READABLE,
60 + 'callback' => array( $this, 'get_items' ),
61 + 'permission_callback' => array(
62 + $this,
63 + 'get_items_permissions_check',
64 + ),
65 + ),
65 66 )
66 67 );
67 68
68 69 register_rest_route(
69 70 $this->namespace, $this->base, array(
70 - array(
71 - 'methods' => WP_REST_Server::DELETABLE,
72 - 'callback' => array( $this, 'delete_items' ),
73 - 'permission_callback' => array(
74 - $this,
75 - 'delete_items_permissions_check',
76 - ),
77 - ),
71 + array(
72 + 'methods' => WP_REST_Server::DELETABLE,
73 + 'callback' => array( $this, 'delete_items' ),
74 + 'permission_callback' => array(
75 + $this,
76 + 'delete_items_permissions_check',
77 + ),
78 + ),
78 79 )
79 80 );
80 81
81 82 register_rest_route(
82 83 $this->namespace, $this->base . '/(?P<id>[\d]+)', array(
83 - array(
84 - 'methods' => WP_REST_Server::READABLE,
85 - 'callback' => array( $this, 'get_item' ),
86 - 'permission_callback' => array(
87 - $this,
88 - 'get_item_permissions_check',
89 - ),
90 - ),
84 + array(
85 + 'methods' => WP_REST_Server::READABLE,
86 + 'callback' => array( $this, 'get_item' ),
87 + 'permission_callback' => array(
88 + $this,
89 + 'get_item_permissions_check',
90 + ),
91 + ),
91 92 )
92 93 );
93 94
94 95 register_rest_route(
95 96 $this->namespace, $this->base . '/(?P<id>[\d]+)', array(
96 - array(
97 - 'methods' => WP_REST_Server::EDITABLE,
98 - 'callback' => array( $this, 'update_item' ),
99 - 'permission_callback' => array(
100 - $this,
101 - 'update_item_permissions_check',
102 - ),
103 - ),
97 + array(
98 + 'methods' => WP_REST_Server::EDITABLE,
99 + 'callback' => array( $this, 'update_item' ),
100 + 'permission_callback' => array(
101 + $this,
102 + 'update_item_permissions_check',
103 + ),
104 + ),
104 105 )
105 106 );
106 107
107 108 register_rest_route(
108 109 $this->namespace, $this->base . '/(?P<id>[\d]+)', array(
109 - array(
110 - 'methods' => WP_REST_Server::DELETABLE,
111 - 'callback' => array( $this, 'delete_item' ),
112 - 'permission_callback' => array(
113 - $this,
114 - 'delete_item_permissions_check',
115 - ),
116 - ),
110 + array(
111 + 'methods' => WP_REST_Server::DELETABLE,
112 + 'callback' => array( $this, 'delete_item' ),
113 + 'permission_callback' => array(
114 + $this,
115 + 'delete_item_permissions_check',
116 + ),
117 + ),
117 118 )
118 119 );
119 120
120 121 register_rest_route(
121 122 $this->namespace, $this->base . '/(?P<id>[\d]+)/clone', array(
122 - array(
123 - 'methods' => WP_REST_Server::CREATABLE,
124 - 'callback' => array( $this, 'clone_item' ),
125 - 'permission_callback' => array(
126 - $this,
127 - 'create_item_permissions_check',
128 - ),
129 - ),
123 + array(
124 + 'methods' => WP_REST_Server::CREATABLE,
125 + 'callback' => array( $this, 'clone_item' ),
126 + 'permission_callback' => array(
127 + $this,
128 + 'create_item_permissions_check',
129 + ),
130 + ),
130 131 )
131 132 );
132 133 }
133 134
@@ -149,14 +150,13 @@
149 150 $service = $service->to_array();
150 151
151 152 $team_member_ids = is_array( $service['team_member'] )
152 153 ? array_unique( $service['team_member'] ) : array( $service['team_member'] );
153 - $service['team_member_details'] = $this->team_member_details( $team_member_ids );
154 + $service['team_member_details'] = Service_Helper::team_member_details( $team_member_ids );
154 155 $service['team_member'] = $team_member_ids;
155 156
156 - $category_ids = is_array( $service['categories'] )
157 - ? array_unique( $service['categories'] ) : array( $service['categories'] );
158 - $service['category_details'] = $this->category_details( $category_ids );
157 + $category_ids = $this->get_service_category_ids( $service['id'] );
158 + $service['category_details'] = Service_Helper::category_details( $category_ids );
159 159 $service['categories'] = $category_ids;
160 160
161 161 $schedule_record = ( new Schedule_Record() )
162 162 ->get_schedules( $id, 'service' );
@@ -164,9 +164,9 @@
164 164 : $schedule_record['schedule'];
165 165
166 166 $service['custom'] = $schedule_record['custom'];
167 167 $service['holiday'] = $schedule_record['holiday'];
168 - $service['shortcode'] = '[booktics-service-view id="' . $service['id'] . '"]';
168 + $service['shortcode'] = '[booktics_service_view id="' . $service['id'] . '"]';
169 169 $service = apply_filters( 'booktics_service_format', $service );
170 170
171 171 return $this->response( $service );
172 172 }
@@ -195,8 +195,9 @@
195 195
196 196 $args = array(
197 197 'per_page' => $per_page,
198 198 'paged' => $paged,
199 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Meta query is necessary for filtering services by meta fields
199 200 'meta_query' => array(),
200 201 );
201 202
202 203 if ( ! empty( $request['team_member_id'] ) ) {
@@ -206,16 +207,8 @@
206 207 'compare' => 'LIKE',
207 208 );
208 209 }
209 210
210 - if ( ! empty( $request['category_id'] ) ) {
211 - $args['meta_query'][] = array(
212 - 'key' => 'categories',
213 - 'value' => sprintf( 'i:%d;', intval( $request['category_id'] ) ),
214 - 'compare' => 'LIKE',
215 - );
216 - }
217 -
218 211 if ( ! empty( $request['search'] ) ) {
219 212 $args['s'] = sanitize_text_field( $request['search'] );
220 213 }
221 214
@@ -222,8 +215,30 @@
222 215 if ( ! empty( $args['meta_query'] ) ) {
223 216 $args['meta_query']['relation'] = 'AND';
224 217 }
225 218
219 + $args = apply_filters( 'booktics_service_args', $args, $request );
220 +
221 + // Get service IDs for category BEFORE pagination to ensure correct total count
222 + $service_ids_for_category = null;
223 + if ( ! empty( $request['category_id'] ) ) {
224 + $service_ids_for_category = get_term_meta( absint( $request['category_id'] ), 'booktics_category_services', true );
225 +
226 + // If category filter is applied, add post__in to args to filter BEFORE pagination
227 + if ( ! empty( $service_ids_for_category ) && is_array( $service_ids_for_category ) ) {
228 + $args['post__in'] = $service_ids_for_category;
229 + } elseif ( ! empty( $service_ids_for_category ) ) {
230 + // If category has no services, return early
231 + return $this->response( array(
232 + 'items' => array(),
233 + 'total' => 0,
234 + 'per_page' => $per_page,
235 + 'current_page' => $paged,
236 + 'last_page' => 0,
237 + ) );
238 + }
239 + }
240 +
226 241 $data = Service_Model::paginate( $per_page, $paged, $args );
227 242
228 243 if ( ! $data ) {
229 244 return $this->error( __( 'No service found', 'booktics' ), 404 );
@@ -232,20 +247,20 @@
232 247 if ( ! empty( $data['items'] ) ) {
233 248 $enhanced_items = array();
234 249 foreach ( $data['items'] as $service ) {
235 250 $service_array = $service->to_array();
251 +
236 252 if ( ! empty( $service_array['team_member'] ) ) {
237 253 $team_member_ids = is_array( $service->team_member ) ? array_unique( $service->team_member ) : array( $service->team_member );
238 254 $service->team_member = $team_member_ids;
239 - $service_array['team_member_details'] = $this->team_member_details( $team_member_ids );
255 + $service_array['team_member_details'] = Service_Helper::team_member_details( $team_member_ids );
240 256 }
241 -
242 - if ( ! empty( $service_array['categories'] ) ) {
243 - $category_ids = is_array( $service->categories ) ? array_unique( $service->categories ) : array( $service->categories );
257 + $category_ids = $this->get_service_category_ids( $service_array['id'] );
258 + if ( ! empty( $category_ids ) ) {
244 259 $service->categories = $category_ids;
245 - $service_array['category_details'] = $this->category_details( $category_ids );
260 + $service_array['category_details'] = Service_Helper::category_details( $category_ids );
246 261 }
247 - $service_array['shortcode'] = '[booktics-service-view id="' . $service_array['id'] . '"]';
262 + $service_array['shortcode'] = '[booktics_service_view id="' . $service_array['id'] . '"]';
248 263 $service_array = apply_filters( 'booktics_service_format', $service_array );
249 264 $enhanced_items[] = $service_array;
250 265 }
251 266 $data['items'] = $enhanced_items;
@@ -254,8 +269,39 @@
254 269 return $this->response( $data );
255 270 }
256 271
257 272 /**
273 + * Get all category IDs linked to a given service
274 + *
275 + * @param int $service_id
276 + * @return array
277 + */
278 + private function get_service_category_ids( int $service_id ): array {
279 + $args = array(
280 + 'taxonomy' => 'booktics_service_category', // Category taxonomy
281 + 'hide_empty' => false,
282 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Meta query is necessary for services by category ID
283 + 'meta_query' => array(
284 + array(
285 + 'key' => 'booktics_category_services',
286 + 'value' => sprintf( 'i:%d;', $service_id ),
287 + 'compare' => 'LIKE',
288 + ),
289 + ),
290 + 'fields' => 'ids', // returning only ids
291 + );
292 +
293 + $categories = get_terms( $args );
294 +
295 + if ( is_wp_error( $categories ) || empty( $categories ) ) {
296 + return [];
297 + }
298 +
299 + return $categories;
300 + }
301 +
302 +
303 + /**
258 304 * Check if a given request has access to get items.
259 305 *
260 306 * @param $request
261 307 *
@@ -274,9 +320,8 @@
274 320 * @throws Exception
275 321 */
276 322 public function create_item( $request ) {
277 323 $data = $this->prepare_item_for_database( $request );
278 -
279 324 if ( is_wp_error( $data ) ) {
280 325 return $this->error( $data->get_error_message() );
281 326 }
282 327
@@ -283,15 +328,20 @@
283 328 $service = Service_Model::create( $data );
284 329
285 330 do_action( 'booktics_service_created', $service, $request );
286 331
332 + if ( ! empty( $data['team_member'] ) && is_array( $data['team_member'] ) ) {
333 + $this->update_team_members( $service->id, $data['team_member'] );
334 + $this->remove_service_from_other_team_members( $service->id, $data['team_member'] );
335 + }
336 +
287 337 if ( is_wp_error( $service ) ) {
288 338 return $this->error( $service->get_error_message() );
289 339 }
290 340 $service = $service->to_array();
291 - $service['shortcode'] = '[booktics-service-view id="' . $service['id'] . '"]';
292 - $service['category_details'] = array();
293 - $service['team_member_details'] = array();
341 + $service['shortcode'] = '[booktics_service_view id="' . $service['id'] . '"]';
342 + $service['category_details'] = Service_Helper::category_details( $service['categories'] );
343 + $service['team_member_details'] = Service_Helper::team_member_details( $service['team_member'] );
294 344 $service = apply_filters( 'booktics_service_format', $service );
295 345
296 346 return $this->response( $service, __( 'Successfully created service', 'booktics' ) );
297 347 }
@@ -303,9 +353,9 @@
303 353 *
304 354 * @return WP_Error
305 355 */
306 356 public function create_item_permissions_check( $request ): bool {
307 - return true;
357 + return current_user_can( 'manage_options' );
308 358 }
309 359
310 360 /**
311 361 * Update one item from the collection.
@@ -335,19 +385,60 @@
335 385 return $this->error( $result->get_error_message() );
336 386 }
337 387
338 388 if ( ! empty( $data['team_member'] ) && is_array( $data['team_member'] ) ) {
339 - foreach ( $data['team_member'] as $team_member_id ) {
340 - $team_member_model = ( new Team_Member_Model( $team_member_id ) );
341 - $team_member = $team_member_model->find( $team_member_id );
342 - $team_member_services = $team_member->services == '' ? array() : $team_member->services;
389 + $this->update_team_members( $id, $data['team_member'] );
390 + $this->remove_service_from_other_team_members( $id, $data['team_member'] );
391 + }
343 392
344 - if ( ! in_array( (int) $id, $team_member_services ) ) {
345 - $team_member_services[] = (int) $id;
346 - if ( $team_member ) {
347 - $team_member->update(
393 + $input_data = json_decode( $request->get_body(), true );
394 + $this->update_service_schedule( $id, $input_data );
395 +
396 + do_action( 'booktics_service_updated', $service, $request );
397 +
398 + $response = $this->format_service_response( $id );
399 + return $this->response( $response, __( 'Successfully updated service', 'booktics' ) );
400 + }
401 +
402 + /**
403 + * Update team members for a service
404 + */
405 + private function update_team_members( $service_id, $team_members ) {
406 + foreach ( $team_members as $team_member_id ) {
407 + $team_member_model = ( new Team_Member_Model( $team_member_id ) );
408 + $team_member = $team_member_model->find( $team_member_id );
409 + $team_member_services = $team_member->services == '' ? array() : $team_member->services;
410 +
411 + if ( ! in_array( (int) $service_id, $team_member_services ) ) {
412 + $team_member_services[] = (int) $service_id;
413 + if ( $team_member ) {
414 + $team_member->update(
415 + array(
416 + 'services' => $team_member_services,
417 + )
418 + );
419 + }
420 + }
421 + }
422 + }
423 +
424 + /**
425 + * Remove service from other team members not in the list
426 + */
427 + private function remove_service_from_other_team_members( $service_id, $team_members ) {
428 + $other_team_members = ( new Team_Member_Model() )
429 + ->where( 'services', $service_id, 'LIKE' )
430 + ->all( array() );
431 +
432 + if ( ! empty( $other_team_members['items'] ) ) {
433 + foreach ( $other_team_members['items'] as $other_team_member ) {
434 + if ( ! in_array( $other_team_member['id'], $team_members ) ) {
435 + $other_services = $other_team_member['services'];
436 + if ( ( $key = array_search( $service_id, $other_services ) ) !== false ) {
437 + unset( $other_services[ $key ] );
438 + ( new Team_Member_Model( $other_team_member['id'] ) )->update(
348 439 array(
349 - 'services' => $team_member_services,
440 + 'services' => array_values( $other_services ),
350 441 )
351 442 );
352 443 }
353 444 }
@@ -352,28 +443,33 @@
352 443 }
353 444 }
354 445 }
355 446 }
447 + }
356 448
357 - $input_data = json_decode( $request->get_body(), true );
449 + /**
450 + * Update the service schedule if provided
451 + */
452 + private function update_service_schedule( $service_id, $input_data ) {
358 453 if ( isset( $input_data['schedule'] ) || isset( $input_data['custom'] ) || isset( $input_data['holiday'] ) ) {
359 454 $service_schedule = Schedule_Manager::make( $input_data );
360 - $service_schedule->with_service_id( $request['id'] );
455 + $service_schedule->with_service_id( $service_id );
361 456 $service_schedule->save();
362 457 }
458 + }
363 459
364 - do_action( 'booktics_service_updated', $service, $request );
365 -
366 - $response = Service_Model::find( $id )->to_array();
367 - $response['shortcode'] = '[booktics-service-view id="' . $response['id'] . '"]';
368 - $response['team_member_details'] = $this->team_member_details( $response['team_member'] );
460 + /**
461 + * Format the service response after update
462 + */
463 + private function format_service_response( $service_id ) {
464 + $response = Service_Model::find( $service_id )->to_array();
465 + $response['shortcode'] = '[booktics_service_view id="' . $response['id'] . '"]';
466 + $response['team_member_details'] = Service_Helper::team_member_details( $response['team_member'] );
369 467 if ( ! empty( $response['categories'] ) ) {
370 468 $category_ids = is_array( $response['categories'] ) ? $response['categories'] : array( $response['categories'] );
371 - $response['category_details'] = $this->category_details( $category_ids );
469 + $response['category_details'] = Service_Helper::category_details( $category_ids );
372 470 }
373 - $response = apply_filters( 'booktics_service_format', $response );
374 -
375 - return $this->response( $response, __( 'Successfully updated service', 'booktics' ) );
471 + return apply_filters( 'booktics_service_format', $response );
376 472 }
377 473
378 474 /**
379 475 * Check if a given request has access to update a specific item.
@@ -382,9 +478,9 @@
382 478 *
383 479 * @return WP_Error
384 480 */
385 481 public function update_item_permissions_check( $request ) {
386 - return true;
482 + return current_user_can( 'manage_options' );
387 483 }
388 484
389 485 /**
390 486 * Delete one item from the collection.
@@ -407,9 +503,9 @@
407 503 if ( is_wp_error( $deleted ) ) {
408 504 return $this->error( $deleted->get_error_message() );
409 505 }
410 506
411 - return $this->response( (array) $service, __( 'Successfully deleted service', 'booktics' ) );
507 + return $this->response( $service, __( 'Successfully deleted service', 'booktics' ) );
412 508 }
413 509
414 510 /**
415 511 * Check if a given request has access to delete a specific item.
@@ -429,9 +525,9 @@
429 525 *
430 526 * @return WP_HTTP_Response
431 527 */
432 528 public function delete_items( $request ) {
433 - $ids = $request['ids'];
529 + $ids = isset( $request['ids'] ) ? $request['ids'] : array();
434 530
435 531 if ( ! is_array( $ids ) ) {
436 532 return $this->error( __( 'Ids should be an array of items ids', 'booktics' ) );
437 533 }
@@ -447,14 +543,14 @@
447 543 ++$count;
448 544 }
449 545 }
450 546
451 - if ( $count === 0 ) {
547 + if ( 0 === $count ) {
452 548 return $this->error( __( 'No item deleted.', 'booktics' ) );
453 549 }
550 + /* translators: 1: deleted count, 2: total count */
551 + $message = sprintf( __( 'Deleted %1$d items of %2$d', 'booktics' ), $count, $total );
454 552
455 - $message = sprintf( 'Deleted %d items of %d', $count, $total );
456 -
457 553 return $this->response( array(), $message );
458 554 }
459 555
460 556 /**
@@ -478,11 +574,11 @@
478 574 public function prepare_item_for_database( $request ) {
479 575 $data = json_decode( $request->get_body(), true );
480 576 $validate = booktics_validate(
481 577 $data, array(
482 - 'title' => array(
483 - 'required',
484 - ),
578 + 'title' => array(
579 + 'required',
580 + ),
485 581 )
486 582 );
487 583
488 584 if ( is_wp_error( $validate ) ) {
@@ -487,8 +583,19 @@
487 583
488 584 if ( is_wp_error( $validate ) ) {
489 585 return $validate;
490 586 }
587 + if ( empty( $data['team_member'] ) ) {
588 + $admin_query = new \WP_User_Query(
589 + array(
590 + 'role' => array( 'administrator', 'booktics_team_member' ),
591 + )
592 + );
593 + $admins = $admin_query->get_results();
594 + $admin = reset( $admins );
595 + $team_member_id = $admin->id;
596 + $data['team_member'] = array( $team_member_id );
597 + }
491 598
492 599 $data['title'] = ! empty( $data['title'] ) ? sanitize_text_field( $data['title'] ) : '';
493 600 $data['description'] = ! empty( $data['description'] ) ? sanitize_text_field( $data['description'] ) : '';
494 601 $data['content'] = ! empty( $data['content'] ) ? sanitize_text_field( $data['content'] ) : '';
@@ -494,10 +601,12 @@
494 601 $data['content'] = ! empty( $data['content'] ) ? sanitize_text_field( $data['content'] ) : '';
495 602 $data['link'] = ! empty( $data['link'] ) ? sanitize_text_field( $data['link'] ) : '';
496 603 $data['image'] = ! empty( $data['image'] ) ? esc_url_raw( $data['image'] ) : '';
497 604 $data['image_id'] = ! empty( $data['image_id'] ) ? esc_url_raw( $data['image_id'] ) : '';
498 - $data['interval_time'] = ! empty( $data['interval_time'] ) ? sanitize_text_field( $data['interval_time'] ) : '';
499 - $data['before_buffer_time'] = ! empty( $data['before_buffer_time'] ) ? sanitize_text_field( $data['before_buffer_time'] ) : '';
605 + $data['interval_time'] = ! empty( $data['interval_time'] ) ? sanitize_text_field( $data['interval_time'] ) : 0;
606 + $data['before_buffer_time'] = ! empty( $data['before_buffer_time'] ) ? sanitize_text_field( $data['before_buffer_time'] ) : 0;
607 + $data['after_buffer_time'] = ! empty( $data['after_buffer_time'] ) ? sanitize_text_field( $data['after_buffer_time'] ) : 0;
608 + $data['show_end_time'] = ! empty( $data['show_end_time'] ) ? sanitize_text_field( $data['show_end_time'] ) : false;
500 609 $data['status'] = ! empty( $data['status'] ) ? sanitize_text_field( $data['status'] ) : 'deactive';
501 610 $data['team_member'] = empty( $data['team_member'] ) ? array() : array_unique( $data['team_member'] );
502 611 $data['categories'] = empty( $data['categories'] ) ? array() : array_unique( $data['categories'] );
503 612 $sanitized_durations = array();
@@ -506,9 +615,9 @@
506 615 if ( is_array( $duration ) ) {
507 616 $sanitized_durations[] = array(
508 617 'id' => ! empty( $duration['id'] ) ? sanitize_text_field( $duration['id'] ) : '',
509 618 'name' => ! empty( $duration['name'] ) ? sanitize_text_field( $duration['name'] ) : '',
510 - 'duration_time' => ! empty( $duration['duration_time'] ) ? sanitize_text_field( $duration['duration_time'] ) : '',
619 + 'duration_time' => ! empty( $duration['duration_time'] ) ? sanitize_text_field( $duration['duration_time'] ) : 0,
511 620 'duration_unit' => ! empty( $duration['duration_unit'] ) ? sanitize_text_field( $duration['duration_unit'] ) : '',
512 621 'charge_amount' => ! empty( $duration['charge_amount'] ) ? (float) number_format( (float) $duration['charge_amount'], 4, '.', '' ) : '0.0000',
513 622 'deposit_amount' => ! empty( $duration['deposit_amount'] ) ? (float) number_format( (float) $duration['deposit_amount'], 4, '.', '' ) : '0.0000',
514 623 );
@@ -513,8 +622,19 @@
513 622 'deposit_amount' => ! empty( $duration['deposit_amount'] ) ? (float) number_format( (float) $duration['deposit_amount'], 4, '.', '' ) : '0.0000',
514 623 );
515 624 }
516 625 }
626 + } else {
627 + $sanitized_durations = array(
628 + array(
629 + 'id' => 'default',
630 + 'name' => 'default',
631 + 'duration_time' => 30,
632 + 'duration_unit' => 'min',
633 + 'charge_amount' => 0,
634 + 'deposit_amount' => 0,
635 + ),
636 + );
517 637 }
518 638 $data['additional_durations'] = $sanitized_durations;
519 639 $data = apply_filters( 'booktics_prepare_service_custom_fields', $data );
520 640 $image_url = $request->get_param( 'image' );
@@ -540,31 +660,30 @@
540 660
541 661 if ( ! $service ) {
542 662 return $this->error( __( 'Service not found', 'booktics' ), 404 );
543 663 }
664 + $clone_data = [
665 + 'title' => $service->title . __( ' Copy', 'booktics' ),
666 + 'description' => $service->description,
667 + 'content' => $service->content,
668 + 'image' => $service->image,
669 + 'image_id' => $service->image_id,
670 + 'categories' => $service->categories,
671 + 'interval_time' => $service->interval_time,
672 + 'before_buffer_time' => $service->before_buffer_time,
673 + 'after_buffer_time' => $service->after_buffer_time,
674 + 'team_member' => $service->team_member,
675 + 'show_end_time' => $service->show_end_time,
676 + 'additional_durations' => $service->additional_durations,
677 + 'enable_custom_holiday' => $service->enable_custom_holiday,
678 + 'enable_custom_schedule' => $service->enable_custom_schedule,
679 + 'enable_additional_service_duration' => $service->enable_additional_service_duration,
680 + ];
544 681
545 - $cloned = Service_Model::create(
546 - array(
547 - 'title' => $service->title . __( ' Copy', 'booktics' ),
548 - 'description' => $service->description,
549 - 'content' => $service->content,
550 - 'image' => $service->image,
551 - 'image_id' => $service->image_id,
552 - 'categories' => $service->categories,
553 - 'interval_time' => $service->interval_time,
554 - 'before_buffer_time' => $service->before_buffer_time,
555 - 'after_buffer_time' => $service->after_buffer_time,
556 - 'team_member' => $service->team_member,
557 - 'show_end_time' => $service->show_end_time,
558 - 'additional_durations' => $service->additional_durations,
559 - 'enable_custom_holiday' => $service->enable_custom_holiday,
560 - 'enable_custom_schedule' => $service->enable_custom_schedule,
561 - 'enable_additional_service_duration' => $service->enable_additional_service_duration,
562 - 'custom_field' => $service->custom_field,
563 - 'extra_services' => $service->extra_services,
564 - )
565 - );
682 + $clone_data = apply_filters( 'booktics_clone_service_data', $clone_data, $service );
566 683
684 + $cloned = Service_Model::create( $clone_data );
685 +
567 686 if ( is_wp_error( $cloned ) ) {
568 687 return $this->error( $cloned->get_error_message() );
569 688 }
570 689
@@ -577,11 +696,12 @@
577 696 $service_schedule = Schedule_Manager::make( $schedule_data );
578 697 $service_schedule->with_service_id( $cloned->id );
579 698 $service_schedule->save();
580 699
581 - $team_member_details = $this->team_member_details( $service->team_member );
700 + $team_member_details = Service_Helper::team_member_details( $service->team_member );
582 701 $cloned = $cloned->to_array();
583 702 $cloned['team_member_details'] = $team_member_details;
703 + $cloned['category_details'] = Service_Helper::category_details( $cloned['categories'] );
584 704
585 705 $clone_schedule_record = ( new Schedule_Record() )
586 706 ->get_schedules( $cloned['id'], 'service' );
587 707 $cloned['schedule'] = empty( $clone_schedule_record['schedule'] ) ? (object) array()
@@ -587,58 +707,10 @@
587 707 $cloned['schedule'] = empty( $clone_schedule_record['schedule'] ) ? (object) array()
588 708 : $clone_schedule_record['schedule'];
589 709 $cloned['custom'] = $clone_schedule_record['custom'];
590 710 $cloned['holiday'] = $clone_schedule_record['holiday'];
711 + $cloned['shortcode'] = '[booktics_service_view id="' . $cloned['id'] . '"]';
591 712 $cloned = apply_filters( 'booktics_service_format', $cloned );
592 713
593 714 return $this->response( $cloned, __( 'Successfully cloned service', 'booktics' ) );
594 - }
595 -
596 - /**
597 - * Map team member details
598 - *
599 - * @param $team_member_ids
600 - *
601 - * @return array
602 - */
603 - private function team_member_details( $team_member_ids ): array {
604 - $team_member_details = array();
605 - foreach ( $team_member_ids as $team_member_id ) {
606 - $team_member = ( new Team_Member_Model() )->find( $team_member_id );
607 - if ( $team_member ) {
608 - $team_member = $team_member->to_array();
609 - $team_member_details[] = array(
610 - 'id' => $team_member['id'],
611 - 'display_name' => $team_member['display_name'],
612 - 'email' => $team_member['email'],
613 - 'image' => $team_member['image'],
614 - );
615 - }
616 - }
617 -
618 - return $team_member_details;
619 - }
620 -
621 - /**
622 - * Get category details for given category IDs.
623 - *
624 - * @param array|int[] $category_ids
625 - *
626 - * @return array
627 - */
628 - private function category_details( $category_ids ): array {
629 - $category_details = array();
630 - foreach ( $category_ids as $category_id ) {
631 - $category = get_term( $category_id, ( new Category() )->get_name() );
632 -
633 - if ( $category ) {
634 - $category = $category->to_array();
635 - $category_details[] = array(
636 - 'id' => $category['term_id'],
637 - 'name' => $category['name'],
638 - );
639 - }
640 - }
641 -
642 - return $category_details;
643 715 }
644 716 }