PATH:
home
/
ediuae
/
petalwellnessspa.com
/
wp-content
/
plugins
/
simply-schedule-appointments
/
includes
<?php /** * Simply Schedule Appointments Upgrade. * * @since 0.0.3 * @package Simply_Schedule_Appointments */ /** * Simply Schedule Appointments Upgrade. * * @since 0.0.3 */ class SSA_Upgrade { protected $last_version_seen; protected $versions_requiring_upgrade = array( // '0.0.3', // create /appointments booking page maybe_create_booking_page() '1.2.3', // fix "Email address" -> "email" '1.5.1', // fix customer_information vs custom_customer_information capitalization '2.6.9_12', // flush permalinks '2.6.9_13', // Whitelist for Disable REST API '2.7.1', // Notifications '2.9.2', // SMS phone '3.1.0', // Appointment.date_timezone -> Appointment.customer_timezone '3.5.0', // Appointment.AppointmentType.instructions -> instructions '4.2.2', // Team Member Role '4.4.5', // Fix staff_capacity=100000 -> staff_capacity=1 '5.4.4', // Run Google Calendar sync '5.4.6', // Cleanup Calendar events templates '6.1.5', // Populate the new appt type labels table '6.4.3', // Maybe fix appt type label id equal to zero '6.4.5', // Fix missing appointment types '6.4.9', // Handle upgrade to new class-error-notices logic '6.5.1', // Add cancelation_note to the admin and customers canceled notifications '6.5.4', // Enforce encrypting stripe keys and secrets '6.5.20', // Remove public_edit_url from event_type_group_shared type '6.6.19', // Handle displaying new booking app banners '6.6.21', // Remove public_edit_url from event_type_group_admin type '6.7.13', // Disable old booking app if enabled with resources enabled at the same time '6.7.45', // Disable old booking app for all users '6.8.1', // Update Google Calendar Quick Connect mode from saved dev settings '6.8.6', // Notifications: update notification column schema in appointment types table ); /** * Parent plugin class. * * @since 0.0.3 * * @var Simply_Schedule_Appointments */ protected $plugin = null; /** * Constructor. * * @since 0.0.3 * * @param Simply_Schedule_Appointments $plugin Main plugin object. */ public function __construct( $plugin ) { $this->plugin = $plugin; $this->hooks(); } /** * Initiate our hooks. * * @since 0.0.3 */ public function hooks() { add_action( 'init', array( $this, 'migrations' ), 20 ); add_action( 'init', array( $this, 'check_version_change' ), 20 ); add_action( 'ssa_upgrade_free_to_paid', array( $this, 'migrate_free_to_paid_customer_info' ), 30 ); add_action( 'ssa_downgrade_paid_to_free', array( $this, 'migrate_paid_to_free_customer_info' ), 30 ); } public function record_version_change( $current_version, $stored_version ) { $ssa_version_changes = get_option('ssa_version_changes', []); if( ! isset( $ssa_version_changes[ $stored_version . '--' . $current_version ] ) ) { $utc_timezone = new DateTimeZone( 'UTC' ); $utc_datetime = new DateTimeImmutable( 'now', $utc_timezone ); $record = [ 'home_url' => home_url(), 'wordpress_version' => get_bloginfo('version'), 'php_version' => phpversion(), 'current_version' => $current_version, 'previous_version' => $stored_version, 'timestamp' => $utc_datetime ]; $ssa_version_changes[ $stored_version . '--' .$current_version ] = $record; update_option('ssa_version_changes', $ssa_version_changes); } } /** * Helper function to check version changes - when the user upgrades or downgrades - and to run migration logic when necessary. * * @since 4.4.9 * * @return void */ public function check_version_change() { $current_version = $this->plugin->get_current_version(); $stored_version = get_option( 'ssa_plugin_version' ); $current_version_num = $this->plugin->get_current_edition(); // Reset/Disable beta option if ( $current_version_num > 1 && ! empty( $stored_version ) ) { if ( $current_version !== $stored_version ) { $this->reset_beta_option(); $this->record_version_change( $current_version, $stored_version ); } } // If no stored version, might be the either a fresh install or an existing install with an old version of the plugin. // On this case, we still want to run the logic to make sure that all fields are properly updated. if ( ! $stored_version ) { // if no stored version, and current version is "Free", run the logic to update fields to the free version. if ( 1 === $current_version_num ) { do_action( 'ssa_downgrade_paid_to_free' ); } // if no stored version, and current version is "Paid" run the logic to update fields to paid version. if ( 1 < $current_version_num ) { do_action( 'ssa_upgrade_free_to_paid' ); } $this->plugin->store_current_version(); return; } // Ok, we do have a version number. On this case, we need to verify if it's an upgrade or downgrade, and run the necessary conversion. $stored_version_num = mb_substr( $stored_version, 0, 1 ); // if stored version was "Free" and the user upgraded to a paid version, run the logic to update fields again. if ( '1' === $stored_version_num && $current_version_num > $stored_version_num ) { do_action( 'ssa_upgrade_free_to_paid' ); } // if stored version was "Paid" and the user downgraded to the free version, run the logic to update fields again. if ( '1' < $stored_version_num && 1 === $current_version_num ) { do_action( 'ssa_downgrade_paid_to_free' ); } $this->plugin->store_current_version(); } /** * Helper logic to migrate customer info from free to paid edition. * * @since 4.4.9 * * @return void */ public function migrate_free_to_paid_customer_info() { $field_type_conversion_map = array( 'Name' => 'single-text', 'Email' => 'single-text', 'Phone' => 'phone', 'Address' => 'single-text', 'City' => 'single-text', 'State' => 'single-text', 'Zip' => 'single-text', 'Notes' => 'multi-text', ); /* Migrate Appointment Types */ $appointment_types = $this->plugin->appointment_type_model->query( array( 'number' => -1, ) ); foreach ( $appointment_types as $appointment_type_key => $appointment_type ) { // if custom_customer_information is not empty, then we can't populate it again, since it might lose data. if ( ! empty( $appointment_type['custom_customer_information'] ) ) { continue; } if ( ! empty( $appointment_type['customer_information']['0']['field'] ) ) { $appointment_types[ $appointment_type_key ]['custom_customer_information'] = array(); foreach ( $appointment_type['customer_information'] as $field_key => $field ) { $field = $appointment_type['customer_information'][ $field_key ]; if ( ! $field['display'] ) { continue; } $field_array = $field; // include field type. $type = isset( $field_type_conversion_map[ $field['field'] ] ) ? $field_type_conversion_map[ $field['field'] ] : 'single-text'; $field_array['type'] = $type; $field_array['values'] = array(); $appointment_types[ $appointment_type_key ]['custom_customer_information'][] = $field_array; } } // update appointment type. $this->plugin->appointment_type_model->update( $appointment_types[ $appointment_type_key ]['id'], $appointment_types[ $appointment_type_key ] ); } /* Migrate Appointments */ $appointments = $this->plugin->appointment_model->query( array( 'number' => -1, ) ); // clear appointment types cache. $this->plugin->appointment_type_model->invalidate_appointment_type_cache(); } /** * Helper logic to migrate customer info from paid to free edition. * * @since 4.4.9 * * @return void */ public function migrate_paid_to_free_customer_info() { $field_conversion_map = array( 'Name' => array( 'field' => 'Name', 'display' => true, 'required' => true, 'icon' => 'face', ), 'Email' => array( 'field' => 'Email', 'display' => true, 'required' => true, 'icon' => 'email', ), 'Phone' => array( 'field' => 'Phone', 'display' => true, 'required' => false, 'icon' => 'phone', ), 'Address' => array( 'field' => 'Address', 'display' => false, 'required' => false, 'icon' => 'place', ), 'City' => array( 'field' => 'City', 'display' => false, 'required' => false, 'icon' => 'place', ), 'State' => array( 'field' => 'State', 'display' => false, 'required' => false, 'icon' => 'place', ), 'Zip' => array( 'field' => 'Zip', 'display' => false, 'required' => false, 'icon' => 'place', ), 'Notes' => array( 'field' => 'Notes', 'display' => false, 'required' => false, 'icon' => 'assignment', ), ); /* Migrate Appointment Types */ $appointment_types = $this->plugin->appointment_type_model->query( array( 'number' => -1, ) ); foreach ( $appointment_types as $appointment_type_key => $appointment_type ) { // if customer_information is not empty, then we can't populate it again, since it might lose data. if ( ! empty( $appointment_type['customer_information'] ) ) { continue; } $appointment_types[ $appointment_type_key ]['customer_information'] = array(); if ( ! empty( $appointment_type['custom_customer_information']['0']['field'] ) ) { $schema = $appointment_type['custom_customer_information']['0']; foreach ( $field_conversion_map as $field_key => $field_value ) { // check if we have this field set before so we can verify if it's set to display / require. $existing_field_key = array_search( $field_value, array_column( $appointment_type['custom_customer_information'], 'field' ), true ); if ( false !== $existing_field_key ) { $field = $appointment_type['custom_customer_information'][ $existing_field_key ]; } else { $field = $field_conversion_map[ $field_key ]; } // remove field type. if ( isset( $field['type'] ) ) { unset( $field['type'] ); } $appointment_types[ $appointment_type_key ]['customer_information'][] = $field; } } // update appointment type. $this->plugin->appointment_type_model->update( $appointment_types[ $appointment_type_key ]['id'], $appointment_types[ $appointment_type_key ] ); } // clear appointment types cache. $this->plugin->appointment_type_model->invalidate_appointment_type_cache(); } public function get_last_version_seen() { $db_versions = get_option( 'ssa_versions', json_encode( array() ) ); $db_versions = json_decode( $db_versions, true ); $db_version_keys = array_keys( $db_versions ); $last_changed_date = array_pop( $db_version_keys ); if ( $last_changed_date === null ) { // First time we're seeing SSA installed $this->last_version_seen = '0.0.0'; } else { $this->last_version_seen = $db_versions[$last_changed_date]; } return $this->last_version_seen; } public function record_version( $version ) { $db_versions = get_option( 'ssa_versions', json_encode( array() ) ); $db_versions = json_decode( $db_versions, true ); $db_versions[gmdate('Y-m-d H:i:s')] = $version; $this->last_version_seen = $version; return update_option( 'ssa_versions', json_encode($db_versions) ); } public function migrations() { $this->last_version_seen = $this->get_last_version_seen(); foreach ( $this->versions_requiring_upgrade as $version ) { if ( version_compare($this->last_version_seen, $version,'>=' ) ) { continue; } $method_name = 'migrate_to_version_'.str_replace('.', '_', $version); $this->$method_name( $this->last_version_seen ); } } public function migrate_to_version_1_2_3( $from_version ) { if ( $from_version === '0.0.0' ) { return; // we don't need to migrate fresh installs } $appointment_types = $this->plugin->appointment_type_model->query( array( 'number' => -1, ) ); if ( empty( $appointment_types['0']['id'] ) ) { $this->record_version( '1.2.3' ); return; } foreach ($appointment_types as $appointment_type_key => $appointment_type) { if ( empty( $appointment_type['custom_customer_information']['0']['field'] ) ) { continue; } foreach ($appointment_type['custom_customer_information'] as $field_key => $field ) { if ( $field['field'] != 'Email address' ) { continue; } $appointment_types[$appointment_type_key]['custom_customer_information'][$field_key]['field'] = 'Email'; } $this->plugin->appointment_type_model->update( $appointment_types[$appointment_type_key]['id'], $appointment_types[$appointment_type_key] ); } $this->record_version( '1.2.3' ); } public function migrate_to_version_1_5_1( $from_version ) { if ( $from_version === '0.0.0' ) { return; // we don't need to migrate fresh installs } $field_name_conversion_map = array( 'name' => 'Name', 'email' => 'Email', 'phone_number' => 'Phone', 'address' => 'Address', 'city' => 'City', 'state' => 'State', 'zip' => 'Zip', 'notes' => 'Notes', ); /* Migrate Appointment Types */ $appointment_types = $this->plugin->appointment_type_model->query( array( 'number' => -1, ) ); foreach ($appointment_types as $appointment_type_key => $appointment_type) { if ( !empty( $appointment_type['custom_customer_information']['0']['field'] ) ) { foreach ($appointment_type['custom_customer_information'] as $field_key => $field ) { if ( empty( $field_name_conversion_map[$field['field']] ) ) { continue; } $appointment_types[$appointment_type_key]['custom_customer_information'][$field_key]['field'] = $field_name_conversion_map[$field['field']]; } } if ( !empty( $appointment_type['customer_information']['0']['field'] ) ) { foreach ($appointment_type['customer_information'] as $field_key => $field ) { if ( empty( $field_name_conversion_map[$field['field']] ) ) { continue; } $appointment_types[$appointment_type_key]['customer_information'][$field_key]['field'] = $field_name_conversion_map[$field['field']]; } } $this->plugin->appointment_type_model->update( $appointment_types[$appointment_type_key]['id'], $appointment_types[$appointment_type_key] ); } /* Migrate Appointments */ $appointments = $this->plugin->appointment_model->query( array( 'number' => -1, ) ); foreach ($appointments as $appointment_key => $appointment) { if ( !empty( $appointment['customer_information'] ) ) { foreach ($appointment['customer_information'] as $field_key => $value ) { if ( empty( $field_name_conversion_map[$field_key] ) ) { continue; } $appointments[$appointment_key]['customer_information'][$field_name_conversion_map[$field_key]] = $value; unset( $appointments[$appointment_key]['customer_information'][$field_key] ); } } $this->plugin->appointment_model->update( $appointments[$appointment_key]['id'], $appointments[$appointment_key] ); } $this->record_version( '1.5.1' ); } public function migrate_to_version_2_6_9_12( $from_version ) { global $wp_rewrite; $wp_rewrite->init(); flush_rewrite_rules(); $this->record_version( '2.6.9_12' ); } public function migrate_to_version_2_6_9_13( $from_version ) { $DRA_route_whitelist = get_option( 'DRA_route_whitelist', array() ); $ssa_routes_to_whitelist = array( "/ssa/v1","/ssa/v1/settings", "/ssa/v1/settings/(?P<id>[a-zA-Z0-9_-]+)", "/ssa/v1/settings/schema", "/ssa/v1/notices", "/ssa/v1/notices/(?P<id>[a-zA-Z0-9_-]+)", "/ssa/v1/notices/schema", "/ssa/v1/license", "/ssa/v1/license/schema", "/ssa/v1/google_calendars", "/ssa/v1/google_calendars/disconnect", "/ssa/v1/google_calendars/authorize_url", "/ssa/v1/mailchimp", "/ssa/v1/mailchimp/disconnect", "/ssa/v1/mailchimp/authorize", "/ssa/v1/mailchimp/deauthorize", "/ssa/v1/mailchimp/lists", "/ssa/v1/mailchimp/subscribe", "/ssa/v1/support_status", "/ssa/v1/support_ticket", "/oembed/1.0", "/ssa/v1/appointments", "/ssa/v1/appointments/bulk", "/ssa/v1/appointments/(?P<id>[\\d]+)", "/ssa/v1/appointments/(?P<id>[\\d]+)/ics", "/ssa/v1/appointment_types", "/ssa/v1/appointment_types/bulk", "/ssa/v1/appointment_types/(?P<id>[\\d]+)", "/ssa/v1/appointment_types/(?P<id>[\\d]+)/availability", "/ssa/v1/availability", "/ssa/v1/availability/bulk", "/ssa/v1/availability/(?P<id>[\\d]+)", "/ssa/v1/async", "/ssa/v1/payments", "/ssa/v1/payments/bulk", "/ssa/v1/payments/(?P<id>[\\d]+)" ); if ( empty( $DRA_route_whitelist ) ) { $DRA_route_whitelist = $ssa_routes_to_whitelist; } else { foreach ( $ssa_routes_to_whitelist as $key => $route ) { if ( ! in_array( $route, $DRA_route_whitelist ) ) { $DRA_route_whitelist[] = $route; } } } update_option( 'DRA_route_whitelist', $DRA_route_whitelist ); $this->record_version( '2.6.9_13' ); } public function migrate_to_version_2_7_1( $from_version ) { $notifications_settings = $this->plugin->notifications_settings->get(); $should_enable_admin_notification_for_all_appointment_types = true; $should_enable_customer_notification_for_all_appointment_types = true; $appointment_type_ids_with_admin_notification = array(); $appointment_type_ids_with_customer_notification = array(); $appointment_types = $this->plugin->appointment_type_model->query(); if ( ! empty( $appointment_types ) ) { foreach ( $appointment_types as $key => $appointment_type ) { if ( empty( $appointment_type['notifications'] ) ) { $appointment_type_ids_with_admin_notification[] = $appointment_type['id']; $appointment_type_ids_with_customer_notification[] = $appointment_type['id']; continue; } foreach ($appointment_type['notifications'] as $notification_key => $notification ) { if ( empty( $notification['field'] ) ) { continue; } if ( $notification['field'] === 'admin' ) { if ( empty( $notification['send'] ) ) { $should_enable_admin_notification_for_all_appointment_types = false; } else { $appointment_type_ids_with_admin_notification[] = $appointment_type['id']; } } elseif ( $notification['field'] === 'customer' ) { if ( empty( $notification['send'] ) ) { $should_enable_customer_notification_for_all_appointment_types = false; } else { $appointment_type_ids_with_customer_notification[] = $appointment_type['id']; } } } } } $id = time(); $booked_admin_notification = array( 'appointment_types' => ( $should_enable_admin_notification_for_all_appointment_types ) ? array() : $appointment_type_ids_with_admin_notification, 'id' => $id, 'schema' => '2019-04-02', 'sent_to' => array( '{{admin_email}}', ), 'title' => 'Email (Admin)', 'subject' => '{{ Appointment.customer_information.Name }} just booked an appointment', 'message' => wpautop( nl2br( $this->plugin->templates->get_template( 'notifications/email/text/booked-staff.php' ) ) ), 'trigger' => 'appointment_booked', 'type' => 'email', 'when' => 'after', 'duration' => 0, ); $id = time() + 1; $booked_customer_notification = array( 'appointment_types' => ( $should_enable_customer_notification_for_all_appointment_types ) ? array() : $appointment_type_ids_with_customer_notification, 'id' => $id, 'schema' => '2019-04-02', 'sent_to' => array( '{{customer_email}}', ), 'subject' => 'Your appointment details', 'message' => wpautop( nl2br( $this->plugin->templates->get_template( 'notifications/email/text/booked-customer.php' ) ) ), 'title' => 'Email (Customer)', 'trigger' => 'appointment_booked', 'type' => 'email', 'when' => 'after', 'duration' => 0, ); $id = time() + 2; $canceled_admin_notification = array( 'appointment_types' => ( $should_enable_admin_notification_for_all_appointment_types ) ? array() : $appointment_type_ids_with_admin_notification, 'id' => $id, 'schema' => '2019-04-02', 'sent_to' => array( '{{admin_email}}', ), 'title' => 'Email (Admin)', 'subject' => '{{ Appointment.customer_information.Name }} just canceled an appointment', 'message' => wpautop( nl2br( $this->plugin->templates->get_template( 'notifications/email/text/canceled-staff.php' ) ) ), 'trigger' => 'appointment_canceled', 'type' => 'email', 'when' => 'after', 'duration' => 0, ); $id = time() + 3; $canceled_customer_notification = array( 'appointment_types' => ( $should_enable_customer_notification_for_all_appointment_types ) ? array() : $appointment_type_ids_with_customer_notification, 'id' => $id, 'schema' => '2019-04-02', 'sent_to' => array( '{{customer_email}}', ), 'subject' => 'Your appointment has been canceled', 'message' => wpautop( nl2br( $this->plugin->templates->get_template( 'notifications/email/text/canceled-customer.php' ) ) ), 'title' => 'Email (Customer)', 'trigger' => 'appointment_canceled', 'type' => 'email', 'when' => 'after', 'duration' => 0, ); $notifications_settings['notifications'] = array( $booked_admin_notification, $booked_customer_notification, $canceled_admin_notification, $canceled_customer_notification, ); $this->plugin->notifications_settings->update( $notifications_settings ); $this->record_version( '2.7.1' ); } public function migrate_to_version_2_9_2( $from_version ) { $appointment_types = $this->plugin->appointment_type_model->query( array( 'number' => -1, ) ); if ( empty( $appointment_types['0']['id'] ) ) { $this->record_version( '2.9.2' ); return; } foreach ($appointment_types as $appointment_type_key => $appointment_type) { if ( empty( $appointment_type['custom_customer_information']['0']['field'] ) ) { continue; } foreach ($appointment_type['custom_customer_information'] as $field_key => $field ) { if ( false === stripos( $field['field'], 'phone' ) ) { if ( $field['type'] !== 'single-text' ) { continue; } if ( empty( $field['icon'] ) || ( $field['icon'] !== 'call' ) ) { continue; } } $appointment_types[$appointment_type_key]['custom_customer_information'][$field_key]['type'] = 'phone'; } $this->plugin->appointment_type_model->update( $appointment_types[$appointment_type_key]['id'], $appointment_types[$appointment_type_key] ); } $this->record_version( '2.9.2' ); } public function migrate_to_version_3_1_0( $from_version ) { $notifications_settings = $this->plugin->notifications_settings->get(); foreach ($notifications_settings['notifications'] as $key => $notification) { if ( empty( $notification['sent_to'] ) || ! is_array( $notification['sent_to'] ) ) { continue; } $is_customer_notification = false; foreach ( $notification['sent_to'] as $recipient ) { if ( false !== strpos( $recipient, '{{customer' ) ) { $is_customer_notification = true; } } if ( ! $is_customer_notification ) { continue; } $notifications_settings['notifications'][$key]['message'] = str_replace( 'Appointment.date_timezone', 'Appointment.customer_timezone', $notifications_settings['notifications'][$key]['message'] ); } $this->plugin->notifications_settings->update( $notifications_settings ); $this->record_version( '3.1.0' ); } public function migrate_to_version_3_5_0( $from_version ) { $notifications_settings = $this->plugin->notifications_settings->get(); foreach ($notifications_settings['notifications'] as $key => $notification) { $notifications_settings['notifications'][$key]['message'] = str_replace( 'Appointment.AppointmentType.instructions', 'instructions', $notifications_settings['notifications'][$key]['message'] ); } $this->plugin->notifications_settings->update( $notifications_settings ); $this->record_version( '3.5.0' ); } public function migrate_to_version_4_2_2( $from_version ) { $this->plugin->capabilities->remove_roles(); $this->plugin->capabilities->add_roles(); $this->record_version( '4.2.2' ); } public function migrate_to_version_4_4_5( $from_version ) { $appointment_types = $this->plugin->appointment_type_model->query( array( 'number' => -1, ) ); foreach ($appointment_types as $appointment_type) { if ( empty( $appointment_type['staff']['required'] ) ) { continue; } if ( $appointment_type['capacity_type'] == 'individual' && $appointment_type['staff_capacity'] == SSA_Constants::CAPACITY_MAX ) { $this->plugin->appointment_type_model->update( $appointment_type['id'], array( 'staff_capacity' => 1, ) ); } } $this->record_version( '4.4.5' ); } public function migrate_to_version_5_4_4( $from_version ) { // Get list of booked + upcoming appointments. $appointments = $this->plugin->appointment_model->query( array( 'status' => array('booked'), 'start_date_min' => gmdate('Y-m-d H:i:s'), 'number' => -1, ) ); if (empty($appointments)) { $this->record_version('5.4.4'); return; } $appointments = array_values( array_filter( $appointments, function ($appointment) { return empty($appointment['google_calendar_event_id']); } ) ); // if we have a list of appointments, we need to sync them with Google Calendar. $this->plugin->google_calendar->bulk_schedule_google_calendar_sync($appointments); $this->record_version( '5.4.4' ); } /** * Migrate to version 5.4.6 * * @param string $from_version The version we are migrating from. */ public function migrate_to_version_5_4_6( $from_version ) { $settings = $this->plugin->calendar_events_settings->get(); $settings_map = array( 'event_type_customer', 'event_type_individual_shared', 'event_type_group_shared', 'event_type_individual_admin', 'event_type_group_admin', ); $clear_map = array( '</p>' => "</p>\r\n", '<br />' => "\r\n", '<br>' => "\r\n", '<br/>' => "\r\n", ); foreach ( $settings_map as $event_type ) { if ( ! isset( $settings[ $event_type ] ) ) { continue; } foreach ( $settings[ $event_type ] as $key => $value ) { if ( ! isset( $settings[ $event_type ][ $key ] ) ) { continue; } // Remove all html tags and turn paragraphs or <br> into line breaks. // Required to avoid html issues with Google Calendar and other calendar apps. $value = str_replace( array_keys( $clear_map ), array_values( $clear_map ), $value ); $value = wp_strip_all_tags( $value ); $settings[ $event_type ][ $key ] = $value; } } $this->plugin->calendar_events_settings->update( $settings ); $this->record_version( '5.4.6' ); } /** * Reset/Disable the beta option * Beta optin one time only; Turn off after one beta is downloaded. * * @return void */ public function reset_beta_option() { $developer_settings = $this->plugin->developer_settings->get(); if ( ! empty($developer_settings['beta_updates']) ) { $developer_settings['beta_updates'] = false; $this->plugin->developer_settings->update($developer_settings); } } /** * Populate the new appt type labels with the existing registered labels if any * * @param string $from_version * @return void */ public function migrate_to_version_6_1_5( $from_version ) { $this->migrate_appointment_type_labels(); $this->record_version( '6.1.5' ); } /** * Helper function to migrate to the new appt type labels setup * Needed in case to be called when importing; check class-support-status -> import_data() * * @return void */ public function migrate_appointment_type_labels(){ if( ! empty( $GLOBALS["_COOKIE"]["__cypress_initial"] ) ) { return; } // First let's make sure we have a fresh appt type labels tabel for the IDs to be reset $this->plugin->appointment_type_label_model->truncate(); $this->plugin->appointment_type_label_model->create_table(); // Query all appointment types that are defined $appointment_types = $this->plugin->appointment_type_model->query( array( 'number' => -1, ) ); if ( empty( $appointment_types ) ) { // This is either a new install or has no appt types defined -> insert one row in labels table $default_label['name'] = __('Default', 'simply-schedule-appointments'); $default_label['color'] = 'light-green'; $this->plugin->appointment_type_label_model->raw_insert( $default_label ); } else { // Get all registered labels for this site $labels = array(); foreach( $appointment_types as $appointment_type ) { if ( empty( $appointment_type['label'] ) ){ continue; } if ( ! in_array( $appointment_type['label'], $labels)){ $labels[] = $appointment_type['label']; } } // If no labels have been detected insert the Default label into labels table if( empty( $labels ) ){ $default_label['name'] = __('Default', 'simply-schedule-appointments'); $default_label['color'] = 'light-green'; $this->plugin->appointment_type_label_model->raw_insert( $default_label ); } elseif( count( $labels ) === 1 ){ // If only one label detected then add this label with its name set to Default $default_label['name'] = __('Default', 'simply-schedule-appointments'); $default_label['color'] = $labels[0]; $this->plugin->appointment_type_label_model->raw_insert( $default_label ); } else { // Insert all labels into new labels table foreach( $labels as $label ) { $row['name'] = ucwords( str_replace( '-', ' ', $label ) ); $row['color'] = $label; $this->plugin->appointment_type_label_model->raw_insert( $row ); } } } // confirm at this point that we have a label at ID 1 $existing_default_label = $this->plugin->appointment_type_label_model->query( array( $this->plugin->appointment_type_label_model->primary_key() => 1, ) ); // if not then insert the default label if ( empty( $existing_default_label ) ) { $this->plugin->appointment_type_label_model->raw_insert( array( // force insert at ID 1 $this->plugin->appointment_type_label_model->primary_key() => 1, // the name of the label is intentionally different from the default label name above 'name' => __('Default Label', 'simply-schedule-appointments'), 'color' => 'light-green', ) ); } if ( ! empty( $appointment_types ) ) { // Query all labels that were inserted to access their ids $appointment_type_labels = $this->plugin->appointment_type_label_model->query( array( 'number' => -1, ) ); // Set the new label ids as foreign keys in appt types table foreach( $appointment_types as $appointment_type ) { if ( empty( $appointment_type['label'] ) ) { continue; } foreach($appointment_type_labels as $label ) { if ( $appointment_type['label'] === $label['color'] ) { $this->plugin->appointment_type_model->update( $appointment_type['id'], array( 'label_id' => $label['id'], )); } } } } } /** * Since an index ID of 0 in Microsoft SQL Server is allowed * Fix Default label id not being found * * @param string $from_version * @return void */ public function migrate_to_version_6_4_3( $from_version ) { $this->maybe_fix_appointment_type_label_id_equal_to_zero(); $this->record_version( '6.4.3' ); } /** * Since an index ID of 0 in Microsoft SQL Server is allowed * Fix Default label id not being found * * @param string $from_version * @return void */ public function migrate_to_version_6_4_5( $from_version ) { $this->maybe_fix_deleted_appointment_types(); $this->record_version( '6.4.5' ); } public function maybe_fix_deleted_appointment_types() { static $has_already_run_once_during_this_php_execution = false; if ( $has_already_run_once_during_this_php_execution ) { return; // this prevents an infinite loop since this function queries, which calls prepare_for_response(), which in turn may call this function again // There is still a problem if we end up here, but this prevents a fatal error } $has_already_run_once_during_this_php_execution = true; $orphaned_appointments = $this->plugin->appointment_model->query( array( 'number' => -1, 'append_where_sql' => " AND `appointment_type_id` NOT IN( SELECT `id` FROM " . $this->plugin->appointment_type_model->get_table_name() . " )", ) ); $labels = $this->plugin->appointment_type_label_model->query( array( 'number' => 1, ) ); if ( empty( $orphaned_appointments ) ) { return; } $map_missing_appointment_type_ids_to_replacement_ids = array(); foreach( $orphaned_appointments as $orphaned_appointment ) { $missing_appointment_type_id = $orphaned_appointment['appointment_type_id']; if ( empty( $map_missing_appointment_type_ids_to_replacement_ids[$missing_appointment_type_id] ) ) { // Create a new appointment type ID to replace the missing one $replacement_id = $this->plugin->appointment_type_model->insert( array( 'title' => __( 'Previously Deleted Appointment Type #', 'simply-schedule-appointments' ) . $missing_appointment_type_id, 'label_id' => $labels[0]['id'], 'status' => 'delete', 'custom_customer_information' => array ( array ( 'field' => 'Name', 'display' => true, 'required' => true, 'type' => 'single-text', 'icon' => 'face', 'values' => '', ), array ( 'field' => 'Email', 'display' => true, 'required' => true, 'type' => 'single-text', 'icon' => 'email', 'values' => '', ), ), 'customer_information' => array ( array ( 'field' => 'Name', 'display' => true, 'required' => true, 'type' => 'single-text', 'icon' => 'face', 'values' => '', ), array ( 'field' => 'Email', 'display' => true, 'required' => true, 'type' => 'single-text', 'icon' => 'email', 'values' => '', ), ), ) ); $map_missing_appointment_type_ids_to_replacement_ids[$missing_appointment_type_id] = $replacement_id; } $this->plugin->appointment_model->db_update( $orphaned_appointment['id'], array( 'appointment_type_id' => $map_missing_appointment_type_ids_to_replacement_ids[$missing_appointment_type_id], ) ); } } public function maybe_fix_appointment_type_label_id_equal_to_zero() { // Query all labels that were inserted to access their ids $appointment_type_labels = $this->plugin->appointment_type_label_model->query( array( 'number' => -1, 'append_where_sql' => " AND `id` IN( 0 ) ", ) ); foreach ( $appointment_type_labels as $label ) { $raw_id = $this->plugin->appointment_type_label_model->raw_insert( array( 'name' => $label['name'], 'color' => $label['color'] )); $this->plugin->appointment_type_label_model->db_delete( $label['id'], true ); // Update appointment types to use new label id $appointment_types = $this->plugin->appointment_type_model->query( array( 'number' => -1, 'label_id' => $label['id'], )); if( empty( $appointment_types ) ) { continue; } foreach( $appointment_types as $type ) { $this->plugin->appointment_type_model->update( $type['id'], array( 'label_id' => $raw_id, )); } } } /** * Clear ssa_error_notices array since the old format of the stored errors has changed from indexed array to associative array * * @param string $from_version * @return void */ public function migrate_to_version_6_4_9( $from_version ) { $errors = get_option( 'ssa_error_notices', array() ); if( ! empty( $errors ) ) { update_option( 'ssa_error_notices', array() ); } $this->record_version( '6.4.9' ); } /** * Add {{ cancelation_note }} to the customer and admin canceled notifications * * @param string $from_version * @return void */ public function migrate_to_version_6_5_1( $from_version ) { $notifications_settings = $this->plugin->notifications_settings->get(); if ( empty( $notifications_settings['notifications'] ) ) { $this->record_version( '6.5.1' ); return; } foreach( $notifications_settings['notifications'] as $key => $notification ) { if( $notification['trigger'] === 'appointment_canceled' && $notification['type'] === 'email' ) { $message = $notification['message']; if ( empty( $message ) ) { continue; } $pattern = '/has been canceled\s*\<\/p>/i'; $is_matching = preg_match($pattern, $message); if ( $is_matching ) { $message = preg_replace_callback( $pattern, function( $matches ) { return $matches[0] . '{% if cancelation_note %}' . '<p>' . '{% if canceled_by_name %} {{ canceled_by_name }} ' . __( 'left a note', 'simply-schedule-appointments' ) . ': {% else %}' . __( 'Note', 'simply-schedule-appointments' ) . ': {% endif %}' . '{{ cancelation_note }} </p>' . '{% endif %}'; }, $message ); } else { $message .= '{% if cancelation_note %}' . '<p>' . '{% if canceled_by_name %} {{ canceled_by_name }} ' . __( 'left a note', 'simply-schedule-appointments' ) . ': {% else %}' . __( 'Note', 'simply-schedule-appointments' ) . ': {% endif %}' . '{{ cancelation_note }} </p>' . '{% endif %}'; } $notifications_settings['notifications'][$key]['message'] = $message; } } $this->plugin->notifications_settings->update( $notifications_settings ); $this->record_version( '6.5.1' ); } /** * Get and save stripe settings to enforce stripe settings encryption * * @param string $from_version * @return void */ public function migrate_to_version_6_5_4( $from_version ) { if ( class_exists( 'SSA_Stripe_Settings' ) ) { $stripe_settings = $this->plugin->stripe_settings->get(); $this->plugin->stripe_settings->update( $stripe_settings ); } $this->record_version( '6.5.4' ); } /** * Remove public_edit_url from calendar shared group event * * @param string $from_version * @return void */ public function migrate_to_version_6_5_20( $from_version ) { $settings = $this->plugin->calendar_events_settings->get(); if ( ! isset( $settings[ 'event_type_group_shared' ] ) ) { $this->record_version( '6.5.20' ); return; } $settings[ 'event_type_group_shared' ] = str_replace('Need to make changes to this event?', '',$settings[ 'event_type_group_shared' ]); $settings[ 'event_type_group_shared' ] = str_replace('{{ Appointment.public_edit_url }}', '',$settings[ 'event_type_group_shared' ]); $this->plugin->calendar_events_settings->update( $settings ); $this->record_version( '6.5.20' ); } /** * Migrates settings after specifically checking for the presence of a custom CSS file. * * @param string $from_version The version from which the migration is being performed. * * @return void */ public function migrate_to_version_6_6_19( $from_version ) { $settings = $this->plugin->settings->get(); if ( $settings ) { $theme_directory = get_stylesheet_directory(); // Build the path to the custom CSS directory $custom_css_dir = $theme_directory . '/ssa/booking-app/'; // List all files in the custom CSS directory if (is_dir($custom_css_dir)) { // List all files in the custom CSS directory $files = scandir($custom_css_dir); // Check if there's at least one CSS file foreach ($files as $file) { if (pathinfo($file, PATHINFO_EXTENSION) === 'css') { $settings['global'][ 'should_display_new_booking_app_banner' ] = 'notice'; $this->plugin->settings->update( $settings ); } } } $is_custom_css_existing = $this->plugin->styles_settings->get()['css']; if ($is_custom_css_existing !== '') { $settings['global'][ 'should_display_new_booking_app_banner' ] = 'notice'; } $this->plugin->settings->update( $settings ); } $this->record_version( '6.6.19' ); } /* * Remove public_edit_url from calendar admin group event * * @param string $from_version * @return void */ public function migrate_to_version_6_6_21( $from_version ) { $settings = $this->plugin->calendar_events_settings->get(); if ( ! isset( $settings[ 'event_type_group_admin' ] ) ) { $this->record_version( '6.6.21' ); return; } $settings[ 'event_type_group_admin' ] = str_replace('Need to make changes to this event?', '',$settings[ 'event_type_group_admin' ]); $settings[ 'event_type_group_admin' ] = str_replace('{{ Appointment.public_edit_url }}', '',$settings[ 'event_type_group_admin' ]); $this->plugin->calendar_events_settings->update( $settings ); $this->record_version( '6.6.21' ); } /** * Disable old booking app if enabled with resources enabled at the same time * * @param string $from_version * @return void */ public function migrate_to_version_6_7_13( $from_version ) { $ssa_settings = $this->plugin->settings->get(); // if resources are enabled if( !empty( $ssa_settings['resources']['enabled'] ) ) { // disable the old booking app $developer_settings = $this->plugin->developer_settings->get(); if ( !empty( $developer_settings['old_booking_app'] ) ) { $developer_settings['old_booking_app'] = false; $this->plugin->developer_settings->update( $developer_settings ); } } $this->record_version( '6.7.13' ); } /** * Disable old booking app for all users * */ public function migrate_to_version_6_7_45() { $developer_settings = $this->plugin->developer_settings->get(); if ( !empty( $developer_settings['old_booking_app'] ) ) { $developer_settings['old_booking_app'] = false; $this->plugin->developer_settings->update( $developer_settings ); } $this->record_version( '6.7.45' ); } /** * Update Google Calendar Quick Connect mode from saved dev settings * * @param string $from_version * @return void */ public function migrate_to_version_6_8_1() { // global variable skip token invalidation global $ssa_skip_token_invalidation; $ssa_skip_token_invalidation = true; $developer_settings = $this->plugin->developer_settings->get(); // if quick connect was on - keep it on if ( ! empty( $developer_settings['quick_connect_gcal_mode'] ) ) { $this->plugin->google_calendar_settings->update( array( 'quick_connect_gcal_mode' => true, ) ); } else { // if quick connect was off $settings = $this->plugin->settings->get(); if ( ! empty( $settings[ 'google_calendar' ]['access_token'] ) ) { // and gcal is connected - do nothing } else { // but if gcal is not connected - switch to quick connect mode $this->plugin->google_calendar_settings->update( array( 'quick_connect_gcal_mode' => true, ) ); } } $this->record_version( '6.8.1' ); } public function migrate_to_version_6_8_6() { $appointment_types = $this->plugin->appointment_type_model->query(); $old_schema = array ( 0 => array ( 'field' => 'admin', 'send' => true, ), 1 => array ( 'field' => 'customer', 'send' => true, ), ); if ( ! empty( $appointment_types ) ) { foreach ( $appointment_types as $key => $appointment_type ) { if( ! empty( $appointment_type['notifications']['notifications_opt_in'] ) ) { continue; } if ( ! empty( $appointment_type['notifications'] ) && is_array( $appointment_type['notifications'] ) && ! empty( $appointment_type['notifications'][0]['field'] ) ) { $old_schema = $appointment_type['notifications']; } $updated_notifications = [ "fields" => $old_schema, "notifications_opt_in" => [ "enabled" => false, "label" => "Receive notifications", "description" => "Check this box to receive appointment notifications." ] ]; $this->plugin->appointment_type_model->update( $appointment_type['id'], array( 'notifications' => $updated_notifications, )); } } $this->record_version( '6.8.6' ); } }
[-] class-settings.php
[edit]
[-] class-hooks.php
[edit]
[-] class-availability-query.php
[edit]
[-] class-appointment-model.php
[edit]
[-] class-beaver-builder.php
[edit]
[-] class-web-meetings.php
[edit]
[-] class-availability-model.php
[edit]
[-] class-recipient-admin.php
[edit]
[-] class-recipient-customer.php
[edit]
[-] class-constants.php
[edit]
[-] class-async-action-model.php
[edit]
[-] class-support.php
[edit]
[-] class-google-calendar-client.php
[edit]
[+]
..
[-] class-capabilities.php
[edit]
[-] class-encryption.php
[edit]
[-] class-availability-cache-invalidation.php
[edit]
[-] class-calendar-events-settings.php
[edit]
[-] class-settings-global.php
[edit]
[-] class-translation.php
[edit]
[-] class-cli.php
[edit]
[-] class-missing.php
[edit]
[-] class-action-scheduler.php
[edit]
[-] class-templates-api.php
[edit]
[-] class-blackout-dates.php
[edit]
[-] class-calendar-events-object.php
[edit]
[-] class-divi.php
[edit]
[-] class-templates.php
[edit]
[-] class-wp-admin.php
[edit]
[-] class-appointment-factory.php
[edit]
[-] class-scheduling-max-per-day.php
[edit]
[-] class-notifications-api.php
[edit]
[-] class-shortcodes.php
[edit]
[-] class-validation.php
[edit]
[-] class-resource-group-object-factory.php
[edit]
[-] class-payment-object.php
[edit]
[-] class-locale.php
[edit]
[-] class-ics-exporter.php
[edit]
[-] class-filesystem.php
[edit]
[-] class-recipient-shared.php
[edit]
[-] class-availability-schedule.php
[edit]
[-] class-block-upcoming-appointments.php
[edit]
[-] class-elementor.php
[edit]
[-] class-appointment-meta-model.php
[edit]
[-] class-revision-meta-model.php
[edit]
[+]
divi
[-] class-notifications.php
[edit]
[-] class-upgrade.php
[edit]
[-] class-utils.php
[edit]
[-] class-availability-functions.php
[edit]
[-] class-external-calendar-api.php
[edit]
[-] class-csv-exporter.php
[edit]
[-] class-external-google-calendar-api.php
[edit]
[-] class-twig-extension.php
[edit]
[-] class-bootstrap.php
[edit]
[-] class-notices.php
[edit]
[-] class-availability-schedule-factory.php
[edit]
[-] class-blackout-dates-settings.php
[edit]
[-] class-support-status.php
[edit]
[-] class-block-booking.php
[edit]
[-] class-advanced-scheduling-availability.php
[edit]
[-] class-exception.php
[edit]
[-] class-styles-settings.php
[edit]
[-] class-forms.php
[edit]
[-] class-recipient-staff.php
[edit]
[+]
beaver-builder
[-] class-users.php
[edit]
[-] class-sequence-factory.php
[edit]
[+]
third-party
[-] class-locales.php
[edit]
[-] class-db-model.php
[edit]
[-] class-db.php
[edit]
[-] class-availability-default.php
[edit]
[-] class-staff-settings.php
[edit]
[-] class-notification-model.php
[edit]
[-] class-settings-installed.php
[edit]
[-] class-appointment-object.php
[edit]
[-] class-notices-api.php
[edit]
[-] class-translation-settings.php
[edit]
[-] class-support-status-api.php
[edit]
[-] class-notices-data.php
[edit]
[-] class-appointment-type-object.php
[edit]
[-] class-appointment-type-object-factory.php
[edit]
[-] class-availability-block-factory.php
[edit]
[-] class-recipient.php
[edit]
[-] class-revision-model.php
[edit]
[-] class-customers.php
[edit]
[-] class-settings-api.php
[edit]
[-] class-cache.php
[edit]
[-] class-availability-detective-case.php
[edit]
[-] class-styles.php
[edit]
[-] class-capacity-settings.php
[edit]
[-] class-gcal-exporter.php
[edit]
[-] class-advanced-scheduling-settings.php
[edit]
[-] class-appointment-type-model.php
[edit]
[-] class-notifications-settings.php
[edit]
[-] class-period.php
[edit]
[-] class-external-api.php
[edit]
[-] class-error-notices.php
[edit]
[-] class-availability-cache.php
[edit]
[-] class-developer-settings.php
[edit]
[-] class-dashboard-upcoming-appointments-widget.php
[edit]
[-] class-availability-external-model.php
[edit]
[-] class-availability-block.php
[edit]
[-] class-customer-information.php
[edit]
[+]
elementor
[-] class-appointment-type-label-model.php
[edit]
[-] class-embed-booking-app-api.php
[edit]
[+]
lib
[-] class-sequence.php
[edit]
[-] class-debug.php
[edit]
[-] class-appointment-types-db.php
[edit]