filesystem = Imagify_Filesystem::get_instance(); } /** * Launch the hooks. * * @since 1.6.11 */ public function init() { $doing_ajax = wp_doing_ajax(); foreach ( $this->ajax_post_actions as $action ) { $action_callback = "{$action}_callback"; if ( $doing_ajax ) { add_action( 'wp_ajax_' . $action, array( $this, $action_callback ) ); } add_action( 'admin_post_' . $action, array( $this, $action_callback ) ); } // Actions triggered only on admin ajax. if ( $doing_ajax ) { foreach ( $this->ajax_only_actions as $action ) { add_action( 'wp_ajax_' . $action, array( $this, $action . '_callback' ) ); } } // Actions triggered on admin post. foreach ( $this->post_only_actions as $action ) { add_action( 'admin_post_' . $action, array( $this, $action . '_callback' ) ); } } /** ----------------------------------------------------------------------------------------- */ /** OPTIMIZATION PROCESSES ================================================================== */ /** ----------------------------------------------------------------------------------------- */ /** * Optimize one media. * * @since 1.9 * * @param int $media_id The media ID. * @param string $context The context. * @return bool|WP_Error True if successfully launched. A \WP_Error instance on failure. */ protected function optimize_media( $media_id, $context ) { return imagify_get_optimization_process( $media_id, $context )->optimize(); } /** * Re-optimize a media to a different optimization level. * * @since 1.9 * * @param int $media_id The media ID. * @param string $context The context. * @param int $level The optimization level. * @return bool|WP_Error True if successfully launched. A \WP_Error instance on failure. */ protected function reoptimize_media( $media_id, $context, $level ) { return imagify_get_optimization_process( $media_id, $context )->reoptimize( $level ); } /** * Optimize all files from a media, whatever this media’s previous optimization status (will be restored if needed). * This is used by the bulk optimization page. * * @since 1.9 * * @param int $media_id The media ID. * @param string $context The context. * @param int $level The optimization level. * @return bool|WP_Error True if successfully launched. A \WP_Error instance on failure. */ protected function force_optimize( $media_id, $context, $level ) { $process = imagify_get_optimization_process( $media_id, $context ); $data = $process->get_data(); // Restore before re-optimizing. if ( $data->is_optimized() ) { $result = $process->restore(); if ( is_wp_error( $result ) ) { // Return an error message. return $result; } } return $process->optimize( $level ); } /** * Optimize one or some thumbnails that are not optimized yet. * * @since 1.9 * * @param int $media_id The media ID. * @param string $context The context. * @return bool|WP_Error True if successfully launched. A \WP_Error instance on failure. */ protected function optimize_missing_sizes( $media_id, $context ) { return imagify_get_optimization_process( $media_id, $context )->optimize_missing_thumbnails(); } /** * Generate next-gen images if they are missing. * * @since 1.9 * * @param int $media_id The media ID. * @param string $context The context. * @return bool|WP_Error True if successfully launched. A \WP_Error instance on failure. */ protected function generate_nextgen_versions( $media_id, $context ) { return imagify_get_optimization_process( $media_id, $context )->generate_nextgen_versions(); } /** * Delete Next gen images for media that are "already_optimize". * * @since 1.9.6 * * @param int $media_id The media ID. * @param string $context The context. * @return bool|WP_Error True if successfully launched. A \WP_Error instance on failure. */ protected function delete_nextgen_versions( $media_id, $context ) { $process = imagify_get_optimization_process( $media_id, $context ); if ( ! $process->is_valid() ) { return new WP_Error( 'invalid_media', __( 'This media is not valid.', 'imagify' ) ); } $data = $process->get_data(); if ( ! $data->is_already_optimized() ) { return new WP_Error( 'not_already_optimized', __( 'This media does not have the right optimization status.', 'imagify' ) ); } if ( ! $process->has_next_gen() ) { return true; } $data->delete_optimization_data(); $deleted = $process->delete_nextgen_files( false, true ); if ( is_wp_error( $deleted ) ) { return new WP_Error( 'nextgen_not_deleted', __( 'Previous next-gen files could not be deleted.', 'imagify' ) ); } return true; } /** * Restore a media. * * @since 1.9 * * @param int $media_id The media ID. * @param string $context The context. * @return bool|WP_Error True on success. A \WP_Error instance on failure. */ protected function restore_media( $media_id, $context ) { return imagify_get_optimization_process( $media_id, $context )->restore(); } /** ----------------------------------------------------------------------------------------- */ /** WP OPTIMIZATION CALLBACKS =============================================================== */ /** ----------------------------------------------------------------------------------------- */ /** * Optimize all thumbnails of a specific image with the manual method. * * @since 1.6.11 */ public function imagify_manual_optimize_callback() { $context = $this->get_context(); $media_id = $this->get_media_id(); if ( ! $media_id || ! $context ) { imagify_die( __( 'Invalid request', 'imagify' ) ); } imagify_check_nonce( 'imagify-optimize-' . $media_id . '-' . $context ); if ( ! imagify_get_context( $context )->current_user_can( 'manual-optimize', $media_id ) ) { imagify_die(); } $result = $this->optimize_media( $media_id, $context ); imagify_maybe_redirect( is_wp_error( $result ) ? $result : false ); if ( is_wp_error( $result ) ) { // Return an error message. $output = $result->get_error_message(); wp_send_json_error( [ 'html' => $output ] ); } wp_send_json_success(); } /** * Optimize all thumbnails of a specific image with a different optimization level. * * @since 1.6.11 */ public function imagify_manual_reoptimize_callback() { $context = $this->get_context(); $media_id = $this->get_media_id(); if ( ! $media_id || ! $context ) { imagify_die( __( 'Invalid request', 'imagify' ) ); } imagify_check_nonce( 'imagify-manual-reoptimize-' . $media_id . '-' . $context ); if ( ! imagify_get_context( $context )->current_user_can( 'manual-optimize', $media_id ) ) { imagify_die(); } $result = $this->reoptimize_media( $media_id, $context, $this->get_optimization_level() ); imagify_maybe_redirect( is_wp_error( $result ) ? $result : false ); if ( is_wp_error( $result ) ) { // Return an error message. $output = $result->get_error_message(); wp_send_json_error( [ 'html' => $output ] ); } wp_send_json_success(); } /** * Optimize one or some thumbnails that are not optimized yet. * * @since 1.6.11 */ public function imagify_optimize_missing_sizes_callback() { $context = $this->get_context(); $media_id = $this->get_media_id(); if ( ! $media_id || ! $context ) { imagify_die( __( 'Invalid request', 'imagify' ) ); } imagify_check_nonce( 'imagify-optimize-missing-sizes-' . $media_id . '-' . $context ); if ( ! imagify_get_context( $context )->current_user_can( 'manual-optimize', $media_id ) ) { imagify_die(); } $result = $this->optimize_missing_sizes( $media_id, $context ); imagify_maybe_redirect( is_wp_error( $result ) ? $result : false ); if ( is_wp_error( $result ) ) { // Return an error message. $output = $result->get_error_message(); wp_send_json_error( [ 'html' => $output ] ); } wp_send_json_success(); } /** * Generate next-gen images if they are missing. * * @since 1.9 */ public function imagify_generate_nextgen_versions_callback() { $context = $this->get_context(); $media_id = $this->get_media_id(); if ( ! $media_id || ! $context ) { imagify_die( __( 'Invalid request', 'imagify' ) ); } imagify_check_nonce( 'imagify-generate-nextgen-versions-' . $media_id . '-' . $context ); if ( ! imagify_get_context( $context )->current_user_can( 'manual-optimize', $media_id ) ) { imagify_die(); } $result = $this->generate_nextgen_versions( $media_id, $context ); imagify_maybe_redirect( is_wp_error( $result ) ? $result : false ); if ( is_wp_error( $result ) ) { // Return an error message. $output = $result->get_error_message(); wp_send_json_error( [ 'html' => $output ] ); } wp_send_json_success(); } /** * Generate next-gen images if they are missing. * * @since 1.9.6 */ public function imagify_delete_nextgen_versions_callback() { $context = $this->get_context(); $media_id = $this->get_media_id(); if ( ! $media_id || ! $context ) { imagify_die( __( 'Invalid request', 'imagify' ) ); } imagify_check_nonce( 'imagify-delete-nextgen-versions-' . $media_id . '-' . $context ); if ( ! imagify_get_context( $context )->current_user_can( 'manual-restore', $media_id ) ) { imagify_die(); } $result = $this->delete_nextgen_versions( $media_id, $context ); imagify_maybe_redirect( is_wp_error( $result ) ? $result : false ); if ( is_wp_error( $result ) ) { // Return an error message. $output = $result->get_error_message(); wp_send_json_error( [ 'html' => $output ] ); } wp_send_json_success(); } /** * Process a restoration to the original attachment. * * @since 1.6.11 */ public function imagify_restore_callback() { $context = $this->get_context(); $media_id = $this->get_media_id(); if ( ! $media_id || ! $context ) { imagify_die( __( 'Invalid request', 'imagify' ) ); } imagify_check_nonce( 'imagify-restore-' . $media_id . '-' . $context ); if ( ! imagify_get_context( $context )->current_user_can( 'manual-restore', $media_id ) ) { imagify_die(); } $result = $this->restore_media( $media_id, $context ); imagify_maybe_redirect( is_wp_error( $result ) ? $result : false ); if ( is_wp_error( $result ) ) { // Return an error message. $output = $result->get_error_message(); wp_send_json_error( [ 'html' => $output ] ); } // Return the optimization button. $output = Imagify_Views::get_instance()->get_template( 'button/optimize', [ 'url' => get_imagify_admin_url( 'optimize', array( 'attachment_id' => $media_id, 'context' => $context, ) ), ] ); wp_send_json_success( [ 'html' => $output ] ); } /** ----------------------------------------------------------------------------------------- */ /** CUSTOM FOLDERS OPTIMIZATION CALLBACKS =================================================== */ /** ----------------------------------------------------------------------------------------- */ /** * Optimize a file. * * @since 1.7 */ public function imagify_optimize_file_callback() { imagify_check_nonce( 'imagify_optimize_file' ); $media_id = $this->get_media_id( 'GET', 'id' ); if ( ! $media_id ) { imagify_die( __( 'Invalid request', 'imagify' ) ); } if ( ! imagify_get_context( 'custom-folders' )->current_user_can( 'manual-optimize', $media_id ) ) { imagify_die(); } $result = $this->optimize_media( $media_id, 'custom-folders' ); imagify_maybe_redirect( is_wp_error( $result ) ? $result : false ); if ( is_wp_error( $result ) ) { // Return an error message. wp_send_json_error( $result->get_error_message() ); } wp_send_json_success(); } /** * Re-optimize a file. * * @since 1.7 */ public function imagify_reoptimize_file_callback() { imagify_check_nonce( 'imagify_reoptimize_file' ); $media_id = $this->get_media_id( 'GET', 'id' ); if ( ! $media_id ) { imagify_die( __( 'Invalid request', 'imagify' ) ); } if ( ! imagify_get_context( 'custom-folders' )->current_user_can( 'manual-optimize', $media_id ) ) { imagify_die(); } $level = $this->get_optimization_level( 'GET', 'level' ); $result = $this->reoptimize_media( $media_id, 'custom-folders', $level ); imagify_maybe_redirect( is_wp_error( $result ) ? $result : false ); if ( is_wp_error( $result ) ) { // Return an error message. wp_send_json_error( $result->get_error_message() ); } wp_send_json_success(); } /** * Restore a file. * * @since 1.7 */ public function imagify_restore_file_callback() { imagify_check_nonce( 'imagify_restore_file' ); $media_id = $this->get_media_id( 'GET', 'id' ); if ( ! $media_id ) { imagify_die( __( 'Invalid request', 'imagify' ) ); } if ( ! imagify_get_context( 'custom-folders' )->current_user_can( 'manual-restore', $media_id ) ) { imagify_die(); } $result = $this->restore_media( $media_id, 'custom-folders' ); imagify_maybe_redirect( is_wp_error( $result ) ? $result : false ); if ( is_wp_error( $result ) ) { // Return an error message. wp_send_json_error( $result->get_error_message() ); } $process = imagify_get_optimization_process( $media_id, 'custom-folders' ); $this->file_optimization_output( $process ); } /** * Check if a file has been modified, and update the database accordingly. * * @since 1.7 */ public function imagify_refresh_file_modified_callback() { imagify_check_nonce( 'imagify_refresh_file_modified' ); $media_id = $this->get_media_id( 'GET', 'id' ); if ( ! $media_id ) { imagify_die( __( 'Invalid request', 'imagify' ) ); } if ( ! imagify_get_context( 'custom-folders' )->current_user_can( 'manual-optimize', $media_id ) ) { imagify_die(); } $process = imagify_get_optimization_process( $media_id, 'custom-folders' ); $result = Imagify_Custom_Folders::refresh_file( $process ); if ( is_wp_error( $result ) ) { // The media is not valid or has been removed from the database. $message = $result->get_error_message(); imagify_maybe_redirect( $message ); wp_send_json_error( array( 'row' => $message, ) ); } imagify_maybe_redirect(); // Return some HTML to the ajax call. $this->file_optimization_output( $process ); } /** * Look for new files in custom folders. * * @since 1.7 */ public function imagify_scan_custom_folders_callback() { imagify_check_nonce( 'imagify_scan_custom_folders' ); if ( ! imagify_get_context( 'custom-folders' )->current_user_can( 'optimize' ) ) { imagify_die(); } $folder = (int) filter_input( INPUT_GET, 'folder', FILTER_VALIDATE_INT ); if ( $folder > 0 ) { // A specific custom folder (selected or not). $folders_db = Imagify_Folders_DB::get_instance(); $folders_key = $folders_db->get_primary_key(); $folder = $folders_db->get( $folder ); if ( ! $folder ) { // This should not happen. imagify_maybe_redirect( __( 'This folder is not in the database.', 'imagify' ) ); } $folder['folder_path'] = Imagify_Files_Scan::remove_placeholder( $folder['path'] ); $folders = array( $folder[ $folders_key ] => $folder, ); Imagify_Custom_Folders::get_files_from_folders( $folders, array( 'add_inactive_folder_files' => true, ) ); imagify_maybe_redirect(); } // All selected custom folders. $folders = Imagify_Custom_Folders::get_folders( array( 'active' => true, ) ); Imagify_Custom_Folders::get_files_from_folders( $folders ); imagify_maybe_redirect(); } /** ----------------------------------------------------------------------------------------- */ /** SETTINGS PAGE CALLBACKS ================================================================= */ /** ----------------------------------------------------------------------------------------- */ /** * Check if the backup directory is writable. * This is used to display an error message in the plugin's settings page. * * @since 1.6.11 */ public function imagify_check_backup_dir_is_writable_callback() { imagify_check_nonce( 'imagify_check_backup_dir_is_writable' ); if ( ! imagify_get_context( 'wp' )->current_user_can( 'manage' ) ) { imagify_die(); } wp_send_json_success( array( 'is_writable' => (int) Imagify_Requirements::attachments_backup_dir_is_writable(), ) ); } /** * Get files and folders that are direct children of a given folder. * * @since 1.7 */ public function imagify_get_files_tree_callback() { imagify_check_nonce( 'get-files-tree' ); if ( ! imagify_get_context( 'custom-folders' )->current_user_can( 'manage' ) ) { imagify_die(); } if ( ! isset( $_POST['folder'] ) || '' === $_POST['folder'] ) { imagify_die( __( 'Invalid request', 'imagify' ) ); } $folder = wp_unslash( $_POST['folder'] ); $folder = trailingslashit( sanitize_text_field( $folder ) ); $folder = realpath( $this->filesystem->get_site_root() . ltrim( $folder, '/' ) ); if ( ! $folder ) { imagify_die( __( 'This folder doesn\'t exist.', 'imagify' ) ); } if ( ! $this->filesystem->is_dir( $folder ) ) { imagify_die( __( 'This file is not a folder.', 'imagify' ) ); } $folder = $this->filesystem->normalize_dir_path( $folder ); if ( Imagify_Files_Scan::is_path_forbidden( $folder ) ) { imagify_die( __( 'This folder is not allowed.', 'imagify' ) ); } // Finally we made all our validations. $selected = ! empty( $_POST['selected'] ) && is_array( $_POST['selected'] ) ? array_flip( wp_unslash( $_POST['selected'] ) ) : array(); $views = Imagify_Views::get_instance(); $output = ''; if ( $this->filesystem->is_site_root( $folder ) ) { $output .= $views->get_template( 'part-settings-files-tree-row', array( 'relative_path' => '/', // Value #///# Label. 'checkbox_value' => '{{ROOT}}/#///#' . esc_attr__( 'Site\'s root', 'imagify' ), 'checkbox_id' => 'ABSPATH', 'checkbox_selected' => isset( $selected['{{ROOT}}/'] ), 'label' => __( 'Site\'s root', 'imagify' ), 'no_button' => true, ) ); } $dir = new DirectoryIterator( $folder ); $dir = new Imagify_Files_Iterator( $dir ); $images = 0; foreach ( new IteratorIterator( $dir ) as $file ) { if ( ! $file->isDir() ) { ++$images; continue; } $folder_path = trailingslashit( $file->getPathname() ); $relative_path = $this->filesystem->make_path_relative( $folder_path ); $placeholder = Imagify_Files_Scan::add_placeholder( $folder_path ); $output .= $views->get_template( 'part-settings-files-tree-row', array( 'relative_path' => esc_attr( $relative_path ), // Value #///# Label. 'checkbox_value' => esc_attr( $placeholder ) . '#///#' . esc_attr( $relative_path ), 'checkbox_id' => sanitize_html_class( $placeholder ), 'checkbox_selected' => isset( $selected[ $placeholder ] ), 'label' => $this->filesystem->file_name( $folder_path ), ) ); } if ( $images ) { /* translators: %s is a formatted number, dont use %d. */ $output .= '