This commit is contained in:
Tony Volpe
2024-06-17 14:41:24 -04:00
parent f885e93ca8
commit a00f379f7f
11158 changed files with 0 additions and 1781316 deletions

View File

@@ -1,27 +0,0 @@
<?php
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
/**
* Plugins.
*/
require IMAGIFY_PATH . 'inc/3rd-party/amazon-s3-and-cloudfront/amazon-s3-and-cloudfront.php';
require IMAGIFY_PATH . 'inc/3rd-party/amp/amp.php';
require IMAGIFY_PATH . 'inc/3rd-party/enable-media-replace/enable-media-replace.php';
require IMAGIFY_PATH . 'inc/3rd-party/formidable-pro/formidable-pro.php';
require IMAGIFY_PATH . 'inc/3rd-party/nextgen-gallery/nextgen-gallery.php';
require IMAGIFY_PATH . 'inc/3rd-party/regenerate-thumbnails/regenerate-thumbnails.php';
require IMAGIFY_PATH . 'inc/3rd-party/screets-lc.php';
require IMAGIFY_PATH . 'inc/3rd-party/wp-real-media-library.php';
require IMAGIFY_PATH . 'inc/3rd-party/wp-cloudflare-super-page-cache.php';
require IMAGIFY_PATH . 'inc/3rd-party/wp-rocket/wp-rocket.php';
require IMAGIFY_PATH . 'inc/3rd-party/yoast-seo.php';
require IMAGIFY_PATH . 'inc/3rd-party/WooCommerce/class-woocommerce.php';
/**
* Hosting.
*/
require IMAGIFY_PATH . 'inc/3rd-party/hosting/flywheel.php';
require IMAGIFY_PATH . 'inc/3rd-party/hosting/pressable.php';
require IMAGIFY_PATH . 'inc/3rd-party/hosting/siteground.php';
require IMAGIFY_PATH . 'inc/3rd-party/hosting/wordpress-com.php';
require IMAGIFY_PATH . 'inc/3rd-party/hosting/wpengine.php';

View File

@@ -1,95 +0,0 @@
<?php
namespace Imagify\ThirdParty\WooCommerce;
/**
* Compatibility for WooCommerce.
*
* @since 1.10.0
*/
class WooCommerce {
/**
* Initialize compatibility functionality.
*
* @since 1.10.0
*
* @return void
*/
public function init() {
add_action( 'woocommerce_single_product_summary', [ $this, 'variable_products_nextgen_compat' ] );
}
/**
* Add Variable Products Next-gen images Compatibility.
*
* @since 1.10.0
*
* @return void
*/
public function variable_products_nextgen_compat() {
global $product;
if ( ! isset( $product ) || ! $product->is_type( 'variable' ) ) {
return;
}
add_filter( 'imagify_picture_attributes', [ $this, 'remove_wp_post_image_class' ], 10, 2 );
add_filter(
'imagify_picture_source_attributes',
[ $this, 'maybe_add_wp_post_image_class_on_picture_internal_tags' ],
10,
2
);
add_filter(
'imagify_picture_img_attributes',
[ $this, 'maybe_add_wp_post_image_class_on_picture_internal_tags' ],
10,
2
);
}
/**
* Remove wp-post-image class from picture tags.
*
* @since 1.10.0
*
* @param array $attributes The picture tag attributes.
*
* @return array The picture tage attributes with modified or removed 'class'.
*/
public function remove_wp_post_image_class( $attributes ) {
if ( isset( $attributes['class'] ) ) {
$attributes['class'] = str_replace( 'wp-post-image', '', $attributes['class'] );
}
if ( empty( $attributes['class'] ) ) {
unset( $attributes['class'] );
}
return $attributes;
}
/**
* Add wp-post-image class to source and image tags internal to a picture tag.
*
* @since 1.10.0
*
* @param array $attributes The source or img tag attributes.
* @param array $image The original image tag data.
*
* @return array Source or image tag attributes with modified 'class'.
*/
public function maybe_add_wp_post_image_class_on_picture_internal_tags( $attributes, $image ) {
if (
! empty( $image['attributes']['class'] )
&& strpos( $image['attributes']['class'], 'wp-post-image' ) !== false
) {
$attributes['class'] = isset( $attributes['class'] )
? $attributes['class'] . ' wp-post-image'
: 'wp-post-image';
}
return $attributes;
}
}
( new WooCommerce() )->init();

View File

@@ -1,64 +0,0 @@
<?php
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
/**
* Tell if WP Offload S3 compatibility is loaded.
*
* @since 1.7
* @author Grégory Viguier
*
* @return bool
*/
function imagify_load_as3cf_compat() {
if ( function_exists( 'as3cf_init' ) ) {
// WP Offload S3 Lite.
$version = ! empty( $GLOBALS['aws_meta']['amazon-s3-and-cloudfront']['version'] ) ? $GLOBALS['aws_meta']['amazon-s3-and-cloudfront']['version'] : false;
if ( ! $version ) {
return false;
}
if ( ! function_exists( 'amazon_web_services_init' ) && version_compare( $version, '1.3' ) < 0 ) {
// Old version, plugin Amazon Web Services is required.
return false;
}
if ( version_compare( $version, '2.3' ) >= 0 ) {
// A new version that removes a punlic method.
return false;
}
return true;
}
if ( function_exists( 'as3cf_pro_init' ) ) {
// WP Offload S3 Pro.
$version = ! empty( $GLOBALS['aws_meta']['amazon-s3-and-cloudfront-pro']['version'] ) ? $GLOBALS['aws_meta']['amazon-s3-and-cloudfront-pro']['version'] : false;
if ( ! $version ) {
return false;
}
if ( ! function_exists( 'amazon_web_services_init' ) && version_compare( $version, '1.6' ) < 0 ) {
// Old version, plugin Amazon Web Services is required.
return false;
}
if ( version_compare( $version, '2.3' ) >= 0 ) {
// A new version that removes a punlic method.
return false;
}
return true;
}
return false;
}
if ( imagify_load_as3cf_compat() ) :
class_alias( '\\Imagify\\ThirdParty\\AS3CF\\Main', '\\Imagify_AS3CF' );
add_action( 'imagify_loaded', [ \Imagify\ThirdParty\AS3CF\Main::get_instance(), 'init' ], 1 );
endif;

View File

@@ -1,513 +0,0 @@
<?php
namespace Imagify\ThirdParty\AS3CF\CDN\WP;
use Imagify\CDN\PushCDNInterface;
use Imagify\Context\ContextInterface;
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
/**
* AS3 CDN for WP context.
*
* @since 1.9
* @author Grégory Viguier
*/
class AS3 implements PushCDNInterface {
/**
* The media ID.
*
* @var int
* @since 1.9
* @access protected
* @author Grégory Viguier
*/
protected $id;
/**
* Filesystem object.
*
* @var object Imagify_Filesystem
* @since 1.9
* @access protected
* @author Grégory Viguier
*/
protected $filesystem;
/**
* Tell if were playing in WP 5.3s garden.
*
* @var bool
* @since 1.9.8
* @access protected
* @author Grégory Viguier
*/
protected $is_wp53;
/**
* Constructor.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param int $media_id The media ID.
*/
public function __construct( $media_id ) {
$this->id = (int) $media_id;
$this->filesystem = \Imagify_Filesystem::get_instance();
}
/**
* Tell if the CDN is ready (not necessarily reachable).
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @return bool
*/
public function is_ready() {
global $as3cf;
static $is;
if ( ! isset( $is ) ) {
$is = $as3cf && $as3cf->is_plugin_setup();
}
return $is;
}
/**
* Tell if the media is on the CDN.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @return bool
*/
public function media_is_on_cdn() {
return (bool) $this->get_cdn_info();
}
/**
* Get files from the CDN.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param array $file_paths A list of file paths.
* @return bool|\WP_Error True on success. A \WP_error object on failure.
*/
public function get_files_from_cdn( $file_paths ) {
global $as3cf;
if ( ! $this->is_ready() ) {
return new \WP_Error( 'not_ready', __( 'CDN is not set up.', 'imagify' ) );
}
$cdn_info = $this->get_cdn_info();
if ( ! $cdn_info ) {
// The media is not on the CDN.
return new \WP_Error( 'not_on_cdn', __( 'This media could not be found on the CDN.', 'imagify' ) );
}
$directory = $this->filesystem->dir_path( $cdn_info['key'] );
$directory = $this->filesystem->is_root( $directory ) ? '' : $directory;
$new_method = method_exists( $as3cf->plugin_compat, 'copy_s3_file_to_server' );
$errors = [];
foreach ( $file_paths as $file_path ) {
$cdn_info['key'] = $directory . $this->filesystem->file_name( $file_path );
// Retrieve file from the CDN.
if ( $new_method ) {
$as3cf->plugin_compat->copy_s3_file_to_server( $cdn_info, $file_path );
} else {
$as3cf->plugin_compat->copy_provider_file_to_server( $cdn_info, $file_path );
}
if ( ! $this->filesystem->exists( $file_path ) ) {
$errors[] = $file_path;
}
}
if ( $errors ) {
$nbr_errors = count( $errors );
$errors_txt = array_map( [ $this->filesystem, 'make_path_relative' ], $errors );
$errors_txt = wp_sprintf_l( '%l', $errors_txt );
return new \WP_Error(
'not_retrieved',
sprintf(
/* translators: %s is a list of file paths. */
_n( 'The following file could not be retrieved from the CDN: %s.', 'The following files could not be retrieved from the CDN: %s.', $nbr_errors, 'imagify' ),
$errors_txt
),
$errors
);
}
return true;
}
/**
* Remove files from the CDN.
* Don't use this to empty a folder.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param array $file_paths A list of file paths. Those paths are not necessary absolute, and can be also file names.
* @return bool|\WP_Error True on success. A \WP_error object on failure.
*/
public function remove_files_from_cdn( $file_paths ) {
global $as3cf;
if ( ! $this->is_ready() ) {
return new \WP_Error( 'not_ready', __( 'CDN is not set up.', 'imagify' ) );
}
$cdn_info = $this->get_cdn_info();
if ( ! $cdn_info ) {
// The media is not on the CDN.
return new \WP_Error( 'not_on_cdn', __( 'This media could not be found on the CDN.', 'imagify' ) );
}
$directory = $this->filesystem->dir_path( $cdn_info['key'] );
$directory = $this->filesystem->is_root( $directory ) ? '' : $directory;
if ( method_exists( $as3cf, 'get_s3object_region' ) ) {
$region = $as3cf->get_s3object_region( $cdn_info );
} else {
$region = $as3cf->get_provider_object_region( $cdn_info );
}
if ( is_wp_error( $region ) ) {
$region = '';
}
$to_remove = [];
foreach ( $file_paths as $file_path ) {
$to_remove[] = [
'Key' => $directory . $this->filesystem->file_name( $file_path ),
];
}
if ( method_exists( $as3cf, 'delete_s3_objects' ) ) {
$result = $as3cf->delete_s3_objects( $region, $cdn_info['bucket'], $to_remove, false, false, false );
} else {
$result = $as3cf->delete_objects( $region, $cdn_info['bucket'], $to_remove, false, false, false );
}
if ( is_wp_error( $result ) ) {
return new \WP_Error( 'deletion_failed', __( 'File(s) could not be removed from the CDN.', 'imagify' ) );
}
return true;
}
/**
* Send all files from a media to the CDN.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param bool $is_new_upload Tell if the current media is a new upload. If not, it means it's a media being regenerated, restored, etc.
* @return bool|\WP_Error True/False if sent or not. A \WP_error object on failure.
*/
public function send_to_cdn( $is_new_upload ) {
global $as3cf;
if ( ! $this->is_ready() ) {
return new \WP_Error( 'not_ready', __( 'CDN is not set up.', 'imagify' ) );
}
if ( ! $this->can_send_to_cdn( $is_new_upload ) ) {
return false;
}
// Retrieve the missing files from the CDN: we must send all of them at once, even those that have not been modified.
$file_paths = \AS3CF_Utils::get_attachment_file_paths( $this->id, false );
if ( $file_paths ) {
foreach ( $file_paths as $size => $file_path ) {
if ( $this->filesystem->exists( $file_path ) ) {
// Keep only the files that don't exist.
unset( $file_paths[ $size ] );
}
}
}
if ( $file_paths ) {
$result = $this->get_files_from_cdn( $file_paths );
if ( is_wp_error( $result ) ) {
return $result;
}
}
$remove_local_files = $this->should_delete_files( $is_new_upload );
if ( ! $is_new_upload ) {
if ( $remove_local_files ) {
// Force files deletion when not a new media.
add_filter( 'as3cf_get_setting', [ $this, 'force_local_file_removal_setting' ], 100, 2 );
add_filter( 'as3cf_setting_remove-local-file', 'imagify_return_true', 100 );
} else {
// Force to keep the files when not a new media.
add_filter( 'as3cf_get_setting', [ $this, 'force_local_file_keep_setting' ], 100, 2 );
add_filter( 'as3cf_setting_remove-local-file', 'imagify_return_false', 100 );
}
}
if ( method_exists( $as3cf, 'upload_attachment_to_s3' ) ) {
$result = $as3cf->upload_attachment_to_s3( $this->id, null, null, false, $remove_local_files );
} else {
$result = $as3cf->upload_attachment( $this->id, null, null, false, $remove_local_files );
}
if ( ! $is_new_upload ) {
if ( $remove_local_files ) {
remove_filter( 'as3cf_get_setting', [ $this, 'force_local_file_removal_setting' ], 100 );
remove_filter( 'as3cf_setting_remove-local-file', 'imagify_return_true', 100 );
} else {
remove_filter( 'as3cf_get_setting', [ $this, 'force_local_file_keep_setting' ], 100 );
remove_filter( 'as3cf_setting_remove-local-file', 'imagify_return_false', 100 );
}
}
if ( is_wp_error( $result ) ) {
return $result;
}
return true;
}
/**
* Get a file URL.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param string $file_name Name of the file. Leave empty for the full size file.
* @return string URL to the file.
*/
public function get_file_url( $file_name = false ) {
$file_url = wp_get_attachment_url( $this->id );
if ( $file_name ) {
// It's not the full size.
$file_url = $this->filesystem->dir_path( $file_url ) . $file_name;
}
return $file_url;
}
/**
* Get a file path.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param string $file_name Name of the file. Leave empty for the full size file. Use 'original' to get the path to the original file.
* @return string Path to the file.
*/
public function get_file_path( $file_name = false ) {
if ( ! $file_name ) {
// Full size.
return get_attached_file( $this->id, true );
}
if ( 'original' === $file_name ) {
// Original file.
if ( $this->is_wp_53() ) {
// `wp_get_original_image_path()` may return false.
$file_path = wp_get_original_image_path( $this->id );
} else {
$file_path = false;
}
if ( ! $file_path ) {
$file_path = get_attached_file( $this->id, true );
}
return $file_path;
}
// Thumbnail.
$file_path = get_attached_file( $this->id, true );
$file_path = $this->filesystem->dir_path( $file_path ) . $file_name;
return $file_path;
}
/** ----------------------------------------------------------------------------------------- */
/** INTERNAL TOOLS ========================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Filter the CDN setting 'remove-local-file': this is used to force deletion when the media is not a new one.
* Caution to not use $this->should_delete_files() when this filter is used!
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param bool $setting The setting value.
* @param string $key The setting name.
* @return bool
*/
public function force_local_file_removal_setting( $setting, $key ) {
if ( 'remove-local-file' === $key ) {
return true;
}
return $setting;
}
/**
* Filter the CDN setting 'remove-local-file': this is used to force not-deletion when the media is not a new one.
* Caution to not use $this->should_delete_files() when this filter is used!
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param bool $setting The setting value.
* @param string $key The setting name.
* @return bool
*/
public function force_local_file_keep_setting( $setting, $key ) {
if ( 'remove-local-file' === $key ) {
return false;
}
return $setting;
}
/**
* Tell if a media is stored on the CDN.
*
* @since 1.9
* @access protected
* @author Grégory Viguier
*
* @return array|bool The CDN info on success. False if the media is not on the CDN.
*/
protected function get_cdn_info() {
global $as3cf;
if ( ! $as3cf ) {
return false;
}
if ( method_exists( $as3cf, 'get_attachment_s3_info' ) ) {
return $as3cf->get_attachment_s3_info( $this->id );
}
return $as3cf->get_attachment_provider_info( $this->id );
}
/**
* Tell if a media can (and should) be sent to the CDN.
*
* @since 1.9
* @access protected
* @author Grégory Viguier
*
* @param bool $is_new_upload Tell if the current media is a new upload. If not, it means it's a media being regenerated, restored, etc.
* @return bool
*/
protected function can_send_to_cdn( $is_new_upload ) {
global $as3cf;
static $can = [];
static $cdn_setting;
if ( isset( $can[ $this->id ] ) ) {
return $can[ $this->id ];
}
if ( ! $this->is_ready() ) {
$can[ $this->id ] = false;
return $can[ $this->id ];
}
if ( ! isset( $cdn_setting ) ) {
$cdn_setting = $as3cf && $as3cf->get_setting( 'copy-to-s3' );
}
// The CDN is set up: test if the media is on it.
$can[ $this->id ] = $this->media_is_on_cdn();
if ( $can[ $this->id ] && $is_new_upload ) {
// Use the CDN setting to tell if we're allowed to send the files (should be true since it's a new upload and it's already there).
$can[ $this->id ] = $cdn_setting;
}
/**
* Tell if a media can (and should) be sent to the CDN.
*
* @since 1.9
* @author Grégory Viguier
*
* @param bool $can True if the media can be sent. False otherwize.
* @param PushCDNInterface $cdn The CDN instance.
* @param bool $cdn_setting CDN setting that tells if a new media can be sent to the CDN.
* @param bool $is_new_upload Tell if the current media is a new upload. If not, it means it's a media being regenerated, restored, etc.
*/
$can[ $this->id ] = (bool) apply_filters( 'imagify_can_send_to_cdn', $can[ $this->id ], $this, $cdn_setting, $is_new_upload );
return $can[ $this->id ];
}
/**
* Tell if the files should be deleted after optimization.
*
* @since 1.9
* @access protected
* @author Grégory Viguier
*
* @param bool $is_new_upload Tell if the current media is a new upload. If not, it means it's a media being regenerated, restored, etc.
* @return bool
*/
protected function should_delete_files( $is_new_upload ) {
global $as3cf;
if ( $is_new_upload ) {
return (bool) $as3cf->get_setting( 'remove-local-file' );
}
// If the attachment has a 'filesize' metadata, that means the local files are meant to be deleted.
return (bool) get_post_meta( $this->id, 'wpos3_filesize_total', true );
}
/**
* Tell if were playing in WP 5.3s garden.
*
* @since 1.9.8
* @access protected
* @author Grégory Viguier
*
* @return bool
*/
protected function is_wp_53() {
if ( isset( $this->is_wp53 ) ) {
return $this->is_wp53;
}
$this->is_wp53 = function_exists( 'wp_get_original_image_path' );
return $this->is_wp53;
}
}

