cleanup_old_temp_images(); } // Activation hook. register_activation_hook(__FILE__, "wp_agentic_writer_activate"); /** * Plugin activation. * * @since 0.1.0 */ function wp_agentic_writer_activate() { // Set default options using model registry for consistency. $registry_defaults = WPAW_Model_Registry::get_activation_defaults(); $default_options = [ "openrouter_api_key" => "", "planning_model" => $registry_defaults["planning_model"], "execution_model" => $registry_defaults["execution_model"], "image_model" => $registry_defaults["image_model"], "web_search_enabled" => false, "search_engine" => "auto", "search_depth" => "medium", "cost_tracking_enabled" => true, "enable_clarification_quiz" => true, "clarity_confidence_threshold" => "0.6", "chat_history_limit" => 20, "preferred_languages" => ["auto", "English", "Indonesian"], "custom_languages" => [], ]; add_option("wp_agentic_writer_settings", $default_options); // Set default custom models from registry (separate option for custom models) $registry = WPAW_Model_Registry::get_registry(); $default_custom_models = []; foreach ($registry["image_models"] as $id => $name) { $default_custom_models[] = [ "id" => $id, "name" => $name, "type" => "image", ]; } add_option("wp_agentic_writer_custom_models", $default_custom_models); // Create cost tracking table. wp_agentic_writer_create_cost_table(); // Create image management tables. WP_Agentic_Writer_Image_Manager::get_instance()->create_tables(); // Create conversations table. require_once WP_AGENTIC_WRITER_DIR . "includes/class-conversation-migration.php"; wpaw_create_conversations_table(); } /** * Create cost tracking table. * * @since 0.1.0 */ function wp_agentic_writer_create_cost_table() { global $wpdb; $table_name = $wpdb->prefix . "wpaw_cost_tracking"; $charset_collate = $wpdb->get_charset_collate(); $sql = "CREATE TABLE $table_name ( id bigint(20) NOT NULL AUTO_INCREMENT, post_id bigint(20) NOT NULL, session_id varchar(32) DEFAULT '' NOT NULL, model varchar(255) NOT NULL, provider varchar(50) DEFAULT 'openrouter' NOT NULL, action varchar(50) NOT NULL, input_tokens int(11) NOT NULL, output_tokens int(11) NOT NULL, cost decimal(10,6) NOT NULL, status varchar(20) DEFAULT 'success' NOT NULL, created_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, PRIMARY KEY (id), KEY post_id (post_id), KEY session_id (session_id), KEY provider (provider), KEY action (action), KEY created_at (created_at) ) $charset_collate;"; require_once ABSPATH . "wp-admin/includes/upgrade.php"; dbDelta($sql); } // Version-based table creation (runs on plugins_loaded to ensure tables exist). add_action("plugins_loaded", "wp_agentic_writer_maybe_create_tables"); /** * Create database tables if they don't exist or version is outdated. * * @since 0.1.0 */ function wp_agentic_writer_maybe_create_tables() { // Cost tracking table - controlled by main db version. $current_version = get_option("wpaw_db_version", "0"); $required_version = "1.1.0"; if (version_compare($current_version, $required_version, "<")) { // Create cost tracking table. wp_agentic_writer_create_cost_table(); // Create image management tables. WP_Agentic_Writer_Image_Manager::get_instance()->create_tables(); // Create conversations table (migrate if needed). if (!function_exists("wpaw_create_conversations_table")) { require_once WP_AGENTIC_WRITER_DIR . "includes/class-conversation-migration.php"; } wpaw_create_conversations_table(); // Update version. update_option("wpaw_db_version", $required_version); } else { // Even if main version is current, still check conversation table independently. if (!function_exists("wpaw_create_conversations_table")) { require_once WP_AGENTIC_WRITER_DIR . "includes/class-conversation-migration.php"; } $conv_version = get_option("wpaw_conversations_db_version", "0"); if (version_compare($conv_version, "0.1.4", "<")) { wpaw_create_conversations_table(); } } } // Deactivation hook. register_deactivation_hook(__FILE__, "wp_agentic_writer_deactivate"); /** * Plugin deactivation. * * @since 0.1.0 */ function wp_agentic_writer_deactivate() { // Clear scheduled cron jobs. $timestamp = wp_next_scheduled("wpaw_cleanup_temp_images"); if ($timestamp) { wp_unschedule_event($timestamp, "wpaw_cleanup_temp_images"); } wp_clear_scheduled_hook("wpaw_cleanup_old_sessions"); } // Uninstall hook. register_uninstall_hook(__FILE__, "wp_agentic_writer_uninstall"); /** * Plugin uninstall. * * Removes all plugin data including settings, database tables, * post meta, user meta, transients, scheduled events, and temp files. * * @since 0.1.0 */ function wp_agentic_writer_uninstall() { global $wpdb; // Delete options. delete_option("wp_agentic_writer_settings"); delete_option("wpaw_db_version"); delete_option("wpaw_conversations_db_version"); delete_option("wp_agentic_writer_custom_models"); // Delete post meta. $post_meta_keys = [ "_wpaw_plan", "_wpaw_chat_history", "_wpaw_memory", "_wpaw_post_config", "_wpaw_focus_keyword", "_wpaw_writing_status", "_wpaw_current_section", "_wpaw_sections_written", "_wpaw_writing_state_updated", "_wpaw_plan_id", "_wpaw_resume_token", ]; foreach ($post_meta_keys as $key) { delete_post_meta_by_key($key); } // Delete user meta. $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->usermeta} WHERE meta_key LIKE %s", "wpaw_%", ), ); // Delete database tables. $tables = [ $wpdb->prefix . "wpaw_cost_tracking", $wpdb->prefix . "wpaw_images", $wpdb->prefix . "wpaw_images_variants", $wpdb->prefix . "wpaw_conversations", ]; foreach ($tables as $table) { $wpdb->query("DROP TABLE IF EXISTS {$table}"); } // Clear transients. delete_transient("wpaw_openrouter_models"); delete_transient("wpaw_openrouter_model_objects"); delete_transient("wpaw_openrouter_model_ids"); // Unschedule cron events. wp_clear_scheduled_hook("wpaw_cleanup_old_sessions"); wp_clear_scheduled_hook("wpaw_daily_cleanup"); // Delete temp image directory. $upload_dir = wp_upload_dir(); $temp_dir = $upload_dir["basedir"] . "/wpaw"; if (file_exists($temp_dir)) { $files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $temp_dir, RecursiveDirectoryIterator::SKIP_DOTS, ), RecursiveIteratorIterator::CHILD_FIRST, ); foreach ($files as $fileinfo) { $todo = $fileinfo->isDir() ? "rmdir" : "unlink"; $todo($fileinfo->getRealPath()); } rmdir($temp_dir); } }