seed_settings(); $this->seed_statuses(); $staff_id = $this->seed_default_staff(); $location_id = $this->seed_default_location(); $this->seed_staff_location( $staff_id, $location_id ); $this->seed_default_availability( $staff_id, $location_id ); } private function seed_settings(): void { $settings = get_option( 'abientot_settings' ); if ( ! is_array( $settings ) ) { $settings = array(); } $defaults = array( 'delete_data_on_uninstall' => false, 'business_timezone' => wp_timezone_string(), 'currency' => 'USD', 'booking_min_notice_hours' => 24, 'booking_window_days' => 90, 'default_payment_status' => 'unpaid', 'payment_instructions' => __( 'Please pay on site at your appointment.', 'abientot' ), ); update_option( 'abientot_settings', array_merge( $defaults, $settings ), false ); } public const STATUS_LABELS_OPTION = 'abientot_status_labels_locale'; /** * English labels of the system statuses, as first installed. * * @return array */ public static function default_status_labels(): array { return array( 'pending' => 'Pending', 'confirmed' => 'Confirmed', 'completed' => 'Completed', 'cancelled' => 'Cancelled', 'no_show' => 'No-show', ); } /** * System status labels in the current language. * * @return array */ public static function translated_status_labels(): array { return array( 'pending' => _x( 'Pending', 'booking status', 'abientot' ), 'confirmed' => _x( 'Confirmed', 'booking status', 'abientot' ), 'completed' => _x( 'Completed', 'booking status', 'abientot' ), 'cancelled' => _x( 'Cancelled', 'booking status', 'abientot' ), 'no_show' => _x( 'No-show', 'booking status', 'abientot' ), ); } /** * Status names are business data shown in admin screens and customer emails. They are stored * in English at installation; this writes them in the site language. Only a label that is still * a default (English, or the default of the previous site language) changes: names the business * edited are kept. Runs again only when the site language changes. */ public static function localize_status_labels(): void { // Same language as the email templates: Abientot's language setting, else the site language. $locale = \Abientot\Admin\Settings::configured_locale(); $locale = '' !== $locale ? $locale : get_locale(); $state = get_option( self::STATUS_LABELS_OPTION ); if ( ( is_array( $state ) && ( $state['locale'] ?? '' ) === $locale ) || get_transient( self::STATUS_LABELS_OPTION . '_retry' ) ) { return; } try { $labels = \Abientot\Support\Translations::with_locale( $locale, array( self::class, 'translated_status_labels' ) ); } catch ( \InvalidArgumentException $error ) { $labels = self::default_status_labels(); // No Abientot catalogue for this language. } if ( 0 !== strpos( $locale, 'en_' ) && self::default_status_labels() === $labels ) { // No translation installed for this language yet (language pack pending): check again tomorrow. set_transient( self::STATUS_LABELS_OPTION . '_retry', 1, DAY_IN_SECONDS ); return; } global $wpdb; $previous = is_array( $state ) && is_array( $state['labels'] ?? null ) ? $state['labels'] : array(); foreach ( self::default_status_labels() as $slug => $english ) { $old = isset( $previous[ $slug ] ) && is_string( $previous[ $slug ] ) ? $previous[ $slug ] : $english; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- One-time update of the plugin's own status rows. $result = $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->prefix}abientot_booking_statuses SET label = %s, updated_at = %s WHERE slug = %s AND is_system = 1 AND label IN ( %s, %s )", $labels[ $slug ], gmdate( 'Y-m-d H:i:s' ), $slug, $english, $old ) ); if ( false === $result ) { return; // Try again on the next admin request. } } update_option( self::STATUS_LABELS_OPTION, array( 'locale' => $locale, 'labels' => $labels, ), true ); } private function seed_statuses(): void { global $wpdb; $table = $this->table( 'booking_statuses' ); $now = $this->now(); $statuses = array( array( 'pending', 'Pending', '#f59e0b', 1, 0, 1, 1, 10 ), array( 'confirmed', 'Confirmed', '#2563eb', 1, 0, 0, 1, 20 ), array( 'completed', 'Completed', '#16a34a', 1, 1, 0, 1, 30 ), array( 'cancelled', 'Cancelled', '#64748b', 0, 0, 0, 1, 40 ), array( 'no_show', 'No-show', '#dc2626', 0, 0, 0, 1, 50 ), ); foreach ( $statuses as $status ) { $exists = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->prefix}abientot_booking_statuses WHERE slug = %s", $status[0] ) ); if ( $exists ) { continue; } $wpdb->insert( $table, array( 'slug' => $status[0], 'label' => $status[1], 'color' => $status[2], 'blocks_availability' => $status[3], 'counts_as_revenue' => $status[4], 'is_default' => $status[5], 'is_system' => $status[6], 'sort_order' => $status[7], 'created_at' => $now, 'updated_at' => $now, ), array( '%s', '%s', '%s', '%d', '%d', '%d', '%d', '%d', '%s', '%s' ) ); } } private function seed_default_staff(): int { global $wpdb; $table = $this->table( 'staff' ); $id = (int) $wpdb->get_var( "SELECT id FROM {$wpdb->prefix}abientot_staff WHERE is_default = 1 ORDER BY id ASC LIMIT 1" ); if ( $id > 0 ) { return $id; } $now = $this->now(); $wpdb->insert( $table, array( 'display_name' => __( 'Default Staff', 'abientot' ), 'timezone' => wp_timezone_string(), 'is_default' => 1, 'status' => 'active', 'created_at' => $now, 'updated_at' => $now, ), array( '%s', '%s', '%d', '%s', '%s', '%s' ) ); return (int) $wpdb->insert_id; } private function seed_default_location(): int { global $wpdb; $table = $this->table( 'locations' ); $id = (int) $wpdb->get_var( "SELECT id FROM {$wpdb->prefix}abientot_locations WHERE is_default = 1 ORDER BY id ASC LIMIT 1" ); if ( $id > 0 ) { return $id; } $now = $this->now(); $wpdb->insert( $table, array( 'name' => __( 'Default Location', 'abientot' ), 'timezone' => wp_timezone_string(), 'is_default' => 1, 'status' => 'active', 'created_at' => $now, 'updated_at' => $now, ), array( '%s', '%s', '%d', '%s', '%s', '%s' ) ); return (int) $wpdb->insert_id; } private function seed_staff_location( int $staff_id, int $location_id ): void { global $wpdb; if ( $staff_id <= 0 || $location_id <= 0 ) { return; } $table = $this->table( 'staff_locations' ); $exists = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->prefix}abientot_staff_locations WHERE staff_id = %d AND location_id = %d", $staff_id, $location_id ) ); if ( $exists ) { return; } $wpdb->insert( $table, array( 'staff_id' => $staff_id, 'location_id' => $location_id, 'created_at' => $this->now(), ), array( '%d', '%d', '%s' ) ); } private function seed_default_availability( int $staff_id, int $location_id ): void { global $wpdb; if ( $staff_id <= 0 ) { return; } $table = $this->table( 'availability_rules' ); $existing = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->prefix}abientot_availability_rules WHERE staff_id = %d AND rule_type = %s", $staff_id, 'working' ) ); if ( $existing ) { return; } $now = $this->now(); for ( $weekday = 1; $weekday <= 5; $weekday++ ) { $wpdb->insert( $table, array( 'staff_id' => $staff_id, 'location_id' => $location_id > 0 ? $location_id : null, 'service_id' => null, 'weekday' => $weekday, 'start_time' => '09:00:00', 'end_time' => '17:00:00', 'rule_type' => 'working', 'is_active' => 1, 'created_at' => $now, 'updated_at' => $now, ), array( '%d', '%d', '%d', '%d', '%s', '%s', '%s', '%d', '%s', '%s' ) ); } } private function table( string $suffix ): string { global $wpdb; return $wpdb->prefix . 'abientot_' . $suffix; } private function now(): string { return gmdate( 'Y-m-d H:i:s' ); } }