id, array( 'plugins', 'dashboard', 'toplevel_page_' . Spinix_Image_Optimization_Admin::SLUG ), true ); } /** * Styles for the plugin's admin notices (only where they can appear). */ public static function notice_styles() { if ( current_user_can( 'activate_plugins' ) && self::notice_screen() ) { wp_enqueue_style( 'spinix-io-notices', SPINIX_IMAGE_OPTIMIZATION_URL . 'assets/css/notices.css', array(), SPINIX_IMAGE_OPTIMIZATION_VERSION ); } } /** * Remember the installed version (for future upgrade routines). */ private static function maybe_upgrade() { if ( SPINIX_IMAGE_OPTIMIZATION_VERSION !== get_option( 'spinix_io_version' ) && false !== get_option( Spinix_Image_Optimization_Settings::OPTION, false ) ) { update_option( 'spinix_io_version', SPINIX_IMAGE_OPTIMIZATION_VERSION, false ); } } /** * Optimize right after WordPress has generated all sizes for an upload. * * @param array $metadata Metadata. * @param int $id Attachment ID. * @return array */ public function on_generate_metadata( $metadata, $id ) { if ( ! Spinix_Image_Optimization_Settings::get( 'optimize_on_upload' ) || ! is_array( $metadata ) || Spinix_Image_Optimization_Conflicts::paused() || Spinix_Image_Optimization_Lifecycle::is_paused() ) { return $metadata; } if ( ! in_array( get_post_mime_type( $id ), Spinix_Image_Optimization_Optimizer::mimes(), true ) ) { return $metadata; } /** * Return false to optimize uploads in the background instead of during the upload request. * * @param bool $inline Inline. * @param int $id Attachment ID. */ if ( apply_filters( 'spinix_io_optimize_inline', true, $id ) ) { try { Spinix_Image_Optimization_Bulk::log( array( Spinix_Image_Optimization_Optimizer::optimize( $id, true, $metadata ) ) ); } catch ( Throwable $e ) { wp_schedule_single_event( time() + 30, Spinix_Image_Optimization_Bulk::SINGLE_HOOK, array( (int) $id ) ); } } else { wp_schedule_single_event( time() + 5, Spinix_Image_Optimization_Bulk::SINGLE_HOOK, array( (int) $id ) ); } return $metadata; } /** * Re-optimize when an image is edited (crop/rotate in the media editor). * * @param array $metadata Metadata. * @param int $id Attachment ID. * @return array */ public function on_update_metadata( $metadata, $id ) { if ( 'optimized' !== get_post_meta( $id, Spinix_Image_Optimization_Optimizer::META_STATUS, true ) ) { return $metadata; } $data = get_post_meta( $id, Spinix_Image_Optimization_Optimizer::META_DATA, true ); $file = get_attached_file( $id ); $rel = $file ? Spinix_Image_Optimization_Storage::relative( $file ) : false; if ( is_array( $data ) && $rel && isset( $data['source'] ) && $data['source'] !== $rel ) { if ( ! wp_next_scheduled( Spinix_Image_Optimization_Bulk::SINGLE_HOOK, array( (int) $id ) ) ) { wp_schedule_single_event( time() + 5, Spinix_Image_Optimization_Bulk::SINGLE_HOOK, array( (int) $id ) ); } } return $metadata; } /** * Activation was refused (another optimizer is active): switch Spinix off again * right away and explain why, with a one-click way to fix it. */ public static function enforce_activation_block() { if ( false === get_option( 'spinix_io_activation_blocked', false ) ) { return; } $files = (array) get_option( 'spinix_io_activation_blocked', array() ); $names = (string) get_option( 'spinix_io_activation_blocked_names', '' ); delete_option( 'spinix_io_activation_blocked' ); delete_option( 'spinix_io_activation_blocked_names' ); if ( ! function_exists( 'deactivate_plugins' ) ) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } deactivate_plugins( plugin_basename( SPINIX_IMAGE_OPTIMIZATION_FILE ), true ); unset( $_GET['activate'], $_GET['activate-multi'] ); // phpcs:ignore WordPress.Security.NonceVerification -- hide "Plugin activated." add_action( 'admin_notices', static function () use ( $files, $names ) { if ( ! current_user_can( 'activate_plugins' ) ) { return; } echo '
'; echo '

' . esc_html__( 'Spinix Image Optimization was not activated', 'spinix-image-optimization' ) . '

'; /* translators: %s: plugin names */ echo '

' . esc_html( sprintf( __( '%s is already optimizing your images. Two image optimizers on one site convert and rewrite the same images and break each other. Deactivate it first, then activate Spinix Image Optimization again.', 'spinix-image-optimization' ), $names ) ) . '

