blog_id); $this->run_site_activation(); restore_current_blog(); } catch (Throwable $e) { restore_current_blog(); $this->log_error('initialize_new_site', $e); } } public function maybe_run_activation() { if (!is_admin()) { return; } try { $pending = get_option('acadlix_activation_pending'); if (empty($pending) || $pending['plugin'] !== ACADLIX_PLUGIN_BASENAME) { return; } delete_option('acadlix_activation_pending'); if (is_multisite() && !empty($pending['network'])) { foreach (get_sites(['fields' => 'ids']) as $site_id) { switch_to_blog($site_id); $this->run_site_activation(); restore_current_blog(); } } else { $this->run_site_activation(); } } catch (Throwable $e) { $this->log_error('maybe_run_activation', $e); } } // public function activate($network_wide) // { // if (is_multisite() && $network_wide) { // // Loop through all existing sites // foreach (get_sites(['fields' => 'ids']) as $site_id) { // switch_to_blog($site_id); // $this->run_site_activation(); // restore_current_blog(); // } // } else { // $this->run_site_activation(); // } // } private function run_site_activation() { try { if (function_exists('acadlix')) { acadlix()->migration()->createTable(); acadlix()->seeder()->seed(); acadlix()->admin()->option()->createOption(); acadlix()->admin()->userRole()->addCapabilities(); acadlix()->cpt()->register_all_cpts(); acadlix()->schedule()->createSchedules(); acadlix()->integrations()->caches()->clearAll(); } } catch (Throwable $e) { $this->log_error('run_site_activation', $e); } } public function deactivate($network_wide) { try { if (is_multisite() && $network_wide) { foreach (get_sites(['fields' => 'ids']) as $site_id) { switch_to_blog($site_id); $this->run_site_deactivation(); restore_current_blog(); } } else { $this->run_site_deactivation(); } } catch (Throwable $e) { $this->log_error('deactivate', $e); } } public function run_site_deactivation() { try { if (function_exists('acadlix')) { acadlix()->admin()->userRole()->removeCapabilities(); acadlix()->cpt()->unregister_all_cpts(); acadlix()->schedule()->deleteSchedules(); } } catch (Throwable $e) { $this->log_error('run_site_deactivation', $e); } } public function uninstall() { try { if (is_multisite()) { foreach (get_sites(['fields' => 'ids']) as $site_id) { switch_to_blog($site_id); $delete_data = acadlix()->helper()->acadlix_get_option('acadlix_delete_data_on_plugin_uninstall', "no"); if ($delete_data !== "no") { $this->run_site_uninstall(); } restore_current_blog(); } } else { $delete_data = acadlix()->helper()->acadlix_get_option('acadlix_delete_data_on_plugin_uninstall', "no"); if ($delete_data !== "no") { $this->run_site_uninstall(); } } } catch (Throwable $e) { $this->log_error('uninstall', $e); } } public function acadlix_delete_site($site) { try { $blog_id = (int) $site->id; switch_to_blog($blog_id); if (function_exists('acadlix')) { acadlix()->migration()->removeTable(); } restore_current_blog(); } catch (Throwable $e) { restore_current_blog(); $this->log_error('acadlix_delete_site', $e); } } private function run_site_uninstall() { try { if (function_exists('acadlix')) { acadlix()->admin()->core()->acadlix_delete_post_type_data(); acadlix()->migration()->removeTable(); acadlix()->admin()->option()->removeOptions(); } } catch (Throwable $e) { $this->log_error('run_site_uninstall', $e); } } public function acadlix_load_textdomain() { // load_plugin_textdomain('acadlix', false, ACADLIX_PLUGIN_FOLDER_NAME . '/languages/' . acadlix()->versionPath); } public function acadlix_check_version_update() { if (!current_user_can('manage_options')) { return; } if (acadlix()->isDev) { return; } try { if (is_multisite() && is_plugin_active_for_network(ACADLIX_PLUGIN_BASENAME)) { $sites = get_sites(['deleted' => 0]); foreach ($sites as $site) { switch_to_blog($site->blog_id); $this->run_version_update(); restore_current_blog(); } } else { $this->run_version_update(); } } catch (Throwable $e) { $this->log_error('acadlix_check_version_update', $e); } } public function get_option_name() { return acadlix()->pro ? 'acadlix_pro_version' : 'acadlix_version'; } public function get_current_version() { $option_name = $this->get_option_name(); return acadlix()->helper()->acadlix_get_option($option_name); } public function run_version_update() { $current_version = $this->get_current_version(); if (version_compare($current_version, ACADLIX_VERSION, '==')) { return; } $this->update_version(); acadlix()->helper()->acadlix_update_option($this->get_option_name(), ACADLIX_VERSION); } public function update_version() { // This method is intentionally left blank. Use run_version_update() to perform the actual update. } public function acadlix_check_db_update() { if (!current_user_can('manage_options')) { return; } try { if (is_multisite() && is_plugin_active_for_network(ACADLIX_PLUGIN_BASENAME)) { $sites = get_sites(['deleted' => 0]); foreach ($sites as $site) { switch_to_blog($site->blog_id); $this->run_db_update(); restore_current_blog(); } } else { $this->run_db_update(); } } catch (Throwable $e) { $this->log_error('acadlix_check_db_update', $e); } } protected function run_db_update() { $installed_ver = (int) acadlix()->helper()->acadlix_get_option('acadlix_db_version') ?: 1; $updates = [ 2 => 'updateV2', 3 => 'updateV3', 4 => 'updateV4', 5 => 'updateV5', 6 => 'updateV6', // update 1.3.0 7 => 'updateV7', // update 1.4.0 8 => 'updateV8', // update 1.5.0 9 => 'updateV9', // update 1.6.0, 10 => 'updateV10', // update 1.6.1, 11 => 'updateV11', // update 1.6.2, 12 => 'updateV12', // update 1.6.3 (pro) 1.0.5 (free), 13 => 'updateV13', // update 1.6.4 (pro) 1.0.6 (free), 14 => 'updateV14', // update 1.6.5 (pro) 1.0.7 (free), 15 => 'updateV15', // update 1.6.8 (pro) 1.0.8 (free), 16 => 'updateV16', // update 1.6.9 (pro) 1.0.9 (free), 17 => 'updateV17', // update 1.7.0 (pro) 1.1.0 (free), 18 => 'updateV18', // update 1.1.2 (free), 19 => 'updateV19', // 20 => 'updateV20', 21 => 'updateV21', 22 => 'updateV22', 23 => 'updateV23', 24 => 'updateV24', ]; foreach ($updates as $version => $method) { if ($installed_ver < $version && method_exists($this, $method)) { try { acadlix()->migration()->createTable(); acadlix()->seeder()->seed(); acadlix()->admin()->option()->createOption(); acadlix()->admin()->userRole()->addCapabilities(); acadlix()->integrations()->caches()->clearAll(); // Run the specific migration method $this->$method(); // Update version per step so successful migrations aren't re-run acadlix()->helper()->acadlix_update_option('acadlix_db_version', $this->dbVersion); } catch (Throwable $e) { $this->log_error("DB Migration (Version {$version})", $e); // Break out of loop so subsequent dependent migrations don't run on broken DB state break; } } } } protected function updateV24() { } protected function updateV23() { } protected function updateV22() { } protected function updateV21() { } protected function updateV20() { /** * In this update add student home page module. */ flush_rewrite_rules(); } protected function updateV19() { } protected function updateV18() { /** * In this update add course enrollment module. */ if (!get_option('acadlix_free_course_enrollment_update')) { $orderItems = acadlix() ->model() ->orderItem() ->with('order') ->whereHas('order', function ($query) { $query->where('status', Order::STATUS_SUCCESS); }) ->whereNull("subscription_id") ->where('type', 'course') ->get(); foreach ($orderItems as $item) { // Ensure the item has an associated order and valid user/course IDs to prevent errors if (!$item->order || !$item->order->user_id || !$item->item_id) { continue; } try { // Use your fluent factory method to safely upsert the record (Scenario A) $course = acadlix()->model()->course()->find($item->item_id); if (!$course) { // Cast IDs to int before interpolation so the message can't carry unescaped/unsafe data throw new \Exception('Course not found for Order Item ID ' . (int) $item->id . ' with Course ID ' . (int) $item->item_id); } $percentage = $course->getCourseCompletionPercentage($item->order->user_id); $courseSectionContentId = $course->getCurrentCourseContentId($item->order->user_id); $start_time = acadlix()->model()->userActivityMeta() ->where('user_id', $item->order->user_id) ->where('type', 'course') ->where('type_id', $item->item_id) ->where('meta_key', 'course_start_time') ->first(); acadlix()->model()->courseEnrollment()->enroll( (int) $item->order->user_id, (int) $item->item_id, // Assuming item_id stores your course_id [ 'source_type' => 'order', 'source_id' => $item->order_id, 'type' => $item->type, 'item_id' => $item->item_id, 'via' => 'user', 'via_id' => $item->order->user_id, 'course_section_content_id' => $courseSectionContentId, // Use the current course content ID 'started_at' => $start_time ? $start_time->meta_value : null, 'progress_percent' => $percentage, // Use the calculated percentage ] ); } catch (\Exception $e) { // Log individual errors so the entire loop doesn't crash if one row has corrupt data $this->log_error('Acadlix Migration Error for Order Item ID ' . $item->id, $e); } } update_option('acadlix_free_course_enrollment_update', true); } } protected function updateV17() { /** * In this add question sorting. */ } protected function updateV16() { /** * In this update add course student module. */ } protected function updateV15() { /** * In this update add Microsoft Teams module. */ } protected function updateV14() { /** * In this update add course bundle module. */ } protected function updateV13() { /** * In this update add certificate module. */ } protected function updateV12() { /** * In this update add coupon module. */ } protected function updateV11() { /** * In this update add assessment question type. */ } protected function updateV10() { /** * Update for review module */ } protected function updateV9() { /** * In this update add export functionality. */ } protected function updateV8() { /** * In this update modify course statistic * Add Schedule */ $course_statistic = acadlix()->model()->courseStatistic() ->whereNull('course_id') ->get(); foreach ($course_statistic as $statistic) { $statistic->update([ 'course_id' => $statistic->order_item->course_id, ]); } acadlix()->schedule()->createSchedules(); } protected function updateV7() { /** * In this update some user roles. */ } protected function updateV6() { /** * In this update add student module. */ } protected function updateV5() { /** * In this update add multisite functionality. */ } protected function updateV4() { /** * In this update add capabilities for zoom run through addCapabilities function. */ } protected function updateV3() { /** * In this update add column attempted_at in statistic table run through createTable function. */ } protected function updateV2() { /** * In this update also run subject seeder to add default subject. * Update questions subject_id */ $subject = acadlix()->model()->subject()->where('default', 1)->first(); $questions = acadlix()->model()->question()->where('subject_id', null)->get(); if ($questions->count() > 0 && $subject) { foreach ($questions as $question) { $question->update([ 'subject_id' => $subject->id, ]); } } } /** * Safely log errors to debug.log and notify admin gracefully */ protected function log_error(string $context, Throwable $e): void { $message = sprintf( '[Acadlix Activator Error] Context: %s | Message: %s | File: %s Line: %d', $context, $e->getMessage(), $e->getFile(), $e->getLine() ); error_log($message); if (is_admin()) { set_transient( 'acadlix_migration_last_error', sprintf( /* translators: 1: error context */ __('A background update step encountered an issue (%s). The site was kept safe.', 'acadlix'), $context ), HOUR_IN_SECONDS ); } } }