View File

@@ -1,631 +0,0 @@
<?php
namespace Imagify\ThirdParty\AS3CF;
use \Imagify\Optimization\File;
use \Imagify\ThirdParty\AS3CF\CDN\WP\AS3 as CDN;
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
/**
* Imagify WP Offload S3 class.
*
* @since 1.9
* @author Grégory Viguier
*/
class Main extends \Imagify_AS3CF_Deprecated {
use \Imagify\Traits\InstanceGetterTrait;
/**
* AS3CF settings.
*
* @var array
* @since 1.9
* @access protected
* @author Grégory Viguier
*/
protected $s3_settings;
/**
* Filesystem object.
*
* @var \Imagify_Filesystem
* @since 1.9
* @access protected
* @author Grégory Viguier
*/
protected $filesystem;
/**
* The class constructor.
*
* @since 1.6.6
* @author Grégory Viguier
*/
protected function __construct() {
$this->filesystem = \Imagify_Filesystem::get_instance();
}
/**
* Launch the hooks.
*
* @since 1.6.6
* @author Grégory Viguier
*/
public function init() {
static $done = false;
if ( $done ) {
return;
}
$done = true;
/**
* WebP images to display with a <picture> tag.
*/
add_action( 'as3cf_init', [ $this, 'store_s3_settings' ] );
add_filter( 'imagify_webp_picture_process_image', [ $this, 'picture_tag_webp_image' ] );
/**
* Register CDN.
*/
add_filter( 'imagify_cdn', [ $this, 'register_cdn' ], 8, 3 );
/**
* Optimization process.
*/
add_filter( 'imagify_before_optimize_size', [ $this, 'maybe_copy_file_from_cdn_before_optimization' ], 8, 6 );
add_action( 'imagify_after_optimize', [ $this, 'maybe_send_media_to_cdn_after_optimization' ], 8, 2 );
/**
* Restoration process.
*/
add_action( 'imagify_after_restore_media', [ $this, 'maybe_send_media_to_cdn_after_restore' ], 8, 4 );
/**
* WebP support.
*/
add_filter( 'as3cf_attachment_file_paths', [ $this, 'add_webp_images_to_attachment' ], 8, 3 );
add_filter( 'mime_types', [ $this, 'add_webp_support' ] );
/**
* Redirections.
*/
add_filter( 'imagify_redirect_to', [ $this, 'redirect_referrer' ] );
/**
* Stats.
*/
add_filter( 'imagify_total_attachment_filesize', [ $this, 'add_stats_for_s3_files' ], 8, 4 );
}
/** ----------------------------------------------------------------------------------------- */
/** OPTIMIZATION PROCESS ==================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* On AS3CF init, store its settings.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param \Amazon_S3_And_CloudFront $as3cf AS3CFs main instance.
*/
public function store_s3_settings( $as3cf ) {
if ( method_exists( $as3cf, 'get_settings' ) ) {
$this->store_s3_settings = (array) $as3cf->get_settings();
}
}
/**
* WebP images to display with a <picture> tag.
*
* @since 1.9
* @see \Imagify\Picture\Display->process_image()
* @author Grégory Viguier
*
* @param array $data An array of data for this image.
* @return array
*/
public function picture_tag_webp_image( $data ) {
global $wpdb;
if ( ! empty( $data['src']['webp_path'] ) ) {
// The file is local.
return $data;
}
$match = $this->is_s3_url( $data['src']['url'] );
if ( ! $match ) {
// The file is not on S3.
return $data;
}
// Get the image ID.
$post_id = (int) $wpdb->get_var(
$wpdb->prepare(
"SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wp_attached_file' AND meta_value = %s",
// We use only year/month + filename, we should not have any subdir between them for the main file.
$match['year_month'] . $match['filename']
)
);
if ( $post_id <= 0 ) {
// Not in the database.
return $data;
}
$s3_info = get_post_meta( $post_id, 'amazonS3_info', true );
$imagify_data = get_post_meta( $post_id, '_imagify_data', true );
if ( ! $s3_info || ! $imagify_data ) {
return $data;
}
$webp_size_suffix = constant( imagify_get_optimization_process_class_name( 'wp' ) . '::WEBP_SUFFIX' );
$webp_size_name = 'full' . $webp_size_suffix;
if ( ! empty( $imagify_data['sizes'][ $webp_size_name ]['success'] ) ) {
// We have a WebP image.
$data['src']['webp_exists'] = true;
}
if ( empty( $data['srcset'] ) ) {
return $data;
}
$meta_data = get_post_meta( $post_id, '_wp_attachment_metadata', true );
if ( empty( $meta_data['sizes'] ) ) {
return $data;
}
// Ease the search for corresponding file name.
$size_files = [];
foreach ( $meta_data['sizes'] as $size_name => $size_data ) {
$size_files[ $size_data['file'] ] = $size_name;
}
// Look for a corresponding size name.
foreach ( $data['srcset'] as $i => $srcset_data ) {
if ( empty( $srcset_data['webp_url'] ) ) {
// Not a supported image format.
continue;
}
if ( ! empty( $srcset_data['webp_path'] ) ) {
// The file is local.
continue;
}
$match = $this->is_s3_url( $srcset_data['url'] );
if ( ! $match ) {
// Not on S3.
continue;
}
// Try with no subdirs.
$filename = $match['filename'];
if ( isset( $size_files[ $filename ] ) ) {
$size_name = $size_files[ $filename ];
} else {
// Try with subdirs.
$filename = $match['subdirs'] . $match['filename'];
if ( isset( $size_files[ $filename ] ) ) {
$size_name = $size_files[ $filename ];
} elseif ( preg_match( '@/\d+/$@', $match['subdirs'] ) ) {
// Last try: the subdirs may contain the S3 versioning. If not the case, we can still build a pyramid with this code.
$filename = preg_replace( '@/\d+/$@', '/', $match['subdirs'] ) . $match['filename'];
if ( isset( $size_files[ $filename ] ) ) {
$size_name = $size_files[ $filename ];
} else {
continue;
}
}
}
$webp_size_name = $size_name . $webp_size_suffix;
if ( ! empty( $imagify_data['sizes'][ $webp_size_name ]['success'] ) ) {
// We have a WebP image.
$data['srcset'][ $i ]['webp_exists'] = true;
}
}
return $data;
}
/**
* The CDN to use for this media.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param bool|PushCDNInterface $cdn A PushCDNInterface instance. False if no CDN is used.
* @param int $media_id The media ID.
* @param ContextInterface $context The context object.
*/
public function register_cdn( $cdn, $media_id, $context ) {
if ( 'wp' !== $context->get_name() ) {
return $cdn;
}
if ( $cdn instanceof PushCDNInterface ) {
return $cdn;
}
return new CDN( $media_id );
}
/**
* Before performing a file optimization, download the file from the CDN if it is missing.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param null|\WP_Error $response Null by default.
* @param ProcessInterface $process The optimization process instance.
* @param File $file The file instance. If $webp is true, $file references the non-webp file.
* @param string $thumb_size The media size.
* @param int $optimization_level The optimization level (0=normal, 1=aggressive, 2=ultra).
* @param bool $webp The image will be converted to WebP.
* @return null|\WP_Error Null. A \WP_Error object on error.
*/
public function maybe_copy_file_from_cdn_before_optimization( $response, $process, $file, $thumb_size, $optimization_level, $webp ) {
if ( is_wp_error( $response ) || 'wp' !== $process->get_media()->get_context() ) {
return $response;
}
$media = $process->get_media();
$cdn = $media->get_cdn();
if ( ! $cdn instanceof CDN ) {
return $response;
}
if ( $this->filesystem->exists( $file->get_path() ) ) {
return $response;
}
// Get files from the CDN.
$result = $cdn->get_files_from_cdn( [ $file->get_path() ] );
if ( is_wp_error( $result ) ) {
return $result;
}
return $response;
}
/**
* After performing a media optimization:
* - Save some data,
* - Upload the files to the CDN,
* - Maybe delete them from the server.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param ProcessInterface $process The optimization process.
* @param array $item The item being processed.
*/
public function maybe_send_media_to_cdn_after_optimization( $process, $item ) {
if ( 'wp' !== $process->get_media()->get_context() ) {
return;
}
$media = $process->get_media();
$cdn = $media->get_cdn();
if ( ! $cdn instanceof CDN ) {
return;
}
$cdn->send_to_cdn( ! empty( $item['data']['is_new_upload'] ) );
}
/**
* After restoring a media:
* - Save some data,
* - Upload the files to the CDN,
* - Maybe delete WebP files from the CDN.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param ProcessInterface $process The optimization process.
* @param bool|WP_Error $response The result of the operation: true on success, a WP_Error object on failure.
* @param array $files The list of files, before restoring them.
* @param array $data The optimization data, before deleting it.
*/
public function maybe_send_media_to_cdn_after_restore( $process, $response, $files, $data ) {
if ( 'wp' !== $process->get_media()->get_context() ) {
return;
}
$media = $process->get_media();
$cdn = $media->get_cdn();
if ( ! $cdn instanceof CDN ) {
return;
}
if ( is_wp_error( $response ) ) {
$error_code = $response->get_error_code();
if ( 'copy_failed' === $error_code ) {
// No files have been restored.
return;
}
// No thumbnails left?
}
$cdn->send_to_cdn( false );
// Remove WebP files from CDN.
$webp_files = [];
if ( $files ) {
// Get the paths to the WebP files.
foreach ( $files as $size_name => $file ) {
$webp_size_name = $size_name . $process::WEBP_SUFFIX;
if ( empty( $data['sizes'][ $webp_size_name ]['success'] ) ) {
// This size has no WebP version.
continue;
}
if ( 0 === strpos( $file['mime-type'], 'image/' ) ) {
$webp_file = new File( $file['path'] );
if ( ! $webp_file->is_webp() ) {
$webp_files[] = $webp_file->get_path_to_webp();
}
}
}
}
if ( $webp_files ) {
$cdn->remove_files_from_cdn( $webp_files );
}
}
/** ----------------------------------------------------------------------------------------- */
/** OPTIMIZATION PROCESS ==================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Add the WebP files to the list of files that the CDN must handle.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param array $paths A list of file paths, keyed by size name. 'file' for the full size. Includes a 'backup' size and a 'thumb' size.
* @param int $attachment_id The media ID.
* @param array $metadata The attachment meta data.
* @return array
*/
public function add_webp_images_to_attachment( $paths, $attachment_id, $metadata ) {
if ( ! $paths ) {
// ¯\(°_o)/¯.
return $paths;
}
$process = imagify_get_optimization_process( $attachment_id, 'wp' );
if ( ! $process->is_valid() ) {
return $paths;
}
$media = $process->get_media();
if ( ! $media->is_image() ) {
return $paths;
}
// Use the optimization data (the files may not be on the server).
$data = $process->get_data()->get_optimization_data();
if ( empty( $data['sizes'] ) ) {
return $paths;
}
foreach ( $paths as $size_name => $file_path ) {
if ( 'thumb' === $size_name || 'backup' === $size_name || $process->is_size_next_gen( $size_name ) ) {
continue;
}
if ( 'file' === $size_name ) {
$size_name = 'full';
}
$webp_size_name = $size_name . $process::WEBP_SUFFIX;
if ( empty( $data['sizes'][ $webp_size_name ]['success'] ) ) {
// This size has no WebP version.
continue;
}
$file = new File( $file_path );
if ( ! $file->is_webp() ) {
$paths[ $webp_size_name ] = $file->get_path_to_webp();
}
}
return $paths;
}
/**
* Add WebP format to the list of allowed mime types.
*
* @since 1.9
* @access public
* @see get_allowed_mime_types()
* @author Grégory Viguier
*
* @param array $mime_types A list of mime types.
* @return array
*/
public function add_webp_support( $mime_types ) {
$mime_types['webp'] = 'image/webp';
return $mime_types;
}
/** ----------------------------------------------------------------------------------------- */
/** VARIOUS HOOKS =========================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* After a non-ajax optimization, remove some unnecessary arguments from the referrer used for the redirection.
* Those arguments don't break anything, they're just not relevant and display obsolete admin notices.
*
* @since 1.6.10
* @author Grégory Viguier
*
* @param string $redirect The URL to redirect to.
* @return string
*/
public function redirect_referrer( $redirect ) {
return remove_query_arg( [ 'as3cfpro-action', 'as3cf_id', 'errors', 'count' ], $redirect );
}
/**
* Provide the file sizes and the number of thumbnails for files that are only on S3.
*
* @since 1.6.7
* @author Grégory Viguier
*
* @param bool $size_and_count False by default.
* @param int $image_id The attachment ID.
* @param array $files An array of file paths with thumbnail sizes as keys.
* @param array $image_ids An array of all attachment IDs.
* @return bool|array False by default. Provide an array with the keys 'filesize' (containing the total filesize) and 'thumbnails' (containing the number of thumbnails).
*/
public function add_stats_for_s3_files( $size_and_count, $image_id, $files, $image_ids ) {
static $data;
if ( is_array( $size_and_count ) ) {
return $size_and_count;
}
if ( $this->filesystem->exists( $files['full'] ) ) {
// If the full size is on the server, that probably means all files are on the server too.
return $size_and_count;
}
if ( ! isset( $data ) ) {
$data = \Imagify_DB::get_metas( [
// Get the filesizes.
's3_filesize' => 'wpos3_filesize_total',
], $image_ids );
$data = array_map( 'absint', $data['s3_filesize'] );
}
if ( empty( $data[ $image_id ] ) ) {
// The file is not on S3.
return $size_and_count;
}
// We can't take the disallowed sizes into account here.
return [
'filesize' => (int) $data[ $image_id ],
'thumbnails' => count( $files ) - 1,
];
}
/** ----------------------------------------------------------------------------------------- */
/** TOOLS =================================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Tell if an URL is a S3 one.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param string $url The URL to test.
* @return array|bool {
* An array if an S3 URL. False otherwise.
*
* @type string $key Bucket key. Ex: subdir/wp-content/uploads/2019/02/13142432/foobar-480x510.jpg.
* @type string $year_month The uploads year/month folders. Ex: 2019/02/.
* @type string $subdirs Sub-directories between year/month folders and the filename.
* It can be the S3 versioning folder, any folder added by a plugin, or both.
* There is no way to know which one it is. Ex: foo/13142432/.
* @type string $filename The file name. Ex: foobar-480x510.jpg.
* }
*/
public function is_s3_url( $url ) {
static $uploads_dir;
static $domain;
/**
* Tell if an URL is a S3 one.
*
* @since 1.9
* @author Grégory Viguier
*
* @param null|array|bool $is Null by default. Must return an array if an S3 URL, or false if not.
* @param string $url The URL to test.
*/
$is = apply_filters( 'imagify_as3cf_is_s3_url', null, $url );
if ( false === $is ) {
return false;
}
if ( is_array( $is ) ) {
return imagify_merge_intersect( $is, [
'key' => '',
'year_month' => '',
'subdirs' => '',
'filename' => '',
] );
}
if ( ! isset( $uploads_dir ) ) {
$uploads_dir = wp_parse_url( $this->filesystem->get_upload_baseurl() );
$uploads_dir = trim( $uploads_dir['path'], '/' ) . '/';
}
if ( ! isset( $domain ) ) {
if ( ! empty( $this->store_s3_settings['cloudfront'] ) ) {
$domain = sanitize_text_field( $this->store_s3_settings['cloudfront'] );
$domain = preg_replace( '@^(?:https?:)?//@', '//', $domain );
$domain = preg_quote( $domain, '@' );
} else {
$domain = 's3-.+\.amazonaws\.com/[^/]+/';
}
}
$pattern = '@^(?:https?:)?//' . $domain . '/(?<key>' . $uploads_dir . '(?<year_month>\d{4}/\d{2}/)?(?<subdirs>.+/)?(?<filename>[^/]+))$@i';
if ( ! preg_match( $pattern, $url, $match ) ) {
return false;
}
unset( $match[0] );
return array_merge( [
'year_month' => '',
'subdirs' => '',
], $match );
}
}

