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,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' ) );
}
}