This commit is contained in:
2024-05-20 15:37:46 +03:00
commit 00b7dbd0b7
10404 changed files with 3285853 additions and 0 deletions

View File

@ -0,0 +1,260 @@
<?php
namespace ShortPixel\Controller\View;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
use ShortPixel\ShortPixelLogger\ShortPixelLogger as Log;
use ShortPixel\Notices\NoticeController as Notices;
use ShortPixel\Controller\AdminNoticesController as AdminNoticesController;
use ShortPixel\Controller\ApiKeyController as ApiKeyController;
use ShortPixel\Controller\QuotaController as QuotaController;
use ShortPixel\Controller\OptimizeController as OptimizeController;
use ShortPixel\Controller\BulkController as BulkController;
use ShortPixel\Controller\StatsController as StatsController;
use ShortPixel\Controller\OtherMediaController as OtherMediaController;
use ShortPixel\Helper\UiHelper as UiHelper;
use ShortPixel\Model\AccessModel as AccessModel;
class BulkViewController extends \ShortPixel\ViewController
{
protected $form_action = 'sp-bulk';
protected $template = 'view-bulk';
protected $quotaData;
protected $pendingMeta;
protected $selected_folders = array();
protected static $instance;
public function load()
{
$quota = QuotaController::getInstance();
$optimizeController = new OptimizeController();
$this->view->quotaData = $quota->getQuota();
$this->view->stats = $optimizeController->getStartupData();
$this->view->approx = $this->getApproxData();
$this->view->logHeaders = array(__('Images', 'shortpixel_image_optimiser'), __('Errors', 'shortpixel_image_optimizer'), __('Date', 'shortpixel_image_optimizer'));
$this->view->logs = $this->getLogs();
$keyControl = ApiKeyController::getInstance();
$this->view->error = false;
if ( ! $keyControl->keyIsVerified() )
{
$adminNoticesController = AdminNoticesController::getInstance();
$this->view->error = true;
$this->view->errorTitle = __('Missing API Key', 'shortpixel_image_optimiser');
$this->view->errorContent = $this->getActivationNotice();
$this->view->showError = 'key';
}
elseif ( ! $quota->hasQuota())
{
$this->view->error = true;
$this->view->errorTitle = __('Quota Exceeded','shortpixel-image-optimiser');
$this->view->errorContent = __('Can\'t start the Bulk Process due to lack of credits.', 'shortpixel-image-optimiser');
$this->view->errorText = __('Please check or add quota and refresh the page', 'shortpixel-image-optimiser');
$this->view->showError = 'quota';
}
$this->view->mediaErrorLog = $this->loadCurrentLog('media');
$this->view->customErrorLog = $this->loadCurrentLog('custom');
$this->view->buyMoreHref = 'https://shortpixel.com/' . ($keyControl->getKeyForDisplay() ? 'login/' . $keyControl->getKeyForDisplay() . '/spio-unlimited' : 'pricing');
$this->loadView();
}
// Double with ApiNotice . @todo Fix.
protected function getActivationNotice()
{
$message = "<p>" . __('In order to start the optimization process, you need to validate your API Key in the '
. '<a href="options-general.php?page=wp-shortpixel-settings">ShortPixel Settings</a> page in your WordPress Admin.','shortpixel-image-optimiser') . "
</p>
<p>" . __('If you dont have an API Key, just fill out the form and a key will be created.','shortpixel-image-optimiser') . "</p>";
return $message;
}
protected function getApproxData()
{
$otherMediaController = OtherMediaController::getInstance();
$approx = new \stdClass; // guesses on basis of the statsController SQL.
$approx->media = new \stdClass;
$approx->custom = new \stdClass;
$approx->total = new \stdClass;
$sc = StatsController::getInstance();
$sc->reset(); // Get a fresh stat.
$excludeSizes = \wpSPIO()->settings()->excludeSizes;
$approx->media->items = $sc->find('media', 'itemsTotal') - $sc->find('media', 'items');
// ThumbsTotal - Approx thumbs in installation - Approx optimized thumbs (same query)
$approx->media->thumbs = $sc->find('media', 'thumbsTotal') - $sc->find('media', 'thumbs');
// If sizes are excluded, remove this count from the approx.
if (is_array($excludeSizes) && count($excludeSizes) > 0)
$approx->media->thumbs = $approx->media->thumbs - ($approx->media->items * count($excludeSizes));
// Total optimized items + Total optimized (approx) thumbnails
$approx->media->total = $approx->media->items + $approx->media->thumbs;
$approx->custom->images = $sc->find('custom', 'itemsTotal') - $sc->find('custom', 'items');
$approx->custom->has_custom = $otherMediaController->hasCustomImages();
$approx->total->images = $approx->media->total + $approx->custom->images; // $sc->totalImagesToOptimize();
$approx->media->isLimited = $sc->find('media', 'isLimited');
// Prevent any guesses to go below zero.
foreach($approx->media as $item => $value)
{
if (is_numeric($value))
$approx->media->$item = max($value, 0);
}
foreach($approx->total as $item => $value)
{
if (is_numeric($value))
$approx->total->$item = max($value, 0);
}
return $approx;
}
/* Function to check for and load the current Log. This can be present on load time when the bulk page is refreshed during operations.
* Reload the past error and display them in the error box.
* @param String $type media or custom
*/
protected function loadCurrentLog($type = 'media')
{
$bulkController = BulkController::getInstance();
$log = $bulkController->getLog('current_bulk_' . $type . '.log');
if ($log == false)
return false;
$content = $log->getContents();
$lines = array_filter(explode(';', $content));
$output = '';
foreach ($lines as $line)
{
$cells = array_filter(explode('|', $line));
if (count($cells) == 1)
continue; // empty line.
$date = $filename = $message = $item_id = false;
$date = $cells[0];
$filename = isset($cells[1]) ? $cells[1] : false;
$item_id = isset($cells[2]) ? $cells[2] : false;
$message = isset($cells[3]) ? $cells[3] : false;
$kblink = UIHelper::getKBSearchLink($message);
$kbinfo = '<span class="kbinfo"><a href="' . $kblink . '" target="_blank" ><span class="dashicons dashicons-editor-help">&nbsp;</span></a></span>';
$output .= '<div class="fatal">';
$output .= $date . ': ';
if ($message)
$output .= $message;
if ($filename)
$output .= ' ( '. __('in file ','shortpixel-image-optimiser') . ' ' . $filename . ' ) ' . $kbinfo;
$output .= '</div>';
}
return $output;
}
public function getLogs()
{
$bulkController = BulkController::getInstance();
$logs = $bulkController->getLogs();
$fs = \wpSPIO()->filesystem();
$backupDir = $fs->getDirectory(SHORTPIXEL_BACKUP_FOLDER);
$view = array();
foreach($logs as $logData)
{
$logFile = $fs->getFile($backupDir->getPath() . 'bulk_' . $logData['type'] . '_' . $logData['date'] . '.log');
$errors = $logData['fatal_errors'];
if ($logFile->exists())
{
$errors = '<a data-action="OpenLog" data-file="' . $logFile->getFileName() . '" href="' . $fs->pathToUrl($logFile) . '">' . $errors . '</a>';
}
$op = (isset($logData['operation'])) ? $logData['operation'] : false;
// BulkName is just to compile a user-friendly name for the operation log.
$bulkName = '';
switch($logData['type'])
{
case 'custom':
$bulkName = __('Custom Media Bulk', 'shortpixel-image-optimiser');
break;
case 'media':
$bulkName = __('Media Library Bulk', 'shortpixel-image-optimiser');
break;
}
$bulkName .= ' '; // add a space.
switch($op)
{
case 'bulk-restore':
$bulkName .= __('Restore', 'shortpixel-image-optimiser');
break;
case 'migrate':
$bulkName .= __('Migrate old Metadata', 'shortpixel-image-optimiser');
break;
case 'removeLegacy':
$bulkName = __('Remove Legacy Data', 'shortpixel-image-optimiser');
break;
default:
$bulkName .= __('Optimization', 'shortpixel-image-optimiser');
break;
}
$images = isset($logData['total_images']) ? $logData['total_images'] : $logData['processed'];
$view[] = array('type' => $logData['type'], 'images' => $images, 'errors' => $errors, 'date' => UiHelper::formatTS($logData['date']), 'operation' => $op, 'bulkName' => $bulkName);
}
krsort($view);
return $view;
}
} // class