View File

@@ -1,22 +0,0 @@
<?php
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
/**
* Compatibility with AMP plugin from WordPress.com VIP.
*/
if ( function_exists( 'is_amp_endpoint' ) ) :
add_filter( 'imagify_allow_picture_tags_for_nextgen', 'imagify_amp_disable_picture_on_endpoint' );
/**
* Do not use <picture> tags in AMP pages.
*
* @since 1.9
*
* @param bool $allow True to allow the use of <picture> tags (default). False to prevent their use.
* @return bool
*/
function imagify_amp_disable_picture_on_endpoint( $allow ) {
return $allow && ! is_amp_endpoint();
};
endif;

View File

@@ -1,152 +0,0 @@
<?php
namespace Imagify\ThirdParty\EnableMediaReplace;
use Imagify\Traits\InstanceGetterTrait;
use Imagify_Enable_Media_Replace_Deprecated;
use Imagify_Filesystem;
/**
* Compat class for Enable Media Replace plugin.
*
* @since 1.6.9
*/
class Main extends Imagify_Enable_Media_Replace_Deprecated {
use InstanceGetterTrait;
/**
* The media ID.
*
* @var int
* @since 1.9
*/
protected $media_id;
/**
* The process instance for the current attachment.
*
* @var ProcessInterface
* @since 1.9
*/
protected $process;
/**
* The path to the old backup file.
*
* @var string
* @since 1.6.9
*/
protected $old_backup_path;
/**
* List of paths to the old next-gen files.
*
* @var array
* @since 1.9.8
*/
protected $old_nextgen_paths = [];
/**
* Launch the hooks before the files and data are replaced.
*
* @since 1.6.9
* @since 1.9.10 The parameter changed from boolean to array. The method doesnt return anything.
*
* @param array $args An array containing the post ID.
*/
public function init( $args = [] ) {
if ( is_array( $args ) && ! empty( $args['post_id'] ) ) {
$this->media_id = $args['post_id'];
} else {
// Backward compatibility.
$this->media_id = (int) filter_input( INPUT_POST, 'ID' );
$this->media_id = max( 0, $this->media_id );
if ( ! $this->media_id ) {
return;
}
}
// Store the old backup file path.
$this->get_process();
if ( ! $this->process ) {
$this->media_id = 0;
return;
}
$this->old_backup_path = $this->process->get_media()->get_backup_path();
if ( ! $this->old_backup_path ) {
$this->media_id = 0;
return;
}
/**
* Keep track of existing next-gen files.
*
* Whether the user chooses to rename the files or not, we will need to delete the current next-gen files before creating new ones:
* - Rename the files: the old ones must be removed, they are useless now.
* - Do not rename the files: the thumbnails may still get new names because of the suffix containing the image dimensions, which may differ (for example when thumbnails are scaled, not cropped).
* In this last case, the thumbnails with the old dimensions are removed from the drive and from the WPs post meta, so there is no need of keeping orphan next-gen files that would stay on the drive for ever, even after the attachment is deleted from WP.
*/
foreach ( $this->process->get_media()->get_media_files() as $media_file ) {
foreach ( [ 'avif', 'webp' ] as $format ) {
$this->old_nextgen_paths[] = imagify_path_to_nextgen( $media_file['path'], $format );
}
}
// Delete the old backup file and old next-gen files.
add_action( 'imagify_before_auto_optimization', [ $this, 'delete_backup' ] );
add_action( 'imagify_not_optimized_attachment_updated', [ $this, 'delete_backup' ] );
}
/**
* Delete previous backup file and next-gen files.
* This is done after the images have been already replaced by Enable Media Replace.
*
* @since 1.8.4
*
* @param int $media_id The attachment ID.
*/
public function delete_backup( $media_id ) {
if ( ! $this->old_backup_path || ! $this->media_id || $media_id !== $this->media_id ) {
return;
}
$filesystem = Imagify_Filesystem::get_instance();
if ( $filesystem->exists( $this->old_backup_path ) ) {
// Delete old backup file.
$filesystem->delete( $this->old_backup_path );
$this->old_backup_path = false;
}
if ( ! empty( $this->old_nextgen_paths ) ) {
// Delete old next-gen files.
$this->old_nextgen_paths = array_filter( $this->old_nextgen_paths, [ $filesystem, 'exists' ] );
array_map( [ $filesystem, 'delete' ], $this->old_nextgen_paths );
$this->old_nextgen_paths = [];
}
}
/**
* Get the optimization process corresponding to the current media.
*
* @since 1.9
*
* @return ProcessInterface|bool False if invalid.
*/
protected function get_process() {
if ( isset( $this->process ) ) {
return $this->process;
}
$this->process = imagify_get_optimization_process( $this->media_id, 'wp' );
if ( ! $this->process->is_valid() ) {
$this->process = false;
}
return $this->process;
}
}

View File

@@ -1,10 +0,0 @@
<?php
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
if ( function_exists( 'enable_media_replace' ) || class_exists( '\\EnableMediaReplace\\EnableMediaReplacePlugin' ) ) :
class_alias( '\\Imagify\\ThirdParty\\EnableMediaReplace\\Main', '\\Imagify_Enable_Media_Replace' );
add_filter( 'wp_handle_replace', [ \Imagify\ThirdParty\EnableMediaReplace\Main::get_instance(), 'init' ] );
endif;

View File

@@ -1,69 +0,0 @@
<?php
namespace Imagify\ThirdParty\FormidablePro;
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
/**
* Compat class for Formidable Forms Pro plugin.
* Each call to `new WP_Query()` made by Imagify must have a `'is_imagify' => true` argument.
*
* @since 1.6.13
* @author Grégory Viguier
*/
class Main {
use \Imagify\Traits\InstanceGetterTrait;
/**
* Class version.
*
* @var string
*/
const VERSION = '1.1';
/**
* Set to true when the current query comes from Imagify.
*
* @var int
*/
protected $is_imagify;
/**
* Launch the hooks.
*
* @since 1.6.13
* @author Grégory Viguier
*/
public function init() {
add_action( 'parse_query', array( $this, 'maybe_remove_media_library_filter' ) );
add_action( 'posts_selection', array( $this, 'maybe_put_media_library_filter_back' ) );
}
/**
* Fires before the 'pre_get_posts' hook.
*
* @since 1.6.13
* @author Grégory Viguier
*
* @param object $wp_query The WP_Query instance (passed by reference).
*/
public function maybe_remove_media_library_filter( $wp_query ) {
if ( ! empty( $wp_query->query_vars['is_imagify'] ) && class_exists( 'FrmProFileField' ) ) {
$this->is_imagify = true;
remove_action( 'pre_get_posts', 'FrmProFileField::filter_media_library', 99 );
} else {
$this->is_imagify = false;
}
}
/**
* Fires after the 'pre_get_posts' hook.
*
* @since 1.6.13
* @author Grégory Viguier
*/
public function maybe_put_media_library_filter_back() {
if ( $this->is_imagify ) {
add_action( 'pre_get_posts', 'FrmProFileField::filter_media_library', 99 );
}
}
}

View File

@@ -1,12 +0,0 @@
<?php
use Imagify\ThirdParty\FormidablePro;
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
if ( class_exists( 'FrmProEddController' ) ) :
class_alias( '\\Imagify\\ThirdParty\\FormidablePro\\Main', '\\Imagify_Formidable_Pro' );
FormidablePro\Main::get_instance()->init();
endif;

View File

@@ -1,34 +0,0 @@
<?php
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
if ( defined( 'FLYWHEEL_CONFIG_DIR' ) ) :
add_filter( 'imagify_site_root', 'imagify_flywheel_site_root', IMAGIFY_INT_MAX );
/**
* Filter the path to the sites root.
*
* @since 1.9
* @author Grégory Viguier
*
* @param string|null $root_path Path to the site's root. Default is null.
* @return string|null
*/
function imagify_flywheel_site_root( $root_path ) {
if ( ! empty( $_SERVER['DOCUMENT_ROOT'] ) ) {
return trailingslashit( wp_unslash( $_SERVER['DOCUMENT_ROOT'] ) );
}
$upload_basedir = imagify_get_filesystem()->get_upload_basedir( true );
if ( strpos( $upload_basedir, '/wp-content/' ) === false ) {
// Uh oooooh...
return $root_path;
}
$upload_basedir = explode( '/wp-content/', $upload_basedir );
$upload_basedir = reset( $upload_basedir );
return $upload_basedir . '/';
}
endif;

View File

@@ -1,24 +0,0 @@
<?php
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
if ( defined( 'IS_PRESSABLE' ) ) :
add_filter( 'imagify_site_root', 'imagify_pressable_site_root', IMAGIFY_INT_MAX );
/**
* Filter the path to the site's root.
*
* @since 1.9.4
* @author Grégory Viguier
*
* @param string|null $root_path Path to the site's root. Default is null.
* @return string
*/
function imagify_pressable_site_root( $root_path ) {
$upload_basedir = trim( wp_normalize_path( WP_CONTENT_DIR ), '/' );
$upload_basedir = explode( '/', $upload_basedir );
$upload_basedir = reset( $upload_basedir );
return '/' . $upload_basedir . '/';
}
endif;

View File

@@ -1,71 +0,0 @@
<?php
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
add_filter( 'http_request_args', 'imagify_siteground_change_user_agent', 10, 2 );
/**
* Filter the arguments used in a HTTP request to change the User Agent for requests "to self", to prevent firewalls to be triggered.
*
* @since 1.6.13
* @author Grégory Viguier
*
* @param array $r An array of HTTP request arguments.
* @param string $url The request URL.
* @return array
*/
function imagify_siteground_change_user_agent( $r, $url ) {
static $user_agent;
static $site_url;
$url = wp_parse_url( $url );
if ( empty( $url['path'] ) ) {
return $r;
}
$paths = array(
'/wp-admin/admin-ajax.php',
'/wp-admin/admin-post.php',
'/wp-cron.php',
);
if ( ! isset( $site_url ) ) {
$site_url = wp_parse_url( site_url( '/' ) );
}
// Limit to requests to self.
if ( false === strpos( $url['path'], $site_url['path'] ) && false === strpos( $site_url['path'], $url['path'] ) ) {
return $r;
}
// Limit to requests to admin-ajax.php, admin-post.php, and wp-cron.php.
foreach ( $paths as $i => $path ) {
if ( false !== strpos( $url['path'], $path ) ) {
$paths = false;
break;
}
}
if ( $paths ) {
return $r;
}
// Randomize the User-Agent.
if ( ! isset( $user_agent ) ) {
$user_agent = wp_generate_password( 12, false );
/**
* Filter the User-Agent used for requests "to self".
*
* @since 1.7.1
* @author Grégory Viguier
*
* @param string $user_agent The User-Agent.
* @param array $r An array of HTTP request arguments.
* @param array $url The request URL, parsed.
*/
$user_agent = apply_filters( 'imagify_user_agent_for_internal_requests', $user_agent, $r, $url );
}
$r['user-agent'] = $user_agent;
return $r;
}

View File

@@ -1,30 +0,0 @@
<?php
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
if ( defined( 'WPCOMSH_VERSION' ) ) :
add_filter( 'imagify_site_root', 'imagify_wpcom_site_root', IMAGIFY_INT_MAX );
/**
* Filter the path to the site's root.
*
* @since 1.8.4
* @author Grégory Viguier
*
* @param string|null $root_path Path to the site's root. Default is null.
* @return string|null
*/
function imagify_wpcom_site_root( $root_path ) {
$upload_basedir = imagify_get_filesystem()->get_upload_basedir( true );
if ( strpos( $upload_basedir, '/wp-content/' ) === false ) {
// Uh oooooh...
return $root_path;
}
$upload_basedir = explode( '/wp-content/', $upload_basedir );
$upload_basedir = reset( $upload_basedir );
return $upload_basedir . '/';
}
endif;

View File

@@ -1,21 +0,0 @@
<?php
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
if ( class_exists( 'WpeCommon' ) ) :
add_filter( 'imagify_unoptimized_attachment_limit', '_imagify_wpengine_unoptimized_attachment_limit' );
add_filter( 'imagify_count_saving_data_limit', '_imagify_wpengine_unoptimized_attachment_limit' );
/**
* Change the limit for the number of posts: WP Engine limits SQL queries size to 2048 octets (16384 characters).
*
* @since 1.4.7
* @since 1.6.7 Renamed (and deprecated) _imagify_wengine_unoptimized_attachment_limit() into _imagify_wpengine_unoptimized_attachment_limit().
* @author Jonathan Buttigieg
*
* @return int
*/
function _imagify_wpengine_unoptimized_attachment_limit() {
return 2500;
}
endif;

View File

