2026-03-27 15:53:29 +00:00

1035 lines
30 KiB
PHP

<?php
/**
* Simply Schedule Appointments Support.
*
* @since 2.1.6
* @package Simply_Schedule_Appointments
*/
/**
* Simply Schedule Appointments Support.
*
* @since 2.1.6
*/
class SSA_Support {
/**
* Parent plugin class.
*
* @since 2.1.6
*
* @var Simply_Schedule_Appointments
*/
protected $plugin = null;
protected $secret_urls = array(
array(
'callback' => 'fix_appointment_durations',
'title' => 'Fix appointment durations',
'details' => 'Pass 1 as a parameter to update the end date of all appointments to match the duration of the appointment type.',
'param' => 'ssa-fix-appointment-durations',
'param_default_value' => '1'
),
array(
'callback' => 'fix_appointment_group_ids',
'title' => 'Fix appointment group ids',
'details' => 'Pass 1 as a parameter to update the group id of all appointments to match the group id of the first appointment in the group.',
'param' => 'ssa-fix-appointment-group-ids',
'param_default_value' => '1'
),
array(
'callback' => 'fix_db_datetime_schema',
'title' => 'Fix database datetime schema',
'details' => 'Pass 1 as a parameter to update the datetime schema of all appointments and appointment types.',
'param' => 'ssa-fix-db-datetime-schema',
'param_default_value' => '1'
),
array(
'callback' => 'fix_db_availability_schema',
'title' => 'Fix database availability schema',
'details' => 'Pass 1 as a parameter to drop and recreate the availability table.',
'param' => 'ssa-fix-db-availability-schema',
'param_default_value' => '1'
),
array(
'callback' => 'fix_appointment_types',
'title' => 'Fix appointment types',
'details' => 'Pass 1 as a parameter to update the custom customer information and customer information fields of all appointment types',
'param' => 'ssa-fix-appointment-types',
'param_default_value' => '1'
),
array(
'callback' => 'fix_missing_appointment_types',
'title' => 'Fix missing appointment types',
'details' => 'Pass 1 as a parameter to update appointments with appointment types replacing the deleted ones.',
'param' => 'ssa-fix-missing-appointment-types',
'param_default_value' => '1'
),
array(
'callback' => 'purge_abandoned_appointments',
'title' => 'Purge abandoned appointments',
'details' => 'Pass 1 as a parameter to delete all appointments with a status of "abandoned" from the database.',
'param' => 'ssa-purge-abandoned-appointments',
'param_default_value' => '1'
),
array(
'callback' => 'ssa_factory_reset',
'title' => 'Factory reset SSA',
'details' => 'Pass 1 as a parameter to delete all SSA settings from the database and truncate all SSA database tables.',
'param' => 'ssa-factory-reset',
'param_default_value' => '1'
),
array(
'callback' => 'rebuild_db',
'title' => 'Rebuild SSA database',
'details' => 'Pass 1 as a parameter to recreate all SSA database tables.',
'param' => 'ssa-rebuild-db',
'param_default_value' => '1'
),
array(
'callback' => 'clear_google_cache',
'title' => 'Clear Google cache',
'details' => 'Pass 1 as a parameter to clear the Google Calendar cache.',
'param' => 'ssa-clear-google-cache',
'param_default_value' => '1'
),
array(
'callback' => 'set_google_query_limit',
'title' => 'Set Google Calendar query limit',
'details' => 'Pass a new limit to use for Google Calendar events. SSA defaults to 500.',
'param' => 'ssa-set-google-query-limit',
'param_default_value' => '500'
),
array(
'callback' => 'clear_all_cache',
'title' => 'Clear all cache',
'details' => 'Pass 1 as a parameter to clear all cache.',
'param' => 'ssa-clear-all-cache',
'param_default_value' => '1'
),
array(
'callback' => 'populate_cache',
'title' => 'Populate cache',
'details' => 'Pass 1 as a parameter to populate the cache.',
'param' => 'ssa-populate-cache',
'param_default_value' => '1'
),
array(
'callback' => 'restore_plugin_backup',
'title' => 'Restore plugin backup',
'details' => 'Pass 1 as a parameter to restore the last backup of the plugin settings.',
'param' => 'ssa-restore-backup',
'param_default_value' => '1'
),
array(
'callback' => 'bulk_send_notifications',
'title' => 'Bulk send notifications',
'details' => 'Pass 1 as a parameter to send notifications for all future booked appointments.',
'param' => 'ssa-resend-booked-notifications',
'param_default_value' => '1'
),
array(
'callback' => 'set_display_capacity_available',
'title' => 'Set display capacity available',
'details' => 'Pass 1 as a parameter to set the display capacity available setting to true. Pass 0 as a parameter to set the display capacity available setting to false.',
'param' => 'ssa-set-display-capacity-available',
'param_default_value' => '1'
),
array(
'callback' => 'ssa_set_license',
'title' => 'Set license',
'details' => 'Pass the license key as a parameter to activate it.',
'param' => 'ssa-set-license',
'param_default_value' => '1'
),
array(
'callback' => 'ssa_set_debug_level',
'title' => 'Set debug level',
'details' => 'Pass the debug level as a parameter to set the ssa_debug_level option.',
'param' => 'ssa-set-debug-level',
'param_default_value' => '10'
),
array(
'callback' => 'ssa_cleanup_excluded_calendars',
'title' => 'Clean up excluded calendars for main calendar and staff profiles',
'details' => 'Will remove any excluded calendars that are not accessible by SSA. Both from the main calendar and staff profiles.',
'param' => 'ssa-cleanup-excluded-calendars',
'param_default_value' => '1'
),
array(
'callback' => 'ssa_remove_all_appointments',
'title' => 'Removes all appointments and their associated data',
'details' => 'Will totally remove all appointments and their associated data from the database. This cannot be undone!',
'param' => 'ssa-remove-all-appointments',
'param_default_value' => '1'
),
);
/**
* Constructor.
*
* @since 2.1.6
*
* @param Simply_Schedule_Appointments $plugin Main plugin object.
*/
public function __construct( $plugin ) {
$this->plugin = $plugin;
$this->hooks();
}
/**
* Initiate our hooks.
*
* @since 2.1.6
*/
public function hooks() {
foreach( $this->secret_urls as $secret_url ) {
if ( ! method_exists( $this, $secret_url['callback'] ) ) {
// if method does not exist on this class
// throw an exception here to catch the problems in the CI/CD pipeline
throw new Exception( 'Method does not exist on this class: ' . $secret_url['callback'] );
}
add_action( 'admin_init', array( $this, $secret_url['callback'] ) );
}
// maybe render support page
add_action( 'admin_init', array( $this, 'render_secret_support_page' ), 0 );
}
/**
* Render support page.
* Called from wp-admin/admin.php
*/
public function render_secret_support_page() {
if ( empty( $_GET['ssa-support-admin'] ) || $_GET['ssa-support-admin'] !== '1') {
return;
}
if( !current_user_can( 'ssa_manage_site_settings' ) ) {
return;
}
header( 'Content-Type: text/html' );
?>
<main>
<style>
* {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
main {
padding: 40px;
}
main > div > * {
margin-bottom: 20px;
}
h1 {
font-size: 2em;
}
h2 {
font-size: 1.5em;
}
p {
font-size: 1em;
}
.danger {
color: red;
}
.actions-container {
display: flex;
flex-direction: column;
gap: 50px;
}
.actions-container section {
border-top: 1px solid #ccc;
padding-top: 20px;
display: flex;
flex-direction: column;
gap: 20px;
}
section span {
display: flex;
gap: 80px;
}
.link {
color: blue;
margin-right: auto;
}
input {
height: 30px;
padding: 10px;
}
</style>
<div>
<h1 class="danger"><?php echo home_url()?></h1>
<h2>You are on the SSA secret support page</h2>
<p>This is available to site administrators only, and should only be used for debugging and support purposes.</p>
</div>
<br>
<h2>Actions</h2>
<div class="actions-container">
<?php
foreach( $this->secret_urls as $secret_url ) {
$nonce = wp_create_nonce( $secret_url['param'] );
$link = admin_url() . '?ssa_nonce=' . $nonce . '&' . $secret_url['param'] . '=' . $secret_url['param_default_value'];
echo $this->generateSupportUrl($secret_url, $link);
}
?>
</div>
</main>
<?php
// exit to avoid rendering any other content
exit;
}
/**
* Generate a support url
*/
public function generateSupportUrl( $secret_url, $link ) {
return '
<section>
<h3>' . $secret_url['title'] . '</h3>' .
( empty($secret_url['details']) ? '' : '<p>' . $secret_url['details'] .'</p>' ) .
'<a class="link" href="' . $link . '" id="' . $secret_url['param'] . '-link">' . $link . '</a>
</section>
';
}
/**
* Remove all appointments and their associated data. Keeping SSA settings and appointment types intact.
*
* @return void
*/
public function ssa_remove_all_appointments () {
if ( empty( $_GET['ssa-remove-all-appointments'] ) ) {
return;
}
if (!current_user_can('ssa_manage_site_settings')) {
return;
}
if ( wp_verify_nonce( $_GET['ssa_nonce'], 'ssa-remove-all-appointments' ) === false ) {
return;
}
$appointments_to_delete = $this->plugin->appointment_model->query( array(
'number' => -1,
) );
$appointments_to_delete_ids = wp_list_pluck( $appointments_to_delete, 'id' );
$revisions_to_delete = $this->plugin->revision_model->query( array(
'number' => -1,
'appointment_id' => $appointments_to_delete_ids,
) );
$revisions_to_delete_ids = wp_list_pluck( $revisions_to_delete, 'id' );
$revision_meta_to_delete = $this->plugin->revision_meta_model->query( array(
'number' => -1,
'revision_id' => $revisions_to_delete_ids,
) );
// remove all appointment async actions
$this->plugin->async_action_model->bulk_delete( array(
'number' => -1,
'object_type' => 'appointment',
) );
$this->plugin->revision_meta_model->bulk_delete( wp_list_pluck( $revision_meta_to_delete, 'id' ) );
$this->plugin->revision_model->bulk_delete( wp_list_pluck( $revisions_to_delete, 'id' ) );
$this->plugin->resource_appointment_model->truncate();
$this->plugin->payment_model->truncate();
$this->plugin->appointment_meta_model->truncate();
$this->plugin->appointment_model->truncate();
}
/**
* Removes GCAL excluded calendars that the user removed their subscription to. Both from the main calendar and staff profiles.
*
*/
public function ssa_cleanup_excluded_calendars () {
if ( empty( $_GET['ssa-cleanup-excluded-calendars'] ) ) {
return;
}
if (!current_user_can('ssa_manage_site_settings')) {
return;
}
if ( wp_verify_nonce( $_GET['ssa_nonce'], 'ssa-cleanup-excluded-calendars' ) === false ) {
return;
}
// cleanup main excluded calendars
$this->plugin->appointment_type_model->cleanup_main_excluded_calendars();
$this->plugin->staff_model->cleanup_staff_excluded_calendars();
wp_redirect( remove_query_arg( 'ssa-cleanup-excluded-calendars' ) );
exit;
}
/**
* Set the debug level.
* Used to write logs of levels lower than 10.
*
*/
public function ssa_set_debug_level() {
if ( empty( $_GET['ssa-set-debug-level'] ) ) {
return;
}
if (!current_user_can('ssa_manage_site_settings')) {
return;
}
if ( wp_verify_nonce( $_GET['ssa_nonce'], 'ssa-set-debug-level' ) === false ) {
return;
}
$debug_level = (int) sanitize_text_field( $_GET['ssa-set-debug-level'] );
update_option( 'ssa_debug_level', $debug_level );
wp_redirect( remove_query_arg( 'ssa-set-debug-level' ) );
exit;
}
public function ssa_set_license() {
if ( empty( $_GET['ssa-set-license'] )) {
return;
}
if (!current_user_can('ssa_manage_site_settings')) {
return;
}
if ( wp_verify_nonce( $_GET['ssa_nonce'], 'ssa-set-license' ) === false ) {
return;
}
$license_key = sanitize_text_field( $_GET['ssa-set-license'] );
$this->plugin->license->activate( $license_key );
wp_redirect( remove_query_arg( 'ssa-set-license' ) );
exit;
}
public function populate_cache() {
if ( empty( $_GET['ssa-populate-cache'] ) ) {
return;
}
if ( ! current_user_can( 'ssa_manage_site_settings' ) ) {
return;
}
if ( wp_verify_nonce( $_GET['ssa_nonce'], 'ssa-populate-cache' ) === false ) {
return;
}
$this->plugin->availability_cache->populate_cache();
wp_redirect( remove_query_arg( 'ssa-populate-cache' ) );
exit;
}
public function clear_google_cache() {
if ( empty( $_GET['ssa-clear-google-cache'] ) ) {
return;
}
if ( ! current_user_can( 'ssa_manage_site_settings' ) ) {
return;
}
if ( wp_verify_nonce( $_GET['ssa_nonce'], 'ssa-clear-google-cache' ) === false ) {
return;
}
$this->plugin->availability_external_model->bulk_delete( array(
'service' => 'google',
) );
$this->plugin->google_calendar->increment_google_cache_version();
wp_redirect( remove_query_arg( 'ssa-clear-google-cache' ) );
exit;
}
public function set_google_query_limit() {
if ( empty( $_GET['ssa-set-google-query-limit'] ) ) {
return;
}
if ( ! current_user_can( 'ssa_manage_site_settings' ) ) {
return;
}
if ( wp_verify_nonce( $_GET['ssa_nonce'], 'ssa-set-google-query-limit' ) === false ) {
return;
}
$set_google_query_limit = (int)esc_attr( $_GET['ssa-set-google-query-limit'] );
if ( empty( $set_google_query_limit ) ) {
return;
}
$this->plugin->google_calendar_settings->update( array(
'query_limit' => $set_google_query_limit,
) );
$this->plugin->google_calendar->increment_google_cache_version();
wp_redirect( remove_query_arg( 'ssa-set-google-query-limit' ) );
exit;
}
public function set_display_capacity_available() {
if ( ! isset ( $_GET['ssa-set-display-capacity-available'] ) ) {
return;
}
if (!current_user_can('ssa_manage_site_settings')) {
return;
}
if ( wp_verify_nonce( $_GET['ssa_nonce'], 'ssa-set-display-capacity-available' ) === false ) {
return;
}
// if ( ! is_user_logged_in() ) {
// return;
// }
$new_value = (bool) $_GET['ssa-set-display-capacity-available'];
$developer_settings = $this->plugin->developer_settings->get();
$developer_settings['display_capacity_available'] = $new_value;
$this->plugin->developer_settings->update( $developer_settings );
$this->plugin->availability_cache_invalidation->increment_cache_version();
wp_redirect( remove_query_arg( 'ssa-set-display-capacity-available' ) );
exit;
}
public function clear_all_cache() {
if ( empty( $_GET['ssa-clear-all-cache'] ) ) {
return;
}
if ( ! current_user_can( 'ssa_manage_site_settings' ) ) {
return;
}
if ( wp_verify_nonce( $_GET['ssa_nonce'], 'ssa-clear-all-cache' ) === false ) {
return;
}
$this->plugin->availability_external_model->bulk_delete( array(
'service' => 'google',
) );
$this->plugin->google_calendar->increment_google_cache_version();
$this->plugin->availability_cache_invalidation->increment_cache_version();
wp_redirect( remove_query_arg( 'ssa-clear-all-cache' ) );
exit;
}
public function fix_appointment_durations() {
if ( empty( $_GET['ssa-fix-appointment-durations'] ) ) {
return;
}
if ( ! current_user_can( 'ssa_manage_site_settings' ) ) {
return;
}
if ( wp_verify_nonce( $_GET['ssa_nonce'], 'ssa-fix-appointment-durations' ) === false ) {
return;
}
$appointments = $this->plugin->appointment_model->query( array(
'number' => -1,
) );
$now = new DateTimeImmutable();
foreach ($appointments as $key => $appointment) {
if ( empty( $appointment['appointment_type_id'] ) ) {
continue; // likely an abandoned appointment from a form integration (where an appointment type was never selected)
}
$appointment_type = new SSA_Appointment_Type_Object( $appointment['appointment_type_id'] );
$duration = $appointment_type->duration;
$start_date = new DateTimeImmutable( $appointment['start_date'] );
$end_date = $start_date->add( new DateInterval( 'PT' .$duration. 'M' ) );
if ( $end_date->format( 'Y-m-d H:i:s' ) != $appointment['end_date'] ) {
echo '<pre>'.print_r($appointment, true).'</pre>'; // phpcs:ignore
$appointment['end_date'] = $end_date->format( 'Y-m-d H:i:s' );
$this->plugin->appointment_model->update( $appointment['id'], $appointment );
}
}
wp_redirect( $this->plugin->wp_admin->url(), $status = 302);
exit;
}
public function purge_abandoned_appointments() {
if ( empty( $_GET['ssa-purge-abandoned-appointments'] ) ) {
return;
}
if ( ! current_user_can( 'ssa_manage_site_settings' ) ) {
return;
}
if ( wp_verify_nonce( $_GET['ssa_nonce'], 'ssa-purge-abandoned-appointments' ) === false ) {
return;
}
$this->plugin->appointment_model->delete_abandoned();
wp_redirect( $this->plugin->wp_admin->url(), $status = 302);
exit;
}
public function fix_db_availability_schema() {
if ( empty( $_GET['ssa-fix-db-availability-schema'] ) ) {
return;
}
if ( ! current_user_can( 'ssa_manage_site_settings' ) ) {
return;
}
if ( wp_verify_nonce( $_GET['ssa_nonce'], 'ssa-fix-db-availability-schema' ) === false ) {
return;
}
$this->plugin->availability_model->drop();
$this->plugin->availability_model->create_table();
wp_redirect( $this->plugin->wp_admin->url(), $status = 302);
exit;
}
public function fix_appointment_types() {
if ( empty( $_GET['ssa-fix-appointment-types'] ) ) {
return;
}
if ( ! current_user_can( 'ssa_manage_site_settings' ) ) {
return;
}
if ( wp_verify_nonce( $_GET['ssa_nonce'], 'ssa-fix-appointment-types' ) === false ) {
return;
}
$appointment_types = $this->plugin->appointment_type_model->query( array(
'number' => -1,
) );
foreach ($appointment_types as $appointment_type) {
if ( empty( $appointment_type['custom_customer_information'] ) ) {
$appointment_type['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' => '',
),
);
}
if ( empty( $appointment_type['customer_information'] ) ) {
$appointment_type['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' => '',
),
);
}
$appointment_type['custom_customer_information'] = array_values( (array) $appointment_type['custom_customer_information'] );
$appointment_type['customer_information'] = array_values( (array) $appointment_type['customer_information'] );
$appointment_types = $this->plugin->appointment_type_model->update(
$appointment_type['id'],
$appointment_type
);
}
wp_redirect( $this->plugin->wp_admin->url(), $status = 302);
exit;
}
public function fix_missing_appointment_types() {
if ( empty( $_GET['ssa-fix-missing-appointment-types'] ) ) {
return;
}
if ( ! current_user_can( 'ssa_manage_site_settings' ) ) {
return;
}
if ( wp_verify_nonce( $_GET['ssa_nonce'], 'ssa-fix-missing-appointment-types' ) === false ) {
return;
}
$this->plugin->upgrade->maybe_fix_deleted_appointment_types();
wp_redirect( $this->plugin->wp_admin->url(), $status = 302);
exit;
}
public function fix_db_datetime_schema() {
if ( empty( $_GET['ssa-fix-db-datetime-schema'] ) ) {
return;
}
if ( ! current_user_can( 'ssa_manage_site_settings' ) ) {
return;
}
if ( wp_verify_nonce( $_GET['ssa_nonce'], 'ssa-fix-db-datetime-schema' ) === false ) {
return;
}
global $wpdb;
$now = gmdate( 'Y-m-d H:i:s' );
$before_queries = array(
/* Appointment Types */
"UPDATE {$this->plugin->appointment_type_model->get_table_name()} SET `booking_start_date`='".SSA_Constants::EPOCH_START_DATE."' WHERE `booking_start_date`=0",
"UPDATE {$this->plugin->appointment_type_model->get_table_name()} SET `booking_end_date`='".SSA_Constants::EPOCH_END_DATE."' WHERE `booking_end_date`=0",
"UPDATE {$this->plugin->appointment_type_model->get_table_name()} SET `availability_start_date`='".SSA_Constants::EPOCH_START_DATE."' WHERE `availability_start_date`=0",
"UPDATE {$this->plugin->appointment_type_model->get_table_name()} SET `availability_end_date`='".SSA_Constants::EPOCH_END_DATE."' WHERE `availability_end_date`=0",
"UPDATE {$this->plugin->appointment_type_model->get_table_name()} SET `date_created`='1970-01-01' where `date_created`=0",
"UPDATE {$this->plugin->appointment_type_model->get_table_name()} SET `date_modified`='1970-01-01' where `date_modified`=0",
/* Appointments */
"UPDATE {$this->plugin->appointment_model->get_table_name()} SET `start_date`='1970-01-01' where `start_date`=0",
"UPDATE {$this->plugin->appointment_model->get_table_name()} SET `end_date`='1970-01-01' where `end_date`=0",
"UPDATE {$this->plugin->appointment_model->get_table_name()} SET `date_created`='1970-01-01' where `date_created`=0",
"UPDATE {$this->plugin->appointment_model->get_table_name()} SET `date_modified`='1970-01-01' where `date_modified`=0",
);
$after_queries = array(
/* Appointment Types */
"UPDATE {$this->plugin->appointment_type_model->get_table_name()} SET `booking_start_date`=NULL where `booking_start_date`='".SSA_Constants::EPOCH_START_DATE."'",
"UPDATE {$this->plugin->appointment_type_model->get_table_name()} SET `booking_end_date`=NULL where `booking_end_date`='".SSA_Constants::EPOCH_END_DATE."'",
"UPDATE {$this->plugin->appointment_type_model->get_table_name()} SET `availability_start_date`=NULL where `availability_start_date`='".SSA_Constants::EPOCH_START_DATE."'",
"UPDATE {$this->plugin->appointment_type_model->get_table_name()} SET `availability_end_date`=NULL where `availability_end_date`='".SSA_Constants::EPOCH_END_DATE."'",
);
$has_failed = false;
foreach ($before_queries as $query) {
$result = $wpdb->query( $query );
if ( false === $result ) {
$has_failed = true;
}
}
$this->plugin->appointment_type_model->create_table();
$this->plugin->appointment_model->create_table();
foreach ($after_queries as $query) {
$result = $wpdb->query( $query );
if ( false === $result ) {
$has_failed = true;
}
}
$this->fix_appointment_group_ids( true );
wp_redirect( $this->plugin->wp_admin->url(), $status = 302);
exit;
}
public function fix_appointment_group_ids( $force = false ) {
if ( empty( $force ) && empty( $_GET['ssa-fix-appointment-group-ids'] ) ) {
return;
}
if ( ! current_user_can( 'ssa_manage_site_settings' ) ) {
return;
}
if ( wp_verify_nonce( $_GET['ssa_nonce'], 'ssa-fix-appointment-group-ids' ) === false ) {
return;
}
$appointments = $this->plugin->appointment_model->query( array(
'number' => -1,
) );
$now = new DateTimeImmutable();
foreach ($appointments as $key => $appointment) {
if ( ! empty( $appointment['group_id'] ) ) {
continue;
}
$appointment_type = new SSA_Appointment_Type_Object( $appointment['appointment_type_id'] );
$capacity_type = $appointment_type->capacity_type;
if ( empty( $capacity_type ) || $capacity_type !== 'group' ) {
continue;
}
$start_date = new DateTimeImmutable( $appointment['start_date'] );
$args = array(
'number' => -1,
'orderby' => 'id',
'order' => 'ASC',
'appointment_type_id' => $appointment['appointment_type_id'],
'start_date' => $appointment['start_date'],
'exclude_ids' => $appointment['id'],
);
$new_group_id = 0;
$appointment_arrays = $this->plugin->appointment_model->query( $args );
foreach ($appointment_arrays as $appointment_array) {
if ( ! empty( $appointment_array['group_id'] ) ) {
$new_group_id = $appointment_array['group_id'];
}
}
if ( empty( $new_group_id ) && empty( $appointment_arrays[0]['id'] ) ) {
continue;
}
$new_group_id = $appointment_arrays[0]['id'];
$this->plugin->appointment_model->update( $appointment['id'], array(
'group_id' => $new_group_id
) );
foreach ($appointment_arrays as $appointment_array) {
$this->plugin->appointment_model->update( $appointment_array['id'], array(
'group_id' => $new_group_id
) );
}
}
wp_redirect( $this->plugin->wp_admin->url(), $status = 302);
exit;
}
/**
* Deletes all ssa related options from wp_options table and truncate all ssa database tables.
*
* @since 5.4.3
*
* @return void
*/
public function ssa_factory_reset() {
if ( empty( $_GET['ssa-factory-reset'] ) ) { // phpcs:ignore
return;
}
if ( ! current_user_can( 'ssa_manage_site_settings' ) ) {
return;
}
if ( wp_verify_nonce( $_GET['ssa_nonce'], 'ssa-factory-reset' ) === false ) {
return;
}
// Finds and delete all rows from the wp_options table that contains "ssa_" in the option_name column.
global $wpdb;
$wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE 'ssa\_%'" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
// Truncate all ssa database tables.
$this->plugin->appointment_model->truncate();
$this->plugin->appointment_meta_model->truncate();
$this->plugin->appointment_type_model->truncate();
$this->plugin->availability_model->truncate();
$this->plugin->availability_external_model->truncate();
$this->plugin->async_action_model->truncate();
$this->plugin->payment_model->truncate();
$this->plugin->staff_model->truncate();
$this->plugin->staff_appointment_model->truncate();
$this->plugin->staff_appointment_type_model->truncate();
$this->plugin->resource_model->truncate();
$this->plugin->resource_group_model->truncate();
$this->plugin->resource_group_resource_model->truncate();
$this->plugin->resource_group_appointment_type_model->truncate();
$this->plugin->resource_appointment_model->truncate();
$this->plugin->revision_model->truncate();
$this->plugin->revision_meta_model->truncate();
wp_safe_redirect( $this->plugin->wp_admin->url(), $status = 302 );
exit;
}
public function rebuild_db() {
if ( empty( $_GET['ssa-rebuild-db'] ) ) {
return;
}
if ( ! current_user_can( 'ssa_manage_site_settings' ) ) {
return;
}
if ( wp_verify_nonce( $_GET['ssa_nonce'], 'ssa-rebuild-db' ) === false ) {
return;
}
$this->plugin->appointment_model->create_table();
$this->plugin->appointment_meta_model->create_table();
$this->plugin->appointment_type_model->create_table();
$this->plugin->appointment_type_label_model->create_table();
$this->plugin->availability_model->create_table();
$this->plugin->availability_external_model->create_table();
$this->plugin->async_action_model->create_table();
$this->plugin->payment_model->create_table();
$this->plugin->revision_model->create_table();
$this->plugin->revision_meta_model->create_table();
$this->plugin->resource_appointment_model->create_table();
$this->plugin->resource_group_appointment_type_model->create_table();
$this->plugin->resource_model->create_table();
$this->plugin->resource_group_model->create_table();
$this->plugin->resource_group_resource_model->create_table();
$this->plugin->staff_model->create_table();
$this->plugin->staff_appointment_model->create_table();
$this->plugin->staff_appointment_type_model->create_table();
wp_redirect( $this->plugin->wp_admin->url(), $status = 302);
exit;
}
public function restore_plugin_backup() {
if ( empty( $_GET['ssa-restore-backup'] ) ) {
return;
}
if ( ! current_user_can( 'ssa_manage_site_settings' ) ) {
return;
}
if ( wp_verify_nonce( $_GET['ssa_nonce'], 'ssa-restore-backup' ) === false ) {
return;
}
// restore previous backup file
$restore = $this->plugin->support_status->restore_settings_backup();
// if something happens, print the errors
if( is_wp_error( $restore ) ) {
$string = implode("\n", $restore->get_error_messages());
wp_die($string);
}
wp_redirect( $this->plugin->wp_admin->url(), $status = 302);
exit;
}
/**
* Given a GET parameter on the url, get a list of future booked appointments and schedule notifications for the ones that are valid.
*
* @since 4.8.8
*
* @return void
*/
public function bulk_send_notifications() {
if ( empty( $_GET['ssa-resend-booked-notifications'] ) ) {
return;
}
if ( ! current_user_can( 'ssa_manage_site_settings' ) ) {
return;
}
if ( wp_verify_nonce( $_GET['ssa_nonce'], 'ssa-resend-booked-notifications' ) === false ) {
return;
}
// Get list of booked appointments.
$appointments = $this->plugin->appointment_model->query(
array(
'status' => SSA_Appointment_Model::get_booked_statuses(),
'start_date_min' => gmdate( 'Y-m-d H:i:s' ),
'number' => -1,
)
);
$notifications = $this->plugin->notifications_settings->get_notifications();
if ( empty( $notifications ) ) {
wp_safe_redirect( $this->plugin->wp_admin->url(), $status = 302 );
exit;
}
// filter list of notifications to return only the one to be sent to the customer.
$customer_booked_notifications = array_values(
array_filter(
$notifications,
function( $notification ) {
return (
( !isset( $notification['active'] ) || true == $notification['active'] ) &&
'appointment_booked' === $notification['trigger'] &&
strpos( implode( ';', $notification['sent_to'] ), 'customer_email' ) !== false
);
}
)
);
// If notification is found, then send list of appointments to validate the notification and possibly send them.
if ( ! empty( $customer_booked_notifications ) ) {
foreach ( $customer_booked_notifications as $customer_booked_notification ) {
$this->plugin->action_scheduler->bulk_schedule_notifications( $customer_booked_notification, $appointments );
}
}
wp_safe_redirect( $this->plugin->wp_admin->url(), $status = 302 );
exit();
}
public static function should_display_support_tab() {
// hide support tab via wp-config
if( defined( 'SSA_DISPLAY_SUPPORT_TAB' ) && false === SSA_DISPLAY_SUPPORT_TAB ) {
return false;
}
if( is_multisite() && ! current_user_can('manage_network') ) {
return false;
}
return true;
}
}