PluginProbe
Booking Calendar / 11.8.3
Booking Calendar v11.8.3
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 / save-user-meta / save-user-meta.php

save-user-meta.php in Booking Calendar 11.8.3, at includes/save-user-meta/save-user-meta.php

269 lines 10.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @version 1.0
4 * @package Booking Calendar
5 * @subpackage User_Custom_Data_Saver
6 * @category Functions
7 * @author wpdevelop
8 * @link https://wpbookingcalendar.com/
9 * @email info@wpbookingcalendar.com
10 * @modified 2025-06-25
11 */
12
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit; // Exit if accessed directly.
15 }
16
17 class WPBC_User_Custom_Data_Saver {
18
19 private static $ajax_action = 'AJAX_SAVE_USER_META_DATA';
20 private static $user_option_prefix = 'booking_custom_';
21
22 /**
23 * Init hooks
24 */
25 public static function init() {
26 add_action( 'init', array( __CLASS__, 'register_ajax_handler' ) );
27 add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueue_scripts' ) );
28 }
29
30 /**
31 * Register AJAX handler
32 */
33 public static function register_ajax_handler() {
34 add_action( 'wp_ajax_' . self::$ajax_action, array( __CLASS__, 'handle_ajax_save' ) );
35 }
36
37 /**
38 * Enqueue JavaScript file and pass AJAX URL
39 */
40 public static function enqueue_scripts() {
41
42 $js_url = function_exists( 'wpbc_plugin_url' ) ? wpbc_plugin_url( '/includes/save-user-meta/_out/save-user-meta.js' ) : plugins_url( '_out/user-data-saver.js', WPBC_FILE );
43
44 wp_register_script( 'wpbc-user-data-saver', $js_url, array( 'jquery' ), '1.1', true );
45 wp_enqueue_script( 'wpbc-user-data-saver' );
46
47 wp_localize_script( 'wpbc-user-data-saver', 'WPBC_UserDataSaver', array(
48 'ajax_url' => admin_url( 'admin-ajax.php' ),
49 'action' => self::$ajax_action,
50 ) );
51 }
52
53 /**
54 * Create nonce
55 */
56 public static function create_nonce( $action_name ) {
57 return wp_create_nonce( $action_name );
58 }
59
60 /**
61 * Render a save button or div with onclick and data attributes
62 */
63 public static function render_save_button( $args = array() ) {
64 $defaults = array(
65 'label' => __( 'Save', 'booking' ),
66 'data_name' => 'custom_data_block',
67 'nonce_action' => 'wpbc_custom_data_nonce',
68 'user_id' => get_current_user_id(),
69 'element' => 'div',
70 'id' => '',
71 'class' => 'wpbc-save-button button button-primary',
72 'data_fields' => array(),
73 );
74 $args = wp_parse_args( $args, $defaults );
75
76 $tag = $args['element'];
77 $id_attr = $args['id'] ? ' id="' . esc_attr( $args['id'] ) . '"' : '';
78 $nonce = self::create_nonce( $args['nonce_action'] );
79 $selectors = implode( ',', $args['data_fields'] );
80 $onclick = 'wpbc_save_custom_user_data_from_element(this);';
81
82 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
83 echo '<' . $tag . $id_attr . ' class="' . esc_attr( $args['class'] ) . '"' . ' data-wpbc-u-save-name="' . esc_attr( $args['data_name'] ) . '"' . ' data-wpbc-u-save-nonce="' . esc_attr( $nonce ) . '"' . ' data-wpbc-u-save-user-id="' . esc_attr( $args['user_id'] ) . '"' . ' data-wpbc-u-save-action="' . esc_attr( $args['nonce_action'] ) . '"' . ' data-wpbc-u-save-fields="' . esc_attr( $selectors ) . '"' . ' onclick="' . esc_attr( $onclick ) . '"' . '>' . esc_html( $args['label'] ) . '</' . $tag . '>';
84 }
85
86 /**
87 * AJAX handler
88 */
89 public static function handle_ajax_save() {
90 $user_id = isset( $_POST['user_id'] ) ? intval( $_POST['user_id'] ) : 0;
91 $data_name = isset( $_POST['data_name'] ) ? sanitize_key( wp_unslash( $_POST['data_name'] ) ) : '';
92 $data_raw = isset( $_POST['data_value'] ) ? wp_unslash( $_POST['data_value'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
93 $nonce_name = isset( $_POST['nonce_action'] ) ? sanitize_key( wp_unslash( $_POST['nonce_action'] ) ) : '';
94 $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
95
96 if ( empty( $nonce_name ) || ! wp_verify_nonce( $nonce, $nonce_name ) ) {
97 wp_send_json_error( array( 'message' => 'Invalid nonce.' ) );
98 }
99
100 if ( empty( $user_id ) || empty( $data_name ) || empty( $data_raw ) ) {
101 wp_send_json_error( array( 'message' => 'Missing required parameters.' ) );
102 }
103 // FixIn: 10.14.15.2.
104 if ( wpbc_get_current_user_id() !== $user_id ) {
105 wp_send_json_error( array( 'message' => 'Unauthorized: You can only modify your own settings.' ) );
106 }
107 parse_str( $data_raw, $parsed_data );
108
109 $sanitized_data = array();
110 foreach ( $parsed_data as $key => $val ) {
111
112 // $key = sanitize_key( $key ); // This strips square brackets and digits for complex input keys (like rows[0][title]) //.
113
114 $key = preg_replace( '/[^a-zA-Z0-9_\[\]]/', '', $key ); // This preserves structure like rows[0][title] (important for array-style inputs), but still sanitizes.
115
116 $sanitized_data[ $key ] = is_array( $val ) ? array_map( 'sanitize_text_field', $val )
117 : sanitize_text_field( $val );
118 }
119
120 $option_name = self::$user_option_prefix . $data_name;
121 update_user_option( $user_id, $option_name, $sanitized_data );
122
123 $stored_data = get_user_option( $option_name, $user_id );
124 if ( ! is_array( $stored_data ) || $sanitized_data !== $stored_data ) {
125 wp_send_json_error( array( 'message' => 'The setting could not be saved. Please reload the page and try again.' ) );
126 }
127
128 /**
129 * Fires after Booking Calendar user data has been stored and verified.
130 *
131 * @param int $user_id Current WordPress user ID.
132 * @param string $data_name Sanitized Booking Calendar preference name.
133 * @param array $sanitized_data Sanitized value confirmed in user metadata.
134 */
135 do_action( 'wpbc_user_custom_data_saved', $user_id, $data_name, $sanitized_data );
136
137 wp_send_json_success( array( 'message' => 'Settings saved successfully.' ) );
138 }
139
140 /**
141 * Get saved data
142 *
143 * Usage for simple values:
144 *
145 * $is_full_screen = WPBC_User_Custom_Data_Saver::get_user_data_value( wpbc_get_current_user_id(), $user_cust_option );
146 * $is_full_screen= ( isset( $is_full_screen_data['value'] ) && $is_full_screen_data['value'] === 'On' );
147 */
148 public static function get_user_data( $user_id, $data_name ) {
149 $option_key = self::$user_option_prefix . sanitize_key( $data_name );
150 $data = get_user_option( $option_key, $user_id );
151
152 return is_array( $data ) ? $data : array();
153 }
154
155 /**
156 * Get simple saved value.
157 *
158 * @param $user_id
159 * @param $data_name
160 * @param $key
161 *
162 * @return mixed|string
163 */
164 public static function get_user_data_value( $user_id, $data_name, $key = 'value' ) {
165 $data = self::get_user_data( $user_id, $data_name );
166
167 return isset( $data[ $key ] ) ? $data[ $key ] : '';
168 }
169 }
170
171 // Register loading JavaScript and Ajax handlers. In initi used other init hooks, that is why we use 'plugins_loaded'.
172 add_action( 'plugins_loaded', array( 'WPBC_User_Custom_Data_Saver', 'init' ) );
173
174 /*
175 if ( 0 ) {
176
177 ?>
178 Example #1:
179 <input type="text" id="my_setting" value="Hello"/>
180 <?php
181 WPBC_User_Custom_Data_Saver::render_save_button( array(
182 'label' => 'Save Setting',
183 'data_name' => 'my_text_value',
184 'nonce_action' => 'wpbc_text_value_nonce',
185 'id' => 'wpbc_save_text_btn',
186 'data_fields' => array( '#my_setting' ),
187 ) );
188 ?>
189
190 Example #2:
191 <input type="text" name="rows[0][title]" id="row_0_title" value="Title 1"/>
192 <input type="text" name="rows[0][value]" id="row_0_value" value="100"/>
193 <input type="text" name="rows[1][title]" id="row_1_title" value="Title 2"/>
194 <input type="text" name="rows[1][value]" id="row_1_value" value="200"/>
195 <?php
196 WPBC_User_Custom_Data_Saver::render_save_button( array(
197 'label' => 'Save Table Rows',
198 'data_name' => 'my_object_array',
199 'nonce_action' => 'wpbc_object_array_nonce',
200 'id' => 'wpbc_save_array_btn',
201 'data_fields' => array( '#row_0_title', '#row_0_value', '#row_1_title', '#row_1_value' ),
202 ) );
203 ?>
204
205 Example #3:
206 <?php
207 $nonce_action = 'wpbc_manual_example_nonce';
208 ?>
209 <input type="text" id="custom_note" value="My note"/>
210 <div class="button button-primary"
211 onclick="wpbc_save_custom_user_data_from_element(this)"
212 data-wpbc-u-save-name="user_note"
213 data-wpbc-u-save-nonce="<?php echo esc_attr( wp_create_nonce( $nonce_action ) ); ?>"
214 data-wpbc-u-save-user-id="<?php echo esc_attr( get_current_user_id() ); ?>"
215 data-wpbc-u-save-action="<?php echo esc_attr( $nonce_action ); ?>"
216 data-wpbc-u-save-fields="#custom_note">
217 Save Note
218 </div>
219
220 Example #4:
221 <?php
222 $nonce_action = 'wpbc_array_rows_nonce';
223 ?>
224 <input type="text" name="rows[0][title]" id="row_0_title" value="Title 1"/>
225 <input type="text" name="rows[0][value]" id="row_0_value" value="100"/>
226 <input type="text" name="rows[1][title]" id="row_1_title" value="Title 2"/>
227 <input type="text" name="rows[1][value]" id="row_1_value" value="200"/>
228 <a href="javascript:void(0);"
229 class="button button-primary"
230 onclick="wpbc_save_custom_user_data_from_element(this)"
231 data-wpbc-u-save-name="object_array_example"
232 data-wpbc-u-save-nonce="<?php echo esc_attr( wp_create_nonce( $nonce_action ) ); ?>"
233 data-wpbc-u-save-user-id="<?php echo esc_attr( get_current_user_id() ); ?>"
234 data-wpbc-u-save-action="<?php echo esc_attr( $nonce_action ); ?>"
235 data-wpbc-u-save-fields="#row_0_title,#row_0_value,#row_1_title,#row_1_value">
236 Save Rows
237 </a>
238
239 Example #5:
240 <?php $nonce_action = 'wpbc_simple_value_nonce'; ?>
241 <a href="javascript:void(0);"
242 class="button button-primary"
243 onclick="wpbc_save_custom_user_data_from_element(this)"
244 data-wpbc-u-save-name="simple_note"
245 data-wpbc-u-save-value="My saved string value"
246 data-wpbc-u-save-nonce="<?php echo esc_attr( wp_create_nonce( $nonce_action ) ); ?>"
247 data-wpbc-u-save-user-id="<?php echo esc_attr( get_current_user_id() ); ?>"
248 data-wpbc-u-save-action="<?php echo esc_attr( $nonce_action ); ?>"
249 >
250 Save Simple Note
251 </a>
252
253 Example #6:
254 <?php $nonce_action = 'wpbc_simple_value_nonce'; ?>
255 <a href="javascript:void(0);"
256 class="button button-primary"
257 onclick="wpbc_save_custom_user_data_from_element(this)"
258 data-wpbc-u-save-name="simple_note"
259 data-wpbc-u-save-value-json='{"title":"Hello","value":42}'
260 data-wpbc-u-save-nonce="<?php echo esc_attr( wp_create_nonce( $nonce_action ) ); ?>"
261 data-wpbc-u-save-user-id="<?php echo esc_attr( get_current_user_id() ); ?>"
262 data-wpbc-u-save-action="<?php echo esc_attr( $nonce_action ); ?>"
263 >
264 Save Simple Note
265 </a>
266 <?php
267 }
268 */
269