@@ -1,240 +0,0 @@
<?php
namespace Imagify\ThirdParty\NGG\Bulk;
use C_Gallery_Storage;
use Imagify\Bulk\AbstractBulk;
use Imagify\ThirdParty\NGG\DB;
/**
* Class to use for bulk for NextGen Gallery.
*
* @since 1.9
*/
class NGG extends AbstractBulk {
/**
* Context "short name".
*
* @var string
* @since 1.9
*/
protected $context = 'ngg';
/**
* Get all unoptimized media ids.
*
* @since 1.9
*
* @param int $optimization_level The optimization level.
* @return array A list of unoptimized media IDs.
*/
public function get_unoptimized_media_ids( $optimization_level ) {
global $wpdb;
$this->set_no_time_limit();
$storage = C_Gallery_Storage::get_instance();
$ngg_table = $wpdb->prefix . 'ngg_pictures';
$data = [];
$images = $wpdb->get_results( $wpdb->prepare( // WPCS: unprepared SQL ok.
"
SELECT DISTINCT picture.pid as id, picture.filename, idata.optimization_level, idata.status, idata.data
FROM $ngg_table as picture
LEFT JOIN $wpdb->ngg_imagify_data as idata
ON picture.pid = idata.pid
WHERE idata.pid IS NULL
OR idata.optimization_level != %d
OR idata.status = 'error'
LIMIT %d",
$optimization_level,
imagify_get_unoptimized_attachment_limit()
), ARRAY_A );
if ( ! $images ) {
return [];
}
foreach ( $images as $image ) {
$id = absint( $image['id'] );
$file_path = $storage->get_image_abspath( $id );
if ( ! $file_path || ! $this->filesystem->exists( $file_path ) ) {
continue;
}
$attachment_data = maybe_unserialize( $image['data'] );
$attachment_error = '';
if ( isset( $attachment_data['sizes']['full']['error'] ) ) {
$attachment_error = $attachment_data['sizes']['full']['error'];
}
$attachment_error = trim( $attachment_error );
$attachment_status = $image['status'];
$attachment_optimization_level = $image['optimization_level'];
$attachment_backup_path = get_imagify_ngg_attachment_backup_path( $file_path );
// Don't try to re-optimize if the optimization level is still the same.
if ( $optimization_level === $attachment_optimization_level && is_string( $attachment_error ) ) {
continue;
}
// Don't try to re-optimize if there is no backup file.
if ( 'success' === $attachment_status && $optimization_level !== $attachment_optimization_level && ! $this->filesystem->exists( $attachment_backup_path ) ) {
continue;
}
// Don't try to re-optimize images already compressed.
if ( 'already_optimized' === $attachment_status && $attachment_optimization_level >= $optimization_level ) {
continue;
}
// Don't try to re-optimize images with an empty error message.
if ( 'error' === $attachment_status && empty( $attachment_error ) ) {
continue;
}
$data[] = $id;
} // End foreach().
return $data;
}
/**
* Get ids of all optimized media without next-gen versions.
*
* @since 2.2
*
* @param string $format Format we are looking for. (webp|avif).
*
* @return array {
* @type array $ids A list of media IDs.
* @type array $errors {
* @type array $no_file_path A list of media IDs.
* @type array $no_backup A list of media IDs.
* }
* }
*/
public function get_optimized_media_ids_without_format( $format ) {
global $wpdb;
$this->set_no_time_limit();
$storage = C_Gallery_Storage::get_instance();
$ngg_table = $wpdb->prefix . 'ngg_pictures';
$data_table = DB::get_instance()->get_table_name();
$suffix = constant( imagify_get_optimization_process_class_name( 'ngg' ) . '::WEBP_SUFFIX' );
if ( 'avif' === get_imagify_option( 'optimization_format' ) ) {
$suffix = constant( imagify_get_optimization_process_class_name( 'ngg' ) . '::AVIF_SUFFIX' );
}
$files = $wpdb->get_col( $wpdb->prepare( // WPCS: unprepared SQL ok.
"
SELECT ngg.pid
FROM $ngg_table as ngg
INNER JOIN $data_table AS data
ON ( ngg.pid = data.pid )
WHERE
( data.status = 'success' OR data.status = 'already_optimized' )
AND data.data NOT LIKE %s
ORDER BY ngg.pid DESC",
'%' . $wpdb->esc_like( $suffix . '";a:4:{s:7:"success";b:1;' ) . '%'
) );
$wpdb->flush();
unset( $ngg_table, $data_table, $suffix );
$data = [
'ids' => [],
'errors' => [
'no_file_path' => [],
'no_backup' => [],
],
];
if ( ! $files ) {
return $data;
}
foreach ( $files as $file_id ) {
$file_id = absint( $file_id );
$file_path = $storage->get_image_abspath( $file_id );
if ( ! $file_path ) {
// Problem.
$data['errors']['no_file_path'][] = $file_id;
continue;
}
$backup_path = get_imagify_ngg_attachment_backup_path( $file_path );
if ( ! $this->filesystem->exists( $backup_path ) ) {
// No backup, no next-gen.
$data['errors']['no_backup'][] = $file_id;
continue;
}
$data['ids'][] = $file_id;
} // End foreach().
return $data;
}
/**
* Tell if there are optimized media without next-gen versions.
*
* @since 2.2
*
* @return int The number of media.
*/
public function has_optimized_media_without_nextgen() {
global $wpdb;
$ngg_table = $wpdb->prefix . 'ngg_pictures';
$data_table = DB::get_instance()->get_table_name();
$suffix = constant( imagify_get_optimization_process_class_name( 'ngg' ) . '::WEBP_SUFFIX' );
if ( 'avif' === get_imagify_option( 'optimization_format' ) ) {
$suffix = constant( imagify_get_optimization_process_class_name( 'ngg' ) . '::AVIF_SUFFIX' );
}
return (int) $wpdb->get_var( $wpdb->prepare( // WPCS: unprepared SQL ok.
"
SELECT COUNT(ngg.pid)
FROM $ngg_table as ngg
INNER JOIN $data_table AS data
ON ( ngg.pid = data.pid )
WHERE
( data.status = 'success' OR data.status = 'already_optimized' )
AND data.data NOT LIKE %s",
'%' . $wpdb->esc_like( $suffix . '";a:4:{s:7:"success";b:1;' ) . '%'
) );
}
/**
* Get the context data.
*
* @since 1.9
*
* @return array {
* The formated data.
*
* @type string $count-optimized Number of media optimized.
* @type string $count-errors Number of media having an optimization error, with a link to the page listing the optimization errors.
* @type string $optimized-size Optimized filesize.
* @type string $original-size Original filesize.
* }
*/
public function get_context_data() {
$total_saving_data = imagify_count_saving_data();
$data = [
'count-optimized' => imagify_ngg_count_optimized_attachments(),
'count-errors' => imagify_ngg_count_error_attachments(),
'optimized-size' => $total_saving_data['optimized_size'],
'original-size' => $total_saving_data['original_size'],
'errors_url' => get_imagify_admin_url( 'folder-errors', $this->context ),
];
return $this->format_context_data( $data );
}
}

View File

@@ -1,113 +0,0 @@
<?php
namespace Imagify\ThirdParty\NGG\Context;
use Imagify\Context\AbstractContext;
use Imagify\Traits\InstanceGetterTrait;
/**
* Context class used for the WP media library.
*
* @since 1.9
* @author Grégory Viguier
*/
class NGG extends AbstractContext {
use InstanceGetterTrait;
/**
* Context "short name".
*
* @var string
* @since 1.9
* @author Grégory Viguier
*/
protected $context = 'ngg';
/**
* Type of files this context allows.
*
* @var string Possible values are:
* - 'all' to allow all types.
* - 'image' to allow only images.
* - 'not-image' to allow only pdf files.
* @since 1.9
* @see imagify_get_mime_types()
* @author Grégory Viguier
*/
protected $allowed_mime_types = 'image';
/**
* The thumbnail sizes for this context, except the full size.
*
* @var array {
* Data for the currently registered thumbnail sizes.
* Size names are used as array keys.
*
* @type int $width The image width.
* @type int $height The image height.
* @type bool $crop True to crop, false to resize.
* @type string $name The size name.
* }
* @since 1.9
* @author Grégory Viguier
*/
protected $thumbnail_sizes = [];
/**
* Tell if the optimization process is allowed to backup in this context.
*
* @var bool
* @since 1.9
* @author Grégory Viguier
*/
protected $can_backup = true;
/**
* Get images max width for this context. This is used when resizing.
* 0 means to not resize.
*
* @since 1.9.8
* @author Grégory Viguier
*
* @return int
*/
public function get_resizing_threshold() {
return 0;
}
/**
* Get user capacity to operate Imagify in this context.
*
* @since 1.9
* @author Grégory Viguier
*
* @param string $describer Capacity describer. Possible values are like 'manage', 'bulk-optimize', 'manual-optimize', 'auto-optimize'.
* @return string
*/
public function get_capacity( $describer = 'manage' ) {
switch ( $describer ) {
case 'manage':
$capacity = 'NextGEN Change options';
break;
case 'bulk-optimize':
$capacity = 'NextGEN Manage others gallery';
break;
case 'optimize':
case 'restore':
case 'manual-optimize':
case 'manual-restore':
$capacity = 'NextGEN Manage gallery';
break;
case 'auto-optimize':
$capacity = 'NextGEN Upload images';
break;
default:
$capacity = $describer;
}
return $this->filter_capacity( $capacity, $describer );
}
}

View File