View File

@ -0,0 +1,352 @@
<?php
namespace ShortPixel\Controller\View;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
use ShortPixel\ShortPixelLogger\ShortPixelLogger as Log;
use ShortPixel\Helper\UiHelper as UiHelper;
use ShortPixel\Helper\UtilHelper as UtilHelper;
use ShortPixel\Controller\OptimizeController as OptimizeController;
use ShortPixel\Controller\ErrorController as ErrorController;
use ShortPixel\Model\File\FileModel as FileModel;
use ShortPixel\Helper\DownloadHelper as DownloadHelper;
// Future contoller for the edit media metabox view.
class EditMediaViewController extends \ShortPixel\ViewController
{
protected $template = 'view-edit-media';
// protected $model = 'image';
protected $post_id;
protected $legacyViewObj;
protected $imageModel;
protected $hooked;
protected static $instance;
public function __construct()
{
parent::__construct();
}
protected function loadHooks()
{
add_action( 'add_meta_boxes_attachment', array( $this, 'addMetaBox') );
$this->hooked = true;
}
public function load()
{
if (! $this->hooked)
$this->loadHooks();
$fs = \wpSPIO()->filesystem();
$fs->startTrustedMode();
}
public function addMetaBox()
{
add_meta_box(
'shortpixel_info_box', // this is HTML id of the box on edit screen
__('ShortPixel Info', 'shortpixel-image-optimiser'), // title of the box
array( $this, 'doMetaBox'), // function to be called to display the info
null,//, // on which edit screen the box should appear
'side'//'normal', // part of page where the box should appear
//'default' // priority of the box
);
}
public function dometaBox($post)
{
$this->post_id = $post->ID;
$this->view->debugInfo = array();
$this->view->id = $this->post_id;
$this->view->list_actions = '';
$fs = \wpSPIO()->filesystem();
$this->imageModel = $fs->getMediaImage($this->post_id);
// Asking for something non-existing.
if ($this->imageModel === false)
{
$this->view->status_message = __('File Error. This could be not an image or the file is missing', 'shortpixel-image-optimiser');
$this->loadView();
return false;
}
$this->view->status_message = null;
$this->view->text = UiHelper::getStatusText($this->imageModel);
$this->view->list_actions = UiHelper::getListActions($this->imageModel);
if ( count($this->view->list_actions) > 0)
$this->view->list_actions = UiHelper::renderBurgerList($this->view->list_actions, $this->imageModel);
else
$this->view->list_actions = '';
//$this->imageModel->cancelUserExclusions();
$this->view->actions = UiHelper::getActions($this->imageModel);
$this->view->stats = $this->getStatistics();
if (! $this->userIsAllowed)
{
$this->view->actions = array();
$this->view->list_actions = '';
}
if(true === \wpSPIO()->env()->is_debug )
{
$this->view->debugInfo = $this->getDebugInfo();
}
$this->loadView();
}
protected function getStatusMessage()
{
return UIHelper::renderSuccessText($this->imageModel);
}
protected function getStatistics()
{
//$data = $this->data;
$stats = array();
$imageObj = $this->imageModel;
$did_keepExif = $imageObj->getMeta('did_keepExif');
$did_convert = $imageObj->getMeta()->convertMeta()->isConverted();
$resize = $imageObj->getMeta('resize');
// Not optimized, not data.
if (! $imageObj->isOptimized())
return array();
if ($did_keepExif)
$stats[] = array(__('EXIF kept', 'shortpixel-image-optimiser'), '');
elseif ( $did_keepExif === false) {
$stats[] = array(__('EXIF removed', 'shortpixel-image-optimiser'), '');
}
if (true === $did_convert )
{
$ext = $imageObj->getMeta()->convertMeta()->getFileFormat();
$stats[] = array( sprintf(__('Converted from %s','shortpixel-image-optimiser'), $ext), '');
}
elseif (false !== $imageObj->getMeta()->convertMeta()->didTry()) {
$ext = $imageObj->getMeta()->convertMeta()->getFileFormat();
$error = $imageObj->getMeta()->convertMeta()->getError(); // error code.
$stats[] = array(UiHelper::getConvertErrorReason($error, $ext), '');
}
if ($resize == true)
{
$from = $imageObj->getMeta('originalWidth') . 'x' . $imageObj->getMeta('originalHeight');
$to = $imageObj->getMeta('resizeWidth') . 'x' . $imageObj->getMeta('resizeHeight');
$type = ($imageObj->getMeta('resizeType') !== null) ? '(' . $imageObj->getMeta('resizeType') . ')' : '';
$stats[] = array(sprintf(__('Resized %s %s to %s'), $type, $from, $to), '');
}
$tsOptimized = $imageObj->getMeta('tsOptimized');
if ($tsOptimized !== null)
$stats[] = array(__("Optimized on :", 'shortpixel-image-optimiser') . "<br /> ", UiHelper::formatTS($tsOptimized) );
if ($imageObj->isOptimized())
{
$stats[] = array( sprintf(__('%s %s Read more about theses stats %s ', 'shortpixel-image-optimiser'), '
<p><img alt=' . esc_html('Info Icon', 'shortpixel-image-optimiser') . ' src=' . esc_url( wpSPIO()->plugin_url('res/img/info-icon.png' )) . ' style="margin-bottom: -4px;"/>', '<a href="https://shortpixel.com/knowledge-base/article/553-the-stats-from-the-shortpixel-column-in-the-media-library-explained" target="_blank">', '</a></p>'), '');
}
return $stats;
}
protected function getDebugInfo()
{
if(! \wpSPIO()->env()->is_debug )
{
return array();
}
$meta = \wp_get_attachment_metadata($this->post_id);
$fs = \wpSPIO()->filesystem();
$imageObj = $this->imageModel;
if ($imageObj->isProcessable())
{
$optimizeData = $imageObj->getOptimizeData();
$urls = $optimizeData['urls'];
}
$thumbnails = $imageObj->get('thumbnails');
$processable = ($imageObj->isProcessable()) ? '<span class="green">Yes</span>' : '<span class="red">No</span> (' . $imageObj->getReason('processable') . ')';
$anyFileType = ($imageObj->isProcessableAnyFileType()) ? '<span class="green">Yes</span>' : '<span class="red">No</span>';
$restorable = ($imageObj->isRestorable()) ? '<span class="green">Yes</span>' : '<span class="red">No</span> (' . $imageObj->getReason('restorable') . ')';
$hasrecord = ($imageObj->hasDBRecord()) ? '<span class="green">Yes</span>' : '<span class="red">No</span> ';
$debugInfo = array();
$debugInfo[] = array(__('URL (get attachment URL)', 'shortpixel_image_optiser'), wp_get_attachment_url($this->post_id));
$debugInfo[] = array(__('File (get attached)'), get_attached_file($this->post_id));
if ($imageObj->is_virtual())
{
$virtual = $imageObj->get('virtual_status');
if($virtual == FileModel::$VIRTUAL_REMOTE)
$vtext = 'Remote';
elseif($virtual == FileModel::$VIRTUAL_STATELESS)
$vtext = 'Stateless';
else
$vtext = 'Not set';
$debugInfo[] = array(__('Is Virtual: ') . $vtext, $imageObj->getFullPath() );
}
$debugInfo[] = array(__('Size and Mime (ImageObj)'), $imageObj->get('width') . 'x' . $imageObj->get('height'). ' (' . $imageObj->get('mime') . ')');
$debugInfo[] = array(__('Status (ShortPixel)'), $imageObj->getMeta('status') . ' ' );
$debugInfo[] = array(__('Processable'), $processable);
$debugInfo[] = array(__('Avif/Webp needed'), $anyFileType);
$debugInfo[] = array(__('Restorable'), $restorable);
$debugInfo[] = array(__('Record'), $hasrecord);
if ($imageObj->getMeta()->convertMeta()->didTry())
{
$debugInfo[] = array(__('Converted'), ($imageObj->getMeta()->convertMeta()->isConverted() ?'<span class="green">Yes</span>' : '<span class="red">No</span> '));
$debugInfo[] = array(__('Checksum'), $imageObj->getMeta()->convertMeta()->didTry());
$debugInfo[] = array(__('Error'), $imageObj->getMeta()->convertMeta()->getError());
}
$debugInfo[] = array(__('WPML Duplicates'), json_encode($imageObj->getWPMLDuplicates()) );
if ($imageObj->getParent() !== false)
{
$debugInfo[] = array(__('WPML duplicate - Parent: '), $imageObj->getParent());
}
if (isset($urls))
{
$debugInfo[] = array(__('To Optimize URLS'), $urls);
}
if (isset($optimizeData))
{
$debugInfo[] = array(__('Optimize Data'), $optimizeData);
$optControl = new optimizeController();
$q = $optControl->getQueue($imageObj->get('type'));
$debugInfo[] = array(__('Image to Queue'), $q->_debug_imageModelToQueue($imageObj) );
}
$debugInfo['imagemetadata'] = array(__('ImageModel Metadata (ShortPixel)'), $imageObj);
$debugInfo[] = array('', '<hr>');
$debugInfo['wpmetadata'] = array(__('WordPress Get Attachment Metadata'), $meta );
$debugInfo[] = array('', '<hr>');
if ($imageObj->hasBackup())
$backupFile = $imageObj->getBackupFile();
else {
$backupFile = $fs->getFile($fs->getBackupDirectory($imageObj) . $imageObj->getBackupFileName());
}
$debugInfo[] = array(__('Backup Folder'), (string) $backupFile->getFileDir() );
if ($imageObj->hasBackup())
$backupText = __('Backup File :');
else {
$backupText = __('Target Backup File after optimization (no backup) ');
}
$debugInfo[] = array( $backupText, (string) $backupFile . '(' . UiHelper::formatBytes($backupFile->getFileSize()) . ')' );
$debugInfo[] = array(__("No Main File Backup Available"), '');
if ($imageObj->getMeta()->convertMeta()->isConverted())
{
$convertedBackup = ($imageObj->hasBackup(array('forceConverted' => true))) ? '<span class="green">Yes</span>' : '<span class="red">No</span>';
$backup = $imageObj->getBackupFile(array('forceConverted' => true));
$debugInfo[] = array('Has converted backup', $convertedBackup);
if (is_object($backup))
$debugInfo[] = array('Backup: ', $backup->getFullPath() );
}
if ($or = $imageObj->hasOriginal())
{
$original = $imageObj->getOriginalFile();
$debugInfo[] = array(__('Has Original File: '), $original->getFullPath() . '(' . UiHelper::formatBytes($original->getFileSize()) . ')');
$orbackup = $original->getBackupFile();
if ($orbackup)
$debugInfo[] = array(__('Has Backup Original Image'), $orbackup->getFullPath() . '(' . UiHelper::formatBytes($orbackup->getFileSize()) . ')');
$debugInfo[] = array('', '<hr>');
}
if (! isset($meta['sizes']) )
{
$debugInfo[] = array('', __('Thumbnails were not generated', 'shortpixel-image-optimiser'));
}
else
{
foreach($thumbnails as $thumbObj)
{
$size = $thumbObj->get('size');
$display_size = ucfirst(str_replace("_", " ", $size));
//$thumbObj = $imageObj->getThumbnail($size);
if ($thumbObj === false)
{
$debugInfo[] = array(__('Thumbnail not found / loaded: ', 'shortpixel-image-optimiser'), $size );
continue;
}
$url = $thumbObj->getURL(); //$fs->pathToURL($thumbObj); //wp_get_attachment_image_src($this->post_id, $size);
$filename = $thumbObj->getFullPath();
$backupFile = $thumbObj->getBackupFile();
if ($thumbObj->hasBackup())
{
$backup = $backupFile->getFullPath();
$backupText = __('Backup File :');
}
else {
$backupFile = $fs->getFile($fs->getBackupDirectory($thumbObj) . $thumbObj->getBackupFileName());
$backup = $backupFile->getFullPath();
$backupText = __('Target Backup File after optimization (no backup) ');
}
$width = $thumbObj->get('width');
$height = $thumbObj->get('height');
$processable = ($thumbObj->isProcessable()) ? '<span class="green">Yes</span>' : '<span class="red">No</span> (' . $thumbObj->getReason('processable') . ')';
$restorable = ($thumbObj->isRestorable()) ? '<span class="green">Yes</span>' : '<span class="red">No</span> (' . $thumbObj->getReason('restorable') . ')';
$hasrecord = ($thumbObj->hasDBRecord()) ? '<span class="green">Yes</span>' : '<span class="red">No</span> ';
$dbid = $thumbObj->getMeta('databaseID');
$debugInfo[] = array('', "<div class='$size previewwrapper'><img src='" . $url . "'><p class='label'>
<b>URL:</b> $url ( $display_size - $width X $height ) <br><b>FileName:</b> $filename <br> <b> $backupText </b> $backup </p>
<p><b>Processable: </b> $processable <br> <b>Restorable:</b> $restorable <br> <b>Record:</b> $hasrecord ($dbid) </p>
<hr></div>");
}
}
return $debugInfo;
}
} // controller .

View File

@ -0,0 +1,259 @@
<?php
namespace ShortPixel\Controller\View;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
use ShortPixel\ShortPixelLogger\ShortPixelLogger as Log;
use ShortPixel\Helper\UiHelper as UiHelper;
use ShortPixel\Helper\UtilHelper as UtilHelper;
use ShortPixel\Controller\ApiKeyController as ApiKeyController;
use ShortPixel\Controller\QuotaController as QuotaController;
use ShortPixel\Controller\OptimizeController as OptimizeController;
use ShortPixel\Notices\NoticeController as Notice;
use ShortPixel\Model\Image\ImageModel as ImageModel;
use ShortPixel\Model\Image\MediaLibraryModel as MediaLibraryModel;
// Controller for the MediaLibraryView
class ListMediaViewController extends \ShortPixel\ViewController
{
protected static $instance;
protected $template = 'view-list-media';
// protected $model = 'image';
public function __construct()
{
parent::__construct();
}
public function load()
{
$fs = \wpSPIO()->filesystem();
$fs->startTrustedMode();
$this->checkAction(); // bulk action checkboxes, y'all
$this->loadHooks();
}
/** Check if a bulk action (checkboxes) was requested
*/
protected function checkAction()
{
$wp_list_table = _get_list_table('WP_Media_List_Table');
$action = $wp_list_table->current_action();
if (! $action)
return;
if(strpos($action, 'shortpixel') === 0 ) {
check_admin_referer('bulk-media');
}
// Nothing selected, nothing doin'
if (! isset($_GET['media']) || ! is_array($_GET['media']))
return;
$fs = \wpSPIO()->filesystem();
$optimizeController = new OptimizeController();
$items = array_filter($_GET['media'], 'intval');
$numItems = count($items);
$plugin_action = str_replace('shortpixel-', '', $action);
$targetCompressionType = $targetCrop = null;
switch ($plugin_action)
{
case "glossy":
$targetCompressionType = ImageModel::COMPRESSION_GLOSSY;
break;
case "lossy":
$targetCompressionType = ImageModel::COMPRESSION_LOSSY;
break;
case "lossless":
$targetCompressionType = ImageModel::COMPRESSION_LOSSLESS;
break;
case 'smartcrop':
$targetCrop = ImageModel::ACTION_SMARTCROP;
break;
case 'smartcropless':
$targetCrop = ImageModel::ACTION_SMARTCROPLESS;
break;
}
foreach($items as $item_id)
{
$mediaItem = $fs->getMediaImage($item_id);
switch($plugin_action)
{
case 'optimize':
if ($mediaItem->isProcessable())
$res = $optimizeController->addItemToQueue($mediaItem);
break;
case 'smartcrop':
case 'smartcropless':
if ($mediaItem->isOptimized())
{
$targetCompressionType = $mediaItem->getMeta('compressionType');
}
else {
$targetCompressionType = \wpSPIO()->settings()->compressionType;
}
case 'glossy':
case 'lossy':
case 'lossless':
if ($mediaItem->isOptimized() && $mediaItem->getMeta('compressionType') == $targetCompressionType && is_null($targetCrop) )
{
// do nothing if already done w/ this compression.
}
elseif(! $mediaItem->isOptimized())
{
$mediaItem->setMeta('compressionType', $targetCompressionType);
if (! is_null($targetCrop))
{
$mediaItem->doSetting('smartcrop', $targetCrop);
}
$res = $optimizeController->addItemToQueue($mediaItem);
}
else
{
$args = array();
if (! is_null($targetCrop))
{
$args = array('smartcrop' => $targetCrop);
}
$res = $optimizeController->reOptimizeItem($mediaItem, $targetCompressionType, $args);
}
break;
case 'restore';
if ($mediaItem->isOptimized())
$res = $optimizeController->restoreItem($mediaItem);
break;
case 'mark-completed':
if ($mediaItem->isProcessable())
{
$mediaItem->markCompleted(__('This item has been manually marked as completed', 'shortpixel-image-optimiser'), ImageModel::FILE_STATUS_MARKED_DONE);
}
break;
}
}
}
/** Hooks for the MediaLibrary View */
protected function loadHooks()
{
add_filter( 'manage_media_columns', array( $this, 'headerColumns' ) );//add media library column header
add_action( 'manage_media_custom_column', array( $this, 'doColumn' ), 10, 2 );//generate the media library column
//Sort and filter on ShortPixel Compression column
//add_filter( 'manage_upload_sortable_columns', array( $this, 'registerSortable') );
add_action('restrict_manage_posts', array( $this, 'mediaAddFilterDropdown'));
add_action('loop_end', array($this, 'loadComparer'));
}
public function headerColumns($defaults)
{
$defaults['wp-shortPixel'] = __('ShortPixel Compression', 'shortpixel-image-optimiser');
return $defaults;
}
public function doColumn($column_name, $id)
{
if($column_name == 'wp-shortPixel')
{
$this->view = new \stdClass; // reset every row
$this->view->id = $id;
$this->loadItem($id);
$this->loadView(null, false);
}
}
public function loadItem($id)
{
$fs = \wpSPIO()->filesystem();
$mediaItem = $fs->getMediaImage($id);
$keyControl = ApiKeyController::getInstance();
$quotaControl = QuotaController::getInstance();
// Asking for something non-existing.
if ($mediaItem === false)
{
$this->view->text = __('File Error. This could be not an image or the file is missing', 'shortpixel-image-optimiser');
return;
}
$this->view->mediaItem = $mediaItem;
$actions = array();
$list_actions = array();
$this->view->text = UiHelper::getStatusText($mediaItem);
$this->view->list_actions = UiHelper::getListActions($mediaItem);
if ( count($this->view->list_actions) > 0)
{
$this->view->list_actions = UiHelper::renderBurgerList($this->view->list_actions, $mediaItem);
}
else
{
$this->view->list_actions = '';
}
$this->view->actions = UiHelper::getActions($mediaItem);
//$this->view->actions = $actions;
if (! $this->userIsAllowed)
{
$this->view->actions = array();
$this->view->list_actions = '';
}
}
public function loadComparer()
{
$this->loadView('snippets/part-comparer');
}
/*
* @hook restrict_manage_posts
*/
public function mediaAddFilterDropdown() {
$scr = get_current_screen();
if ( $scr->base !== 'upload' ) return;
$status = filter_input(INPUT_GET, 'shortpixel_status', FILTER_UNSAFE_RAW );
$options = array(
'all' => __('Any ShortPixel State', 'shortpixel-image-optimiser'),
'optimized' => __('Optimized', 'shortpixel-image-optimiser'),
'unoptimized' => __('Unoptimized', 'shortpixel-image-optimiser'),
'prevented' => __('Optimization Error', 'shortpixer-image-optimiser'),
);
echo "<select name='shortpixel_status' id='shortpixel_status'>\n";
foreach($options as $optname => $optval)
{
$selected = ($status == $optname) ? esc_attr('selected') : '';
echo "<option value='". esc_attr($optname) . "' $selected >" . esc_html($optval) . "</option>\n";
}
echo "</select>";
}
}

View File

@ -0,0 +1,487 @@
<?php
namespace ShortPixel\Controller\View;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
use ShortPixel\ShortPixelLogger\ShortPixelLogger as Log;
use ShortPixel\Notices\NoticeController as Notices;
use ShortPixel\Helper\InstallHelper as InstallHelper;
use ShortPixel\Controller\OtherMediaController as OtherMediaController;
class OtherMediaFolderViewController extends \ShortPixel\ViewController
{
protected $template = 'view-other-media-folder';
protected static $instance;
// Pagination .
protected $items_per_page = 20;
protected $currentPage = 1;
protected $total_items = 0;
protected $order;
protected $orderby;
protected $search;
protected $show_hidden = false;
protected $has_hidden_items = false;
protected $customFolderBase;
private $controller;
public function __construct()
{
parent::__construct();
$fs = \wpSPIO()->filesystem();
$this->controller = OtherMediaController::getInstance();
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is not a form
$this->currentPage = isset($_GET['paged']) ? intval($_GET['paged']) : 1;
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is not a form
$this->orderby = ( ! empty( $_GET['orderby'] ) ) ? $this->filterAllowedOrderBy(sanitize_text_field(wp_unslash($_GET['orderby']))) : 'id';
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is not a form
$this->order = ( ! empty($_GET['order'] ) ) ? sanitize_text_field( wp_unslash($_GET['order'])) : 'desc'; // If no order, default to asc
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is not a form
$this->search = (isset($_GET["s"]) && strlen($_GET["s"]) > 0) ? sanitize_text_field( wp_unslash($_GET['s'])) : false;
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is not a form
$this->show_hidden = isset($_GET['show_hidden']) ? sanitize_text_field(wp_unslash($_GET['show_hidden'])) : false;
$customFolderBase = $fs->getWPFileBase();
$this->customFolderBase = $customFolderBase->getPath();
$this->loadSettings();
}
/** Controller default action - overview */
public function load()
{
// $this->process_actions();
//
$this->view->items = $this->getItems();
// $this->view->folders = $this->getItemFolders($this->view->items);
$this->view->headings = $this->getHeadings();
$this->view->pagination = $this->getPagination();
$this->view->filter = $this->getFilter();
// $this->checkQueue();
$this->loadView();
}
public function singleItemView($folderObj)
{
ob_start();
$this->view->current_item = $folderObj;
$this->loadView('custom/part-single-folder', false);
$result = ob_get_contents();
ob_end_clean();
return $result;
}
protected function loadSettings()
{
$settings = \wpSPIO()->settings();
$this->view->settings = new \stdclass;
$this->view->settings->includeNextGen = $settings->includeNextGen;
$this->view->title = __('Shortpixel Custom Folders', 'shortpixel-image-optimiser');
$this->view->show_search = true;
$this->view->has_filters = true;
}
protected function getRowActions($item)
{
$actions = array();
$removeAction = array('remove' => array(
'function' => 'window.ShortPixelProcessor.screen.StopMonitoringFolder(' . intval($item->get('id')) . ')',
'type' => 'js',
'text' => __('Stop Monitoring', 'shortpixel-image-optimiser'),
'display' => 'inline',
));
$refreshAction = array('refresh' => array(
'function' => 'window.ShortPixelProcessor.screen.RefreshFolder(' . intval($item->get('id')) . ')',
'type' => 'js',
'text' => __('Refresh Folder', 'shortpixel-image-optimiser'),
'display' => 'inline',
));
// @todo Get path of last one/two subdirectories and link to files page (?) or add a query for folder_id options.
$url = add_query_arg('part', 'files', $this->url);
$url = add_query_arg('folder_id', $item->get('id'), $url);
$showFilesAction = array('showfiles' => array(
'function' => esc_url($url),
'type' => 'link',
'text' => __('Show all Files', 'shortpixel-image-optimiser'),
'display' => 'inline',
));
$actions = array_merge($actions, $refreshAction, $removeAction, $showFilesAction);
// $actions = array_merge($actions, );
return $actions;
}
private function getItems($args = array())
{
$results = $this->queryItems($args);
$items = array();
foreach($results as $index => $databaseObj)
{
$db_id = $databaseObj->id;
$folderObj = $this->controller->getFolderByID($db_id);
$items[$db_id] = $folderObj;
}
$this->total_items = $this->queryItems(array('limit' => -1, 'only_count' => true));
return $items;
}
private function queryItems($args = array())
{
global $wpdb;
$page = $this->currentPage;
if ($page <= 0)
$page = 1;
$defaults = array(
'id' => false, // Get folder by Id
'remove_hidden' => true, // Query only active folders
'path' => false,
'only_count' => false,
'limit' => $this->items_per_page,
'offset' => ($page - 1) * $this->items_per_page,
);
$filters = $this->getFilter();
$args = wp_parse_args($args, $defaults);
if (! $this->hasFoldersTable())
{
if ($args['only_count'])
return 0;
else
return array();
}
$fs = \wpSPIO()->fileSystem();
if ($args['only_count'])
$selector = 'count(id) as id';
else
$selector = '*';
$sql = "SELECT " . $selector . " FROM " . $wpdb->prefix . "shortpixel_folders WHERE 1=1 ";
$prepare = array();
// $mask = array();
if ($args['id'] !== false && $args['id'] > 0)
{
$sql .= ' AND id = %d';
$prepare[] = $args['id'];
}
elseif($args['path'] !== false && strlen($args['path']) > 0)
{
$sql .= ' AND path = %s';
$prepare[] = $args['path'];
}
if ($args['remove_hidden'])
{
$sql .= " AND status <> -1";
}
$sql .= ($this->orderby ? " ORDER BY " . $this->orderby . " " . $this->order . " " : "");
if ($args['limit'] > 0)
{
$sql .= " LIMIT " . intval($args['limit']) . " OFFSET " . intval($args['offset']);
}
if (count($prepare) > 0)
$sql = $wpdb->prepare($sql, $prepare);
if ($args['only_count'])
$results = intval($wpdb->get_var($sql));
else
$results = $wpdb->get_results($sql);
return $results;
}
protected function getHeadings()
{
$headings = array(
'checkbox' => array('title' => '<input type="checkbox" name="select-all">',
'sortable' => false,
'orderby' => 'id', // placeholder to allow sort on this.
),
'name' => array('title' => __('Folder Name', 'shortpixel-image-optimiser'),
'sortable' => true,
'orderby' => 'name',
),
'type' => array('title' => __('Type', 'shortpixel-image-optimiser'),
'sortable' => false,
'orderby' => 'path',
),
'files' => array('title' => __('Files', 'shortpixel-image-optimiser'),
'sortable' => false,
'orderby' => 'files',
'title_context' => __('Images in folder - optimized / unoptimized ','shortpixel-image-optimiser'),
),
'date' => array('title' => __('Last change', 'shortpixel-image-optimiser'),
'sortable' => true,
'orderby' => 'ts_updated',
),
/* Status is only yes, or nextgen. Already in the Type string. Status use for messages */
'status' => array('title' => __('Message', 'shortpixel-image-optimiser'),
'sortable' => false,
'orderby' => 'status',
),
/* 'actions' => array('title' => __('Actions', 'shortpixel-image-optimiser'),
'sortable' => false,
), */
);
return $headings;
}
private function getPageArgs($args = array())
{
$defaults = array(
'orderby' => $this->orderby,
'order' => $this->order,
's' => $this->search,
'paged' => $this->currentPage,
'part' => 'folders',
);
$page_args = array_filter(wp_parse_args($args, $defaults));
return $page_args; // has url
}
// @todo duplicate of OtherMediaViewController which is not nice.
protected function getDisplayHeading($heading)
{
$output = '';
$defaults = array('title' => '', 'sortable' => false);
$heading = wp_parse_args($heading, $defaults);
$title = $heading['title'];
if ($heading['sortable'])
{
//$current_order = isset($_GET['order']) ? $current_order : false;
//$current_orderby = isset($_GET['orderby']) ? $current_orderby : false;
$sorturl = add_query_arg('orderby', $heading['orderby'] );
$sorted = '';
if ($this->orderby == $heading['orderby'])
{
if ($this->order == 'desc')
{
$sorturl = add_query_arg('order', 'asc', $sorturl);
$sorted = 'sorted desc';
}
else
{
$sorturl = add_query_arg('order', 'desc', $sorturl);
$sorted = 'sorted asc';
}
}
else
{
$sorturl = add_query_arg('order', 'asc', $sorturl);
}
$output = '<a href="' . esc_url($sorturl) . '"><span>' . esc_html($title) . '</span><span class="sorting-indicator '. esc_attr($sorted) . '">&nbsp;</span></a>';
}
else
{
$output = $title;
}
return $output;
}
protected function filterAllowedOrderBy($orderby)
{
$headings = $this->getHeadings() ;
$filters = array();
foreach ($headings as $heading)
{
if (isset($heading['orderby']))
{
$filters[]= $heading['orderby'];
}
}
if (! in_array($orderby, $filters))
return '';
return $orderby;
}
protected function getPagination()
{
$parray = array();
$current = $this->currentPage;
$total = $this->total_items;
$per_page = $this->items_per_page;
$pages = ceil($total / $per_page);
if ($pages <= 1)
return false; // no pages.
$disable_first = $disable_last = $disable_prev = $disable_next = false;
$page_links = array();
if ( $current == 1 ) {
$disable_first = true;
$disable_prev = true;
}
if ( $current == 2 ) {
$disable_first = true;
}
if ( $current == $pages ) {
$disable_last = true;
$disable_next = true;
}
if ( $current == $pages - 1 ) {
$disable_last = true;
}
$total_pages_before = '<span class="paging-input">';
$total_pages_after = '</span></span>';
$page_args =$this->getPageArgs(); // has url
if (isset($page_args['paged']))
unset($page_args['paged']);
// Try with controller URL, if not present, try with upload URL and page param.
$admin_url = admin_url('upload.php');
$url = (is_null($this->url)) ? add_query_arg('page','wp-short-pixel-custom', $admin_url) : $this->url; // has url
$current_url = add_query_arg($page_args, $url);
$url = remove_query_arg('page', $url);
$page_args['page'] = 'wp-short-pixel-custom';
$output = '<form method="GET" action="'. esc_attr($url) . '">';
foreach($page_args as $arg => $val)
{
$output .= sprintf('<input type="hidden" name="%s" value="%s">', $arg, $val);
}
$output .= '<span class="displaying-num">'. sprintf(esc_html__('%d Images', 'shortpixel-image-optimiser'), $this->total_items) . '</span>';
if ( $disable_first ) {
$page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&laquo;</span>';
} else {
$page_links[] = sprintf(
"<a class='first-page button' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
esc_url( $current_url ),
esc_html__( 'First page' ),
'&laquo;'
);
}
if ( $disable_prev ) {
$page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&lsaquo;</span>';
} else {
$page_links[] = sprintf(
"<a class='prev-page button' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
esc_url( add_query_arg( 'paged', max( 1, $current - 1 ), $current_url ) ),
esc_html__( 'Previous page' ),
'&lsaquo;'
);
}
$html_current_page = sprintf(
"%s<input class='current-page' id='current-page-selector' type='text' name='paged' value='%s' size='%d' aria-describedby='table-paging' /><span class='tablenav-paging-text'>",
'<label for="current-page-selector" class="screen-reader-text">' . esc_html__( 'Current Page' ) . '</label>',
$current,
strlen( $pages )
);
$html_total_pages = sprintf( "<span class='total-pages'>%s</span>", number_format_i18n( $pages ) );
$page_links[] = $total_pages_before . sprintf(
/* translators: 1: Current page, 2: Total pages. */
_x( '%1$s of %2$s', 'paging' ),
$html_current_page,
$html_total_pages
) . $total_pages_after;
if ( $disable_next ) {
$page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&rsaquo;</span>';
} else {
$page_links[] = sprintf(
"<a class='next-page button' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
esc_url( add_query_arg( 'paged', min( $pages, $current + 1 ), $current_url ) ),
__( 'Next page' ),
'&rsaquo;'
);
}
if ( $disable_last ) {
$page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&raquo;</span>';
} else {
$page_links[] = sprintf(
"<a class='last-page button' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
esc_url( add_query_arg( 'paged', $pages, $current_url ) ),
__( 'Last page' ),
'&raquo;'
);
}
$output .= "\n<span class='pagination-links'>" . join( "\n", $page_links ) . '</span>';
$output .= "</form>";
return $output;
}
protected function getFilter() {
$filter = array();
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is not a form
$search = (isset($_GET['s'])) ? sanitize_text_field(wp_unslash($_GET['s'])) : '';
if(strlen($search) > 0) {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is not a form
$filter['path'] = (object)array("operator" => "like", "value" =>"'%" . esc_sql($search) . "%'");
}
return $filter;
}
private function hasFoldersTable()
{
return InstallHelper::checkTableExists('shortpixel_folders');
}
} // class

View File

@ -0,0 +1,45 @@
<?php
namespace ShortPixel\Controller\View;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
use ShortPixel\ShortPixelLogger\ShortPixelLogger as Log;
use ShortPixel\Notices\NoticeController as Notices;
use ShortPixel\Helper\InstallHelper as InstallHelper;
use ShortPixel\Controller\OtherMediaController as OtherMediaController;
class OtherMediaScanViewController extends \ShortPixel\ViewController
{
protected $template = 'view-other-media-scan';
protected static $instance;
protected static $allFolders;
private $controller;
public function __construct()
{
parent::__construct();
$this->controller = OtherMediaController::getInstance();
}
public function load()
{
$this->view->title = __('Scan for new files', 'shortpixel-image-optimiser');
$this->view->pagination = false;
$this->view->show_search = false;
$this->view->has_filters = false;
$this->view->totalFolders = count($this->controller->getActiveDirectoryIDS());
$this->loadView();
}
} // class

View File

@ -0,0 +1,591 @@
<?php
namespace ShortPixel\Controller\View;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
use ShortPixel\ShortPixelLogger\ShortPixelLogger as Log;
use ShortPixel\Notices\NoticeController as Notices;
use ShortPixel\Controller\ApiKeyController as ApiKeyController;
use ShortPixel\Controller\OtherMediaController as OtherMediaController;
use ShortPixel\Model\File\DirectoryOtherMediaModel as DirectoryOtherMediaModel;
use ShortPixel\Model\Image\ImageModel as ImageModel;
use ShortPixel\Controller\Queue\CustomQueue as CustomQueue;
use ShortPixel\Helper\UiHelper as UiHelper;
// Future contoller for the edit media metabox view.
class OtherMediaViewController extends \ShortPixel\ViewController
{
//$this->model = new
protected $template = 'view-other-media';
protected static $instance;
// Pagination .
protected $items_per_page = 20;
protected $currentPage = 1;
protected $total_items = 0;
protected $order;
protected $orderby;
protected $search;
protected $show_hidden = false;
protected $has_hidden_items = false;
public function __construct()
{
parent::__construct();
// 2015: https://github.com/WordPress/WordPress-Coding-Standards/issues/426 !
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is not a form
$this->currentPage = isset($_GET['paged']) ? intval($_GET['paged']) : 1;
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is not a form
$this->orderby = ( ! empty( $_GET['orderby'] ) ) ? $this->filterAllowedOrderBy(sanitize_text_field(wp_unslash($_GET['orderby']))) : 'id';
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is not a form
$this->order = ( ! empty($_GET['order'] ) ) ? sanitize_text_field( wp_unslash($_GET['order'])) : 'desc'; // If no order, default to asc
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is not a form
$this->search = (isset($_GET["s"]) && strlen($_GET["s"]) > 0) ? sanitize_text_field( wp_unslash($_GET['s'])) : false;
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is not a form
$this->show_hidden = isset($_GET['show_hidden']) ? sanitize_text_field(wp_unslash($_GET['show_hidden'])) : false;
}
/** Controller default action - overview */
public function load()
{
// $this->process_actions();
$this->view->items = $this->getItems();
$this->view->folders = $this->getItemFolders($this->view->items);
$this->view->headings = $this->getHeadings();
$this->view->pagination = $this->getPagination();
$this->view->filter = $this->getFilter();
$this->view->title = __('Custom Media optimized by ShortPixel', 'shortpixel-image-optimiser');
$this->view->show_search = true;
// $this->checkQueue();
$this->loadView();
}
protected function getHeadings()
{
$headings = array(
'checkbox' => array('title' => '<input type="checkbox" name="select-all">', 'sortable' => false),
'thumbnails' => array('title' => __('Thumbnail', 'shortpixel-image-optimiser'),
'sortable' => false,
'orderby' => 'id', // placeholder to allow sort on this.
),
'name' => array('title' => __('Name', 'shortpixel-image-optimiser'),
'sortable' => true,
'orderby' => 'name',
),
'folder' => array('title' => __('Folder', 'shortpixel-image-optimiser'),
'sortable' => true,
'orderby' => 'path',
),
'type' => array('title' => __('Type', 'shortpixel-image-optimiser'),
'sortable' => false,
),
'date' => array('title' => __('Date', 'shortpixel-image-optimiser'),
'sortable' => true,
'orderby' => 'ts_optimized',
),
'status' => array('title' => __('Status', 'shortpixel-image-optimiser'),
'sortable' => true,
'orderby' => 'status',
),
/* 'actions' => array('title' => __('Actions', 'shortpixel-image-optimiser'),
'sortable' => false,
), */
);
$keyControl = ApiKeyController::getInstance();
if (! $keyControl->keyIsVerified())
{
$headings['actions']['title'] = '';
}
return $headings;
}
protected function getItems()
{
$fs = \wpSPIO()->filesystem();
// [BS] Moving this from ts_added since often images get added at the same time, resulting in unpredictable sorting
$items = $this->queryItems();
$removed = array();
foreach($items as $index => $item)
{
$mediaItem = $fs->getImage($item->id, 'custom');
if (! $mediaItem->exists()) // remove image if it doesn't exist.
{
$mediaItem->onDelete();
$removed[] = $item->path;
unset($items[$index]);
}
$items[$index] = $mediaItem;
}
if (count($removed) > 0)
{
Notices::addWarning(sprintf(__('Some images were missing. They have been removed from the Custom Media overview : %s %s'),
'<BR>', implode('<BR>', $removed)));
}
return $items;
}
protected function getItemFolders($items)
{
$folderArray = array();
$otherMedia = OtherMediaController::getInstance();
foreach ($items as $item) // mediaItem;
{
$folder_id = $item->get('folder_id');
if (! isset($folderArray[$folder_id]))
{
$folderArray[$folder_id] = $otherMedia->getFolderByID($folder_id);
}
}
return $folderArray;
}
/* Check which folders are in result, and load them. */
protected function loadFolders($items)
{
$folderArray = array();
$otherMedia = OtherMediaController::getInstance();
foreach($items as $item)
{
$folder_id = $item->get('folder_id');
if (! isset($folderArray[$folder_id]))
{
$folderArray[$folder_id] = $otherMedia->getFolderByID($folder_id);
}
}
return $folderArray;
}
protected function getFilter() {
$filter = array();
$this->view->hasFilter = false;
$this->view->hasSearch = false;
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is not a form
$search = (isset($_GET['s'])) ? sanitize_text_field(wp_unslash($_GET['s'])) : '';
if(strlen($search) > 0) {
$this->view->hasSearch = true;
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is not a form
$filter['path'] = (object)array("operator" => "like", "value" =>"'%" . esc_sql($search) . "%'");
}
$folderFilter = (isset($_GET['folder_id'])) ? intval($_GET['folder_id']) : false;
if (false !== $folderFilter)
{
$this->view->hasFilter = true;
$filter['folder_id'] = (object)array("operator" => "=", "value" =>"'" . esc_sql($folderFilter) . "'");
}
$statusFilter = isset($_GET['custom-status']) ? sanitize_text_field($_GET['custom-status']) : false;
if (false !== $statusFilter)
{
$operator = '=';
$value = false;
$this->view->hasFilter = true;
switch($statusFilter)
{
case 'optimized':
$value = ImageModel::FILE_STATUS_SUCCESS;
break;
case 'unoptimized':
$value = ImageModel::FILE_STATUS_UNPROCESSED;
break;
case 'prevented':
// $value = 0;
// $operator = '<';
$filter['status'] = (object) array('field' => 'status',
'operator' => "<", 'value' => "0");
$filter['status2'] = (object) array('field' => 'status',
'operator' => '<>', 'value' => ImageModel::FILE_STATUS_MARKED_DONE
);
break;
}
if (false !== $value)
{
$filter['status'] = (object)array("operator" => $operator, "value" =>"'" . esc_sql($value) . "'");
}
}
return $filter;
}
public function queryItems() {
$filters = $this->getFilter();
global $wpdb;
$page = $this->currentPage;
if ($page <= 0)
$page = 1;
$controller = OtherMediaController::getInstance();
$hidden_ids = $controller->getHiddenDirectoryIDS();
if (count($hidden_ids) > 0)
$this->has_hidden_items = true;
if ($this->show_hidden == true)
$dirs = implode(',', $hidden_ids );
else
$dirs = implode(',', $controller->getActiveDirectoryIDS() );
if (strlen($dirs) == 0)
return array();
$sql = "SELECT COUNT(id) as count FROM " . $wpdb->prefix . "shortpixel_meta where folder_id in ( " . $dirs . ") ";
foreach($filters as $field => $value) {
$field = property_exists($value, 'field') ? $value->field : $field;
$sql .= " AND $field " . $value->operator . " ". $value->value . " ";
}
$this->total_items = $wpdb->get_var($sql);
$sql = "SELECT * FROM " . $wpdb->prefix . "shortpixel_meta where folder_id in ( " . $dirs . ") ";
foreach($filters as $field => $value) {
$field = property_exists($value, 'field') ? $value->field : $field;
$sql .= " AND $field " . $value->operator . " ". $value->value . " ";
}
$sql .= ($this->orderby ? " ORDER BY " . $this->orderby . " " . $this->order . " " : "")
. " LIMIT " . $this->items_per_page . " OFFSET " . ($page - 1) * $this->items_per_page;
$results = $wpdb->get_results($sql);
return $results;
}
private function getPageArgs($args = array())
{
$defaults = array(
'orderby' => $this->orderby,
'order' => $this->order,
's' => $this->search,
'paged' => $this->currentPage
);
$page_args = array_filter(wp_parse_args($args, $defaults));
return $page_args; // has url
}
protected function filterAllowedOrderBy($orderby)
{
$headings = $this->getHeadings() ;
$filters = array();
foreach ($headings as $heading)
{
if (isset($heading['orderby']))
{
$filters[]= $heading['orderby'];
}
}
if (! in_array($orderby, $filters))
return '';
return $orderby;
}
protected function getPagination()
{
$parray = array();
$current = $this->currentPage;
$total = $this->total_items;
$per_page = $this->items_per_page;
$pages = ceil($total / $per_page);
if ($pages <= 1)
return false; // no pages.
$disable_first = $disable_last = $disable_prev = $disable_next = false;
$page_links = array();
if ( $current == 1 ) {
$disable_first = true;
$disable_prev = true;
}
if ( $current == 2 ) {
$disable_first = true;
}
if ( $current == $pages ) {
$disable_last = true;
$disable_next = true;
}
if ( $current == $pages - 1 ) {
$disable_last = true;
}
$total_pages_before = '<span class="paging-input">';
$total_pages_after = '</span></span>';
$page_args =$this->getPageArgs(); // has url
if (isset($page_args['paged']))
unset($page_args['paged']);
// Try with controller URL, if not present, try with upload URL and page param.
$admin_url = admin_url('upload.php');
$url = (is_null($this->url)) ? add_query_arg('page','wp-short-pixel-custom', $admin_url) : $this->url; // has url
$current_url = add_query_arg($page_args, $url);
$url = remove_query_arg('page', $url);
$page_args['page'] = 'wp-short-pixel-custom';
$output = '<form method="GET" action="'. esc_attr($url) . '">';
foreach($page_args as $arg => $val)
{
$output .= sprintf('<input type="hidden" name="%s" value="%s">', $arg, $val);
}
$output .= '<span class="displaying-num">'. sprintf(esc_html__('%d Images', 'shortpixel-image-optimiser'), $this->total_items) . '</span>';
if ( $disable_first ) {
$page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&laquo;</span>';
} else {
$page_links[] = sprintf(
"<a class='first-page button' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
esc_url( $current_url ),
esc_html__( 'First page' ),
'&laquo;'
);
}
if ( $disable_prev ) {
$page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&lsaquo;</span>';
} else {
$page_links[] = sprintf(
"<a class='prev-page button' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
esc_url( add_query_arg( 'paged', max( 1, $current - 1 ), $current_url ) ),
esc_html__( 'Previous page' ),
'&lsaquo;'
);
}
$html_current_page = sprintf(
"%s<input class='current-page' id='current-page-selector' type='text' name='paged' value='%s' size='%d' aria-describedby='table-paging' /><span class='tablenav-paging-text'>",
'<label for="current-page-selector" class="screen-reader-text">' . esc_html__( 'Current Page' ) . '</label>',
$current,
strlen( $pages )
);
$html_total_pages = sprintf( "<span class='total-pages'>%s</span>", number_format_i18n( $pages ) );
$page_links[] = $total_pages_before . sprintf(
/* translators: 1: Current page, 2: Total pages. */
_x( '%1$s of %2$s', 'paging' ),
$html_current_page,
$html_total_pages
) . $total_pages_after;
if ( $disable_next ) {
$page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&rsaquo;</span>';
} else {
$page_links[] = sprintf(
"<a class='next-page button' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
esc_url( add_query_arg( 'paged', min( $pages, $current + 1 ), $current_url ) ),
__( 'Next page' ),
'&rsaquo;'
);
}
if ( $disable_last ) {
$page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&raquo;</span>';
} else {
$page_links[] = sprintf(
"<a class='last-page button' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
esc_url( add_query_arg( 'paged', $pages, $current_url ) ),
__( 'Last page' ),
'&raquo;'
);
}
$output .= "\n<span class='pagination-links'>" . join( "\n", $page_links ) . '</span>';
$output .= "</form>";
return $output;
}
/** Actions to list under the Image row
* @param $item CustomImageModel
*/
protected function getRowActions($item)
{
$settings = \wpSPIO()->settings();
$keyControl = ApiKeyController::getInstance();
$actions = UIHelper::getActions($item);
$viewAction = array('view' => array(
'function' => $item->getUrl(),
'type' => 'link',
'text' => __('View', 'shortpixel-image-optimiser'),
'display' => 'inline',
));
$rowActions = array();
$rowActions = array_merge($rowActions, $viewAction);
if (false === $settings->quotaExceeded || true === $keyControl->keyIsVerified() )
$rowActions = array_merge($rowActions,$actions);
return $rowActions;
}
// Function to sync output exactly with Media Library functions for consistency
public function doActionColumn($item)
{
?>
<div id='sp-msg-<?php echo esc_attr($item->get('id')) ?>' class='sp-column-info'><?php
$this->printItemActions($item);
echo "<div>" . UiHelper::getStatusText($item) . "</div>";
?>
</div> <!-- sp-column-info -->
<?php
}
// Use for view, also for renderItemView
public function printItemActions($item)
{
$this->view->actions = UiHelper::getActions($item); // $this->getActions($item, $itemFile);
$list_actions = UiHelper::getListActions($item);
if (count($list_actions) > 0)
$list_actions = UiHelper::renderBurgerList($list_actions, $item);
else
$list_actions = '';
if (count($this->view->actions) > 0)
{
$this->loadView('snippets/part-single-actions', false);
}
echo $list_actions;
}
public function printFilter()
{
$status = filter_input(INPUT_GET, 'custom-status', FILTER_UNSAFE_RAW );
$options = array(
'all' => __('Any ShortPixel State', 'shortpixel-image-optimiser'),
'optimized' => __('Optimized', 'shortpixel-image-optimiser'),
'unoptimized' => __('Unoptimized', 'shortpixel-image-optimiser'),
'prevented' => __('Optimization Error', 'shortpixer-image-optimiser'),
);
echo "<select name='custom-status' id='status'>\n";
foreach($options as $optname => $optval)
{
$selected = ($status == $optname) ? esc_attr('selected') : '';
echo "<option value='". esc_attr($optname) . "' $selected >" . esc_html($optval) . "</option>\n";
}
echo "</select>";
}
protected function getDisplayHeading($heading)
{
$output = '';
$defaults = array('title' => '', 'sortable' => false);
$heading = wp_parse_args($heading, $defaults);
$title = $heading['title'];
if ($heading['sortable'])
{
//$current_order = isset($_GET['order']) ? $current_order : false;
//$current_orderby = isset($_GET['orderby']) ? $current_orderby : false;
$sorturl = add_query_arg('orderby', $heading['orderby'] );
$sorted = '';
if ($this->orderby == $heading['orderby'])
{
if ($this->order == 'desc')
{
$sorturl = add_query_arg('order', 'asc', $sorturl);
$sorted = 'sorted desc';
}
else
{
$sorturl = add_query_arg('order', 'desc', $sorturl);
$sorted = 'sorted asc';
}
}
else
{
$sorturl = add_query_arg('order', 'asc', $sorturl);
}
$output = '<a href="' . esc_url($sorturl) . '"><span>' . esc_html($title) . '</span><span class="sorting-indicator '. esc_attr($sorted) . '">&nbsp;</span></a>';
}
else
{
$output = $title;
}
return $output;
}
protected function getDisplayDate($item)
{
if ($item->getMeta('tsOptimized') > 0)
$timestamp = $item->getMeta('tsOptimized');
else
$timestamp = $item->getMeta('tsAdded');
$date = new \DateTime();
$date->setTimestamp($timestamp);
$display_date = UiHelper::formatDate($date);
return $display_date;
}
}