booted ) { return; } $this->booted = true; // phpcs:ignore WordPress.WP.CronInterval.CronSchedulesInterval -- Minute interval is intentional; the worker is time-boxed and idles on an empty queue. add_filter( 'cron_schedules', array( $this, 'register_cron_schedule' ) ); add_action( 'admin_init', array( Installer::class, 'maybe_upgrade' ) ); add_action( 'admin_init', array( $this, 'add_privacy_policy_content' ) ); add_filter( 'pre_update_option_' . Options::CREDENTIALS, array( Connections::class, 'before_update' ), 10, 2 ); add_action( 'update_option_' . Options::CREDENTIALS, array( Options::class, 'on_credentials_updated' ), 10, 2 ); add_action( 'wp_initialize_site', array( $this, 'on_new_site' ), 100 ); add_action( 'wp_delete_site', array( $this, 'on_delete_site' ), 10 ); add_action( Installer::CRON_HOOK, array( Worker::class, 'run_scheduled' ) ); add_action( 'wp_ajax_' . Worker::AJAX_ACTION, array( Worker::class, 'ajax_tick' ) ); if ( is_admin() ) { Admin::register(); \R2Clouder\Admin\Media_Library::register(); } Handlers::register(); Uploads::register(); Lifecycle::register(); Delivery::register(); Purger::register(); } /** * Registers suggested privacy policy text describing the R2 transfer. * * @return void */ public function add_privacy_policy_content(): void { if ( ! function_exists( 'wp_add_privacy_policy_content' ) ) { return; } wp_add_privacy_policy_content( 'OffloadKit', wp_kses_post( '

' . __( 'OffloadKit copies media library files to the storage provider configured by the site administrator. Visitors request delivered media directly from that provider or the configured CDN. Review the selected services and update the suggested text to describe this site’s configuration.', 'devsyed-media-offloader' ) . '

' . '

' . __( 'Suggested text:', 'devsyed-media-offloader' ) . ' ' . __( 'Media files uploaded to this site, including their file names and types, may be stored with our configured cloud storage provider. Requests for delivered media share your IP address and browser request information with the delivery provider. The provider and its privacy policy should be identified in this site’s privacy policy; service policy links are available in the OffloadKit plugin documentation.', 'devsyed-media-offloader' ) . '

' ) ); } // phpcs:disable WordPress.WP.CronInterval -- The worker is time-boxed and returns immediately on an empty queue; a minute interval is what keeps freshly uploaded media from sitting unoffloaded. /** * Adds the one-minute interval used by the queue worker. * * @param array $schedules Registered cron schedules. * @return array */ public function register_cron_schedule( $schedules ): array { if ( ! is_array( $schedules ) ) { $schedules = array(); } // Translating before `init` triggers a _load_textdomain_just_in_time // notice on WP 6.7+, and cron schedules can be requested that early. $display = did_action( 'init' ) ? __( 'Every minute (R2Clouder queue)', 'devsyed-media-offloader' ) : 'Every minute (R2Clouder queue)'; $schedules[ Installer::CRON_SCHEDULE ] = array( 'interval' => MINUTE_IN_SECONDS, 'display' => $display, ); return $schedules; } // phpcs:enable WordPress.WP.CronInterval /** * Creates the plugin's tables on a newly created multisite site. * * @param \WP_Site $new_site The site that was just created. * @return void */ public function on_new_site( $new_site ): void { if ( ! is_multisite() || ! ( $new_site instanceof \WP_Site ) ) { return; } // `wp_initialize_site` can fire outside the admin, where this file is absent. require_once ABSPATH . 'wp-admin/includes/plugin.php'; if ( ! is_plugin_active_for_network( plugin_basename( R2CLOUDER_FILE ) ) ) { return; } switch_to_blog( (int) $new_site->blog_id ); Installer::create_tables(); Installer::schedule(); restore_current_blog(); } /** * Cleans up plugin data when a multisite site is deleted. * * @param \WP_Site $old_site The site being deleted. * @return void */ public function on_delete_site( $old_site ): void { if ( ! is_multisite() || ! ( $old_site instanceof \WP_Site ) ) { return; } switch_to_blog( (int) $old_site->blog_id ); global $wpdb; wp_clear_scheduled_hook( Installer::CRON_HOOK ); delete_transient( 'r2clouder_worker_lock' ); delete_post_meta_by_key( '_r2clouder_offload' ); $table = esc_sql( $wpdb->prefix . 'r2clouder_jobs' ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQL.InterpolatedNotPrepared $wpdb->query( "DROP TABLE IF EXISTS `{$table}`" ); delete_option( Options::SETTINGS ); delete_option( Options::CREDENTIALS ); delete_option( Options::VERSION ); delete_option( 'r2clouder_db_version' ); restore_current_blog(); } }