'; foreach ( array_filter( $files ) as $file ) { $url = wp_nonce_url( admin_url( 'plugins.php?action=deactivate&plugin=' . rawurlencode( $file ) ), 'deactivate-plugin_' . $file ); $data = get_plugins(); $name = isset( $data[ $file ]['Name'] ) ? $data[ $file ]['Name'] : $file; /* translators: %s: plugin name */ echo '' . esc_html( sprintf( __( 'Deactivate %s', 'spinix-image-optimization' ), $name ) ) . ''; } echo '

'; } ); } /** * The conflicting plugin was deactivated: start optimizing right away. * * @param string $plugin Plugin basename that was deactivated. */ public function maybe_resume( $plugin = '' ) { if ( plugin_basename( SPINIX_IMAGE_OPTIMIZATION_FILE ) === $plugin ) { return; // Spinix itself is being deactivated. } // WordPress saves the new list of active plugins only after this hook, // so check once the request has finished. if ( ! has_action( 'shutdown', array( $this, 'resume_check' ) ) ) { add_action( 'shutdown', array( $this, 'resume_check' ) ); } } /** * Start optimizing when nothing blocks Spinix anymore. */ public function resume_check() { wp_cache_delete( 'alloptions', 'options' ); Spinix_Image_Optimization_Conflicts::flush(); if ( ! Spinix_Image_Optimization_Conflicts::paused() && 'running' !== Spinix_Image_Optimization_Bulk::state() && Spinix_Image_Optimization_Bulk::pending_ids( 1 ) ) { Spinix_Image_Optimization_Bulk::start(); } } /** * Remove our files when the attachment is deleted. * * @param int $id Attachment ID. */ public function on_delete_attachment( $id ) { Spinix_Image_Optimization_Optimizer::delete_files( (int) $id ); } /** * Plugin list links. * * @param array $links Links. * @return array */ public function action_links( $links ) { $url = admin_url( 'admin.php?page=' . Spinix_Image_Optimization_Admin::SLUG ); array_unshift( $links, '' . esc_html__( 'Dashboard', 'spinix-image-optimization' ) . '', '' . esc_html__( 'Settings', 'spinix-image-optimization' ) . '' ); return $links; } /** * Activation. */ public static function activate() { // Refuse to run next to another image optimizer (they would fight over the same images). Spinix_Image_Optimization_Conflicts::flush(); $found = Spinix_Image_Optimization_Conflicts::detect(); if ( ! empty( $found['optimizers'] ) && ! ( defined( 'SPINIX_IMAGE_OPTIMIZATION_ALLOW_CONFLICTS' ) && SPINIX_IMAGE_OPTIMIZATION_ALLOW_CONFLICTS ) ) { $names = implode( ', ', wp_list_pluck( $found['optimizers'], 'name' ) ); if ( defined( 'WP_CLI' ) && WP_CLI ) { WP_CLI::error( sprintf( 'Spinix Image Optimization was not activated: %s is active. Deactivate it first (two image optimizers on one site break each other).', $names ) ); } update_option( 'spinix_io_activation_blocked', wp_list_pluck( $found['optimizers'], 'file' ) + array(), false ); update_option( 'spinix_io_activation_blocked_names', $names, false ); return; } delete_option( 'spinix_io_activation_blocked' ); if ( false === get_option( Spinix_Image_Optimization_Settings::OPTION, false ) ) { add_option( Spinix_Image_Optimization_Settings::OPTION, Spinix_Image_Optimization_Settings::defaults(), '', 'no' ); } Spinix_Image_Optimization_Settings::flush(); Spinix_Image_Optimization_Storage::ensure_dir(); update_option( 'spinix_io_version', SPINIX_IMAGE_OPTIMIZATION_VERSION, false ); if ( Spinix_Image_Optimization_Settings::get( 'scan_on_activation' ) && 'paused' !== get_option( Spinix_Image_Optimization_Bulk::STATE_OPTION ) && ! Spinix_Image_Optimization_Conflicts::paused() ) { // Make sure our schedule exists before scheduling the event. add_filter( 'cron_schedules', array( 'Spinix_Image_Optimization_Bulk', 'schedules' ) ); // phpcs:ignore WordPress.WP.CronInterval -- one-minute interval while a bulk run is active. Spinix_Image_Optimization_Bulk::start(); set_transient( 'spinix_io_activation_notice', 1, DAY_IN_SECONDS ); } } /** * Deactivation: stop background jobs, keep files and settings. */ public static function deactivate() { wp_clear_scheduled_hook( Spinix_Image_Optimization_Bulk::CRON_HOOK ); wp_unschedule_hook( Spinix_Image_Optimization_Bulk::SINGLE_HOOK ); if ( 'running' === get_option( Spinix_Image_Optimization_Bulk::STATE_OPTION ) ) { update_option( Spinix_Image_Optimization_Bulk::STATE_OPTION, 'idle', false ); } Spinix_Image_Optimization_Bulk::unlock(); } }