PluginProbe
Booking Calendar / 11.9
Booking Calendar v11.9
11.9 11.8.4 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 All 205 releases
booking / includes / page-setup-wizard / step-appearance / class-wpbc-setup-wizard-appearance-save-handler.php

class-wpbc-setup-wizard-appearance-save-handler.php in Booking Calendar 11.9, at includes/page-setup-wizard/step-appearance/class-wpbc-setup-wizard-appearance-save-handler.php

162 lines 6.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Progressive save handler for Setup Wizard Appearance settings.
4 *
5 * @package Booking Calendar
6 */
7
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit;
10 }
11
12 /**
13 * Persist the validated Guided appointment appearance through canonical options.
14 */
15 final class WPBC_Setup_Wizard_Appearance_Save_Handler implements WPBC_Setup_Wizard_Step_Save_Handler {
16
17 /** @var WPBC_Setup_Wizard_Appearance */
18 private $appearance;
19
20 /**
21 * Build the handler around the Appearance validator.
22 *
23 * @param WPBC_Setup_Wizard_Appearance|null $appearance Optional domain service for tests.
24 */
25 public function __construct( $appearance = null ) {
26 $this->appearance = $appearance instanceof WPBC_Setup_Wizard_Appearance
27 ? $appearance
28 : new WPBC_Setup_Wizard_Appearance();
29 }
30
31 /**
32 * Return the owned step identifier.
33 *
34 * @return string Stable step ID.
35 */
36 public function get_step_id() {
37 return 'appearance';
38 }
39
40 /**
41 * Return the ordinary scalar-setting action label.
42 *
43 * @param array<string,mixed> $checkpoint Current checkpoint.
44 * @param array<string,mixed> $step_context Authorized presentation context.
45 *
46 * @return string Translated action label.
47 */
48 public function get_primary_action_label( array $checkpoint, array $step_context = array() ) {
49 unset( $checkpoint, $step_context );
50
51 return __( 'Save & continue', 'booking' );
52 }
53
54 /**
55 * Revalidate, save, verify, and compensate the canonical Appearance options.
56 *
57 * @param array<string,mixed> $validated_fields Validated current-step fields.
58 * @param array<string,mixed> $checkpoint Current checkpoint.
59 * @param array<string,mixed> $operation_context Stable operation metadata.
60 *
61 * @return array<string,mixed>|WP_Error Verified result or error.
62 */
63 public function save( array $validated_fields, array $checkpoint, array $operation_context ) {
64 unset( $operation_context );
65
66 if ( ! WPBC_Setup_Wizard_Customer_Journey_Policy::uses_booking_form_and_appearance_route( $this->get_customer_journey_id( $checkpoint ) ) ) {
67 return new WP_Error( 'wpbc_setup_wizard_appearance_journey_invalid', __( 'Appearance cannot be saved for the selected customer journey.', 'booking' ) );
68 }
69 $manage_capability = function_exists( 'wpbc_bfb_get_manage_cap' ) ? wpbc_bfb_get_manage_cap() : 'manage_options';
70 if ( ! current_user_can( $manage_capability ) || ! function_exists( 'get_bk_option' ) || ! function_exists( 'update_bk_option' ) || ! function_exists( 'delete_bk_option' ) ) {
71 return new WP_Error( 'wpbc_setup_wizard_appearance_forbidden', __( 'You are not allowed to update Booking Calendar appearance settings.', 'booking' ) );
72 }
73
74 $configuration = $this->appearance->get_preview_configuration( $validated_fields );
75 if ( is_wp_error( $configuration ) ) {
76 return $configuration;
77 }
78
79 $desired_options = array_merge( $configuration['form_style'], $configuration['option_overrides'] );
80 $before_options = array();
81 $missing_marker = array( 'wpbc_setup_wizard_missing_option' => function_exists( 'wp_generate_uuid4' ) ? wp_generate_uuid4() : uniqid( 'wpbc_', true ) );
82 foreach ( array_keys( $desired_options ) as $option_name ) {
83 $before_value = get_bk_option( $option_name, $missing_marker );
84 $before_options[ $option_name ] = array(
85 'exists' => $missing_marker !== $before_value,
86 'value' => $before_value,
87 );
88 }
89
90 foreach ( $desired_options as $option_name => $option_value ) {
91 update_bk_option( $option_name, $option_value );
92 }
93
94 $verified_options = array();
95 foreach ( $desired_options as $option_name => $option_value ) {
96 $verified_options[ $option_name ] = (string) get_bk_option( $option_name );
97 if ( (string) $option_value !== $verified_options[ $option_name ] ) {
98 $was_restored = $this->restore_options( $before_options, $missing_marker );
99 $message = $was_restored
100 ? __( 'Appearance settings could not be verified. Previous values were restored.', 'booking' )
101 : __( 'Appearance settings could not be verified or restored completely. Review Booking Form and Calendar Appearance settings before continuing.', 'booking' );
102 return new WP_Error( 'wpbc_setup_wizard_appearance_not_verified', $message );
103 }
104 }
105
106 return array(
107 'status' => 'saved',
108 'summary' => __( 'Booking Form and calendar appearance updated.', 'booking' ),
109 'canonical_fingerprint' => hash( 'sha256', wp_json_encode( $verified_options ) ),
110 'created_ids' => array(),
111 'updated_ids' => array_keys( $verified_options ),
112 'warnings' => array(),
113 'writes_canonical_settings' => true,
114 );
115 }
116
117 /**
118 * Restore exact option before-images after a failed verification.
119 *
120 * @param array<string,array{exists:bool,value:mixed}> $before_options Canonical before-images.
121 * @param array<string,string> $missing_marker Missing-option marker.
122 *
123 * @return bool True when every previous value or missing state was restored.
124 */
125 private function restore_options( array $before_options, array $missing_marker ) {
126 $was_restored = true;
127 foreach ( $before_options as $option_name => $before_option ) {
128 if ( ! empty( $before_option['exists'] ) ) {
129 update_bk_option( $option_name, $before_option['value'] );
130 $was_restored = $was_restored && $before_option['value'] === get_bk_option( $option_name, $missing_marker );
131 } else {
132 delete_bk_option( $option_name );
133 $was_restored = $was_restored && $missing_marker === get_bk_option( $option_name, $missing_marker );
134 }
135 }
136
137 return $was_restored;
138 }
139
140 /**
141 * Read the saved Customer Journey.
142 *
143 * @param array<string,mixed> $checkpoint Current checkpoint.
144 *
145 * @return string Journey ID.
146 */
147 private function get_customer_journey_id( array $checkpoint ) {
148 return isset( $checkpoint['values']['customer_journey']['customer_journey'] )
149 ? sanitize_key( (string) $checkpoint['values']['customer_journey']['customer_journey'] )
150 : '';
151 }
152
153 /**
154 * Appearance is not the terminal route step.
155 *
156 * @return bool False.
157 */
158 public function is_terminal() {
159 return false;
160 }
161 }
162