1317 lines
43 KiB
PHP
1317 lines
43 KiB
PHP
<?php
|
||
defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' );
|
||
|
||
/**
|
||
* Class that regroups things about "custom folders".
|
||
*
|
||
* @since 1.7
|
||
* @author Grégory Viguier
|
||
*/
|
||
class Imagify_Custom_Folders {
|
||
|
||
/**
|
||
* Class version.
|
||
*
|
||
* @var string
|
||
*/
|
||
const VERSION = '1.1';
|
||
|
||
|
||
/** ----------------------------------------------------------------------------------------- */
|
||
/** BACKUP FOLDER =========================================================================== */
|
||
/** ----------------------------------------------------------------------------------------- */
|
||
|
||
/**
|
||
* Get the path to the backups directory (custom folders).
|
||
*
|
||
* @since 1.7
|
||
* @access public
|
||
* @author Grégory Viguier
|
||
*
|
||
* @return string Path to the backups directory.
|
||
*/
|
||
public static function get_backup_dir_path() {
|
||
static $backup_dir;
|
||
|
||
if ( isset( $backup_dir ) ) {
|
||
return $backup_dir;
|
||
}
|
||
|
||
$filesystem = imagify_get_filesystem();
|
||
$backup_dir = $filesystem->get_site_root() . 'imagify-backup/';
|
||
|
||
/**
|
||
* Filter the backup directory path (custom folders).
|
||
*
|
||
* @since 1.7
|
||
* @author Grégory Viguier
|
||
*
|
||
* @param string $backup_dir The backup directory path.
|
||
*/
|
||
$backup_dir = apply_filters( 'imagify_files_backup_directory', $backup_dir );
|
||
$backup_dir = $filesystem->normalize_dir_path( $backup_dir );
|
||
|
||
return $backup_dir;
|
||
}
|
||
|
||
/**
|
||
* Tell if the folder containing the backups is writable (custom folders).
|
||
*
|
||
* @since 1.7
|
||
* @access public
|
||
* @author Grégory Viguier
|
||
*
|
||
* @return bool
|
||
*/
|
||
public static function backup_dir_is_writable() {
|
||
return imagify_get_filesystem()->make_dir( self::get_backup_dir_path() );
|
||
}
|
||
|
||
/**
|
||
* Get the backup path of a specific file (custom folders).
|
||
*
|
||
* @since 1.7
|
||
* @access public
|
||
* @author Grégory Viguier
|
||
*
|
||
* @param string $file_path The file path.
|
||
* @return string|bool The backup path. False on failure.
|
||
*/
|
||
public static function get_file_backup_path( $file_path ) {
|
||
$file_path = wp_normalize_path( (string) $file_path );
|
||
$site_root = imagify_get_filesystem()->get_site_root();
|
||
$backup_dir = self::get_backup_dir_path();
|
||
|
||
if ( ! $file_path ) {
|
||
return false;
|
||
}
|
||
|
||
return preg_replace( '@^' . preg_quote( $site_root, '@' ) . '@', $backup_dir, $file_path );
|
||
}
|
||
|
||
/**
|
||
* Add index.php files recursively to a given directory and all its subdirectories.
|
||
*
|
||
* @since 1.9.11
|
||
*
|
||
* @param string $backup_dir (optional) Path to the directory where we will start adding indexes.
|
||
* Defaults to custom-folders backup dir.
|
||
*
|
||
* @return void
|
||
*/
|
||
public static function add_indexes( $backup_dir = '' ) {
|
||
$filesystem = Imagify_Filesystem::get_instance();
|
||
|
||
if ( empty( $backup_dir ) ) {
|
||
$backup_dir = self::get_backup_dir_path();
|
||
}
|
||
|
||
if ( ! $filesystem->is_writable( $backup_dir ) ) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
$directory = new RecursiveDirectoryIterator( $backup_dir );
|
||
$iterator = new RecursiveIteratorIterator( $directory );
|
||
|
||
foreach ( $iterator as $fileinfo ) {
|
||
|
||
if ( '.' !== $fileinfo->getFilename() ) {
|
||
continue;
|
||
}
|
||
|
||
$path = trailingslashit( $fileinfo->getRealPath() );
|
||
|
||
if ( ! $filesystem->is_file( $path . 'index.html' )
|
||
&& ! $filesystem->is_file( $path . 'index.php' )
|
||
) {
|
||
$filesystem->touch( $path . 'index.php' );
|
||
}
|
||
}
|
||
} catch ( Exception $e ) {
|
||
return;
|
||
}
|
||
}
|
||
|
||
/** ----------------------------------------------------------------------------------------- */
|
||
/** SINGLE FILE ============================================================================= */
|
||
/** ----------------------------------------------------------------------------------------- */
|
||
|
||
/**
|
||
* Insert a file into the DB.
|
||
*
|
||
* @since 1.7
|
||
* @access public
|
||
* @author Grégory Viguier
|
||
*
|
||
* @param array $args An array of arguments to pass to Imagify_Files_DB::insert(). Required values are 'folder_id' and ( 'path' or 'file_path').
|
||
* @return int The file ID on success. 0 on failure.
|
||
*/
|
||
public static function insert_file( $args = array() ) {
|
||
if ( empty( $args['folder_id'] ) ) {
|
||
return 0;
|
||
}
|
||
|
||
if ( empty( $args['path'] ) ) {
|
||
if ( empty( $args['file_path'] ) ) {
|
||
return 0;
|
||
}
|
||
|
||
$args['path'] = Imagify_Files_Scan::add_placeholder( $args['file_path'] );
|
||
}
|
||
|
||
if ( empty( $args['file_path'] ) ) {
|
||
$args['file_path'] = Imagify_Files_Scan::remove_placeholder( $args['path'] );
|
||
}
|
||
|
||
$filesystem = imagify_get_filesystem();
|
||
|
||
if ( ! $filesystem->is_readable( $args['file_path'] ) ) {
|
||
return 0;
|
||
}
|
||
|
||
if ( empty( $args['file_date'] ) || '0000-00-00 00:00:00' === $args['file_date'] ) {
|
||
$args['file_date'] = $filesystem->get_date( $args['file_path'] );
|
||
}
|
||
|
||
if ( empty( $args['mime_type'] ) ) {
|
||
$args['mime_type'] = $filesystem->get_mime_type( $args['file_path'] );
|
||
}
|
||
|
||
if ( ( empty( $args['width'] ) || empty( $args['height'] ) ) && strpos( $args['mime_type'], 'image/' ) === 0 ) {
|
||
$file_size = $filesystem->get_image_size( $args['file_path'] );
|
||
$args['width'] = $file_size ? $file_size['width'] : 0;
|
||
$args['height'] = $file_size ? $file_size['height'] : 0;
|
||
}
|
||
|
||
if ( empty( $args['hash'] ) ) {
|
||
$args['hash'] = md5_file( $args['file_path'] );
|
||
}
|
||
|
||
if ( empty( $args['original_size'] ) ) {
|
||
$args['original_size'] = (int) $filesystem->size( $args['file_path'] );
|
||
}
|
||
|
||
$files_db = Imagify_Files_DB::get_instance();
|
||
$primary_key = $files_db->get_primary_key();
|
||
unset( $args[ $primary_key ] );
|
||
|
||
return $files_db->insert( $args );
|
||
}
|
||
|
||
/**
|
||
* Delete a custom file.
|
||
*
|
||
* @since 1.7
|
||
* @access public
|
||
* @author Grégory Viguier
|
||
*
|
||
* @param array $args An array of arguments.
|
||
* At least: 'file_id'. At best: 'file_id', 'file_path' (or 'path' for the placeholder), and 'backup_path'.
|
||
*/
|
||
public static function delete_file( $args = [] ) {
|
||
$args = array_merge( [
|
||
'file_id' => 0,
|
||
'file_path' => '',
|
||
'path' => '',
|
||
'backup_path' => '',
|
||
'process' => false,
|
||
], $args );
|
||
|
||
$filesystem = imagify_get_filesystem();
|
||
|
||
// Fill the blanks.
|
||
if ( $args['process'] && $args['process'] instanceof \Imagify\Optimization\Process\ProcessInterface ) {
|
||
$process = $args['process'];
|
||
} else {
|
||
$process = imagify_get_optimization_process( $args['file_id'], 'custom-folders' );
|
||
}
|
||
|
||
if ( ! $process->is_valid() ) {
|
||
// You fucked up!
|
||
return;
|
||
}
|
||
|
||
if ( ! $args['file_path'] && $args['path'] ) {
|
||
$args['file_path'] = Imagify_Files_Scan::remove_placeholder( $args['path'] );
|
||
}
|
||
|
||
if ( ! $args['file_path'] && $args['file_id'] ) {
|
||
$args['file_path'] = $process->get_media()->get_fullsize_path();
|
||
}
|
||
|
||
if ( ! $args['backup_path'] && $args['file_path'] ) {
|
||
$args['backup_path'] = self::get_file_backup_path( $args['file_path'] );
|
||
}
|
||
|
||
if ( ! $args['backup_path'] && $args['file_id'] ) {
|
||
$args['backup_path'] = $process->get_media()->get_raw_backup_path();
|
||
}
|
||
|
||
// Trigger a common hook.
|
||
imagify_trigger_delete_media_hook( $process );
|
||
|
||
// The file.
|
||
if ( $args['file_path'] && $filesystem->exists( $args['file_path'] ) ) {
|
||
$filesystem->delete( $args['file_path'] );
|
||
}
|
||
|
||
// The backup file.
|
||
if ( $args['backup_path'] && $filesystem->exists( $args['backup_path'] ) ) {
|
||
$filesystem->delete( $args['backup_path'] );
|
||
}
|
||
|
||
// WebP.
|
||
$mime_type = $filesystem->get_mime_type( $args['file_path'] );
|
||
$is_image = $mime_type && strpos( $mime_type, 'image/' ) === 0;
|
||
$webp_path = $is_image ? imagify_path_to_webp( $args['file_path'] ) : false;
|
||
|
||
if ( $webp_path && $filesystem->is_writable( $webp_path ) ) {
|
||
$filesystem->delete( $webp_path );
|
||
}
|
||
|
||
// In the database.
|
||
$process->get_media()->delete_row();
|
||
}
|
||
|
||
/**
|
||
* Check if a file has been modified, and update the database accordingly.
|
||
*
|
||
* @since 1.7
|
||
* @access public
|
||
* @author Grégory Viguier
|
||
*
|
||
* @param ProcessInterface $process A \Imagify\Optimization\Process\ProcessInterface object.
|
||
* @param bool $is_folder_active Tell if the folder is active.
|
||
* @return int|bool|object The file ID if modified. False if not modified. A WP_Error object if the entry has been removed from the database.
|
||
* The entry is removed from the database if:
|
||
* - The file doesn't exist anymore.
|
||
* - Or if its folder is not active and: the file has been modified, or the file is not optimized by Imagify, or the file is orphan (its folder is not in the database anymore).
|
||
*/
|
||
public static function refresh_file( $process, $is_folder_active = null ) {
|
||
global $wpdb;
|
||
|
||
if ( ! $process->is_valid() ) {
|
||
return new \WP_Error( 'invalid_media', __( 'This media is not valid.', 'imagify' ) );
|
||
}
|
||
|
||
$filesystem = imagify_get_filesystem();
|
||
$media = $process->get_media();
|
||
$file_path = $media->get_fullsize_path();
|
||
$mime_type = $filesystem->get_mime_type( $file_path );
|
||
$is_image = $mime_type && strpos( $mime_type, 'image/' ) === 0;
|
||
$webp_path = $is_image ? imagify_path_to_webp( $file_path ) : false;
|
||
$has_webp = $webp_path && $filesystem->is_writable( $webp_path );
|
||
$modified = false;
|
||
|
||
if ( ! $file_path || ! $filesystem->exists( $file_path ) ) {
|
||
/**
|
||
* The file doesn't exist anymore.
|
||
*/
|
||
// Delete the backup file.
|
||
$process->delete_backup();
|
||
|
||
// Get the folder ID before removing the row.
|
||
$folder_id = $media->get_row();
|
||
$folder_id = $folder_id['folder_id'];
|
||
|
||
// Remove the entry from the database.
|
||
$media->delete_row();
|
||
|
||
// Remove the corresponding folder if inactive and have no files left.
|
||
self::remove_empty_inactive_folders( $folder_id );
|
||
|
||
// Delete the WebP version.
|
||
if ( $has_webp ) {
|
||
$filesystem->delete( $webp_path );
|
||
}
|
||
|
||
return new WP_Error( 'no-file', __( 'The file was missing or its path could not be retrieved from the database. The entry has been deleted from the database.', 'imagify' ) );
|
||
}
|
||
|
||
/**
|
||
* The file still exists.
|
||
*/
|
||
$old_data = $media->get_row();
|
||
$new_data = [];
|
||
|
||
// Folder ID.
|
||
if ( $old_data['folder_id'] ) {
|
||
$folder = wp_cache_get( 'custom_folder_' . $old_data['folder_id'], 'imagify' );
|
||
|
||
if ( false === $folder ) {
|
||
// The folder is not in the cache.
|
||
$folder = Imagify_Folders_DB::get_instance()->get( $old_data['folder_id'] );
|
||
$folder = $folder ? $folder : 0;
|
||
}
|
||
|
||
if ( ! $folder ) {
|
||
// The folder is not in the database anymore.
|
||
$old_data['folder_id'] = 0;
|
||
$new_data['folder_id'] = 0;
|
||
}
|
||
} else {
|
||
$folder = 0;
|
||
}
|
||
|
||
// Hash + modified.
|
||
$current_hash = md5_file( $file_path );
|
||
|
||
if ( ! $old_data['hash'] ) {
|
||
$new_data['modified'] = 0;
|
||
} else {
|
||
$new_data['modified'] = (int) ! hash_equals( $old_data['hash'], $current_hash );
|
||
}
|
||
|
||
// The file is modified or is not optimized.
|
||
if ( $new_data['modified'] || ! $process->get_data()->is_optimized() ) {
|
||
if ( ! isset( $is_folder_active ) ) {
|
||
$is_folder_active = $folder && $folder['active'];
|
||
}
|
||
|
||
// Its folder is not active: remove the entry from the database and delete the backup.
|
||
if ( ! $is_folder_active ) {
|
||
// Delete the backup file.
|
||
$process->delete_backup();
|
||
|
||
// Remove the entry from the database.
|
||
$media->delete_row();
|
||
|
||
// Remove the corresponding folder if inactive and have no files left.
|
||
if ( $old_data['folder_id'] ) {
|
||
self::remove_empty_inactive_folders( $old_data['folder_id'] );
|
||
}
|
||
|
||
// Delete the WebP version.
|
||
if ( $has_webp ) {
|
||
$filesystem->delete( $webp_path );
|
||
}
|
||
|
||
return new WP_Error( 'folder-not-active', __( 'The file has been modified or was not optimized: its folder not being selected in the settings, the entry has been deleted from the database.', 'imagify' ) );
|
||
}
|
||
}
|
||
|
||
$new_data['hash'] = $current_hash;
|
||
|
||
// The file is modified.
|
||
if ( $new_data['modified'] ) {
|
||
// Delete all optimization data and update file data.
|
||
$modified = true;
|
||
$mime_type = ! empty( $old_data['mime_type'] ) ? $old_data['mime_type'] : $filesystem->get_mime_type( $file_path );
|
||
|
||
if ( $is_image ) {
|
||
$size = $filesystem->get_image_size( $file_path );
|
||
|
||
// Delete the WebP version.
|
||
if ( $has_webp ) {
|
||
$filesystem->delete( $webp_path );
|
||
}
|
||
} else {
|
||
$size = false;
|
||
}
|
||
|
||
$new_data = array_merge( $new_data, [
|
||
'file_date' => $filesystem->get_date( $file_path ),
|
||
'width' => $size ? $size['width'] : 0,
|
||
'height' => $size ? $size['height'] : 0,
|
||
'original_size' => $filesystem->size( $file_path ),
|
||
'optimized_size' => null,
|
||
'percent' => null,
|
||
'optimization_level' => null,
|
||
'status' => null,
|
||
'error' => null,
|
||
'data' => [],
|
||
] );
|
||
|
||
// Delete the backup of the previous file.
|
||
$process->delete_backup();
|
||
} else {
|
||
// Update file data to make sure nothing is missing.
|
||
$backup_path = $media->get_backup_path();
|
||
$path = $backup_path ? $backup_path : $file_path;
|
||
$mime_type = ! empty( $old_data['mime_type'] ) ? $old_data['mime_type'] : $filesystem->get_mime_type( $path );
|
||
$file_date = ! empty( $old_data['file_date'] ) && '0000-00-00 00:00:00' !== $old_data['file_date'] ? $old_data['file_date'] : $filesystem->get_date( $path );
|
||
|
||
if ( $is_image ) {
|
||
$size = $filesystem->get_image_size( $path );
|
||
} else {
|
||
$size = false;
|
||
}
|
||
|
||
$new_data = array_merge( $new_data, [
|
||
'file_date' => $file_date,
|
||
'width' => $size ? $size['width'] : 0,
|
||
'height' => $size ? $size['height'] : 0,
|
||
'original_size' => $filesystem->size( $path ),
|
||
] );
|
||
|
||
// WebP.
|
||
$webp_size = 'full' . $process::WEBP_SUFFIX;
|
||
|
||
if ( $has_webp && empty( $old_data['data'][ $webp_size ]['success'] ) ) {
|
||
$webp_file_size = $filesystem->size( $webp_path );
|
||
|
||
$old_data['data'][ $webp_size ] = [
|
||
'success' => true,
|
||
'original_size' => $new_data['original_size'],
|
||
'optimized_size' => $webp_file_size,
|
||
'percent' => round( ( ( $new_data['original_size'] - $webp_file_size ) / $new_data['original_size'] ) * 100, 2 ),
|
||
];
|
||
}
|
||
}
|
||
|
||
// Save the new data.
|
||
$old_data = array_intersect_key( $old_data, $new_data );
|
||
ksort( $old_data );
|
||
ksort( $new_data );
|
||
|
||
if ( $old_data !== $new_data ) {
|
||
$media->update_row( $new_data );
|
||
}
|
||
|
||
return $modified ? $media->get_id() : false;
|
||
}
|
||
|
||
|
||
/** ----------------------------------------------------------------------------------------- */
|
||
/** FOLDERS AND FILES ======================================================================= */
|
||
/** ----------------------------------------------------------------------------------------- */
|
||
|
||
/**
|
||
* Get folders from the DB.
|
||
*
|
||
* @since 1.7
|
||
* @access public
|
||
* @author Grégory Viguier
|
||
*
|
||
* @param array $args A list of arguments to tell more precisely what to fetch:
|
||
* - bool $active True to fetch only "active" folders (checked in the settings). False to fetch only folders that are not "active".
|
||
* @return array An array of arrays containing the following values:
|
||
* - int $folder_id The folder ID.
|
||
* - string $path The folder path, with placeholder.
|
||
* - int $active 1 if the folder should be optimized. 0 otherwize.
|
||
* - string $folder_path The real absolute folder path.
|
||
* Example:
|
||
* Array(
|
||
* [7] => Array(
|
||
* [folder_id] => 7
|
||
* [path] => {{ROOT}}/custom-path/
|
||
* [active] => 1
|
||
* [folder_path] => /absolute/path/to/custom-path/
|
||
* )
|
||
* [13] => Array(
|
||
* [folder_id] => 13
|
||
* [path] => {{CONTENT}}/another-custom-path/
|
||
* [active] => 1
|
||
* [folder_path] => /absolute/path/to/wp-content/another-custom-path/
|
||
* )
|
||
* )
|
||
*/
|
||
public static function get_folders( $args = array() ) {
|
||
global $wpdb;
|
||
|
||
$folders_db = Imagify_Folders_DB::get_instance();
|
||
$folders_table = $folders_db->get_table_name();
|
||
$primary_key = $folders_db->get_primary_key();
|
||
$where_active = '';
|
||
|
||
if ( isset( $args['active'] ) ) {
|
||
if ( $args['active'] ) {
|
||
$args['active'] = true;
|
||
$where_active = 'WHERE active = 1';
|
||
} else {
|
||
$args['active'] = false;
|
||
$where_active = 'WHERE active = 0';
|
||
}
|
||
}
|
||
|
||
// Get the folders from the DB.
|
||
$results = $wpdb->get_results( "SELECT * FROM $folders_table $where_active;", ARRAY_A ); // WPCS: unprepared SQL ok.
|
||
|
||
if ( ! $results || ! is_array( $results ) ) {
|
||
return array();
|
||
}
|
||
|
||
// Cast results, add absolute paths.
|
||
$folders = array();
|
||
|
||
foreach ( $results as $row_fields ) {
|
||
// Cast the row.
|
||
$row_fields = $folders_db->cast_row( $row_fields );
|
||
|
||
// Add the absolute path.
|
||
$row_fields['folder_path'] = Imagify_Files_Scan::remove_placeholder( $row_fields['path'] );
|
||
|
||
// Add the row to the list.
|
||
$folders[ $row_fields[ $primary_key ] ] = $row_fields;
|
||
}
|
||
|
||
return $folders;
|
||
}
|
||
|
||
/**
|
||
* Get files belonging to the given folders.
|
||
* Files are scanned from the folders, then:
|
||
* - If a file doesn't exist in the DB, it is added (maybe, depending on arguments provided).
|
||
* - If a file is in the DB, but with a wrong folder_id, it is fixed.
|
||
* - If a file doesn't exist, it is removed from the database and its backup is deleted.
|
||
*
|
||
* @since 1.7
|
||
* @access public
|
||
* @see Imagify_Custom_Folders::get_folders()
|
||
* @author Grégory Viguier
|
||
*
|
||
* @param array $folders An array of arrays containing at least the keys 'folder_path' and 'active'. See Imagify_Custom_Folders::get_folders() for the format.
|
||
* @param array $args A list of arguments to tell more precisely what to fetch:
|
||
* - int $optimization_level If set with an integer, only files that needs to be optimized to this level will be returned (the status is also checked).
|
||
* - bool $return_only_old_files True to return only files that have not been newly inserted.
|
||
* - bool $add_inactive_folder_files When true: if a file is not in the database and its folder is not "active", it is added to the DB. Default false: new files are not added to the database if the folder is not active.
|
||
* @return array A list of files in the following format:
|
||
* Array(
|
||
* [_2] => Array(
|
||
* [file_id] => 2
|
||
* [folder_id] => 7
|
||
* [path] => {{ROOT}}/custom-path/image-1.jpg
|
||
* [optimization_level] => null
|
||
* [status] => null
|
||
* [file_path] => /absolute/path/to/custom-path/image-1.jpg
|
||
* ),
|
||
* [_3] => Array(
|
||
* [file_id] => 3
|
||
* [folder_id] => 7
|
||
* [path] => {{ROOT}}/custom-path/image-2.jpg
|
||
* [optimization_level] => 2
|
||
* [status] => success
|
||
* [file_path] => /absolute/path/to/custom-path/image-2.jpg
|
||
* ),
|
||
* [_6] => Array(
|
||
* [file_id] => 6
|
||
* [folder_id] => 13
|
||
* [path] => {{CONTENT}}/another-custom-path/image-1.jpg
|
||
* [optimization_level] => 0
|
||
* [status] => error
|
||
* [file_path] => /absolute/path/to/wp-content/another-custom-path/image-1.jpg
|
||
* ),
|
||
* )
|
||
* The fields 'optimization_level' and 'status' are set only if the argument 'optimization_level' was set.
|
||
*/
|
||
public static function get_files_from_folders( $folders, $args = array() ) {
|
||
global $wpdb;
|
||
|
||
if ( ! $folders ) {
|
||
return array();
|
||
}
|
||
|
||
$filesystem = imagify_get_filesystem();
|
||
$files_db = Imagify_Files_DB::get_instance();
|
||
$files_table = $files_db->get_table_name();
|
||
$files_key = $files_db->get_primary_key();
|
||
$files_key_esc = esc_sql( $files_key );
|
||
|
||
$optimization = isset( $args['optimization_level'] ) && is_numeric( $args['optimization_level'] );
|
||
$no_new_files = ! empty( $args['return_only_old_files'] );
|
||
$add_inactive_folder_files = ! empty( $args['add_inactive_folder_files'] );
|
||
|
||
/**
|
||
* Scan folders for files. $files_from_scan will be in the following format:
|
||
* Array(
|
||
* [7] => Array(
|
||
* [/absolute/path/to/custom-path/image-1.jpg] => 0
|
||
* [/absolute/path/to/custom-path/image-2.jpg] => 1
|
||
* )
|
||
* [13] => Array(
|
||
* [/absolute/path/to/wp-content/another-custom-path/image-1.jpg] => 0
|
||
* [/absolute/path/to/wp-content/another-custom-path/image-2.jpg] => 1
|
||
* [/absolute/path/to/wp-content/another-custom-path/image-3.jpg] => 2
|
||
* )
|
||
* )
|
||
*/
|
||
$files_from_scan = array();
|
||
|
||
foreach ( $folders as $folder_id => $folder ) {
|
||
$files_from_scan[ $folder_id ] = Imagify_Files_Scan::get_files_from_folder( $folder['folder_path'] );
|
||
|
||
if ( is_wp_error( $files_from_scan[ $folder_id ] ) ) {
|
||
unset( $files_from_scan[ $folder_id ] );
|
||
}
|
||
}
|
||
|
||
$files_from_scan = array_map( 'array_flip', $files_from_scan );
|
||
|
||
/**
|
||
* Get the files from DB. $files_from_db will be in the same format as the function output.
|
||
*/
|
||
$already_optimized = array();
|
||
$folder_ids = array_keys( $folders );
|
||
$files_from_db = array_fill_keys( $folder_ids, array() );
|
||
$folder_ids = Imagify_DB::prepare_values_list( $folder_ids );
|
||
$select_fields = "$files_key_esc, folder_id, path" . ( $optimization ? ', optimization_level, status' : '' );
|
||
|
||
if ( $optimization ) {
|
||
$orderby = "
|
||
CASE status
|
||
WHEN 'already_optimized' THEN 3
|
||
WHEN 'error' THEN 2
|
||
ELSE 1
|
||
END ASC,
|
||
$files_key_esc DESC";
|
||
} else {
|
||
$orderby = "folder_id, $files_key_esc";
|
||
}
|
||
|
||
$results = $wpdb->get_results( "SELECT $select_fields FROM $files_table WHERE folder_id IN ( $folder_ids ) ORDER BY $orderby;", ARRAY_A ); // WPCS: unprepared SQL ok.
|
||
|
||
if ( $results ) {
|
||
$wpdb->flush();
|
||
|
||
foreach ( $results as $i => $row_fields ) {
|
||
// Cast the row.
|
||
$row_fields = $files_db->cast_row( $row_fields );
|
||
|
||
// Add the absolute path.
|
||
$row_fields['file_path'] = Imagify_Files_Scan::remove_placeholder( $row_fields['path'] );
|
||
|
||
// Remove the file from the scan.
|
||
unset( $files_from_scan[ $row_fields['folder_id'] ][ $row_fields['file_path'] ] );
|
||
|
||
if ( $optimization ) {
|
||
if ( 'error' !== $row_fields['status'] && $row_fields['optimization_level'] === $args['optimization_level'] ) {
|
||
// Try the same level only if the status is an error.
|
||
continue;
|
||
}
|
||
|
||
if ( 'already_optimized' === $row_fields['status'] && $row_fields['optimization_level'] >= $args['optimization_level'] ) {
|
||
// If the image is already compressed, optimize only if the requested level is higher.
|
||
continue;
|
||
}
|
||
|
||
if ( 'success' === $row_fields['status'] && $args['optimization_level'] !== $row_fields['optimization_level'] ) {
|
||
$file_backup_path = self::get_file_backup_path( $row_fields['file_path'] );
|
||
|
||
if ( ! $file_backup_path || ! $filesystem->exists( $file_backup_path ) ) {
|
||
// Don't try to re-optimize if there is no backup file.
|
||
continue;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ( ! $filesystem->exists( $row_fields['file_path'] ) ) {
|
||
// If the file doesn't exist: remove all traces of it and bail out.
|
||
self::delete_file( array(
|
||
'file_id' => $row_fields[ $files_key ],
|
||
'file_path' => $row_fields['file_path'],
|
||
) );
|
||
continue;
|
||
}
|
||
|
||
if ( $optimization && 'already_optimized' === $row_fields['status'] ) {
|
||
$already_optimized[ '_' . $row_fields[ $files_key ] ] = 1;
|
||
}
|
||
|
||
// Add the row to the list.
|
||
$files_from_db[ $row_fields['folder_id'] ][ '_' . $row_fields[ $files_key ] ] = $row_fields;
|
||
}
|
||
}
|
||
|
||
unset( $results );
|
||
$files_from_scan = array_filter( $files_from_scan );
|
||
|
||
// Make sure files from the scan are not already in the DB with another folder (shouldn't be possible, but, you know...).
|
||
if ( $files_from_scan ) {
|
||
$folders_by_placeholder = array();
|
||
|
||
foreach ( $files_from_scan as $folder_id => $folder_files ) {
|
||
foreach ( $folder_files as $file_path => $i ) {
|
||
$placeholder = Imagify_Files_Scan::add_placeholder( $file_path );
|
||
|
||
$folders_by_placeholder[ $placeholder ] = $folder_id;
|
||
$files_from_scan[ $folder_id ][ $file_path ] = $placeholder;
|
||
}
|
||
}
|
||
|
||
$placeholders = Imagify_DB::prepare_values_list( array_keys( $folders_by_placeholder ) );
|
||
$select_fields = "$files_key_esc, folder_id, path" . ( $optimization ? ', optimization_level, status' : '' );
|
||
|
||
$results = $wpdb->get_results( "SELECT $select_fields FROM $files_table WHERE path IN ( $placeholders ) ORDER BY folder_id, $files_key_esc;", ARRAY_A ); // WPCS: unprepared SQL ok.
|
||
|
||
if ( $results ) {
|
||
// Damn...
|
||
$wpdb->flush();
|
||
|
||
foreach ( $results as $i => $row_fields ) {
|
||
// Cast the row.
|
||
$row_fields = $files_db->cast_row( $row_fields );
|
||
$old_folder_id = $row_fields['folder_id'];
|
||
|
||
// Add the absolute path.
|
||
$row_fields['file_path'] = Imagify_Files_Scan::remove_placeholder( $row_fields['path'] );
|
||
|
||
// Set the new folder ID.
|
||
$row_fields['folder_id'] = $folders_by_placeholder[ $row_fields['path'] ];
|
||
|
||
// Remove the file from everywhere.
|
||
unset(
|
||
$files_from_db[ $old_folder_id ][ '_' . $row_fields[ $files_key ] ],
|
||
$files_from_scan[ $old_folder_id ][ $row_fields['file_path'] ],
|
||
$files_from_scan[ $row_fields['folder_id'] ][ $row_fields['file_path'] ]
|
||
);
|
||
|
||
if ( $optimization ) {
|
||
if ( 'error' !== $row_fields['status'] && $row_fields['optimization_level'] === $args['optimization_level'] ) {
|
||
// Try the same level only if the status is an error.
|
||
continue;
|
||
}
|
||
|
||
if ( 'already_optimized' === $row_fields['status'] && $row_fields['optimization_level'] >= $args['optimization_level'] ) {
|
||
// If the image is already compressed, optimize only if the requested level is higher.
|
||
continue;
|
||
}
|
||
|
||
if ( 'success' === $row_fields['status'] && $args['optimization_level'] !== $row_fields['optimization_level'] ) {
|
||
$file_backup_path = self::get_file_backup_path( $row_fields['file_path'] );
|
||
|
||
if ( ! $file_backup_path || ! $filesystem->exists( $file_backup_path ) ) {
|
||
// Don't try to re-optimize if there is no backup file.
|
||
continue;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ( ! $filesystem->exists( $row_fields['file_path'] ) ) {
|
||
// If the file doesn't exist: remove all traces of it and bail out.
|
||
self::delete_file( array(
|
||
'file_id' => $row_fields[ $files_key ],
|
||
'file_path' => $row_fields['file_path'],
|
||
) );
|
||
continue;
|
||
}
|
||
|
||
// Set the correct folder ID in the DB.
|
||
$success = $files_db->update( $row_fields[ $files_key ], array(
|
||
'folder_id' => $row_fields['folder_id'],
|
||
) );
|
||
|
||
if ( $success ) {
|
||
if ( $optimization && 'already_optimized' === $row_fields['status'] ) {
|
||
$already_optimized[ '_' . $row_fields[ $files_key ] ] = 1;
|
||
}
|
||
|
||
$files_from_db[ $row_fields['folder_id'] ][ '_' . $row_fields[ $files_key ] ] = $row_fields;
|
||
}
|
||
}
|
||
}
|
||
|
||
unset( $results, $folders_by_placeholder );
|
||
}
|
||
|
||
$files_from_scan = array_filter( $files_from_scan );
|
||
|
||
// Insert the remaining files into the DB.
|
||
if ( $files_from_scan ) {
|
||
foreach ( $files_from_scan as $folder_id => $placeholders ) {
|
||
// Don't add the file to the DB if its folder is not "active".
|
||
if ( ! $add_inactive_folder_files && empty( $folders[ $folder_id ]['active'] ) ) {
|
||
unset( $files_from_scan[ $folder_id ] );
|
||
continue;
|
||
}
|
||
|
||
foreach ( $placeholders as $file_path => $placeholder ) {
|
||
$file_id = self::insert_file( array(
|
||
'folder_id' => $folder_id,
|
||
'path' => $placeholder,
|
||
'file_path' => $file_path,
|
||
) );
|
||
|
||
if ( $file_id && ! $no_new_files ) {
|
||
$files_from_db[ $folder_id ][ '_' . $file_id ] = array(
|
||
'file_id' => $file_id,
|
||
'folder_id' => $folder_id,
|
||
'path' => $placeholder,
|
||
'optimization_level' => null,
|
||
'status' => null,
|
||
'file_path' => $file_path,
|
||
);
|
||
}
|
||
}
|
||
|
||
unset( $files_from_scan[ $folder_id ] );
|
||
}
|
||
}
|
||
|
||
$files_from_db = array_filter( $files_from_db );
|
||
|
||
if ( ! $files_from_db ) {
|
||
return array();
|
||
}
|
||
|
||
$files_from_db = call_user_func_array( 'array_merge', array_values( $files_from_db ) );
|
||
|
||
if ( $already_optimized ) {
|
||
// Put the files already optimized at the end of the list.
|
||
$already_optimized = array_intersect_key( $files_from_db, $already_optimized );
|
||
$files_from_db = array_diff_key( $files_from_db, $already_optimized );
|
||
$files_from_db = array_merge( $files_from_db, $already_optimized );
|
||
}
|
||
|
||
return $files_from_db;
|
||
}
|
||
|
||
/**
|
||
* Check if files inside the given folders have been modified, and update the database accordingly.
|
||
*
|
||
* @since 1.7
|
||
* @access public
|
||
* @author Grégory Viguier
|
||
*
|
||
* @param array $folders A list of folders. See Imagify_Custom_Folders::get_folders() for the format.
|
||
*/
|
||
public static function synchronize_files_from_folders( $folders ) {
|
||
global $wpdb;
|
||
/**
|
||
* Get the files from DB, and from the folder.
|
||
*/
|
||
$files = self::get_files_from_folders( $folders, array(
|
||
'return_only_old_files' => true,
|
||
) );
|
||
|
||
if ( ! $files ) {
|
||
// This folder doesn't have (new) images.
|
||
return;
|
||
}
|
||
|
||
$files_db = Imagify_Files_DB::get_instance();
|
||
$files_table = $files_db->get_table_name();
|
||
$files_key = $files_db->get_primary_key();
|
||
$files_key_esc = esc_sql( $files_key );
|
||
$file_ids = wp_list_pluck( $files, $files_key );
|
||
$file_ids = Imagify_DB::prepare_values_list( $file_ids );
|
||
$results = $wpdb->get_results( "SELECT * FROM $files_table WHERE $files_key IN ( $file_ids ) ORDER BY $files_key_esc;", ARRAY_A ); // WPCS: unprepared SQL ok.
|
||
|
||
if ( ! $results ) {
|
||
// WAT?!
|
||
return;
|
||
}
|
||
|
||
// Caching the folders will prevent unecessary SQL queries in Imagify_Custom_Folders::refresh_file().
|
||
foreach ( $folders as $folder_id => $folder ) {
|
||
wp_cache_set( 'custom_folder_' . $folder_id, $folder, 'imagify' );
|
||
}
|
||
|
||
// Finally, refresh the files data.
|
||
foreach ( $results as $file ) {
|
||
$file = $files_db->cast_row( $file );
|
||
$folder_id = $file['folder_id'];
|
||
$process = imagify_get_optimization_process( $file, 'custom-folders' );
|
||
|
||
self::refresh_file( $process, $folders[ $folder_id ]['active'] );
|
||
}
|
||
|
||
foreach ( $folders as $folder_id => $folder ) {
|
||
wp_cache_delete( 'custom_folder_' . $folder_id, 'imagify' );
|
||
}
|
||
}
|
||
|
||
|
||
/** ----------------------------------------------------------------------------------------- */
|
||
/** WHEN SAVING SELECTED FOLDERS ============================================================ */
|
||
/** ----------------------------------------------------------------------------------------- */
|
||
|
||
/**
|
||
* Dectivate all active folders.
|
||
*
|
||
* @since 1.7
|
||
* @access public
|
||
* @author Grégory Viguier
|
||
*/
|
||
public static function deactivate_all_folders() {
|
||
self::deactivate_not_selected_folders();
|
||
}
|
||
|
||
/**
|
||
* Dectivate folders that are not selected.
|
||
*
|
||
* @since 1.7
|
||
* @access public
|
||
* @author Grégory Viguier
|
||
*
|
||
* @param array|object|string $selected_paths A list of "placeholdered" paths corresponding to the selected folders.
|
||
*/
|
||
public static function deactivate_not_selected_folders( $selected_paths = array() ) {
|
||
global $wpdb;
|
||
|
||
$folders_table = Imagify_Folders_DB::get_instance()->get_table_name();
|
||
|
||
if ( $selected_paths ) {
|
||
if ( is_array( $selected_paths ) || is_object( $selected_paths ) ) {
|
||
$selected_paths = Imagify_DB::prepare_values_list( $selected_paths );
|
||
}
|
||
|
||
$selected_paths_clause = "AND path NOT IN ( $selected_paths )";
|
||
} else {
|
||
$selected_paths_clause = '';
|
||
}
|
||
|
||
// Remove the active status from the folders that are not selected.
|
||
$wpdb->query( "UPDATE $folders_table SET active = 0 WHERE active != 0 $selected_paths_clause" ); // WPCS: unprepared SQL ok.
|
||
}
|
||
|
||
/**
|
||
* Activate folders that are selected.
|
||
*
|
||
* @since 1.7
|
||
* @access public
|
||
* @author Grégory Viguier
|
||
*
|
||
* @param array|object $selected_paths A list of "placeholdered" paths corresponding to the selected folders.
|
||
* @return array An array of paths of folders that are not in the DB.
|
||
*/
|
||
public static function activate_selected_folders( $selected_paths ) {
|
||
global $wpdb;
|
||
|
||
if ( ! $selected_paths ) {
|
||
return $selected_paths;
|
||
}
|
||
|
||
$folders_db = Imagify_Folders_DB::get_instance();
|
||
$folders_table = $folders_db->get_table_name();
|
||
$folders_key = $folders_db->get_primary_key();
|
||
|
||
$selected_paths = (array) $selected_paths;
|
||
$selected_in = Imagify_DB::prepare_values_list( $selected_paths );
|
||
|
||
// Get folders that already are in the DB.
|
||
$folders = $wpdb->get_results( "SELECT * FROM $folders_table WHERE path IN ( $selected_in );", ARRAY_A ); // WPCS: unprepared SQL ok.
|
||
|
||
if ( ! $folders ) {
|
||
return $selected_paths;
|
||
}
|
||
|
||
$selected_paths = array_flip( $selected_paths );
|
||
|
||
foreach ( $folders as $folder ) {
|
||
$folder = $folders_db->cast_row( $folder );
|
||
|
||
if ( Imagify_Files_Scan::placeholder_path_exists( $folder['path'] ) ) {
|
||
if ( ! $folder['active'] ) {
|
||
// Add the active status only if not already set and if the folder exists.
|
||
$folders_db->update( $folder[ $folders_key ], array(
|
||
'active' => 1,
|
||
) );
|
||
}
|
||
} else {
|
||
// Remove the active status if the folder does not exist.
|
||
$folders_db->update( $folder[ $folders_key ], array(
|
||
'active' => 0,
|
||
) );
|
||
}
|
||
|
||
// Remove the path from the selected list, so the remaining will be created.
|
||
unset( $selected_paths[ $folder['path'] ] );
|
||
}
|
||
|
||
// Paths of folders that are not in the DB.
|
||
return array_flip( $selected_paths );
|
||
}
|
||
|
||
/**
|
||
* Insert folders into the database.
|
||
*
|
||
* @since 1.7
|
||
* @access public
|
||
* @author Grégory Viguier
|
||
*
|
||
* @param array $folders An array of "placeholdered" paths.
|
||
* @return array An array of folder IDs.
|
||
*/
|
||
public static function insert_folders( $folders ) {
|
||
if ( ! $folders ) {
|
||
return array();
|
||
}
|
||
|
||
$folder_ids = array();
|
||
$filesystem = imagify_get_filesystem();
|
||
$folders_db = Imagify_Folders_DB::get_instance();
|
||
|
||
foreach ( $folders as $placeholder ) {
|
||
$full_path = Imagify_Files_Scan::remove_placeholder( $placeholder );
|
||
$full_path = realpath( $full_path );
|
||
|
||
if ( ! $full_path || ! $filesystem->is_readable( $full_path ) || ! $filesystem->is_dir( $full_path ) ) {
|
||
continue;
|
||
}
|
||
|
||
if ( Imagify_Files_Scan::is_path_forbidden( trailingslashit( $full_path ) ) ) {
|
||
continue;
|
||
}
|
||
|
||
$folder_ids[] = $folders_db->insert( array(
|
||
'path' => $placeholder,
|
||
'active' => 1,
|
||
) );
|
||
}
|
||
|
||
return array_filter( $folder_ids );
|
||
}
|
||
|
||
/**
|
||
* Remove files that are in inactive folders and are not optimized.
|
||
*
|
||
* @since 1.7
|
||
* @access public
|
||
* @author Grégory Viguier
|
||
*/
|
||
public static function remove_unoptimized_files_from_inactive_folders() {
|
||
global $wpdb;
|
||
|
||
$folders_db = Imagify_Folders_DB::get_instance();
|
||
$folders_key = $folders_db->get_primary_key();
|
||
$files_table = Imagify_Files_DB::get_instance()->get_table_name();
|
||
$folder_ids = $folders_db->get_active_folders_column( $folders_key );
|
||
|
||
if ( $folder_ids ) {
|
||
$folder_ids = Imagify_DB::prepare_values_list( $folder_ids );
|
||
|
||
$wpdb->query( "DELETE FROM $files_table WHERE folder_id NOT IN ( $folder_ids ) AND ( status != 'success' OR status IS NULL )" ); // WPCS: unprepared SQL ok.
|
||
} else {
|
||
$wpdb->query( "DELETE FROM $files_table WHERE status != 'success' OR status IS NULL" ); // WPCS: unprepared SQL ok.
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Reassign inactive files to active folders.
|
||
* Example:
|
||
* - Consider the file "/a/b/c/d/file.png".
|
||
* - The folder "/a/b/c/", previously active, becomes inactive.
|
||
* - The folder "/a/b/", previously inactive, becomes active.
|
||
* - The file is reassigned to the folder "/a/b/".
|
||
*
|
||
* @since 1.7
|
||
* @access public
|
||
* @author Grégory Viguier
|
||
*/
|
||
public static function reassign_inactive_files() {
|
||
global $wpdb;
|
||
|
||
$folders_db = Imagify_Folders_DB::get_instance();
|
||
$folders_table = $folders_db->get_table_name();
|
||
$folders_key = $folders_db->get_primary_key();
|
||
$folders_key_esc = esc_sql( $folders_key );
|
||
|
||
$files_db = Imagify_Files_DB::get_instance();
|
||
$files_table = $files_db->get_table_name();
|
||
$files_key = $files_db->get_primary_key();
|
||
$files_key_esc = esc_sql( $files_key );
|
||
|
||
// All active folders.
|
||
$active_folders = $wpdb->get_results( "SELECT $folders_key_esc, path FROM $folders_table WHERE active = 1;", ARRAY_A ); // WPCS: unprepared SQL ok.
|
||
|
||
if ( ! $active_folders ) {
|
||
return;
|
||
}
|
||
|
||
$active_folder_ids = array();
|
||
$has_site_root = false;
|
||
|
||
foreach ( $active_folders as $i => $active_folder ) {
|
||
$active_folders[ $i ] = $folders_db->cast_row( $active_folder );
|
||
$active_folder_ids[] = $active_folders[ $i ][ $folders_key ];
|
||
|
||
if ( '{{ROOT}}/' === $active_folders[ $i ]['path'] ) {
|
||
$has_site_root = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// Files not in active folders.
|
||
$active_folder_ids = Imagify_DB::prepare_values_list( $active_folder_ids );
|
||
$inactive_files = $wpdb->get_results( "SELECT $files_key_esc, path FROM $files_table WHERE folder_id NOT IN ( $active_folder_ids )", ARRAY_A ); // WPCS: unprepared SQL ok.
|
||
|
||
if ( ! $inactive_files ) {
|
||
return;
|
||
}
|
||
|
||
$filesystem = imagify_get_filesystem();
|
||
$file_ids_by_folder = array();
|
||
$active_folders = self::sort_folders( $active_folders, true );
|
||
|
||
foreach ( $inactive_files as $inactive_file ) {
|
||
$inactive_file = $files_db->cast_row( $inactive_file );
|
||
$inactive_file['full_path'] = Imagify_Files_Scan::remove_placeholder( $inactive_file['path'] );
|
||
|
||
if ( $has_site_root ) {
|
||
$inactive_file['dirname'] = $filesystem->dir_path( $inactive_file['full_path'] );
|
||
}
|
||
|
||
foreach ( $active_folders as $active_folder ) {
|
||
$folder_id = $active_folder[ $folders_key ];
|
||
|
||
if ( strpos( $inactive_file['full_path'], $active_folder['full_path'] ) !== 0 ) {
|
||
// The file is not in this folder.
|
||
continue;
|
||
}
|
||
|
||
if ( ! isset( $file_ids_by_folder[ $folder_id ] ) ) {
|
||
$file_ids_by_folder[ $folder_id ] = array();
|
||
}
|
||
|
||
if ( '{{ROOT}}/' === $active_folder['path'] ) {
|
||
// For the site's root: only direct childs.
|
||
if ( $inactive_file['dirname'] === $active_folder['full_path'] ) {
|
||
// This file is in the site's root folder.
|
||
$file_ids_by_folder[ $folder_id ][] = $inactive_file[ $files_key ];
|
||
}
|
||
break;
|
||
}
|
||
|
||
// This file is not in the site's root, but still a grand-child of this folder.
|
||
$file_ids_by_folder[ $folder_id ][] = $inactive_file[ $files_key ];
|
||
break;
|
||
}
|
||
}
|
||
|
||
$file_ids_by_folder = array_filter( $file_ids_by_folder );
|
||
|
||
if ( ! $file_ids_by_folder ) {
|
||
return;
|
||
}
|
||
|
||
// Set the new folder ID.
|
||
foreach ( $file_ids_by_folder as $folder_id => $file_ids ) {
|
||
$file_ids = Imagify_DB::prepare_values_list( $file_ids );
|
||
|
||
$wpdb->query( "UPDATE $files_table SET folder_id = $folder_id WHERE $files_key_esc IN ( $file_ids )" ); // WPCS: unprepared SQL ok.
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Remove the given folders from the DB if they are inactive and have no files.
|
||
*
|
||
* @since 1.7
|
||
* @access public
|
||
* @author Grégory Viguier
|
||
*
|
||
* @param array $folder_ids An array of folder IDs.
|
||
* @return int Number of removed folders.
|
||
*/
|
||
public static function remove_empty_inactive_folders( $folder_ids = null ) {
|
||
global $wpdb;
|
||
|
||
$folders_db = Imagify_Folders_DB::get_instance();
|
||
$folders_table = $folders_db->get_table_name();
|
||
$folders_key = $folders_db->get_primary_key();
|
||
$folders_key_esc = esc_sql( $folders_key );
|
||
$files_table = Imagify_Files_DB::get_instance()->get_table_name();
|
||
|
||
$folder_ids = array_filter( (array) $folder_ids );
|
||
|
||
if ( $folder_ids ) {
|
||
$folder_ids = $folders_db->cast_col( $folder_ids, $folders_key );
|
||
$folder_ids = Imagify_DB::prepare_values_list( $folder_ids );
|
||
$in_clause = "folders.$folders_key_esc IN ( $folder_ids )";
|
||
} else {
|
||
$in_clause = '1=1';
|
||
}
|
||
|
||
// Within the range of given folder IDs, filter the ones that are inactive and have no files.
|
||
$results = $wpdb->get_col( // WPCS: unprepared SQL ok.
|
||
"
|
||
SELECT folders.$folders_key_esc FROM $folders_table AS folders
|
||
LEFT JOIN $files_table AS files ON folders.$folders_key_esc = files.folder_id
|
||
WHERE $in_clause
|
||
AND folders.active != 1
|
||
AND files.folder_id IS NULL"
|
||
);
|
||
|
||
if ( ! $results ) {
|
||
return 0;
|
||
}
|
||
|
||
$results = $folders_db->cast_col( $results, $folders_key );
|
||
$results = Imagify_DB::prepare_values_list( $results );
|
||
|
||
// Remove inactive folders with no files.
|
||
$wpdb->query( "DELETE FROM $folders_table WHERE $folders_key_esc IN ( $results )" ); // WPCS: unprepared SQL ok.
|
||
|
||
return (int) $wpdb->rows_affected;
|
||
}
|
||
|
||
|
||
/** ----------------------------------------------------------------------------------------- */
|
||
/** TOOLS =================================================================================== */
|
||
/** ----------------------------------------------------------------------------------------- */
|
||
|
||
/**
|
||
* Sort folders by full path.
|
||
* The row "full_path" is added to each folder.
|
||
*
|
||
* @since 1.7
|
||
* @access public
|
||
* @author Grégory Viguier
|
||
*
|
||
* @param array $folders An array of folders with at least a "path" row.
|
||
* @param bool $reverse Reverse the order.
|
||
* @return array
|
||
*/
|
||
public static function sort_folders( $folders, $reverse = false ) {
|
||
if ( ! $folders ) {
|
||
return array();
|
||
}
|
||
|
||
$keyed_folders = array();
|
||
$keyed_paths = array();
|
||
|
||
foreach ( $folders as $folder ) {
|
||
$folder = (array) $folder;
|
||
$folder['full_path'] = Imagify_Files_Scan::remove_placeholder( $folder['path'] );
|
||
|
||
$keyed_folders[ $folder['path'] ] = $folder;
|
||
$keyed_paths[ $folder['path'] ] = $folder['full_path'];
|
||
}
|
||
|
||
natcasesort( $keyed_paths );
|
||
|
||
if ( $reverse ) {
|
||
$keyed_paths = array_reverse( $keyed_paths, true );
|
||
}
|
||
|
||
$keyed_folders = array_merge( $keyed_paths, $keyed_folders );
|
||
|
||
return array_values( $keyed_folders );
|
||
}
|
||
|
||
/**
|
||
* Remove sub-paths: if 'a/b/' and 'a/b/c/' are in the array, we keep only the "parent" 'a/b/'.
|
||
*
|
||
* @since 1.7
|
||
* @access public
|
||
* @author Grégory Viguier
|
||
*
|
||
* @param array $placeholders A list of "placeholdered" paths.
|
||
* @return array
|
||
*/
|
||
public static function remove_sub_paths( $placeholders ) {
|
||
sort( $placeholders );
|
||
|
||
foreach ( $placeholders as $i => $placeholder_path ) {
|
||
if ( '{{ROOT}}/' === $placeholder_path ) {
|
||
continue;
|
||
}
|
||
|
||
if ( ! isset( $prev_path ) ) {
|
||
$prev_path = strtolower( Imagify_Files_Scan::remove_placeholder( $placeholder_path ) );
|
||
continue;
|
||
}
|
||
|
||
$placeholder_path = strtolower( Imagify_Files_Scan::remove_placeholder( $placeholder_path ) );
|
||
|
||
if ( strpos( $placeholder_path, $prev_path ) === 0 ) {
|
||
unset( $placeholders[ $i ] );
|
||
} else {
|
||
$prev_path = $placeholder_path;
|
||
}
|
||
}
|
||
|
||
return $placeholders;
|
||
}
|
||
}
|