PluginProbe
Booktics – Appointment Booking Calendar for Service Businesses / 1.0.28
Booktics – Appointment Booking Calendar for Service Businesses v1.0.28
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
booktics / core / cart / cart-session.php

cart-session.php in Booktics – Appointment Booking Calendar for Service Businesses 1.0.28, at core/cart/cart-session.php

222 lines 6.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Booktics\Cart;
4
5 /**
6 * Class Cart_Session
7 * Handles cart session management for the Booktics plugin
8 *
9 * @package Booktics\Cart
10 */
11 class Cart_Session {
12
13 /**
14 * Session key used to store cart data in a PHP session
15 *
16 * @var string
17 */
18 const SESSION_KEY = 'booktics_cart';
19
20 /**
21 * Start a PHP session when one is not running yet.
22 *
23 * Sessions are started lazily instead of on every request so that a session
24 * is never opened after output has already been flushed, which triggers a
25 * "Session cannot be started after headers have already been sent" warning.
26 *
27 * @return bool True when $_SESSION is usable.
28 */
29 private static function maybe_start_session(): bool {
30 if ( PHP_SESSION_ACTIVE === session_status() ) {
31 return true;
32 }
33
34 if ( PHP_SESSION_DISABLED === session_status() ) {
35 return false;
36 }
37
38 if ( headers_sent() || ( defined( 'WP_CLI' ) && WP_CLI ) ) {
39 return false;
40 }
41
42 return session_start();
43 }
44
45 /**
46 * Get an empty cart structure
47 *
48 * @return array{items: array, total: float, coupon: string}
49 */
50 private static function empty_cart(): array {
51 return array(
52 'items' => array(),
53 'total' => 0.00,
54 'coupon' => '',
55 );
56 }
57
58 /**
59 * Get cart data from session
60 *
61 * @return array{items: array, total: float}
62 */
63 public static function get() {
64 if ( ! self::maybe_start_session() ) {
65 return self::empty_cart();
66 }
67
68 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized via sanitize_session_data() on next line.
69 $raw_data = ! empty( $_SESSION[ self::SESSION_KEY ] ) ? wp_unslash( $_SESSION[ self::SESSION_KEY ] ) : null;
70 $session_data = self::sanitize_session_data( $raw_data );
71
72 if ( ! is_array( $session_data ) ) {
73 return self::empty_cart();
74 }
75
76 return $session_data;
77 }
78
79 /**
80 * Sanitize raw cart session data
81 *
82 * @param mixed $data Raw data retrieved from the session.
83 *
84 * @return mixed Sanitized array or null if input is not an array.
85 */
86 private static function sanitize_session_data( $data ) {
87 if ( ! is_array( $data ) ) {
88 return null;
89 }
90
91 $sanitized_items = array();
92
93 if ( ! empty( $data['items'] ) && is_array( $data['items'] ) ) {
94 foreach ( $data['items'] as $item ) {
95 if ( ! is_array( $item ) ) {
96 continue;
97 }
98
99 $sanitized_item = array(
100 'uuid' => sanitize_text_field( $item['uuid'] ?? '' ),
101 'service_id' => absint( $item['service_id'] ?? 0 ),
102 'team_member_id' => absint( $item['team_member_id'] ?? 0 ),
103 'date' => sanitize_text_field( $item['date'] ?? '' ),
104 'start_time' => sanitize_text_field( $item['start_time'] ?? '' ),
105 'end_time' => sanitize_text_field( $item['end_time'] ?? '' ),
106 'price' => floatval( $item['price'] ?? 0 ),
107 'subtotal' => floatval( $item['subtotal'] ?? 0 ),
108 'total' => floatval( $item['total'] ?? 0 ),
109 );
110
111 $sanitized_item = apply_filters( 'booktics_pro_sanitize_cart_item', $sanitized_item, $item );
112
113 $sanitized_items[] = $sanitized_item;
114 }
115 }
116
117 return array(
118 'items' => $sanitized_items,
119 'total' => floatval( $data['total'] ?? 0.00 ),
120 'coupon' => sanitize_text_field( $data['coupon'] ?? '' ),
121 );
122 }
123
124 /**
125 * Set cart data in session
126 *
127 * @param array $cart Cart data to store in session
128 *
129 * @return void
130 */
131 public static function set( array $cart ) {
132 if ( ! self::maybe_start_session() ) {
133 return;
134 }
135
136 $_SESSION[ self::SESSION_KEY ] = $cart;
137 }
138
139 /**
140 * Clear cart data from session
141 *
142 * @return void
143 */
144 public static function clear() {
145 if ( ! self::maybe_start_session() ) {
146 return;
147 }
148
149 unset( $_SESSION[ self::SESSION_KEY ] );
150 }
151
152 /**
153 * Add an item to the cart session
154 *
155 * @param array $item
156 *
157 * @return array
158 */
159 public static function add_item( array $item ): array {
160 $cart = self::get();
161 $cart['items'][] = $item;
162 $cart['total'] = floatval( $cart['total'] ?? 0 ) + floatval( $item['subtotal'] ?? $item['price'] ?? 0 );
163 $cart = apply_filters( 'booktics_pro_cart_session', $cart );
164
165 self::set( $cart );
166
167 return end( $cart['items'] );
168 }
169
170 /**
171 * Delete an item from the cart session
172 *
173 * @param string $id
174 *
175 * @return void
176 */
177 public static function delete_item( string $id ) {
178 $cart = self::get();
179 $cart['items'] = array_values(
180 array_filter(
181 $cart['items'],
182 function ( $item ) use ( $id ) {
183 return $item['uuid'] != $id;
184 }
185 )
186 );
187 $cart['total'] = array_reduce(
188 $cart['items'], function ( $total, $item ) {
189 return $total + $item['price'];
190 }, 0.00
191 );
192
193 self::set( $cart );
194 }
195
196 /**
197 * Edit an item in the cart session
198 *
199 * @param string $uuid UUID of the item to edit
200 * @param array $new_data New data to update the item with
201 *
202 * @return void
203 */
204 public static function edit_item( string $uuid, array $new_data ) {
205 $cart = self::get();
206 $cart['total'] = 0;
207
208 $cart['items'] = array_map(
209 function ( $item ) use ( $uuid, $new_data, &$cart ) {
210 if ( $item['uuid'] === $uuid ) {
211 $item = array_merge( $item, $new_data );
212 }
213 $cart['total'] += floatval( $item['subtotal'] ?? $item['price'] ?? 0 );
214
215 return $item;
216 }, $cart['items']
217 );
218 $cart = apply_filters( 'booktics_pro_cart_session', $cart );
219 self::set( $cart );
220 }
221 }
222