@@ -1,142 +0,0 @@
<?php
namespace Imagify\ThirdParty\NGG;
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
/**
* Imagify NextGen Gallery DB class.
*
* @since 1.5
* @author Jonathan Buttigieg
*/
class DB extends \Imagify_Abstract_DB {
/**
* Class version.
*
* @var string
*/
const VERSION = '1.1.1';
/**
* The single instance of the class.
*
* @var object
* @since 1.5
* @access protected
*/
protected static $_instance;
/**
* The suffix used in the name of the database table (so, without the wpdb prefix).
*
* @var string
* @since 1.7
* @access protected
*/
protected $table = 'ngg_imagify_data';
/**
* The version of our database table.
*
* @var int
* @since 1.5
* @since 1.7 Not public anymore, now an integer.
* @access protected
*/
protected $table_version = 100;
/**
* Tell if the table is the same for each site of a Multisite.
*
* @var bool
* @since 1.7
* @access protected
*/
protected $table_is_global = false;
/**
* The name of the primary column.
*
* @var string
* @since 1.5
* @since 1.7 Not public anymore.
* @access protected
*/
protected $primary_key = 'pid';
/**
* Get the main Instance.
*
* @since 1.6.5
* @access public
* @author Grégory Viguier
*
* @return object Main instance.
*/
public static function get_instance() {
if ( ! isset( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
/**
* Whitelist of columns.
*
* @since 1.5
* @access public
* @author Jonathan Buttigieg
*
* @return array
*/
public function get_columns() {
return array(
'data_id' => '%d',
'pid' => '%d',
'optimization_level' => '%s',
'status' => '%s',
'data' => '%s',
);
}
/**
* Default column values.
*
* @since 1.5
* @access public
* @author Jonathan Buttigieg
*
* @return array
*/
public function get_column_defaults() {
return array(
'data_id' => 0,
'pid' => 0,
'optimization_level' => '',
'status' => '',
'data' => array(),
);
}
/**
* Get the query to create the table fields.
*
* @since 1.7
* @access protected
* @author Grégory Viguier
*
* @return string
*/
protected function get_table_schema() {
return "
data_id int(11) unsigned NOT NULL AUTO_INCREMENT,
pid int(11) unsigned NOT NULL default 0,
optimization_level varchar(1) NOT NULL default '',
status varchar(30) NOT NULL default '',
data longtext NOT NULL default '',
PRIMARY KEY (data_id),
KEY pid (pid)";
}
}

View File

@@ -1,133 +0,0 @@
<?php
namespace Imagify\ThirdParty\NGG;
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
/**
* Class that handles the optimization of thumbnails dynamically generated.
*
* @since 1.9
* @author Grégory Viguier
*/
class DynamicThumbnails {
use \Imagify\Traits\InstanceGetterTrait;
/**
* The queue containing the sizes, grouped by image ID.
*
* @var array
* @since 1.9
* @access protected
* @author Grégory Viguier
*/
protected static $sizes = [];
/**
* A list of NGG image objects, grouped by image ID.
*
* @var array
* @since 1.9
* @access protected
* @author Grégory Viguier
*/
protected static $images = [];
/**
* Add a dynamically generated thumbnail to the background process queue.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param object $image A NGG image object.
* @param string $size The thumbnail size name.
*/
public function push_to_queue( $image, $size ) {
static $done = false;
if ( empty( $image->pid ) ) {
// WUT?
return;
}
if ( empty( static::$sizes[ $image->pid ] ) ) {
static::$sizes[ $image->pid ] = [];
}
static::$sizes[ $image->pid ][] = $size;
if ( empty( static::$images[ $image->pid ] ) ) {
static::$images[ $image->pid ] = $image;
}
if ( $done ) {
return;
}
$done = true;
add_action( 'shutdown', [ $this, 'optimize' ], 555 ); // Must come before 666 (see Imagify_Abstract_Background_Process->init()).
}
/**
* Launch the optimizations.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*/
public function optimize() {
if ( empty( static::$sizes ) ) {
// ¯\(°_o)/¯
return;
}
foreach ( static::$sizes as $image_id => $sizes ) {
if ( empty( static::$images[ $image_id ] ) ) {
// ¯\(°_o)/¯
continue;
}
$sizes = array_filter( $sizes );
if ( empty( $sizes ) ) {
continue;
}
$process = imagify_get_optimization_process( static::$images[ $image_id ], 'ngg' );
if ( ! $process->is_valid() || ! $process->get_media()->is_supported() ) {
continue;
}
$data = $process->get_data();
if ( ! $data->is_optimized() ) {
// The main image is not optimized.
continue;
}
$sizes = array_unique( $sizes );
foreach ( $sizes as $i => $size ) {
$size_status = $data->get_size_data( $size, 'success' );
if ( $size_status ) {
// This thumbnail has already been processed.
unset( $sizes[ $i ] );
}
}
if ( empty( $sizes ) ) {
continue;
}
$optimization_level = $process->get_data()->get_optimization_level();
$args = [
'hook_suffix' => 'optimize_generated_image',
];
$process->optimize_sizes( $sizes, $optimization_level, $args );
}
}
}

View File

@@ -1,137 +0,0 @@
<?php
namespace Imagify\ThirdParty\NGG;
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
/**
* Imagify NextGen Gallery class.
*
* @since 1.5
* @author Jonathan Buttigieg
*/
class Main {
use \Imagify\Traits\InstanceGetterTrait;
/**
* Class version.
*
* @var string
*/
const VERSION = '1.1';
/**
* The constructor.
*
* @since 1.5
* @since 1.6.5 Doesn't launch the hooks anymore.
* @since 1.9 Visibility set to public.
* @access public
* @author Jonathan Buttigieg
*/
public function __construct() {}
/**
* Launch the hooks.
*
* @since 1.6.5
* @access public
* @author Grégory Viguier
*/
public function init() {
static $done = false;
if ( $done ) {
return;
}
$done = true;
add_filter( 'imagify_register_context', [ $this, 'register_context' ] );
add_filter( 'imagify_context_class_name', [ $this, 'add_context_class_name' ], 10, 2 );
add_filter( 'imagify_process_class_name', [ $this, 'add_process_class_name' ], 10, 2 );
add_filter( 'imagify_bulk_class_name', [ $this, 'add_bulk_class_name' ], 10, 2 );
add_action( 'init', [ $this, 'add_mixin' ] );
}
/**
* Register the context used for NGG.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param array $contexts An array of context names.
* @return array
*/
public function register_context( $contexts ) {
$contexts[] = 'ngg';
return $contexts;
}
/**
* Filter the name of the class to use to define a context.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param int $class_name The class name.
* @param string $context The context name.
* @return string
*/
public function add_context_class_name( $class_name, $context ) {
if ( 'ngg' === $context ) {
return '\\Imagify\\ThirdParty\\NGG\\Context\\NGG';
}
return $class_name;
}
/**
* Filter the name of the class to use for the optimization.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param int $class_name The class name.
* @param string $context The context name.
* @return string
*/
public function add_process_class_name( $class_name, $context ) {
if ( 'ngg' === $context ) {
return '\\Imagify\\ThirdParty\\NGG\\Optimization\\Process\\NGG';
}
return $class_name;
}
/**
* Filter the name of the class to use for the bulk optimization.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param int $class_name The class name.
* @param string $context The context name.
* @return string
*/
public function add_bulk_class_name( $class_name, $context ) {
if ( 'ngg' === $context ) {
return '\\Imagify\\ThirdParty\\NGG\\Bulk\\NGG';
}
return $class_name;
}
/**
* Add custom NGG mixin to override its functions.
*
* @since 1.5
* @access public
* @author Jonathan Buttigieg
*/
public function add_mixin() {
\C_Gallery_Storage::get_instance()->get_wrapped_instance()->add_mixin( '\\Imagify\\ThirdParty\\NGG\\NGGStorage' );
}
}

View File

@@ -1,543 +0,0 @@
<?php
namespace Imagify\ThirdParty\NGG\Media;
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
/**
* Media class for the medias from NextGen Gallery.
*
* @since 1.9
* @author Grégory Viguier
*/
class NGG extends \Imagify\Media\AbstractMedia {
use \Imagify\Deprecated\Traits\Media\NGGDeprecatedTrait;
/**
* Context (where the media "comes from").
*
* @var string
* @since 1.9
* @access protected
* @author Grégory Viguier
*/
protected $context = 'ngg';
/**
* The image object.
*
* @var object A \nggImage object.
* @since 1.9
* @access protected
* @author Grégory Viguier
*/
protected $image;
/**
* The storage object used by NGG.
*
* @var object A \C_Gallery_Storage object (by default).
* @since 1.8.
* @access protected
*/
protected $storage;
/**
* The constructor.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param int|\nggImage|\nggdb|\StdClass $id The NGG image ID, \nggImage object, \nggdb object, or an anonym object containing a pid property.
*/
public function __construct( $id ) {
if ( ! static::constructor_accepts( $id ) ) {
parent::__construct( 0 );
return;
}
if ( is_numeric( $id ) ) {
$this->image = \nggdb::find_image( (int) $id );
$id = ! empty( $this->image->pid ) ? (int) $this->image->pid : 0;
} elseif ( $id instanceof \nggImage ) {
$this->image = $id;
$id = (int) $id->pid;
} elseif ( is_object( $id ) ) {
$this->image = \nggdb::find_image( (int) $id->pid );
$id = ! empty( $this->image->pid ) ? (int) $this->image->pid : 0;
} else {
$id = 0;
}
if ( ! $id ) {
$this->image = null;
parent::__construct( 0 );
return;
}
parent::__construct( $id );
// NGG storage.
if ( ! empty( $this->image->_ngiw ) ) {
$this->storage = $this->image->_ngiw->get_storage()->object;
} else {
$this->storage = \C_Gallery_Storage::get_instance()->object;
}
// Load nggAdmin class.
$ngg_admin_functions_path = WP_PLUGIN_DIR . '/' . NGGFOLDER . '/products/photocrati_nextgen/modules/ngglegacy/admin/functions.php';
if ( ! class_exists( 'nggAdmin' ) && $this->filesystem->exists( $ngg_admin_functions_path ) ) {
require_once $ngg_admin_functions_path;
}
}
/**
* Tell if the given entry can be accepted in the constructor.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param mixed $id Whatever.
* @return bool
*/
public static function constructor_accepts( $id ) {
if ( ! $id ) {
return false;
}
if ( is_numeric( $id ) || $id instanceof \nggImage ) {
return true;
}
return is_object( $id ) && ! empty( $id->pid ) && is_numeric( $id->pid );
}
/** ----------------------------------------------------------------------------------------- */
/** NGG SPECIFICS =========================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Get the NGG image object.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @return \nggImage
*/
public function get_ngg_image() {
return $this->image;
}
/**
* Get the NGG storage object.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @return \C_Gallery_Storage
*/
public function get_ngg_storage() {
return $this->storage;
}
/** ----------------------------------------------------------------------------------------- */
/** ORIGINAL FILE =========================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Get the original file path, even if the file doesn't exist.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @return string|bool The file path. False on failure.
*/
public function get_raw_original_path() {
if ( ! $this->is_valid() ) {
return false;
}
if ( $this->get_cdn() ) {
return $this->get_cdn()->get_file_path( 'original' );
}
return ! empty( $this->image->imagePath ) ? $this->image->imagePath : false;
}
/** ----------------------------------------------------------------------------------------- */
/** FULL SIZE FILE ========================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Get the URL of the medias full size file.
*
* @since 1.9.8
* @access public
* @author Grégory Viguier
*
* @return string|bool The file URL. False on failure.
*/
public function get_fullsize_url() {
if ( ! $this->is_valid() ) {
return false;
}
if ( $this->get_cdn() ) {
return $this->get_cdn()->get_file_url();
}
return ! empty( $this->image->imageURL ) ? $this->image->imageURL : false;
}
/**
* Get the path to the medias full size file, even if the file doesn't exist.
*
* @since 1.9.8
* @access public
* @author Grégory Viguier
*
* @return string|bool The file path. False on failure.
*/
public function get_raw_fullsize_path() {
if ( ! $this->is_valid() ) {
return false;
}
if ( $this->get_cdn() ) {
return $this->get_cdn()->get_file_path();
}
return ! empty( $this->image->imagePath ) ? $this->image->imagePath : false;
}
/** ----------------------------------------------------------------------------------------- */
/** BACKUP FILE ============================================================================= */
/** ----------------------------------------------------------------------------------------- */
/**
* Get the backup URL, even if the file doesn't exist.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @return string|bool The file URL. False on failure.
*/
public function get_backup_url() {
if ( ! $this->is_valid() ) {
return false;
}
return site_url( '/' . $this->filesystem->make_path_relative( $this->get_raw_backup_path() ) );
}
/**
* Get the backup file path, even if the file doesn't exist.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @return string|bool The file path. False on failure.
*/
public function get_raw_backup_path() {
if ( ! $this->is_valid() ) {
return false;
}
return get_imagify_ngg_attachment_backup_path( $this->get_raw_original_path() );
}
/** ----------------------------------------------------------------------------------------- */
/** THUMBNAILS ============================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Create the media thumbnails.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @return bool|WP_Error True on success. A \WP_Error instance on failure.
*/
public function generate_thumbnails() {
if ( ! $this->is_valid() ) {
return new \WP_Error( 'invalid_media', __( 'This media is not valid.', 'imagify' ) );
}
$image_data = $this->storage->_image_mapper->find( $this->get_id() ); // stdClass Object.
if ( ! $image_data ) {
// ¯\(°_o)/¯
return new \WP_Error( 'no_ngg_image', __( 'Image not found in NextGen Gallery data.', 'imagify' ) );
}
if ( empty( $image_data->meta_data['backup'] ) || ! is_array( $image_data->meta_data['backup'] ) ) {
$full_path = $this->storage->get_image_abspath( $image_data );
$image_data->meta_data['backup'] = [
'filename' => $this->filesystem->file_name( $full_path ), // Yes, $full_path.
'width' => $image_data->meta_data['width'], // Original image width.
'height' => $image_data->meta_data['height'], // Original image height.
'generated' => microtime(),
];
}
$backup_path = $this->storage->get_image_abspath( $image_data, 'backup' );
$failed = [];
foreach ( $this->get_media_files() as $size_name => $size_data ) {
if ( 'full' === $size_name ) {
continue;
}
$params = $this->storage->get_image_size_params( $image_data, $size_name );
$thumbnail = @$this->storage->generate_image_clone( // Don't remove this @ or the sky will fall.
$backup_path,
$this->storage->get_image_abspath( $image_data, $size_name ),
$params
);
if ( ! $thumbnail ) {
// Failed.
$failed[] = $size_name;
unset( $image_data->meta_data[ $size_name ] );
continue;
}
$size_meta = [
'width' => 0,
'height' => 0,
'filename' => \M_I18n::mb_basename( $thumbnail->fileName ),
'generated' => microtime(),
];
$dimensions = $this->filesystem->get_image_size( $thumbnail->fileName );
if ( $dimensions ) {
$size_meta['width'] = $dimensions['width'];
$size_meta['height'] = $dimensions['height'];
}
if ( isset( $params['crop_frame'] ) ) {
$size_meta['crop_frame'] = $params['crop_frame'];
}
$image_data->meta_data[ $size_name ] = $size_meta;
} // End foreach().
// Keep our property up to date.
$this->image->_ngiw->_cache['meta_data'] = $image_data->meta_data;
$this->image->_ngiw->_orig_image = $image_data;
$post_id = $this->storage->_image_mapper->save( $image_data );
if ( ! $post_id ) {
return new \WP_Error( 'meta_data_not_saved', __( 'Related NextGen Gallery data could not be saved.', 'imagify' ) );
}
if ( $failed ) {
return new \WP_Error(
'thumbnail_restore_failed',
sprintf( _n( '%n thumbnail could not be restored.', '%n thumbnails could not be restored.', count( $failed ), 'imagify' ), count( $failed ) ),
[ 'failed_thumbnails' => $failed ]
);
}
return true;
}
/** ----------------------------------------------------------------------------------------- */
/** MEDIA DATA ============================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Tell if the current media has the required data (the data containing the file paths and thumbnails).
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @return bool
*/
public function has_required_media_data() {
static $sizes;
if ( ! $this->is_valid() ) {
return false;
}
if ( ! isset( $sizes ) ) {
$sizes = $this->get_media_files();
}
return $sizes && ! empty( $this->image->imagePath );
}
/**
* Get the list of the files of this media, including the full size file.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @return array {
* An array with the size names as keys ('full' is used for the full size file), and arrays of data as values:
*
* @type string $size The size name.
* @type string $path Absolute path to the file.
* @type int $width The file width.
* @type int $height The file height.
* @type string $mime-type The file mime type.
* @type bool $disabled True if the size is disabled in the plugins settings.
* }
*/
public function get_media_files() {
if ( ! $this->is_valid() ) {
return [];
}
$fullsize_path = $this->get_raw_fullsize_path();
if ( ! $fullsize_path ) {
return [];
}
$dimensions = $this->get_dimensions();
$all_sizes = [
'full' => [
'size' => 'full',
'path' => $fullsize_path,
'width' => $dimensions['width'],
'height' => $dimensions['height'],
'mime-type' => $this->get_mime_type(),
'disabled' => false,
],
];
if ( ! $this->is_image() ) {
return $this->filter_media_files( $all_sizes );
}
// Remove common values (that have no value for us here, lol). Also remove 'full' and 'backup'.
$image_data = array_diff_key( $this->image->meta_data, [
'full' => 1,
'backup' => 1,
'width' => 1,
'height' => 1,
'md5' => 1,
'aperture' => 1,
'credit' => 1,
'camera' => 1,
'caption' => 1,
'created_timestamp' => 1,
'copyright' => 1,
'focal_length' => 1,
'iso' => 1,
'shutter_speed' => 1,
'flash' => 1,
'title' => 1,
'keywords' => 1,
'saved' => 1,
] );
if ( ! $image_data ) {
return $this->filter_media_files( $all_sizes );
}
$ngg_data = $this->storage->_image_mapper->find( $this->get_id() );
foreach ( $image_data as $size => $size_data ) {
if ( ! isset( $size_data['width'], $size_data['height'], $size_data['filename'], $size_data['generated'] ) ) {
continue;
}
$file_type = (object) wp_check_filetype( $size_data['filename'], $this->get_allowed_mime_types() );
if ( ! $file_type->type ) {
continue;
}
$all_sizes[ $size ] = [
'size' => $size,
'path' => $this->storage->get_image_abspath( $ngg_data, $size ),
'width' => (int) $size_data['width'],
'height' => (int) $size_data['height'],
'mime-type' => $file_type->type,
'disabled' => false,
];
}
return $this->filter_media_files( $all_sizes );
}
/**
* If the media is an image, get its width and height.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @return array
*/
public function get_dimensions() {
if ( ! $this->is_image() ) {
return [
'width' => 0,
'height' => 0,
];
}
return [
'width' => ! empty( $this->image->meta_data['width'] ) ? (int) $this->image->meta_data['width'] : 0,
'height' => ! empty( $this->image->meta_data['height'] ) ? (int) $this->image->meta_data['height'] : 0,
];
}
/**
* Update the media data dimensions.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param array $dimensions {
* An array containing width and height.
*
* @type int $width The image width.
* @type int $height The image height.
* }
*/
protected function update_media_data_dimensions( $dimensions ) {
$changed = false;
$data = [
'width' => $dimensions['width'],
'height' => $dimensions['height'],
'md5' => md5_file( $this->get_raw_fullsize_path() ),
];
foreach ( $data as $k => $v ) {
if ( ! isset( $this->image->meta_data[ $k ] ) || $this->image->meta_data[ $k ] !== $v ) {
$this->image->meta_data[ $k ] = $v;
$changed = true;
}
}
if ( $changed ) {
\nggdb::update_image_meta( $this->id, $this->image->meta_data );
}
}
}

View File

@@ -1,106 +0,0 @@
<?php
namespace Imagify\ThirdParty\NGG;
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
/**
* Imagify NextGen Gallery storage class.
*
* @since 1.5
* @author Jonathan Buttigieg
*/
class NGGStorage extends \Mixin {
/**
* Class version.
*
* @var string
*/
const VERSION = '1.1';
/**
* Delete a gallery AND all the pictures associated to this gallery!
*
* @since 1.5
* @author Jonathan Buttigieg
*
* @param int|object $gallery A gallery ID or object.
* @return bool Whetther tha gallery was been deleted or not.
*/
public function delete_gallery( $gallery ) {
$gallery_id = is_numeric( $gallery ) ? $gallery : $gallery->{$gallery->id_field};
$images_id = \nggdb::get_ids_from_gallery( $gallery_id );
foreach ( $images_id as $pid ) {
$process = imagify_get_optimization_process( $pid, 'ngg' );
if ( $process->is_valid() && $process->get_data()->is_optimized() ) {
$process->get_data()->delete_optimization_data();
}
}
return $this->call_parent( 'delete_gallery', $gallery );
}
/**
* Generates a specific size for an image.
*
* @since 1.5
* @author Jonathan Buttigieg
*
* @param int|object $image An image ID or NGG object.
* @param string $size An image size.
* @param array $params An array of parameters.
* @param bool $skip_defaults Whatever NGG does with default settings.
* @return bool|object An object on success. False on failure.
*/
public function generate_image_size( $image, $size, $params = null, $skip_defaults = false ) {
// $image could be an object or an (int) image ID.
if ( is_numeric( $image ) ) {
$image = $this->object->_image_mapper->find( $image );
}
// If a user adds a watermark, rotates or resizes an image, we restore it.
// TO DO - waiting for a hook to be able to re-optimize the original size after restoring.
if ( isset( $image->pid ) && ( true === $params['watermark'] || ( isset( $params['rotation'] ) || isset( $params['flip'] ) ) || ( ! empty( $params['width'] ) || ! empty( $params['height'] ) ) ) ) {
$process = imagify_get_optimization_process( $image->pid, 'ngg' );
if ( $process->is_valid() && $process->get_data()->is_optimized() ) {
$process->get_data()->delete_optimization_data();
}
}
return $this->call_parent( 'generate_image_size', $image, $size, $params, $skip_defaults );
}
/**
* Recover image from backup.
*
* @since 1.5
* @author Jonathan Buttigieg
*
* @param int|object $image An image ID or NGG object.
* @return string|bool Result code on success. False on failure.
*/
public function recover_image( $image ) {
// $image could be an object or an (int) image ID.
if ( is_numeric( $image ) ) {
$image = $this->object->_image_mapper->find( $image );
}
if ( ! $image ) {
return false;
}
// Remove Imagify data.
if ( isset( $image->pid ) ) {
$process = imagify_get_optimization_process( $image->pid, 'ngg' );
if ( $process->is_valid() && $process->get_data()->is_optimized() ) {
$process->get_data()->delete_optimization_data();
}
}
return $this->call_parent( 'recover_image', $image );
}
}

View File

@@ -1,284 +0,0 @@
<?php
namespace Imagify\ThirdParty\NGG\Optimization\Data;
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
/**
* Optimization data class for the custom folders.
* This class constructor accepts:
* - A NGG image ID (int).
* - A \nggImage object.
* - A \nggdb object.
* - An anonym object containing a pid property (and everything else).
* - A \Imagify\Media\MediaInterface object.
*
* @since 1.9
* @see Imagify\ThirdParty\NGG\Media\NGG
* @author Grégory Viguier
*/
class NGG extends \Imagify\Optimization\Data\AbstractData {
use \Imagify\Traits\MediaRowTrait;
/**
* The attachment SQL DB class.
*
* @var string
* @since 1.9
* @access protected
* @author Grégory Viguier
*/
protected $db_class_name = '\\Imagify\\ThirdParty\\NGG\\DB';
/**
* The constructor.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param mixed $id An ID, or whatever type the "Media" class constructor accepts.
*/
public function __construct( $id ) {
parent::__construct( $id );
if ( ! $this->is_valid() ) {
return;
}
// This is required by MediaRowTrait.
$this->id = $this->get_media()->get_id();
}
/**
* Get the whole media optimization data.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @return array The data. See parent method for details.
*/
public function get_optimization_data() {
if ( ! $this->is_valid() ) {
return $this->default_optimization_data;
}
$row = array_merge( $this->get_row_db_instance()->get_column_defaults(), $this->get_row() );
$data = $this->default_optimization_data;
$data['status'] = $row['status'];
$data['level'] = $row['optimization_level'];
$data['level'] = is_numeric( $data['level'] ) ? (int) $data['level'] : false;
$data['stats'] = [
'original_size' => 0,
'optimized_size' => 0,
'percent' => 0,
];
if ( ! empty( $row['data']['sizes'] ) && is_array( $row['data']['sizes'] ) ) {
$data['sizes'] = $row['data']['sizes'];
$data['sizes'] = array_filter( $data['sizes'], 'is_array' );
}
if ( empty( $data['sizes']['full'] ) ) {
if ( 'success' === $row['status'] ) {
$data['sizes']['full'] = [
'success' => true,
'original_size' => 0,
'optimized_size' => 0,
'percent' => 0,
];
} elseif ( ! empty( $row['status'] ) ) {
$data['sizes']['full'] = [
'success' => false,
'error' => '',
];
}
}
if ( empty( $data['sizes'] ) ) {
return $data;
}
foreach ( $data['sizes'] as $size_data ) {
// Cast.
if ( isset( $size_data['original_size'] ) ) {
$size_data['original_size'] = (int) $size_data['original_size'];
}
if ( isset( $size_data['optimized_size'] ) ) {
$size_data['optimized_size'] = (int) $size_data['optimized_size'];
}
if ( isset( $size_data['percent'] ) ) {
$size_data['percent'] = round( $size_data['percent'], 2 );
}
// Stats.
if ( ! empty( $size_data['original_size'] ) && ! empty( $size_data['optimized_size'] ) ) {
$data['stats']['original_size'] += $size_data['original_size'];
$data['stats']['optimized_size'] += $size_data['optimized_size'];
}
}
if ( $data['stats']['original_size'] && $data['stats']['optimized_size'] ) {
$data['stats']['percent'] = $data['stats']['original_size'] - $data['stats']['optimized_size'];
$data['stats']['percent'] = round( $data['stats']['percent'] / $data['stats']['original_size'] * 100, 2 );
}
return $data;
}
/**
* Update the optimization data, level, and status for a size.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param string $size The size name.
* @param array $data The optimization data. See parent method for details.
*/
public function update_size_optimization_data( $size, array $data ) {
if ( ! $this->is_valid() ) {
return;
}
$old_data = array_merge( $this->get_reset_data(), $this->get_row() );
$old_data['data']['sizes'] = ! empty( $old_data['data']['sizes'] ) && is_array( $old_data['data']['sizes'] ) ? $old_data['data']['sizes'] : [];
if ( 'full' === $size ) {
/**
* Original file.
*/
$old_data['optimization_level'] = $data['level'];
$old_data['status'] = $data['status'];
}
if ( ! $data['success'] ) {
/**
* Error.
*/
$old_data['data']['sizes'][ $size ] = [
'success' => false,
'error' => $data['error'],
];
} else {
/**
* Success.
*/
$old_data['data']['sizes'][ $size ] = [
'success' => true,
'original_size' => $data['original_size'],
'optimized_size' => $data['optimized_size'],
'percent' => round( ( $data['original_size'] - $data['optimized_size'] ) / $data['original_size'] * 100, 2 ),
];
}
$this->update_row( $old_data );
}
/**
* Delete the media optimization data, level, and status.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*/
public function delete_optimization_data() {
if ( ! $this->is_valid() ) {
return;
}
$this->delete_row();
}
/**
* Delete the optimization data for the given sizes.
* If all sizes are removed, all optimization data is deleted.
* Status and level are not modified nor removed if the "full" size is removed. This leaves the media in a Schrödinger state.
*
* @since 1.9.8
* @access public
* @author Grégory Viguier
*
* @param array $sizes A list of sizes to remove.
*/
public function delete_sizes_optimization_data( array $sizes ) {
if ( ! $sizes || ! $this->is_valid() ) {
return;
}
$data = array_merge( $this->get_reset_data(), $this->get_row() );
$data['data']['sizes'] = ! empty( $data['data']['sizes'] ) && is_array( $data['data']['sizes'] ) ? $data['data']['sizes'] : [];
if ( ! $data['data']['sizes'] ) {
return;
}
$remaining_sizes_data = array_diff_key( $data['data']['sizes'], array_flip( $sizes ) );
if ( ! $remaining_sizes_data ) {
// All sizes have been removed: delete everything.
$this->delete_optimization_data();
return;
}
if ( count( $remaining_sizes_data ) === count( $data['data']['sizes'] ) ) {
// Nothing has been removed.
return;
}
$data['data']['sizes'] = $remaining_sizes_data;
$this->update_row( $data );
}
/**
* Get default values used to reset optimization data.
*
* @since 1.9
* @access protected
* @author Grégory Viguier
*
* @return array {
* The default values related to the optimization.
*
* @type string $optimization_level The optimization level.
* @type string $status The status: success, already_optimized, error.
* @type array $data Data related to the thumbnails.
* }
*/
protected function get_reset_data() {
$db_instance = $this->get_row_db_instance();
$primary_key = $db_instance->get_primary_key();
$column_defaults = $db_instance->get_column_defaults();
return array_diff_key( $column_defaults, [
'data_id' => 0,
$primary_key => 0,
] );
}
/**
* Update the row.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param array $data The data to update.
*/
public function update_row( $data ) {
if ( ! $this->db_class_name || $this->id <= 0 ) {
return;
}
$primary_key = $this->get_row_db_instance()->get_primary_key();
// This is needed in case the row doesn't exist yet.
$data[ $primary_key ] = $this->id;
$this->get_row_db_instance()->update( $this->id, $data );
$this->reset_row_cache();
}
}

View File

@@ -1,88 +0,0 @@
<?php
namespace Imagify\ThirdParty\NGG\Optimization\Process;
use Imagify\Optimization\File;
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
/**
* Optimization class for NextGen Gallery.
* This class constructor accepts:
* - A NGG image ID (int).
* - A \nggImage object.
* - A \nggdb object.
* - An anonym object containing a pid property (and everything else).
* - A \Imagify\Media\MediaInterface object.
*
* @since 1.9
* @see Imagify\ThirdParty\NGG\Media\NGG
* @author Grégory Viguier
*/
class NGG extends \Imagify\Optimization\Process\AbstractProcess {
/** ----------------------------------------------------------------------------------------- */
/** MISSING THUMBNAILS ====================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Get the sizes for this media that have not get through optimization.
* Since this context doesn't handle this feature, this will always return an empty array, unless an error is triggered.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @return array|WP_Error A WP_Error object on failure. An empty array on success: this context has no thumbnails.
* The tests are kept for consistency.
*/
public function get_missing_sizes() {
// The media must have been optimized once and have a backup.
if ( ! $this->is_valid() ) {
return new \WP_Error( 'invalid_media', __( 'This media is not valid.', 'imagify' ) );
}
$media = $this->get_media();
if ( ! $media->is_supported() ) {
return new \WP_Error( 'media_not_supported', __( 'This media is not supported.', 'imagify' ) );
}
$data = $this->get_data();
if ( ! $data->is_optimized() ) {
return new \WP_Error( 'media_not_optimized', __( 'This media is not optimized yet.', 'imagify' ) );
}
if ( ! $media->has_backup() ) {
return new \WP_Error( 'no_backup', __( 'This file has no backup file.', 'imagify' ) );
}
if ( ! $media->is_image() ) {
return new \WP_Error( 'media_not_an_image', __( 'This media is not an image.', 'imagify' ) );
}
return [];
}
/**
* Optimize missing thumbnail sizes.
* Since this context doesn't handle this feature, this will always return a \WP_Error object.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @return bool|WP_Error True if successfully launched. A \WP_Error instance on failure.
*/
public function optimize_missing_thumbnails() {
if ( ! $this->is_valid() ) {
return new \WP_Error( 'invalid_media', __( 'This media is not valid.', 'imagify' ) );
}
if ( ! $this->get_media()->is_supported() ) {
return new \WP_Error( 'media_not_supported', __( 'This media is not supported.', 'imagify' ) );
}
return new \WP_Error( 'no_sizes', __( 'No thumbnails seem to be missing.', 'imagify' ) );
}
}

View File

@@ -1,107 +0,0 @@
<?php
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
add_filter( 'imagify_bulk_page_types', 'imagify_ngg_bulk_page_types' );
/**
* Filter the types to display in the bulk optimization page.
*
* @since 1.7.1
* @author Grégory Viguier
*
* @param array $types The folder types displayed on the page. If a folder type is "library", the context should be suffixed after a pipe character. They are passed as array keys.
* @return array
*/
function imagify_ngg_bulk_page_types( $types ) {
if ( ! empty( $_GET['page'] ) && imagify_get_ngg_bulk_screen_slug() === $_GET['page'] ) { // WPCS: CSRF ok.
$types['library|ngg'] = 1;
}
return $types;
}
add_filter( 'imagify_bulk_stats', 'imagify_ngg_bulk_stats', 10, 2 );
/**
* Filter the generic stats used in the bulk optimization page.
*
* @since 1.7.1
* @author Grégory Viguier
*
* @param array $data The data.
* @param array $types The folder types. They are passed as array keys.
* @return array
*/
function imagify_ngg_bulk_stats( $data, $types ) {
if ( ! isset( $types['library|ngg'] ) ) {
return $data;
}
add_filter( 'imagify_count_saving_data', 'imagify_ngg_count_saving_data', 8 );
$total_saving_data = imagify_count_saving_data();
remove_filter( 'imagify_count_saving_data', 'imagify_ngg_count_saving_data', 8 );
// Global chart.
$data['total_attachments'] += imagify_ngg_count_attachments();
$data['unoptimized_attachments'] += imagify_ngg_count_unoptimized_attachments();
$data['optimized_attachments'] += imagify_ngg_count_optimized_attachments();
$data['errors_attachments'] += imagify_ngg_count_error_attachments();
// Stats block.
$data['already_optimized_attachments'] += $total_saving_data['count'];
$data['original_human'] += $total_saving_data['original_size'];
$data['optimized_human'] += $total_saving_data['optimized_size'];
return $data;
}
add_filter( 'imagify_bulk_page_data', 'imagify_ngg_bulk_page_data', 10, 2 );
/**
* Filter the data to use on the bulk optimization page.
*
* @since 1.7
* @since 1.7.1 Added the $types parameter.
* @author Grégory Viguier
*
* @param array $data The data to use.
* @param array $types The folder types displayed on the page. They are passed as array keys.
* @return array
*/
function imagify_ngg_bulk_page_data( $data, $types ) {
if ( ! isset( $types['library|ngg'] ) ) {
return $data;
}
// Limits.
$data['unoptimized_attachment_limit'] += imagify_get_unoptimized_attachment_limit();
// Group.
$data['groups']['ngg'] = array(
/**
* The group_id corresponds to the file names like 'part-bulk-optimization-results-row-{$group_id}'.
* It is also used in get_imagify_localize_script_translations().
*/
'group_id' => 'library',
'context' => 'ngg',
'title' => __( 'NextGen Galleries', 'imagify' ),
/* translators: 1 is the opening of a link, 2 is the closing of this link. */
'footer' => sprintf( __( 'You can also re-optimize your images more finely directly in each %1$sgallery%2$s.', 'imagify' ), '<a href="' . esc_url( admin_url( 'admin.php?page=nggallery-manage-gallery' ) ) . '">', '</a>' ),
);
return $data;
}
add_filter( 'imagify_optimization_errors_url', 'imagify_ngg_optimization_errors_url', 10, 2 );
/**
* Provide a URL to a page displaying optimization errors for the NGG context.
*
* @since 1.9
* @author Grégory Viguier
*
* @param string $url The URL.
* @param string $context The context.
* @return string
*/
function imagify_ngg_optimization_errors_url( $url, $context ) {
if ( 'ngg' === $context ) {
return admin_url( 'admin.php?page=nggallery-manage-gallery' );
}
return $url;
}

View File

@@ -1,45 +0,0 @@
<?php
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
add_action( 'imagify_assets_enqueued', '_imagify_ngg_admin_print_styles' );
/**
* Add some CSS and JS for NGG compatibility.
*
* @since 1.5
* @since 1.6.10 Use the new class Imagify_Assets.
* @author Jonathan Buttigieg
* @author Grégory Viguier
*/
function _imagify_ngg_admin_print_styles() {
$assets = Imagify_Assets::get_instance();
/**
* Manage Gallery Images.
*/
if ( imagify_is_screen( 'nggallery-manage-images' ) || isset( $_GET['gid'] ) && ! empty( $_GET['pid'] ) && imagify_is_screen( 'nggallery-manage-gallery' ) ) { // WPCS: CSRF ok.
$assets->enqueue_style( 'admin' )->enqueue_script( 'library' );
return;
}
/**
* NGG Bulk Optimization.
*/
$bulk_screen_id = imagify_get_ngg_bulk_screen_id();
if ( ! imagify_is_screen( $bulk_screen_id ) ) {
return;
}
$assets->remove_deferred_localization( 'bulk', 'imagifyBulk' );
$l10n = $assets->get_localization_data( 'bulk', [
'bufferSizes' => [
'ngg' => 4,
],
] );
/** This filter is documented in inc/functions/i18n.php */
$l10n['bufferSizes'] = apply_filters( 'imagify_bulk_buffer_sizes', $l10n['bufferSizes'] );
$assets->enqueue_assets( [ 'pricing-modal', 'bulk' ] )->localize( 'imagifyBulk', $l10n );
}

View File

@@ -1,64 +0,0 @@
<?php
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
add_filter( 'ngg_manage_images_number_of_columns', '_imagify_ngg_manage_images_number_of_columns' );
/**
* Add "Imagify" column in admin.php?page=nggallery-manage-gallery.
*
* @since 1.5
* @author Jonathan Buttigieg
*
* @param int $count Number of columns.
* @return int Incremented number of columns.
*/
function _imagify_ngg_manage_images_number_of_columns( $count ) {
$count++;
add_filter( 'ngg_manage_images_column_' . $count . '_header', '_imagify_ngg_manage_media_columns' );
add_filter( 'ngg_manage_images_column_' . $count . '_content', '_imagify_ngg_manage_media_custom_column', 10, 2 );
return $count;
}
/**
* Get the column title.
*
* @since 1.5
* @author Jonathan Buttigieg
*
* @return string
*/
function _imagify_ngg_manage_media_columns() {
return 'Imagify';
}
/**
* Get the column content.
*
* @since 1.5
* @author Jonathan Buttigieg
*
* @param string $output The column content.
* @param object $image An NGG Image object.
* @return string
*/
function _imagify_ngg_manage_media_custom_column( $output, $image ) {
$process = imagify_get_optimization_process( $image, 'ngg' );
return get_imagify_media_column_content( $process );
}
add_filter( 'imagify_display_missing_thumbnails_link', '_imagify_ngg_hide_missing_thumbnails_link', 10, 3 );
/**
* Hide the "Optimize missing thumbnails" link.
*
* @since 1.6.10
* @author Grégory Viguier
*
* @param bool $display True to display the link. False to not display it.
* @param object $attachment The attachement object.
* @param string $context The context.
* @return bool
*/
function _imagify_ngg_hide_missing_thumbnails_link( $display, $attachment, $context ) {
return 'ngg' === $context ? false : $display;
}

View File

@@ -1,19 +0,0 @@
<?php
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
add_action( 'admin_menu', '_imagify_ngg_bulk_optimization_menu' );
/**
* Add submenu in menu "Media"
*
* @since 1.5
* @author Jonathan Buttigieg
*/
function _imagify_ngg_bulk_optimization_menu() {
if ( ! defined( 'NGGFOLDER' ) ) {
return;
}
$capacity = imagify_get_context( 'ngg' )->get_capacity( 'bulk-optimize' );
add_submenu_page( NGGFOLDER, __( 'Bulk Optimization', 'imagify' ), __( 'Bulk Optimization', 'imagify' ), $capacity, imagify_get_ngg_bulk_screen_slug(), '_imagify_display_bulk_page' );
}

View File

@@ -1,347 +0,0 @@
<?php
use \Imagify\Optimization\File;
use \Imagify\ThirdParty\NGG;
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
add_action( 'ngg_after_new_images_added', '_imagify_ngg_optimize_attachment', IMAGIFY_INT_MAX, 2 );
/**
* Auto-optimize when a new attachment is added to the database (NGG plugin's table), except for images imported from the library.
*
* @since 1.5
* @author Jonathan Buttigieg
*
* @param int $gallery_id A Gallery ID.
* @param array $image_ids An array of Ids or objects. Ids which are sucessfully added.
*/
function _imagify_ngg_optimize_attachment( $gallery_id, $image_ids ) {
if ( ! Imagify_Requirements::is_api_key_valid() || ! get_imagify_option( 'auto_optimize' ) ) {
return;
}
$is_maybe_library_import = ! empty( $_POST['action'] ) && 'import_media_library' === $_POST['action'] && ! empty( $_POST['attachment_ids'] ) && is_array( $_POST['attachment_ids'] ); // WPCS: CSRF ok.
if ( $is_maybe_library_import && ! empty( $_POST['nextgen_upload_image_sec'] ) ) { // WPCS: CSRF ok.
/**
* The images are imported from the library.
* In this case, those images are dealt with in _imagify_ngg_media_library_imported_image_data().
*/
return;
}
if ( $is_maybe_library_import && ( ! empty( $_POST['gallery_id'] ) || ! empty( $_POST['gallery_name'] ) ) ) { // WPCS: CSRF ok.
/**
* Same thing but for NGG 2.0 probably.
*/
return;
}
foreach ( $image_ids as $image ) {
if ( is_numeric( $image ) ) {
$image_id = (int) $image;
} elseif ( is_object( $image ) && ! empty( $image->pid ) ) {
$image_id = (int) $image->pid;
} else {
$image_id = 0;
}
if ( ! $image_id ) {
continue;
}
/**
* Allow to prevent automatic optimization for a specific NGG gallery image.
*
* @since 1.6.12
* @author Grégory Viguier
*
* @param bool $optimize True to optimize, false otherwise.
* @param int $image_id Image ID.
* @param int $gallery_id Gallery ID.
*/
$optimize = apply_filters( 'imagify_auto_optimize_ngg_gallery_image', true, $image_id, $gallery_id );
if ( ! $optimize ) {
continue;
}
$process = imagify_get_optimization_process( $image, 'ngg' );
if ( ! $process->is_valid() ) {
continue;
}
if ( $process->get_data()->get_optimization_status() ) {
// Optimization already attempted.
continue;
}
$process->optimize();
}
}
add_filter( 'ngg_medialibrary_imported_image', '_imagify_ngg_media_library_imported_image_data', 10, 2 );
/**
* Import Imagify data from a WordPress image to a new NGG image, and optimize the thumbnails.
*
* @since 1.5
* @author Jonathan Buttigieg
*
* @param object $image A NGG image object.
* @param object $attachment An attachment object.
* @return object
*/
function _imagify_ngg_media_library_imported_image_data( $image, $attachment ) {
$wp_process = imagify_get_optimization_process( $attachment->ID, 'wp' );
if ( ! $wp_process->is_valid() || ! $wp_process->get_media()->is_supported() ) {
return $image;
}
$wp_data = $wp_process->get_data();
if ( ! $wp_data->is_optimized() ) {
// The main image is not optimized.
return $image;
}
// Copy the full size data.
$wp_full_size_data = $wp_data->get_size_data();
$optimization_level = $wp_data->get_optimization_level();
NGG\DB::get_instance()->update( $image->pid, [
'pid' => $image->pid,
'optimization_level' => $optimization_level,
'status' => $wp_data->get_optimization_status(),
'data' => [
'sizes' => [
'full' => $wp_full_size_data,
],
'stats' => [
'original_size' => $wp_full_size_data['original_size'],
'optimized_size' => $wp_full_size_data['optimized_size'],
'percent' => $wp_full_size_data['percent'],
],
],
] );
$ngg_process = imagify_get_optimization_process( $image->pid, 'ngg' );
if ( ! $ngg_process->is_valid() ) {
// WTF.
return $image;
}
// Copy the backup file (we don't want to backup the optimized file if it can be avoided).
$ngg_media = $ngg_process->get_media();
$wp_media = $wp_process->get_media();
$wp_backup_path = $wp_media->get_backup_path();
$filesystem = imagify_get_filesystem();
$backup_copied = false;
if ( $wp_backup_path ) {
$ngg_backup_path = $ngg_media->get_raw_backup_path();
$backup_copied = $filesystem->copy( $wp_backup_path, $ngg_backup_path, true );
if ( $backup_copied ) {
$filesystem->chmod_file( $ngg_backup_path );
}
}
/**
* Next-gen for the full size.
* Look for an existing copy locally:
* - if it exists, copy it (and its optimization data),
* - if not, add it to the optimization queue.
*/
$add_full_nextgen = $wp_media->is_image();
if ( $add_full_nextgen ) {
$formats = [
'avif' => $wp_process::AVIF_SUFFIX,
'webp' => $wp_process::WEBP_SUFFIX,
];
foreach ( $formats as $extension => $suffix ) {
$wp_full_path_nextgen = false;
$nextgen_size_name = 'full' . $suffix;
$wp_nextgen_data = $wp_data->get_size_data( $nextgen_size_name );
// Get the path to the next-gen image if it exists.
$wp_full_path_nextgen = $wp_process->get_fullsize_file()->get_path_to_nextgen( $extension );
if ( $wp_full_path_nextgen && ! $filesystem->exists( $wp_full_path_nextgen ) ) {
$wp_full_path_nextgen = false;
}
if ( $wp_full_path_nextgen ) {
// We know we have a next-gen version. Make sure we have the right data.
$wp_nextgen_data['success'] = true;
if ( empty( $wp_nextgen_data['original_size'] ) ) {
// The next-gen data is missing.
$full_size_weight = $wp_full_size_data['original_size'];
if ( ! $full_size_weight && $wp_backup_path ) {
// For some reason we don't have the original file weight, but we can get it from the backup file.
$full_size_weight = $filesystem->size( $wp_backup_path );
if ( $full_size_weight ) {
$wp_nextgen_data['original_size'] = $full_size_weight;
}
}
}
if ( ! empty( $wp_nextgen_data['original_size'] ) && empty( $wp_nextgen_data['optimized_size'] ) ) {
// The next-gen file size.
$wp_nextgen_data['optimized_size'] = $filesystem->size( $wp_full_path_nextgen );
}
if ( empty( $wp_nextgen_data['original_size'] ) || empty( $wp_nextgen_data['optimized_size'] ) ) {
// We must have both original and optimized sizes.
$wp_nextgen_data = [];
}
}
if ( $wp_full_path_nextgen && $wp_nextgen_data ) {
// We have the file and the data.
// Copy the file.
$ngg_full_file = new File( $ngg_media->get_raw_fullsize_path() );
$ngg_full_path_nextgen = $ngg_full_file->get_path_to_nextgen( $extension ); // Destination.
if ( $ngg_full_path_nextgen ) {
$copied = $filesystem->copy( $wp_full_path_nextgen, $ngg_full_path_nextgen, true );
if ( $copied ) {
// Success.
$filesystem->chmod_file( $ngg_full_path_nextgen );
$add_full_nextgen = false;
}
}
if ( ! $add_full_nextgen ) {
// The next-gen file has been successfully copied: now, copy the data.
$ngg_process->get_data()->update_size_optimization_data( $nextgen_size_name, $wp_nextgen_data );
}
}
}
}
// Optimize thumbnails.
$sizes = $ngg_media->get_media_files();
unset( $sizes['full'] );
if ( $add_full_nextgen ) {
// We could not use a local next-gen copy: ask for a new one.
$formats = imagify_nextgen_images_formats();
foreach ( $formats as $format ) {
if ( 'webp' === $format ) {
$suffix = $wp_process::WEBP_SUFFIX;
} elseif ( 'avif' === $format ) {
$suffix = $wp_process::AVIF_SUFFIX;
}
$sizes[ 'full' . $suffix ] = [];
}
}
if ( ! $sizes ) {
return $image;
}
$args = [
'hook_suffix' => 'optimize_imported_images',
];
$ngg_process->optimize_sizes( array_keys( $sizes ), $optimization_level, $args );
return $image;
}
add_action( 'ngg_generated_image', 'imagify_ngg_maybe_add_dynamic_thumbnail_to_background_process', IMAGIFY_INT_MAX, 2 );
/**
* Add a dynamically generated thumbnail to the background process queue.
* Note that this wont work when images are imported (from WP Library or uploaded), since they are already being processed, and locked.
*
* @since 1.8
* @since 1.9 Doesn't use the class Imagify_NGG_Dynamic_Thumbnails_Background_Process anymore.
* @author Grégory Viguier
*
* @param object $image A NGG image object.
* @param string $size The thumbnail size name.
*/
function imagify_ngg_maybe_add_dynamic_thumbnail_to_background_process( $image, $size ) {
NGG\DynamicThumbnails::get_instance()->push_to_queue( $image, $size );
}
add_action( 'ngg_delete_picture', 'imagify_ngg_cleanup_after_media_deletion', 10, 2 );
/**
* Delete everything when a NGG image is deleted.
*
* @since 1.9
* @author Grégory Viguier
*
* @param int $image_id The image ID.
* @param object $image A NGG object.
*/
function imagify_ngg_cleanup_after_media_deletion( $image_id, $image ) {
$process = imagify_get_optimization_process( $image, 'ngg' );
if ( ! $process->is_valid() ) {
return;
}
// Trigger a common hook.
imagify_trigger_delete_media_hook( $process );
/**
* The backup file has already been deleted by NGG.
* Delete the next-gen versions and the optimization data.
*/
$process->delete_nextgen_files();
$process->get_data()->delete_optimization_data();
}
add_filter( 'imagify_crop_thumbnail', 'imagify_ngg_should_crop_thumbnail', 10, 4 );
/**
* In case of a dynamic thumbnail, tell if the image must be croped or resized.
*
* @since 1.9
* @author Grégory Viguier
*
* @param bool $crop True to crop the thumbnail, false to resize. Null by default.
* @param string $size Name of the thumbnail size.
* @param array $size_data Data of the thumbnail being processed. Contains at least 'width', 'height', and 'path'.
* @param MediaInterface $media The MediaInterface instance corresponding to the image being processed.
* @return bool
*/
function imagify_ngg_should_crop_thumbnail( $crop, $size, $size_data, $media ) {
static $data_per_media = [];
static $storage_per_media = [];
if ( 'ngg' !== $media->get_context() ) {
return $crop;
}
$media_id = $media->get_id();
if ( ! isset( $data_per_media[ $media_id ] ) ) {
$image = \nggdb::find_image( $media_id );
if ( ! empty( $image->_ngiw ) ) {
$storage_per_media[ $media_id ] = $image->_ngiw->get_storage()->object;
} else {
$storage_per_media[ $media_id ] = \C_Gallery_Storage::get_instance()->object;
}
$data_per_media[ $media_id ] = $storage_per_media[ $media_id ]->_image_mapper->find( $media_id ); // stdClass Object.
}
$params = $storage_per_media[ $media_id ]->get_image_size_params( $data_per_media[ $media_id ], $size );
return ! empty( $params['crop'] );
}

View File

@@ -1,198 +0,0 @@
<?php
use \Imagify\ThirdParty\NGG\DB;
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
/**
* Count number of attachments.
*
* @since 1.5
* @author Jonathan Buttigieg
*
* @return int The number of attachments.
*/
function imagify_ngg_count_attachments() {
global $wpdb;
static $count;
if ( isset( $count ) ) {
return $count;
}
$table_name = $wpdb->prefix . 'ngg_pictures';
$count = (int) $wpdb->get_var( "SELECT COUNT($table_name.pid) FROM $table_name" ); // WPCS: unprepared SQL ok.
return $count;
}
/**
* Count number of optimized attachments with an error.
*
* @since 1.5
* @author Jonathan Buttigieg
*
* @return int The number of attachments.
*/
function imagify_ngg_count_error_attachments() {
static $count;
if ( isset( $count ) ) {
return $count;
}
$ngg_db = DB::get_instance();
$key = $ngg_db->get_primary_key();
$count = (int) $ngg_db->get_var_by( "COUNT($key)", 'status', 'error' );
return $count;
}
/**
* Count number of optimized attachments (by Imagify or an other tool before).
*
* @since 1.5
* @author Jonathan Buttigieg
*
* @return int The number of attachments.
*/
function imagify_ngg_count_optimized_attachments() {
static $count;
if ( isset( $count ) ) {
return $count;
}
$ngg_db = DB::get_instance();
$key = $ngg_db->get_primary_key();
$count = (int) $ngg_db->get_var_in( "COUNT($key)", 'status', array( 'success', 'already_optimized' ) );
return $count;
}
/**
* Count number of unoptimized attachments.
*
* @since 1.0
* @author Jonathan Buttigieg
*
* @return int The number of attachments.
*/
function imagify_ngg_count_unoptimized_attachments() {
return imagify_ngg_count_attachments() - imagify_ngg_count_optimized_attachments() - imagify_ngg_count_error_attachments();
}
/**
* Count percent of optimized attachments.
*
* @since 1.0
* @author Jonathan Buttigieg
*
* @return int The percent of optimized attachments.
*/
function imagify_ngg_percent_optimized_attachments() {
$total_attachments = imagify_ngg_count_attachments();
$total_optimized_attachments = imagify_ngg_count_optimized_attachments();
if ( ! $total_attachments || ! $total_optimized_attachments ) {
return 0;
}
return min( round( 100 * $total_optimized_attachments / $total_attachments ), 100 );
}
/**
* Count percent, original & optimized size of all images optimized by Imagify.
*
* @since 1.5
* @since 1.6.7 Revamped to handle huge libraries.
* @author Jonathan Buttigieg
*
* @param bool|array $attachments An array containing the keys 'count', 'original_size', and 'optimized_size', or an array of attachments (back compat', deprecated), or false.
* @return array An array containing the keys 'count', 'original_size', and 'optimized_size'.
*/
function imagify_ngg_count_saving_data( $attachments ) {
global $wpdb;
if ( is_array( $attachments ) ) {
return $attachments;
}
/**
* Filter the query to get all optimized NGG attachments.
* 3rd party will be able to override the result.
*
* @since 1.6.7
*
* @param bool|array $attachments An array containing the keys ('count', 'original_size', and 'optimized_size'), or false.
*/
$attachments = apply_filters( 'imagify_ngg_count_saving_data', false );
if ( is_array( $attachments ) ) {
return $attachments;
}
$original_size = 0;
$optimized_size = 0;
$count = 0;
/** This filter is documented in /inc/functions/admin-stats.php */
$limit = apply_filters( 'imagify_count_saving_data_limit', 15000 );
$limit = absint( $limit );
$offset = 0;
$query = "
SELECT data
FROM $wpdb->ngg_imagify_data
WHERE status = 'success'
LIMIT %d, %d";
$attachments = $wpdb->get_col( $wpdb->prepare( $query, $offset, $limit ) ); // WPCS: unprepared SQL ok.
$wpdb->flush();
while ( $attachments ) {
$attachments = array_map( 'maybe_unserialize', $attachments );
foreach ( $attachments as $attachment_data ) {
if ( ! $attachment_data ) {
continue;
}
++$count;
$original_data = $attachment_data['sizes']['full'];
// Increment the original sizes.
$original_size += $original_data['original_size'] ? $original_data['original_size'] : 0;
$optimized_size += $original_data['optimized_size'] ? $original_data['optimized_size'] : 0;
unset( $attachment_data['sizes']['full'], $original_data );
// Increment the thumbnails sizes.
foreach ( $attachment_data['sizes'] as $size_data ) {
if ( ! empty( $size_data['success'] ) ) {
$original_size += $size_data['original_size'] ? $size_data['original_size'] : 0;
$optimized_size += $size_data['optimized_size'] ? $size_data['optimized_size'] : 0;
}
}
unset( $size_data );
}
unset( $attachment_data );
if ( count( $attachments ) === $limit ) {
// Unless we are really unlucky, we still have attachments to fetch.
$offset += $limit;
$attachments = $wpdb->get_col( $wpdb->prepare( $query, $offset, $limit ) ); // WPCS: unprepared SQL ok.
$wpdb->flush();
} else {
// Save one request, don't go back to the beginning of the loop.
$attachments = array();
}
} // End while().
return array(
'count' => $count,
'original_size' => $original_size,
'optimized_size' => $optimized_size,
);
}

View File

@@ -1,21 +0,0 @@
<?php
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
/**
* Get the backup path of a specific attachement.
*
* @since 1.6.8
* @author Grégory Viguier
*
* @param string $file_path The file path.
* @return string|bool The backup path. False on failure.
*/
function get_imagify_ngg_attachment_backup_path( $file_path ) {
$file_path = wp_normalize_path( (string) $file_path );
if ( ! $file_path ) {
return false;
}
return $file_path . '_backup';
}

View File

@@ -1,32 +0,0 @@
<?php
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
/**
* Get NGG Bulk Optimization screen ID.
* Because WP nonsense, the screen ID depends on the menu title, which is translated. So the screen ID changes depending on the administration locale.
*
* @since 1.6.13
* @author Grégory Viguier
*
* @return string
*/
function imagify_get_ngg_bulk_screen_id() {
global $admin_page_hooks;
$ngg_menu_slug = defined( 'NGGFOLDER' ) ? plugin_basename( NGGFOLDER ) : 'nextgen-gallery';
$ngg_menu_slug = isset( $admin_page_hooks[ $ngg_menu_slug ] ) ? $admin_page_hooks[ $ngg_menu_slug ] : 'gallery';
return $ngg_menu_slug . '_page_' . imagify_get_ngg_bulk_screen_slug();
}
/**
* Get NGG Bulk Optimization screen slug.
*
* @since 1.7
* @author Grégory Viguier
*
* @return string
*/
function imagify_get_ngg_bulk_screen_slug() {
return IMAGIFY_SLUG . '-ngg-bulk-optimization';
}

View File

@@ -1,27 +0,0 @@
<?php
use Imagify\ThirdParty\NGG;
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
if ( ! class_exists( 'C_NextGEN_Bootstrap' ) || ! class_exists( 'Mixin' ) || ! get_site_option( 'ngg_options' ) ) {
return;
}
class_alias( '\\Imagify\\ThirdParty\\NGG\\Main', '\\Imagify_NGG' );
class_alias( '\\Imagify\\ThirdParty\\NGG\\DB', '\\Imagify_NGG_DB' );
class_alias( '\\Imagify\\ThirdParty\\NGG\\NGGStorage', '\\Imagify_NGG_Storage' );
require IMAGIFY_PATH . 'inc/3rd-party/nextgen-gallery/inc/functions/admin-stats.php';
require IMAGIFY_PATH . 'inc/3rd-party/nextgen-gallery/inc/functions/attachments.php';
require IMAGIFY_PATH . 'inc/3rd-party/nextgen-gallery/inc/functions/common.php';
require IMAGIFY_PATH . 'inc/3rd-party/nextgen-gallery/inc/common/attachments.php';
NGG\Main::get_instance()->init();
NGG\DB::get_instance()->init();
if ( is_admin() ) {
require IMAGIFY_PATH . 'inc/3rd-party/nextgen-gallery/inc/admin/enqueue.php';
require IMAGIFY_PATH . 'inc/3rd-party/nextgen-gallery/inc/admin/menu.php';
require IMAGIFY_PATH . 'inc/3rd-party/nextgen-gallery/inc/admin/gallery.php';
require IMAGIFY_PATH . 'inc/3rd-party/nextgen-gallery/inc/admin/bulk.php';
}

View File

@@ -1,401 +0,0 @@
<?php
namespace Imagify\ThirdParty\RegenerateThumbnails;
use Imagify_Requirements;
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
/**
* Class that handles compatibility with Regenerate Thumbnails plugin.
*
* @since 1.7.1
* @author Grégory Viguier
*/
class Main extends \Imagify_Regenerate_Thumbnails_Deprecated {
use \Imagify\Traits\InstanceGetterTrait;
/**
* Class version.
*
* @var string
* @since 1.7.1
* @author Grégory Viguier
*/
const VERSION = '1.2';
/**
* Action used for the ajax callback.
*
* @var string
* @since 1.9
* @author Grégory Viguier
*/
const HOOK_SUFFIX = 'regenerate_thumbnails';
/**
* List of optimization processes.
*
* @var array An array of ProcessInterface objects. The array keys are the media IDs.
* @since 1.7.1
* @access protected
* @author Grégory Viguier
*/
protected $processes = [];
/**
* Tell if were playing in WP 5.3s garden.
*
* @var bool
* @since 1.9.8
* @access protected
* @author Grégory Viguier
*/
protected $is_wp53;
/** ----------------------------------------------------------------------------------------- */
/** INIT ==================================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Launch the hooks.
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*/
public function init() {
if ( ! class_exists( '\RegenerateThumbnails_Regenerator' ) ) {
return;
}
add_filter( 'rest_dispatch_request', [ $this, 'maybe_init_attachment' ], 4, 4 );
add_action( 'imagify_after_' . static::HOOK_SUFFIX, [ $this, 'after_regenerate_thumbnails' ], 8, 2 );
}
/** ----------------------------------------------------------------------------------------- */
/** HOOKS =================================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Filter the REST dispatch request result, to hook before Regenerate Thumbnails starts its magic.
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @param bool $dispatch_result Dispatch result, will be used if not empty.
* @param WP_REST_Request $request Request used to generate the response.
* @param string $route Route matched for the request.
* @param array $handler Route handler used for the request.
* @return bool
*/
public function maybe_init_attachment( $dispatch_result, $request, $route = null, $handler = null ) {
if ( strpos( $route, static::get_route_prefix() ) === false ) {
return $dispatch_result;
}
$media_id = $request->get_param( 'id' );
if ( ! $this->set_process( $media_id ) ) {
return $dispatch_result;
}
$media_id = $this->get_process( $media_id )->get_media()->get_id();
// The attachment can be regenerated: keep the optimized full-sized file safe, and replace it by the backup file.
$this->backup_optimized_file( $media_id );
// Prevent automatic optimization.
\Imagify_Auto_Optimization::prevent_optimization( $media_id );
// Launch the needed hook.
add_filter( 'wp_generate_attachment_metadata', [ $this, 'launch_async_optimization' ], IMAGIFY_INT_MAX - 30, 2 );
return $dispatch_result;
}
/**
* Auto-optimize after an attachment is regenerated.
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @param array $metadata An array of attachment meta data, containing the sizes that have been regenerated.
* @param int $media_id Current media ID.
* @return array
*/
public function launch_async_optimization( $metadata, $media_id ) {
$process = $this->get_process( $media_id );
if ( ! $process ) {
return $metadata;
}
$sizes = isset( $metadata['sizes'] ) && is_array( $metadata['sizes'] ) ? $metadata['sizes'] : [];
$media = $process->get_media();
$fullsize_path = $media->get_raw_fullsize_path();
if ( $fullsize_path ) {
$original_path = $media->get_original_path();
if ( $original_path && $this->is_wp_53() && $original_path !== $fullsize_path ) {
/**
* The original file and the full-sized file are not the same:
* That means wp_generate_attachment_metadata() recreated the full-sized file, based on the original one.
* So it must be optimized again now.
*/
$sizes['full'] = [];
}
}
if ( ! $sizes ) {
// Put the optimized full-sized file back.
$this->put_optimized_file_back( $media_id );
return $metadata;
}
/**
* Optimize the sizes that have been regenerated.
*/
// If the media has next-gen versions, recreate them for the sizes that have been regenerated.
$data = $process->get_data();
$optimization_data = $data->get_optimization_data();
if ( ! empty( $optimization_data['sizes'] ) ) {
foreach ( $optimization_data['sizes'] as $size_name => $size_data ) {
$non_nextgen_size_name = $process->is_size_next_gen( $size_name );
if ( ! $non_nextgen_size_name || ! isset( $sizes[ $non_nextgen_size_name ] ) ) {
continue;
}
// Add the next-gen size.
$sizes[ $size_name ] = [];
}
}
$sizes = array_keys( $sizes );
$optimization_level = $data->get_optimization_level();
$optimization_args = [ 'hook_suffix' => static::HOOK_SUFFIX ];
// Delete related optimization data or nothing will be optimized.
$data->delete_sizes_optimization_data( $sizes );
$process->optimize_sizes( $sizes, $optimization_level, $optimization_args );
$this->unset_process( $media_id );
return $metadata;
}
/**
* Fires after regenerating the thumbnails.
* This puts the full-sized optimized file back.
*
* @since 1.9
* @access public
* @author Grégory Viguier
*
* @param ProcessInterface $process The optimization process.
* @param array $item The item being processed. See $this->task().
*/
public function after_regenerate_thumbnails( $process, $item ) {
$media_id = $process->get_media()->get_id();
$this->processes[ $media_id ] = $process;
$this->put_optimized_file_back( $media_id );
}
/** ----------------------------------------------------------------------------------------- */
/** INTERNAL TOOLS ========================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Set an optimization process.
*
* @since 1.9
* @author Grégory Viguier
* @access protected
*
* @param int $media_id The media ID.
* @return bool
*/
protected function set_process( $media_id ) {
if ( ! $media_id || ! Imagify_Requirements::is_api_key_valid() ) {
return false;
}
$process = imagify_get_optimization_process( $media_id, 'wp' );
if ( ! $process->is_valid() || ! $process->get_media()->is_image() || ! $process->get_data()->is_optimized() ) {
// Invalid, not animage, or no optimization have been attempted yet.
return false;
}
$this->processes[ $media_id ] = $process;
return true;
}
/**
* Unset an optimization process.
*
* @since 1.9
* @access protected
* @author Grégory Viguier
*
* @param int $media_id The media ID.
*/
protected function unset_process( $media_id ) {
unset( $this->processes[ $media_id ] );
}
/**
* Unset an optimization process.
*
* @since 1.9
* @access protected
* @author Grégory Viguier
*
* @param int $media_id The media ID.
* @return ProcessInterface|bool An optimization process object. False on failure.
*/
protected function get_process( $media_id ) {
return ! empty( $this->processes[ $media_id ] ) ? $this->processes[ $media_id ] : false;
}
/**
* Backup the optimized full-sized file and replace it by the original backup file.
*
* @since 1.7.1
* @access protected
* @author Grégory Viguier
*
* @param int $media_id Media ID.
*/
protected function backup_optimized_file( $media_id ) {
$media = $this->get_process( $media_id )->get_media();
$fullsize_path = $media->get_raw_fullsize_path();
if ( ! $fullsize_path ) {
// Uh?
return;
}
$original_path = $media->get_original_path();
if ( $original_path && $this->is_wp_53() && $original_path !== $fullsize_path ) {
/**
* The original file and the full-sized file are not the same:
* That means wp_generate_attachment_metadata() will recreate the full-sized file, based on the original one.
* Then, the thumbnails will be created from a newly created (unoptimized) file.
*/
return;
}
$backup_path = $media->get_backup_path();
if ( ! $backup_path ) {
// No backup file, too bad.
return;
}
/**
* Replace the optimized full-sized file by the backup, so any optimization will not use an optimized file, but the original one.
* The optimized full-sized file is kept and renamed, and will be put back in place at the end of the optimization process.
*/
$filesystem = \Imagify_Filesystem::get_instance();
if ( $filesystem->exists( $fullsize_path ) ) {
$tmp_file_path = static::get_temporary_file_path( $fullsize_path );
$moved = $filesystem->move( $fullsize_path, $tmp_file_path, true );
}
$filesystem->copy( $backup_path, $fullsize_path );
}
/**
* Put the optimized full-sized file back.
*
* @since 1.7.1
* @since 1.9 Replaced $attachment parameter by $media_id.
* @access protected
* @author Grégory Viguier
*
* @param int $media_id Media ID.
*/
protected function put_optimized_file_back( $media_id ) {
$file_path = $this->get_process( $media_id )->get_media()->get_raw_fullsize_path();
$tmp_file_path = static::get_temporary_file_path( $file_path );
$filesystem = \Imagify_Filesystem::get_instance();
if ( $filesystem->exists( $tmp_file_path ) ) {
$moved = $filesystem->move( $tmp_file_path, $file_path, true );
}
}
/**
* Tell if were playing in WP 5.3s garden.
*
* @since 1.9.8
* @access protected
* @author Grégory Viguier
*
* @return bool
*/
protected function is_wp_53() {
if ( isset( $this->is_wp53 ) ) {
return $this->is_wp53;
}
$this->is_wp53 = function_exists( 'wp_get_original_image_path' );
return $this->is_wp53;
}
/** ----------------------------------------------------------------------------------------- */
/** PUBLIC TOOLS ============================================================================ */
/** ----------------------------------------------------------------------------------------- */
/**
* Get the beginning of the route used to regenerate thumbnails.
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @return string
*/
public static function get_route_prefix() {
static $route;
if ( ! isset( $route ) ) {
$regen = \RegenerateThumbnails();
if ( ( empty( $regen->rest_api ) || ! is_object( $regen->rest_api ) ) && method_exists( $regen, 'rest_api_init' ) ) {
$regen->rest_api_init();
}
$route = '/' . trim( $regen->rest_api->namespace, '/' ) . '/regenerate/';
}
return $route;
}
/**
* Get the path to the temporary file.
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @param string $file_path The optimized full-sized file path.
* @return string
*/
public static function get_temporary_file_path( $file_path ) {
return $file_path . '_backup';
}
}

View File

@@ -1,10 +0,0 @@
<?php
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
if ( ! class_exists( 'RegenerateThumbnails' ) || ! function_exists( 'RegenerateThumbnails' ) ) {
return;
}
class_alias( '\\Imagify\\ThirdParty\\RegenerateThumbnails\\Main', '\\Imagify_Regenerate_Thumbnails' );
add_action( 'init', [ \Imagify\ThirdParty\RegenerateThumbnails\Main::get_instance(), 'init' ], 20 );

View File

@@ -1,31 +0,0 @@
<?php
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
if ( function_exists( 'fn_lc_fix_ssl_upload_url' ) && defined( 'SLC_VERSION' ) && version_compare( SLC_VERSION, '2.2.8' ) < 0 ) :
/**
* Fixes a bug in Screets Live Chat plugin (prior version 2.2.8), preventing wp_get_upload_dir() to work properly.
*/
remove_filter( 'upload_dir', 'fn_lc_fix_ssl_upload_url' );
add_filter( 'upload_dir', 'imagify_screets_lc_fix_ssl_upload_url' );
/**
* Filters the uploads directory data to force https URLs.
*
* @since 1.6.7
* @author Grégory Viguier
*
* @param array $uploads Array of upload directory data with keys of 'path', 'url', 'subdir, 'basedir', 'baseurl', and 'error'.
* @return array
*/
function imagify_screets_lc_fix_ssl_upload_url( $uploads ) {
if ( false !== $uploads['error'] || ! is_ssl() ) {
return $uploads;
}
$uploads['url'] = str_replace( 'http://', 'https://', $uploads['url'] );
$uploads['baseurl'] = str_replace( 'http://', 'https://', $uploads['baseurl'] );
return $uploads;
}
endif;

View File

@@ -1,25 +0,0 @@
<?php
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
add_action( 'admin_enqueue_scripts', function( $hook_suffix ) {
$imagify_admin_pages = array(
'media_page_imagify-bulk-optimization',
'settings_page_imagify',
'media_page_imagify-files',
'nextgen-gallery_page_imagify-ngg-bulk-optimization',
);
if (
! is_admin()
||
! class_exists( 'SWCFPC_Backend' )
||
! in_array( $hook_suffix, $imagify_admin_pages, true )
) {
return;
}
wp_deregister_script( 'swcfpc_sweetalert_js' );
}, 100 );

View File

@@ -1,72 +0,0 @@
<?php
use Imagify\Notices\Notices;
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
if ( defined( 'RML_FILE' ) ) :
/**
* Dequeue all WP Real Media Library's styles and scripts where we use ours.
*
* Prevent WP Real Media Library to use its outdated version of SweetAlert where we need ours, and to mess with our CSS styles.
*
* @since 1.6.13
*/
function imagify_wprml_init() {
static $done = false;
if ( $done ) {
return;
}
$done = true;
if ( ! class_exists( '\\MatthiasWeb\\RealMediaLibrary\\general\\Backend' ) ) {
return;
}
$notices = Notices::get_instance();
if ( $notices->has_notices() && ( $notices->display_welcome_steps() || $notices->display_wrong_api_key() ) ) {
// We display a notice that uses SweetAlert.
imagify_wprml_dequeue();
return;
}
if ( imagify_is_screen( 'bulk' ) || imagify_is_screen( 'imagify-settings' ) ) {
// We display a page that uses SweetAlert.
imagify_wprml_dequeue();
return;
}
if ( function_exists( 'imagify_get_ngg_bulk_screen_id' ) && imagify_is_screen( imagify_get_ngg_bulk_screen_id() ) ) {
// We display the NGG Bulk Optimization page.
imagify_wprml_dequeue();
}
}
add_action( 'current_screen', 'imagify_wprml_init' );
/**
* Prevent WP Real Media Library to enqueue its styles and scripts.
*
* @since 1.6.13
*/
function imagify_wprml_dequeue() {
$instance = \MatthiasWeb\RealMediaLibrary\general\Backend::getInstance();
remove_action( 'admin_enqueue_scripts', [ $instance, 'admin_enqueue_scripts' ], 0 );
remove_action( 'admin_footer', [ $instance, 'admin_footer' ] );
if ( class_exists( '\\MatthiasWeb\\RealMediaLibrary\\general\\FolderShortcode' ) ) {
$instance = \MatthiasWeb\RealMediaLibrary\general\FolderShortcode::getInstance();
remove_action( 'admin_head', [ $instance, 'admin_head' ] );
remove_action( 'admin_enqueue_scripts', [ $instance, 'admin_enqueue_scripts' ] );
}
if ( class_exists( '\\MatthiasWeb\\RealMediaLibrary\\comp\\PageBuilders' ) ) {
$instance = \MatthiasWeb\RealMediaLibrary\comp\PageBuilders::getInstance();
remove_action( 'init', [ $instance, 'init' ] );
}
}
endif;

View File

@@ -1,87 +0,0 @@
<?php
namespace Imagify\ThirdParty\WPRocket;
use Imagify\Traits\InstanceGetterTrait;
/**
* Compat class for WP Rocket plugin.
*
* @since 1.9.3
*/
class Main {
use InstanceGetterTrait;
/**
* Launch the hooks.
*
* @since 1.9.3
*/
public function init() {
add_filter( 'imagify_cdn_source', [ $this, 'set_cdn_source' ] );
}
/** ----------------------------------------------------------------------------------------- */
/** HOOKS =================================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Provide a custom CDN source.
*
* @since 1.9.3
*
* @param array $source {
* An array of arguments.
*
* @type $name string The name of which provides the URL (plugin name, etc).
* @type $url string The CDN URL.
* }
* @return array
*/
public function set_cdn_source( $source ) {
if ( ! function_exists( 'get_rocket_option' ) ) {
return $source;
}
if ( ! get_rocket_option( 'cdn' ) ) {
return $source;
}
$container = apply_filters( 'rocket_container', null );
if ( is_object( $container ) && method_exists( $container, 'get' ) ) {
$cdn = $container->get( 'cdn' );
if ( $cdn && method_exists( $cdn, 'get_cdn_urls' ) ) {
$url = $cdn->get_cdn_urls( [ 'all', 'images' ] );
}
}
if ( ! isset( $url ) && function_exists( 'get_rocket_cdn_cnames' ) ) {
$url = get_rocket_cdn_cnames( [ 'all', 'images' ] );
}
if ( empty( $url ) ) {
return $source;
}
$url = reset( $url );
if ( ! $url ) {
return $source;
}
if ( ! preg_match( '@^(https?:)?//@i', $url ) ) {
$url = '//' . $url;
}
$scheme = wp_parse_url( \Imagify_Filesystem::get_instance()->get_site_root_url() );
$scheme = ! empty( $scheme['scheme'] ) ? $scheme['scheme'] : null;
$url = set_url_scheme( $url, $scheme );
$source['name'] = 'WP Rocket';
$source['url'] = $url;
return $source;
}
}

View File

@@ -1,8 +0,0 @@
<?php
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
if ( defined( 'WP_ROCKET_VERSION' ) ) :
\Imagify\ThirdParty\WPRocket\Main::get_instance()->init();
endif;

View File

@@ -1,24 +0,0 @@
<?php
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
if ( defined( 'WPSEO_VERSION' ) && is_admin() && ! wp_doing_ajax() ) :
add_action( 'wp_print_scripts', '_imagify_dequeue_yoastseo_script' );
/**
* Remove Yoast SEO bugged script.
*
* @since 1.4.1
*/
function _imagify_dequeue_yoastseo_script() {
if ( ! function_exists( 'get_current_screen' ) ) {
return;
}
$current_screen = get_current_screen();
if ( isset( $current_screen ) && 'post' === $current_screen->base && 'attachment' === $current_screen->post_type ) {
wp_dequeue_script( 'yoast-seo' );
wp_deregister_script( 'yoast-seo' );
}
}
endif;