' . __FUNCTION__ . '()' ); return apply_filters( 'ewww_image_optimizer_filter_page_output', $buffer ); } /** * Skips optimization when a file is within EWWW IO's own folder. * * @param bool $skip Defaults to false. * @param string $filename The name of the file about to be optimized. * @return bool True if the file is within the EWWW IO folder, unaltered otherwise. */ function ewww_image_optimizer_ignore_self( $skip, $filename ) { if ( 0 === strpos( $filename, EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH ) ) { return true; } return $skip; } /** * Gets the version number from a plugin file. * * @param string $plugin_file The path to the plugin's main file. * @return array With a single index, 'Version'. */ function ewww_image_optimizer_get_plugin_version( $plugin_file ) { $default_headers = array( 'Version' => 'Version', ); $plugin_data = get_file_data( $plugin_file, $default_headers, 'plugin' ); return $plugin_data; } /** * Checks to see if some other lazy loader is active. * * @return bool True if third-party lazy load detected, false otherwise. */ function ewwwio_other_lazy_detected() { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( class_exists( 'RocketLazyLoadPlugin\Plugin' ) || defined( 'ROCKET_LL_VERSION' ) ) { $rocketll_settings = get_option( 'rocket_lazyload_options' ); if ( is_array( $rocketll_settings ) && ! empty( $rocketll_settings['images'] ) ) { ewwwio_debug_message( 'rocket lazy detected (standalone free plugin)' ); return true; } } if ( class_exists( 'WP_Rocket\Plugin' ) || defined( 'WP_ROCKET_VERSION' ) ) { $rocket_settings = get_option( 'wp_rocket_settings' ); if ( is_array( $rocket_settings ) && ! empty( $rocket_settings['lazyload'] ) ) { ewwwio_debug_message( 'WP Rocket with lazy detected' ); return true; } } if ( class_exists( 'autoptimizeExtra' ) || defined( 'AUTOPTIMIZE_PLUGIN_VERSION' ) ) { $ao_extra = get_option( 'autoptimize_imgopt_settings' ); if ( ! empty( $ao_extra['autoptimize_imgopt_checkbox_field_3'] ) ) { ewwwio_debug_message( 'Autoptimize lazy detected' ); return true; } } if ( class_exists( 'SiteGround_Optimizer\Helper\Helper' ) && get_option( 'siteground_optimizer_lazyload_images' ) ) { ewwwio_debug_message( 'SG Optimizer lazy detected' ); return true; } if ( class_exists( '\A3Rev\LazyLoad' ) || defined( 'A3_LAZY_VERSION' ) ) { ewwwio_debug_message( 'A3 lazy detected' ); return true; } if ( class_exists( 'WpFastestCache' ) || defined( 'WPFC_WP_PLUGIN_DIR' ) ) { if ( ! empty( $GLOBALS['wp_fastest_cache_options']->wpFastestCacheLazyLoad ) ) { ewwwio_debug_message( 'WPFC lazy detected' ); return true; } } if ( class_exists( '\W3TC\Dispatcher' ) || defined( 'W3TC_VERSION' ) ) { if ( method_exists( '\W3TC\Dispatcher', 'config' ) ) { $w3tc_config = \W3TC\Dispatcher::config(); if ( method_exists( $w3tc_config, 'get_boolean' ) && $w3tc_config->get_boolean( 'lazyload.enabled' ) ) { ewwwio_debug_message( 'W3TC lazy detected' ); return true; } } } if ( class_exists( 'Jetpack' ) && method_exists( 'Jetpack', 'is_module_active' ) && Jetpack::is_module_active( 'lazy-images' ) ) { ewwwio_debug_message( 'Jetpack lazy detected' ); return true; } if ( class_exists( '\Automattic\Jetpack_Boost\Jetpack_Boost' ) ) { if ( \get_option( 'jetpack_boost_status_lazy-images' ) ) { ewwwio_debug_message( 'Jetpack Boost lazy detected' ); return true; } } return false; } /** * Checks to see if the WebP option from the Cache Enabler plugin is enabled. * * @return bool True if the WebP option for CE is enabled. */ function ewww_image_optimizer_ce_webp_enabled() { if ( class_exists( 'Cache_Enabler' ) ) { $ce_options = get_option( 'cache_enabler', array() ); if ( ! empty( $ce_options['convert_image_urls_to_webp'] ) || ! empty( $ce_options['webp'] ) ) { ewwwio_debug_message( 'Cache Enabler WebP option enabled' ); return true; } } return false; } /** * Checks to see if the WebP option from the SWIS Performance plugin is enabled. * * @return bool True if the WebP option for SWIS is enabled. */ function ewww_image_optimizer_swis_webp_enabled() { if ( function_exists( 'swis' ) && class_exists( '\SWIS\Cache' ) ) { $cache_settings = swis()->cache->get_settings(); if ( swis()->settings->get_option( 'cache' ) && ! empty( $cache_settings['webp'] ) ) { ewwwio_debug_message( 'SWIS WebP option enabled' ); return true; } } return false; } /** * Checks to see if there is a method available for WebP conversion. * * @return bool True if a WebP Convertor is available. */ function ewww_image_optimizer_webp_available() { return true; // Because API mode is the fallback and is free for everyone. if ( ! ewwwio()->local->exec_check() && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' ) && ! ewwwio()->imagick_supports_webp() && ! ewwwio()->gd_supports_webp() ) { return false; } return true; } /** * Checks to see if the WebP rules from WPFC are enabled. * * @return bool True if the WebP rules from WPFC are found. */ function ewww_image_optimizer_wpfc_webp_enabled() { if ( class_exists( 'WpFastestCache' ) ) { $wpfc_abspath = get_home_path() . '.htaccess'; ewwwio_debug_message( "looking for WPFC rules in $wpfc_abspath" ); $wpfc_rules = ewwwio_extract_from_markers( $wpfc_abspath, 'WEBPWpFastestCache' ); if ( empty( $wpfc_rules ) ) { $wpfc_abspath = ABSPATH . '.htaccess'; ewwwio_debug_message( "looking for WPFC rules in $wpfc_abspath" ); $wpfc_rules = ewwwio_extract_from_markers( $wpfc_abspath, 'WEBPWpFastestCache' ); } if ( ! empty( $wpfc_rules ) ) { ewwwio_debug_message( 'WPFC webp rules enabled' ); if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) ) { ewwwio_debug_message( 'removing htaccess webp to prevent ExactDN problems' ); insert_with_markers( $wpfc_abspath, 'WEBPWpFastestCache', '' ); return false; } return true; } } return false; } /** * Set default permissions for manual operations (single image optimize, convert, restore). * * @param string $permissions A valid WP capability level. * @return string Either the original value, unchanged, or the default capability level. */ function ewww_image_optimizer_manual_permissions( $permissions ) { if ( empty( $permissions ) ) { return 'edit_others_posts'; } return $permissions; } /** * Set default permissions for admin (configuration) and bulk operations. * * @param string $permissions A valid WP capability level. * @return string Either the original value, unchanged, or the default capability level. */ function ewww_image_optimizer_admin_permissions( $permissions ) { if ( empty( $permissions ) ) { return 'activate_plugins'; } return $permissions; } /** * Set default permissions for multisite/network admin (configuration) operations. * * @param string $permissions A valid WP capability level. * @return string Either the original value, unchanged, or the default capability level. */ function ewww_image_optimizer_superadmin_permissions( $permissions ) { if ( empty( $permissions ) ) { return 'manage_network_options'; } return $permissions; } if ( ! function_exists( 'wp_getimagesize' ) ) { /** * Stub for WP prior to 5.7. * * @param string $filename The file path. * @return array|false Array of image information or false on failure. */ function wp_getimagesize( $filename ) { // phpcs:ignore WordPress.PHP.NoSilencedErrors return @getimagesize( $filename ); } } if ( ! function_exists( 'str_ends_with' ) ) { /** * Polyfill for `str_ends_with()` function added in WP 5.9 or PHP 8.0. * * Performs a case-sensitive check indicating if * the haystack ends with needle. * * @since 6.8.1 * * @param string $haystack The string to search in. * @param string $needle The substring to search for in the `$haystack`. * @return bool True if `$haystack` ends with `$needle`, otherwise false. */ function str_ends_with( $haystack, $needle ) { if ( '' === $haystack && '' !== $needle ) { return false; } $len = strlen( $needle ); return 0 === substr_compare( $haystack, $needle, -$len, $len ); } } /** * Find out if set_time_limit() is allowed. */ function ewww_image_optimizer_stl_check() { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( defined( 'EWWW_IMAGE_OPTIMIZER_DISABLE_STL' ) && EWWW_IMAGE_OPTIMIZER_DISABLE_STL ) { ewwwio_debug_message( 'stl disabled by user' ); return false; } if ( function_exists( 'wp_is_ini_value_changeable' ) && ! wp_is_ini_value_changeable( 'max_execution_time' ) ) { ewwwio_debug_message( 'max_execution_time not configurable' ); return false; } return ewwwio()->function_exists( '\set_time_limit' ); } /** * Save the multi-site settings, if this is the WP admin, and they've been POSTed. */ function ewww_image_optimizer_save_network_settings() { if ( ! is_admin() ) { return; } if ( ! function_exists( 'is_plugin_active_for_network' ) && is_multisite() ) { // Need to include the plugin library for the is_plugin_active function. require_once ABSPATH . 'wp-admin/includes/plugin.php'; } if ( is_multisite() && is_plugin_active_for_network( EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE_REL ) ) { ewwwio_debug_message( 'saving network settings' ); // Set the common network settings if they have been POSTed. if ( ! empty( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), 'ewww_image_optimizer_options-options' ) && isset( $_POST['option_page'] ) && false !== strpos( sanitize_text_field( wp_unslash( $_POST['option_page'] ) ), 'ewww_image_optimizer_options' ) && current_user_can( 'manage_network_options' ) && ! get_site_option( 'ewww_image_optimizer_allow_multisite_override' ) && false === strpos( wp_get_referer(), 'options-general' ) ) { ewwwio_debug_message( 'network-wide settings, no override' ); $ewww_image_optimizer_debug = ( empty( $_POST['ewww_image_optimizer_debug'] ) ? false : true ); update_site_option( 'ewww_image_optimizer_debug', $ewww_image_optimizer_debug ); $ewww_image_optimizer_metadata_remove = ( empty( $_POST['ewww_image_optimizer_metadata_remove'] ) ? false : true ); update_site_option( 'ewww_image_optimizer_metadata_remove', $ewww_image_optimizer_metadata_remove ); $ewww_image_optimizer_jpg_level = empty( $_POST['ewww_image_optimizer_jpg_level'] ) ? '' : (int) $_POST['ewww_image_optimizer_jpg_level']; update_site_option( 'ewww_image_optimizer_jpg_level', $ewww_image_optimizer_jpg_level ); $ewww_image_optimizer_png_level = empty( $_POST['ewww_image_optimizer_png_level'] ) ? '' : (int) $_POST['ewww_image_optimizer_png_level']; update_site_option( 'ewww_image_optimizer_png_level', $ewww_image_optimizer_png_level ); $ewww_image_optimizer_gif_level = empty( $_POST['ewww_image_optimizer_gif_level'] ) ? '' : (int) $_POST['ewww_image_optimizer_gif_level']; update_site_option( 'ewww_image_optimizer_gif_level', $ewww_image_optimizer_gif_level ); $ewww_image_optimizer_pdf_level = empty( $_POST['ewww_image_optimizer_pdf_level'] ) ? '' : (int) $_POST['ewww_image_optimizer_pdf_level']; update_site_option( 'ewww_image_optimizer_pdf_level', $ewww_image_optimizer_pdf_level ); $ewww_image_optimizer_svg_level = empty( $_POST['ewww_image_optimizer_svg_level'] ) ? '' : (int) $_POST['ewww_image_optimizer_svg_level']; update_site_option( 'ewww_image_optimizer_svg_level', $ewww_image_optimizer_svg_level ); $ewww_image_optimizer_delete_originals = ( empty( $_POST['ewww_image_optimizer_delete_originals'] ) ? false : true ); update_site_option( 'ewww_image_optimizer_delete_originals', $ewww_image_optimizer_delete_originals ); $ewww_image_optimizer_jpg_to_png = ( empty( $_POST['ewww_image_optimizer_jpg_to_png'] ) ? false : true ); update_site_option( 'ewww_image_optimizer_jpg_to_png', $ewww_image_optimizer_jpg_to_png ); $ewww_image_optimizer_png_to_jpg = ( empty( $_POST['ewww_image_optimizer_png_to_jpg'] ) ? false : true ); update_site_option( 'ewww_image_optimizer_png_to_jpg', $ewww_image_optimizer_png_to_jpg ); $ewww_image_optimizer_gif_to_png = ( empty( $_POST['ewww_image_optimizer_gif_to_png'] ) ? false : true ); update_site_option( 'ewww_image_optimizer_gif_to_png', $ewww_image_optimizer_gif_to_png ); $ewww_image_optimizer_webp = ( empty( $_POST['ewww_image_optimizer_webp'] ) ? false : true ); update_site_option( 'ewww_image_optimizer_webp', $ewww_image_optimizer_webp ); $ewww_image_optimizer_jpg_background = empty( $_POST['ewww_image_optimizer_jpg_background'] ) ? '' : sanitize_text_field( wp_unslash( $_POST['ewww_image_optimizer_jpg_background'] ) ); update_site_option( 'ewww_image_optimizer_jpg_background', ewww_image_optimizer_jpg_background( $ewww_image_optimizer_jpg_background ) ); $ewww_image_optimizer_sharpen = empty( $_POST['ewww_image_optimizer_sharpen'] ) ? false : true; update_site_option( 'ewww_image_optimizer_sharpen', $ewww_image_optimizer_sharpen ); $ewww_image_optimizer_jpg_quality = empty( $_POST['ewww_image_optimizer_jpg_quality'] ) ? '' : (int) $_POST['ewww_image_optimizer_jpg_quality']; update_site_option( 'ewww_image_optimizer_jpg_quality', ewww_image_optimizer_jpg_quality( $ewww_image_optimizer_jpg_quality ) ); $ewww_image_optimizer_webp_quality = empty( $_POST['ewww_image_optimizer_webp_quality'] ) ? '' : (int) $_POST['ewww_image_optimizer_webp_quality']; update_site_option( 'ewww_image_optimizer_webp_quality', ewww_image_optimizer_webp_quality( $ewww_image_optimizer_webp_quality ) ); $ewww_image_optimizer_avif_quality = empty( $_POST['ewww_image_optimizer_avif_quality'] ) ? '' : (int) $_POST['ewww_image_optimizer_avif_quality']; update_site_option( 'ewww_image_optimizer_avif_quality', ewww_image_optimizer_avif_quality( $ewww_image_optimizer_avif_quality ) ); $ewww_image_optimizer_disable_convert_links = ( empty( $_POST['ewww_image_optimizer_disable_convert_links'] ) ? false : true ); update_site_option( 'ewww_image_optimizer_disable_convert_links', $ewww_image_optimizer_disable_convert_links ); $ewww_image_optimizer_backup_files = ( empty( $_POST['ewww_image_optimizer_backup_files'] ) ? '' : sanitize_text_field( wp_unslash( $_POST['ewww_image_optimizer_backup_files'] ) ) ); update_site_option( 'ewww_image_optimizer_backup_files', $ewww_image_optimizer_backup_files ); $ewww_image_optimizer_auto = ( empty( $_POST['ewww_image_optimizer_auto'] ) ? false : true ); update_site_option( 'ewww_image_optimizer_auto', $ewww_image_optimizer_auto ); $ewww_image_optimizer_aux_paths = empty( $_POST['ewww_image_optimizer_aux_paths'] ) ? '' : sanitize_textarea_field( wp_unslash( $_POST['ewww_image_optimizer_aux_paths'] ) ); update_site_option( 'ewww_image_optimizer_aux_paths', ewww_image_optimizer_aux_paths_sanitize( $ewww_image_optimizer_aux_paths ) ); $ewww_image_optimizer_exclude_paths = empty( $_POST['ewww_image_optimizer_exclude_paths'] ) ? '' : sanitize_textarea_field( wp_unslash( $_POST['ewww_image_optimizer_exclude_paths'] ) ); update_site_option( 'ewww_image_optimizer_exclude_paths', ewww_image_optimizer_exclude_paths_sanitize( $ewww_image_optimizer_exclude_paths ) ); $ewww_image_optimizer_enable_cloudinary = ( empty( $_POST['ewww_image_optimizer_enable_cloudinary'] ) ? false : true ); update_site_option( 'ewww_image_optimizer_enable_cloudinary', $ewww_image_optimizer_enable_cloudinary ); $exactdn_all_the_things = ( empty( $_POST['exactdn_all_the_things'] ) ? false : true ); update_site_option( 'exactdn_all_the_things', $exactdn_all_the_things ); $exactdn_lossy = ( empty( $_POST['exactdn_lossy'] ) ? false : true ); update_site_option( 'exactdn_lossy', $exactdn_lossy ); $exactdn_exclude = empty( $_POST['exactdn_exclude'] ) ? '' : sanitize_textarea_field( wp_unslash( $_POST['exactdn_exclude'] ) ); update_site_option( 'exactdn_exclude', ewww_image_optimizer_exclude_paths_sanitize( $exactdn_exclude ) ); $ewww_image_optimizer_add_missing_dims = ( empty( $_POST['ewww_image_optimizer_add_missing_dims'] ) ? false : true ); update_site_option( 'ewww_image_optimizer_add_missing_dims', $ewww_image_optimizer_add_missing_dims ); $ewww_image_optimizer_lazy_load = ( empty( $_POST['ewww_image_optimizer_lazy_load'] ) ? false : true ); update_site_option( 'ewww_image_optimizer_lazy_load', $ewww_image_optimizer_lazy_load ); $ewww_image_optimizer_ll_autoscale = ( empty( $_POST['ewww_image_optimizer_ll_autoscale'] ) ? false : true ); update_site_option( 'ewww_image_optimizer_ll_autoscale', $ewww_image_optimizer_ll_autoscale ); $ewww_image_optimizer_use_lqip = ( empty( $_POST['ewww_image_optimizer_use_lqip'] ) ? false : true ); update_site_option( 'ewww_image_optimizer_use_lqip', $ewww_image_optimizer_use_lqip ); // Using sanitize_text_field instead of textarea on purpose. $ewww_image_optimizer_ll_all_things = empty( $_POST['ewww_image_optimizer_ll_all_things'] ) ? '' : sanitize_text_field( wp_unslash( $_POST['ewww_image_optimizer_ll_all_things'] ) ); update_site_option( 'ewww_image_optimizer_ll_all_things', $ewww_image_optimizer_ll_all_things ); $ewww_image_optimizer_ll_exclude = empty( $_POST['ewww_image_optimizer_ll_exclude'] ) ? '' : sanitize_textarea_field( wp_unslash( $_POST['ewww_image_optimizer_ll_exclude'] ) ); update_site_option( 'ewww_image_optimizer_ll_exclude', ewww_image_optimizer_exclude_paths_sanitize( $ewww_image_optimizer_ll_exclude ) ); $ewww_image_optimizer_maxmediawidth = empty( $_POST['ewww_image_optimizer_maxmediawidth'] ) ? 0 : (int) $_POST['ewww_image_optimizer_maxmediawidth']; update_site_option( 'ewww_image_optimizer_maxmediawidth', $ewww_image_optimizer_maxmediawidth ); $ewww_image_optimizer_maxmediaheight = empty( $_POST['ewww_image_optimizer_maxmediaheight'] ) ? 0 : (int) $_POST['ewww_image_optimizer_maxmediaheight']; update_site_option( 'ewww_image_optimizer_maxmediaheight', $ewww_image_optimizer_maxmediaheight ); $ewww_image_optimizer_resize_detection = ( empty( $_POST['ewww_image_optimizer_resize_detection'] ) ? false : true ); update_site_option( 'ewww_image_optimizer_resize_detection', $ewww_image_optimizer_resize_detection ); $ewww_image_optimizer_resize_existing = ( empty( $_POST['ewww_image_optimizer_resize_existing'] ) ? false : true ); update_site_option( 'ewww_image_optimizer_resize_existing', $ewww_image_optimizer_resize_existing ); $ewww_image_optimizer_resize_other_existing = ( empty( $_POST['ewww_image_optimizer_resize_other_existing'] ) ? false : true ); update_site_option( 'ewww_image_optimizer_resize_other_existing', $ewww_image_optimizer_resize_other_existing ); $ewww_image_optimizer_include_media_paths = ( empty( $_POST['ewww_image_optimizer_include_media_paths'] ) ? false : true ); update_site_option( 'ewww_image_optimizer_include_media_paths', $ewww_image_optimizer_include_media_paths ); $ewww_image_optimizer_include_originals = ( empty( $_POST['ewww_image_optimizer_include_originals'] ) ? false : true ); update_site_option( 'ewww_image_optimizer_include_originals', $ewww_image_optimizer_include_originals ); $ewww_image_optimizer_webp_for_cdn = ( empty( $_POST['ewww_image_optimizer_webp_for_cdn'] ) ? false : true ); update_site_option( 'ewww_image_optimizer_webp_for_cdn', $ewww_image_optimizer_webp_for_cdn ); $ewww_image_optimizer_picture_webp = ( empty( $_POST['ewww_image_optimizer_picture_webp'] ) ? false : true ); update_site_option( 'ewww_image_optimizer_picture_webp', $ewww_image_optimizer_picture_webp ); $ewww_image_optimizer_webp_rewrite_exclude = empty( $_POST['ewww_image_optimizer_webp_rewrite_exclude'] ) ? '' : sanitize_textarea_field( wp_unslash( $_POST['ewww_image_optimizer_webp_rewrite_exclude'] ) ); update_site_option( 'ewww_image_optimizer_webp_rewrite_exclude', ewww_image_optimizer_exclude_paths_sanitize( $ewww_image_optimizer_webp_rewrite_exclude ) ); $ewww_image_optimizer_webp_force = ( empty( $_POST['ewww_image_optimizer_webp_force'] ) ? false : true ); update_site_option( 'ewww_image_optimizer_webp_force', $ewww_image_optimizer_webp_force ); $ewww_image_optimizer_webp_paths = ( empty( $_POST['ewww_image_optimizer_webp_paths'] ) ? '' : sanitize_textarea_field( wp_unslash( $_POST['ewww_image_optimizer_webp_paths'] ) ) ); update_site_option( 'ewww_image_optimizer_webp_paths', ewww_image_optimizer_webp_paths_sanitize( $ewww_image_optimizer_webp_paths ) ); $ewww_image_optimizer_allow_multisite_override = empty( $_POST['ewww_image_optimizer_allow_multisite_override'] ) ? false : true; update_site_option( 'ewww_image_optimizer_allow_multisite_override', $ewww_image_optimizer_allow_multisite_override ); $ewww_image_optimizer_enable_help = empty( $_POST['ewww_image_optimizer_enable_help'] ) ? false : true; update_site_option( 'ewww_image_optimizer_enable_help', $ewww_image_optimizer_enable_help ); $ewww_image_optimizer_allow_tracking = empty( $_POST['ewww_image_optimizer_allow_tracking'] ) ? false : ewwwio()->tracking->check_for_settings_optin( (bool) $_POST['ewww_image_optimizer_allow_tracking'] ); update_site_option( 'ewww_image_optimizer_allow_tracking', $ewww_image_optimizer_allow_tracking ); add_action( 'network_admin_notices', 'ewww_image_optimizer_network_settings_saved' ); } elseif ( isset( $_POST['ewww_image_optimizer_allow_multisite_override_active'] ) && current_user_can( 'manage_network_options' ) && isset( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), 'ewww_image_optimizer_options-options' ) ) { ewwwio_debug_message( 'network-wide settings, single-site overriding' ); $ewww_image_optimizer_allow_multisite_override = empty( $_POST['ewww_image_optimizer_allow_multisite_override'] ) ? false : true; update_site_option( 'ewww_image_optimizer_allow_multisite_override', $ewww_image_optimizer_allow_multisite_override ); $ewww_image_optimizer_allow_tracking = empty( $_POST['ewww_image_optimizer_allow_tracking'] ) ? false : ewwwio()->tracking->check_for_settings_optin( (bool) $_POST['ewww_image_optimizer_allow_tracking'] ); update_site_option( 'ewww_image_optimizer_allow_tracking', $ewww_image_optimizer_allow_tracking ); add_action( 'network_admin_notices', 'ewww_image_optimizer_network_settings_saved' ); } // End if(). } // End if(). if ( is_multisite() && get_site_option( 'ewww_image_optimizer_allow_multisite_override' ) && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_jpg_level' ) && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_png_level' ) && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_gif_level' ) && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_pdf_level' ) && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_svg_level' ) ) { ewwwio()->set_defaults(); update_option( 'ewww_image_optimizer_disable_pngout', true ); update_option( 'ewww_image_optimizer_disable_svgcleaner', true ); update_option( 'ewww_image_optimizer_optipng_level', 2 ); update_option( 'ewww_image_optimizer_pngout_level', 2 ); update_option( 'ewww_image_optimizer_metadata_remove', true ); update_option( 'ewww_image_optimizer_jpg_level', '10' ); update_option( 'ewww_image_optimizer_png_level', '10' ); update_option( 'ewww_image_optimizer_gif_level', '10' ); update_option( 'ewww_image_optimizer_svg_level', 0 ); } } /** * Load plugin compat on the plugins_loaded hook, which is about as early as possible. */ function ewww_image_optimizer_load_plugin_compat() { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( ewww_image_optimizer_s3_uploads_enabled() ) { ewwwio_debug_message( 's3-uploads detected, deferring resize_upload' ); add_filter( 'ewww_image_optimizer_defer_resizing', '__return_true' ); } $active_plugins = get_option( 'active_plugins' ); if ( is_multisite() && is_array( $active_plugins ) ) { $sitewide_plugins = get_site_option( 'active_sitewide_plugins' ); if ( is_array( $sitewide_plugins ) ) { $active_plugins = array_merge( $active_plugins, array_flip( $sitewide_plugins ) ); } } if ( ewww_image_optimizer_iterable( $active_plugins ) ) { ewwwio_debug_message( 'checking active plugins' ); foreach ( $active_plugins as $active_plugin ) { if ( strpos( $active_plugin, '/nggallery.php' ) || strpos( $active_plugin, '\nggallery.php' ) ) { $ngg = ewww_image_optimizer_get_plugin_version( trailingslashit( WP_PLUGIN_DIR ) . $active_plugin ); // Include the file that loads the nextgen gallery optimization functions. ewwwio_debug_message( 'Nextgen version: ' . $ngg['Version'] ); if ( 1 < intval( substr( $ngg['Version'], 0, 1 ) ) ) { // For Nextgen 2+ support. $nextgen_major_version = substr( $ngg['Version'], 0, 1 ); ewwwio_debug_message( "loading nextgen $nextgen_major_version support for $active_plugin" ); require_once EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-ewww-nextgen.php'; } else { preg_match( '/\d+\.\d+\.(\d+)/', $ngg['Version'], $nextgen_minor_version ); if ( ! empty( $nextgen_minor_version[1] ) && $nextgen_minor_version[1] < 14 ) { ewwwio_debug_message( "NOT loading nextgen legacy support for $active_plugin" ); } elseif ( ! empty( $nextgen_minor_version[1] ) && $nextgen_minor_version[1] > 13 ) { ewwwio_debug_message( "loading nextcellent support for $active_plugin" ); require_once EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-ewww-nextcellent.php'; } } } if ( strpos( $active_plugin, '/flag.php' ) || strpos( $active_plugin, '\flag.php' ) ) { ewwwio_debug_message( "loading flagallery support for $active_plugin" ); // Include the file that loads the grand flagallery optimization functions. require_once EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-ewww-flag.php'; } } } } /** * Runs early for checks that need to happen on init before anything else. */ function ewww_image_optimizer_init() { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); // For the settings page, check for the enable-local param and take appropriate action. if ( ! empty( $_GET['enable-local'] ) && ! empty( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), 'ewww_image_optimizer_options-options' ) ) { update_option( 'ewww_image_optimizer_ludicrous_mode', true ); update_site_option( 'ewww_image_optimizer_ludicrous_mode', true ); } elseif ( isset( $_GET['enable-local'] ) && ! (bool) $_GET['enable-local'] && ! empty( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), 'ewww_image_optimizer_options-options' ) ) { delete_option( 'ewww_image_optimizer_ludicrous_mode' ); delete_site_option( 'ewww_image_optimizer_ludicrous_mode' ); } if ( ! empty( $_GET['complete_wizard'] ) && ! empty( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), 'ewww_image_optimizer_options-options' ) ) { update_option( 'ewww_image_optimizer_wizard_complete', true, false ); } if ( ! empty( $_GET['uncomplete_wizard'] ) && ! empty( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), 'ewww_image_optimizer_options-options' ) ) { update_option( 'ewww_image_optimizer_wizard_complete', false, false ); } if ( defined( 'DOING_WPLR_REQUEST' ) && DOING_WPLR_REQUEST ) { // Unhook all automatic processing, and save an option that (does not autoload) tells the user LR Sync regenerated their images and they should run the bulk optimizer. remove_filter( 'wp_image_editors', 'ewww_image_optimizer_load_editor', 60 ); remove_filter( 'wp_generate_attachment_metadata', 'ewww_image_optimizer_resize_from_meta_data', 15 ); add_action( 'wplr_add_media', 'ewww_image_optimizer_lr_sync_update' ); add_action( 'wplr_update_media', 'ewww_image_optimizer_lr_sync_update' ); add_filter( 'ewww_image_optimizer_allowed_reopt', '__return_true' ); } } /** * Plugin upgrade function * * @global object $wpdb */ function ewww_image_optimizer_upgrade() { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); global $ewwwio_upgrading; $ewwwio_upgrading = false; if ( get_option( 'ewww_image_optimizer_version' ) < EWWW_IMAGE_OPTIMIZER_VERSION ) { if ( wp_doing_ajax() && ! empty( $_POST['ewwwio_test_verify'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification return; } $ewwwio_upgrading = true; ewww_image_optimizer_install_table(); ewwwio()->set_defaults(); ewww_image_optimizer_enable_background_optimization(); // This will get re-enabled if things are too slow. ewww_image_optimizer_set_option( 'exactdn_prevent_db_queries', false ); if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) && ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn_verify_method' ) > 0 ) { delete_option( 'ewww_image_optimizer_exactdn_verify_method' ); delete_site_option( 'ewww_image_optimizer_exactdn_verify_method' ); } if ( get_option( 'ewww_image_optimizer_version' ) < 297.5 ) { // Cleanup background test mess. wp_clear_scheduled_hook( 'wp_ewwwio_test_optimize_cron' ); global $wpdb; if ( is_multisite() ) { $wpdb->query( "DELETE FROM $wpdb->sitemeta WHERE meta_key LIKE 'wp_ewwwio_test_optimize_batch_%'" ); } $wpdb->query( "DELETE FROM $wpdb->options WHERE option_name LIKE 'wp_ewwwio_test_optimize_batch_%'" ); } if ( ! get_option( 'ewww_image_optimizer_version' ) && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) ) { add_option( 'exactdn_never_been_active', true, '', false ); } if ( get_option( 'ewww_image_optimizer_version' ) < 280 ) { ewww_image_optimizer_migrate_settings_to_levels(); } if ( get_option( 'ewww_image_optimizer_version' ) > 0 && get_option( 'ewww_image_optimizer_version' ) < 434 && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_jpegtran_copy' ) ) { ewww_image_optimizer_set_option( 'ewww_image_optimizer_metadata_remove', false ); } if ( get_option( 'ewww_image_optimizer_version' ) < 454 ) { update_option( 'ewww_image_optimizer_bulk_resume', '' ); update_option( 'ewww_image_optimizer_aux_resume', '' ); ewww_image_optimizer_delete_pending(); // Make sure some of our options are not autoloaded (since they can be huge). $bulk_attachments = get_option( 'ewww_image_optimizer_flag_attachments', '' ); delete_option( 'ewww_image_optimizer_flag_attachments' ); add_option( 'ewww_image_optimizer_flag_attachments', $bulk_attachments, '', 'no' ); $bulk_attachments = get_option( 'ewww_image_optimizer_ngg_attachments', '' ); delete_option( 'ewww_image_optimizer_ngg_attachments' ); add_option( 'ewww_image_optimizer_ngg_attachments', $bulk_attachments, '', 'no' ); } if ( get_option( 'ewww_image_optimizer_version' ) < 530 ) { ewww_image_optimizer_migrate_option_queue_to_table(); } if ( get_option( 'ewww_image_optimizer_version' ) < 550 && ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_force' ) ) { ewww_image_optimizer_set_option( 'ewww_image_optimizer_force_gif2webp', false ); } elseif ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_force_gif2webp' ) ) { ewww_image_optimizer_set_option( 'ewww_image_optimizer_force_gif2webp', true ); } if ( get_option( 'ewww_image_optimizer_version' ) <= 601.0 && PHP_OS !== 'WINNT' && ewwwio_is_file( EWWW_IMAGE_OPTIMIZER_TOOL_PATH . '/pngout-static' ) && is_writable( EWWW_IMAGE_OPTIMIZER_TOOL_PATH . '/pngout-static' ) ) { ewwwio_debug_message( 'removing old version of pngout' ); ewwwio_delete_file( EWWW_IMAGE_OPTIMIZER_TOOL_PATH . '/pngout-static' ); } if ( get_option( 'ewww_image_optimizer_version' ) < 661 && get_option( 'ewww_image_optimizer_exactdn' ) && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_ludicrous_mode' ) && ! ewww_image_optimizer_get_option( 'exactdn_lossy' ) ) { ewww_image_optimizer_set_option( 'exactdn_lossy', true ); } if ( get_option( 'ewww_image_optimizer_version' ) <= 670 && ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ) ) { $backup_mode = ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ); if ( 'local' !== $backup_mode && 'cloud' !== $backup_mode ) { ewww_image_optimizer_set_option( 'ewww_image_optimizer_backup_files', 'cloud' ); } } if ( get_option( 'ewww_image_optimizer_local_mode' ) || get_site_option( 'ewww_image_optimizer_local_mode' ) ) { update_option( 'ewww_image_optimizer_ludicrous_mode', true ); update_site_option( 'ewww_image_optimizer_ludicrous_mode', true ); delete_option( 'ewww_image_optimizer_local_mode' ); delete_site_option( 'ewww_image_optimizer_local_mode' ); } if ( get_option( 'ewww_image_optimizer_version' ) && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_review_time' ) ) { $review_time = rand( time(), time() + 51 * DAY_IN_SECONDS ); add_option( 'ewww_image_optimizer_review_time', $review_time, '', false ); add_site_option( 'ewww_image_optimizer_review_time', $review_time ); } elseif ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_review_time' ) ) { $review_time = time() + 7 * DAY_IN_SECONDS; add_option( 'ewww_image_optimizer_review_time', $review_time, '', false ); add_site_option( 'ewww_image_optimizer_review_time', $review_time ); } if ( get_option( 'ewww_image_optimizer_version' ) && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_wizard_complete' ) ) { add_option( 'ewww_image_optimizer_wizard_complete', true, '', false ); add_site_option( 'ewww_image_optimizer_wizard_complete', true ); } if ( is_file( EWWWIO_CONTENT_DIR . 'debug.log' ) && is_writable( EWWWIO_CONTENT_DIR . 'debug.log' ) ) { unlink( EWWWIO_CONTENT_DIR . 'debug.log' ); } ewww_image_optimizer_remove_obsolete_settings(); update_option( 'ewww_image_optimizer_version', EWWW_IMAGE_OPTIMIZER_VERSION ); } ewwwio_memory( __FUNCTION__ ); } /** * Tests background optimization. * * Send a known packet to admin-ajax.php via the EWWW\Async_Test_Request class. */ function ewww_image_optimizer_enable_background_optimization() { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( ewww_image_optimizer_detect_wpsf_location_lock() ) { return; } ewww_image_optimizer_set_option( 'ewww_image_optimizer_background_optimization', false ); ewwwio_debug_message( 'running test async handler' ); ewwwio()->async_test_request->data( array( 'ewwwio_test_verify' => '949c34123cf2a4e4ce2f985135830df4a1b2adc24905f53d2fd3f5df5b162932' ) )->dispatch(); ewww_image_optimizer_debug_log(); } /** * Re-tests background optimization at a user's request. */ function ewww_image_optimizer_retest_background_optimization() { if ( ! current_user_can( apply_filters( 'ewww_image_optimizer_admin_permissions', '' ) ) ) { wp_die( esc_html__( 'Access denied.', 'ewww-image-optimizer' ) ); } ewww_image_optimizer_enable_background_optimization(); sleep( 10 ); $sendback = wp_get_referer(); wp_safe_redirect( $sendback ); exit; } /** * Apply 6.2.0+ current_timestamp db upgrade. */ function ewww_image_optimizer_620_upgrade() { if ( ! current_user_can( apply_filters( 'ewww_image_optimizer_admin_permissions', '' ) ) ) { wp_die( esc_html__( 'Access denied.', 'ewww-image-optimizer' ) ); } delete_transient( 'ewww_image_optimizer_620_upgrade_needed' ); global $wpdb; $suppress = $wpdb->suppress_errors(); $wpdb->query( "ALTER TABLE $wpdb->ewwwio_images MODIFY updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" ); $wpdb->suppress_errors( $suppress ); wp_safe_redirect( wp_get_referer() ); exit; } /** * Setup wp_cron tasks for scheduled optimization. * * @global object $wpdb * * @param string $event Name of cron hook to schedule. */ function ewww_image_optimizer_cron_setup( $event ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); // Setup scheduled optimization if the user has enabled it, and it isn't already scheduled. if ( ewww_image_optimizer_get_option( $event ) && ! wp_next_scheduled( $event ) ) { ewwwio_debug_message( "scheduling $event" ); wp_schedule_event( time(), apply_filters( 'ewww_image_optimizer_schedule', 'hourly', $event ), $event ); } elseif ( ewww_image_optimizer_get_option( $event ) ) { ewwwio_debug_message( "$event already scheduled: " . wp_next_scheduled( $event ) ); } elseif ( wp_next_scheduled( $event ) ) { ewwwio_debug_message( "un-scheduling $event" ); wp_clear_scheduled_hook( $event ); if ( ! function_exists( 'is_plugin_active_for_network' ) && is_multisite() ) { // Need to include the plugin library for the is_plugin_active function. require_once ABSPATH . 'wp-admin/includes/plugin.php'; } if ( is_multisite() && is_plugin_active_for_network( EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE_REL ) ) { global $wpdb; $blogs = $wpdb->get_results( $wpdb->prepare( "SELECT blog_id FROM $wpdb->blogs WHERE site_id = %d", $wpdb->siteid ), ARRAY_A ); if ( ewww_image_optimizer_iterable( $blogs ) ) { foreach ( $blogs as $blog ) { switch_to_blog( $blog['blog_id'] ); wp_clear_scheduled_hook( $event ); restore_current_blog(); } } } } } /** * Checks to see if this is an AJAX request, and whether the WP_Image_Editor hooks should be undone. * * @since 3.3.0 */ function ewww_image_optimizer_ajax_compat_check() { if ( ! wp_doing_ajax() ) { return; } ewwwio_debug_message( '' . __FUNCTION__ . '()' ); $action = ! empty( $_REQUEST['action'] ) ? sanitize_key( $_REQUEST['action'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification if ( $action ) { ewwwio_debug_message( "doing $action" ); } // Check for (Force) Regenerate Thumbnails action (includes MLP regenerate). if ( 'regeneratethumbnail' === $action || 'rta_regenerate_thumbnails' === $action || 'meauh_save_image' === $action || 'hotspot_save' === $action ) { ewwwio_debug_message( 'doing regeneratethumbnail' ); ewww_image_optimizer_image_sizes( false ); add_filter( 'ewww_image_optimizer_allowed_reopt', '__return_true' ); return; } if ( 'mic_crop_image' === $action ) { ewwwio_debug_message( 'doing Manual Image Crop' ); if ( ! defined( 'EWWWIO_EDITOR_OVERWRITE' ) ) { define( 'EWWWIO_EDITOR_OVERWRITE', true ); } add_filter( 'ewww_image_optimizer_allowed_reopt', '__return_true' ); return; } if ( false !== strpos( $action, 'wc_regenerate_images' ) ) { // Unhook all automatic processing, and save an option that (does not autoload) tells the user WC regenerated their images and they should run the bulk optimizer. remove_filter( 'wp_image_editors', 'ewww_image_optimizer_load_editor', 60 ); remove_filter( 'wp_generate_attachment_metadata', 'ewww_image_optimizer_resize_from_meta_data', 15 ); update_option( 'ewww_image_optimizer_wc_regen', true, false ); return; } // Check for Image Watermark plugin. $iwaction = ! empty( $_REQUEST['iw-action'] ) ? sanitize_key( $_REQUEST['iw-action'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification if ( $iwaction ) { ewwwio_debug_message( "doing $iwaction" ); global $ewww_preempt_editor; $ewww_preempt_editor = true; if ( 'applywatermark' === $iwaction ) { remove_filter( 'wp_generate_attachment_metadata', 'ewww_image_optimizer_resize_from_meta_data', 15 ); add_action( 'iw_after_apply_watermark', 'ewww_image_optimizer_single_size_optimize', 10, 2 ); } add_filter( 'ewww_image_optimizer_allowed_reopt', '__return_true' ); return; } // Check for other MLP actions, including multi-regen. if ( class_exists( 'MaxGalleriaMediaLib' ) && ( 'regen_mlp_thumbnails' === $action || 'move_media' === $action || 'copy_media' === $action || 'maxgalleria_rename_image' === $action ) ) { ewwwio_debug_message( 'doing regen_mlp_thumbnails' ); ewww_image_optimizer_image_sizes( false ); add_filter( 'ewww_image_optimizer_allowed_reopt', '__return_true' ); return; } // Check for MLP upload. if ( class_exists( 'MaxGalleriaMediaLib' ) && ! empty( $_REQUEST['nonce'] ) && 'upload_attachment' === $action ) { // phpcs:ignore WordPress.Security.NonceVerification ewwwio_debug_message( 'doing maxgalleria upload' ); ewww_image_optimizer_image_sizes( false ); add_filter( 'ewww_image_optimizer_allowed_reopt', '__return_true' ); return; } // Check for Image Regenerate and Select Crop (better way). if ( defined( 'DOING_SIRSC' ) && DOING_SIRSC ) { ewwwio_debug_message( 'IRSC action/regen' ); ewww_image_optimizer_image_sizes( false ); add_filter( 'ewww_image_optimizer_allowed_reopt', '__return_true' ); return; } elseif ( 0 === strpos( $action, 'sirsc' ) ) { // Image Regenerate and Select Crop (old check). ewwwio_debug_message( 'IRSC action/regen (old)' ); ewww_image_optimizer_image_sizes( false ); add_filter( 'ewww_image_optimizer_allowed_reopt', '__return_true' ); return; } // Check for Phoenix Media Rename action. if ( class_exists( 'Phoenix_Media_Rename' ) && 'phoenix_media_rename' === $action ) { ewwwio_debug_message( 'Phoenix Media Rename, verifying' ); if ( check_ajax_referer( 'phoenix_media_rename', '_wpnonce', false ) ) { ewwwio_debug_message( 'PMR verified' ); remove_filter( 'wp_generate_attachment_metadata', 'ewww_image_optimizer_resize_from_meta_data', 15 ); ewww_image_optimizer_image_sizes( false ); add_filter( 'ewww_image_optimizer_allowed_reopt', '__return_true' ); return; } } } /** * Adds suggested privacy policy content for site admins. * * Note that this is just a suggestion, it should be customized for your site. */ function ewww_image_optimizer_privacy_policy_content() { if ( ! function_exists( 'wp_add_privacy_policy_content' ) || ! function_exists( 'wp_kses_post' ) ) { return; } $content = '
'; $content .= wp_kses_post( __( 'By default, the EWWW Image Optimizer does not store any personal data nor share it with anyone.', 'ewww-image-optimizer' ) ) . '
'; $content .= wp_kses_post( __( 'If you accept user-submitted images and use the API or Easy IO, those images may be transmitted to third-party servers in foreign countries. If Backup Originals is enabled, images are stored for 30 days. Otherwise, no images are stored on the API for longer than 30 minutes.', 'ewww-image-optimizer' ) ) . '
'; $content .= '' . wp_kses_post( __( 'Suggested API Text:' ) ) . ' ' . wp_kses_post( __( 'User-submitted images may be transmitted to image compression servers in the United States and stored there for up to 30 days.' ) ) . '
'; $content .= '' . wp_kses_post( __( 'Suggested Easy IO Text:' ) ) . ' ' . wp_kses_post( __( 'User-submitted images that are displayed on this site will be transmitted and stored on a global network of third-party servers (a CDN).' ) ) . '
'; wp_add_privacy_policy_content( 'EWWW Image Optimizer', $content ); } /** * Check the current screen, currently used to temporarily enable debugging on settings page. * * @param object $screen Information about the page/screen currently being loaded. */ function ewww_image_optimizer_current_screen( $screen ) { if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_debug' ) ) { return; } if ( false !== strpos( $screen->id, 'settings_page_ewww-image-optimizer' ) ) { return; } if ( false !== strpos( $screen->id, 'media_page_ewww-image-optimizer-bulk' ) ) { return; } EWWW\Base::$debug_data = ''; EWWW\Base::$temp_debug = false; } /** * Optimize a single image from an attachment, based on the size and ID. * * @param int $id The attachment ID number. * @param string $size The slug/name of the image size. */ function ewww_image_optimizer_single_size_optimize( $id, $size ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); session_write_close(); $meta = wp_get_attachment_metadata( $id ); global $wpdb; if ( strpos( $wpdb->charset, 'utf8' ) === false ) { ewww_image_optimizer_db_init(); global $ewwwdb; } else { $ewwwdb = $wpdb; } list( $file_path, $upload_path ) = ewww_image_optimizer_attachment_path( $meta, $id ); ewwwio_debug_message( "retrieved file path: $file_path" ); $type = ewww_image_optimizer_mimetype( $file_path, 'i' ); $supported_types = array( 'image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'image/svg+xml', ); if ( ! in_array( $type, $supported_types, true ) ) { ewwwio_debug_message( "mimetype not supported: $id" ); return; } if ( 'full' === $size ) { $ewww_image = new EWWW_Image( $id, 'media', $file_path ); $ewww_image->resize = 'full'; // Run the optimization and store the results. ewww_image_optimizer( $file_path, 4, false, false, true ); return; } // Resized version, continue. if ( isset( $meta['sizes'] ) && is_array( $meta['sizes'][ $size ] ) ) { $disabled_sizes = ewww_image_optimizer_get_option( 'ewww_image_optimizer_disable_resizes_opt', false, true ); ewwwio_debug_message( "processing size: $size" ); $base_dir = trailingslashit( dirname( $file_path ) ); $data = $meta['sizes'][ $size ]; if ( strpos( $size, 'webp' ) === 0 ) { return; } if ( ! empty( $disabled_sizes[ $size ] ) ) { return; } if ( ! empty( $disabled_sizes['pdf-full'] ) && 'full' === $size ) { return; } if ( empty( $data['file'] ) ) { return; } // If this is a unique size. $resize_path = $base_dir . wp_basename( $data['file'] ); if ( 'application/pdf' === $type && 'full' === $size ) { $size = 'pdf-full'; ewwwio_debug_message( 'processing full size pdf preview' ); } $ewww_image = new EWWW_Image( $id, 'media', $resize_path ); $ewww_image->resize = $size; // Run the optimization and store the results. ewww_image_optimizer( $resize_path ); // Optimize retina images, if they exist. if ( function_exists( 'wr2x_get_retina' ) ) { $retina_path = wr2x_get_retina( $resize_path ); } else { $retina_path = false; } if ( $retina_path && ewwwio_is_file( $retina_path ) ) { $ewww_image = new EWWW_Image( $id, 'media', $retina_path ); $ewww_image->resize = $size . '-retina'; ewww_image_optimizer( $retina_path ); } else { ewww_image_optimizer_hidpi_optimize( $resize_path ); } } // End if(). } /** * Checks to see if this is a REST API request, and whether the WP_Image_Editor hooks should be undone. * * @since 4.0.6 */ function ewww_image_optimizer_restapi_compat_check() { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( ! empty( $GLOBALS['wp']->query_vars['rest_route'] ) && false !== strpos( $GLOBALS['wp']->query_vars['rest_route'], '/regenerate-thumbnails' ) ) { ewwwio_debug_message( 'doing regenerate-thumbnails via REST' ); ewww_image_optimizer_image_sizes( false ); add_filter( 'ewww_image_optimizer_allowed_reopt', '__return_true' ); return; } if ( ! empty( $GLOBALS['wp']->query_vars['rest_route'] ) && strpos( $GLOBALS['wp']->query_vars['rest_route'], '/media/' ) && preg_match( '/media\/\d+\/edit$/', $GLOBALS['wp']->query_vars['rest_route'] ) ) { ewwwio_debug_message( 'image edited via REST' ); global $ewww_preempt_editor; $ewww_preempt_editor = true; } } /** * Generates css include for progressbars to match admin style. */ function ewww_image_optimizer_progressbar_style() { wp_add_inline_style( 'jquery-ui-progressbar', '.ui-widget-header { background-color: ' . ewww_image_optimizer_admin_background() . '; }' ); ewwwio_memory( __FUNCTION__ ); } /** * Grabs the color scheme information from the current admin theme and saves it for later. * * @global $ewwwio_admin_color The color we want to use for theming. * @global array $_wp_admin_css_colors An array of available admin color/theme objects. */ function ewww_image_optimizer_save_admin_colors() { global $ewwwio_admin_color; global $_wp_admin_css_colors; if ( function_exists( 'wp_add_inline_style' ) ) { $user_info = wp_get_current_user(); if ( is_array( $_wp_admin_css_colors ) && ! empty( $user_info->admin_color ) && isset( $_wp_admin_css_colors[ $user_info->admin_color ] ) && is_object( $_wp_admin_css_colors[ $user_info->admin_color ] ) && is_array( $_wp_admin_css_colors[ $user_info->admin_color ]->colors ) && ! empty( $_wp_admin_css_colors[ $user_info->admin_color ]->colors[2] ) && preg_match( '/^\#([0-9a-fA-F]){3,6}$/', $_wp_admin_css_colors[ $user_info->admin_color ]->colors[2] ) ) { $ewwwio_admin_color = $_wp_admin_css_colors[ $user_info->admin_color ]->colors[2]; } } if ( empty( $ewwwio_admin_color ) ) { $ewwwio_admin_color = '#0073aa'; } } /** * Determines the background color to use based on the selected admin theme. */ function ewww_image_optimizer_admin_background() { global $ewwwio_admin_color; if ( ! empty( $ewwwio_admin_color ) && preg_match( '/^\#([0-9a-fA-F]){3,6}$/', $ewwwio_admin_color ) ) { return $ewwwio_admin_color; } if ( function_exists( 'wp_add_inline_style' ) ) { $user_info = wp_get_current_user(); global $_wp_admin_css_colors; if ( is_array( $_wp_admin_css_colors ) && ! empty( $user_info->admin_color ) && isset( $_wp_admin_css_colors[ $user_info->admin_color ] ) && is_object( $_wp_admin_css_colors[ $user_info->admin_color ] ) && is_array( $_wp_admin_css_colors[ $user_info->admin_color ]->colors ) && ! empty( $_wp_admin_css_colors[ $user_info->admin_color ]->colors[2] ) && preg_match( '/^\#([0-9a-fA-F]){3,6}$/', $_wp_admin_css_colors[ $user_info->admin_color ]->colors[2] ) ) { $ewwwio_admin_color = $_wp_admin_css_colors[ $user_info->admin_color ]->colors[2]; return $ewwwio_admin_color; } switch ( $user_info->admin_color ) { case 'midnight': return '#e14d43'; case 'blue': return '#096484'; case 'light': return '#04a4cc'; case 'ectoplasm': return '#a3b745'; case 'coffee': return '#c7a589'; case 'ocean': return '#9ebaa0'; case 'sunrise': return '#dd823b'; default: return '#0073aa'; } } return '#0073aa'; } /** * If a multisite is over 1000 sites, tells WP this is a 'large network' when querying image stats. * * @param bool $large_network Normally only true with 10,000+ users or sites. * @param string $criteria The criteria for determining a large network, 'sites' or 'users'. * @param int $count The number of sites/users. * @return bool True if this is a 'large network'. */ function ewww_image_optimizer_large_network( $large_network, $criteria, $count ) { if ( 'sites' === $criteria && $count > 1000 ) { return true; } return false; } /** * Adds/upgrades table in db for storing status of all images that have been optimized. * * @global object $wpdb */ function ewww_image_optimizer_install_table() { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); global $wpdb; $wpdb->ewwwio_images = $wpdb->prefix . 'ewwwio_images'; $wpdb->ewwwio_queue = $wpdb->prefix . 'ewwwio_queue'; // Get the current wpdb charset and collation. $db_collation = $wpdb->get_charset_collate(); ewwwio_debug_message( "current collation: $db_collation" ); $primary_key_definition = 'PRIMARY KEY (id),'; // See if the path column exists, and what collation it uses to determine the column index size. if ( $wpdb->get_var( "SHOW TABLES LIKE '$wpdb->ewwwio_images'" ) === $wpdb->ewwwio_images ) { ewwwio_debug_message( 'upgrading table and checking collation for path, table exists' ); $mysql_version = 'unknown'; if ( method_exists( $wpdb, 'db_server_info' ) ) { $mysql_version = strtolower( $wpdb->db_server_info() ); } ewwwio_debug_message( $mysql_version ); if ( false !== strpos( $mysql_version, 'maria' ) && false !== strpos( $mysql_version, '10.4.' ) ) { $primary_key_definition = 'UNIQUE KEY id (id),'; } if ( false && false === strpos( $mysql_version, 'maria' ) || false === strpos( $mysql_version, '10.4.' ) ) { ewwwio_debug_message( 'checking primary/unique index' ); if ( ! $wpdb->get_results( "SHOW INDEX FROM $wpdb->ewwwio_images WHERE Key_name = 'PRIMARY'", ARRAY_A ) ) { ewwwio_debug_message( 'adding primary index' ); $wpdb->query( "ALTER TABLE $wpdb->ewwwio_images ADD PRIMARY KEY(id)" ); } if ( $wpdb->get_results( "SHOW INDEX FROM $wpdb->ewwwio_images WHERE Key_name = 'id'", ARRAY_A ) ) { ewwwio_debug_message( 'dropping unique index' ); $wpdb->query( "ALTER TABLE $wpdb->ewwwio_images DROP INDEX id" ); } } // Check if the old path_image_size index exists, and drop it. if ( $wpdb->get_results( "SHOW INDEX FROM $wpdb->ewwwio_images WHERE Key_name = 'path_image_size'", ARRAY_A ) ) { ewwwio_debug_message( 'getting rid of path_image_size index' ); $wpdb->query( "ALTER TABLE $wpdb->ewwwio_images DROP INDEX path_image_size" ); } // Make sure there are valid dates in updated column. $wpdb->query( "UPDATE $wpdb->ewwwio_images SET updated = '1971-01-01 00:00:00' WHERE updated < '1001-01-01 00:00:01'" ); // Get the current table layout. $suppress = $wpdb->suppress_errors(); $tablefields = $wpdb->get_results( "DESCRIBE {$wpdb->ewwwio_images};" ); $wpdb->suppress_errors( $suppress ); $timestamp_upgrade_needed = false; if ( ewww_image_optimizer_iterable( $tablefields ) ) { foreach ( $tablefields as $tablefield ) { if ( 'updated' === $tablefield->Field && // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase false === stripos( $tablefield->Default, 'current_timestamp' ) && // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase false === stripos( $tablefield->Default, 'now' ) // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase ) { $timestamp_upgrade_needed = true; ewwwio_debug_message( 'updated timestamp upgrade needed' ); } } } if ( ( false !== strpos( $mysql_version, '5.6.' ) || false !== strpos( $mysql_version, '5.7.' ) || false !== strpos( $mysql_version, '10.1.' ) ) && $timestamp_upgrade_needed ) { $count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->ewwwio_images" ); if ( is_multisite() || $count < 10000 ) { // Do the upgrade in real-time for multi-site and sites with less than 10k image records. $wpdb->query( "ALTER TABLE $wpdb->ewwwio_images MODIFY updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" ); } else { // Do it later via user interaction. set_transient( 'ewww_image_optimizer_620_upgrade_needed', true ); } } elseif ( $timestamp_upgrade_needed ) { $wpdb->query( "ALTER TABLE $wpdb->ewwwio_images ALTER updated SET DEFAULT (CURRENT_TIMESTAMP)" ); } // Check the current collation and adjust it if necessary. $column_collate = $wpdb->get_col_charset( $wpdb->ewwwio_images, 'path' ); if ( ! empty( $column_collate ) && ! is_wp_error( $column_collate ) && 'utf8mb4' !== $column_collate ) { $path_index_size = 255; ewwwio_debug_message( "current column collation: $column_collate" ); if ( strpos( $column_collate, 'utf8' ) === false ) { ewwwio_debug_message( 'converting path column to utf8' ); $wpdb->query( "ALTER TABLE $wpdb->ewwwio_images CHANGE path path BLOB" ); if ( $wpdb->has_cap( 'utf8mb4_520' ) && strpos( $db_collation, 'utf8mb4' ) ) { ewwwio_debug_message( 'using mb4 version 5.20' ); $wpdb->query( "ALTER TABLE $wpdb->ewwwio_images DROP INDEX path_image_size" ); $wpdb->query( "ALTER TABLE $wpdb->ewwwio_images CONVERT TO CHARACTER SET utf8mb4, CHANGE path path TEXT" ); unset( $path_index_size ); } elseif ( $wpdb->has_cap( 'utf8mb4' ) && strpos( $db_collation, 'utf8mb4' ) ) { ewwwio_debug_message( 'using mb4 version 4' ); $wpdb->query( "ALTER TABLE $wpdb->ewwwio_images DROP INDEX path_image_size" ); $wpdb->query( "ALTER TABLE $wpdb->ewwwio_images CONVERT TO CHARACTER SET utf8mb4, CHANGE path path TEXT" ); unset( $path_index_size ); } else { ewwwio_debug_message( 'using plain old utf8' ); $wpdb->query( "ALTER TABLE $wpdb->ewwwio_images CONVERT TO CHARACTER SET utf8, CHANGE path path TEXT" ); } } elseif ( strpos( $column_collate, 'utf8mb4' ) === false && strpos( $db_collation, 'utf8mb4' ) ) { if ( $wpdb->has_cap( 'utf8mb4_520' ) ) { ewwwio_debug_message( 'using mb4 version 5.20' ); $wpdb->query( "ALTER TABLE $wpdb->ewwwio_images DROP INDEX path_image_size" ); $wpdb->query( "ALTER TABLE $wpdb->ewwwio_images CONVERT TO CHARACTER SET utf8mb4, CHANGE path path TEXT" ); unset( $path_index_size ); } elseif ( $wpdb->has_cap( 'utf8mb4' ) ) { ewwwio_debug_message( 'using mb4 version 4' ); $wpdb->query( "ALTER TABLE $wpdb->ewwwio_images DROP INDEX path_image_size" ); $wpdb->query( "ALTER TABLE $wpdb->ewwwio_images CONVERT TO CHARACTER SET utf8mb4, CHANGE path path TEXT" ); unset( $path_index_size ); } } } } // End if(). // If the path column doesn't yet exist, and the default collation is utf8mb4, then we need to lower the column index size. if ( empty( $path_index_size ) && strpos( $db_collation, 'utf8mb4' ) ) { $path_index_size = 191; } else { $path_index_size = 255; } ewwwio_debug_message( "path index size: $path_index_size" ); /* * Create a table with 15 columns: * id: unique for each record/image, * attachment_id: the unique id within the media library, nextgen, or flag * gallery: 'media', 'nextgen', 'nextcell', or 'flag', * resize: size of the image, * path: filename of the image, potentially replaced with ABSPATH or WP_CONTENT_DIR, * converted: filename of the image before conversion, * results: human-readable savings message, * image_size: optimized size of the image, * orig_size: original size of the image, * backup: hash where the image is stored on the API servers, * level: the optimization level used on the image, * pending: 1 if the image is queued for optimization, * updates: how many times an image has been optimized, * updated: when the image was last optimized, * trace: tracelog from the last optimization if debugging was enabled. */ $sql = "CREATE TABLE $wpdb->ewwwio_images ( id int unsigned NOT NULL AUTO_INCREMENT, attachment_id bigint unsigned, gallery varchar(10), resize varchar(75), path text NOT NULL, converted text NOT NULL, results varchar(75) NOT NULL, image_size int unsigned, orig_size int unsigned, backup varchar(100), level int unsigned, pending tinyint NOT NULL DEFAULT 0, updates int unsigned, updated timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, trace blob, $primary_key_definition KEY path (path($path_index_size)), KEY attachment_info (gallery(3),attachment_id) ) $db_collation;"; // Include the upgrade library to install/upgrade a table. require_once ABSPATH . 'wp-admin/includes/upgrade.php'; $updates = dbDelta( $sql ); ewwwio_debug_message( 'images db upgrade results: ' . implode( '' . esc_html__( 'Pngout was successfully installed.', 'ewww-image-optimizer' ) . "
\n" . "' . sprintf( /* translators: 1: An error message 2: The folder where pngout should be installed */ esc_html__( 'Pngout was not installed: %1$s. Make sure this folder is writable: %2$s', 'ewww-image-optimizer' ), ( ! empty( $_REQUEST['ewww_error'] ) ? esc_html( sanitize_text_field( wp_unslash( $_REQUEST['ewww_error'] ) ) ) : esc_html( 'unknown error', 'ewww-image-optimizer' ) ), // phpcs:ignore WordPress.Security.NonceVerification esc_html( EWWW_IMAGE_OPTIMIZER_TOOL_PATH ) ) . "
\n" . "' . esc_html__( 'Svgcleaner was successfully installed.', 'ewww-image-optimizer' ) . "
\n" . "' . sprintf( /* translators: 1: An error message 2: The folder where svgcleaner should be installed */ esc_html__( 'Svgcleaner was not installed: %1$s. Make sure this folder is writable: %2$s', 'ewww-image-optimizer' ), ( ! empty( $_REQUEST['ewww_error'] ) ? esc_html( sanitize_text_field( wp_unslash( $_REQUEST['ewww_error'] ) ) ) : esc_html( 'unknown error', 'ewww-image-optimizer' ) ), // phpcs:ignore WordPress.Security.NonceVerification esc_html( EWWW_IMAGE_OPTIMIZER_TOOL_PATH ) ) . "
\n" . "' .
sprintf(
/* translators: %s: A link to the documentation */
esc_html__( 'Could not activate Easy IO, please try again in a few minutes. If this error continues, please see %s for troubleshooting steps.', 'ewww-image-optimizer' ),
'https://docs.ewww.io/article/66-exactdn-not-verified'
) .
'' . esc_html( $exactdn_activate_error ) . '
' .
'
' . esc_html( $stored_local_domain ) . '',
'' . esc_html( $exactdn->upload_domain ) . ''
);
?>
' . esc_html__( 'settings page', 'ewww-image-optimizer' ) . ''
);
?>
" . esc_html__( 'ShortPixel image optimization has been disabled to prevent conflicts with Easy IO (EWWW Image Optimizer).', 'ewww-image-optimizer' ) . '
'; } /** * Display a notice that PHP version 7.2 will be required in a future version. */ function ewww_image_optimizer_php72_warning() { if ( ! current_user_can( apply_filters( 'ewww_image_optimizer_admin_permissions', '' ) ) ) { return; } echo ''; } /** * Display a notice that debugging mode is enabled. */ function ewww_image_optimizer_debug_enabled_notice() { if ( ! current_user_can( apply_filters( 'ewww_image_optimizer_admin_permissions', '' ) ) ) { return; } ?>" . esc_html__( 'Settings saved', 'ewww-image-optimizer' ) . '.
'; } /** * Warn the user that scheduled optimization will no longer work without background/async mode. */ function ewww_image_optimizer_notice_schedule_noasync() { if ( ! current_user_can( apply_filters( 'ewww_image_optimizer_admin_permissions', '' ) ) ) { return; } global $ewwwio_upgrading; if ( $ewwwio_upgrading ) { return; } echo "" . esc_html__( 'Scheduled Optimization will not work without background/async ability. See the EWWW Image Optimizer Settings for further instructions.', 'ewww-image-optimizer' ) . '
" . esc_html__( 'New thumbnails will be optimized by the EWWW Image Optimizer as they are generated. You may wish to disable the plugin and run a bulk optimize later to speed up the process.', 'ewww-image-optimizer' ) . ''; echo ' ' . esc_html__( 'Learn more.', 'ewww-image-optimizer' ) . '
" . esc_html__( 'EWWW Image Optimizer has detected a WooCommerce thumbnail regeneration. To optimize new thumbnails, you may run the Bulk Optimizer from the Media menu. This notice may be dismissed after the regeneration is complete.', 'ewww-image-optimizer' ) . '
" . esc_html__( 'EWWW Image Optimizer has detected a WP/LR Sync process. To optimize new thumbnails, you may run the Bulk Optimizer from the Media menu. This notice may be dismissed after the Sync process is complete.', 'ewww-image-optimizer' ) . '
" .
esc_html__( 'EWWW Image Optimizer needs to upgrade the image log table.', 'ewww-image-optimizer' ) . '
' .
'' .
esc_html__( 'Upgrade', 'ewww-image-optimizer' ) . '' .
'
" .
esc_html__( "Hi, you've been using the EWWW Image Optimizer for a while, and we hope it has been a big help for you.", 'ewww-image-optimizer' ) . '
' .
esc_html__( 'If you could take a few moments to rate it on WordPress.org, we would really appreciate your help making the plugin better. Thanks!', 'ewww-image-optimizer' ) .
'
' . esc_html__( 'Post Review', 'ewww-image-optimizer' ) . '' .
'
' .
esc_html__( 'Enable the EWWW I.O. support beacon, which gives you access to documentation and our support team right from your WordPress dashboard. To assist you more efficiently, we collect the current url, IP address, browser/device information, and debugging information.', 'ewww-image-optimizer' ) .
'
' . esc_html__( 'Allow', 'ewww-image-optimizer' ) . '' .
' ' . esc_html__( 'Do not allow', 'ewww-image-optimizer' ) . '' .
'
" . sprintf( /* translators: %s: A link to the EWWW IO Tools page */ esc_html__( 'The EWWW Image Optimizer has detected excessive re-optimization of multiple images. Please use the %s page to Show Re-Optimized Images.', 'ewww-image-optimizer' ), "" . esc_html__( 'Tools', 'ewww-image-optimizer' ) . '' ) . " " . esc_html__( 'Reset Counters' ) . '
' . esc_html__( 'Optimizing', 'ewww-image-optimizer' ) . "
", 'restoring' => '' . esc_html__( 'Restoring', 'ewww-image-optimizer' ) . "
", ) ); } } /** * Gets the link to the main EWWW IO settings. * * @return string The link to the main settings (network vs. single-site). */ function ewww_image_optimizer_get_settings_link() { if ( ! function_exists( 'is_plugin_active_for_network' ) && is_multisite() ) { // Need to include the plugin library for the is_plugin_active function. require_once ABSPATH . 'wp-admin/includes/plugin.php'; } // Load the html for the settings link. if ( is_multisite() && is_plugin_active_for_network( EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE_REL ) && ! get_site_option( 'ewww_image_optimizer_allow_multisite_override' ) ) { return network_admin_url( 'settings.php?page=ewww-image-optimizer-options' ); } else { return admin_url( 'options-general.php?page=ewww-image-optimizer-options' ); } } /** * Adds a link on the Plugins page for the EWWW IO settings. * * @param array $links A list of links to display next to the plugin listing. * @return array The new list of links to be displayed. */ function ewww_image_optimizer_settings_link( $links ) { if ( ! is_array( $links ) ) { $links = array(); } $settings_link = '' . esc_html__( 'Settings', 'ewww-image-optimizer' ) . ''; // Load the settings link into the plugin links array. array_unshift( $links, $settings_link ); // Send back the plugin links array. return $links; } /** * Check for GD support of both PNG and JPG. * * @param bool $cache Whether to use a cached result. * @return string The version of GD if full support is detected. */ function ewww_image_optimizer_gd_support( $cache = true ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); return ewwwio()->gd_support(); } /** * Check for GD support of WebP format. * * @return bool True if proper WebP support is detected. */ function ewww_image_optimizer_gd_supports_webp() { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); return ewwwio()->gd_supports_webp(); } /** * Use GD to convert an image to WebP. * * @param string $file The original source image path. * @param string $type The mime-type of the original image. * @param string $webpfile The location to store the new WebP image. */ function ewww_image_optimizer_gd_create_webp( $file, $type, $webpfile ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); $quality = (int) apply_filters( 'webp_quality', 75, 'image/webp' ); if ( $quality < 50 || $quality > 100 ) { $quality = 75; } switch ( $type ) { case 'image/jpeg': $image = imagecreatefromjpeg( $file ); if ( false === $image ) { return; } break; case 'image/png': $image = imagecreatefrompng( $file ); if ( false === $image ) { return; } if ( ! imageistruecolor( $image ) ) { ewwwio_debug_message( 'converting to true color' ); imagepalettetotruecolor( $image ); } if ( ewww_image_optimizer_png_alpha( $file ) ) { ewwwio_debug_message( 'saving alpha and disabling alpha blending' ); imagealphablending( $image, false ); imagesavealpha( $image, true ); } if ( ! defined( 'EWWW_IMAGE_OPTIMIZER_LOSSY_PNG2WEBP' ) || ! EWWW_IMAGE_OPTIMIZER_LOSSY_PNG2WEBP ) { $quality = 100; } break; default: return; } ewwwio_debug_message( "creating $webpfile with quality $quality" ); $result = imagewebp( $image, $webpfile, $quality ); // Make sure to cleanup--if $webpfile is borked, that will be handled elsewhere. imagedestroy( $image ); } /** * Check for IMagick support of both PNG and JPG. * * @return bool True if full Imagick support is detected. */ function ewww_image_optimizer_imagick_support() { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); return ewwwio()->imagick_support(); } /** * Check for IMagick support of WebP. * * @return bool True if WebP support is detected. */ function ewww_image_optimizer_imagick_supports_webp() { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); return ewwwio()->imagick_supports_webp(); } /** * Use IMagick to convert an image to WebP. * * @param string $file The original source image path. * @param string $type The mime-type of the original image. * @param string $webpfile The location to store the new WebP image. */ function ewww_image_optimizer_imagick_create_webp( $file, $type, $webpfile ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); $sharp_yuv = defined( 'EIO_WEBP_SHARP_YUV' ) && EIO_WEBP_SHARP_YUV ? true : false; if ( empty( $sharp_yuv ) && ewww_image_optimizer_get_option( 'ewww_image_optimizer_sharpen' ) ) { $sharp_yuv = true; } $quality = (int) apply_filters( 'webp_quality', 75, 'image/webp' ); if ( $quality < 50 || $quality > 100 ) { $quality = 75; } $profiles = array(); switch ( $type ) { case 'image/jpeg': $image = new Imagick( $file ); if ( false === $image ) { return; } if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_metadata_remove' ) ) { // Getting possible color profiles. $profiles = $image->getImageProfiles( 'icc', true ); } $color = $image->getImageColorspace(); ewwwio_debug_message( "color space is $color" ); if ( Imagick::COLORSPACE_CMYK === $color ) { ewwwio_debug_message( 'found CMYK image' ); if ( ewwwio_is_file( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'vendor/icc/sRGB2014.icc' ) ) { ewwwio_debug_message( 'adding icc profile' ); $icc_profile = file_get_contents( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'vendor/icc/sRGB2014.icc' ); $image->profileImage( 'icc', $icc_profile ); } ewwwio_debug_message( 'attempting SRGB transform' ); $image->transformImageColorspace( Imagick::COLORSPACE_SRGB ); ewwwio_debug_message( 'removing icc profile' ); $image->setImageProfile( '*', null ); $profiles = array(); } $image->setImageFormat( 'WEBP' ); if ( $sharp_yuv ) { ewwwio_debug_message( 'enabling sharp_yuv' ); $image->setOption( 'webp:use-sharp-yuv', 'true' ); } ewwwio_debug_message( "setting quality to $quality" ); $image->setImageCompressionQuality( $quality ); break; case 'image/png': $image = new Imagick( $file ); if ( false === $image ) { return; } $image->setImageFormat( 'WEBP' ); if ( defined( 'EWWW_IMAGE_OPTIMIZER_LOSSY_PNG2WEBP' ) && EWWW_IMAGE_OPTIMIZER_LOSSY_PNG2WEBP ) { ewwwio_debug_message( 'doing lossy conversion' ); if ( $sharp_yuv ) { ewwwio_debug_message( 'enabling sharp_yuv' ); $image->setOption( 'webp:use-sharp-yuv', 'true' ); } ewwwio_debug_message( "setting quality to $quality" ); $image->setImageCompressionQuality( $quality ); } else { ewwwio_debug_message( 'sticking to lossless' ); $image->setOption( 'webp:lossless', true ); $image->setOption( 'webp:alpha-quality', 100 ); } break; default: return; } if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_metadata_remove' ) ) { ewwwio_debug_message( 'removing meta' ); $image->stripImage(); if ( ! empty( $profiles ) ) { ewwwio_debug_message( 'adding color profile to WebP' ); $image->profileImage( 'icc', $profiles['icc'] ); } } ewwwio_debug_message( 'getting blob' ); $image_blob = $image->getImageBlob(); ewwwio_debug_message( 'writing file' ); file_put_contents( $webpfile, $image_blob ); } /** * Check for GMagick support of both PNG and JPG. * * @return bool True if full Gmagick support is detected. */ function ewww_image_optimizer_gmagick_support() { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); return ewwwio()->gmagick_support(); } /** * Filter the filename past any folders the user chose to ignore. * * @param bool $bypass True to skip optimization, defaults to false. * @param string $filename The file about to be optimized. * @return bool True if the file matches any folders to ignore. */ function ewww_image_optimizer_ignore_file( $bypass, $filename ) { $ignore_folders = ewww_image_optimizer_get_option( 'ewww_image_optimizer_exclude_paths' ); if ( ! ewww_image_optimizer_iterable( $ignore_folders ) ) { return $bypass; } foreach ( $ignore_folders as $ignore_folder ) { if ( strpos( $filename, $ignore_folder ) !== false ) { return true; } } return $bypass; } /** * Add a file to the exclusions list. * * @param string $file_path The path of the file to ignore. */ function ewww_image_optimizer_add_file_exclusion( $file_path ) { if ( ! is_string( $file_path ) ) { return; } // Add it to the files to ignore. $ignore_folders = ewww_image_optimizer_get_option( 'ewww_image_optimizer_exclude_paths' ); if ( ! is_array( $ignore_folders ) ) { $ignore_folders = array(); } $file_path = str_replace( ABSPATH, '', $file_path ); $file_path = str_replace( WP_CONTENT_DIR, '', $file_path ); $ignore_folders[] = $file_path; ewww_image_optimizer_set_option( 'ewww_image_optimizer_exclude_paths', $ignore_folders ); } /** * Sanitize the list of disabled resizes. * * @param array $disabled_resizes A list of sizes, like 'medium_large', 'thumb', etc. * @return array|string The sanitized list of sizes, or an empty string. */ function ewww_image_optimizer_disable_resizes_sanitize( $disabled_resizes ) { if ( is_array( $disabled_resizes ) ) { return $disabled_resizes; } else { return ''; } } /** * Sanitize the list of folders to optimize. * * @param string $input A list of filesystem paths, from a textarea. * @return array The list of paths, validated, and converted to an array. */ function ewww_image_optimizer_aux_paths_sanitize( $input ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( empty( $input ) ) { return ''; } $path_array = array(); if ( is_array( $input ) ) { $paths = $input; } elseif ( is_string( $input ) ) { $paths = explode( "\n", $input ); } $abspath = false; $permissions = apply_filters( 'ewww_image_optimizer_superadmin_permissions', '' ); if ( is_multisite() && current_user_can( $permissions ) ) { $abspath = true; } elseif ( ! is_multisite() ) { $abspath = true; } $blog_one = false; if ( 1 === get_current_blog_id() ) { $blog_one = true; } if ( ewww_image_optimizer_iterable( $paths ) ) { $i = 0; foreach ( $paths as $path ) { ++$i; $path = sanitize_text_field( $path ); ewwwio_debug_message( "validating auxiliary path: $path" ); // Retrieve the location of the WordPress upload folder. $upload_dir = wp_get_upload_dir(); // Retrieve the path of the upload folder from the array. $upload_path = trailingslashit( $upload_dir['basedir'] ); if ( ! $abspath && $blog_one && false !== strpos( $path, $upload_path . 'sites' ) ) { add_settings_error( 'ewww_image_optimizer_aux_paths', "ewwwio-aux-paths-$i", sprintf( /* translators: %s: A file system path */ esc_html__( 'Could not save Folder to Optimize: %s. Access denied.', 'ewww-image-optimizer' ), esc_html( $path ) ) ); continue; } if ( ( ( $abspath && strpos( $path, ABSPATH ) === 0 ) || strpos( $path, $upload_path ) === 0 ) && ewwwio_is_dir( $path ) ) { $path_array[] = $path; continue; } // If they put in a relative path. if ( $abspath && ewwwio_is_dir( ABSPATH . ltrim( $path, '/' ) ) ) { $path_array[] = ABSPATH . ltrim( $path, '/' ); continue; } // Or a path relative to the upload dir? if ( ewwwio_is_dir( $upload_path . ltrim( $path, '/' ) ) ) { $path_array[] = $upload_path . ltrim( $path, '/' ); continue; } // What if they put in a url? $pathabsurl = ABSPATH . ltrim( str_replace( get_site_url(), '', $path ), '/' ); if ( $abspath && ewwwio_is_dir( $pathabsurl ) ) { $path_array[] = $pathabsurl; continue; } // Or a url in the uploads folder? $pathupurl = $upload_path . ltrim( str_replace( $upload_dir['baseurl'], '', $path ), '/' ); if ( ewwwio_is_dir( $pathupurl ) ) { $path_array[] = $pathupurl; continue; } if ( ! empty( $path ) ) { add_settings_error( 'ewww_image_optimizer_aux_paths', "ewwwio-aux-paths-$i", sprintf( /* translators: %s: A file system path */ esc_html__( 'Could not save Folder to Optimize: %s. Please ensure that it is a valid location on the server.', 'ewww-image-optimizer' ), esc_html( $path ) ) ); } } // End foreach(). } // End if(). ewwwio_memory( __FUNCTION__ ); return $path_array; } /** * Sanitize the url patterns used for WebP rewriting. * * @param string $paths A list of urls/patterns, from a textarea. * @return array The sanitize list of url patterns for WebP matching. */ function ewww_image_optimizer_webp_paths_sanitize( $paths ) { if ( empty( $paths ) ) { return ''; } $paths_saved = array(); if ( is_array( $paths ) ) { $paths_entered = $paths; } elseif ( is_string( $paths ) ) { $paths_entered = explode( "\n", $paths ); } if ( ewww_image_optimizer_iterable( $paths_entered ) ) { $i = 0; foreach ( $paths_entered as $path ) { ++$i; $original_path = esc_html( trim( $path, '*' ) ); $path = esc_url( $path, null, 'db' ); if ( ! empty( $path ) ) { if ( ! substr_count( $path, '.' ) ) { add_settings_error( 'ewww_image_optimizer_webp_paths', "ewwwio-webp-paths-$i", sprintf( /* translators: %s: A url or domain name */ esc_html__( 'Could not save WebP URL: %s.', 'ewww-image-optimizer' ), esc_html( $original_path ) ) . ' ' . esc_html__( 'Please enter a valid URL including the domain name.', 'ewww-image-optimizer' ) ); continue; } $paths_saved[] = trailingslashit( str_replace( 'http://', '', $path ) ); } } } return $paths_saved; } /** * Retrieves/sanitizes jpg background fill setting or returns null for png2jpg conversions. * * @param string $background The hexadecimal value entered by the user. * @return string The background color sanitized. */ function ewww_image_optimizer_jpg_background( $background = null ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( is_null( $background ) ) { // Retrieve the user-supplied value for jpg background color. $background = ewww_image_optimizer_get_option( 'ewww_image_optimizer_jpg_background' ); } // Verify that the supplied value is in hex notation. if ( is_string( $background ) && preg_match( '/^\#*([0-9a-fA-F]){6}$/', $background ) ) { // We remove a leading # symbol, since we take care of it later. $background = ltrim( $background, '#' ); // Send back the verified, cleaned-up background color. ewwwio_debug_message( "background: $background" ); ewwwio_memory( __FUNCTION__ ); return $background; } else { if ( ! empty( $background ) ) { add_settings_error( 'ewww_image_optimizer_jpg_background', 'ewwwio-jpg-background', esc_html__( 'Could not save the JPG background color, please enter a six-character, hexadecimal value.', 'ewww-image-optimizer' ) ); } // Send back a blank value. ewwwio_memory( __FUNCTION__ ); return ''; } } /** * Retrieves/sanitizes the jpg quality setting for png2jpg conversion or returns null. * * @param int $quality The JPG quality level as set by the user. * @return int The sanitized JPG quality level. */ function ewww_image_optimizer_jpg_quality( $quality = null ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( is_null( $quality ) ) { // Retrieve the user-supplied value for jpg quality. $quality = ewww_image_optimizer_get_option( 'ewww_image_optimizer_jpg_quality' ); } // Verify that the quality level is an integer, 1-100. if ( is_numeric( $quality ) && preg_match( '/^(100|[1-9][0-9]?)$/', $quality ) ) { ewwwio_debug_message( "quality: $quality" ); // Send back the valid quality level. ewwwio_memory( __FUNCTION__ ); return $quality; } else { if ( ! empty( $quality ) ) { add_settings_error( 'ewww_image_optimizer_jpg_quality', 'ewwwio-jpg-quality', esc_html__( 'Could not save the JPG quality, please enter an integer between 1 and 100.', 'ewww-image-optimizer' ) ); } // Send back nothing. return ''; } } /** * Overrides the default JPG quality for WordPress image editing operations. * * @param int $quality The default JPG quality level. * @return int The default quality, or the user configured level. */ function ewww_image_optimizer_set_jpg_quality( $quality ) { $new_quality = ewww_image_optimizer_jpg_quality(); if ( ! empty( $new_quality ) ) { return min( 92, $new_quality ); } return min( 92, $quality ); } /** * Retrieves/sanitizes the WebP quality setting or returns null. * * @param int $quality The WebP quality level as set by the user. * @return int The sanitized WebP quality level. */ function ewww_image_optimizer_webp_quality( $quality = null ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( is_null( $quality ) ) { // Retrieve the user-supplied value for WebP quality. $quality = ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_quality' ); } // Verify that the quality level is an integer, 1-100. if ( is_numeric( $quality ) && preg_match( '/^(100|[1-9][0-9]?)$/', $quality ) ) { ewwwio_debug_message( "webp quality: $quality" ); // Send back the valid quality level. return $quality; } else { if ( ! empty( $quality ) ) { add_settings_error( 'ewww_image_optimizer_webp_quality', 'ewwwio-webp-quality', esc_html__( 'Could not save the WebP quality, please enter an integer between 50 and 100.', 'ewww-image-optimizer' ) ); } // Send back nothing. return ''; } } /** * Overrides the default WebP quality (if a user-defined value is set). * * @param int $quality The default WebP quality level. * @return int The default quality, or the user configured level. */ function ewww_image_optimizer_set_webp_quality( $quality ) { $new_quality = ewww_image_optimizer_webp_quality(); if ( ! empty( $new_quality ) ) { return min( 92, $new_quality ); } return min( 92, $quality ); } /** * Retrieves/sanitizes the AVIF quality setting or returns null. * * @param int $quality The AVIF quality level as set by the user. * @return int The sanitized AVIF quality level. */ function ewww_image_optimizer_avif_quality( $quality = null ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( is_null( $quality ) ) { // Retrieve the user-supplied value for AVIF quality. $quality = ewww_image_optimizer_get_option( 'ewww_image_optimizer_avif_quality' ); } // Verify that the quality level is an integer, 1-100. if ( is_numeric( $quality ) && preg_match( '/^(100|[1-9][0-9]?)$/', $quality ) ) { ewwwio_debug_message( "avif quality: $quality" ); // Send back the valid quality level. return $quality; } else { if ( ! empty( $quality ) ) { add_settings_error( 'ewww_image_optimizer_avif_quality', 'ewwwio-avif-quality', esc_html__( 'Could not save the AVIF quality, please enter an integer between 50 and 100.', 'ewww-image-optimizer' ) ); } // Send back nothing. return ''; } } /** * Overrides the default AVIF quality (if a user-defined value is set). * * @param int $quality The default AVIF quality level. * @return int The default quality, or the user configured level. */ function ewww_image_optimizer_set_avif_quality( $quality ) { $new_quality = ewww_image_optimizer_avif_quality(); if ( ! empty( $new_quality ) ) { return min( 92, $new_quality ); } return min( 92, $quality ); } /** * Check default WP threshold and adjust to comply with normal EWWW IO behavior. * * @param int $size The default WP scaling size, or whatever has been filtered by other plugins. * @param array $imagesize { * Indexed array of the image width and height in pixels. * * @type int $0 The image width. * @type int $1 The image height. * } * @param string $file Full path to the uploaded image file. * @return int The proper size to use for scaling originals. */ function ewww_image_optimizer_adjust_big_image_threshold( $size, $imagesize = array(), $file = '' ) { if ( false !== strpos( $file, 'noresize' ) ) { return false; } $max_size = max( ewww_image_optimizer_get_option( 'ewww_image_optimizer_maxmediawidth' ), ewww_image_optimizer_get_option( 'ewww_image_optimizer_maxmediaheight' ), (int) $size ); return $max_size; } /** * Setup the global filesystem class variable. */ function ewwwio_get_filesystem() { require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php'; require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php'; global $eio_filesystem; if ( ! defined( 'FS_CHMOD_DIR' ) ) { define( 'FS_CHMOD_DIR', ( fileperms( ABSPATH ) & 0777 | 0755 ) ); } if ( ! defined( 'FS_CHMOD_FILE' ) ) { define( 'FS_CHMOD_FILE', ( fileperms( ABSPATH . 'index.php' ) & 0777 | 0644 ) ); } if ( ! isset( $eio_filesystem ) || ! is_object( $eio_filesystem ) ) { $eio_filesystem = new WP_Filesystem_Direct( '' ); } } /** * Check filesize, and prevent errors by ensuring file exists, and that the cache has been cleared. * * @param string $file The name of the file. * @return int The size of the file or zero. */ function ewww_image_optimizer_filesize( $file ) { $file = realpath( $file ); if ( ewwwio_is_file( $file ) ) { global $eio_filesystem; ewwwio_get_filesystem(); // Flush the cache for filesize. clearstatcache(); // Find out the size of the new PNG file. return $eio_filesystem->size( $file ); } else { return 0; } } /** * Check if open_basedir restriction is in effect, and that the path is allowed and exists. * * Note that when the EWWWIO_OPEN_BASEDIR constant is defined, is_file() will be skipped. * * @param string $file The path of the file to check. * @return bool False if open_basedir setting cannot be retrieved, or the file is "out of bounds", true if the file exists. */ function ewwwio_system_binary_exists( $file ) { if ( ! ewww_image_optimizer_function_exists( 'ini_get' ) && ! defined( 'EWWWIO_OPEN_BASEDIR' ) ) { return false; } if ( defined( 'EWWWIO_OPEN_BASEDIR' ) ) { $basedirs = EWWWIO_OPEN_BASEDIR; } else { $basedirs = ini_get( 'open_basedir' ); } if ( empty( $basedirs ) ) { return defined( 'EWWWIO_OPEN_BASEDIR' ) ? true : is_file( $file ); } $basedirs = explode( PATH_SEPARATOR, $basedirs ); foreach ( $basedirs as $basedir ) { $basedir = trim( $basedir ); if ( 0 === strpos( $file, $basedir ) ) { return defined( 'EWWWIO_OPEN_BASEDIR' ) ? true : is_file( $file ); } } return false; } /** * Check if a file/directory is readable. * * @param string $file The path to check. * @return bool True if it is, false if it ain't. */ function ewwwio_is_readable( $file ) { global $eio_filesystem; ewwwio_get_filesystem(); return $eio_filesystem->is_readable( $file ); } /** * Check if directory exists, and that it is local rather than using a protocol like http:// or phar:// * * @param string $dir The path of the directoy to check. * @return bool True if the directory exists and is local, false otherwise. */ function ewwwio_is_dir( $dir ) { if ( false !== strpos( $dir, '://' ) ) { return false; } if ( false !== strpos( $dir, 'phar://' ) ) { return false; } global $eio_filesystem; ewwwio_get_filesystem(); $dir = realpath( $dir ); $wp_dir = realpath( ABSPATH ); $upload_dir = wp_get_upload_dir(); $upload_dir = realpath( $upload_dir['basedir'] ); $content_dir = realpath( WP_CONTENT_DIR ); if ( empty( $content_dir ) ) { $content_dir = $wp_dir; } if ( empty( $upload_dir ) ) { $upload_dir = $content_dir; } if ( defined( 'EWWW_IMAGE_OPTIMIZER_TOOL_PATH' ) ) { $tool_dir = realpath( EWWW_IMAGE_OPTIMIZER_TOOL_PATH ); $tool_dir = dirname( $tool_dir ); } if ( empty( $tool_dir ) ) { $tool_dir = $content_dir; } if ( defined( 'EWWWIO_CONTENT_DIR' ) ) { $eio_content_dir = realpath( EWWWIO_CONTENT_DIR ); } if ( empty( $eio_content_dir ) ) { $eio_content_dir = $content_dir; } $plugin_dir = realpath( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH ); if ( false === strpos( $dir, $upload_dir ) && false === strpos( $dir, $content_dir ) && false === strpos( $dir, $wp_dir ) && false === strpos( $dir, $plugin_dir ) && false === strpos( $file, $tool_dir ) && false === strpos( $file, $eio_content_dir ) ) { return false; } return $eio_filesystem->is_dir( $dir ); } /** * Check if file exists, and that it is local rather than using a protocol like http:// or phar:// * * @param string $file The path of the file to check. * @return bool True if the file exists and is local, false otherwise. */ function ewwwio_is_file( $file ) { if ( false !== strpos( $file, '://' ) ) { return false; } if ( false !== strpos( $file, 'phar://' ) ) { return false; } global $eio_filesystem; ewwwio_get_filesystem(); $file = realpath( $file ); $wp_dir = realpath( ABSPATH ); $upload_dir = wp_get_upload_dir(); $upload_dir = realpath( $upload_dir['basedir'] ); $content_dir = realpath( WP_CONTENT_DIR ); if ( empty( $content_dir ) ) { $content_dir = $wp_dir; } if ( empty( $upload_dir ) ) { $upload_dir = $content_dir; } $plugin_dir = realpath( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH ); if ( defined( 'EWWW_IMAGE_OPTIMIZER_TOOL_PATH' ) ) { $tool_dir = realpath( EWWW_IMAGE_OPTIMIZER_TOOL_PATH ); $tool_dir = dirname( $tool_dir ); } if ( empty( $tool_dir ) ) { $tool_dir = $content_dir; } if ( defined( 'EWWWIO_CONTENT_DIR' ) ) { $eio_content_dir = realpath( EWWWIO_CONTENT_DIR ); } if ( empty( $eio_content_dir ) ) { $eio_content_dir = $content_dir; } if ( false === strpos( $file, $upload_dir ) && false === strpos( $file, $content_dir ) && false === strpos( $file, $wp_dir ) && false === strpos( $file, $plugin_dir ) && false === strpos( $file, $tool_dir ) && false === strpos( $file, $eio_content_dir ) ) { return false; } return $eio_filesystem->is_file( $file ); } /** * Check if destination is in an approved location and rename the original. * * @param string $src The path of the original file. * @param string $dst The destination file path. * @return bool True if the file was removed, false otherwise. */ function ewwwio_rename( $src, $dst ) { global $eio_filesystem; ewwwio_get_filesystem(); $src = realpath( $src ); if ( false !== strpos( $dst, WP_CONTENT_DIR ) ) { return $eio_filesystem->move( $src, $dst, true ); } if ( false !== strpos( $dst, ABSPATH ) ) { return $eio_filesystem->move( $src, $dst, true ); } $upload_dir = wp_get_upload_dir(); if ( false !== strpos( $dst, $upload_dir['basedir'] ) ) { return $eio_filesystem->move( $src, $dst, true ); } return false; } /** * Check if file is in an approved location and remove it. * * @param string $file The path of the file to check. * @param string $dir The path of the folder constraint. Optional. * @return bool True if the file was removed, false otherwise. */ function ewwwio_delete_file( $file, $dir = '' ) { $file = realpath( $file ); if ( ! empty( $dir ) ) { return wp_delete_file_from_directory( $file, $dir ); } $wp_dir = realpath( ABSPATH ); $upload_dir = wp_get_upload_dir(); $upload_dir = realpath( $upload_dir['basedir'] ); $content_dir = realpath( WP_CONTENT_DIR ); if ( false !== strpos( $file, $upload_dir ) ) { return wp_delete_file_from_directory( $file, $upload_dir ); } if ( false !== strpos( $file, $content_dir ) ) { return wp_delete_file_from_directory( $file, $content_dir ); } if ( false !== strpos( $file, $wp_dir ) ) { return wp_delete_file_from_directory( $file, $wp_dir ); } return false; } /** * Check if file is in an approved location and chmod it. * * @param string $file The path of the file to check. * @param string $mode The mode to apply to the file. */ function ewwwio_chmod( $file, $mode ) { global $eio_filesystem; ewwwio_get_filesystem(); clearstatcache(); $file = realpath( $file ); $upload_dir = wp_get_upload_dir(); if ( false !== strpos( $file, $upload_dir['basedir'] ) && is_writable( $file ) ) { return $eio_filesystem->chmod( $file, $mode ); } if ( false !== strpos( $file, WP_CONTENT_DIR ) && is_writable( $file ) ) { return $eio_filesystem->chmod( $file, $mode ); } if ( false !== strpos( $file, ABSPATH ) && is_writable( $file ) ) { return $eio_filesystem->chmod( $file, $mode ); } return false; } /** * Manually process an image from the Media Library * * @global bool $ewww_defer True if the image optimization should be deferred. */ function ewww_image_optimizer_manual() { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); global $ewww_force; global $ewww_convert; global $ewww_defer; $ewww_defer = false; add_filter( 'ewww_image_optimizer_allowed_reopt', '__return_true' ); // Check permissions of current user. $permissions = apply_filters( 'ewww_image_optimizer_manual_permissions', '' ); if ( ! current_user_can( $permissions ) ) { // Display error message if insufficient permissions. if ( ! wp_doing_ajax() ) { wp_die( esc_html__( 'You do not have permission to optimize images.', 'ewww-image-optimizer' ) ); } ewwwio_ob_clean(); wp_die( wp_json_encode( array( 'error' => esc_html__( 'You do not have permission to optimize images.', 'ewww-image-optimizer' ) ) ) ); } // Make sure we didn't accidentally get to this page without an attachment to work on. if ( empty( $_REQUEST['ewww_attachment_ID'] ) || empty( $_REQUEST['action'] ) ) { // Display an error message since we don't have anything to work on. if ( ! wp_doing_ajax() ) { wp_die( esc_html__( 'Invalid request.', 'ewww-image-optimizer' ) ); } ewwwio_ob_clean(); wp_die( wp_json_encode( array( 'error' => esc_html__( 'Invalid request.', 'ewww-image-optimizer' ) ) ) ); } session_write_close(); if ( empty( $_REQUEST['ewww_manual_nonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_manual_nonce'] ), 'ewww-manual' ) ) { if ( ! wp_doing_ajax() ) { wp_die( esc_html__( 'Access denied.', 'ewww-image-optimizer' ) ); } ewwwio_ob_clean(); wp_die( wp_json_encode( array( 'error' => esc_html__( 'Access denied.', 'ewww-image-optimizer' ) ) ) ); } // Store the attachment ID value. $attachment_id = (int) $_REQUEST['ewww_attachment_ID']; $ewww_force = ! empty( $_REQUEST['ewww_force'] ) ? true : false; $ewww_convert = ! empty( $_REQUEST['ewww_convert'] ) ? true : false; // Retrieve the existing attachment metadata. $original_meta = wp_get_attachment_metadata( $attachment_id ); // If the call was to optimize... if ( 'ewww_image_optimizer_manual_optimize' === $_REQUEST['action'] || 'ewww_manual_optimize' === $_REQUEST['action'] ) { // Call the optimize from metadata function and store the resulting new metadata. $new_meta = ewww_image_optimizer_resize_from_meta_data( $original_meta, $attachment_id ); } elseif ( 'ewww_image_optimizer_manual_restore' === $_REQUEST['action'] || 'ewww_manual_restore' === $_REQUEST['action'] ) { $new_meta = ewww_image_optimizer_restore_from_meta_data( $original_meta, $attachment_id ); } elseif ( 'ewww_image_optimizer_manual_image_restore' === $_REQUEST['action'] || 'ewww_manual_image_restore' === $_REQUEST['action'] ) { global $eio_backup; $new_meta = $eio_backup->restore_backup_from_meta_data( $attachment_id, 'media', $original_meta ); } else { if ( ! wp_doing_ajax() ) { wp_die( esc_html__( 'Access denied.', 'ewww-image-optimizer' ) ); } ewwwio_ob_clean(); wp_die( wp_json_encode( array( 'error' => esc_html__( 'Access denied.', 'ewww-image-optimizer' ) ) ) ); } $basename = ''; if ( is_array( $new_meta ) && ! empty( $new_meta['file'] ) ) { $basename = wp_basename( $new_meta['file'] ); } // Update the attachment metadata in the database. $meta_saved = wp_update_attachment_metadata( $attachment_id, $new_meta ); if ( ! $meta_saved ) { ewwwio_debug_message( 'failed to save meta, or no changes' ); } if ( 'exceeded' === get_transient( 'ewww_image_optimizer_cloud_status' ) || ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_exceeded' ) > time() ) { if ( ! wp_doing_ajax() ) { wp_die( '' . esc_html__( 'License exceeded', 'ewww-image-optimizer' ) . '' ); } ewwwio_ob_clean(); wp_die( wp_json_encode( array( 'error' => '' . esc_html__( 'License exceeded', 'ewww-image-optimizer' ) . '', ) ) ); } elseif ( 'exceeded quota' === get_transient( 'ewww_image_optimizer_cloud_status' ) ) { if ( ! wp_doing_ajax() ) { wp_die( '' . esc_html__( 'Soft quota reached, contact us for more', 'ewww-image-optimizer' ) . '' ); } ewwwio_ob_clean(); wp_die( wp_json_encode( array( 'error' => '' . esc_html__( 'Soft quota reached, contact us for more', 'ewww-image-optimizer' ) . '', ) ) ); } $success = ewww_image_optimizer_custom_column_capture( 'ewww-image-optimizer', $attachment_id, $new_meta ); ewww_image_optimizer_debug_log(); // Do a redirect, if this was called via GET. if ( ! wp_doing_ajax() ) { // Store the referring webpage location. $sendback = wp_get_referer(); // Send the user back where they came from. wp_safe_redirect( $sendback ); die; } ewwwio_memory( __FUNCTION__ ); ewwwio_ob_clean(); wp_die( wp_json_encode( array( 'success' => $success, 'basename' => $basename, ) ) ); } /** * Manually restore a converted image. * * @global object $wpdb * @global object $ewwwdb A clone of $wpdb unless it is lacking utf8 connectivity. * * @param array $meta The attachment metadata. * @param int $id The attachment id number. * @return array The attachment metadata. */ function ewww_image_optimizer_restore_from_meta_data( $meta, $id ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); global $wpdb; if ( strpos( $wpdb->charset, 'utf8' ) === false ) { ewww_image_optimizer_db_init(); global $ewwwdb; } else { $ewwwdb = $wpdb; } $db_image = $ewwwdb->get_results( "SELECT id,path,converted FROM $ewwwdb->ewwwio_images WHERE attachment_id = $id AND gallery = 'media' AND resize = 'full'", ARRAY_A ); if ( empty( $db_image ) || ! is_array( $db_image ) || empty( $db_image['path'] ) ) { // Get the filepath based on the meta and id. list( $file_path, $upload_path ) = ewww_image_optimizer_attachment_path( $meta, $id ); $db_image = ewww_image_optimizer_find_already_optimized( $file_path ); if ( empty( $db_image ) || ! is_array( $db_image ) || empty( $db_image['path'] ) ) { return $meta; } } $ewww_image = new EWWW_Image( $id, 'media', ewww_image_optimizer_absolutize_path( $db_image['path'] ) ); remove_filter( 'wp_update_attachment_metadata', 'ewww_image_optimizer_update_filesize_metadata', 9 ); return ewww_image_optimizer_update_filesize_metadata( $ewww_image->restore_with_meta( $meta ), $id, $ewww_image->file ); } /** * Manually restore an attachment from the API * * @global object $wpdb * @global object $ewwwdb A clone of $wpdb unless it is lacking utf8 connectivity. * * @param int $id The attachment id number. * @param string $gallery Optional. The gallery from whence we came. Default 'media'. * @param array $meta Optional. The image metadata from the postmeta table. * @return array The altered meta (if size differs), or the original value passed along. */ function ewww_image_optimizer_cloud_restore_from_meta_data( $id, $gallery = 'media', $meta = array() ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); global $wpdb; if ( strpos( $wpdb->charset, 'utf8' ) === false ) { ewww_image_optimizer_db_init(); global $ewwwdb; } else { $ewwwdb = $wpdb; } $images = $ewwwdb->get_results( "SELECT id,path,resize,backup FROM $ewwwdb->ewwwio_images WHERE attachment_id = $id AND gallery = '$gallery'", ARRAY_A ); foreach ( $images as $image ) { if ( ! empty( $image['path'] ) ) { $image['path'] = ewww_image_optimizer_absolutize_path( $image['path'] ); } ewww_image_optimizer_cloud_restore_single_image( $image ); if ( 'media' === $gallery && 'full' === $image['resize'] && ! empty( $meta['width'] ) && ! empty( $meta['height'] ) ) { list( $width, $height ) = wp_getimagesize( $image['path'] ); if ( (int) $width !== (int) $meta['width'] || (int) $height !== (int) $meta['height'] ) { $meta['height'] = $height; $meta['width'] = $width; } } } remove_filter( 'wp_update_attachment_metadata', 'ewww_image_optimizer_update_filesize_metadata', 9 ); $meta = ewww_image_optimizer_update_filesize_metadata( $meta, $id ); if ( ewww_image_optimizer_s3_uploads_enabled() ) { ewww_image_optimizer_remote_push( $meta, $id ); ewwwio_debug_message( 're-uploading to S3(_Uploads)' ); } return $meta; } /** * Handle the AJAX call for a single image restore. */ function ewww_image_optimizer_cloud_restore_single_image_handler() { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); // Check permissions of current user. $permissions = apply_filters( 'ewww_image_optimizer_manual_permissions', '' ); if ( false === current_user_can( $permissions ) ) { // Display error message if insufficient permissions. ewwwio_ob_clean(); wp_die( wp_json_encode( array( 'error' => esc_html__( 'You do not have permission to optimize images.', 'ewww-image-optimizer' ) ) ) ); } // Make sure we didn't accidentally get to this page without an attachment to work on. if ( empty( $_REQUEST['ewww_image_id'] ) ) { // Display an error message since we don't have anything to work on. ewwwio_ob_clean(); wp_die( wp_json_encode( array( 'error' => esc_html__( 'No image ID was provided.', 'ewww-image-optimizer' ) ) ) ); } if ( empty( $_REQUEST['ewww_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ) ) { ewwwio_ob_clean(); wp_die( wp_json_encode( array( 'error' => esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ) ) ); } session_write_close(); $image = (int) $_REQUEST['ewww_image_id']; if ( ewww_image_optimizer_cloud_restore_single_image( $image ) ) { ewwwio_ob_clean(); wp_die( wp_json_encode( array( 'success' => 1 ) ) ); } ewwwio_ob_clean(); wp_die( wp_json_encode( array( 'error' => esc_html__( 'Unable to restore image.', 'ewww-image-optimizer' ) ) ) ); } /** * Restores a single image from the API. * * @global object $wpdb * @global object $ewwwdb A clone of $wpdb unless it is lacking utf8 connectivity. * * @param int|array $image The db record/ID of the image to restore. * @return bool True if the image was restored successfully. */ function ewww_image_optimizer_cloud_restore_single_image( $image ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); global $eio_backup; global $wpdb; if ( strpos( $wpdb->charset, 'utf8' ) === false ) { ewww_image_optimizer_db_init(); global $ewwwdb; } else { $ewwwdb = $wpdb; } if ( ! is_array( $image ) && ! empty( $image ) && is_numeric( $image ) ) { $image = $ewwwdb->get_row( "SELECT id,path,backup FROM $ewwwdb->ewwwio_images WHERE id = $image", ARRAY_A ); } if ( ! empty( $image['path'] ) ) { $image['path'] = ewww_image_optimizer_absolutize_path( $image['path'] ); } $api_key = ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' ); $domain = parse_url( get_site_url(), PHP_URL_HOST ); $url = 'http://optimize.exactlywww.com/backup/restore.php'; $ssl = wp_http_supports( array( 'ssl' ) ); if ( $ssl ) { $url = set_url_scheme( $url, 'https' ); } $result = wp_remote_post( $url, array( 'timeout' => 30, 'sslverify' => false, 'body' => array( 'api_key' => $api_key, 'domain' => $domain, 'hash' => $image['backup'], ), ) ); if ( is_wp_error( $result ) ) { $error_message = $result->get_error_message(); ewwwio_debug_message( "restore request failed: $error_message" ); ewwwio_memory( __FUNCTION__ ); /* translators: %s: An HTTP error message */ $eio_backup->throw_error( sprintf( __( 'Restore failed with HTTP error: %s', 'ewww-image-optimizer' ), $error_message ) ); return false; } elseif ( ! empty( $result['body'] ) && strpos( $result['body'], 'missing' ) === false ) { $enabled_types = array( 'image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'image/svg+xml' ); if ( ! is_dir( dirname( $image['path'] ) ) ) { wp_mkdir_p( dirname( $image['path'] ) ); } file_put_contents( $image['path'] . '.tmp', $result['body'] ); $new_type = ewww_image_optimizer_mimetype( $image['path'] . '.tmp', 'i' ); $old_type = ''; if ( ewwwio_is_file( $image['path'] ) ) { $old_type = ewww_image_optimizer_mimetype( $image['path'], 'i' ); } if ( ! in_array( $new_type, $enabled_types, true ) ) { /* translators: %s: An image filename */ $eio_backup->throw_error( sprintf( __( 'Backup file for %s has the wrong mime type.', 'ewww-image-optimizer' ), $image['path'] ) ); return false; } if ( empty( $old_type ) || $old_type === $new_type ) { if ( ewwwio_rename( $image['path'] . '.tmp', $image['path'] ) ) { ewwwio_debug_message( "{$image['path']} was restored, removing .webp version and resetting db record" ); if ( ewwwio_is_file( $image['path'] . '.webp' ) && is_writable( $image['path'] . '.webp' ) ) { unlink( $image['path'] . '.webp' ); } // Set the results to nothing. $ewwwdb->query( "UPDATE $ewwwdb->ewwwio_images SET results = '', image_size = 0, updates = 0, updated=updated, level = 0 WHERE id = {$image['id']}" ); return true; } } } /* translators: %s: An image filename */ $eio_backup->throw_error( sprintf( __( 'Backup could not be retrieved for %s.', 'ewww-image-optimizer' ), $image['path'] ) ); return false; } /** * Cleans up when an attachment is being deleted. * * Removes any .webp images, backups from conversion, and removes related database records. * * @global object $wpdb * @global object $ewwwdb A clone of $wpdb unless it is lacking utf8 connectivity. * * @param int $id The id number for the attachment being deleted. */ function ewww_image_optimizer_delete( $id ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); global $eio_backup; global $wpdb; if ( strpos( $wpdb->charset, 'utf8' ) === false ) { ewww_image_optimizer_db_init(); global $ewwwdb; } else { $ewwwdb = $wpdb; } $id = (int) $id; // Finds non-meta images to remove from disk, and from db, as well as converted originals. $optimized_images = $ewwwdb->get_results( "SELECT path,converted FROM $ewwwdb->ewwwio_images WHERE attachment_id = $id AND gallery = 'media'", ARRAY_A ); if ( $optimized_images ) { if ( ewww_image_optimizer_iterable( $optimized_images ) ) { foreach ( $optimized_images as $image ) { if ( ! empty( $image['path'] ) ) { $image['path'] = ewww_image_optimizer_absolutize_path( $image['path'] ); } if ( ! empty( $image['path'] ) ) { if ( ewwwio_is_file( $image['path'] ) ) { ewwwio_debug_message( 'removing: ' . $image['path'] ); ewwwio_delete_file( $image['path'] ); } if ( ewwwio_is_file( $image['path'] . '.webp' ) ) { ewwwio_debug_message( 'removing: ' . $image['path'] . '.webp' ); ewwwio_delete_file( $image['path'] . '.webp' ); } $webpfileold = preg_replace( '/\.\w+$/', '.webp', $image['path'] ); if ( ewwwio_is_file( $webpfileold ) ) { ewwwio_debug_message( 'removing: ' . $webpfileold ); ewwwio_delete_file( $webpfileold ); } $eio_backup->delete_local_backup( $image['path'] ); } if ( ! empty( $image['converted'] ) ) { $image['converted'] = ewww_image_optimizer_absolutize_path( $image['converted'] ); $eio_backup->delete_local_backup( $image['converted'] ); } if ( ! empty( $image['converted'] ) && ewwwio_is_file( $image['converted'] ) ) { ewwwio_debug_message( 'removing: ' . $image['converted'] ); ewwwio_delete_file( $image['converted'] ); if ( ewwwio_is_file( $image['converted'] . '.webp' ) ) { ewwwio_debug_message( 'removing: ' . $image['converted'] . '.webp' ); ewwwio_delete_file( $image['converted'] . '.webp' ); } } } } ewwwio_debug_message( "removing all db records for attachment $id" ); $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'attachment_id' => $id ) ); } $s3_path = false; $s3_dir = false; if ( ewww_image_optimizer_s3_uploads_enabled() && ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp' ) ) { $s3_path = get_attached_file( $id ); if ( 0 === strpos( $s3_path, 's3://' ) ) { ewwwio_debug_message( 'removing: ' . $s3_path . '.webp' ); unlink( $s3_path . '.webp' ); } $s3_dir = trailingslashit( dirname( $s3_path ) ); } // Retrieve the image metadata. $meta = wp_get_attachment_metadata( $id ); // If the attachment has an original file set. if ( ! empty( $meta['orig_file'] ) ) { // Get the filepath from the metadata. $file_path = $meta['orig_file']; // Get the base filename. $filename = wp_basename( $file_path ); // Delete any residual webp versions. $webpfile = $file_path . '.webp'; $webpfileold = preg_replace( '/\.\w+$/', '.webp', $file_path ); if ( ewwwio_is_file( $webpfile ) ) { ewwwio_debug_message( 'removing: ' . $webpfile ); ewwwio_delete_file( $webpfile ); } if ( ewwwio_is_file( $webpfileold ) ) { ewwwio_debug_message( 'removing: ' . $webpfileold ); ewwwio_delete_file( $webpfileold ); } // Retrieve any posts that link the original image. $esql = "SELECT ID, post_content FROM $ewwwdb->posts WHERE post_content LIKE '%$filename%' LIMIT 1"; $rows = $ewwwdb->get_row( $esql ); // If the original file still exists and no posts contain links to the image. if ( ewwwio_is_file( $file_path ) && empty( $rows ) ) { ewwwio_debug_message( 'removing: ' . $file_path ); ewwwio_delete_file( $file_path ); $eio_backup->delete_local_backup( $file_path ); ewwwio_debug_message( "removing all db records for $file_path" ); $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'path' => ewww_image_optimizer_relativize_path( $file_path ) ) ); } } $file_path = get_attached_file( $id ); // If the attachment has an original file set. if ( ! empty( $meta['original_image'] ) ) { // One way or another, $file_path is now set, and we can get the base folder name. $base_dir = dirname( $file_path ) . '/'; // Get the original filename from the metadata. $orig_path = $base_dir . wp_basename( $meta['original_image'] ); // Delete any residual webp versions. $webpfile = $orig_path . '.webp'; if ( ewwwio_is_file( $webpfile ) ) { ewwwio_debug_message( 'removing: ' . $webpfile ); ewwwio_delete_file( $webpfile ); } if ( $s3_path && $s3_dir && wp_basename( $meta['original_image'] ) ) { ewwwio_debug_message( 'removing: ' . $s3_dir . wp_basename( $meta['original_image'] ) . '.webp' ); unlink( $s3_dir . wp_basename( $meta['original_image'] ) . '.webp' ); } $eio_backup->delete_local_backup( $orig_path ); ewwwio_debug_message( "removing all db records for $orig_path" ); $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'path' => ewww_image_optimizer_relativize_path( $orig_path ) ) ); } // Remove the regular image from the ewwwio_images tables. ewwwio_debug_message( "removing all db records for $file_path" ); $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'path' => ewww_image_optimizer_relativize_path( $file_path ) ) ); // Resized versions, so we can continue. if ( isset( $meta['sizes'] ) && ewww_image_optimizer_iterable( $meta['sizes'] ) ) { // One way or another, $file_path is now set, and we can get the base folder name. $base_dir = dirname( $file_path ) . '/'; foreach ( $meta['sizes'] as $size => $data ) { // Delete any residual webp versions. $webpfile = $base_dir . wp_basename( $data['file'] ) . '.webp'; $webpfileold = preg_replace( '/\.\w+$/', '.webp', $base_dir . wp_basename( $data['file'] ) ); if ( ewwwio_is_file( $webpfile ) ) { ewwwio_debug_message( 'removing: ' . $webpfile ); ewwwio_delete_file( $webpfile ); } if ( ewwwio_is_file( $webpfileold ) ) { ewwwio_debug_message( 'removing: ' . $webpfileold ); ewwwio_delete_file( $webpfileold ); } if ( $s3_path && $s3_dir && wp_basename( $data['file'] ) ) { ewwwio_debug_message( 'removing: ' . $s3_dir . wp_basename( $data['file'] ) . '.webp' ); unlink( $s3_dir . wp_basename( $data['file'] ) . '.webp' ); } $eio_backup->delete_local_backup( $base_dir . wp_basename( $data['file'] ) ); ewwwio_debug_message( "removing all db records for {$data['file']}" ); $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'path' => ewww_image_optimizer_relativize_path( $base_dir . $data['file'] ) ) ); // If the original resize is set, and still exists. if ( ! empty( $data['orig_file'] ) && ewwwio_is_file( $base_dir . $data['orig_file'] ) ) { unset( $srows ); // Retrieve the filename from the metadata. $filename = $data['orig_file']; // Retrieve any posts that link the image. $esql = "SELECT ID, post_content FROM $ewwwdb->posts WHERE post_content LIKE '%$filename%' LIMIT 1"; $srows = $ewwwdb->get_row( $esql ); // If there are no posts containing links to the original, delete it. if ( empty( $srows ) ) { ewwwio_debug_message( 'removing: ' . $base_dir . $data['orig_file'] ); ewwwio_delete_file( $base_dir . $data['orig_file'] ); $eio_backup->delete_local_backup( $base_dir . $data['orig_file'] ); ewwwio_debug_message( "removing all db records for {$data['orig_file']}" ); $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'path' => ewww_image_optimizer_relativize_path( $base_dir . $data['orig_file'] ) ) ); } } } } if ( ewwwio_is_file( $file_path . '.webp' ) ) { ewwwio_debug_message( 'removing: ' . $file_path . '.webp' ); ewwwio_delete_file( $file_path . '.webp' ); } $webpfileold = preg_replace( '/\.\w+$/', '.webp', $file_path ); if ( ewwwio_is_file( $webpfileold ) ) { ewwwio_debug_message( 'removing: ' . $webpfileold ); ewwwio_delete_file( $webpfileold ); } $eio_backup->delete_local_backup( $file_path ); } /** * Cleans up when a file has been deleted. * * Removes any .webp images, backups from conversion, and removes related database records. * * @global object $wpdb * @global object $ewwwdb A clone of $wpdb unless it is lacking utf8 connectivity. * * @param int $id The id number for the attachment being deleted. * @param string $file The file being deleted. */ function ewww_image_optimizer_file_deleted( $id, $file ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); global $eio_backup; global $wpdb; if ( strpos( $wpdb->charset, 'utf8' ) === false ) { ewww_image_optimizer_db_init(); global $ewwwdb; } else { $ewwwdb = $wpdb; } $id = (int) $id; // Finds non-meta images to remove from disk, and from db, as well as converted originals. $maybe_relative_path = ewww_image_optimizer_relativize_path( $file ); $query = $ewwwdb->prepare( "SELECT * FROM $ewwwdb->ewwwio_images WHERE path = %s", $maybe_relative_path ); $optimized_images = $ewwwdb->get_results( $query, ARRAY_A ); if ( ewww_image_optimizer_iterable( $optimized_images ) ) { foreach ( $optimized_images as $image ) { if ( ! empty( $image['path'] ) ) { $image['path'] = ewww_image_optimizer_absolutize_path( $image['path'] ); } if ( strpos( $image['path'], WP_CONTENT_DIR ) === false ) { continue; } if ( ! empty( $image['converted'] ) ) { $image['converted'] = ewww_image_optimizer_absolutize_path( $image['converted'] ); } if ( ! empty( $image['converted'] ) && ewwwio_is_file( $image['converted'] ) ) { ewwwio_delete_file( $image['converted'] ); if ( ewwwio_is_file( $image['converted'] . '.webp' ) ) { ewwwio_delete_file( $image['converted'] . '.webp' ); } } $eio_backup->delete_local_backup( $image['converted'] ); $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'id' => $image['id'] ) ); } } if ( ewwwio_is_file( $file . '.webp' ) ) { ewwwio_delete_file( $file . '.webp' ); } $eio_backup->delete_local_backup( $file ); } /** * Cleans records from database when an image is about to be replaced. * * @param array $attachment An array with the attachment/image ID. */ function ewww_image_optimizer_media_replace( $attachment ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); global $wpdb; if ( strpos( $wpdb->charset, 'utf8' ) === false ) { ewww_image_optimizer_db_init(); global $ewwwdb; } else { $ewwwdb = $wpdb; } $id = (int) $attachment['post_id']; // Finds non-meta images to remove from disk, and from db, as well as converted originals. $optimized_images = $ewwwdb->get_results( "SELECT path,converted FROM $ewwwdb->ewwwio_images WHERE attachment_id = $id AND gallery = 'media'", ARRAY_A ); if ( $optimized_images ) { if ( ewww_image_optimizer_iterable( $optimized_images ) ) { foreach ( $optimized_images as $image ) { if ( ! empty( $image['path'] ) ) { $image['path'] = ewww_image_optimizer_absolutize_path( $image['path'] ); } if ( false === strpos( $image['path'], WP_CONTENT_DIR ) ) { continue; } if ( ! empty( $image['path'] ) ) { if ( ewwwio_is_file( $image['path'] . '.webp' ) ) { ewwwio_delete_file( $image['path'] . '.webp' ); } } if ( ! empty( $image['converted'] ) ) { $image['converted'] = ewww_image_optimizer_absolutize_path( $image['converted'] ); } if ( ! empty( $image['converted'] ) && ewwwio_is_file( $image['converted'] ) ) { ewwwio_delete_file( $image['converted'] ); if ( ewwwio_is_file( $image['converted'] . '.webp' ) ) { ewwwio_delete_file( $image['converted'] . '.webp' ); } } } } ewwwio_debug_message( "removing all db records for attachment $id" ); $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'attachment_id' => $id ) ); } // Retrieve the image metadata. $meta = wp_get_attachment_metadata( $id ); // If the attachment has an original file set. if ( ! empty( $meta['orig_file'] ) ) { // Get the filepath from the metadata. $file_path = $meta['orig_file']; $webpfile = $file_path . '.webp'; $webpfileold = preg_replace( '/\.\w+$/', '.webp', $file_path ); if ( ewwwio_is_file( $webpfile ) ) { ewwwio_delete_file( $webpfile ); } if ( ewwwio_is_file( $webpfileold ) ) { ewwwio_delete_file( $webpfileold ); } $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'path' => ewww_image_optimizer_relativize_path( $file_path ) ) ); } list( $file_path, $upload_path ) = ewww_image_optimizer_attachment_path( $meta, $id ); // If the attachment has an original file set. if ( ! empty( $meta['original_image'] ) ) { // One way or another, $file_path is now set, and we can get the base folder name. $base_dir = dirname( $file_path ) . '/'; // Get the original filename from the metadata. $orig_path = $base_dir . wp_basename( $meta['original_image'] ); // Delete any residual webp versions. $webpfile = $orig_path . '.webp'; if ( ewwwio_is_file( $webpfile ) ) { ewwwio_delete_file( $webpfile ); } $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'path' => ewww_image_optimizer_relativize_path( $orig_path ) ) ); } // Remove the regular image from the ewwwio_images tables. $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'path' => ewww_image_optimizer_relativize_path( $file_path ) ) ); // Resized versions, so we can continue. if ( isset( $meta['sizes'] ) && ewww_image_optimizer_iterable( $meta['sizes'] ) ) { // One way or another, $file_path is now set, and we can get the base folder name. $base_dir = dirname( $file_path ) . '/'; foreach ( $meta['sizes'] as $size => $data ) { // Delete any residual webp versions. $webpfile = $base_dir . $data['file'] . '.webp'; $webpfileold = preg_replace( '/\.\w+$/', '.webp', $base_dir . $data['file'] ); if ( ewwwio_is_file( $webpfile ) ) { ewwwio_delete_file( $webpfile ); } if ( ewwwio_is_file( $webpfileold ) ) { ewwwio_delete_file( $webpfileold ); } $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'path' => ewww_image_optimizer_relativize_path( $base_dir . $data['file'] ) ) ); // If the original resize is set, and still exists. if ( ! empty( $data['orig_file'] ) ) { // Retrieve the filename from the metadata. $filename = $data['orig_file']; $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'path' => ewww_image_optimizer_relativize_path( $base_dir . $data['orig_file'] ) ) ); } } } } /** * Cleans records from database after an image has been renamed. * * @param string $old_name The filename of the original/old image. * @param string $new_name The filename of the new image. */ function ewww_image_optimizer_media_rename( $old_name, $new_name ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); global $wpdb; if ( strpos( $wpdb->charset, 'utf8' ) === false ) { ewww_image_optimizer_db_init(); global $ewwwdb; } else { $ewwwdb = $wpdb; } if ( ! check_ajax_referer( 'phoenix_media_rename', '_wpnonce', false ) || empty( $_REQUEST['post_id'] ) ) { return; } $id = (int) $_REQUEST['post_id']; ewwwio_debug_message( "image renamed from $old_name to $new_name, looking for old records (id $id)" ); // Finds images to remove from disk, and from db, as well as converted originals. $optimized_images = $ewwwdb->get_results( "SELECT id,path,resize,converted FROM $ewwwdb->ewwwio_images WHERE attachment_id = $id AND gallery = 'media'", ARRAY_A ); if ( ewww_image_optimizer_iterable( $optimized_images ) ) { foreach ( $optimized_images as $image ) { if ( ! empty( $image['path'] ) ) { $image['path'] = ewww_image_optimizer_absolutize_path( $image['path'] ); } ewwwio_debug_message( "checking to see if {$image['path']} is stale" ); if ( false === strpos( $image['path'], WP_CONTENT_DIR ) ) { ewwwio_debug_message( 'not in ' . WP_CONTENT_DIR ); continue; } if ( ewwwio_is_file( $image['path'] ) ) { ewwwio_debug_message( 'file still exists, skipping' ); continue; } if ( ! empty( $image['path'] ) && ewwwio_is_file( $image['path'] . '.webp' ) ) { ewwwio_debug_message( 'removing WebP version' ); ewwwio_delete_file( $image['path'] . '.webp' ); } if ( ! empty( $image['converted'] ) ) { $image['converted'] = ewww_image_optimizer_absolutize_path( $image['converted'] ); } if ( ! empty( $image['converted'] ) && ewwwio_is_file( $image['converted'] ) ) { ewwwio_debug_message( 'removing "converted" file' ); ewwwio_delete_file( $image['converted'] ); if ( ewwwio_is_file( $image['converted'] . '.webp' ) ) { ewwwio_debug_message( 'and WebP derivative' ); ewwwio_delete_file( $image['converted'] . '.webp' ); } } if ( 'full' === $image['resize'] ) { ewwwio_debug_message( "updating path for $id (full)" ); $new_path = str_replace( wp_basename( $old_name ), wp_basename( $new_name ), $image['path'] ); if ( ewwwio_is_file( $new_path ) ) { $new_path = ewww_image_optimizer_relativize_path( $new_path ); $ewwwdb->update( $ewwwdb->ewwwio_images, array( 'path' => $new_path, ), array( 'id' => $image['id'], ) ); continue; } } $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'id' => $image['id'] ) ); } } // Retrieve the image metadata. $meta = wp_get_attachment_metadata( $id ); // If the attachment has an original file set. if ( ! empty( $meta['orig_file'] ) && ! ewwwio_is_file( $meta['orig_file'] ) ) { // Get the filepath from the metadata. $file_path = $meta['orig_file']; $webpfile = $file_path . '.webp'; $webpfileold = preg_replace( '/\.\w+$/', '.webp', $file_path ); if ( ewwwio_is_file( $webpfile ) ) { ewwwio_delete_file( $webpfile ); } if ( ewwwio_is_file( $webpfileold ) ) { ewwwio_delete_file( $webpfileold ); } $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'path' => ewww_image_optimizer_relativize_path( $file_path ) ) ); } ewww_image_optimizer_resize_from_meta_data( $meta, $id ); } /** * Activates Easy IO via AJAX. */ function ewww_image_optimizer_exactdn_activate_ajax() { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( false === current_user_can( apply_filters( 'ewww_image_optimizer_admin_permissions', '' ) ) ) { // Display error message if insufficient permissions. ewwwio_ob_clean(); wp_die( wp_json_encode( array( 'error' => esc_html__( 'Access denied.', 'ewww-image-optimizer' ) ) ) ); } // Make sure we didn't accidentally get to this page without an attachment to work on. if ( empty( $_REQUEST['ewww_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-settings' ) ) { die( wp_json_encode( array( 'error' => esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ) ) ); } if ( is_multisite() && defined( 'EXACTDN_SUB_FOLDER' ) && EXACTDN_SUB_FOLDER ) { update_site_option( 'ewww_image_optimizer_exactdn', true ); } elseif ( defined( 'EXACTDN_SUB_FOLDER' ) ) { update_option( 'ewww_image_optimizer_exactdn', true ); } elseif ( is_multisite() && get_site_option( 'exactdn_sub_folder' ) ) { update_site_option( 'ewww_image_optimizer_exactdn', true ); } else { update_option( 'ewww_image_optimizer_exactdn', true ); } if ( ! class_exists( 'EWWW\ExactDN' ) ) { /** * Page Parsing class for working with HTML content. */ require_once EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-page-parser.php'; /** * ExactDN class for parsing image urls and rewriting them. */ require_once EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-exactdn.php'; } global $exactdn; if ( $exactdn->get_exactdn_domain() ) { die( wp_json_encode( array( 'success' => esc_html__( 'Easy IO setup and verification is complete.', 'ewww-image-optimizer' ) ) ) ); } global $exactdn_activate_error; if ( empty( $exactdn_activate_error ) ) { $exactdn_activate_error = 'error unknown'; } $error_message = sprintf( /* translators: 1: A link to the documentation 2: the error message/details */ esc_html__( 'Could not activate Easy IO, please try again in a few minutes. If this error continues, please see %1$s for troubleshooting steps: %2$s', 'ewww-image-optimizer' ), 'https://docs.ewww.io/article/66-exactdn-not-verified', '' . esc_html( $exactdn_activate_error ) . '
'
);
if ( 'as3cf_cname_active' === $exactdn_activate_error ) {
$error_message = esc_html__( 'Easy IO cannot optimize your images while using a custom domain (CNAME) in WP Offload Media. Please disable the custom domain in the WP Offload Media settings.', 'ewww-image-optimizer' );
}
die(
wp_json_encode(
array(
'error' => $error_message,
)
)
);
}
/**
* Activates Easy IO via AJAX for a given blog on a multi-site install.
*/
function ewww_image_optimizer_exactdn_activate_site_ajax() {
ewwwio_debug_message( '' . __FUNCTION__ . '()' );
if ( false === current_user_can( apply_filters( 'ewww_image_optimizer_admin_permissions', '' ) ) ) {
// Display error message if insufficient permissions.
ewwwio_ob_clean();
wp_die( wp_json_encode( array( 'error' => esc_html__( 'Access denied.', 'ewww-image-optimizer' ) ) ) );
}
if ( empty( $_REQUEST['ewww_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-settings' ) ) {
die( wp_json_encode( array( 'error' => esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ) ) );
}
if ( empty( $_REQUEST['blog_id'] ) ) {
die( wp_json_encode( array( 'error' => esc_html__( 'Blog ID not provided.', 'ewww-image-optimizer' ) ) ) );
}
$blog_id = (int) $_REQUEST['blog_id'];
if ( get_current_blog_id() !== $blog_id ) {
switch_to_blog( $blog_id );
}
ewwwio_debug_message( "activating site $blog_id" );
if ( get_option( 'ewww_image_optimizer_exactdn' ) ) {
die( wp_json_encode( array( 'success' => esc_html__( 'Easy IO setup and verification is complete.', 'ewww-image-optimizer' ) ) ) );
}
update_option( 'ewww_image_optimizer_exactdn', true );
global $exactdn;
if ( ! class_exists( 'EWWW\ExactDN' ) ) {
/**
* Page Parsing class for working with HTML content.
*/
require_once EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-page-parser.php';
/**
* ExactDN class for parsing image urls and rewriting them.
*/
require_once EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-exactdn.php';
} elseif ( is_object( $exactdn ) ) {
unset( $GLOBALS['exactdn'] );
$exactdn = new EWWW\ExactDN();
}
if ( $exactdn->get_exactdn_domain() ) {
ewwwio_debug_message( 'activated site ' . $exactdn->content_url() . ' got domain ' . $exactdn->get_exactdn_domain() );
die( wp_json_encode( array( 'success' => esc_html__( 'Easy IO setup and verification is complete.', 'ewww-image-optimizer' ) ) ) );
}
restore_current_blog();
global $exactdn_activate_error;
if ( empty( $exactdn_activate_error ) ) {
$exactdn_activate_error = 'error unknown';
}
$error_message = sprintf(
/* translators: 1: The blog URL 2: the error message/details */
esc_html__( 'Could not activate Easy IO on %1$s: %2$s', 'ewww-image-optimizer' ),
esc_url( get_home_url( $blog_id ) ),
'' . esc_html( $exactdn_activate_error ) . '
'
);
if ( 'as3cf_cname_active' === $exactdn_activate_error ) {
$error_message = esc_html__( 'Easy IO cannot optimize your images while using a custom domain (CNAME) in WP Offload Media. Please disable the custom domain in the WP Offload Media settings.', 'ewww-image-optimizer' );
}
die(
wp_json_encode(
array(
'error' => $error_message,
)
)
);
}
/**
* Registers Easy IO via AJAX for a given blog on a multi-site install.
*/
function ewww_image_optimizer_exactdn_register_site_ajax() {
ewwwio_debug_message( '' . __FUNCTION__ . '()' );
if ( false === current_user_can( apply_filters( 'ewww_image_optimizer_admin_permissions', '' ) ) ) {
// Display error message if insufficient permissions.
ewwwio_ob_clean();
wp_die( wp_json_encode( array( 'error' => esc_html__( 'Access denied.', 'ewww-image-optimizer' ) ) ) );
}
if ( empty( $_REQUEST['ewww_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-settings' ) ) {
die( wp_json_encode( array( 'error' => esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ) ) );
}
if ( empty( $_REQUEST['blog_id'] ) ) {
die( wp_json_encode( array( 'error' => esc_html__( 'Blog ID not provided.', 'ewww-image-optimizer' ) ) ) );
}
$blog_id = (int) $_REQUEST['blog_id'];
if ( get_current_blog_id() !== $blog_id ) {
$switch = true;
switch_to_blog( $blog_id );
}
ewwwio_debug_message( "registering site $blog_id" );
if ( get_option( 'ewww_image_optimizer_exactdn' ) ) {
if ( ! empty( $switch ) ) {
restore_current_blog();
}
die( wp_json_encode( array( 'status' => 'active' ) ) );
}
$result = ewww_image_optimizer_register_site_post();
if ( ! empty( $switch ) ) {
restore_current_blog();
}
if ( is_wp_error( $result ) ) {
$error_message = $result->get_error_message();
$easyio_site_url = get_home_url( $blog_id );
ewwwio_debug_message( "registration failed for $easyio_site_url: $error_message" );
die(
wp_json_encode(
array(
'error' => sprintf(
/* translators: %s: an HTTP error message */
esc_html__( 'Could not register site, HTTP error: %s', 'ewww-image-optimizer' ),
$error_message
),
)
)
);
} elseif ( ! empty( $result['body'] ) ) {
$response = json_decode( $result['body'], true );
if ( ! empty( $response['error'] ) && false !== strpos( strtolower( $response['error'] ), 'duplicate site url' ) ) {
die( wp_json_encode( array( 'status' => 'registered' ) ) );
}
die( wp_json_encode( $response ) );
}
$error_message = sprintf(
/* translators: %s: The blog URL */
esc_html__( 'Could not register Easy IO for %s: error unknown.', 'ewww-image-optimizer' ),
esc_url( get_home_url( $blog_id ) )
);
die(
wp_json_encode(
array(
'error' => $error_message,
)
)
);
}
/**
* Registers Easy IO for a new blog on a multi-site install.
*
* @param object $new_site WP_Site instace for the new site.
*/
function ewww_image_optimizer_initialize_site( $new_site ) {
ewwwio_debug_message( '' . __FUNCTION__ . '()' );
if ( empty( $new_site->id ) ) {
return;
}
if ( ! defined( 'EASYIO_NEW_SITE_AUTOREG' ) || ! EASYIO_NEW_SITE_AUTOREG ) {
return;
}
if ( get_current_blog_id() !== $new_site->id ) {
$switch = true;
switch_to_blog( $new_site->id );
}
$result = ewww_image_optimizer_register_site_post();
$easyio_site_url = get_home_url( $new_site->id );
if ( ! empty( $switch ) ) {
restore_current_blog();
}
if ( is_wp_error( $result ) ) {
$error_message = $result->get_error_message();
ewwwio_debug_message( "registration failed for $easyio_site_url: $error_message" );
} elseif ( ! empty( $result['body'] ) ) {
$response = json_decode( $result['body'], true );
if ( ! empty( $response['error'] ) ) {
ewwwio_debug_message( "registration failed for $easyio_site_url: {$response['error']}" );
}
}
}
/**
* POSTs the site URL to the API for Easy IO registration.
*
* @return array The results of the http POST request.
*/
function ewww_image_optimizer_register_site_post() {
ewwwio_debug_message( '' . __FUNCTION__ . '()' );
// Get the site URL for a given blog.
$site_url = ewwwio()->content_url();
$key = ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' );
if ( empty( $key ) ) {
return new WP_Error( 'missing_key', __( 'No API key for Easy IO registration', 'ewww-image-optimizer' ) );
}
ewwwio_debug_message( "registering $site_url on Easy IO" );
$url = 'https://optimize.exactlywww.com/exactdn/create.php';
add_filter( 'http_headers_useragent', 'ewww_image_optimizer_cloud_useragent', PHP_INT_MAX );
$result = wp_remote_post(
$url,
array(
'timeout' => 60,
'sslverify' => false,
'body' => array(
'api_key' => $key,
'site_url' => $site_url,
),
)
);
return $result;
}
/**
* Removes site from Easy IO via AJAX for a given site ID.
*/
function ewww_image_optimizer_exactdn_deregister_site_ajax() {
ewwwio_debug_message( '' . __FUNCTION__ . '()' );
if ( false === current_user_can( apply_filters( 'ewww_image_optimizer_admin_permissions', '' ) ) ) {
// Display error message if insufficient permissions.
ewwwio_ob_clean();
wp_die( wp_json_encode( array( 'error' => esc_html__( 'Access denied.', 'ewww-image-optimizer' ) ) ) );
}
if ( empty( $_REQUEST['ewww_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-settings' ) ) {
die( wp_json_encode( array( 'error' => esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ) ) );
}
if ( empty( $_REQUEST['site_id'] ) ) {
die( wp_json_encode( array( 'error' => esc_html__( 'Site ID unknown.', 'ewww-image-optimizer' ) ) ) );
}
$site_id = (int) $_REQUEST['site_id'];
ewwwio_debug_message( "deregistering site $site_id" );
$result = ewww_image_optimizer_deregister_site_post( $site_id );
if ( is_wp_error( $result ) ) {
$error_message = $result->get_error_message();
ewwwio_debug_message( "de-registration failed: $error_message" );
die(
wp_json_encode(
array(
'error' => sprintf(
/* translators: %s: an HTTP error message */
esc_html__( 'Could not de-register site, HTTP error: %s', 'ewww-image-optimizer' ),
$error_message
),
)
)
);
} elseif ( ! empty( $result['body'] ) ) {
$response = json_decode( $result['body'], true );
if ( ! empty( $response['success'] ) ) {
$response['success'] = esc_html__( 'Successfully removed site from Easy IO.', 'ewww-image-optimizer' );
}
die( wp_json_encode( $response ) );
}
die(
wp_json_encode(
array(
'error' => esc_html__( 'Could not remove site from Easy IO: error unknown.', 'ewww-image-optimizer' ),
)
)
);
}
/**
* POSTs the site URL to the API for Easy IO registration.
*
* @param int $site_id The site ID for the Easy IO zone.
* @return array The results of the http POST request.
*/
function ewww_image_optimizer_deregister_site_post( $site_id ) {
ewwwio_debug_message( '' . __FUNCTION__ . '()' );
$key = ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' );
if ( empty( $key ) ) {
return new WP_Error( 'missing_key', __( 'No API key for Easy IO removal', 'ewww-image-optimizer' ) );
}
ewwwio_debug_message( "removing site $site_id from Easy IO" );
$url = 'https://optimize.exactlywww.com/exactdn/remove.php';
add_filter( 'http_headers_useragent', 'ewww_image_optimizer_cloud_useragent', PHP_INT_MAX );
$result = wp_remote_post(
$url,
array(
'timeout' => 60,
'sslverify' => false,
'body' => array(
'api_key' => $key,
'site_id' => (int) $site_id,
),
)
);
return $result;
}
/**
* Checks to see if a site is registered with Easy IO.
*
* @param string $site_url The site URL to check for an Easy IO record.
* @return bool True if the site is already registered, false otherwise.
*/
function ewww_image_optimizer_easy_site_registered( $site_url ) {
ewwwio_debug_message( '' . __FUNCTION__ . '()' );
global $easyio_site_registered;
global $easyio_site_id;
if ( isset( $easyio_site_registered ) ) {
return $easyio_site_registered;
}
$easyio_site_registered = false;
$easyio_site_id = 0;
$cloud_key = ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' );
if ( ! empty( $cloud_key ) ) {
ewwwio_debug_message( "checking $site_url with Easy IO" );
$url = 'https://optimize.exactlywww.com/exactdn/show.php';
add_filter( 'http_headers_useragent', 'ewww_image_optimizer_cloud_useragent', PHP_INT_MAX );
$result = wp_remote_post(
$url,
array(
'timeout' => 30,
'sslverify' => false,
'body' => array(
'api_key' => $cloud_key,
'site_url' => $site_url,
),
)
);
if ( is_wp_error( $result ) ) {
$error_message = $result->get_error_message();
ewwwio_debug_message( "register check via /show.php failed: $error_message" );
} else {
$easy_info = json_decode( $result['body'], true );
if (
is_array( $easy_info ) && ! empty( $easy_info['sites'][0]['site_url'] ) &&
trailingslashit( $site_url ) === $easy_info['sites'][0]['site_url']
) {
$easyio_site_registered = true;
$easyio_site_id = (int) $easy_info['sites'][0]['site_id'];
return true;
}
if ( is_array( $easy_info ) && ! empty( $easy_info['sites'][0]['site_url'] ) ) {
ewwwio_debug_message( 'found (maybe different) site 0: ' . $easy_info['sites'][0]['site_url'] );
}
}
}
return false;
}
/**
* Sanitizes an API key for the cloud service.
*
* @param string $key An API key entered by the user.
* @return string A sanitized API key.
*/
function ewww_image_optimizer_cloud_key_sanitize( $key ) {
ewwwio_debug_message( '' . __FUNCTION__ . '()' );
$key = trim( $key );
if ( ! empty( $key ) && strlen( $key ) < 200 && preg_match( '/^[a-zA-Z0-9]+$/', $key ) ) {
return $key;
}
return '';
}
/**
* Verifies an API key via AJAX.
*/
function ewww_image_optimizer_cloud_key_verify_ajax() {
ewwwio_debug_message( '' . __FUNCTION__ . '()' );
if ( false === current_user_can( apply_filters( 'ewww_image_optimizer_admin_permissions', '' ) ) ) {
// Display error message if insufficient permissions.
ewwwio_ob_clean();
wp_die( wp_json_encode( array( 'error' => esc_html__( 'Access denied.', 'ewww-image-optimizer' ) ) ) );
}
if ( empty( $_REQUEST['ewww_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-settings' ) ) {
die( wp_json_encode( array( 'error' => esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ) ) );
}
if ( empty( $_POST['compress_api_key'] ) ) {
die( wp_json_encode( array( 'error' => esc_html__( 'Please enter your API key and try again.', 'ewww-image-optimizer' ) ) ) );
}
$api_key = trim( ewww_image_optimizer_cloud_key_sanitize( wp_unslash( $_POST['compress_api_key'] ) ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$url = 'http://optimize.exactlywww.com/verify/';
if ( wp_http_supports( array( 'ssl' ) ) ) {
$url = set_url_scheme( $url, 'https' );
}
$result = ewww_image_optimizer_cloud_post_key( $url, $api_key );
if ( is_wp_error( $result ) ) {
$url = set_url_scheme( $url, 'http' );
$error_message = $result->get_error_message();
ewwwio_debug_message( "verification failed: $error_message" );
$result = ewww_image_optimizer_cloud_post_key( $url, $api_key );
}
if ( is_wp_error( $result ) ) {
$error_message = $result->get_error_message();
ewwwio_debug_message( "verification failed via $url: $error_message" );
die(
wp_json_encode(
array(
'error' => sprintf(
/* translators: %s: an HTTP error message */
esc_html__( 'Could not validate API key, HTTP error: %s', 'ewww-image-optimizer' ),
$error_message
),
)
)
);
} elseif ( ! empty( $result['body'] ) && preg_match( '/(great|exceeded)/', $result['body'] ) ) {
$verified = $result['body'];
if ( preg_match( '/exceeded/', $verified ) ) {
die( wp_json_encode( array( 'error' => esc_html__( 'No credits remaining for API key.', 'ewww-image-optimizer' ) ) ) );
}
ewwwio_debug_message( "verification success via: $url" );
delete_option( 'ewww_image_optimizer_cloud_key_invalid' );
ewww_image_optimizer_set_option( 'ewww_image_optimizer_cloud_key', $api_key );
set_transient( 'ewww_image_optimizer_cloud_status', $verified, HOUR_IN_SECONDS );
if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_jpg_level' ) < 20 && ewww_image_optimizer_get_option( 'ewww_image_optimizer_png_level' ) < 20 && ewww_image_optimizer_get_option( 'ewww_image_optimizer_gif_level' ) < 20 && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_pdf_level' ) ) {
ewww_image_optimizer_cloud_enable();
}
ewwwio_debug_message( "verification body contents: {$result['body']}" );
die( wp_json_encode( array( 'success' => esc_html__( 'Successfully validated API key, happy optimizing!', 'ewww-image-optimizer' ) ) ) );
} else {
ewwwio_debug_message( "verification failed via: $url" );
if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_debug' ) && ewww_image_optimizer_function_exists( 'print_r' ) ) {
ewwwio_debug_message( print_r( $result, true ) );
}
die( wp_json_encode( array( 'error' => esc_html__( 'Could not validate API key, please copy and paste your key to ensure it is correct.', 'ewww-image-optimizer' ) ) ) );
}
}
/**
* Checks to see if all images should be processed via the API.
*
* @return bool True if all 'cloud' options are enabled.
*/
function ewww_image_optimizer_full_cloud() {
return ewwwio()->cloud_mode;
if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' ) && ewww_image_optimizer_get_option( 'ewww_image_optimizer_jpg_level' ) > 10 && ewww_image_optimizer_get_option( 'ewww_image_optimizer_png_level' ) > 10 ) {
return true;
}
return false;
}
/**
* Used to turn on the cloud settings when they are all disabled.
*/
function ewww_image_optimizer_cloud_enable() {
ewwwio_debug_message( '' . __FUNCTION__ . '()' );
ewww_image_optimizer_set_option( 'ewww_image_optimizer_jpg_level', 30 );
ewww_image_optimizer_set_option( 'ewww_image_optimizer_png_level', 20 );
ewww_image_optimizer_set_option( 'ewww_image_optimizer_gif_level', 10 );
ewww_image_optimizer_set_option( 'ewww_image_optimizer_pdf_level', 10 );
ewww_image_optimizer_set_option( 'ewww_image_optimizer_svg_level', 10 );
if ( 'local' !== ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ) ) {
ewww_image_optimizer_set_option( 'ewww_image_optimizer_backup_files', 'cloud' );
}
}
/**
* Adds the EWWW IO version to the useragent for http requests.
*
* @param string $useragent The current useragent used in http requests.
* @return string The useragent with the EWWW IO version appended.
*/
function ewww_image_optimizer_cloud_useragent( $useragent ) {
if ( strpos( $useragent, 'EWWW' ) === false ) {
$useragent .= ' EWWW/' . EWWW_IMAGE_OPTIMIZER_VERSION . ' ';
}
return $useragent;
}
/**
* Submits the api key for verification. Will retrieve the key option if parameter not provided.
*
* @param string $api_key The API key to verify. Default empty string.
* @param bool $cache Optional. True to return cached verification results. Default true.
* @return string|bool False if verification fails, status message otherwise: great/exceeded.
*/
function ewww_image_optimizer_cloud_verify( $api_key, $cache = true ) {
ewwwio_debug_message( '' . __FUNCTION__ . '()' );
$sanitize = false;
if ( empty( $api_key ) ) {
if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_jpg_level' ) > 10 ) {
update_site_option( 'ewww_image_optimizer_jpg_level', 10 );
update_option( 'ewww_image_optimizer_jpg_level', 10 );
}
if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_png_level' ) > 10 && 40 !== (int) ewww_image_optimizer_get_option( 'ewww_image_optimizer_png_level' ) ) {
update_site_option( 'ewww_image_optimizer_png_level', 10 );
update_option( 'ewww_image_optimizer_png_level', 10 );
}
if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_pdf_level' ) > 0 ) {
update_site_option( 'ewww_image_optimizer_pdf_level', 0 );
update_option( 'ewww_image_optimizer_pdf_level', 0 );
}
if ( 'local' !== ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ) ) {
update_site_option( 'ewww_image_optimizer_backup_files', '' );
update_option( 'ewww_image_optimizer_backup_files', '' );
}
return false;
}
if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_exceeded' ) > time() ) {
set_transient( 'ewww_image_optimizer_cloud_status', 'exceeded', HOUR_IN_SECONDS );
ewwwio_debug_message( 'license exceeded notice has not expired' );
return 'exceeded';
}
$ewww_cloud_status = get_transient( 'ewww_image_optimizer_cloud_status' );
if ( ! ewww_image_optimizer_detect_wpsf_location_lock() && $cache && preg_match( '/great/', $ewww_cloud_status ) ) {
ewwwio_debug_message( 'using cached verification' );
ewwwio()->async_key_verify->dispatch();
return $ewww_cloud_status;
}
$url = 'http://optimize.exactlywww.com/verify/';
$ssl = wp_http_supports( array( 'ssl' ) );
if ( $ssl ) {
$url = set_url_scheme( $url, 'https' );
}
$result = ewww_image_optimizer_cloud_post_key( $url, $api_key );
if ( is_wp_error( $result ) ) {
$url = set_url_scheme( $url, 'http' );
$error_message = $result->get_error_message();
ewwwio_debug_message( "verification failed: $error_message" );
$result = ewww_image_optimizer_cloud_post_key( $url, $api_key );
}
if ( is_wp_error( $result ) ) {
$error_message = $result->get_error_message();
ewwwio_debug_message( "verification failed via $url: $error_message" );
} elseif ( ! empty( $result['body'] ) && preg_match( '/(great|exceeded)/', $result['body'] ) ) {
$verified = $result['body'];
if ( preg_match( '/exceeded/', $verified ) ) {
ewww_image_optimizer_set_option( 'ewww_image_optimizer_cloud_exceeded', time() + 300 );
}
if ( false !== strpos( $result['body'], 'expired' ) ) {
ewww_image_optimizer_set_option( 'ewww_image_optimizer_cloud_key', '' );
}
ewwwio_debug_message( "verification success via: $url" );
delete_option( 'ewww_image_optimizer_cloud_key_invalid' );
} else {
update_option( 'ewww_image_optimizer_cloud_key_invalid', true, false );
if ( ! empty( $result['body'] ) && false !== strpos( $result['body'], 'invalid' ) ) {
ewww_image_optimizer_set_option( 'ewww_image_optimizer_cloud_key', '' );
}
ewwwio_debug_message( "verification failed via: $url" );
if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_debug' ) && ewww_image_optimizer_function_exists( 'print_r' ) ) {
ewwwio_debug_message( print_r( $result, true ) );
}
}
if ( empty( $verified ) ) {
ewwwio_memory( __FUNCTION__ );
return false;
} else {
set_transient( 'ewww_image_optimizer_cloud_status', $verified, HOUR_IN_SECONDS );
ewwwio_debug_message( "verification body contents: {$result['body']}" );
ewwwio_memory( __FUNCTION__ );
return $verified;
}
}
/**
* POSTs the API key to the API for verification.
*
* @param string $url The address of the server to use.
* @param string $key The API key to submit via POST.
* @return array The results of the http POST request.
*/
function ewww_image_optimizer_cloud_post_key( $url, $key ) {
add_filter( 'http_headers_useragent', 'ewww_image_optimizer_cloud_useragent', PHP_INT_MAX );
$result = wp_remote_post(
$url,
array(
'timeout' => 5,
'sslverify' => false,
'body' => array(
'api_key' => $key,
),
)
);
return $result;
}
/**
* Let the user know their key is invalid.
*/
function ewww_image_optimizer_notice_invalid_key() {
echo "" . esc_html__( 'Could not validate EWWW Image Optimizer API key, please check your key to ensure it is correct.', 'ewww-image-optimizer' ) . '
' . esc_html__( 'Optimized', 'ewww-image-optimizer' ) . ' ' . esc_html( $attachment ) . '
';
// Tell the user what the results were for the original image.
$output['results'] .= $results[1] . '
';
// Calculate how much time has elapsed since we started.
$elapsed = microtime( true ) - $started;
// Output how much time has elapsed since we started.
$output['results'] .= sprintf(
esc_html(
/* translators: %s: number of seconds */
_n( 'Elapsed: %s second', 'Elapsed: %s seconds', $elapsed, 'ewww-image-optimizer' )
) . '
' . esc_html__( 'Optimizing', 'ewww-image-optimizer' ) . ' ' . esc_html( $next_file ) . "
"; } die( wp_json_encode( $output ) ); } if ( $cli ) { return $results[1]; } ewww_image_optimizer_debug_log(); ewwwio_memory( __FUNCTION__ ); } /** * Look for the retina version of a file. * * @param string $orig_path Filename of the image. * @param bool $validate_file True verifies the file exists. * @return string The retina/hidpi file, or nothing. */ function ewww_image_optimizer_get_hidpi_path( $orig_path, $validate_file = true ) { $hidpi_suffix = apply_filters( 'ewww_image_optimizer_hidpi_suffix', '@2x' ); $pathinfo = pathinfo( $orig_path ); if ( empty( $pathinfo['dirname'] ) || empty( $pathinfo['filename'] ) || empty( $pathinfo['extension'] ) ) { return ''; } $hidpi_path = $pathinfo['dirname'] . '/' . $pathinfo['filename'] . $hidpi_suffix . '.' . $pathinfo['extension']; if ( $validate_file && ! ewwwio_is_file( $hidpi_path ) ) { return ''; } ewwwio_debug_message( "found retina at $hidpi_path" ); return $hidpi_path; } /** * Looks for a retina version of the original file so that we can optimize that too. * * @global object $ewww_image Contains more information about the image currently being processed. * * @param string $orig_path Filename of the 'normal' image. * @return string The filename of the retina image. */ function ewww_image_optimizer_hidpi_optimize( $orig_path ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); $hidpi_path = ewww_image_optimizer_get_hidpi_path( $orig_path ); if ( ! $hidpi_path ) { return; } global $ewww_image; if ( is_object( $ewww_image ) && $ewww_image instanceof EWWW_Image ) { $id = $ewww_image->attachment_id; $gallery = 'media'; $size = $ewww_image->resize; } else { $id = 0; $gallery = ''; $size = null; } $ewww_image = new EWWW_Image( $id, $gallery, $hidpi_path ); $ewww_image->resize = $size . '-retina'; ewww_image_optimizer( $hidpi_path ); } /** * Checks the existence of a cloud storage stream wrapper. * * @return bool True if a supported stream wrapper is found, false otherwise. */ function ewww_image_optimizer_stream_wrapper_exists() { $wrappers = stream_get_wrappers(); if ( ! ewww_image_optimizer_iterable( $wrappers ) ) { return false; } foreach ( $wrappers as $wrapper ) { if ( strpos( $wrapper, 's3' ) === 0 ) { return true; } if ( strpos( $wrapper, 'gs' ) === 0 ) { return true; } } return false; } /** * Checks the filename for an S3 or GCS stream wrapper. * * @param string $filename The filename to be searched. * @return bool True if a stream wrapper is found, false otherwise. */ function ewww_image_optimizer_stream_wrapped( $filename ) { if ( false !== strpos( $filename, '://' ) ) { if ( strpos( $filename, 's3' ) === 0 ) { return true; } if ( strpos( $filename, 'gs' ) === 0 ) { return true; } } return false; } /** * Pushes images from local storage back to S3 after optimization. * * @param array $meta The attachment metadata. * @param int $id The attachment ID number. * @return array $meta Send the metadata back from whence it came. */ function ewww_image_optimizer_remote_push( $meta, $id ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( ewww_image_optimizer_s3_uploads_enabled() && ! empty( $meta['file'] ) ) { $s3_upload_dir = wp_get_upload_dir(); $s3_upload_dir = trailingslashit( $s3_upload_dir['basedir'] ); $s3_path = get_attached_file( $id ); if ( false === strpos( $s3_path, $s3_upload_dir ) ) { ewwwio_debug_message( "$s3_path not in $s3_upload_dir" ); return $meta; } $upload_path = trailingslashit( WP_CONTENT_DIR ) . 'uploads/'; $filename = realpath( str_replace( $s3_upload_dir, $upload_path, $s3_path ) ); ewwwio_debug_message( "S3 Uploads fullsize path: $s3_path" ); ewwwio_debug_message( "unfiltered fullsize path: $filename" ); if ( 0 === strpos( $s3_path, 's3://' ) && 0 === strpos( $filename, '/' ) && ewwwio_is_file( $filename ) ) { copy( $filename, $s3_path ); unlink( $filename ); if ( ewwwio_is_file( $filename . '.webp' ) ) { copy( $filename . '.webp', $s3_path . '.webp' ); unlink( $filename . '.webp' ); } } // Original image detected. if ( isset( $meta['original_image'] ) && ewww_image_optimizer_get_option( 'ewww_image_optimizer_include_originals' ) ) { // original_image doesn't contain a path, so we calculate one. $base_dir = trailingslashit( dirname( $filename ) ); $base_s3 = trailingslashit( dirname( $s3_path ) ); // Build the paths for an original pre-scaled image. $resize_path = $base_dir . wp_basename( $meta['original_image'] ); $s3_rpath = $base_s3 . wp_basename( $meta['original_image'] ); ewwwio_debug_message( "pushing $resize_path to $s3_rpath" ); if ( 0 === strpos( $s3_rpath, 's3://' ) && 0 === strpos( $resize_path, '/' ) && ewwwio_is_file( $resize_path ) ) { copy( $resize_path, $s3_rpath ); unlink( $resize_path ); if ( ewwwio_is_file( $resize_path . '.webp' ) ) { copy( $resize_path . '.webp', $s3_rpath . '.webp' ); unlink( $resize_path . '.webp' ); } } } // Resized versions, so we'll grab those too. if ( isset( $meta['sizes'] ) && ewww_image_optimizer_iterable( $meta['sizes'] ) ) { $disabled_sizes = ewww_image_optimizer_get_option( 'ewww_image_optimizer_disable_resizes_opt', false, true ); ewwwio_debug_message( 'retrieving resizes' ); // Meta sizes don't contain a path, so we calculate one. $base_dir = trailingslashit( dirname( $filename ) ); $base_s3 = trailingslashit( dirname( $s3_path ) ); foreach ( $meta['sizes'] as $size => $data ) { ewwwio_debug_message( "processing size: $size" ); if ( preg_match( '/webp/', $size ) ) { continue; } if ( ! empty( $disabled_sizes[ $size ] ) ) { continue; } if ( empty( $data['file'] ) ) { continue; } $resize_path = $base_dir . wp_basename( $data['file'] ); $s3_rpath = $base_s3 . wp_basename( $data['file'] ); if ( ! ewwwio_is_file( $resize_path ) ) { ewwwio_debug_message( "$resize_path does not exist" ); continue; } ewwwio_debug_message( "pushing $resize_path to $s3_rpath" ); if ( 0 === strpos( $s3_rpath, 's3://' ) && 0 === strpos( $resize_path, '/' ) ) { copy( $resize_path, $s3_rpath ); unlink( $resize_path ); if ( ewwwio_is_file( $resize_path . '.webp' ) ) { copy( $resize_path . '.webp', $s3_rpath . '.webp' ); unlink( $resize_path . '.webp' ); } } } } // End if(). } // End if(). return $meta; } /** * Fetches images from S3 or Azure storage so that they can be optimized locally. * * @global object $as3cf * * @param int $id The attachment ID number. * @param array $meta The attachment metadata. * @return string|bool The filename of the image fetched, false on failure. */ function ewww_image_optimizer_remote_fetch( $id, $meta ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( ! function_exists( 'download_url' ) ) { require_once ABSPATH . '/wp-admin/includes/file.php'; } $filename = false; if ( ewww_image_optimizer_s3_uploads_enabled() && ! empty( $meta['file'] ) ) { $s3_upload_dir = wp_get_upload_dir(); $s3_upload_dir = trailingslashit( $s3_upload_dir['basedir'] ); $s3_path = get_attached_file( $id ); if ( false === strpos( $s3_path, $s3_upload_dir ) ) { ewwwio_debug_message( "$s3_path not in $s3_upload_dir" ); return false; } $upload_path = trailingslashit( WP_CONTENT_DIR ) . 'uploads/'; $filename = str_replace( $s3_upload_dir, $upload_path, $s3_path ); if ( false === strpos( $filename, WP_CONTENT_DIR ) ) { ewwwio_debug_message( "$filename not in WP_CONTENT_DIR" ); return false; } ewwwio_debug_message( "S3 Uploads fullsize path: $s3_path" ); ewwwio_debug_message( "unfiltered fullsize path: $filename" ); if ( is_dir( $upload_path ) && ! is_writable( $upload_path ) ) { return false; } elseif ( ! is_dir( $upload_path ) && ! is_writable( WP_CONTENT_DIR ) ) { return false; } if ( ! is_dir( dirname( $filename ) ) ) { wp_mkdir_p( dirname( $filename ) ); } if ( 0 === strpos( $s3_path, 's3://' ) && 0 === strpos( $filename, '/' ) && ! ewwwio_is_file( $filename ) ) { copy( $s3_path, $filename ); } // Original image detected. if ( isset( $meta['original_image'] ) && ewww_image_optimizer_get_option( 'ewww_image_optimizer_include_originals' ) ) { ewwwio_debug_message( 'processing original_image' ); // original_image doesn't contain a path, so we calculate one. $base_dir = trailingslashit( dirname( $filename ) ); $base_s3 = trailingslashit( dirname( $s3_path ) ); // Build the paths for an original pre-scaled image. $resize_path = $base_dir . wp_basename( $meta['original_image'] ); $s3_rpath = $base_s3 . wp_basename( $meta['original_image'] ); ewwwio_debug_message( "fetching $s3_rpath to $resize_path" ); if ( 0 === strpos( $s3_rpath, 's3://' ) && 0 === strpos( $resize_path, '/' ) ) { copy( $s3_rpath, $resize_path ); } } // Resized versions, so we'll grab those too. if ( isset( $meta['sizes'] ) && ewww_image_optimizer_iterable( $meta['sizes'] ) ) { $disabled_sizes = ewww_image_optimizer_get_option( 'ewww_image_optimizer_disable_resizes_opt', false, true ); ewwwio_debug_message( 'retrieving resizes' ); // Meta sizes don't contain a path, so we calculate one. $base_dir = trailingslashit( dirname( $filename ) ); $base_s3 = trailingslashit( dirname( $s3_path ) ); foreach ( $meta['sizes'] as $size => $data ) { ewwwio_debug_message( "processing size: $size" ); if ( preg_match( '/webp/', $size ) ) { continue; } if ( ! empty( $disabled_sizes[ $size ] ) ) { continue; } if ( empty( $data['file'] ) ) { continue; } $resize_path = $base_dir . wp_basename( $data['file'] ); $s3_rpath = $base_s3 . wp_basename( $data['file'] ); if ( ewwwio_is_file( $resize_path ) ) { ewwwio_debug_message( "$resize_path already exists" ); continue; } ewwwio_debug_message( "fetching $s3_rpath to $resize_path" ); if ( 0 === strpos( $s3_rpath, 's3://' ) && 0 === strpos( $resize_path, '/' ) ) { copy( $s3_rpath, $resize_path ); } } } // End if(). } // End if(). if ( class_exists( 'wpCloud\StatelessMedia\EWWW' ) && ! empty( $meta['gs_link'] ) ) { $full_url = $meta['gs_link']; $filename = get_attached_file( $id, true ); ewwwio_debug_message( "GSC (stateless) fullsize url: $full_url" ); ewwwio_debug_message( "unfiltered fullsize path: $filename" ); $temp_file = download_url( $full_url ); if ( ! is_wp_error( $temp_file ) ) { if ( ! is_dir( dirname( $filename ) ) ) { wp_mkdir_p( dirname( $filename ) ); } if ( ! ewwwio_is_file( $filename ) ) { ewwwio_rename( $temp_file, $filename ); } else { unlink( $temp_file ); } } elseif ( is_wp_error( $temp_file ) ) { ewwwio_debug_message( 'could not download: ' . $temp_file->get_error_message() ); } // Resized versions, so we'll grab those too. if ( isset( $meta['sizes'] ) && ewww_image_optimizer_iterable( $meta['sizes'] ) ) { $disabled_sizes = ewww_image_optimizer_get_option( 'ewww_image_optimizer_disable_resizes_opt', false, true ); ewwwio_debug_message( 'retrieving resizes' ); // Meta sizes don't contain a path, so we calculate one. $base_dir = trailingslashit( dirname( $filename ) ); $processed = array(); foreach ( $meta['sizes'] as $size => $data ) { ewwwio_debug_message( "processing size: $size" ); if ( preg_match( '/webp/', $size ) ) { continue; } if ( ! empty( $disabled_sizes[ $size ] ) ) { continue; } if ( empty( $data['file'] ) ) { continue; } $dup_size = false; // Check through all the sizes we've processed so far. foreach ( $processed as $proc => $scan ) { // If a previous resize had identical dimensions. if ( $scan['height'] === $data['height'] && $scan['width'] === $data['width'] ) { // Found a duplicate resize. $dup_size = true; } } // If this is a unique size. if ( ! $dup_size ) { $resize_path = $base_dir . wp_basename( $data['file'] ); $resize_url = $data['gs_link']; if ( ewwwio_is_file( $resize_path ) ) { continue; } ewwwio_debug_message( "fetching $resize_url to $resize_path" ); $temp_file = download_url( $resize_url ); if ( ! is_wp_error( $temp_file ) ) { if ( ! is_dir( dirname( $resize_path ) ) ) { wp_mkdir_p( dirname( $resize_path ) ); } ewwwio_rename( $temp_file, $resize_path ); } } // Store info on the sizes we've processed, so we can check the list for duplicate sizes. $processed[ $size ]['width'] = $data['width']; $processed[ $size ]['height'] = $data['height']; } } // End if(). } // End if(). if ( function_exists( 'as3cf_get_attachment_url' ) ) { global $as3cf; $full_url = get_attached_file( $id ); if ( ewww_image_optimizer_stream_wrapped( $full_url ) ) { $full_url = as3cf_get_attachment_url( $id ); } $filename = get_attached_file( $id, true ); ewwwio_debug_message( "amazon s3 fullsize url: $full_url" ); ewwwio_debug_message( "unfiltered fullsize path: $filename" ); $temp_file = download_url( $full_url ); if ( ! is_wp_error( $temp_file ) ) { ewwwio_debug_message( "downloaded to $temp_file" ); if ( ! is_dir( dirname( $filename ) ) ) { wp_mkdir_p( dirname( $filename ) ); } if ( ! ewwwio_is_file( $filename ) && is_writable( dirname( $filename ) ) ) { ewwwio_debug_message( "renaming $temp_file to $filename" ); ewwwio_rename( $temp_file, $filename ); } elseif ( ! is_writable( dirname( $filename ) ) ) { ewwwio_debug_message( 'destination dir not writable' ); } else { ewwwio_debug_message( 'file already found, nuking temp file' ); unlink( $temp_file ); } if ( ! ewwwio_is_file( $filename ) ) { ewwwio_debug_message( 'download failed' ); } } elseif ( is_wp_error( $temp_file ) ) { ewwwio_debug_message( 'could not download: ' . $temp_file->get_error_message() ); } $base_dir = trailingslashit( dirname( $filename ) ); // Original image detected. if ( isset( $meta['original_image'] ) && ewww_image_optimizer_get_option( 'ewww_image_optimizer_include_originals' ) ) { ewwwio_debug_message( 'processing original_image' ); $base_url = trailingslashit( dirname( $full_url ) ); // Build the paths for an original pre-scaled image. $resize_path = $base_dir . wp_basename( $meta['original_image'] ); $resize_url = $base_url . wp_basename( $meta['original_image'] ); if ( ! ewwwio_is_file( $resize_path ) ) { ewwwio_debug_message( "fetching $resize_url to $resize_path" ); $temp_file = download_url( $resize_url ); if ( ! is_wp_error( $temp_file ) ) { if ( ! is_dir( $base_dir ) ) { wp_mkdir_p( $base_dir ); } ewwwio_rename( $temp_file, $resize_path ); } elseif ( is_wp_error( $temp_file ) ) { ewwwio_debug_message( 'could not download: ' . $temp_file->get_error_message() ); } } } // Resized versions, so we'll grab those too. if ( isset( $meta['sizes'] ) && ewww_image_optimizer_iterable( $meta['sizes'] ) ) { $disabled_sizes = ewww_image_optimizer_get_option( 'ewww_image_optimizer_disable_resizes_opt', false, true ); ewwwio_debug_message( 'retrieving resizes' ); // Meta sizes don't contain a path, so we calculate one. $processed = array(); foreach ( $meta['sizes'] as $size => $data ) { ewwwio_debug_message( "processing size: $size" ); if ( preg_match( '/webp/', $size ) ) { continue; } if ( ! empty( $disabled_sizes[ $size ] ) ) { continue; } if ( empty( $data['file'] ) ) { continue; } $dup_size = false; // Check through all the sizes we've processed so far. foreach ( $processed as $proc => $scan ) { // If a previous resize had identical dimensions. if ( $scan['height'] === $data['height'] && $scan['width'] === $data['width'] ) { // Found a duplicate resize. $dup_size = true; } } // If this is a unique size. if ( ! $dup_size ) { $resize_path = $base_dir . wp_basename( $data['file'] ); $resize_url = as3cf_get_attachment_url( $id, $size ); if ( ewwwio_is_file( $resize_path ) ) { continue; } ewwwio_debug_message( "fetching $resize_url to $resize_path" ); $temp_file = download_url( $resize_url ); if ( ! is_wp_error( $temp_file ) ) { if ( ! is_dir( dirname( $resize_path ) ) ) { wp_mkdir_p( dirname( $resize_path ) ); } ewwwio_rename( $temp_file, $resize_path ); } } // Store info on the sizes we've processed, so we can check the list for duplicate sizes. $processed[ $size ]['width'] = $data['width']; $processed[ $size ]['height'] = $data['height']; } } // End if(). } // End if(). if ( class_exists( 'WindowsAzureStorageUtil' ) && get_option( 'azure_storage_use_for_default_upload' ) ) { $full_url = $meta['url']; $filename = $meta['file']; $filename = get_attached_file( $id, true ); ewwwio_debug_message( "azure fullsize url: $full_url" ); ewwwio_debug_message( "fullsize path: $filename" ); $temp_file = download_url( $full_url ); if ( ! is_wp_error( $temp_file ) ) { if ( ! is_dir( dirname( $filename ) ) ) { wp_mkdir_p( dirname( $filename ) ); } if ( ! ewwwio_is_file( $filename ) ) { ewwwio_rename( $temp_file, $filename ); } else { unlink( $temp_file ); } } $base_dir = trailingslashit( dirname( $filename ) ); $base_url = trailingslashit( dirname( $full_url ) ); // Original image detected. if ( isset( $meta['original_image'] ) && ewww_image_optimizer_get_option( 'ewww_image_optimizer_include_originals' ) ) { ewwwio_debug_message( 'processing original_image' ); // Build the paths for an original pre-scaled image. $resize_path = $base_dir . wp_basename( $meta['original_image'] ); $resize_url = $base_url . wp_basename( $meta['original_image'] ); if ( ! ewwwio_is_file( $resize_path ) ) { ewwwio_debug_message( "fetching $resize_url to $resize_path" ); $temp_file = download_url( $resize_url ); if ( ! is_wp_error( $temp_file ) ) { if ( ! is_dir( $base_dir ) ) { wp_mkdir_p( $base_dir ); } ewwwio_rename( $temp_file, $resize_path ); } } } // Resized versions, so we'll grab those too. if ( isset( $meta['sizes'] ) && ewww_image_optimizer_iterable( $meta['sizes'] ) ) { $disabled_sizes = ewww_image_optimizer_get_option( 'ewww_image_optimizer_disable_resizes_opt', false, true ); ewwwio_debug_message( 'retrieving resizes' ); // Process each resized version. $processed = array(); foreach ( $meta['sizes'] as $size => $data ) { ewwwio_debug_message( "processing size: $size" ); if ( preg_match( '/webp/', $size ) ) { continue; } if ( ! empty( $disabled_sizes[ $size ] ) ) { continue; } if ( empty( $data['file'] ) ) { continue; } $dup_size = false; // Check through all the sizes we've processed so far. foreach ( $processed as $proc => $scan ) { // If a previous resize had identical dimensions. if ( $scan['height'] === $data['height'] && $scan['width'] === $data['width'] ) { // Found a duplicate resize. $dup_size = true; } } // If this is a unique size. if ( ! $dup_size ) { $resize_path = $base_dir . wp_basename( $data['file'] ); $resize_url = $base_url . wp_basename( $data['file'] ); if ( ewwwio_is_file( $resize_path ) ) { continue; } ewwwio_debug_message( "fetching $resize_url to $resize_path" ); $temp_file = download_url( $resize_url ); if ( ! is_wp_error( $temp_file ) ) { if ( ! is_dir( dirname( $resize_path ) ) ) { wp_mkdir_p( dirname( $resize_path ) ); } ewwwio_rename( $temp_file, $resize_path ); } } // Store info on the sizes we've processed, so we can check the list for duplicate sizes. $processed[ $size ]['width'] = $data['width']; $processed[ $size ]['height'] = $data['height']; } } // End if(). } // End if(). clearstatcache(); if ( ! empty( $filename ) && ewwwio_is_file( $filename ) ) { ewwwio_debug_message( "$filename found, success!" ); return $filename; } elseif ( ! empty( $filename ) ) { ewwwio_debug_message( "$filename not found, boo..." ); } return false; } /** * Searches the database for a matching s3 path, and fixes it to use the local path. * * @global object $wpdb * * @param array $meta The attachment metadata. * @param int $id The attachment ID number. * @param string $s3_path The potential s3:// path. */ function ewww_image_optimizer_check_table_as3cf( $meta, $id, $s3_path ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); $local_path = get_attached_file( $id, true ); ewwwio_debug_message( "unfiltered local path: $local_path" ); if ( $local_path !== $s3_path ) { ewww_image_optimizer_update_table_as3cf( $local_path, $s3_path ); } if ( isset( $meta['sizes'] ) && ewww_image_optimizer_iterable( $meta['sizes'] ) ) { ewwwio_debug_message( 'updating s3 resizes' ); // Meta sizes don't contain a path, so we calculate one. $local_dir = trailingslashit( dirname( $local_path ) ); $s3_dir = trailingslashit( dirname( $s3_path ) ); $processed = array(); foreach ( $meta['sizes'] as $size => $data ) { if ( strpos( $size, 'webp' ) === 0 ) { continue; } // Check through all the sizes we've processed so far. foreach ( $processed as $proc => $scan ) { // If a previous resize had identical dimensions. if ( $scan['height'] === $data['height'] && $scan['width'] === $data['width'] ) { // Found a duplicate resize. continue; } } // If this is a unique size. $local_resize_path = $local_dir . $data['file']; $s3_resize_path = $s3_dir . $data['file']; if ( $local_resize_path !== $s3_resize_path ) { ewww_image_optimizer_update_table_as3cf( $local_resize_path, $s3_resize_path ); } // Store info on the sizes we've processed, so we can check the list for duplicate sizes. $processed[ $size ]['width'] = $data['width']; $processed[ $size ]['height'] = $data['height']; } } global $wpdb; $wpdb->flush(); } /** * Given an S3 path, replaces it with the local path. * * @global object $wpdb * @global object $ewwwdb A clone of $wpdb unless it is lacking utf8 connectivity. * * @param string $local_path The local filesystem path to the image. * @param string $s3_path The remote S3 path to the image. */ function ewww_image_optimizer_update_table_as3cf( $local_path, $s3_path ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); // First we need to see if anything matches the s3 path. $s3_image = ewww_image_optimizer_find_already_optimized( $s3_path ); ewwwio_debug_message( "looking for $s3_path" ); if ( is_array( $s3_image ) ) { global $wpdb; if ( strpos( $wpdb->charset, 'utf8' ) === false ) { ewww_image_optimizer_db_init(); global $ewwwdb; } else { $ewwwdb = $wpdb; } ewwwio_debug_message( "found $s3_path in db" ); // When we find a match by the s3 path, we need to find out if there are already records for the local path. $found_local_image = ewww_image_optimizer_find_already_optimized( $local_path ); ewwwio_debug_message( "looking for $local_path" ); // If we found records for both local and s3 paths, we delete the s3 record, but store the original size in the local record. if ( ! empty( $found_local_image ) && is_array( $found_local_image ) ) { ewwwio_debug_message( "found $local_path in db" ); $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'id' => $s3_image['id'], ), array( '%d', ) ); if ( $s3_image['orig_size'] > $found_local_image['orig_size'] ) { $ewwwdb->update( $ewwwdb->ewwwio_images, array( 'orig_size' => $s3_image['orig_size'], 'results' => $s3_image['results'], ), array( 'id' => $found_local_image['id'], ) ); } } else { // If we just found an s3 path and no local match, then we just update the path in the table to the local path. ewwwio_debug_message( 'just updating s3 to local' ); $ewwwdb->update( $ewwwdb->ewwwio_images, array( 'path' => ewww_image_optimizer_relativize_path( $local_path ), ), array( 'id' => $s3_image['id'], ) ); } } // End if(). } /** * Raise the memory limit even higher (to 512M) than WP default of 256M if necessary. * * @param int|string $memory_limit The amount of memory to allocate. * @return int|string The new amount of memory to allocate, if it was only 256M or lower. */ function ewww_image_optimizer_raise_memory_limit( $memory_limit ) { if ( '256M' === $memory_limit || ( is_int( $memory_limit ) && 270000000 > $memory_limit ) ) { ewwwio_debug_message( 'raising the roof' ); return '512M'; } else { return $memory_limit; } } /** * Uses gifsicle or the API to resize an image. * * @since 4.4.0 * * @param string $file The file to resize. * @param int $dst_x X-coordinate of destination image (usually 0). * @param int $dst_y Y-coordinate of destination image (usually 0). * @param int $src_x X-coordinate of source image (usually 0 unless cropping). * @param int $src_y Y-coordinate of source image (usually 0 unless cropping). * @param int $dst_w Desired image width. * @param int $dst_h Desired image height. * @param int $src_w Source width. * @param int $src_h Source height. * @return string|WP_Error The image contents or the error message. */ function ewww_image_optimizer_better_resize( $file, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); ewwwio_debug_message( "resizing to $dst_w and $dst_h" ); if ( $dst_x || $dst_y ) { ewwwio_debug_message( 'cropping too' ); $crop = true; } $type = ewww_image_optimizer_mimetype( $file, 'i' ); if ( false === strpos( $type, 'image' ) ) { ewwwio_debug_message( 'not an image, no resizing possible' ); return new WP_Error( 'invalid_image', __( 'File is not an image.' ), $file ); } if ( 'image/gif' === $type && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' ) && function_exists( 'ewww_image_optimizer_gifsicle_resize' ) ) { return ewww_image_optimizer_gifsicle_resize( $file, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ); } return ewww_image_optimizer_cloud_resize( $file, $type, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ); } /** * If a JPG image is using the EXIF orientiation, correct the rotation, and reset the Orientation. * * @param string $file The file to check for rotation. */ function ewww_image_optimizer_autorotate( $file ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( defined( 'EWWW_IMAGE_OPTIMIZER_DISABLE_AUTOROTATE' ) && EWWW_IMAGE_OPTIMIZER_DISABLE_AUTOROTATE ) { return; } if ( function_exists( 'wp_raise_memory_limit' ) ) { wp_raise_memory_limit( 'image' ); } $type = ewww_image_optimizer_mimetype( $file, 'i' ); if ( 'image/jpeg' !== $type ) { ewwwio_debug_message( 'not a JPG, no rotation needed' ); return; } $orientation = (int) ewww_image_optimizer_get_orientation( $file, $type ); if ( ! $orientation || 1 === $orientation ) { ewwwio_debug_message( 'no rotation needed' ); return; } ewwwio_debug_message( "current orientation: $orientation" ); if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_jpg_level' ) < 20 && function_exists( 'ewww_image_optimizer_jpegtran_autorotate' ) ) { // Read the exif, if it fails, we won't autorotate. try { $jpeg = new PelJpeg( $file ); $exif = $jpeg->getExif(); } catch ( PelDataWindowOffsetException $pelerror ) { ewwwio_debug_message( 'pel exception: ' . $pelerror->getMessage() ); $exif = null; } catch ( PelDataWindowOffsetException $pelerror ) { ewwwio_debug_message( 'pel exception: ' . $pelerror->getMessage() ); $exif = null; } catch ( PelException $pelerror ) { ewwwio_debug_message( 'pel exception: ' . $pelerror->getMessage() ); $exif = null; } catch ( Exception $pelerror ) { ewwwio_debug_message( 'pel exception: ' . $pelerror->getMessage() ); $exif = null; } if ( is_null( $exif ) ) { ewwwio_debug_message( 'could not work with PelJpeg object, no rotation happening here' ); } elseif ( ewww_image_optimizer_jpegtran_autorotate( $file, $type, $orientation ) ) { // Use PEL to correct the orientation flag when metadata was preserved. $jpeg = new PelJpeg( $file ); $exif = $jpeg->getExif(); if ( ! is_null( $exif ) ) { $tiff = $exif->getTiff(); $ifd0 = $tiff->getIfd(); $orientation = $ifd0->getEntry( PelTag::ORIENTATION ); if ( ! is_null( $orientation ) ) { ewwwio_debug_message( 'orientation being adjusted' ); $orientation->setValue( 1 ); } $jpeg->saveFile( $file ); } } return; } ewww_image_optimizer_cloud_autorotate( $file, $type ); } /** * If a PNG image is over the threshold, see if we can make it smaller as a JPG. * * @param string $file The file to check for conversion. */ function ewww_image_optimizer_autoconvert( $file ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( defined( 'EWWW_IMAGE_OPTIMIZER_DISABLE_AUTOCONVERT' ) && EWWW_IMAGE_OPTIMIZER_DISABLE_AUTOCONVERT ) { return; } if ( function_exists( 'wp_raise_memory_limit' ) ) { wp_raise_memory_limit( 'image' ); } $type = ewww_image_optimizer_mimetype( $file, 'i' ); if ( 'image/png' !== $type && 'image/gif' !== $type ) { ewwwio_debug_message( 'not a PNG or GIF, no conversion needed' ); return; } $orig_size = ewww_image_optimizer_filesize( $file ); if ( 'image/png' === $type && $orig_size < apply_filters( 'ewww_image_optimizer_autoconvert_threshold', 250000 ) ) { ewwwio_debug_message( 'not a large PNG (size or dimensions), skipping' ); return; } if ( 'image/png' === $type && ewww_image_optimizer_png_alpha( $file ) && ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_png_to_jpg' ) || ! ewww_image_optimizer_jpg_background() ) ) { ewwwio_debug_message( 'alpha detected, skipping' ); return; } if ( 'image/gif' === $type && ewww_image_optimizer_is_animated( $file ) ) { ewwwio_debug_message( 'animation detected, skipping' ); return; } if ( 'image/png' === $type ) { $newfile = ewww_image_optimizer_unique_filename( $file, '.jpg' ); } elseif ( 'image/gif' === $type ) { $newfile = ewww_image_optimizer_unique_filename( $file, '.png' ); } $ewww_image = new EWWW_Image( 0, '', $file ); // Pass the filename, false for db search/replace, and true for filesize comparison. return $ewww_image->convert( $file, false, true, $newfile ); } /** * Skips resizing for any image with 'noresize' in the filename. * * @param array $dimensions The configured dimensions for resizing. * @param string $filename The filename of the uploaded image. * @return array The new dimensions for resizing. */ function ewww_image_optimizer_noresize( $dimensions, $filename ) { if ( strpos( $filename, 'noresize' ) !== false ) { add_filter( 'big_image_size_threshold', '__return_false' ); return array( 0, 0 ); } $ignore_folders = ewww_image_optimizer_get_option( 'ewww_image_optimizer_exclude_paths' ); if ( ! ewww_image_optimizer_iterable( $ignore_folders ) ) { return $dimensions; } foreach ( $ignore_folders as $ignore_folder ) { if ( strpos( $filename, $ignore_folder ) !== false ) { return array( 0, 0 ); } } return $dimensions; } /** * Check non-Media Library filenames to see if the image is eligible for resizing. * * This function specifically checks to be sure the filename does not preclude an image. * It does not check the dimensions, that is done by ewww_image_optimizer_should_resize(). * * @param string $file The image filename. * @return bool True to allow resizing, false otherwise. */ function ewww_image_optimizer_should_resize_other_image( $file ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_resize_other_existing' ) ) { return false; } $extensions = array( 'gif', 'jpg', 'jpeg', 'jpe', 'png', ); if ( preg_match( '#-(\d+)x(\d+)(@2x)?\.(?:' . implode( '|', $extensions ) . ')$#i', $file ) ) { return false; } if ( strpos( $file, '/wp-includes/' ) ) { return false; } if ( strpos( $file, '/wp-admin/' ) ) { return false; } if ( false !== strpos( $file, get_theme_root() ) ) { return false; } if ( false !== strpos( $file, WP_PLUGIN_DIR ) ) { return false; } ewwwio_debug_message( "allowing resize for $file" ); return true; } /** * Resizes Media Library uploads based on the maximum dimensions specified by the user. * * @global object $wpdb * @global object $ewwwdb A clone of $wpdb unless it is lacking utf8 connectivity. * * @param string $file The file to check for rotation. * @return array|bool The new height and width, or false if no resizing was done. */ function ewww_image_optimizer_resize_upload( $file ) { // Parts adapted from Imsanity (THANKS Jason!). ewwwio_debug_message( '' . __FUNCTION__ . '()' ); global $ewww_webp_only; global $ewwwio_resize_status; $ewwwio_resize_status = ''; if ( ! $file ) { return false; } if ( ! empty( $ewww_webp_only ) ) { return false; } if ( function_exists( 'wp_raise_memory_limit' ) ) { wp_raise_memory_limit( 'image' ); } if ( ! empty( $_REQUEST['post_id'] ) || // phpcs:ignore WordPress.Security.NonceVerification ( ! empty( $_REQUEST['action'] ) && 'upload-attachment' === $_REQUEST['action'] ) || // phpcs:ignore WordPress.Security.NonceVerification strpos( wp_get_referer(), 'media-new.php' ) ) { ewwwio_debug_message( 'resizing image from media library or attached to post' ); $maxwidth = ewww_image_optimizer_get_option( 'ewww_image_optimizer_maxmediawidth' ); $maxheight = ewww_image_optimizer_get_option( 'ewww_image_optimizer_maxmediaheight' ); } elseif ( strpos( wp_get_referer(), '/post.php' ) ) { ewwwio_debug_message( 'resizing image from the post/page editor' ); $maxwidth = ewww_image_optimizer_get_option( 'ewww_image_optimizer_maxmediawidth' ); $maxheight = ewww_image_optimizer_get_option( 'ewww_image_optimizer_maxmediaheight' ); } else { ewwwio_debug_message( 'resizing images from somewhere else' ); $maxwidth = ewww_image_optimizer_get_option( 'ewww_image_optimizer_maxotherwidth' ); $maxheight = ewww_image_optimizer_get_option( 'ewww_image_optimizer_maxotherheight' ); if ( ! $maxwidth && ! $maxheight ) { ewwwio_debug_message( 'other dimensions not set, overriding with media dimensions' ); $maxwidth = ewww_image_optimizer_get_option( 'ewww_image_optimizer_maxmediawidth' ); $maxheight = ewww_image_optimizer_get_option( 'ewww_image_optimizer_maxmediaheight' ); } } if ( wp_get_referer() ) { ewwwio_debug_message( 'uploaded from: ' . wp_get_referer() ); } /** * Filters the dimensions to used for resizing uploaded images. * * @param array $args { * The dimensions to be used in resizing. * * @type int $maxwidth The maximum width of the image. * @type int $maxheight The maximum height of the image. * } * @param string $file The name of the file being resized. */ list( $maxwidth, $maxheight ) = apply_filters( 'ewww_image_optimizer_resize_dimensions', array( $maxwidth, $maxheight ), $file ); $maxwidth = (int) $maxwidth; $maxheight = (int) $maxheight; // Check that options are not both set to zero. if ( 0 === $maxwidth && 0 === $maxheight ) { return false; } $maxwidth = $maxwidth ? $maxwidth : 999999; $maxheight = $maxheight ? $maxheight : 999999; if ( ! ewwwio_is_file( $file ) ) { return false; } // Check the file type. $type = ewww_image_optimizer_mimetype( $file, 'i' ); if ( strpos( $type, 'image' ) === false ) { ewwwio_debug_message( 'not an image, cannot resize' ); return false; } // Check file size (dimensions). list( $oldwidth, $oldheight ) = wp_getimagesize( $file ); if ( $oldwidth <= $maxwidth && $oldheight <= $maxheight ) { ewwwio_debug_message( 'image too small for resizing' ); /* translators: 1: width in pixels 2: height in pixels */ $ewwwio_resize_status = sprintf( __( 'Resize not required, image smaller than %1$s x %2$s', 'ewww-image-optimizer' ), $maxwidth . 'w', $maxheight . 'h' ); if ( $oldwidth && $oldheight ) { return array( $oldwidth, $oldheight ); } return false; } $crop = false; if ( $oldwidth >= $maxwidth && $maxwidth && $oldheight >= $maxheight && $maxheight && apply_filters( 'ewww_image_optimizer_crop_image', false ) ) { $crop = true; $newwidth = $maxwidth; $newheight = $maxheight; } else { list( $newwidth, $newheight ) = wp_constrain_dimensions( $oldwidth, $oldheight, $maxwidth, $maxheight ); } if ( ! ewwwio_check_memory_available( ( $oldwidth * $oldheight + $newwidth * $newheight ) * 4.8 ) ) { // 4.8 = 24-bit or 3 bytes per pixel multiplied by a factor of 1.6 for extra wiggle room. $memory_required = ( $oldwidth * $oldheight + $newwidth * $newheight ) * 4.8; ewwwio_debug_message( "possibly insufficient memory for resizing operation: $memory_required" ); if ( function_exists( 'wp_raise_memory_limit' ) ) { add_filter( 'image_memory_limit', 'ewww_image_optimizer_raise_memory_limit' ); wp_raise_memory_limit( 'image' ); } } if ( ! function_exists( 'wp_get_image_editor' ) ) { ewwwio_debug_message( 'no image editor function' ); $ewwwio_resize_status = __( 'wp_get_image_editor function is missing', 'ewww-image-optimizer' ); return false; } // From here... global $ewww_preempt_editor; $ewww_preempt_editor = true; $editor = wp_get_image_editor( $file ); if ( is_wp_error( $editor ) ) { $error_message = $editor->get_error_message(); ewwwio_debug_message( "could not get image editor: $error_message" ); /* translators: %s: a WP error message, translated elsewhere */ $ewwwio_resize_status = sprintf( __( 'Unable to load resize function: %s', 'ewww-image-optimizer' ), $error_message ); return false; } // Rotation only happens on existing media here, so we need to swap dimension when we rotate by 90. $orientation = ewww_image_optimizer_get_orientation( $file, $type ); $rotated = false; switch ( $orientation ) { case 3: $editor->rotate( 180 ); $rotated = true; break; case 6: $editor->rotate( -90 ); $new_newwidth = $newwidth; $newwidth = $newheight; $newheight = $new_newwidth; $rotated = true; break; case 8: $editor->rotate( 90 ); $new_newwidth = $newwidth; $newwidth = $newheight; $newheight = $new_newwidth; $rotated = true; break; } $resized_image = $editor->resize( $newwidth, $newheight, $crop ); if ( is_wp_error( $resized_image ) ) { $error_message = $resized_image->get_error_message(); ewwwio_debug_message( "error during resizing: $error_message" ); /* translators: %s: a WP error message, translated elsewhere */ $ewwwio_resize_status = sprintf( __( 'Resizing error: %s', 'ewww-image-optimizer' ), $error_message ); return false; } $new_file = $editor->generate_filename( 'tmp' ); $orig_size = filesize( $file ); ewwwio_debug_message( "before resizing: $orig_size" ); $saved = $editor->save( $new_file ); if ( is_wp_error( $saved ) ) { $error_message = $saved->get_error_message(); ewwwio_debug_message( "error saving resized image: $error_message" ); /* translators: %s: a WP error message, translated elsewhere */ $ewwwio_resize_status = sprintf( __( 'Could not save resized image: %s', 'ewww-image-optimizer' ), $error_message ); } if ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_noauto' ) && ( ! defined( 'EWWW_IMAGE_OPTIMIZER_DISABLE_EDITOR' ) || ! EWWW_IMAGE_OPTIMIZER_DISABLE_EDITOR ) ) { $ewww_preempt_editor = false; } // to here is replaced by cloud/API function. $new_size = ewww_image_optimizer_filesize( $new_file ); if ( ( $new_size && (int) $new_size !== (int) $orig_size && apply_filters( 'ewww_image_optimizer_resize_filesize_ignore', false ) ) || ( $new_size && $new_size < $orig_size ) ) { // Use this action to perform any operations on the original file before it is overwritten with the new, smaller file. do_action( 'ewww_image_optimizer_image_resized', $file, $new_file ); ewwwio_debug_message( "after resizing: $new_size" ); // Use PEL to get the exif (if Remove Meta is unchecked) and GD is in use, so we can save it to the new image. if ( 'image/jpeg' === $type && ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_metadata_skip_full' ) || ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_metadata_remove' ) ) && ! ewwwio()->imagick_support() ) { ewwwio_debug_message( 'manually copying metadata for GD' ); try { $old_jpeg = new PelJpeg( $file ); $old_exif = $old_jpeg->getExif(); $new_jpeg = new PelJpeg( $new_file ); } catch ( PelDataWindowOffsetException $pelerror ) { ewwwio_debug_message( 'pel exception: ' . $pelerror->getMessage() ); $old_exif = null; } catch ( PelDataWindowOffsetException $pelerror ) { ewwwio_debug_message( 'pel exception: ' . $pelerror->getMessage() ); $old_exif = null; } catch ( PelException $pelerror ) { ewwwio_debug_message( 'pel exception: ' . $pelerror->getMessage() ); $old_exif = null; } catch ( Exception $pelerror ) { ewwwio_debug_message( 'pel exception: ' . $pelerror->getMessage() ); $old_exif = null; } if ( ! is_null( $old_exif ) ) { if ( $rotated ) { $tiff = $old_exif->getTiff(); $ifd0 = $tiff->getIfd(); $orientation = $ifd0->getEntry( PelTag::ORIENTATION ); if ( ! is_null( $orientation ) ) { $orientation->setValue( 1 ); } } $new_jpeg->setExif( $old_exif ); } if ( ! is_null( $new_jpeg ) ) { $new_jpeg->saveFile( $new_file ); } } // Backup the file before we replace the original. global $eio_backup; if ( ! apply_filters( 'ewww_image_optimizer_backup_post_resize', false ) ) { $eio_backup->backup_file( $file ); } // ewww_image_optimizer_cloud_backup( $file );. $new_type = (string) ewww_image_optimizer_mimetype( $new_file, 'i' ); if ( $type === $new_type ) { ewwwio_rename( $new_file, $file ); } else { ewwwio_debug_message( "resizing did not create a valid image: $new_type" ); /* translators: %s: the mime type of the new file */ $ewwwio_resize_status = sprintf( __( 'Resizing resulted in an invalid file type: %s', 'ewww-image-optimizer' ), $new_type ); unlink( $new_file ); return false; } // Store info on the current image for future reference. global $wpdb; if ( strpos( $wpdb->charset, 'utf8' ) === false ) { ewww_image_optimizer_db_init(); global $ewwwdb; } else { $ewwwdb = $wpdb; } // Delete the record created from optimizing the resized file (if it exists, which it shouldn't). $temp_optimized = ewww_image_optimizer_find_already_optimized( $new_file ); if ( is_array( $temp_optimized ) && ! empty( $temp_optimized['id'] ) ) { $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'id' => $temp_optimized['id'], ), array( '%d', ) ); } /* translators: 1: width in pixels 2: height in pixels */ $ewwwio_resize_status = sprintf( __( 'Resized to %1$s x %2$s', 'ewww-image-optimizer' ), $newwidth . 'w', $newheight . 'h' ); return array( $newwidth, $newheight ); } // End if(). if ( ewwwio_is_file( $new_file ) ) { ewwwio_debug_message( "resizing did not create a smaller image: $new_size" ); $ewwwio_resize_status = __( 'Resizing did not reduce the file size, result discarded', 'ewww-image-optimizer' ); unlink( $new_file ); } return false; } /** * Gets the orientation/rotation of a JPG image using the EXIF data. * * @param string $file Name of the file. * @param string $type Mime type of the file. * @return int|bool The orientation value or false. */ function ewww_image_optimizer_get_orientation( $file, $type ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( function_exists( 'exif_read_data' ) && 'image/jpeg' === $type && ewwwio_is_readable( $file ) ) { $exif = @exif_read_data( $file ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged if ( is_array( $exif ) && array_key_exists( 'Orientation', $exif ) ) { return $exif['Orientation']; } } return false; } /** * Searches the images table for a file. * * If more than one record is found, verifies case and calls duplicate removal if needed. * * @global object $wpdb * @global object $ewwwdb A clone of $wpdb unless it is lacking utf8 connectivity. * * @param string $attachment The name of the file. * @return array|bool If found, information about the image, false otherwise. */ function ewww_image_optimizer_find_already_optimized( $attachment ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); global $wpdb; if ( strpos( $wpdb->charset, 'utf8' ) === false ) { ewww_image_optimizer_db_init(); global $ewwwdb; } else { $ewwwdb = $wpdb; } $maybe_return_image = false; $maybe_relative_path = ewww_image_optimizer_relativize_path( $attachment ); $query = $ewwwdb->prepare( "SELECT * FROM $ewwwdb->ewwwio_images WHERE path = %s", $maybe_relative_path ); $optimized_query = $ewwwdb->get_results( $query, ARRAY_A ); if ( empty( $optimized_query ) && $attachment !== $maybe_relative_path ) { $query = $ewwwdb->prepare( "SELECT * FROM $ewwwdb->ewwwio_images WHERE path = %s", $attachment ); $optimized_query = $ewwwdb->get_results( $query, ARRAY_A ); } if ( ewww_image_optimizer_iterable( $optimized_query ) ) { foreach ( $optimized_query as $image ) { $image['path'] = ewww_image_optimizer_absolutize_path( $image['path'] ); $image['image_size'] = (int) $image['image_size']; $image['orig_size'] = (int) $image['orig_size']; $image['attachment_id'] = (int) $image['attachment_id']; $image['level'] = (int) $image['level']; if ( $image['path'] !== $attachment ) { ewwwio_debug_message( "{$image['path']} does not match $attachment, continuing our search" ); } elseif ( ! $maybe_return_image ) { ewwwio_debug_message( "found a match for $attachment" ); $maybe_return_image = $image; } else { if ( empty( $duplicates ) ) { $duplicates = array( $maybe_return_image, $image ); } else { $duplicates[] = $image; } } } } // Do something with duplicates. if ( ! empty( $duplicates ) && is_array( $duplicates ) ) { $keeper = ewww_image_optimizer_remove_duplicate_records( $duplicates ); if ( ! empty( $keeper ) && is_array( $keeper ) ) { $maybe_return_image = $keeper; } } return $maybe_return_image; } /** * Check if an attachment was previously optimized on a higher compression level and should be restored before continuing. * * @global object $wpdb * * @param int $id The attachment to check for potential restoration. * @param string $type The mime-type of the attachment. * @param array $meta The attachment metadata. * @return array The attachment meta, potentially altered. */ function ewww_image_optimizer_attachment_check_variant_level( $id, $type, $meta ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); global $ewww_force; if ( empty( $ewww_force ) ) { return $meta; } if ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ) ) { return $meta; } if ( 'image/jpeg' === $type && (int) ewww_image_optimizer_get_option( 'ewww_image_optimizer_jpg_level' ) > 20 ) { return $meta; } if ( 'image/png' === $type && (int) ewww_image_optimizer_get_option( 'ewww_image_optimizer_png_level' ) > 20 ) { return $meta; } if ( 'application/pdf' === $type && 10 !== (int) ewww_image_optimizer_get_option( 'ewww_image_optimizer_pdf_level' ) ) { return $meta; } $compression_level = ewww_image_optimizer_get_level( $type ); // Retrieve any records for this image. global $wpdb; $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'media' AND image_size <> 0 ORDER BY orig_size DESC", $id ), ARRAY_A ); foreach ( $optimized_images as $optimized_image ) { if ( 'full' === $optimized_image['resize'] && $compression_level < $optimized_image['level'] ) { global $eio_backup; if ( $eio_backup->is_backup_available( $optimized_image['path'], $optimized_image ) ) { return $eio_backup->restore_backup_from_meta_data( $id, 'media', $meta ); } } } return $meta; } /** * Merge duplicate records from the images table and remove any extras. * * @global object $wpdb * @global object $ewwwdb A clone of $wpdb unless it is lacking utf8 connectivity. * * @param array $duplicates An array of records referencing the same image. * @return array|bool A single image record or false if something unexpected happens. */ function ewww_image_optimizer_remove_duplicate_records( $duplicates ) { if ( empty( $duplicates ) ) { return false; } global $wpdb; if ( strpos( $wpdb->charset, 'utf8' ) === false ) { ewww_image_optimizer_db_init(); global $ewwwdb; } else { $ewwwdb = $wpdb; } if ( ! is_array( $duplicates[0] ) ) { // Retrieve records for the ID #s passed. $duplicate_ids = implode( ',', array_map( 'intval', $duplicates ) ); $duplicates = $ewwwdb->get_results( "SELECT * FROM $ewwwdb->ewwwio_images WHERE id IN ($duplicate_ids)" ); } if ( ! is_array( $duplicates ) || ! is_array( $duplicates[0] ) ) { return false; } $image_size = ewww_image_optimizer_filesize( $duplicates[0]['path'] ); $discard = array(); ewwwio_debug_message( 'looking for duplicates of: ' . $duplicates[0]['path'] . " filesize = $image_size" ); // First look for an image size match. foreach ( $duplicates as $duplicate ) { if ( empty( $keeper ) && ! empty( $duplicate['image_size'] ) && $image_size === $duplicate['image_size'] ) { $keeper = $duplicate; } else { $discard[] = $duplicate; } } // Then look for the first record with an image_size (that means it has been optimized). if ( empty( $keeper ) ) { $discard = array(); foreach ( $duplicates as $duplicate ) { if ( empty( $keeper ) && ! empty( $duplicate['image_size'] ) ) { $keeper = $duplicate; } else { $discard[] = $duplicate; } } } // If we still have nothing, mark the 0 record as the primary and pull it off the stack. if ( empty( $keeper ) ) { $keeper = array_shift( $duplicates ); $discard = $duplicates; } if ( is_array( $keeper ) && is_array( $discard ) ) { $delete_ids = array(); foreach ( $discard as $record ) { foreach ( $record as $key => $value ) { if ( empty( $keeper[ $key ] ) && ! empty( $value ) ) { $keeper[ $key ] = $value; } } $delete_ids[] = (int) $record['id']; } if ( ! empty( $delete_ids ) && is_array( $delete_ids ) ) { $query_ids = implode( ',', $delete_ids ); $ewwwdb->query( "DELETE FROM $ewwwdb->ewwwio_images WHERE id IN ($query_ids)" ); } return $keeper; } return false; } /** * See if background mode is allowed/enabled. * * @return bool True if it is, false if it isn't. */ function ewww_image_optimizer_background_mode_enabled() { if ( defined( 'EWWW_DISABLE_ASYNC' ) && EWWW_DISABLE_ASYNC ) { ewwwio_debug_message( 'background disabled by admin' ); return false; } if ( ! ewww_image_optimizer_function_exists( 'sleep' ) ) { ewwwio_debug_message( 'background disabled by lack of sleep' ); return false; } if ( ewww_image_optimizer_detect_wpsf_location_lock() ) { ewwwio_debug_message( 'background disabled by shield location lock' ); return false; } return (bool) ewww_image_optimizer_get_option( 'ewww_image_optimizer_background_optimization' ); } /** * Checks to see if we should use background optimization for an image. * * Uses the mimetype and current configuration to determine if background mode should be used. * * @global bool $ewww_defer True to defer optimization. * * @param string $type Optional. Mime type of image being processed. Default ''. * @return bool True if background mode should be used. */ function ewww_image_optimizer_test_background_opt( $type = '' ) { if ( ! ewww_image_optimizer_background_mode_enabled() ) { return false; } if ( 'image/type' === $type && ewww_image_optimizer_get_option( 'ewww_image_optimizer_jpg_to_png' ) ) { return apply_filters( 'ewww_image_optimizer_defer_conversion', false ); } if ( 'image/png' === $type && ewww_image_optimizer_get_option( 'ewww_image_optimizer_png_to_jpg' ) ) { return apply_filters( 'ewww_image_optimizer_defer_conversion', false ); } if ( 'image/gif' === $type && ewww_image_optimizer_get_option( 'ewww_image_optimizer_gif_to_png' ) ) { return apply_filters( 'ewww_image_optimizer_defer_conversion', false ); } global $ewww_defer; return (bool) apply_filters( 'ewww_image_optimizer_background_optimization', $ewww_defer ); } /** * Rebuilds metadata and regenerates thumbs for an attachment. * * @param int $attachment_id The ID number of the attachment. * @return array Attachment metadata, if the rebuild was successful. */ function ewww_image_optimizer_rebuild_meta( $attachment_id ) { $file = get_attached_file( $attachment_id ); if ( ewwwio_is_file( $file ) ) { global $ewww_preempt_editor; $ewww_preempt_editor = true; remove_all_filters( 'wp_generate_attachment_metadata' ); ewwwio_debug_message( "generating new meta for $attachment_id" ); $meta = wp_generate_attachment_metadata( $attachment_id, $file ); ewwwio_debug_message( "generated new meta for $attachment_id" ); $updated = update_post_meta( $attachment_id, '_wp_attachment_metadata', $meta ); if ( $updated ) { ewwwio_debug_message( "updated meta for $attachment_id" ); } else { ewwwio_debug_message( "failed meta update for $attachment_id" ); } return $meta; } } /** * Find the path to a backed-up original (not the full-size version like the core WP function). * * @param int $id The attachment ID number. * @param string $image_file The path to a scaled image file. * @param array $meta The attachment metadata. Optional, default to null. * @return bool True on success, false on failure. */ function ewwwio_get_original_image_path( $id, $image_file = '', $meta = null ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); $id = (int) $id; if ( empty( $id ) ) { return false; } if ( ! wp_attachment_is_image( $id ) ) { return false; } if ( is_null( $meta ) ) { $meta = wp_get_attachment_metadata( $id ); } if ( empty( $image_file ) ) { $image_file = get_attached_file( $id, true ); } if ( ! $image_file || ! ewww_image_optimizer_iterable( $meta ) || empty( $meta['original_image'] ) ) { if ( $image_file && apply_filters( 'ewwwio_find_original_image_no_meta', false, $image_file ) && strpos( $image_file, '-scaled.' ) ) { ewwwio_debug_message( "constructing path with $image_file alone" ); $original_image = trailingslashit( dirname( $image_file ) ) . wp_basename( str_replace( '-scaled.', '.', $original_image ) ); if ( $original_image !== $image_file ) { ewwwio_debug_message( "found $original_image" ); return $original_image; } } return false; } ewwwio_debug_message( "constructing path with $image_file and " . $meta['original_image'] ); return trailingslashit( dirname( $image_file ) ) . wp_basename( $meta['original_image'] ); } /** * Remove the backed-up original_image stored by WP 5.3+. * * @param int $id The attachment ID number. * @param array $meta The attachment metadata. Optional, default to null. * @return bool|array Returns meta if modified, false otherwise (even if an "unlinked" original is removed). */ function ewwwio_remove_original_image( $id, $meta = null ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); $id = (int) $id; if ( empty( $id ) ) { return false; } if ( is_null( $meta ) ) { ewwwio_debug_message( "getting meta for $id" ); $meta = wp_get_attachment_metadata( $id ); } if ( $meta && is_array( $meta ) && ! empty( $meta['original_image'] ) && function_exists( 'wp_get_original_image_path' ) ) { $original_image = ewwwio_get_original_image_path( $id, '', $meta ); if ( $original_image && is_file( $original_image ) && is_writable( $original_image ) ) { ewwwio_debug_message( "removing $original_image" ); unlink( $original_image ); } clearstatcache(); if ( empty( $original_image ) || ! is_file( $original_image ) ) { ewwwio_debug_message( 'cleaning meta' ); unset( $meta['original_image'] ); return $meta; } } return false; } /** * Find image paths from an attachment's meta data and process each image. * * Called after `wp_generate_attachment_metadata` is completed, it also searches for retina images, * and a few custom theme resizes. When a new image is uploaded, it is added to the queue, if * possible, and then this same function is run in the background. * * @global object $wpdb * @global object $ewwwdb A clone of $wpdb unless it is lacking utf8 connectivity. * @global bool $ewww_new_image True if this is a newly uploaded image. * @global object $ewww_image Contains more information about the image currently being processed. * @global array $ewww_attachment { * Stores the ID and meta for later use with W3TC. * * @type int $id The attachment ID number. * @type array $meta The attachment metadata from the postmeta table. * } * @global object $as3cf For working with the WP Offload S3 plugin. * @global object $dreamspeed For working with the Dreamspeed CDN plugin. * * @param array $meta The attachment metadata generated by WordPress. * @param int $id Optional. The attachment ID number. Default null. Accepts any non-negative integer. * @param bool $log Optional. True to flush debug info to the log at the end of the function. * @param bool $background_new Optional. True indicates this is a new image processed in the background. * @return array $meta Send the metadata back from whence it came. */ function ewww_image_optimizer_resize_from_meta_data( $meta, $id = null, $log = true, $background_new = false ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( ! is_array( $meta ) && empty( $meta ) ) { $meta = array(); } elseif ( ! is_array( $meta ) ) { ewwwio_debug_message( 'attachment meta is not a usable array' ); return $meta; } global $wpdb; if ( strpos( $wpdb->charset, 'utf8' ) === false ) { ewww_image_optimizer_db_init(); global $ewwwdb; } else { $ewwwdb = $wpdb; } global $ewww_new_image; global $ewww_image; global $ewww_force; global $eio_filesystem; ewwwio_get_filesystem(); $gallery_type = 1; ewwwio_debug_message( "attachment id: $id" ); session_write_close(); if ( ! empty( $ewww_new_image ) ) { ewwwio_debug_message( 'this is a newly uploaded image with no metadata yet' ); $new_image = true; } elseif ( $background_new ) { ewwwio_debug_message( 'this is a newly uploaded image from the async queue' ); $new_image = true; } else { ewwwio_debug_message( 'this image already has metadata, so it is not new' ); $new_image = false; } list( $file_path, $upload_path ) = ewww_image_optimizer_attachment_path( $meta, $id ); /** * Allow altering the metadata or performing other actions before the plugin processes an attachement. * * @param array $meta The attachment metadata. * @param string $file_path The file path to the image. * @param bool $new_image True if this is a newly uploaded image, false otherwise. */ $meta = apply_filters( 'ewww_image_optimizer_resize_from_meta_data', $meta, $file_path, $new_image ); // If the attachment has been uploaded via the image store plugin. if ( 'ims_image' === get_post_type( $id ) ) { $gallery_type = 6; } if ( ! $new_image && class_exists( 'Amazon_S3_And_CloudFront' ) && ewww_image_optimizer_stream_wrapped( $file_path ) ) { ewww_image_optimizer_check_table_as3cf( $meta, $id, $file_path ); } if ( ! ewwwio_is_file( $file_path ) && class_exists( 'wpCloud\StatelessMedia\EWWW' ) && ! empty( $meta['gs_link'] ) ) { $file_path = ewww_image_optimizer_remote_fetch( $id, $meta ); } // If the local file is missing and we have valid metadata, see if we can fetch via CDN. if ( ! ewwwio_is_file( $file_path ) || ewww_image_optimizer_stream_wrapped( $file_path ) ) { $file_path = ewww_image_optimizer_remote_fetch( $id, $meta ); if ( ! $file_path ) { ewwwio_debug_message( 'could not retrieve path' ); return $meta; } } ewwwio_debug_message( "retrieved file path: $file_path" ); $type = ewww_image_optimizer_mimetype( $file_path, 'i' ); $supported_types = array( 'image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'image/svg+xml', ); if ( ! in_array( $type, $supported_types, true ) ) { ewwwio_debug_message( "mimetype not supported: $id" ); return $meta; } $meta = ewww_image_optimizer_attachment_check_variant_level( $id, $type, $meta ); $fullsize_size = ewww_image_optimizer_filesize( $file_path ); // Initialize an EWWW_Image object for the full-size image so that the original size will be tracked before any potential resizing operations. $ewww_image = new EWWW_Image( $id, 'media', $file_path ); $ewww_image->resize = 'full'; // Resize here so long as this is not a new image AND resize existing is enabled, and imsanity isn't enabled with a max size. if ( ( empty( $new_image ) && ewww_image_optimizer_get_option( 'ewww_image_optimizer_resize_existing' ) ) && ! function_exists( 'imsanity_get_max_width_height' ) ) { ewwwio_debug_message( 'not a new image, resize existing enabled, and Imsanity not detected' ); $new_dimensions = ewww_image_optimizer_resize_upload( $file_path ); if ( is_array( $new_dimensions ) ) { $meta['width'] = $new_dimensions[0]; $meta['height'] = $new_dimensions[1]; } } if ( ewww_image_optimizer_test_background_opt( $type ) ) { add_filter( 'http_headers_useragent', 'ewww_image_optimizer_cloud_useragent', PHP_INT_MAX ); ewwwio_debug_message( 's3 upload deferred' ); add_filter( 'as3cf_pre_update_attachment_metadata', '__return_true' ); ewwwio_debug_message( "backgrounding optimization for $id" ); ewwwio()->background_media->push_to_queue( array( 'id' => $id, 'new' => $new_image, ) ); if ( 5 > ewwwio()->background_media->count_queue() ) { ewwwio()->background_media->dispatch(); ewwwio_debug_message( 'small queue, dispatching post-haste' ); } if ( $log ) { ewww_image_optimizer_debug_log(); } return $meta; } // Resize here if the user has used the filter to defer resizing, we have a new image OR resize existing is enabled, and imsanity isn't enabled with a max size. if ( apply_filters( 'ewww_image_optimizer_defer_resizing', false ) && ( ! empty( $new_image ) || ewww_image_optimizer_get_option( 'ewww_image_optimizer_resize_existing' ) ) && ! function_exists( 'imsanity_get_max_width_height' ) ) { ewwwio_debug_message( 'resizing defered and ( new image or resize existing enabled ) and Imsanity not detected' ); $new_dimensions = ewww_image_optimizer_resize_upload( $file_path ); if ( is_array( $new_dimensions ) ) { $meta['width'] = $new_dimensions[0]; $meta['height'] = $new_dimensions[1]; } } ewwwio_debug_message( 'running in sequence' ); // Run the optimization and store the results. list( $file, $msg, $conv, $original ) = ewww_image_optimizer( $file_path, $gallery_type, false, $new_image, true ); // If the file was converted. if ( false !== $conv && $file ) { $ewww_image->file = $file; $ewww_image->converted = $original; $meta['file'] = _wp_relative_upload_path( $file ); $ewww_image->update_converted_attachment( $meta ); $meta = $ewww_image->convert_sizes( $meta ); ewwwio_debug_message( 'image was converted' ); } else { remove_filter( 'wp_update_attachment_metadata', 'ewww_image_optimizer_update_attachment', 10 ); } ewww_image_optimizer_hidpi_optimize( $file ); // See if we are forcing re-optimization per the user's request. if ( ! empty( $ewww_force ) ) { $force = true; } else { $force = false; } $base_dir = trailingslashit( dirname( $file_path ) ); // Resized versions, so we can continue. if ( isset( $meta['sizes'] ) && ewww_image_optimizer_iterable( $meta['sizes'] ) ) { $disabled_sizes = ewww_image_optimizer_get_option( 'ewww_image_optimizer_disable_resizes_opt', false, true ); ewwwio_debug_message( 'processing resizes' ); // Meta sizes don't contain a path, so we calculate one. if ( 6 === $gallery_type ) { $base_ims_dir = trailingslashit( dirname( $file_path ) ) . '_resized/'; } // Process each resized version. $processed = array(); foreach ( $meta['sizes'] as $size => $data ) { ewwwio_debug_message( "processing size: $size" ); if ( strpos( $size, 'webp' ) === 0 ) { continue; } if ( ! empty( $disabled_sizes[ $size ] ) ) { continue; } if ( ! empty( $disabled_sizes['pdf-full'] ) && 'full' === $size ) { continue; } if ( empty( $data['file'] ) ) { continue; } if ( 6 === $gallery_type ) { // We reset base_dir, because base_dir potentially gets overwritten with base_ims_dir. $base_dir = trailingslashit( dirname( $file_path ) ); $image_path = $base_dir . $data['file']; $ims_path = $base_ims_dir . $data['file']; if ( ewwwio_is_file( $ims_path ) ) { ewwwio_debug_message( 'ims resize already exists, wahoo' ); ewwwio_debug_message( "ims path: $ims_path" ); $image_size = ewww_image_optimizer_filesize( $ims_path ); $already_optimized = ewww_image_optimizer_find_already_optimized( $image_path ); if ( is_array( $already_optimized ) ) { ewwwio_debug_message( "updating existing record, path: $ims_path, size: " . $image_size ); // Store info on the current image for future reference. $ewwwdb->update( $ewwwdb->ewwwio_images, array( 'path' => ewww_image_optimizer_relativize_path( $ims_path ), ), array( 'id' => $already_optimized['id'], ) ); } $base_dir = $base_ims_dir; } } // Check through all the sizes we've processed so far. foreach ( $processed as $proc => $scan ) { // If a previous resize had identical dimensions. if ( $scan['height'] === $data['height'] && $scan['width'] === $data['width'] ) { // We found a duplicate resize, so... // Point this resize at the same image as the previous one. $meta['sizes'][ $size ]['file'] = $meta['sizes'][ $proc ]['file']; $meta['sizes'][ $size ]['mime-type'] = $meta['sizes'][ $proc ]['mime-type']; continue( 2 ); } } // If this is a unique size. $resize_path = str_replace( wp_basename( $file_path ), $data['file'], $file_path ); if ( empty( $resize_path ) ) { ewwwio_debug_message( 'strange... $resize_path was empty' ); continue; } $resize_path = path_join( $upload_path, $resize_path ); if ( 'application/pdf' === $type && 'full' === $size ) { $size = 'pdf-full'; ewwwio_debug_message( 'processing full size pdf preview' ); } // Because some SVG plugins populate the resizes with the original path (since SVG is "scalable", of course). // Though it could happen for other types perhaps... if ( $resize_path === $file_path ) { continue; } $ewww_image = new EWWW_Image( $id, 'media', $resize_path ); $ewww_image->resize = $size; // Run the optimization and store the results. ewww_image_optimizer( $resize_path ); // Optimize retina images, if they exist. if ( function_exists( 'wr2x_get_retina' ) ) { $retina_path = wr2x_get_retina( $resize_path ); } else { $retina_path = false; } if ( $retina_path && ewwwio_is_file( $retina_path ) ) { $ewww_image = new EWWW_Image( $id, 'media', $retina_path ); $ewww_image->resize = $size . '-retina'; ewww_image_optimizer( $retina_path ); } else { ewww_image_optimizer_hidpi_optimize( $resize_path ); } // Store info on the sizes we've processed, so we can check the list for duplicate sizes. $processed[ $size ]['width'] = $data['width']; $processed[ $size ]['height'] = $data['height']; } // End foreach(). } // End if(). // Original image detected. if ( isset( $meta['original_image'] ) && ewww_image_optimizer_get_option( 'ewww_image_optimizer_include_originals' ) ) { ewwwio_debug_message( 'processing original_image' ); // Meta sizes don't contain a path, so we calculate one. $resize_path = trailingslashit( dirname( $file_path ) ) . $meta['original_image']; $ewww_image = new EWWW_Image( $id, 'media', $resize_path ); $ewww_image->resize = 'original_image'; // Run the optimization and store the results (gallery type 5 and fullsize=true to obey lossy/metadata exclusions). ewww_image_optimizer( $resize_path, 5, false, false, true ); } // End if(). // Process size from a custom theme. if ( isset( $meta['image_meta']['resized_images'] ) && ewww_image_optimizer_iterable( $meta['image_meta']['resized_images'] ) ) { $imagemeta_resize_pathinfo = pathinfo( $file_path ); $imagemeta_resize_path = ''; foreach ( $meta['image_meta']['resized_images'] as $imagemeta_resize ) { $imagemeta_resize_path = $imagemeta_resize_pathinfo['dirname'] . '/' . $imagemeta_resize_pathinfo['filename'] . '-' . $imagemeta_resize . '.' . $imagemeta_resize_pathinfo['extension']; $ewww_image = new EWWW_Image( $id, 'media', $imagemeta_resize_path ); ewww_image_optimizer( $imagemeta_resize_path ); } } // And another custom theme. if ( isset( $meta['custom_sizes'] ) && ewww_image_optimizer_iterable( $meta['custom_sizes'] ) ) { $custom_sizes_pathinfo = pathinfo( $file_path ); $custom_size_path = ''; foreach ( $meta['custom_sizes'] as $custom_size ) { $custom_size_path = $custom_sizes_pathinfo['dirname'] . '/' . $custom_size['file']; $ewww_image = new EWWW_Image( $id, 'media', $custom_size_path ); ewww_image_optimizer( $custom_size_path ); } } global $ewww_attachment; $ewww_attachment['id'] = $id; $ewww_attachment['meta'] = $meta; add_filter( 'w3tc_cdn_update_attachment_metadata', 'ewww_image_optimizer_w3tc_update_files' ); remove_filter( 'wp_update_attachment_metadata', 'ewww_image_optimizer_update_filesize_metadata', 9 ); $meta = ewww_image_optimizer_update_filesize_metadata( $meta, $id, $file ); // Done optimizing, do whatever you need with the attachment from here. do_action( 'ewww_image_optimizer_after_optimize_attachment', $id, $meta ); if ( class_exists( 'Amazon_S3_And_CloudFront' ) ) { global $as3cf; if ( method_exists( $as3cf, 'wp_update_attachment_metadata' ) ) { ewwwio_debug_message( 'deferring to normal S3 hook' ); } elseif ( method_exists( $as3cf, 'wp_generate_attachment_metadata' ) ) { $as3cf->wp_generate_attachment_metadata( $meta, $id ); ewwwio_debug_message( 'uploading to Amazon S3' ); } } if ( ewww_image_optimizer_s3_uploads_enabled() ) { ewww_image_optimizer_remote_push( $meta, $id ); ewwwio_debug_message( 're-uploading to S3(_Uploads)' ); } if ( class_exists( 'Windows_Azure_Helper' ) && function_exists( 'windows_azure_storage_wp_generate_attachment_metadata' ) ) { $meta = windows_azure_storage_wp_generate_attachment_metadata( $meta, $id ); if ( Windows_Azure_Helper::delete_local_file() && function_exists( 'windows_azure_storage_delete_local_files' ) ) { windows_azure_storage_delete_local_files( $meta, $id ); } } if ( class_exists( 'Cloudinary' ) && Cloudinary::config_get( 'api_secret' ) && ewww_image_optimizer_get_option( 'ewww_image_optimizer_enable_cloudinary' ) && ! empty( $new_image ) ) { try { $result = CloudinaryUploader::upload( $file, array( 'use_filename' => true ) ); } catch ( Exception $e ) { $error = $e->getMessage(); } if ( ! empty( $error ) ) { ewwwio_debug_message( "Cloudinary error: $error" ); } else { ewwwio_debug_message( 'successfully uploaded to Cloudinary' ); // Register the attachment in the database as a cloudinary attachment. $old_url = wp_get_attachment_url( $id ); wp_update_post( array( 'ID' => $id, 'guid' => $result['url'], ) ); update_attached_file( $id, $result['url'] ); $meta['cloudinary'] = true; $errors = array(); // Update the image location for the attachment. CloudinaryPlugin::update_image_src_all( $id, $result, $old_url, $result['url'], true, $errors ); if ( count( $errors ) > 0 ) { ewwwio_debug_message( 'Cannot migrate the following posts:' ); foreach ( $errors as $error ) { ewwwio_debug_message( $error ); } } } } ewwwio_debug_message( 'optimize from meta complete' ); if ( $log ) { ewww_image_optimizer_debug_log(); } ewwwio_memory( __FUNCTION__ ); // Send back the updated metadata. return $meta; } /** * Optimize by attachment ID with optional meta. * * Proxy for ewww_image_optimizer_resize_from_meta_data(), used by Imsanity. * * @param int $id The attachment ID number. * @param array $meta The attachment metadata generated by WordPress. Optional. */ function ewww_image_optimizer_optimize_by_id( $id, $meta = false ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( empty( $id ) ) { return; } if ( ! ewww_image_optimizer_iterable( $meta ) ) { $meta = wp_get_attachment_metadata( $id ); } $meta = ewww_image_optimizer_resize_from_meta_data( $meta, $id ); wp_update_attachment_metadata( $id, $meta ); } /** * Only runs during WP/LR Sync to check if an attachment has been updated. * * @param int $id The attachment ID number. * @return array $meta Send the metadata back from whence it came. */ function ewww_image_optimizer_lr_sync_update( $id ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( empty( $id ) ) { return; } $meta = wp_get_attachment_metadata( $id ); list( $file_path, $upload_path ) = ewww_image_optimizer_attachment_path( $meta, $id ); if ( ewww_image_optimizer_stream_wrapped( $file_path ) || ! ewwwio_is_file( $file_path ) ) { ewwwio_debug_message( "bailing early since no local file or stream wrapped $file_path" ); // Still want to fire off the optimization. if ( defined( 'EWWWIO_WPLR_AUTO' ) && EWWWIO_WPLR_AUTO ) { ewwwio_debug_message( "auto optimizing $file_path" ); $meta = ewww_image_optimizer_resize_from_meta_data( $meta, $id ); } return; } ewwwio_debug_message( "retrieved file path for lr sync image: $file_path" ); $type = ewww_image_optimizer_mimetype( $file_path, 'i' ); $supported_types = array( 'image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'image/svg+xml', ); if ( ! in_array( $type, $supported_types, true ) ) { ewwwio_debug_message( "mimetype not supported: $id" ); return; } // Get a list of all the image files optimized for this attachment. global $wpdb; $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'media' AND image_size <> 0 ORDER BY orig_size DESC", $id ), ARRAY_A ); if ( ewww_image_optimizer_iterable( $optimized_images ) ) { foreach ( $optimized_images as $optimized_image ) { $image_path = ewww_image_optimizer_absolutize_path( $optimized_image['path'] ); $file_size = ewww_image_optimizer_filesize( $image_path ); if ( $file_size === (int) $optimized_image['image_size'] ) { ewwwio_debug_message( "not resetting $image_path for lr sync" ); continue; } if ( ewwwio_is_file( $image_path . '.webp' ) ) { ewwwio_debug_message( "removing WebP version of $image_path for lr sync" ); ewwwio_delete_file( $image_path . '.webp' ); } $wpdb->update( $wpdb->ewwwio_images, array( 'image_size' => 0, ), array( 'id' => $optimized_image['id'], ) ); } } if ( defined( 'EWWWIO_WPLR_AUTO' ) && EWWWIO_WPLR_AUTO ) { ewwwio_debug_message( "auto optimizing $file_path" ); $meta = ewww_image_optimizer_resize_from_meta_data( $meta, $id ); return; } ewwwio_debug_message( 'no auto-opt, will show notice' ); update_option( 'ewww_image_optimizer_lr_sync', true, false ); } /** * Check to see if Shield's location lock option is enabled. * * @return bool True if the IP location lock is enabled. */ function ewww_image_optimizer_detect_wpsf_location_lock() { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( function_exists( 'icwp_wpsf_init' ) ) { ewwwio_debug_message( 'Shield Security detected' ); $shield_user_man = ewww_image_optimizer_get_option( 'icwp_wpsf_user_management_options' ); if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_debug' ) && ewww_image_optimizer_function_exists( 'print_r' ) ) { ewwwio_debug_message( print_r( $shield_user_man, true ) ); } if ( ! empty( $shield_user_man['session_lock_location'] ) && 'Y' === $shield_user_man['session_lock_location'] ) { return true; } } return false; } /** * Parse image paths for WP Offload S3. * * Adds WebP derivatives so that they can be uploaded. * * @param array $paths The image paths currently queued for upload. * @param int $id The ID number of the image in the database. * @return array Attachment meta field. */ function ewww_image_optimizer_as3cf_attachment_file_paths( $paths, $id ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); $as3cf_action = false; if ( ! empty( $_REQUEST['action'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification $as3cf_action = sanitize_text_field( wp_unslash( $_REQUEST['action'] ) ); // phpcs:ignore WordPress.Security.NonceVerification } global $ewww_new_image; if ( ! empty( $ewww_new_image ) ) { // This is so we can detect new uploads for conversion checking. $as3cf_action = 'media_upload'; } foreach ( $paths as $size => $path ) { if ( ! is_string( $path ) ) { continue; } if ( false !== strpos( $size, '-webp' ) || str_ends_with( $path, '.webp' ) ) { continue; } if ( $as3cf_action ) { ewwwio_debug_message( "checking $path for WebP or converted images in as3cf $as3cf_action queue" ); } if ( ewwwio_is_file( $path . '.webp' ) ) { $paths[ $size . '-webp' ] = $path . '.webp'; ewwwio_debug_message( "added $path.webp to as3cf queue" ); } elseif ( // WOM(pro) is downloading from bucket to server, WebP is enabled, and the local/server file does not exist. 'download' === $as3cf_action && ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp' ) && ! ewwwio_is_file( $path ) ) { global $wpdb; $optimized = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'media' AND image_size <> 0 LIMIT 1", $id ) ); if ( $optimized ) { $paths[ $size . '-webp' ] = $path . '.webp'; ewwwio_debug_message( "added $path.webp to as3cf queue (for potential local copy)" ); } } if ( ! is_admin() ) { continue; } $conversion_actions = array( 'bulk_loop', 'copy', 'download', 'ewww_bulk_update_meta', 'ewww_image_optimizer_manual_image_restore', 'ewww_image_optimizer_manual_optimize', 'ewww_image_optimizer_manual_restore', 'media_upload', 'wp_ewwwio_image_optimize', 'wp_ewwwio_media_optimize', 'remove_local', ); // If we're not deleting originals, then they should be re-uploaded to S3. // We'd check if conversion options are enabled, but folks can convert via the Media Library without them enabled, so we need to account for that. if ( in_array( $as3cf_action, $conversion_actions, true ) && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_delete_originals' ) ) { $opt_image = ewww_image_optimizer_find_already_optimized( $path ); if ( ! empty( $opt_image['path'] ) && ! empty( $opt_image['converted'] ) ) { $orig_path = ewww_image_optimizer_absolutize_path( $opt_image['converted'] ); // If WOM(pro) is downloading from bucket to server or a local original exists. if ( 'download' === $as3cf_action || ewwwio_is_file( $orig_path ) ) { $paths[ $size . '-orig' ] = $orig_path; ewwwio_debug_message( "added {$orig_path} to as3cf queue" ); } } } } return $paths; } /** * Cleanup remote storage for WP Offload S3. * * Checks for WebP derivatives and pre-converted originals so that they can be removed. * * @param array $paths The image paths currently queued for deletion. * @return array A list of paths to remove. */ function ewww_image_optimizer_as3cf_remove_source_files( $paths ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); foreach ( $paths as $size => $path ) { if ( ! is_string( $path ) ) { continue; } if ( false !== strpos( $size, '-webp' ) || str_ends_with( $path, '.webp' ) ) { continue; } $paths[ $size . '-webp' ] = $path . '.webp'; ewwwio_debug_message( "added $path.webp to as3cf deletion queue" ); $ewww_image = ewww_image_optimizer_find_already_optimized( $path ); if ( ! empty( $ewww_image['path'] ) ) { $local_path = ewww_image_optimizer_absolutize_path( $ewww_image['path'] ); ewwwio_debug_message( "found optimized $local_path, validating and checking for pre-converted original" ); if ( ! empty( $ewww_image['converted'] ) ) { $orig_path = ewww_image_optimizer_absolutize_path( $ewww_image['converted'] ); $paths[ $size . '-orig' ] = $orig_path; ewwwio_debug_message( "added {$orig_path} to as3cf deletion queue" ); } } } return $paths; } /** * Fixes the ContentType for WebP images because WP mimetype detection stinks. * * @param array $args The parameters to be used for the S3 upload. * @return array The same parameters with ContentType corrected. */ function ewww_image_optimizer_as3cf_object_meta( $args ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( ! empty( $args['SourceFile'] ) && ewwwio_is_file( $args['SourceFile'] ) && empty( $args['ContentType'] ) && false !== strpos( $args['SourceFile'], '.webp' ) ) { $args['ContentType'] = ewww_image_optimizer_quick_mimetype( $args['SourceFile'] ); } return $args; } /** * Update the attachment's meta data after being converted. * * @global object $wpdb * * @param array $meta Attachment metadata. * @param int $id Attachment ID number. */ function ewww_image_optimizer_update_attachment( $meta, $id ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); global $wpdb; // Update the file location in the post metadata based on the new path stored in the attachment metadata. update_attached_file( $id, $meta['file'] ); $guid = wp_get_attachment_url( $id ); if ( empty( $meta['real_orig_file'] ) ) { $old_guid = dirname( $guid ) . '/' . wp_basename( $meta['orig_file'] ); } else { $old_guid = dirname( $guid ) . '/' . wp_basename( $meta['real_orig_file'] ); unset( $meta['real_orig_file'] ); } // Construct the new guid based on the filename from the attachment metadata. ewwwio_debug_message( "old guid: $old_guid" ); ewwwio_debug_message( "new guid: $guid" ); if ( substr( $old_guid, -1 ) === '/' || substr( $guid, -1 ) === '/' ) { ewwwio_debug_message( 'could not obtain full url for current and previous image, bailing' ); return $meta; } // Retrieve any posts that link the image. $esql = $wpdb->prepare( "SELECT ID, post_content FROM $wpdb->posts WHERE post_content LIKE %s", '%' . $wpdb->esc_like( $old_guid ) . '%' ); ewwwio_debug_message( "using query: $esql" ); // While there are posts to process. $rows = $wpdb->get_results( $esql, ARRAY_A ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared if ( ewww_image_optimizer_iterable( $rows ) ) { foreach ( $rows as $row ) { // Replace all occurences of the old guid with the new guid. $post_content = str_replace( $old_guid, $guid, $row['post_content'] ); ewwwio_debug_message( "replacing $old_guid with $guid in post " . $row['ID'] ); // Send the updated content back to the database. $wpdb->update( $wpdb->posts, array( 'post_content' => $post_content, ), array( 'ID' => $row['ID'], ) ); } } if ( isset( $meta['sizes'] ) && ewww_image_optimizer_iterable( $meta['sizes'] ) ) { // For each resized version. foreach ( $meta['sizes'] as $size => $data ) { // If the resize was converted. if ( isset( $data['converted'] ) ) { // Generate the url for the old image. if ( empty( $data['real_orig_file'] ) ) { $old_sguid = dirname( $old_guid ) . '/' . wp_basename( $data['orig_file'] ); } else { $old_sguid = dirname( $old_guid ) . '/' . wp_basename( $data['real_orig_file'] ); unset( $meta['sizes'][ $size ]['real_orig_file'] ); } ewwwio_debug_message( "processing: $size" ); ewwwio_debug_message( "old sguid: $old_sguid" ); // Generate the url for the new image. $sguid = dirname( $old_guid ) . '/' . wp_basename( $data['file'] ); ewwwio_debug_message( "new sguid: $sguid" ); if ( substr( $old_sguid, -1 ) === '/' || substr( $sguid, -1 ) === '/' ) { ewwwio_debug_message( 'could not obtain full url for current and previous resized image, bailing' ); continue; } // Retrieve any posts that link the resize. $rows = $wpdb->get_results( $wpdb->prepare( "SELECT ID, post_content FROM $wpdb->posts WHERE post_content LIKE %s", '%' . $wpdb->esc_like( $old_sguid ) . '%' ), ARRAY_A ); // While there are posts to process. if ( ewww_image_optimizer_iterable( $rows ) ) { foreach ( $rows as $row ) { // Replace all occurences of the old guid with the new guid. $post_content = str_replace( $old_sguid, $sguid, $row['post_content'] ); ewwwio_debug_message( "replacing $old_sguid with $sguid in post " . $row['ID'] ); // Send the updated content back to the database. $wpdb->update( $wpdb->posts, array( 'post_content' => $post_content, ), array( 'ID' => $row['ID'], ) ); } } } // End if(). } // End foreach(). } // End if(). if ( preg_match( '/\.jpg$/i', wp_basename( $meta['file'] ) ) ) { $mime = 'image/jpeg'; } if ( preg_match( '/\.png$/i', wp_basename( $meta['file'] ) ) ) { $mime = 'image/png'; } if ( preg_match( '/\.gif$/i', wp_basename( $meta['file'] ) ) ) { $mime = 'image/gif'; } if ( preg_match( '/\.svg$/i', wp_basename( $meta['file'] ) ) ) { $mime = 'image/svg+xml'; } // Update the attachment post with the new mimetype and id. wp_update_post( array( 'ID' => $id, 'post_mime_type' => $mime, ) ); return $meta; } /** * Update file sizes for an attachment and all thumbs. * * @param array $meta Attachment metadata. * @param int $id Attachment ID number. * @param string $file_path Optional. The full path to the full-size image. * @return array The updated attachment metadata. */ function ewww_image_optimizer_update_filesize_metadata( $meta, $id, $file_path = false ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); global $wpdb; if ( ! $file_path || ! is_string( $file_path ) ) { list( $file_path, $upload_path ) = ewww_image_optimizer_attachment_path( $meta, $id ); } if ( ! $file_path ) { return $meta; } $use_db = false; if ( ewww_image_optimizer_stream_wrapped( $file_path ) || ! ewwwio_is_file( $file_path ) ) { $use_db = true; } if ( $use_db ) { $full_filesize = $wpdb->get_var( $wpdb->prepare( "SELECT image_size FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'media' AND resize = %s", $id, 'full' ) ); if ( empty( $full_filesize ) ) { return $meta; } } else { $full_filesize = ewww_image_optimizer_filesize( $file_path ); } if ( $full_filesize ) { ewwwio_debug_message( "updating full to $full_filesize" ); $meta['filesize'] = (int) $full_filesize; } if ( isset( $meta['sizes'] ) && ewww_image_optimizer_iterable( $meta['sizes'] ) ) { foreach ( $meta['sizes'] as $size => $data ) { if ( $use_db && ! empty( $size ) ) { $scaled_filesize = $wpdb->get_var( $wpdb->prepare( "SELECT image_size FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'media' AND resize = %s", $id, $size ) ); if ( ! $scaled_filesize ) { ewwwio_debug_message( 'checking other thumbs for filesize' ); // Check through all the other sizes. foreach ( $meta['sizes'] as $index => $item ) { // If a different resize had identical dimensions. if ( $item['height'] === $data['height'] && $item['width'] === $data['width'] && ! empty( $item['filesize'] ) && ( ! isset( $data['filesize'] ) || (int) $item['filesize'] !== (int) $data['filesize'] ) ) { ewwwio_debug_message( "using $index filesize for $size" ); $scaled_filesize = $item['filesize']; break; } } } } else { $resize_path = path_join( dirname( $file_path ), $data['file'] ); $scaled_filesize = ewww_image_optimizer_filesize( $resize_path ); } if ( $scaled_filesize ) { ewwwio_debug_message( "updating $size to $scaled_filesize" ); $meta['sizes'][ $size ]['filesize'] = $scaled_filesize; } } } return $meta; } /** * Retrieves the path of an attachment via the $id and the $meta. * * @param array $meta The attachment metadata. * @param int $id The attachment ID number. * @param string $file Optional. Path relative to the uploads folder. Default ''. * @param bool $refresh_cache Optional. True to flush cache prior to fetching path. Default true. * @return array { * Information about the file. * * @type string The full path to the image. * @type string The path to the uploads folder. * } */ function ewww_image_optimizer_attachment_path( $meta, $id, $file = '', $refresh_cache = true ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); // Retrieve the location of the WordPress upload folder. $upload_dir = wp_upload_dir( null, false, $refresh_cache ); $upload_path = trailingslashit( $upload_dir['basedir'] ); if ( ! $file ) { $file = get_post_meta( $id, '_wp_attached_file', true ); } else { ewwwio_debug_message( 'using prefetched _wp_attached_file' ); } $file_path = ( 0 !== strpos( $file, '/' ) && ! preg_match( '|^.:\\\|', $file ) ? $upload_path . $file : $file ); $filtered_file_path = apply_filters( 'get_attached_file', $file_path, $id ); ewwwio_debug_message( "WP (filtered) thinks the file is at: $filtered_file_path" ); if ( ( ! ewww_image_optimizer_stream_wrapped( $filtered_file_path ) || ewww_image_optimizer_stream_wrapper_exists() ) && ewwwio_is_file( $filtered_file_path ) ) { return array( str_replace( '//_imsgalleries/', '/_imsgalleries/', $filtered_file_path ), $upload_path ); } ewwwio_debug_message( "WP (unfiltered) thinks the file is at: $file_path" ); if ( ( ! ewww_image_optimizer_stream_wrapped( $file_path ) || ewww_image_optimizer_stream_wrapper_exists() ) && ewwwio_is_file( $file_path ) ) { return array( str_replace( '//_imsgalleries/', '/_imsgalleries/', $file_path ), $upload_path ); } if ( 'ims_image' === get_post_type( $id ) && is_array( $meta ) && ! empty( $meta['file'] ) ) { ewwwio_debug_message( "finding path for IMS image: $id " ); if ( is_dir( $file_path ) && ewwwio_is_file( $file_path . $meta['file'] ) ) { // Generate the absolute path. $file_path = $file_path . $meta['file']; $upload_path = ewww_image_optimizer_upload_path( $file_path, $upload_path ); ewwwio_debug_message( "found path for IMS image: $file_path" ); } elseif ( ewwwio_is_file( $meta['file'] ) ) { $file_path = $meta['file']; $upload_path = ewww_image_optimizer_upload_path( $file_path, $upload_path ); ewwwio_debug_message( "found path for IMS image: $file_path" ); } else { $upload_path = trailingslashit( WP_CONTENT_DIR ); $file_path = $upload_path . ltrim( $meta['file'], '/' ); ewwwio_debug_message( "checking path for IMS image: $file_path" ); if ( ! file_exists( $file_path ) ) { $file_path = ''; } } return array( $file_path, $upload_path ); } if ( is_array( $meta ) && ! empty( $meta['file'] ) ) { $file_path = $meta['file']; if ( ewww_image_optimizer_stream_wrapped( $file_path ) && ! ewww_image_optimizer_stream_wrapper_exists() ) { return array( '', $upload_path ); } ewwwio_debug_message( "looking for file at $file_path" ); if ( ewwwio_is_file( $file_path ) ) { return array( $file_path, $upload_path ); } $file_path = trailingslashit( $upload_path ) . $file_path; ewwwio_debug_message( "that did not work, try it with the upload_dir: $file_path" ); if ( ewwwio_is_file( $file_path ) ) { return array( $file_path, $upload_path ); } $upload_path = trailingslashit( WP_CONTENT_DIR ) . 'uploads/'; $file_path = $upload_path . $meta['file']; ewwwio_debug_message( "one last shot, using the wp-content/ constant: $file_path" ); if ( ewwwio_is_file( $file_path ) ) { return array( $file_path, $upload_path ); } } ewwwio_memory( __FUNCTION__ ); return array( '', $upload_path ); } /** * Removes parent folders to create a relative path. * * Replaces either ABSPATH, WP_CONTENT_DIR, or EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER with the literal * string name of the applicable constant. For example: /var/www/wp-content/uploads/test.jpg becomes * ABSPATHwp-content/uploads/test.jpg. * * @param string $file The filename to mangle. * @return string The filename with parent folders replaced by a constant name. */ function ewww_image_optimizer_relativize_path( $file ) { if ( ! defined( 'EWWW_IMAGE_OPTIMIZER_RELATIVE' ) || ! EWWW_IMAGE_OPTIMIZER_RELATIVE ) { return $file; } if ( defined( 'EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER' ) && EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER && strpos( $file, EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER ) === 0 ) { return str_replace( EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER, 'EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER', $file ); } if ( strpos( $file, trailingslashit( ABSPATH ) ) === 0 ) { return str_replace( trailingslashit( ABSPATH ), 'ABSPATH', $file ); } if ( defined( 'WP_CONTENT_DIR' ) && WP_CONTENT_DIR && strpos( $file, WP_CONTENT_DIR ) === 0 ) { return str_replace( WP_CONTENT_DIR, 'WP_CONTENT_DIR', $file ); } return $file; } /** * Replaces constant names with their actual values to recreate an absolute path. * * Replaces the literal strings 'ABSPATH', 'WP_CONTENT_DIR', or * 'EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER' with the actual value of the constant contained within * the file path. * * @param string $file The filename to parse. * @return string The full filename with parent folders reinserted. */ function ewww_image_optimizer_absolutize_path( $file ) { if ( ! defined( 'EWWW_IMAGE_OPTIMIZER_RELATIVE' ) ) { return $file; } if ( defined( 'EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER' ) && EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER && strpos( $file, 'EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER' ) === 0 ) { return str_replace( 'EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER', EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER, $file ); } if ( strpos( $file, 'ABSPATH' ) === 0 ) { return str_replace( 'ABSPATH', trailingslashit( ABSPATH ), $file ); } if ( defined( 'WP_CONTENT_DIR' ) && WP_CONTENT_DIR && strpos( $file, 'WP_CONTENT_DIR' ) === 0 ) { return str_replace( 'WP_CONTENT_DIR', WP_CONTENT_DIR, $file ); } return $file; } /** * Takes a file and upload folder, and makes sure that the file is within the folder. * * Used for path replacement with async processing, since security plugins can block * POSTing of full paths. * * @param string $file Name of the file. * @param string $upload_path Location of the upload directory. * @return string The upload path or an empty string if the file is outside the uploads folder. */ function ewww_image_optimizer_upload_path( $file, $upload_path ) { if ( strpos( $file, $upload_path ) === 0 ) { return $upload_path; } else { return ''; } } /** * Takes a human-readable size, and generates an approximate byte-size. * * @param string $formatted A human-readable file size. * @return int The approximated filesize. */ function ewww_image_optimizer_size_unformat( $formatted ) { $size_parts = explode( ' ', $formatted ); switch ( $size_parts[1] ) { case 'B': return intval( $size_parts[0] ); case 'kB': return intval( $size_parts[0] * 1024 ); case 'MB': return intval( $size_parts[0] * 1048576 ); case 'GB': return intval( $size_parts[0] * 1073741824 ); case 'TB': return intval( $size_parts[0] * 1099511627776 ); default: return 0; } } /** * Generate a unique filename for a converted image. * * @param string $file The filename to test for uniqueness. * @param string $fileext The extension to replace the existing file extension. * @return string A unique filename. */ function ewww_image_optimizer_unique_filename( $file, $fileext ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); // Change the file extension. $fileinfo = pathinfo( $file ); if ( empty( $fileinfo['filename'] ) || empty( $fileinfo['dirname'] ) ) { // NOTE: This should never happen, but if it does, we'll be prepared, sort of! return preg_replace( '/\.\w+$/', '-' . uniqid() . $fileext, $file ); } $filename = $fileinfo['filename'] . $fileext; $filenum = ''; add_filter( 'wp_unique_filename', 'ewww_image_optimizer_get_unique_filename_iterator', 99, 6 ); $newname = wp_unique_filename( $fileinfo['dirname'], $filename ); remove_filter( 'wp_unique_filename', 'ewww_image_optimizer_get_unique_filename_iterator', 99 ); return trailingslashit( $fileinfo['dirname'] ) . $newname; } /** * Retrieve the unique filename iterator/number from wp_unique_filename(). * * @param string $filename Unique file name. * @param string $ext File extension. Example: ".png". * @param string $dir Directory path. * @param callable|null $unique_filename_callback Callback function that generates the unique file name. * @param string[] $alt_filenames Array of alternate file names that were checked for collisions. * @param int|string $number The highest number that was used to make the file name unique * or an empty string if unused. */ function ewww_image_optimizer_get_unique_filename_iterator( $filename, $ext, $dir, $unique_filename_callback, $alt_filenames = array(), $number = '' ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( ! empty( $number ) ) { ewwwio_debug_message( "collision avoidance iterator: $number" ); global $ewww_image; if ( isset( $ewww_image ) && is_object( $ewww_image ) ) { ewwwio_debug_message( 'storing in increment property' ); $ewww_image->increment = $number; } } return $filename; } /** * Get mimetype based on file extension instead of file contents when speed outweighs accuracy. * * @param string $path The name of the file. * @return string|bool The mime type based on the extension or false. */ function ewww_image_optimizer_quick_mimetype( $path ) { $pathextension = strtolower( pathinfo( $path, PATHINFO_EXTENSION ) ); switch ( $pathextension ) { case 'jpg': case 'jpeg': case 'jpe': return 'image/jpeg'; case 'png': return 'image/png'; case 'gif': return 'image/gif'; case 'webp': return 'image/webp'; case 'pdf': return 'application/pdf'; case 'svg': return 'image/svg+xml'; default: if ( empty( $pathextension ) && ! ewww_image_optimizer_stream_wrapped( $path ) && ewwwio_is_file( $path ) ) { return ewww_image_optimizer_mimetype( $path, 'i' ); } return false; } } /** * Check a PNG to see if it has transparency. * * @param string $filename The name of the PNG file. * @return bool True if transparency is found. */ function ewww_image_optimizer_png_alpha( $filename ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( ! ewwwio_is_file( $filename ) ) { return false; } if ( false !== strpos( $filename, '../' ) ) { return false; } list( $width, $height ) = wp_getimagesize( $filename ); ewwwio_debug_message( "image dimensions: $width x $height" ); if ( ! ewwwio()->gd_support() || ! ewwwio_check_memory_available( ( $width * $height ) * 4.8 ) ) { // 4.8 = 24-bit or 3 bytes per pixel multiplied by a factor of 1.6 for extra wiggle room. global $eio_filesystem; ewwwio_get_filesystem(); $file_contents = $eio_filesystem->get_contents( $filename ); // Determine what color type is stored in the file. $color_type = ord( substr( $file_contents, 25, 1 ) ); unset( $file_contents ); ewwwio_debug_message( "color type: $color_type" ); if ( 4 === $color_type || 6 === $color_type ) { ewwwio_debug_message( 'transparency found' ); return true; } } elseif ( ewwwio()->gd_support() ) { $image = imagecreatefrompng( $filename ); if ( ! $image ) { ewwwio_debug_message( 'could not load image' ); return false; } if ( imagecolortransparent( $image ) >= 0 ) { ewwwio_debug_message( 'transparency found' ); return true; } ewwwio_debug_message( 'preparing to scan image' ); for ( $y = 0; $y < $height; $y++ ) { for ( $x = 0; $x < $width; $x++ ) { $color = imagecolorat( $image, $x, $y ); $rgb = imagecolorsforindex( $image, $color ); if ( $rgb['alpha'] > 0 ) { ewwwio_debug_message( 'transparency found' ); return true; } } } } ewwwio_debug_message( 'no transparency' ); return false; } /** * Check the submitted GIF to see if it is animated. * * @param string $filename Name of the GIF to test for animation. * @return bool True if animation found. */ function ewww_image_optimizer_is_animated( $filename ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( ! ewwwio_is_file( $filename ) ) { return false; } // If we can't open the file in read-only buffered mode. $fh = fopen( $filename, 'rb' ); if ( ! $fh ) { return false; } $count = 0; // We read through the file til we reach the end of the file, or we've found at least 2 frame headers. while ( ! feof( $fh ) && $count < 2 ) { $chunk = fread( $fh, 1024 * 100 ); // Read 100kb at a time. $count += preg_match_all( '#\x00\x21\xF9\x04.{4}\x00(\x2C|\x21)#s', $chunk, $matches ); } fclose( $fh ); ewwwio_debug_message( "scanned GIF and found $count frames" ); ewwwio_memory( __FUNCTION__ ); return $count > 1; } /** * Check the submitted PNG to see if it is animated. Thanks @GregOriol! * * @param string $filename Name of the PNG to test for animation. * @return bool True if animation found. */ function ewww_image_optimizer_is_animated_png( $filename ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); $apng = false; if ( ! ewwwio_is_file( $filename ) ) { return false; } // If we can't open the file in read-only buffered mode. $fh = fopen( $filename, 'rb' ); if ( ! $fh ) { return false; } $previousdata = ''; // We read through the file til we reach the end of the file, or we've found an acTL or IDAT chunk. while ( ! feof( $fh ) ) { $data = fread( $fh, 1024 ); // Read 1kb at a time. if ( false !== strpos( $data, 'acTL' ) ) { ewwwio_debug_message( 'found acTL chunk (animated) in PNG' ); $apng = true; break; } elseif ( false !== strpos( $previousdata . $data, 'acTL' ) ) { ewwwio_debug_message( 'found acTL chunk (animated) in PNG' ); $apng = true; break; } elseif ( false !== strpos( $data, 'IDAT' ) ) { ewwwio_debug_message( 'found IDAT, but no acTL (animated) chunk in PNG' ); break; } elseif ( false !== strpos( $previousdata . $data, 'IDAT' ) ) { ewwwio_debug_message( 'found IDAT, but no acTL (animated) chunk in PNG' ); break; } $previousdata = $data; } fclose( $fh ); return $apng; } /** * Check a JPG to see if it uses the CMYK color space. * * @param string $filename Name of the JPG to test. * @return bool True if CMYK, false otherwise. */ function ewww_image_optimizer_is_cmyk( $filename ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); if ( ewwwio()->imagick_support() ) { $image = new Imagick( $filename ); $color = $image->getImageColorspace(); ewwwio_debug_message( "color space is $color" ); $image->destroy(); if ( Imagick::COLORSPACE_CMYK === $color ) { return true; } } elseif ( ewwwio()->gd_support() ) { $info = getimagesize( $filename ); if ( ! empty( $info['channels'] ) ) { ewwwio_debug_message( "channel count is {$info['channels']}" ); if ( 4 === (int) $info['channels'] ) { return true; } } } return false; } /** * Count how many sizes are in the metadata, accounting for those with duplicate dimensions. * * @param array $sizes A list of resize information from an attachment. * @return int The number of sizes found. */ function ewww_image_optimizer_resize_count( $sizes ) { if ( empty( $sizes ) || ! is_array( $sizes ) ) { return 0; } $size_count = 0; $processed = array(); foreach ( $sizes as $size => $data ) { if ( strpos( $size, 'webp' ) === 0 ) { continue; } if ( empty( $data['file'] ) ) { continue; } // Check through all the sizes we've processed so far. foreach ( $processed as $proc => $scan ) { // If a previous resize had identical dimensions. if ( $scan['height'] === $data['height'] && $scan['width'] === $data['width'] ) { continue( 2 ); } } // If this is a unique size. ++$size_count; // Sore info on the sizes we've processed, so we can check the list for duplicate sizes. $processed[ $size ]['width'] = $data['width']; $processed[ $size ]['height'] = $data['height']; } return $size_count; } /** * Add column header for optimizer results in the media library listing. * * @param array $columns A list of columns in the media library. * @return array The new list of columns. */ function ewww_image_optimizer_columns( $columns ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); $columns['ewww-image-optimizer'] = esc_html__( 'Image Optimizer', 'ewww-image-optimizer' ); ewwwio_memory( __FUNCTION__ ); return $columns; } /** * Print column data for optimizer results in the media library. * * @global object $wpdb * * @param string $column_name The name of the column being displayed. * @param int $id The attachment ID number. * @param array $meta Optional. The attachment metadata. Default null. * @return string The data that would normally be output directly by the custom_column function. */ function ewww_image_optimizer_custom_column_capture( $column_name, $id, $meta = null ) { ob_start(); ewww_image_optimizer_custom_column( $column_name, $id, $meta ); return ob_get_clean(); } /** * Print column data for optimizer results in the media library. * * @global object $wpdb * * @param string $column_name The name of the column being displayed. * @param int $id The attachment ID number. * @param array $meta Optional. The attachment metadata. Default null. */ function ewww_image_optimizer_custom_column( $column_name, $id, $meta = null ) { ewwwio_debug_message( '' . __FUNCTION__ . '()' ); // Once we get to the EWWW IO custom column. if ( 'ewww-image-optimizer' === $column_name ) { $id = (int) $id; if ( is_null( $meta ) ) { // Retrieve the metadata. $meta = wp_get_attachment_metadata( $id ); } echo '' . esc_html__( 'Image Size', 'ewww-image-optimizer' ) . ' | ' . esc_html__( 'Savings', 'ewww-image-optimizer' ) . ' | |
---|---|---|
' . ucfirst( $optimized_image['resize'] ) . " | $display_size | " . esc_html( ewww_image_optimizer_image_results( $optimized_image['orig_size'], $optimized_image['image_size'] ) ) . ' |
' . esc_html__( 'Bulk Optimizer', 'ewww-image-optimizer' ) . '' ); ewwwio_help_link( 'https://docs.ewww.io/article/4-getting-started', '5853713bc697912ffd6c0b98' ); ?>
' . esc_html__( 'List View in the Media Library', 'ewww-image-optimizer' ) . '',
'wp help ewwwio optimize
'
);
ewwwio_help_link( 'https://docs.ewww.io/article/25-optimizing-with-wp-cli', '592da1482c7d3a074e8aeb6b' );
?>
https://ewww.io/',
'SPEEDER1012
'
);
}
?>
' . esc_html__( 'and more', 'ewww-image-optimizer' ) . '' ); ?>
$exactdn_network_enabled ) : ?> -
get_exactdn_domain() && $exactdn->verify_domain( $exactdn->get_exactdn_domain() ) ) : ?>
get_exactdn_domain() ); ?>
get_exactdn_domain() && $exactdn->get_exactdn_option( 'verified' ) ) : ?>
get_exactdn_domain() && $exactdn->get_exactdn_option( 'suspended' ) ) : ?>
';
'>
' . esc_html__( 'Bulk Optimizer', 'ewww-image-optimizer' ) . '' ); ?>
*
' . esc_html__( 'Bulk Optimizer', 'ewww-image-optimizer' ) . '', '' . esc_html__( 'Easy IO', 'ewww-image-optimizer' ) . '' ); ?>
*
/> | |
|
|
value='true' /> | |
/> | |
|
|
|
/>
imagick_support() ) : ?>
|
|
|
|
/>
|
|
/> |
/> | ||||||||||||
/> | ||||||||||||
/> | ||||||||||||
|
|
' />
/> | |
/> | |
/> | |
/> # | |
/> | |
|
' />
user_email; $hs_debug = ''; if ( ! empty( $debug_info ) ) { $hs_debug = str_replace( array( "'", '