new CategoryExportModule($api, new CategoryExportMapper()), // Export categories to Aikanen (service groups) 'category_import' => new CategoryImportModule($api, $categoryImportMapper, $productImportMapper), // Import categories (service groups) from Aikanen to Woo 'product_export' => new ProductExportModule($api, new ProductExportMapper()), // Export products from Woo to Aikanen 'product_import' => new ProductImportModule($api, $productImportMapper, $categoryImportMapper), // Import products from Aikanen to Woo 'product_sync_status' => new ProductSyncStatusModule($api), // Displaying sync status of products 'stock_sync' => new StockSyncModule($api), // Sync stocks between WooCommerce and Aikanen ]; if (is_admin()) { // Register settings page only for admin (new SettingsPage($modules))->register(); } foreach ($modules as $module) { $module->boot(); $module->register(); } }); // Generate default webhook secret (manually edited only when webhooks are manually ordered on Aikanen) register_activation_hook(__FILE__, function () { if (get_option('aikanen_webhook_secret', '') === '') { add_option('aikanen_webhook_secret', wp_generate_password(64, false)); } }); // Add settings link to plugins page add_filter('plugin_action_links_' . plugin_basename(__FILE__), function (array $links): array { $links[] = '' . __('Settings', 'aikanen') . ''; return $links; }); // Clean up on plugin deactivation register_deactivation_hook(__FILE__, function () { // Remove scheduled actions from Action Scheduler if (function_exists('as_unschedule_all_actions')) { as_unschedule_all_actions('aikanen_export_product'); as_unschedule_all_actions('aikanen_push_stock'); as_unschedule_all_actions('aikanen_stock_full_sync'); }; // Delete transients delete_transient('aikanen_preview'); delete_transient('aikanen_fetched_groups'); }); // Clean up on plugin uninstallation register_uninstall_hook(__FILE__, 'aikanen_uninstall'); function aikanen_uninstall(): void { require_once __DIR__ . '/src/ApiClient.php'; // Required for webhook cancellations // Cancel webhooks $api = new ApiClient(get_option('aikanen_api_token', '')); $events = [ 'category_import' => ['service_group.created', 'service_group.updated', 'service_group.services_attached', 'service_group.services_detached'], 'product_import' => ['service.created', 'service.updated'], 'stock_sync' => ['stock.updated'], ]; foreach ($events as $key => $moduleEvents) { foreach ($moduleEvents as $event) { $id = get_option("aikanen_webhook_id_{$key}_{$event}"); if ($id) { try { $api->delete("/webhooks/{$id}"); } catch (\Exception $e) { // Continue uninstall even if webhook order could not be canceled } delete_option("aikanen_webhook_id_{$key}_{$event}"); } } } // Clean up database entries delete_option('aikanen_api_token'); delete_option('aikanen_auto_export_category'); delete_option('aikanen_auto_export_product'); delete_option('aikanen_auto_import_category'); delete_option('aikanen_auto_import_product'); delete_option('aikanen_auto_stock_sync'); delete_option('aikanen_excluded_service_ids'); delete_option('aikanen_stock_full_sync_interval'); delete_option('aikanen_stock_source_of_truth'); delete_option('aikanen_vat_map'); delete_option('aikanen_webhook_secret'); // Remove _aikanen_service_id from all products $posts = get_posts(['post_type' => 'product', 'meta_key' => '_aikanen_service_id', 'fields' => 'ids', 'nopaging' => true]); foreach ($posts as $id) { delete_post_meta($id, '_aikanen_service_id'); delete_post_meta($id, '_aikanen_last_synced'); } // Remove _aikanen_group_id from all terms $terms = get_terms(['taxonomy' => 'product_cat', 'hide_empty' => false, 'meta_query' => [['key' => '_aikanen_group_id', 'compare' => 'EXISTS']]]); foreach ($terms as $term) { delete_term_meta($term->term_id, '_aikanen_group_id'); } }