prefix . 'bcal_occurrences'; } /** * Import log table: what each import created or changed, for "Undo". * * @return string */ public static function log_table() { global $wpdb; return $wpdb->prefix . 'bcal_import_log'; } /** * Schedules recurring jobs. */ public static function schedule() { if ( ! wp_next_scheduled( 'bcal_daily' ) ) { wp_schedule_event( time() + HOUR_IN_SECONDS, 'daily', 'bcal_daily' ); } if ( ! wp_next_scheduled( 'bcal_feeds_check' ) ) { wp_schedule_event( time() + 10 * MINUTE_IN_SECONDS, 'hourly', 'bcal_feeds_check' ); } } /** * Activation. */ public static function activate() { self::create_tables(); bcal_register_content_types(); bcal_occurrence_rewrite(); flush_rewrite_rules(); self::schedule(); update_option( 'bcal_db_version', BCAL_DB_VERSION, false ); } /** * Deactivation. */ public static function deactivate() { wp_clear_scheduled_hook( 'bcal_daily' ); wp_clear_scheduled_hook( 'bcal_feeds_check' ); wp_clear_scheduled_hook( 'bcal_import_tick' ); flush_rewrite_rules(); } /** * Updates the schema after a plugin update. */ public static function maybe_upgrade() { if ( get_option( 'bcal_db_version' ) !== BCAL_DB_VERSION ) { self::create_tables(); update_option( 'bcal_db_version', BCAL_DB_VERSION, false ); // New rewrite rules (single event base, dates in the path). update_option( 'bcal_flush_rewrite', 1, false ); } self::schedule(); } /** * One-time settings migrations. Runs on init, after translations load. * * Version 2: colour presets fill every colour field, the accent field is * always the real accent and the theme colour became an accent source. */ public static function maybe_migrate_settings() { $version = (int) get_option( 'bcal_settings_version', 0 ); if ( $version >= 2 ) { return; } $saved = get_option( 'bcal_settings', array() ); if ( is_array( $saved ) && $saved ) { $presets = bcal_palettes(); $palette = isset( $saved['palette'] ) ? (string) $saved['palette'] : 'cobalt'; if ( 'theme' === $palette ) { $saved['accent_source'] = 'theme'; $saved['palette'] = 'custom'; } elseif ( isset( $presets[ $palette ] ) ) { $saved['accent'] = $presets[ $palette ]['accent']; foreach ( array( 'dark_accent', 'dark_surface', 'dark_text', 'dark_muted', 'dark_border' ) as $key ) { if ( ! isset( $saved[ $key ] ) ) { $saved[ $key ] = $presets[ $palette ][ $key ]; } } } elseif ( ! isset( $saved['dark_accent'] ) && ! empty( $saved['accent'] ) ) { $saved['dark_accent'] = $saved['accent']; } update_option( 'bcal_settings', $saved ); bcal_settings( true ); } update_option( 'bcal_settings_version', 2, false ); } /** * Creates or updates the index table. * * One row per occurrence. The post stays the single source of truth, * the table only makes date queries cheap for tens of thousands of events. */ public static function create_tables() { global $wpdb; require_once ABSPATH . 'wp-admin/includes/upgrade.php'; $table = self::table(); $charset = $wpdb->get_charset_collate(); $sql = "CREATE TABLE {$table} ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT, event_id bigint(20) unsigned NOT NULL, start_dt datetime NOT NULL, end_dt datetime NOT NULL, start_date date NOT NULL, all_day tinyint(1) NOT NULL DEFAULT 0, city_id bigint(20) unsigned NOT NULL DEFAULT 0, venue_id bigint(20) unsigned NOT NULL DEFAULT 0, featured tinyint(1) NOT NULL DEFAULT 0, pick tinyint(1) NOT NULL DEFAULT 0, hidden tinyint(1) NOT NULL DEFAULT 0, score smallint(6) DEFAULT NULL, status varchar(20) NOT NULL DEFAULT 'scheduled', PRIMARY KEY (id), KEY event_id (event_id), KEY start_dt (start_dt), KEY end_start (end_dt,start_dt), KEY city_start (city_id,start_dt), KEY venue_start (venue_id,start_dt), KEY start_date (start_date) ) {$charset};"; dbDelta( $sql ); $log = self::log_table(); $sql = "CREATE TABLE {$log} ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT, session varchar(32) NOT NULL, obj_type varchar(20) NOT NULL, obj_id bigint(20) unsigned NOT NULL DEFAULT 0, action varchar(20) NOT NULL, data longtext NULL, created datetime NOT NULL, PRIMARY KEY (id), KEY session_id (session,id), KEY obj (obj_type,obj_id) ) {$charset};"; dbDelta( $sql ); } }