get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM %i', $table ) ); if ( $exists > 0 ) { return; } $now = current_time( 'mysql', true ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Write to the plugin's own custom table; its cache group is invalidated right after. $wpdb->insert( $table, [ 'name' => 'Strategy Call', 'slug' => 'strategy-call', 'description' => 'A free 30-minute WordPressistic strategy call to map your automation goals.', 'short_description' => 'Free 30-minute consultation.', 'duration_minutes' => 30, 'buffer_before' => 0, 'buffer_after' => 10, 'price' => 0, 'category' => 'consultation', 'booking_type' => 'one_to_one', 'confirmation_mode' => 'auto', 'max_attendees' => 1, 'status' => 'active', 'sort_order' => 0, 'created_at' => $now, 'updated_at' => $now, ], [ '%s', '%s', '%s', '%s', '%d', '%d', '%d', '%f', '%s', '%s', '%s', '%d', '%s', '%d', '%s', '%s' ] ); wp_cache_delete( 'last_changed', Cache::SERVICES ); } private static function seed_default_settings(): void { if ( false === get_option( 'bookingistic_settings' ) ) { add_option( 'bookingistic_settings', [ 'business_name' => get_bloginfo( 'name' ), 'business_email' => get_option( 'admin_email' ), 'business_phone' => '', 'business_address' => '', 'from_name' => get_bloginfo( 'name' ), 'from_email' => get_option( 'admin_email' ), 'reply_to' => get_option( 'admin_email' ), 'admin_notify' => get_option( 'admin_email' ), 'staff_notify' => '', 'logo_url' => '', 'footer_text' => '', 'min_notice_hours' => 4, 'max_advance_days' => 60, 'slot_interval' => 15, 'cancel_window_hrs' => 12, 'reschedule_window_hrs' => 24, 'working_days' => [ 1, 2, 3, 4, 5 ], 'working_start' => '09:00', 'working_end' => '17:00', 'timezone' => wp_timezone_string(), ] ); } } private static function seed_default_email_automations(): void { global $wpdb; $table = Tables::email_automations_table(); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Activation-time existence check before seeding; must read live data so defaults are never seeded twice. $exists = (int) $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM %i', $table ) ); if ( $exists > 0 ) { return; } $now = current_time( 'mysql', true ); $defaults = [ [ 'name' => 'Customer confirmation', 'trigger_event' => 'booking_confirmed', 'recipient_type' => 'customer', 'delay_amount' => 0, 'delay_unit' => 'minutes', 'subject' => 'Your booking is confirmed — {service_name}', 'body' => "

Hi {customer_first_name},

\n

Your booking is confirmed.

\n

{service_name}
{booking_date} at {booking_time} ({booking_timezone})

\n

Need to make changes? Reschedule or cancel.

\n

— {business_name}

", ], [ 'name' => 'Admin notification', 'trigger_event' => 'booking_submitted', 'recipient_type' => 'admin', 'delay_amount' => 0, 'delay_unit' => 'minutes', 'subject' => 'New booking — {service_name} · {customer_name}', 'body' => "

New booking received.

\n", ], [ 'name' => 'Customer reminder (24h)', 'trigger_event' => 'booking_reminder', 'recipient_type' => 'customer', 'delay_amount' => 24, 'delay_unit' => 'hours', 'subject' => 'Reminder: {service_name} tomorrow', 'body' => "

Hi {customer_first_name},

\n

This is a reminder for your upcoming {service_name} on {booking_date} at {booking_time} ({booking_timezone}).

\n

— {business_name}

", ], [ 'name' => 'Customer cancellation', 'trigger_event' => 'booking_cancelled', 'recipient_type' => 'customer', 'delay_amount' => 0, 'delay_unit' => 'minutes', 'subject' => 'Your booking has been cancelled', 'body' => "

Hi {customer_first_name},

\n

Your booking for {service_name} on {booking_date} at {booking_time} has been cancelled.

\n

— {business_name}

", ], [ 'name' => 'Customer reschedule', 'trigger_event' => 'booking_rescheduled', 'recipient_type' => 'customer', 'delay_amount' => 0, 'delay_unit' => 'minutes', 'subject' => 'Your booking has been rescheduled', 'body' => "

Hi {customer_first_name},

\n

Your booking for {service_name} has been moved to {booking_date} at {booking_time} ({booking_timezone}).

\n

— {business_name}

", ], ]; foreach ( $defaults as $row ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Write to the plugin's own custom table; its cache group is invalidated right after. $wpdb->insert( $table, array_merge( $row, [ 'service_id' => 0, 'status' => 'active', 'created_at' => $now, 'updated_at' => $now, ] ) ); wp_cache_delete( 'last_changed', Cache::EMAIL_AUTOMATIONS ); } } }