time() - 10 * MINUTE_IN_SECONDS ) { return; } update_option( $mark, (string) time(), false ); } if ( self::setup() !== '' ) { return; } delete_option( $mark ); // The signed-in user's permissions were read before init: StoreRuler's menu shows on this very request. $user = wp_get_current_user(); if ( $user->exists() ) { $user->get_role_caps(); } } /** The current site's setup (activate(), setup_network_site()): '' once done, otherwise what stopped it. */ private static function setup() : string { $previous_version = (string) get_option( 'storesuit_version', '' ); if ( $previous_version !== '' && version_compare( $previous_version, STORESUIT_VERSION, '>' ) ) { return I18n::t( 'This store has data from a newer StoreRuler version. Install that version or newer before continuing.' ); } if ( !class_exists( 'WooCommerce' ) ) { return I18n::t( 'WooCommerce must be activated first.' ); } require_once __DIR__ . '/Store.php'; require_once __DIR__ . '/CartSignals.php'; require_once __DIR__ . '/OrderAlerts.php'; require_once __DIR__ . '/Roles.php'; require_once __DIR__ . '/DashboardFacts.php'; Store::install(); CartSignals::install(); OrderAlerts::install(); DashboardFacts::install(); $schemas = get_option( 'storesuit_schema' ) === '2'; if ( !$schemas || get_option( 'storesuit_dashboard_facts_schema' ) !== '1' ) { return I18n::t( 'StoreRuler record storage could not be prepared. No business records were removed; ask your host to check the database and try again.' ); } foreach ( array('administrator', 'shop_manager') as $name ) { $role = get_role( $name ); if ( $role ) { foreach ( array( 'storesuit_orders', 'storesuit_fulfil', 'storesuit_finance', 'storesuit_approve' ) as $cap ) { $role->add_cap( $cap ); } } } delete_option( 'storesuit_roles_version' ); Roles::install(); if ( $previous_version !== '' && version_compare( $previous_version, STORESUIT_VERSION, '<' ) && $schemas ) { update_option( 'storesuit_previous_version', $previous_version, false ); Store::audit( 'settings', 0, 'suite_upgraded', array( 'from' => $previous_version, 'to' => STORESUIT_VERSION, ) ); } // A ready index reads again only the orders changed while StoreRuler was off; otherwise every order (8.30 review I3). require_once __DIR__ . '/IndexRecovery.php'; IndexRecovery::activated(); update_option( 'storesuit_version', STORESUIT_VERSION, false ); return ''; } public static function deactivate( $network_wide = false ) : void { // The free local/offline stand-in has no Freemius uninstall registration; the SDK handles this in normal installs. if ( storeruler_fs() instanceof FreemiusOff ) { $paid = false; // The paid stand-in already registers Freemius's complete after_uninstall callback list. if ( !$paid ) { register_uninstall_hook( STORESUIT_FILE, array(__CLASS__, 'uninstall_email') ); } } // Deactivated across a network: every site StoreRuler set up stops its scheduled work, not only the network admin's. if ( $network_wide && is_multisite() ) { self::each_site( static function () { self::stop(); } ); return; } self::stop(); } /** * Runs $step on every site of a multisite network that StoreRuler set up (its version stored), or on this site alone. * Deleting the plugin is done from the network admin, while the plugin may have been active on any of its sites. */ private static function each_site( callable $step ) : void { if ( !is_multisite() ) { $step(); return; } foreach ( get_sites( array( 'fields' => 'ids', 'number' => 0, ) ) as $site ) { switch_to_blog( (int) $site ); try { if ( get_option( 'storesuit_version', '' ) !== '' ) { $step(); } } finally { restore_current_blog(); } } } /** deactivate(): the current site's scheduled work stops; business records, settings and stock stay. */ private static function stop() : void { // Loaded here: the network admin's request may not have booted StoreRuler (no WooCommerce on its own site). foreach ( array( 'IndexRecovery', 'CartSignals', 'MailLog', 'Redirects' ) as $file ) { require_once __DIR__ . '/' . $file . '.php'; } IndexRecovery::deactivated(); CartSignals::deactivate(); MailLog::deactivate(); Redirects::deactivate(); wp_clear_scheduled_hook( 'storeruler_housekeeping' ); wp_clear_scheduled_hook( 'storesuit_forget_requests' ); // The daily clean-ups of back-in-stock requests and shop searches, scheduled again on the first request after activation. wp_clear_scheduled_hook( 'storesuit_stock_alert_cleanup' ); wp_clear_scheduled_hook( 'storesuit_search_prune' ); // Business records, settings and stock are deliberately not removed. } /** Deleting the plugin, either build: price alerts and review photos (StorefrontPrivacy::uninstall), on every site set up. */ public static function uninstall_privacy() : void { require_once __DIR__ . '/I18n.php'; require_once __DIR__ . '/StorefrontPrivacy.php'; self::each_site( static function () { StorefrontPrivacy::uninstall(); } ); } public static function uninstall_email() : void { require_once __DIR__ . '/EmailSetup.php'; self::each_site( static function () { EmailSetup::uninstall(); } ); } /** The store's OpenAI key of the free AI text (ProductAi), in both builds, like the email credentials. */ public static function uninstall_ai() : void { require_once __DIR__ . '/I18n.php'; require_once __DIR__ . '/ProductAi.php'; self::each_site( static function () { ProductAi::uninstall(); } ); } }