getMessage() ); } } /** * Run schema upgrades on plugin update (the activation hook does not fire on * an in-place "replace current with uploaded" update). Idempotent — dbDelta * only applies the diff. Called from plugins_loaded. * * @return void */ public static function maybe_upgrade(): void { try { $current = defined( 'SIXRSH_DB_VERSION' ) ? SIXRSH_DB_VERSION : '1'; if ( get_option( 'sixrsh_db_version' ) === $current ) { return; } self::create_tables(); update_option( 'sixrsh_db_version', $current ); } catch ( \Throwable $e ) { error_log( '[6rsh WhatsApp] Activator::maybe_upgrade exception: ' . $e->getMessage() ); } } /** * Adopt settings saved by the legacy "6rsh-whatsapp" plugin so a store keeps * its API key and configuration after switching to this renamed plugin. * * The renamed plugin keeps the SAME `sixrsh_*` option namespace as the legacy * plugin, so options written by 6rsh-whatsapp are read directly with no key * change. This pass runs once, is idempotent, and NEVER overwrites a value the * new install has already set — it only fills a key that is currently absent. * * NOTE: if the old plugin is *deleted* (not just deactivated) its uninstall.php * removes the `sixrsh_*` options first — in that case there is nothing left to * adopt. Safe order: deactivate old → install + activate new → verify → delete old. * * @return void */ public static function migrate_legacy_settings(): void { try { if ( get_option( 'sixrsh_settings_migrated' ) ) { return; // already done } // Legacy option keys written by the 6rsh-whatsapp plugin. $keys = array( 'sixrsh_api_key', 'sixrsh_connected_account', 'sixrsh_connected_phone', 'sixrsh_template_mapping', 'sixrsh_settings', 'sixrsh_country_code', 'sixrsh_order_sync_enabled', 'sixrsh_product_sync_enabled', 'sixrsh_followup_rule_1', 'sixrsh_followup_rule_2', 'sixrsh_wizard_complete', ); $adopted = array(); foreach ( $keys as $key ) { $legacy = get_option( $key, null ); // Same-namespace adoption: a legacy value is already stored under // this exact key, so the new plugin reads it as-is. Record it for // auditing; do not overwrite if somehow already managed elsewhere. if ( null !== $legacy && false !== $legacy ) { $adopted[] = $key; } } if ( ! empty( $adopted ) ) { error_log( '[6rsh] Adopted legacy settings from 6rsh-whatsapp: ' . implode( ', ', $adopted ) ); } update_option( 'sixrsh_settings_migrated', defined( 'SIXRSH_VERSION' ) ? SIXRSH_VERSION : '1.4.0' ); } catch ( \Throwable $e ) { error_log( '[6rsh] Activator::migrate_legacy_settings exception: ' . $e->getMessage() ); } } /** * Check if we should redirect to the wizard on admin_init. * * @return void */ public static function check_redirect(): void { try { if ( ! is_admin() ) { return; } if ( wp_doing_ajax() ) { return; } if ( get_option( 'sixrsh_wizard_complete' ) ) { return; } if ( ! get_transient( 'sixrsh_wizard_redirect' ) ) { return; } delete_transient( 'sixrsh_wizard_redirect' ); $wizard_url = admin_url( 'admin.php?page=6rsh-messaging-notifications&setup=1' ); wp_safe_redirect( $wizard_url ); exit; } catch ( \Throwable $e ) { error_log( '[6rsh WhatsApp] Activator::check_redirect exception: ' . $e->getMessage() ); } } /** * Run on plugin deactivation. * * @return void */ public static function deactivate(): void { try { // Remove all scheduled plugin events. wp_clear_scheduled_hook( 'sixrsh_send_order_notification' ); wp_clear_scheduled_hook( 'sixrsh_send_customer_notification' ); wp_clear_scheduled_hook( 'sixrsh_sync_cart' ); wp_clear_scheduled_hook( 'sixrsh_cron_cleanup' ); } catch ( \Throwable $e ) { error_log( '[6rsh WhatsApp] Activator::deactivate exception: ' . $e->getMessage() ); } } /** * Create (or upgrade) the custom database tables. * * @return void */ private static function create_tables(): void { global $wpdb; require_once ABSPATH . 'wp-admin/includes/upgrade.php'; $charset_collate = $wpdb->get_charset_collate(); $prefix = $wpdb->prefix; $carts_table = "CREATE TABLE {$prefix}sixrsh_carts ( cart_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, cart_token VARCHAR(64) NOT NULL, user_phone VARCHAR(30) NOT NULL DEFAULT '', user_email VARCHAR(191) NOT NULL DEFAULT '', opt_in TINYINT(1) NOT NULL DEFAULT 1, items_json TEXT NOT NULL, cart_value DECIMAL(12,2) NOT NULL DEFAULT 0.00, currency VARCHAR(10) NOT NULL DEFAULT '', checkout_url VARCHAR(2048) NOT NULL DEFAULT '', captured_at DATETIME NOT NULL, last_activity_at DATETIME NOT NULL, status ENUM('open','closed','synced') NOT NULL DEFAULT 'open', synced_at DATETIME NULL, PRIMARY KEY (cart_id), UNIQUE KEY cart_token (cart_token) ) {$charset_collate};"; $logs_table = "CREATE TABLE {$prefix}sixrsh_logs ( log_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, event_type VARCHAR(50) NOT NULL DEFAULT '', customer_phone VARCHAR(30) NOT NULL DEFAULT '', template_name VARCHAR(100) NOT NULL DEFAULT '', status ENUM('success','failed') NOT NULL DEFAULT 'failed', error_message TEXT NOT NULL, created_at DATETIME NOT NULL, PRIMARY KEY (log_id), KEY idx_event_status (event_type, status), KEY idx_created_at (created_at) ) {$charset_collate};"; dbDelta( $carts_table ); dbDelta( $logs_table ); } }