886 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			886 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| namespace ShortPixel\Helper;
 | |
| 
 | |
| if ( ! defined( 'ABSPATH' ) ) {
 | |
|  exit; // Exit if accessed directly.
 | |
| }
 | |
| 
 | |
| use ShortPixel\Model\Image\ImageModel as ImageModel;
 | |
| use ShortPixel\Controller\ApiKeyController as ApiKeyController;
 | |
| use ShortPixel\Controller\QuotaController as QuotaController;
 | |
| use ShortPixel\Controller\OptimizeController as OptimizeController;
 | |
| 
 | |
| use ShortPixel\Model\AccessModel as AccessModel;
 | |
| 
 | |
| class UiHelper
 | |
| {
 | |
| 
 | |
| 	private static $outputMode = 'admin';
 | |
| 
 | |
| 	private static $knowledge_url = 'https://shortpixel.com/knowledge-base/search?query='; // the URL of all knowledge.
 | |
| 
 | |
| 	public static function setOutputHandler($name)
 | |
| 	{
 | |
| 		 	self::$outputMode = $name;
 | |
| 	}
 | |
| 
 | |
|   public static function renderBurgerList($actions, $imageObj)
 | |
|   {
 | |
|     $output = "";
 | |
|     $id = $imageObj->get('id');
 | |
|     $primary = isset($actions['optimizethumbs']) ? 'button-primary' : '';
 | |
| 
 | |
|     $output .= "<div class='sp-column-actions '>
 | |
|                     <div class='sp-dropdown'>
 | |
|                         <button onclick='ShortPixel.openImageMenu(event);' class='sp-dropbtn button dashicons dashicons-menu $primary' title='ShortPixel Actions'></button>";
 | |
|     $output .= "<div id='sp-dd-$id' class='sp-dropdown-content'>";
 | |
| 
 | |
|     foreach($actions as $actionName => $actionData)
 | |
|     {
 | |
|         $link = ($actionData['type'] == 'js') ? 'javascript:' . $actionData['function'] : $actionData['function'];
 | |
|         $output .= "<a href='" . $link . "' class='" . esc_attr($actionName) . "' >" . esc_html($actionData['text']) . "</a>";
 | |
| 
 | |
|     }
 | |
| 
 | |
|     $output .= "</div> <!--sp-dropdown-content--> </div> <!--sp-dropdown--> </div> <!--sp-column-actions--> ";
 | |
|     return $output;
 | |
|   }
 | |
| 
 | |
|   public static function renderSuccessText($imageObj)
 | |
|   {
 | |
|     $output = '';
 | |
|     //$percent = $imageObj->getMeta('improvement');
 | |
|     $percent = $imageObj->getImprovement();
 | |
| 
 | |
|     if($percent == 999) return ;
 | |
| 
 | |
|     if ($percent == 999 )
 | |
|       $output .= __("Reduced by X%(unknown)", 'shortpixel-image-optimiser');
 | |
| 
 | |
|     if ($percent && $percent > 0)
 | |
|     {
 | |
|       $output .= __('Reduced by','shortpixel-image-optimiser') . ' <strong>' . self::formatNumber($percent,2) . '%</strong> ';
 | |
|     }
 | |
|     if (intval($percent) < 5)
 | |
|       $output .= __('Bonus processing','shortpixel-image-optimiser');
 | |
| 
 | |
|     $type = $imageObj->getMeta('compressionType');
 | |
|     $output .= ' ('. self::compressionTypeToText($type) .')';
 | |
| 
 | |
|     $thumbs = $imageObj->get('thumbnails');
 | |
|     $thumbsDone = $retinasDone = 0;
 | |
|     $thumbsTotal = ($thumbs) ? count($thumbs) : 0;
 | |
| 
 | |
|     $retinas = $imageObj->get('retinas');
 | |
| 
 | |
|     $webpsTotal = $imageObj->count('webps');
 | |
|     $avifsTotal = $imageObj->count('avifs');
 | |
| 
 | |
|     if($retinas)
 | |
|     {
 | |
|       foreach($retinas as $retinaObj)
 | |
|       {
 | |
|          if ($retinaObj->isOptimized())
 | |
|          {
 | |
|            $retinasDone++;
 | |
|          }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     $improvements = $imageObj->getImprovements();
 | |
|     $thumbTotal = $thumbsDone = 0;
 | |
|     if ($imageObj->get('thumbnails'))
 | |
|     {
 | |
|       $thumbsTotal = count($imageObj->get('thumbnails'));  //
 | |
|       //$thumbsDone =  (isset($improvements['thumbnails'])) ? count($improvements['thumbnails']) : 0;
 | |
|       $thumbsDone = $imageObj->count('optimized', array('thumbs_only' => true));
 | |
|       $excludedThumbs = $imageObj->count('user_excluded', array('thumbs_only' => true));
 | |
|     }
 | |
| 
 | |
|     if (isset($improvements['thumbnails']))
 | |
|     {
 | |
|        $excluded = ($excludedThumbs > 0) ? sprintf(__('(%s excluded)', 'shortpixel-image-optimiser'), $excludedThumbs) : '';
 | |
| 
 | |
|        $output .= '<div class="thumbnails optimized">';
 | |
|        if ($thumbsTotal > $thumbsDone)
 | |
|          $output .= '<div class="totals">' . sprintf(__('+%s of %s thumbnails optimized','shortpixel-image-optimiser'), self::formatNumber($thumbsDone,0), self::formatNumber($thumbsTotal,0)) . ' ' .   $excluded . '</div>';
 | |
| 
 | |
|        elseif ($thumbsDone > 0)
 | |
|          $output .= '<div class="totals">' . sprintf(__('+%s thumbnails optimized','shortpixel-image-optimiser'), self::formatNumber($thumbsDone, 0)) . ' ' . $excluded . '</div>';
 | |
| 
 | |
| 			 $improvs = array();
 | |
| 
 | |
| 				 uasort($improvements['thumbnails'], function ($a, $b) {
 | |
| 					 	//return $b[0] <=> $a[0]; // @todo Efficient code to use once PHP 5 support is done.
 | |
| 						if ($a == $b) {
 | |
| 							return 0;
 | |
| 						}
 | |
| 						return ($b < $a) ? -1 : 1;
 | |
| 				 });
 | |
| 
 | |
| 			 $cutoff = false;
 | |
| 			 $thumbCount = count($improvements['thumbnails']);
 | |
| 			 if ($thumbCount > 20)
 | |
| 			 {
 | |
| 				  $improvements['thumbnails'] =  array_slice($improvements['thumbnails'], 0, 15, true);
 | |
| 					$cutoff = true;
 | |
| 			 }
 | |
| 
 | |
| 
 | |
| 			 // Quality Check
 | |
| 			 foreach($improvements['thumbnails'] as $thumbName => $thumbStat)
 | |
| 			 {
 | |
| 				  $stat = $thumbStat[0];
 | |
| 				 	if (is_numeric($stat) && $stat >= 0)
 | |
| 					{
 | |
| 						 $improvs[$thumbName] = $stat; //self::formatNumber($stat,2);
 | |
| 					}
 | |
| 			 }
 | |
| 
 | |
| 			 if (count($improvs) > 0)
 | |
| 			 {
 | |
| 		       $output .= "<div class='thumb-wrapper'>";
 | |
| 					 $lowrating = 0;
 | |
| 		       foreach($improvs as $thumbName => $stat)
 | |
| 		       {
 | |
| 						   $statText = self::formatNumber($stat, 2);
 | |
| 		           $title =  sprintf(__('%s : %s', 'shortpixel-image-optimiser'), $thumbName, $statText . '%');
 | |
| 		           $rating = ceil( round($stat) / 10);
 | |
| 							 if (0 == $rating)
 | |
| 							 {
 | |
| 								 	$lowrating++;
 | |
| 									continue;
 | |
| 							 }
 | |
| 
 | |
| 		           $blocks_on = str_repeat('<span class="point checked"> </span>', $rating);
 | |
| 		           $blocks_off = str_repeat('<span class="point"> </span>', (10- $rating));
 | |
| 
 | |
| 		           $output .= "<div class='thumb " . $thumbName . "' title='" . $title . "'>"
 | |
| 		                       . "<span class='thumb-name'>" .  $thumbName . '</span>' .
 | |
| 		                        "<span class='optimize-bar'>" . $blocks_on . $blocks_off . "</span>
 | |
| 		                      </div>";
 | |
| 		       }
 | |
| 
 | |
| 					 if ($lowrating > 0)
 | |
| 					 {
 | |
| 						 $blocks_off = str_repeat('<span class="point"> </span>', 10);
 | |
| 
 | |
| 						 $output .= "<div class='thumb'>"
 | |
| 												 . "<span class='thumb-name'>" . sprintf(__('+ %d thumbnails ', 'shortpixel-image-optimiser'), $lowrating) . '</span>' .
 | |
| 													"<span class='optimize-bar'>" . $blocks_off . "</span>
 | |
| 												</div>";
 | |
| 					 }
 | |
| 
 | |
| 					 if (true === $cutoff)
 | |
| 					 {
 | |
| 						 $output .= '<div class="thumb"><span class="cutoff">' . sprintf(__('+ %d more', 'shortpixel-image-optimiser'), ($thumbCount - 15)) . '</span></div>';
 | |
| 					 }
 | |
| 
 | |
| 
 | |
| 		       $output .=  "</div> <!-- /thumb-wrapper -->";
 | |
| 				}
 | |
| 				$output .= "</div> <!-- /thumb optimized -->";
 | |
|     }
 | |
| 
 | |
|     if ($retinasDone > 0)
 | |
|     {
 | |
|       $output .= '<div class="filetype retina">' . sprintf(__('+%s Retina images optimized','shortpixel-image-optimiser') , $retinasDone) . '</div>';
 | |
|     }
 | |
|     if ($webpsTotal > 0)
 | |
|     {
 | |
|       $output .=  '<div class="filetype webp">' . sprintf(__('+%s Webp images ','shortpixel-image-optimiser') , $webpsTotal) . '</div>';
 | |
|     }
 | |
|     if ($avifsTotal > 0)
 | |
|     {
 | |
|         $output .=  '<div class="filetype avif">' . sprintf(__('+%s Avif images ','shortpixel-image-optimiser') , $avifsTotal) . '</div>';
 | |
|     }
 | |
| 
 | |
|     if ($imageObj->isSomethingOptimized() && $imageObj->isProcessable())
 | |
|     {
 | |
|         list($urls, $optimizable) = $imageObj->getCountOptimizeData('thumbnails');
 | |
| 				list($webpUrls, $webpCount)   =  $imageObj->getCountOptimizeData('webp');
 | |
| 				list($avifUrls, $avifCount)   =  $imageObj->getCountOptimizeData('avif');
 | |
| 
 | |
| 
 | |
| 				$maxList = 10;
 | |
| 
 | |
| 			 if (count($urls) > $maxList)
 | |
| 			 {
 | |
| 				  $urls = array_slice($urls, 0, $maxList, true);
 | |
| 					$urls[] = '...';
 | |
| 			 }
 | |
| 			 if (count($webpUrls) > $maxList)
 | |
| 			 {
 | |
| 				  $webpUrls = array_slice($webpUrls, 0, $maxList, true);
 | |
| 					$webpUrls[] = '...';
 | |
| 			 }
 | |
| 			 if (count($avifUrls) > $maxList)
 | |
| 			 {
 | |
| 				  $avifUrls = array_slice($avifUrls, 0, $maxList, true);
 | |
| 					$avifUrls[] = '...';
 | |
| 			 }
 | |
| 
 | |
|         if ($optimizable > 0)
 | |
|         {
 | |
|            $output .= '<div class="thumbs-todo"><h4>' . sprintf(__('%d images to optimize', 'shortpixel-image-optimiser'), $optimizable) . '</h4>';
 | |
|              $output .= "<span>";
 | |
|                foreach($urls as $optObj)
 | |
|                {
 | |
| 								 if ($optObj === '...')
 | |
| 									$output .= $optObj;
 | |
| 								 else
 | |
|                   $output .= substr($optObj, strrpos($optObj, '/')+1) . '<br>';
 | |
|                }
 | |
|              $output .= "</span>";
 | |
|            $output .= '</div>';
 | |
|         }
 | |
| 
 | |
|         if ($webpCount > 0 )
 | |
|         {
 | |
| 
 | |
|            $output .= '<div class="thumbs-todo"><h4>' . sprintf(__('%d Webp files to create', 'shortpixel-image-optimiser'), $webpCount) . '</h4>';
 | |
|              $output .= "<span>";
 | |
|                foreach($webpUrls as $optObj)
 | |
|                {
 | |
| 								  if ($optObj === '...')
 | |
| 									 $output .= $optObj;
 | |
| 									else
 | |
|                   	$output .= self::convertImageTypeName(substr($optObj, strrpos($optObj, '/')+1), 'webp') . '<br>';
 | |
|                }
 | |
|              $output .= "</span>";
 | |
|            $output .= '</div>';
 | |
|         }
 | |
|         if ($avifCount > 0)
 | |
|         {
 | |
|             $output .= '<div class="thumbs-todo"><h4>' . sprintf(__('%d Avif files to create', 'shortpixel-image-optimiser'), $avifCount) . '</h4>';
 | |
|               $output .= "<span>";
 | |
|                 foreach($avifUrls as $optObj)
 | |
|                 {
 | |
|                    $output .= self::convertImageTypeName(substr($optObj, strrpos($optObj, '/')+1), 'avif') . '<br>';
 | |
|                 }
 | |
|               $output .= "</span>";
 | |
|             $output .= '</div>';
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return $output;
 | |
| 
 | |
|   }
 | |
| 
 | |
|   public static function compressionTypeToText($type)
 | |
|   {
 | |
|      if ($type == ImageModel::COMPRESSION_LOSSLESS )
 | |
|        return __('Lossless', 'shortpixel-image-optimiser');
 | |
| 
 | |
|      if ($type == ImageModel::COMPRESSION_LOSSY )
 | |
|          return __('Lossy', 'shortpixel-image-optimiser');
 | |
| 
 | |
|      if ($type == ImageModel::COMPRESSION_GLOSSY )
 | |
|          return __('Glossy', 'shortpixel-image-optimiser');
 | |
| 
 | |
|       return $type;
 | |
|   }
 | |
| 
 | |
|   public static function getListActions($mediaItem)
 | |
|   {
 | |
|       $list_actions = array();
 | |
|       $id = $mediaItem->get('id');
 | |
| 
 | |
| 		  $keyControl = ApiKeyController::getInstance();
 | |
| 			if (! $keyControl->keyIsVerified())
 | |
| 			{
 | |
| 				return array(); // nothing
 | |
| 			}
 | |
| 
 | |
|       $quotaControl = QuotaController::getInstance();
 | |
| 
 | |
| 			$access = AccessModel::getInstance();
 | |
| 			if (! $access->imageIsEditable($mediaItem))
 | |
| 			{
 | |
| 				 return array();
 | |
| 			}
 | |
| 
 | |
| 			if ($id === 0)
 | |
| 				return array();
 | |
| 
 | |
|       if ($mediaItem->isSomethingOptimized() )
 | |
|       {
 | |
| 						list($u, $optimizable) = $mediaItem->getCountOptimizeData('thumbnails');
 | |
| 						list($u, $optimizableWebp)   =  $mediaItem->getCountOptimizeData('webp');
 | |
| 						list($u, $optimizableAvif)   =  $mediaItem->getCountOptimizeData('avif');
 | |
| 
 | |
|            if ($mediaItem->isProcessable() && ! $mediaItem->isOptimizePrevented())
 | |
|            {
 | |
|              $action = self::getAction('optimizethumbs', $id);
 | |
|              if ($optimizable > 0)
 | |
|              {
 | |
| 							 $total = $optimizable + $optimizableWebp + $optimizableAvif;
 | |
| 							 if ($optimizableWebp > 0 || $optimizableAvif > 0)
 | |
| 							 	   $itemText = __('items', 'shortpixel-image-optimiser');
 | |
| 								else {
 | |
| 									 $itemText = __('thumbnails', 'shortpixel-image-optimiser');
 | |
| 								}
 | |
|                $action['text']  = sprintf(__('Optimize %s  %s','shortpixel-image-optimiser'),$total, $itemText);
 | |
|              }
 | |
|              else
 | |
|              {
 | |
|                  if ($optimizableWebp > 0 && $optimizableAvif > 0)
 | |
|                    $text  = sprintf(__('Optimize %s webps and %s avif','shortpixel-image-optimiser'),$optimizableWebp, $optimizableAvif);
 | |
|                  elseif ($optimizableWebp > 0)
 | |
|                    $text  = sprintf(__('Optimize %s webps','shortpixel-image-optimiser'),$optimizableWebp);
 | |
|                  else
 | |
|                     $text  = sprintf(__('Optimize %s avifs','shortpixel-image-optimiser'),$optimizableAvif);
 | |
|                  $action['text'] = $text;
 | |
|              }
 | |
|              $list_actions['optimizethumbs'] = $action;
 | |
|           }
 | |
| 
 | |
| 
 | |
|           if ($mediaItem->isRestorable())
 | |
|           {
 | |
|             if ($mediaItem->get('type') == 'custom')
 | |
|             {
 | |
|                 if ($mediaItem->getExtension() !== 'pdf') // no support for this
 | |
|                   $list_actions['comparer'] = self::getAction('compare-custom', $id);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 // PDF without thumbnail can't be compared.
 | |
|                 $showCompare = true;
 | |
|                 if ($mediaItem->getExtension() == 'pdf')
 | |
|                 {
 | |
|   				            if (! $mediaItem->getThumbnail('full'))
 | |
|   					               $showCompare = false;
 | |
|   				            elseif(! $mediaItem->getThumbnail('full')->hasBackup())
 | |
|   					             $showCompare = false;
 | |
|   			         }
 | |
| 
 | |
|   				       if ($showCompare)
 | |
|                    $list_actions['comparer'] = self::getAction('compare', $id);
 | |
|             }
 | |
| 			 			if ($mediaItem->isRestorable())
 | |
| 						{
 | |
| 
 | |
| 							 $compressionType = $mediaItem->getMeta('compressionType');
 | |
| 		           switch($compressionType)
 | |
| 		           {
 | |
| 		               case ImageModel::COMPRESSION_LOSSLESS:
 | |
| 		                 $list_actions['reoptimize-lossy'] = self::getAction('reoptimize-lossy', $id);
 | |
| 		                 $list_actions['reoptimize-glossy'] = self::getAction('reoptimize-glossy', $id);
 | |
| 
 | |
| 		               break;
 | |
| 		               case ImageModel::COMPRESSION_LOSSY:
 | |
| 		                 $list_actions['reoptimize-lossless'] = self::getAction('reoptimize-lossless', $id);
 | |
| 		                 $list_actions['reoptimize-glossy'] = self::getAction('reoptimize-glossy', $id);
 | |
| 
 | |
| 		               break;
 | |
| 		               case ImageModel::COMPRESSION_GLOSSY:
 | |
| 		                 $list_actions['reoptimize-lossy'] = self::getAction('reoptimize-lossy', $id);
 | |
| 		                 $list_actions['reoptimize-lossless'] = self::getAction('reoptimize-lossless', $id);
 | |
| 		               break;
 | |
| 		           }
 | |
| 
 | |
| 							 if ($mediaItem->get('type') === 'media')
 | |
| 							 {
 | |
| 							 		$list_actions['reoptimize-smartcrop'] = self::getAction('reoptimize-smartcrop', $id, array('compressionType' => $compressionType));
 | |
| 							 		$list_actions['reoptimize-smartcropless'] = self::getAction('reoptimize-smartcropless', $id, array('compressionType' => $compressionType));
 | |
| 								}
 | |
| 		          		$list_actions['restore'] = self::getAction('restore', $id);
 | |
| 							} // isRestorable
 | |
| 						else
 | |
| 						{
 | |
| 
 | |
| 						}
 | |
|         } // hasBackup
 | |
| 
 | |
| 				if (\wpSPIO()->env()->is_debug && $mediaItem->get('type') == 'media')
 | |
| 				{
 | |
| 					 $list_actions['redo_legacy'] = self::getAction('redo_legacy', $id);
 | |
| 				}
 | |
|       } //isOptimized
 | |
| 
 | |
|       if(! $quotaControl->hasQuota())
 | |
|       {
 | |
|          $remove = array('reoptimize-lossy' => '', 'reoptimize-glossy' => '', 'reoptimize-lossless' => '', 'optimizethumbs' => '');
 | |
|          $list_actions = array_diff_key($list_actions, $remove);
 | |
| 
 | |
|       }
 | |
|       return $list_actions;
 | |
|   }
 | |
| 
 | |
|   public static function getActions($mediaItem)
 | |
|   {
 | |
|     $actions = array();
 | |
|     $id = $mediaItem->get('id');
 | |
|     $quotaControl = QuotaController::getInstance();
 | |
| 		$optimizeController = new OptimizeController();
 | |
| 
 | |
| 		$keyControl = ApiKeyController::getInstance();
 | |
| 		if (! $keyControl->keyIsVerified())
 | |
| 		{
 | |
| 			return array(); // nothing
 | |
| 		}
 | |
| 
 | |
| 		$access = AccessModel::getInstance();
 | |
| 		if (! $access->imageIsEditable($mediaItem))
 | |
| 		{
 | |
| 			 return array();
 | |
| 		}
 | |
| 
 | |
| 		if ($id === 0)
 | |
| 			return array();
 | |
| 
 | |
|     if(! $quotaControl->hasQuota())
 | |
|     {
 | |
|        $actions['extendquota'] = self::getAction('extendquota', $id);
 | |
|        $actions['checkquota'] = self::getAction('checkquota', $id);
 | |
|     }
 | |
|     elseif($mediaItem->isProcessable() && ! $mediaItem->isSomethingOptimized() && ! $mediaItem->isOptimizePrevented() && ! $optimizeController->isItemInQueue($mediaItem))
 | |
|     {
 | |
|        $actions['optimize'] = self::getAction('optimize', $id);
 | |
|        $actions['markCompleted']  = self::getAction('markCompleted', $id);
 | |
|     }
 | |
|     elseif ($mediaItem->isUserExcluded() && false === $mediaItem->isSomethingOptimized())
 | |
|     {
 | |
|       $actions['optimize'] = self::getAction('forceOptimize', $id);
 | |
|     }
 | |
| 
 | |
| 
 | |
|     return $actions;
 | |
|   }
 | |
| 
 | |
|   public static function getStatusText($mediaItem)
 | |
|   {
 | |
|     $keyControl = ApiKeyController::getInstance();
 | |
|     $quotaControl = QuotaController::getInstance();
 | |
| 		$optimizeController = new OptimizeController();
 | |
|     $settings = \wpSPIO()->settings();
 | |
| 
 | |
|     $text = '';
 | |
| 
 | |
|     if (! $keyControl->keyIsVerified())
 | |
|     {
 | |
|       $text = __('Invalid API Key. <a href="options-general.php?page=wp-shortpixel-settings">Check your Settings</a>','shortpixel-image-optimiser');
 | |
|     }
 | |
| 		// This basically happens when a NextGen gallery is not added to Custom Media.
 | |
| 		elseif ($mediaItem->get('id') === 0)
 | |
| 		{
 | |
| 			 if ($mediaItem->isProcessable(true) === false)
 | |
| 			 {
 | |
| 				 $text = __('Not Processable: ','shortpixel_image_optimiser');
 | |
| 				 $text  .= $mediaItem->getProcessableReason();
 | |
| 			 }
 | |
| 			 else {
 | |
|          if (\wpSPIO()->env()->has_nextgen && false == $settings->includeNextGen)
 | |
|          {
 | |
|            $text = __('This image was not found in our database. Enable "Optimize nextgen galleries" in the settings, or add this folder manually. ', 'shortpixel-image-optimiser');
 | |
|          }
 | |
|          else {
 | |
|            $text = __('This image was not found in our database. Refresh folders, or add this gallery', 'shortpixel-image-optimiser');
 | |
|          }
 | |
| 			 }
 | |
| 		}
 | |
|     elseif ($mediaItem->isSomethingOptimized())
 | |
|     {
 | |
|        $text = UiHelper::renderSuccessText($mediaItem);
 | |
|     }
 | |
|     elseif (false === $mediaItem->isProcessable()  )
 | |
|     {
 | |
|        $text = __('Not Processable: ','shortpixel_image_optimiser');
 | |
|        $text  .= $mediaItem->getProcessableReason();
 | |
|     }
 | |
|     elseif (! $mediaItem->exists())
 | |
|     {
 | |
|        $text = __('File does not exist.','shortpixel-image-optimiser');
 | |
|     }
 | |
|     elseif ($mediaItem->getMeta('status') < 0)
 | |
|     {
 | |
|       $text = $mediaItem->getMeta('errorMessage');
 | |
|     }
 | |
| 		elseif( $optimizeController->isItemInQueue($mediaItem) === true)
 | |
| 		{
 | |
| 			 $text = '<p>' . __('This item is waiting to be processed', 'shortpixel-image-optimiser') . '</p>';
 | |
| 			 $action = self::getAction('cancelOptimize', $mediaItem->get('id'));
 | |
| 
 | |
| 			 $text .= '<p><a href="javascript:' . $action['function'] . '">' . $action['text'] . '</a></p>';
 | |
| 		}
 | |
| 
 | |
|     if ($mediaItem->isOptimizePrevented() !== false)
 | |
|     {
 | |
|           $retry = self::getAction('retry', $mediaItem->get('id'));
 | |
|           $unmark = self::getAction('unMarkCompleted', $mediaItem->get('id'));
 | |
| 					$redo_legacy = false;
 | |
| 
 | |
| 					if ($mediaItem->get('type') == 'media')
 | |
| 					{
 | |
| 	 					$was_converted = get_post_meta($mediaItem->get('id'), '_shortpixel_was_converted', true);
 | |
| 						$updateTs = 1656892800; // July 4th 2022 - 00:00 GMT
 | |
| 
 | |
| 						if ($was_converted < $updateTs)
 | |
| 						{
 | |
| 							$meta = $mediaItem->getWPMetaData();
 | |
| 							if (is_array($meta) && isset($meta['ShortPixel']))
 | |
| 							{
 | |
| 								$redo_legacy = self::getAction('redo_legacy', $mediaItem->get('id'));
 | |
| 							}
 | |
| 						}
 | |
| 					}
 | |
| 
 | |
|           $status = $mediaItem->getMeta('status');
 | |
|           $text = ''; // reset text
 | |
| 
 | |
|           if (ImageModel::FILE_STATUS_MARKED_DONE == $status)
 | |
|           {
 | |
|             $text .= "<div class='shortpixel-image-notice'>" . esc_html($mediaItem->getReason('processable'));
 | |
| 
 | |
|             $text .= "<p class='shortpixel-error-reset'>" . sprintf(__('%s Click to unmark as completed %s', 'shortpixel-image-optimiser'), '<a href="javascript:' . $unmark['function'] . '">', '</a>') . '</p>';
 | |
|             $text .= '</div>';
 | |
|           }
 | |
|           else {
 | |
|             $text .= "<div class='shortpixel-image-error'>" . esc_html($mediaItem->getReason('processable'));
 | |
|             $text .= "<span class='shortpixel-error-reset'>" . sprintf(__('After you have fixed this issue, you can %s click here to retry %s', 'shortpixel-image-optimiser'), '<a href="javascript:' . $retry['function'] . '">', '</a>') . '</span>';
 | |
|             $text .= '</div>';
 | |
|           }
 | |
| 
 | |
| 
 | |
| 
 | |
| 					if ($redo_legacy !== false)
 | |
| 					{
 | |
| 						$text .= "<div class='shortpixel-image-error'><span class='shortpixel-error-reset'>";
 | |
| 
 | |
| 						$text .= sprintf(esc_html__('It seems you have older converted legacy data, which might cause this issue. You can try to %s %s %s . If nothing changes, this is not the cause. ','shortpixel-image-optimiser'), '<a href="javascript:' . $redo_legacy['function'] . '">', $redo_legacy['text'], '</a>');
 | |
| 						$text .= "</span></div>";
 | |
| 					}
 | |
| 
 | |
|       }
 | |
| 
 | |
|     return $text;
 | |
|   }
 | |
| 
 | |
|   // Defines all possible actions in the Ui
 | |
|   public static function getAction($name, $id, $args = array())
 | |
|   {
 | |
|      $action = array('function' => '', 'type' => '', 'text' => '', 'display' => '');
 | |
|      $keyControl = ApiKeyController::getInstance();
 | |
| 
 | |
| 		 $compressionType = isset($args['compressionType']) ? $args['compressionType'] : null;
 | |
| 
 | |
|     switch($name)
 | |
|     {
 | |
|       case 'optimize':
 | |
|          $action['function'] = 'window.ShortPixelProcessor.screen.Optimize(' . $id . ')';
 | |
|          $action['type']  = 'js';
 | |
|          $action['text'] = __('Optimize Now', 'shortpixel-image-optimiser');
 | |
|          $action['display'] = 'button';
 | |
|       break;
 | |
|       case 'forceOptimize':
 | |
|         $action['function'] = 'window.ShortPixelProcessor.screen.Optimize(' . $id . ', true)';
 | |
|         $action['type']  = 'js';
 | |
|         $action['text'] = __('Override exclusions and optimize now', 'shortpixel-image-optimiser');
 | |
|         $action['display'] = 'button';
 | |
|       break;
 | |
| 			case 'cancelOptimize':
 | |
| 				 $action['function'] = 'window.ShortPixelProcessor.screen.CancelOptimizeItem(' . $id . ')';
 | |
| 				 $action['type']  = 'js';
 | |
| 				 $action['text'] = __('Cancel item optimization', 'shortpixel-image-optimiser');
 | |
| 				 $action['display'] = 'button';
 | |
| 			break;
 | |
|       case 'markCompleted':
 | |
|           $action['function'] = 'window.ShortPixelProcessor.screen.MarkCompleted(' . $id . ')';
 | |
|           $action['type']  = 'js';
 | |
|           $action['text'] = __('Mark as Completed', 'shortpixel-image-optimiser');
 | |
|           $action['display'] = 'button-secondary';
 | |
|           $action['layout'] = 'paragraph';
 | |
|           $action['title'] = __('This will cause the plugin to skip this image for optimization', 'shortpixel-image-optimiser');
 | |
|       break;
 | |
|       case 'unMarkCompleted':
 | |
|           $action['function'] = 'window.ShortPixelProcessor.screen.UnMarkCompleted(' . $id . ')';
 | |
|           $action['type']  = 'js';
 | |
|           $action['text'] = __('Click to unmark this item as done', 'shortpixel-image-optimiser');
 | |
|           $action['display'] = 'js';
 | |
| 
 | |
|       break;
 | |
|       case 'optimizethumbs':
 | |
|           $action['function'] = 'window.ShortPixelProcessor.screen.Optimize(' . $id . ');';
 | |
|           $action['type'] = 'js';
 | |
|           $action['text']  = '';
 | |
|           $action['display'] = 'inline';
 | |
|       break;
 | |
| 
 | |
|       case 'retry':
 | |
|          $action['function'] = 'window.ShortPixelProcessor.screen.Optimize(' . $id . ');';
 | |
|          $action['type']  = 'js';
 | |
|          $action['text'] = __('Retry', 'shortpixel-image-optimiser') ;
 | |
|          $action['display'] = 'button';
 | |
|      break;
 | |
| 		 case 'redo_legacy':
 | |
| 		 			$action['function'] = 'window.ShortPixelProcessor.screen.RedoLegacy(' . $id . ');';
 | |
| 		 			$action['type']  = 'js';
 | |
| 		 			$action['text'] = __('Redo Conversion', 'shortpixel-image-optimiser') ;
 | |
| 		 			$action['display'] = 'button';
 | |
| 		 break;
 | |
| 
 | |
|      case 'restore':
 | |
|          $action['function'] = 'window.ShortPixelProcessor.screen.RestoreItem(' . $id . ');';
 | |
|          $action['type'] = 'js';
 | |
|          $action['text'] = __('Restore backup','shortpixel-image-optimiser');
 | |
|          $action['display'] = 'inline';
 | |
|      break;
 | |
| 
 | |
|      case 'compare':
 | |
|         $action['function'] = 'ShortPixel.loadComparer(' . $id . ')';
 | |
|         $action['type'] = 'js';
 | |
|         $action['text'] = __('Compare', 'shortpixel-image-optimiser');
 | |
|         $action['display'] = 'inline';
 | |
|      break;
 | |
|      case 'compare-custom':
 | |
|         $action['function'] = 'ShortPixel.loadComparer(' . $id . ',"custom")';
 | |
|         $action['type'] = 'js';
 | |
|         $action['text'] = __('Compare', 'shortpixel-image-optimiser');
 | |
|         $action['display'] = 'inline';
 | |
|      break;
 | |
|      case 'reoptimize-glossy':
 | |
|         $action['function'] = 'window.ShortPixelProcessor.screen.ReOptimize(' . $id . ',' . ImageModel::COMPRESSION_GLOSSY . ')';
 | |
|         $action['type'] = 'js';
 | |
|         $action['text'] = __('Re-optimize Glossy','shortpixel-image-optimiser') ;
 | |
|         $action['display'] = 'inline';
 | |
|      break;
 | |
|      case 'reoptimize-lossy':
 | |
|         $action['function'] = 'window.ShortPixelProcessor.screen.ReOptimize(' . $id . ',' . ImageModel::COMPRESSION_LOSSY . ')';
 | |
|         $action['type'] = 'js';
 | |
|         $action['text'] = __('Re-optimize Lossy','shortpixel-image-optimiser');
 | |
|         $action['display'] = 'inline';
 | |
|      break;
 | |
| 
 | |
|      case 'reoptimize-lossless':
 | |
|         $action['function'] = 'window.ShortPixelProcessor.screen.ReOptimize(' . $id . ',' . ImageModel::COMPRESSION_LOSSLESS . ')';
 | |
|         $action['type'] = 'js';
 | |
|         $action['text'] = __('Re-optimize Lossless','shortpixel-image-optimiser');
 | |
|         $action['display'] = 'inline';
 | |
|      break;
 | |
| 		 case 'reoptimize-smartcrop':
 | |
|         $action['function'] = 'window.ShortPixelProcessor.screen.ReOptimize(' . $id . ',' . $compressionType . ',' . ImageModel::ACTION_SMARTCROP . ')';
 | |
|         $action['type'] = 'js';
 | |
|         $action['text'] = __('Re-optimize with SmartCrop','shortpixel-image-optimiser');
 | |
|         $action['display'] = 'inline';
 | |
|      break;
 | |
| 		 case 'reoptimize-smartcropless':
 | |
|         $action['function'] = 'window.ShortPixelProcessor.screen.ReOptimize(' . $id . ',' . $compressionType . ',' . ImageModel::ACTION_SMARTCROPLESS . ')';
 | |
|         $action['type'] = 'js';
 | |
|         $action['text'] = __('Re-optimize without SmartCrop','shortpixel-image-optimiser');
 | |
|         $action['display'] = 'inline';
 | |
|      break;
 | |
|      case 'extendquota':
 | |
|         $action['function'] = 'https://shortpixel.com/login/'. $keyControl->getKeyForDisplay();
 | |
|         $action['type'] = 'button';
 | |
|         $action['text'] = __('Extend Quota','shortpixel-image-optimiser');
 | |
|         $action['display'] = 'button';
 | |
|      break;
 | |
|      case 'checkquota':
 | |
|         $action['function'] = 'ShortPixel.checkQuota()';
 | |
|         $action['type'] = 'js';
 | |
|         $action['display'] = 'button';
 | |
|         $action['text'] = __('Check  Quota','shortpixel-image-optimiser');
 | |
|      break;
 | |
|    }
 | |
| 
 | |
|    return $action;
 | |
|   }
 | |
| 
 | |
| 	public static function getConvertErrorReason($error)
 | |
| 	{
 | |
| 		switch($error)
 | |
| 		{
 | |
| 			case -1: //ERROR_LIBRARY:
 | |
| 				$reason = __('PNG Library is not present or not working', 'shortpixel-image-optimiser');
 | |
| 			break;
 | |
| 			case -2: //ERROR_PATHFAIL:
 | |
| 				$reason = __('Could not create path', 'shortpixel-image-optimiser');
 | |
| 			break;
 | |
| 			case -3: //ERROR_RESULTLARGER:
 | |
| 				$reason  = __('Result file is larger','shortpixel-image-optimiser');
 | |
| 			break;
 | |
| 			case -4: // ERROR_WRITEERROR
 | |
| 				$reason = __('Could not write result file', 'shortpixel-image-optimiser');
 | |
| 			break;
 | |
| 			case -5: // ERROR_BACKUPERROR
 | |
| 				$reason = __('Could not create backup', 'shortpixel-image-optimiser');
 | |
| 			break;
 | |
| 			case -6:  // ERROR_TRANSPARENT
 | |
| 				$reason = __('Image is transparent', 'shortpixel-image-optimiser');
 | |
| 			break;
 | |
| 			default:
 | |
| 				$reason = sprintf(__('Unknown error %s', 'shortpixel-image-optimiser'), $error);
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		$message = sprintf(__('Not converted: %s ', 'shortpixel-image-optimiser'), $reason);
 | |
| 		return $message;
 | |
| 	}
 | |
| 
 | |
| 	public static function getKBSearchLink($subject)
 | |
| 	{
 | |
| 			return esc_url(self::$knowledge_url . sanitize_text_field($subject));
 | |
| 	}
 | |
| 
 | |
| 	// @param MediaLibraryModel Object $imageItem
 | |
| 	// @param String $size  Preferred size
 | |
| 	// @param String Preload The preloader tries to guess what the preview might be for a more smooth process. Ignore optimize / backup
 | |
| 	public static function findBestPreview($imageItem, $size = 800, $preload = false)
 | |
| 	{
 | |
| 		 	$closestObj = $imageItem;
 | |
| 
 | |
| 			// set the standard.
 | |
| 			if ($imageItem->getExtension() == 'pdf') // try not to select non-showable extensions.
 | |
| 				$bestdiff = 0;
 | |
| 			else
 | |
| 				$bestdiff = abs($imageItem->get('width') - $size);
 | |
| 
 | |
| 			$thumbnails = $imageItem->get('thumbnails');
 | |
| 
 | |
| 			if (! is_array($thumbnails))
 | |
| 			{
 | |
| 				 return $closestObj; // nothing more to do.
 | |
| 			}
 | |
| 
 | |
| 			foreach($thumbnails as $thumbnail)
 | |
| 			{
 | |
| 				 if (! $preload && (! $thumbnail->isOptimized() || ! $thumbnail->hasBackup()))
 | |
| 				 	continue;
 | |
| 
 | |
| 					$diff = abs($thumbnail->get('width') - $size);
 | |
| 					if ($diff < $bestdiff)
 | |
| 					{
 | |
| 						 $closestObj = $thumbnail;
 | |
| 						 $bestdiff = $diff;
 | |
| 					}
 | |
| 			}
 | |
| 
 | |
| 			return $closestObj;
 | |
| 	}
 | |
| 
 | |
|   public static function formatTS($ts)
 | |
|   {
 | |
|       //$format = get_option('date_format') .' @ ' . date_i18n(get_option('time_format');
 | |
| 			if (function_exists('wp_date'))
 | |
| 			{
 | |
|       	$date = wp_date(get_option('date_format'), $ts);
 | |
| 				$date .= ' @ ' . wp_date(get_option('time_format'), $ts);
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
|       	$date = date_i18n(get_option('date_format'), $ts);
 | |
| 				$date .= ' @ ' . date_i18n(get_option('time_format'), $ts);
 | |
| 
 | |
| 			}
 | |
|       return $date;
 | |
|   }
 | |
| 
 | |
|   public static function formatBytes($bytes, $precision = 2) {
 | |
|       $units = array('B', 'KB', 'MB', 'GB', 'TB');
 | |
| 
 | |
|       $bytes = max($bytes, 0);
 | |
|       $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
 | |
|       $pow = min($pow, count($units) - 1);
 | |
| 
 | |
|       $bytes /= pow(1024, $pow);
 | |
| 
 | |
|       return number_format_i18n(round($bytes, $precision), $precision) . ' ' . $units[$pow];
 | |
|   }
 | |
| 
 | |
| 	public static function formatNumber($number, $precision = 2)
 | |
| 	{
 | |
| 			global $wp_locale;
 | |
| 			$decimalpoint = isset($wp_locale->number_format['decimal_point']) ? $wp_locale->number_format['decimal_point'] : false;
 | |
| 			$number =  number_format_i18n( (float) $number, $precision);
 | |
| 
 | |
|  			$hasDecimal = (strpos($number, $decimalpoint) === false) ? false : true;
 | |
| 
 | |
| 			// Don't show trailing zeroes if number is a whole unbroken number. -> string comparison because number_format_i18n returns string.
 | |
| 			if ($decimalpoint !== false && $hasDecimal && substr($number, strpos($number, $decimalpoint) + 1) === '00')
 | |
| 			{
 | |
| 				 $number = substr($number, 0, strpos($number, $decimalpoint));
 | |
| 			}
 | |
| 			// Some locale's have no-breaking-space as thousands separator. This doesn't work well in JS / Cron Shell so replace with space.
 | |
| 			$number = str_replace(' ', ' ', $number);
 | |
| 		  return $number;
 | |
| 	}
 | |
| 
 | |
| 	public static function formatDate( $date ) {
 | |
| 
 | |
| 	if ( '0000-00-00 00:00:00' === $date->format('Y-m-d ') ) {
 | |
| 			$h_time = '';
 | |
| 	} else {
 | |
| 			$time   = $date->format('U'); //get_post_time( 'G', true, $post, false );
 | |
| 			if ( ( abs( $t_diff = time() - $time ) ) < DAY_IN_SECONDS ) {
 | |
| 					if ( $t_diff < 0 ) {
 | |
| 							$h_time = sprintf( __( '%s from now' ), human_time_diff( $time ) );
 | |
| 					} else {
 | |
| 							$h_time = sprintf( __( '%s ago' ), human_time_diff( $time ) );
 | |
| 					}
 | |
| 			} else {
 | |
| 					$h_time = $date->format( 'Y/m/d' );
 | |
| 			}
 | |
| 	}
 | |
| 
 | |
| 	return $h_time;
 | |
| }
 | |
| 
 | |
| 	protected static function convertImageTypeName($name, $type)
 | |
| 	{
 | |
| 		if ($type == 'webp')
 | |
| 		{
 | |
| 			$is_double = \wpSPIO()->env()->useDoubleWebpExtension();
 | |
| 		}
 | |
| 		if ($type == 'avif')
 | |
| 		{
 | |
| 			$is_double = \wpSPIO()->env()->useDoubleAvifExtension();
 | |
| 		}
 | |
| 
 | |
| 		if ($is_double)
 | |
| 		{
 | |
| 			 return $name . '.' . $type;
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			 return substr($name, 0, strrpos($name, '.')) . '.' . $type;
 | |
| 		}
 | |
| 
 | |
| 	}
 | |
| 
 | |
|   /* Strings on settings page that need to be available for both JS and PHP  */
 | |
|   public static function getSettingsStrings($name = false)
 | |
|   {
 | |
| 
 | |
|       $strings = array(
 | |
|       );
 | |
| 
 | |
|       $exclusion_types = array(
 | |
|           'name' => __('Name', 'shortpixel-image-optimiser'),
 | |
|           'path' => __('Path', 'shortpixel-image-optimiser'),
 | |
|           'size' => __('Size', 'shortpixel-image-optimiser'),
 | |
|       );
 | |
| 
 | |
|       $exclusion_apply = array(
 | |
|            'all' => __('All', 'shortpixel-image-optimiser'),
 | |
|            'only-thumbs' => __('Only Thumbnails', 'shortpixel-image-optimiser'),
 | |
|            'only-custom' =>  __('Only Custom Media Images', 'shortpixel-image-optimiser'),
 | |
|            'selected-thumbs' => __('Selected Images', 'shortpixel-image-optimiser'),
 | |
|       );
 | |
| 
 | |
|       $strings['exclusion_types'] = $exclusion_types;
 | |
|       $strings['exclusion_apply'] = $exclusion_apply;
 | |
| 
 | |
|       if ($name !== false && isset($strings[$name]))
 | |
|       {
 | |
|          return $strings[$name];
 | |
|       }
 | |
| 
 | |
|       return $strings;
 | |
|   }
 | |
| 
 | |
| 
 | |
| 
 | |
| } // class
 |