'update_225', '2.4.6' => 'update_246', '2.4.8' => 'update_248', '2.5.0' => 'update_250', ); /** * Constructor. */ public function __construct() { add_action( 'init', array( $this, 'check_update' ), 1 ); } /** * Check the plugin version and run the updater if necessary on all requests. * * @since 2.2.5 * @return void */ public function check_update(): void { $db_version = get_option( 'aicw_version' ); $current_version = ai_content_writer()->get_version(); $requires_update = version_compare( $db_version, $current_version, '<' ); $can_install = ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) && ! defined( 'IFRAME_REQUEST' ); if ( $can_install && $requires_update ) { static::install(); $update_versions = array_keys( $this->updates ); usort( $update_versions, 'version_compare' ); if ( ! is_null( $db_version ) && version_compare( $db_version, end( $update_versions ), '<' ) ) { $this->update(); } else { update_option( 'aicw_version', $current_version ); } } } /** * Update the plugin to the new version. * * @since 2.2.5 * @return void */ public function update(): void { $db_version = get_option( 'aicw_version' ); foreach ( $this->updates as $version => $callbacks ) { $callbacks = (array) $callbacks; if ( version_compare( $db_version, $version, '<' ) ) { foreach ( $callbacks as $callback ) { call_user_func( array( $this, $callback ) ); } update_option( 'aicw_version', $version ); $notice = sprintf( /* translators: 1: plugin name 2: version number */ __( '%1$s updated to version %2$s successfully.', 'ai-content-writer' ), __( 'AI Content Writer', 'ai-content-writer' ), $version ); ai_content_writer()->flash_notice( $notice ); } } } /** * Install the plugin. * * @since 2.2.5 * @return void */ public static function install(): void { if ( ! is_blog_installed() ) { return; } add_option( 'aicw_version', ai_content_writer()->get_version() ); add_option( 'aicw_installed', wp_date( 'U' ) ); flush_rewrite_rules(); } /** * Upgrade to 2.2.5 * * @since 2.2.5 * @return void */ public function update_225(): void { $old_hooks = array( 'aicw_generate_title', 'aicw_generate_content', 'aicw_generate_thumbnail', 'aicw_publish_posts', ); foreach ( $old_hooks as $hook ) { if ( wp_next_scheduled( $hook ) ) { wp_clear_scheduled_hook( $hook ); } } $campaigns = get_posts( array( 'post_type' => 'aicw_campaign', 'posts_per_page' => -1, 'fields' => 'ids', 'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query array( 'key' => '_aicw_campaign_frequency', 'compare' => 'NOT EXISTS', ), ), ) ); $old_frequency = 'hourly'; $has_frequency = get_option( 'aicwp_campaign_frequency' ); if ( $has_frequency ) { $old_frequency = $has_frequency; delete_option( 'aicwp_campaign_frequency' ); } foreach ( $campaigns as $campaign_id ) { update_post_meta( $campaign_id, '_aicw_campaign_frequency', $old_frequency ); Cron::schedule_campaign( $campaign_id, $old_frequency ); } } /** * Upgrade to 2.4.6 * * @since 2.4.6 * @return void */ public function update_246(): void { delete_option( 'aicw_allowed_hosts' ); $current_model = get_option( 'aicw_gemini_ai_model' ); if ( in_array( $current_model, array( 'models/gemini-1.5-flash', 'models/gemini-1.5-pro' ), true ) ) { update_option( 'aicw_gemini_ai_model', 'models/gemini-2.5-flash' ); } } /** * Upgrade to 2.4.8 * * Re-arms published campaigns that were left without a scheduled run. * Earlier versions stopped rescheduling a campaign as soon as it had nothing * to do for one cycle (for example once its target was reached), which left * it dormant even after the target was raised again. Campaigns now re-arm * themselves on every run, but existing sites need this one-time nudge. * * @since 2.4.8 * @return void */ public function update_248(): void { $campaigns = get_posts( array( 'post_type' => 'aicw_campaign', 'post_status' => 'publish', 'posts_per_page' => -1, 'fields' => 'ids', ) ); foreach ( $campaigns as $campaign_id ) { if ( wp_next_scheduled( 'aicw_process_campaign', array( $campaign_id ) ) ) { continue; } $frequency = get_post_meta( $campaign_id, '_aicw_campaign_frequency', true ); Cron::schedule_campaign( $campaign_id, $frequency ? $frequency : 'hourly' ); } } /** * Upgrade to 2.5.0 * * Moves saved model settings off models the AI providers have shut down or * deprecated, and drops those models from the cached model lists so they * no longer appear on the settings page. * * @since 2.5.0 * @return void */ public function update_250(): void { $providers = array( 'aicw_gemini' => new Services\Gemini(), 'aicw_chatgpt' => new Services\OpenAI(), ); // Cached API model lists would otherwise put the retired models back on the next settings save. delete_transient( 'aicw_gemini_models_' . md5( (string) get_option( 'aicw_gemini_api_key' ) ) ); delete_transient( 'aicw_openai_models_' . md5( (string) get_option( 'aicw_chatgpt_api_secret_key' ) ) ); foreach ( $providers as $prefix => $provider ) { $retired = $provider->get_retired_models(); $model = (string) get_option( $prefix . '_ai_model' ); $models = get_option( $prefix . '_models' ); $models = is_array( $models ) ? array_diff_key( $models, $retired ) : array(); if ( '' !== $model ) { $model = $provider->replace_retired_model( $model ); update_option( $prefix . '_ai_model', $model ); // Keep the selected model visible until the list is refreshed from the API. if ( ! isset( $models[ $model ] ) ) { $models[ $model ] = $model; } } update_option( $prefix . '_models', $models ); } } }