From e689285a9c1846a3eaca657af1be30caa40d3530 Mon Sep 17 00:00:00 2001 From: Bas Schuiling Date: Mon, 19 Feb 2024 13:23:46 +0200 Subject: [PATCH 01/21] - Restructed part of actions into proper classes - Implemented SPIO Log module - Part to PSR/4 / Autoloading - Removed languages - get translations from WP.org - Updated script.js for outdate Jquery JSON Parse - Changes to UI/Interface --- build/shortpixel/PackageLoader.php | 94 ++ build/shortpixel/autoload.php | 5 + build/shortpixel/composer.json | 1 + build/shortpixel/filesystem/composer.json | 18 + .../src/Controller/FileSystemController.php | 329 +++++++ .../src/Model/File/DirectoryModel.php | 590 +++++++++++++ .../filesystem/src/Model/File/FileModel.php | 823 ++++++++++++++++++ build/shortpixel/log/composer.json | 18 + build/shortpixel/log/src/DebugItem.php | 153 ++++ build/shortpixel/log/src/ShortPixelLogger.php | 463 ++++++++++ build/shortpixel/log/src/view-debug-box.php | 57 ++ build/shortpixel/notices/composer.json | 31 + .../notices/src/NoticeController.php | 372 ++++++++ build/shortpixel/notices/src/NoticeModel.php | 366 ++++++++ build/shortpixel/notices/src/css/notices.css | 65 ++ .../notices/src/css/notices.css.map | 1 + build/shortpixel/notices/src/css/notices.scss | 83 ++ classes/Controller/AdminController.php | 231 +++++ classes/Controller/AjaxController.php | 231 +++++ classes/Controller/CronController.php | 160 ++++ classes/Controller/ProcessController.php | 146 ++++ classes/Controller/WpCliController.php | 33 + classes/Helper/BuildAutoLoader.php | 47 + classes/Plugin.php | 72 ++ classes/plugin.json | 1 + classes/resmushit.class.php | 150 +++- classes/resmushitUI.class.php | 123 +-- composer.json | 30 + js/script.js | 82 +- languages/resmushit-image-optimizer-fr_FR.mo | Bin 7182 -> 0 bytes languages/resmushit-image-optimizer-fr_FR.po | 327 ------- languages/resmushit-image-optimizer-it_IT.mo | Bin 3927 -> 0 bytes languages/resmushit-image-optimizer-it_IT.po | 185 ---- languages/resmushit-image-optimizer-sk_SK.mo | Bin 4092 -> 0 bytes languages/resmushit-image-optimizer-sk_SK.po | 181 ---- languages/resmushit-image-optimizer.pot | 305 ------- resmushit.admin.php | 190 ---- resmushit.inc.php | 167 +--- resmushit.php | 577 ++---------- 39 files changed, 4719 insertions(+), 1988 deletions(-) create mode 100644 build/shortpixel/PackageLoader.php create mode 100644 build/shortpixel/autoload.php create mode 100644 build/shortpixel/composer.json create mode 100644 build/shortpixel/filesystem/composer.json create mode 100644 build/shortpixel/filesystem/src/Controller/FileSystemController.php create mode 100644 build/shortpixel/filesystem/src/Model/File/DirectoryModel.php create mode 100644 build/shortpixel/filesystem/src/Model/File/FileModel.php create mode 100644 build/shortpixel/log/composer.json create mode 100644 build/shortpixel/log/src/DebugItem.php create mode 100644 build/shortpixel/log/src/ShortPixelLogger.php create mode 100644 build/shortpixel/log/src/view-debug-box.php create mode 100644 build/shortpixel/notices/composer.json create mode 100644 build/shortpixel/notices/src/NoticeController.php create mode 100644 build/shortpixel/notices/src/NoticeModel.php create mode 100644 build/shortpixel/notices/src/css/notices.css create mode 100644 build/shortpixel/notices/src/css/notices.css.map create mode 100644 build/shortpixel/notices/src/css/notices.scss create mode 100644 classes/Controller/AdminController.php create mode 100644 classes/Controller/AjaxController.php create mode 100644 classes/Controller/CronController.php create mode 100644 classes/Controller/ProcessController.php create mode 100644 classes/Controller/WpCliController.php create mode 100644 classes/Helper/BuildAutoLoader.php create mode 100644 classes/Plugin.php create mode 100644 classes/plugin.json create mode 100644 composer.json delete mode 100644 languages/resmushit-image-optimizer-fr_FR.mo delete mode 100644 languages/resmushit-image-optimizer-fr_FR.po delete mode 100644 languages/resmushit-image-optimizer-it_IT.mo delete mode 100644 languages/resmushit-image-optimizer-it_IT.po delete mode 100644 languages/resmushit-image-optimizer-sk_SK.mo delete mode 100644 languages/resmushit-image-optimizer-sk_SK.po delete mode 100644 languages/resmushit-image-optimizer.pot diff --git a/build/shortpixel/PackageLoader.php b/build/shortpixel/PackageLoader.php new file mode 100644 index 0000000..a016542 --- /dev/null +++ b/build/shortpixel/PackageLoader.php @@ -0,0 +1,94 @@ +composerFile = json_decode(file_get_contents($filePath),1); + } + + public function getComposerFile($filePath = false ) + { + if (! $this->composerFile) + $this->composerFile = json_decode(file_get_contents($this->dir."/composer.json"), 1); + + return $this->composerFile; + } + + public function load($dir, $prepend = false) + { + $this->dir = $dir; + $composer = $this->getComposerFile(); + + + if(isset($composer["autoload"]["psr-4"])){ + $this->loadPSR4($composer['autoload']['psr-4'], $prepend); + } + if(isset($composer["autoload"]["psr-0"])){ + $this->loadPSR0($composer['autoload']['psr-0']); + } + if(isset($composer["autoload"]["files"])){ + $this->loadFiles($composer["autoload"]["files"]); + } + } + + public function loadFiles($files){ + foreach($files as $file){ + $fullpath = $this->dir."/".$file; + if(file_exists($fullpath)){ + include_once($fullpath); + } + } + } + + public function loadPSR4($namespaces, $prepend) + { + $this->loadPSR($namespaces, true, $prepend); + } + + public function loadPSR0($namespaces) + { + $this->loadPSR($namespaces, false); + } + + public function loadPSR($namespaces, $psr4, $prepend = false) + { + $dir = $this->dir; + // Foreach namespace specified in the composer, load the given classes + foreach ($namespaces as $namespace => $classpaths) { + if (!is_array($classpaths)) { + $classpaths = array($classpaths); + } + spl_autoload_register(function ($classname) use ($namespace, $classpaths, $dir, $psr4) { + // Check if the namespace matches the class we are looking for + if (preg_match("#^".preg_quote($namespace)."#", $classname)) { + // Remove the namespace from the file path since it's psr4 + if ($psr4) { + $classname = str_replace($namespace, "", $classname); + } + + // $filename = preg_replace("#\\\\#", "", $classname).".php"; + // This is fix for nested classes which were losing a / + $filename = ltrim($classname .'.php', '\\'); + $filename = str_replace('\\','/', $filename); + + foreach ($classpaths as $classpath) { + $fullpath = trailingslashit($dir) . trailingslashit($classpath) .$filename; + if (file_exists($fullpath)) { + include_once $fullpath; + } + } + } + }, true, $prepend); + } + } +} diff --git a/build/shortpixel/autoload.php b/build/shortpixel/autoload.php new file mode 100644 index 0000000..31c9ff8 --- /dev/null +++ b/build/shortpixel/autoload.php @@ -0,0 +1,5 @@ +load(__DIR__); + \ No newline at end of file diff --git a/build/shortpixel/composer.json b/build/shortpixel/composer.json new file mode 100644 index 0000000..3b1665b --- /dev/null +++ b/build/shortpixel/composer.json @@ -0,0 +1 @@ +{"name":"Resmush\/shortpixelmodules","description":"ShortPixel submodules","type":"function","autoload":{"psr-4":{"Resmush\\Notices":"notices\/src","Resmush\\ShortPixelLogger":"log\/src","Resmush\\FileSystem":"filesystem\/src"}}} \ No newline at end of file diff --git a/build/shortpixel/filesystem/composer.json b/build/shortpixel/filesystem/composer.json new file mode 100644 index 0000000..c5d214d --- /dev/null +++ b/build/shortpixel/filesystem/composer.json @@ -0,0 +1,18 @@ +{ + "name": "shortpixel/filesystem", + "description": "ShortPixel FileSystem", + "version": 1.0, + "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Bas", + "email": "bas@weblogmechanic.com" + } + ], + "minimum-stability": "dev", + "require": {}, + "autoload": { + "psr-4": { "ShortPixel\\FileSystem\\" : "src" } + } +} diff --git a/build/shortpixel/filesystem/src/Controller/FileSystemController.php b/build/shortpixel/filesystem/src/Controller/FileSystemController.php new file mode 100644 index 0000000..4a30206 --- /dev/null +++ b/build/shortpixel/filesystem/src/Controller/FileSystemController.php @@ -0,0 +1,329 @@ +filesystem(); +*/ +Class FileSystemController +{ + + public function __construct() + { + + } + + /** Get FileModel for a certain path. This can exist or not + * + * @param String Path Full Path to the file + * @return FileModel FileModel Object. If file does not exist, not all values are set. + */ + public function getFile($path) + { + return new FileModel($path); + } + + + + /** Get DirectoryModel for a certain path. This can exist or not + * + * @param String $path Full Path to the Directory. + * @return DirectoryModel Object with status set on current directory. + */ + public function getDirectory($path) + { + return new DirectoryModel($path); + } + + + + + /** This function returns the WordPress Basedir for uploads ( without date and such ) + * Normally this would point to /wp-content/uploads. + * @returns DirectoryModel + */ + public function getWPUploadBase() + { + $upload_dir = wp_upload_dir(null, false); + + return $this->getDirectory($upload_dir['basedir']); + } + + /** This function returns the Absolute Path of the WordPress installation where the **CONTENT** directory is located. + * Normally this would be the same as ABSPATH, but there are installations out there with -cough- alternative approaches + * @returns DirectoryModel Either the ABSPATH or where the WP_CONTENT_DIR is located + */ + public function getWPAbsPath() + { + $wpContentAbs = str_replace( 'wp-content', '', WP_CONTENT_DIR); + if (ABSPATH == $wpContentAbs) + $abspath = ABSPATH; + else + $abspath = $wpContentAbs; + + if (defined('UPLOADS')) // if this is set, lead. + $abspath = trailingslashit(ABSPATH) . UPLOADS; + + $abspath = apply_filters('resmush/filesystem/abspath', $abspath ); + + return $this->getDirectory($abspath); + } + + public function getFullPathForWP(FileModel $file) + { + $fullpath = $file->getFullPath(); + $abspath = $this->getWPAbsPath(); + + if (! strpos($abspath, $fullpath)) + { + + } + + } + + + /** Utility function that tries to convert a file-path to a webURL. + * + * If possible, rely on other better methods to find URL ( e.g. via WP functions ). + */ + public function pathToUrl(FileModel $file) + { + $filepath = $file->getFullPath(); + $directory = $file->getFileDir(); + + $is_multi_site = (function_exists("is_multisite") && is_multisite()) ? true : false; + $is_main_site = is_main_site(); + + //$is_multi_site = $this->env->is_multisite; + //$is_main_site = $this->env->is_mainsite; + + // stolen from wp_get_attachment_url + if ( ( $uploads = wp_get_upload_dir() ) && (false === $uploads['error'] || strlen(trim($uploads['error'])) == 0 ) ) { + // Check that the upload base exists in the file location. + if ( 0 === strpos( $filepath, $uploads['basedir'] ) ) { // Simple as it should, filepath and basedir share. + // Replace file location with url location. + $url = str_replace( $uploads['basedir'], $uploads['baseurl'], $filepath ); + } + // Multisite backups are stored under uploads/ShortpixelBackups/etc , but basedir would include uploads/sites/2 etc, not matching above + // If this is case, test if removing the last two directories will result in a 'clean' uploads reference. + // This is used by getting preview path ( backup pathToUrl) in bulk and for comparer.. + elseif ($is_multi_site && ! $is_main_site && 0 === strpos($filepath, dirname(dirname($uploads['basedir']))) ) + { + + $url = str_replace( dirname(dirname($uploads['basedir'])), dirname(dirname($uploads['baseurl'])), $filepath ); + $homeUrl = home_url(); + + // The result didn't end in a full URL because URL might have less subdirs ( dirname dirname) . + // This happens when site has blogs.dir (sigh) on a subdomain . Try to substitue the ABSPATH root with the home_url + if (strpos($url, $homeUrl) === false) + { + $url = str_replace( trailingslashit(ABSPATH), trailingslashit($homeUrl), $filepath); + } + + } elseif ( false !== strpos( $filepath, 'wp-content/uploads' ) ) { + // Get the directory name relative to the basedir (back compat for pre-2.7 uploads) + //$relativePath = $this->getFile(_wp_get_attachment_relative_path( $filepath ) ); + //$basename = wp_basename($relativePath->getFullPath()); + + $url = trailingslashit( $uploads['baseurl'] . '/' . _wp_get_attachment_relative_path( $filepath ) ) . wp_basename( $filepath ); + } else { + // It's a newly-uploaded file, therefore $file is relative to the basedir. + $url = $uploads['baseurl'] . "/$filepath"; + } + } + + $wp_home_path = (string) $this->getWPAbsPath(); + // If the whole WP homepath is still in URL, assume the replace when wrong ( not replaced w/ URL) + // This happens when file is outside of wp_uploads_dir + if (strpos($url, $wp_home_path) !== false) + { + // This is SITE URL, for the same reason it should be home_url in FILEMODEL. The difference is when the site is running on a subdirectory + // (1) ** This is a fix for a real-life issue, do not change if this causes issues, another fix is needed then. + // (2) ** Also a real life fix when a path is /wwwroot/assets/sites/2/ etc, in get site url, the home URL is the site URL, without appending the sites stuff. Fails on original image. + if ($is_multi_site && ! $is_main_site) + { + $wp_home_path = trailingslashit($uploads['basedir']); + $home_url = trailingslashit($uploads['baseurl']); + } + else + $home_url = trailingslashit(get_site_url()); // (1) + $url = str_replace($wp_home_path, $home_url, $filepath); + } + + // can happen if there are WP path errors. + if (is_null($url)) + return false; + + $parsed = parse_url($url); // returns array, null, or false. + + // Some hosts set the content dir to a relative path instead of a full URL. Api can't handle that, so add domain and such if this is the case. + if ( !isset($parsed['scheme']) ) {//no absolute URLs used -> we implement a hack + + if (isset($parsed['host'])) // This is for URL's for // without http or https. hackhack. + { + $scheme = is_ssl() ? 'https:' : 'http:'; + return $scheme. $url; + } + else + { + // From Metafacade. Multiple solutions /hacks. + $home_url = trailingslashit((function_exists("is_multisite") && is_multisite()) ? trim(network_site_url("/")) : trim(home_url())); + return $home_url . ltrim($url,'/');//get the file URL + } + } + + if (! is_null($parsed) && $parsed !== false) + return $url; + + return false; + } + + /** Utility function to check if a path is an URL + * Checks if this path looks like an URL. + * @param $path String Path to check + * @return Boolean If path seems domain. + */ + public function pathIsUrl($path) + { + $is_http = (substr($path, 0, 4) == 'http') ? true : false; + $is_https = (substr($path, 0, 5) == 'https') ? true : false; + $is_neutralscheme = (substr($path, 0, 2) == '//') ? true : false; // when URL is relative like //wp-content/etc + $has_urldots = (strpos($path, '://') !== false) ? true : false; // Like S3 offloads + + if ($is_http || $is_https || $is_neutralscheme || $has_urldots) + return true; + else + return false; + } + + /** Sort files / directories in a certain way. + * Future dev to include options via arg. + */ + public function sortFiles($array, $args = array() ) + { + if (count($array) == 0) + return $array; + + // what are we sorting. + $class = get_class($array[0]); + $is_files = ($class == 'Resmush\FileModel') ? true : false; // if not files, then dirs. + + usort($array, function ($a, $b) use ($is_files) + { + if ($is_files) + return strcmp($a->getFileName(), $b->getFileName()); + else { + return strcmp($a->getName(), $b->getName()); + } + } + ); + + return $array; + + } + + public function downloadFile($url, $destinationPath) + { + + //$downloadTimeout = defined(SHORTPIXEL_MAX_EXECUTION_TIME) ? max(SHORTPIXEL_MAX_EXECUTION_TIME - 10, 15) :; + $max_exec = intval(ini_get('max_execution_time')); + if ($max_exec === 0) // max execution time of zero means infinite. Quantify. + $max_exec = 60; + elseif($max_exec < 0) // some hosts like to set negative figures on this. Ignore that. + $max_exec = 30; + + $downloadTimeout = $max_exec; + + + $destinationFile = $this->getFile($destinationPath); + + $args_for_get = array( + 'stream' => true, + 'filename' => $destinationPath, + ); + + $response = wp_remote_get( $url, $args_for_get ); + + if(is_wp_error( $response )) { + Log::addError('Download file failed', array($url, $response->get_error_messages(), $response->get_error_codes() )); + + // Try to get it then via this way. + $response = download_url($url, $downloadTimeout); + if (!is_wp_error($response)) // response when alright is a tmp filepath. But given path can't be trusted since that can be reason for fail. + { + $tmpFile = $this->getFile($response); + $result = $tmpFile->move($destinationFile); + + } // download_url .. + else { + Log::addError('Secondary download failed', array($url, $response->get_error_messages(), $response->get_error_codes() )); + } + } + else { // success, at least the download. + $destinationFile = $this->getFile($response['filename']); + } + + Log::addDebug('Remote Download attempt result', array($url, $destinationPath)); + if ($destinationFile->exists()) + return true; + else + return false; + } + + + + /** Get all files from a directory tree, starting at given dir. + * @param DirectoryModel $dir to recursive into + * @param Array $filters Collection of optional filters as accepted by FileFilter in directoryModel + * @return Array Array of FileModel Objects + **/ + public function getFilesRecursive(DirectoryModel $dir, $filters = array() ) + { + $fileArray = array(); + + if (! $dir->exists()) + return $fileArray; + + $files = $dir->getFiles($filters); + $fileArray = array_merge($fileArray, $files); + + $subdirs = $dir->getSubDirectories(); + + foreach($subdirs as $subdir) + { + $fileArray = array_merge($fileArray, $this->getFilesRecursive($subdir, $filters)); + } + + return $fileArray; + } + + // Url very sparingly. + public function url_exists($url) + { + if (! function_exists('curl_init')) + { + return null; + } + + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_NOBODY, true); + curl_exec($ch); + $responseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + if ($responseCode == 200) + { + return true; + } + else { + return false; + } + + } +} diff --git a/build/shortpixel/filesystem/src/Model/File/DirectoryModel.php b/build/shortpixel/filesystem/src/Model/File/DirectoryModel.php new file mode 100644 index 0000000..98728c5 --- /dev/null +++ b/build/shortpixel/filesystem/src/Model/File/DirectoryModel.php @@ -0,0 +1,590 @@ +getFS(); + + if ($fs->pathIsUrl($path)) + { + $pathinfo = pathinfo($path); + if (isset($pathinfo['extension'])) // check if this is a file, remove the file information. + { + $path = $pathinfo['dirname']; + } + + $this->is_virtual = true; + $this->is_readable = true; // assume + $this->exists = true; + } + + if( false == $this->is_virtual() && true === $this->fileIsRestricted($path) ) + { + $this->exists = false; + $this->is_readable = false; + $this->is_writable = false; + $this->is_restricted = true; + } + else { + $this->is_virtual = false; + } + + if (false === $this->is_virtual() && + false === $this->is_restricted && + false === is_dir($path) + ) // path is wrong, *or* simply doesn't exist. + { + /* Test for file input. + * If pathinfo is fed a fullpath, it rips of last entry without setting extension, don't further trust. + * If it's a file extension is set, then trust. + */ + $pathinfo = pathinfo($path); + + if (isset($pathinfo['extension'])) + { + $path = $pathinfo['dirname']; + } + elseif (is_file($path)) + $path = dirname($path); + } + + if (false === $this->is_virtual() && + false === $this->is_restricted && + false === is_dir($path) + ) // path is wrong, *or* simply doesn't exist. + { + /* Check if realpath improves things. We support non-existing paths, which realpath fails on, so only apply on result. + Moved realpath to check after main pathinfo is set. Reason is that symlinked directories which don't include the WordPress upload dir will start to fail in file_model on processpath ( doesn't see it as a wp path, starts to try relative path). Not sure if realpath should be used anyhow in this model /BS + */ + $testpath = realpath($path); + if ($testpath) + $path = $testpath; + } + + $this->path = trailingslashit($path); + + // Basename doesn't work properly on non-latin ( cyrillic, greek etc ) directory names, returning the parent path instead. + $dir = new \SplFileInfo($path); + //basename($this->path); + $this->name = $dir->getFileName(); + + // Off the keep resources / not sure if needed. + // if (file_exists($this->path)) + // { + // $this->exists(); + // $this->is_writable(); + // $this->is_readable(); + // } + } + + private function getFS() + { + return new \Resmush\FileSystem\Controller\FileSystemController(); + } + + + public function __toString() + { + return (string) $this->path; + } + + /** Returns path *with* trailing slash + * + * @return String Path with trailing slash + */ + public function getPath() + { + return $this->path; + } + + public function getModified() + { + return filemtime($this->path); + } + + /** + * Get basename of the directory. Without path + */ + public function getName() + { + return $this->name; + } + + public function exists() + { + if (is_null($this->exists)) + { + $this->exists = file_exists($this->path) && is_dir($this->path); + } + return $this->exists; + } + + public function is_writable() + { + if (is_null($this->is_writable)) + { + $this->is_writable = is_writable($this->path); + } + return $this->is_writable; + } + + + public function is_readable() + { + if (is_null($this->is_readable)) + { + $this->is_readable = is_readable($this->path); + } + + return $this->is_readable; + } + + public function is_virtual() + { + return $this->is_virtual; + } + /** Try to obtain the path, minus the installation directory. + * @return Mixed False if this didn't work, Path as string without basedir if it did. With trailing slash, without starting slash. + */ + public function getRelativePath() + { + // not used anywhere in directory. + // $upload_dir = wp_upload_dir(null, false); + + $install_dir = get_home_path(); + if($install_dir == '/') { + $install_dir = $this->getFS()->getWPAbsPath(); + } + + $install_dir = trailingslashit($install_dir); + + $path = $this->getPath(); + // try to build relativePath without first slash. + $relativePath = str_replace($install_dir, '', $path); + + if (is_dir( $install_dir . $relativePath) === false) + { + $test_path = $this->reverseConstructPath($path, $install_dir); + if ($test_path !== false) + { + $relativePath = $test_path; + } + else { + if($test_path = $this->constructUsualDirectories($path)) + { + $relativePath = $test_path; + } + + } + } + + // If relativePath has less amount of characters, changes are this worked. + if (strlen($path) > strlen($relativePath)) + { + return ltrim(trailingslashit($relativePath), '/'); + } + return false; + } + + + private function reverseConstructPath($path, $install_path) + { + // Array value to reset index + $pathar = array_values(array_filter(explode('/', $path))); + $parts = array(); + + if (is_array($pathar)) + { + // Reverse loop the structure until solid ground is found. + for ($i = (count($pathar)); $i > 0; $i--) + { + $parts[] = $pathar[$i - 1]; + $testpath = implode('/', array_reverse($parts)); + // if the whole thing exists + if (is_dir($install_path . $testpath) === true) + { + return $testpath; + } + } + } + return false; + + } + + /** Check if path is allowed within openbasedir restrictions. This is an attempt to limit notices in file funtions if so. Most likely the path will be relative in that case. + * @param String Path as String + */ + private function fileIsRestricted($path) + { + $basedir = ini_get('open_basedir'); + + if (false === $basedir || strlen($basedir) == 0) + { + return false; + } + + $restricted = true; + $basedirs = preg_split('/:|;/i', $basedir); + + foreach($basedirs as $basepath) + { + if (strpos($path, $basepath) !== false) + { + $restricted = false; + break; + } + } + + return $restricted; + } + + + /* Last Resort function to just reduce path to various known WorPress paths. */ + private function constructUsualDirectories($path) + { + $pathar = array_values(array_filter(explode('/', $path))); // array value to reset index + $testpath = false; + if ( ($key = array_search('wp-content', $pathar)) !== false) + { + $testpath = implode('/', array_slice($pathar, $key)); + } + elseif ( ($key = array_search('uploads', $pathar)) !== false) + { + $testpath = implode('/', array_slice($pathar, $key)); + } + + return $testpath; + } + + /** Checks the directory into working order + * Tries to create directory if it doesn't exist + * Tries to fix file permission if writable is needed + * @param $check_writable Boolean Directory should be writable + */ + public function check($check_writable = false) + { + $permission = $this->getPermissionRecursive(); + + if ($permission === false) // if something wrong, return to default. + { + $permission = $this->new_directory_permission; + } + + if (! $this->exists()) + { + + Log::addInfo('Directory does not exists. Try to create recursive ' . $this->path . ' with ' . $permission); + + + $result = @mkdir($this->path, $permission , true); + chmod ($this->path, $permission ); + + if (! $result) + { + $error = error_get_last(); + Log::addWarn('MkDir failed: ' . $error['message'], array($error)); + } + // reset. + $this->exists = null; + $this->is_readable = null; + $this->is_writable = null; + + } + if ($this->exists() && $check_writable && ! $this->is_writable()) + { + chmod($this->path, $this->permission); + if (! $this->is_writable()) // perhaps parent permission is no good. + { + chmod($this->path, $this->new_directory_permission); + } + } + + if (! $this->exists()) + { + Log::addInfo('Directory does not exist :' . $this->path); + return false; + } + if ($check_writable && !$this->is_writable()) + { + Log::addInfo('Directory not writable :' . $this->path); + return false; + } + return true; + } + + public function getPermissionRecursive() + { + $parent = $this->getParent(); + if (! $parent->exists()) + { + return $parent->getPermissionRecursive(); + } + else + { + return $parent->getPermissions(); + } + + } + + /* Get files from directory + * @returns Array|boolean Returns false if something wrong w/ directory, otherwise a files array of FileModel Object. + */ + public function getFiles($args = array()) + { + + $defaults = array( + 'date_newer' => null, + 'exclude_files' => null, + 'include_files' => null, + ); + $args = wp_parse_args($args, $defaults); + + // if all filters are set to null, so point in checking those. + $has_filters = (count(array_filter($args)) > 0) ? true : false; + + if ( ! $this->exists() || ! $this->is_readable() ) + return false; + + $fileArray = array(); + + if ($handle = opendir($this->path)) { + while (false !== ($entry = readdir($handle))) { + if ( ($entry != "." && $entry != "..") && ! is_dir($this->path . $entry) ) { + + + $fileObj = new FileModel($this->path . $entry); + if ($has_filters) + { + if ($this->fileFilter($fileObj,$args) === false) + { + $fileObj = null; + } + } + + if (! is_null($fileObj)) + $fileArray[] = $fileObj; + } + } + closedir($handle); + } + +/* + if ($has_filters) + { + $fileArray = array_filter($fileArray, function ($file) use ($args) { + return $this->fileFilter($file, $args); + } ); + } */ + return $fileArray; + } + + // @return boolean true if it should be kept in array, false if not. + private function fileFilter(FileModel $file, $args) + { + $filter = true; + + if (! is_null($args['include_files'])) + { + foreach($args['include_files'] as $inc) + { + // If any in included is true, filter is good for us. + $filter = false; + if (strpos( strtolower($file->getRawFullPath()), strtolower($inc) ) !== false) + { + $filter = true; + break; + } + } + } + if (! is_null($args['date_newer'])) + { + $modified = $file->getModified(); + if ($modified < $args['date_newer'] ) + $filter = false; + } + if (! is_null($args['exclude_files'])) + { + foreach($args['exclude_files'] as $ex) + { + if (strpos( strtolower($file->getRawFullPath()), strtolower($ex) ) !== false) + $filter = false; + } + } + + return $filter; + } + + /** Get subdirectories from directory + * * @returns Array|boolean Returns false if something wrong w/ directory, otherwise a files array of DirectoryModel Object. + */ + public function getSubDirectories() + { + + if (! $this->exists() || ! $this->is_readable()) + { + return false; + } + + $dirIt = new \DirectoryIterator($this->path); + $dirArray = array(); + foreach ($dirIt as $fileInfo) + { // IsDot must go first here, or there is possiblity to run into openbasedir restrictions. + if (! $fileInfo->isDot() && $fileInfo->isDir() && $fileInfo->isReadable()) + { + if ('Resmush\Model\File\DirectoryOtherMediaModel' == get_called_class()) + { + $dir = new DirectoryOtherMediaModel($fileInfo->getRealPath()); + } + else + { + $dir = new DirectoryModel($fileInfo->getRealPath()); + } + + if ($dir->exists()) + $dirArray[] = $dir; + } + + } + return $dirArray; + } + + /** Check if this dir is a subfolder + * @param DirectoryModel The directoryObject that is tested as the parent */ + public function isSubFolderOf(DirectoryModel $dir) + { + // the same path, is not a subdir of. + if ($this->getPath() === $dir->getPath()) + return false; + + // the main path must be followed from the beginning to be a subfolder. + if (strpos($this->getPath(), $dir->getPath() ) === 0) + { + return true; + } + return false; + } + + //** Note, use sparingly, recursive function + public function getFolderSize() + { + $size = 0; + $files = $this->getFiles(); + + // GetFiles can return Boolean false on missing directory. + if (! is_array($files)) + { + return $size; + } + + foreach($files as $fileObj) + { + $size += $fileObj->getFileSize(); + } + unset($files); //attempt at performance. + + $subdirs = $this->getSubDirectories(); + + foreach($subdirs as $subdir) + { + $size += $subdir->getFolderSize(); + } + + return $size; + } + + /** Get this paths parent */ + public function getParent() + { + $path = $this->getPath(); + $parentPath = dirname($path); + + if ($path === $parentPath) + { + return false; + } + $parentDir = new DirectoryModel($parentPath); + + return $parentDir; + } + + public function getPermissions() + { + if (! $this->exists()) + { + Log::addWarning('Directory not existing (fileperms): '. $this->getPath() ); + return false; + } + $perms = fileperms($this->getPath()); + + if ($perms !== false) + { + return $perms; + } + else + return false; + + } + + public function delete() + { + return rmdir($this->getPath()); + } + + /** This will try to remove the whole structure. Use with care. + * This is mostly used to clear the backups. + */ + public function recursiveDelete() + { + if (! $this->exists() || ! $this->is_writable()) + return false; + + // This is a security measure to prevent unintended wipes. + $wpdir = $this->getFS()->getWPUploadBase(); + if (! $this->isSubFolderOf($wpdir)) + return false; + + $files = $this->getFiles(); + $subdirs = $this->getSubDirectories(); + + foreach($files as $file) + $file->delete(); + + foreach($subdirs as $subdir) + $subdir->recursiveDelete(); + + $this->delete(); + + } + +} diff --git a/build/shortpixel/filesystem/src/Model/File/FileModel.php b/build/shortpixel/filesystem/src/Model/File/FileModel.php new file mode 100644 index 0000000..927ff11 --- /dev/null +++ b/build/shortpixel/filesystem/src/Model/File/FileModel.php @@ -0,0 +1,823 @@ +rawfullpath = $path; + + if (is_null($path)) + { + Log::addWarn('FileModel: Loading null path! '); + return false; + } + + if (strlen($path) > 0) + $path = trim($path); + + $this->fullpath = $path; + + $this->checkTrustedMode(); + + $fs = $this->getFS(); + + if ($fs->pathIsUrl($path)) // Asap check for URL's to prevent remote wrappers from running. + { + $this->UrlToPath($path); + } + } + + private function getFS() + { + return new \Resmush\FileSystem\Controller\FileSystemController(); + } + + /* Get a string representation of file, the fullpath + * Note - this might be risky, without processedpath, in cases. + * @return String Full path processed or unprocessed. + */ + public function __toString() + { + return (string) $this->fullpath; + } + + protected function setFileInfo() + { + $processed_path = $this->processPath($this->fullpath); + if ($processed_path !== false) + $this->fullpath = $processed_path; // set processed path if that went alright + + + $info = $this->mb_pathinfo($this->fullpath); + // Todo, maybe replace this with splFileINfo. + if ($this->is_file()) // only set fileinfo when it's an actual file. + { + $this->filename = isset($info['basename']) ? $info['basename'] : null; // filename + extension + $this->filebase = isset($info['filename']) ? $info['filename'] : null; // only filename + $this->extension = isset($info['extension']) ? strtolower($info['extension']) : null; // only (last) extension + } + + } + + /** Call when file status changed, so writable / readable / exists are not reliable anymore */ + public function resetStatus() + { + $this->is_writable = null; + $this->is_directory_writable = null; + $this->is_readable = null; + $this->is_file = null; + $this->exists = null; + $this->is_virtual = null; + $this->filesize = null; + $this->permissions = null; + } + + /** + * @param $forceCheck Forces a filesystem check instead of using cached. Use very sparingly. Implemented for retina on trusted mode. + */ + public function exists($forceCheck = false) + { + if (true === $forceCheck || is_null($this->exists)) + { + if (true === $this->fileIsRestricted($this->fullpath)) + { + $this->exists = false; + } + else { + $this->exists = (@file_exists($this->fullpath) && is_file($this->fullpath)); + } + + } + + + $this->exists = apply_filters('shortpixel_image_exists', $this->exists, $this->fullpath, $this); //legacy + $this->exists = apply_filters('resmush/file/exists', $this->exists, $this->fullpath, $this); + return $this->exists; + } + + public function is_writable() + { + // Return when already asked / Stateless might set this + if (! is_null($this->is_writable)) + { + return $this->is_writable; + } + elseif ($this->is_virtual()) + { + $this->is_writable = false; // can't write to remote files + } + elseif (is_null($this->is_writable)) + { + if ($this->exists()) + { + $this->is_writable = @is_writable($this->fullpath); + } + else // quite expensive check to see if file is writable. + { + $res = $this->create(); + $this->delete(); + $this->is_writable = $res; + } + + } + + return $this->is_writable; + } + + public function is_directory_writable() + { + // Return when already asked / Stateless might set this + if (! is_null($this->is_directory_writable)) + { + return $this->is_directory_writable; + } + elseif ($this->is_virtual()) + { + $this->is_directory_writable = false; // can't write to remote files + } + elseif (is_null($this->is_directory_writable)) + { + $directory = $this->getFileDir(); + if (is_object($directory) && $directory->exists()) + { + $this->is_directory_writable = $directory->is_writable(); + } + else { + $this->is_directory_writable = false; + } + + } + + return $this->is_directory_writable; + } + + public function is_readable() + { + if (is_null($this->is_readable)) + $this->is_readable = @is_readable($this->fullpath); + + return $this->is_readable; + } + + // A file is virtual when the file is remote with URL and no local alternative is present. + public function is_virtual() + { + if ( is_null($this->is_virtual)) + $this->is_virtual = false; // return bool + return $this->is_virtual; + } + + /* Function checks if path is actually a file. This can be used to check possible confusion if a directory path is given to filemodel */ + public function is_file() + { + if ($this->is_virtual()) // don't look further when virtual + { + $this->is_file = true; + return $this->is_file; + } + elseif (is_null($this->is_file)) + { + if ($this->exists()) + { + if (basename($this->fullpath) == '..' || basename($this->fullpath) == '.') + $this->is_file = false; + else + $this->is_file = is_file($this->fullpath); + } + else // file can not exist, but still have a valid filepath format. In that case, if file should return true. + { + + /* if file does not exist on disk, anything can become a file ( with/ without extension, etc). Meaning everything non-existing is a potential file ( or directory ) until created. */ + + if (basename($this->fullpath) == '..' || basename($this->fullpath) == '.') // don't see this as file. + { + $this->is_file = false; + } + else if (! file_exists($this->fullpath) && ! is_dir($this->fullpath)) + { + $this->is_file = true; + } + else //if (! is_file($this->fullpath)) // can be a non-existing directory. / + { + $this->is_file = false; + } + + } + } + return $this->is_file; + } + + public function getModified() + { + return filemtime($this->fullpath); + } + + + /** Returns the Directory Model this file resides in + * + * @return DirectoryModel Directorymodel Object + */ + public function getFileDir() + { + $fullpath = $this->getFullPath(); // triggers a file lookup if needed. + // create this only when needed. + if (is_null($this->directory) && strlen($fullpath) > 0) + { + // Feed to full path to DirectoryModel since it checks if input is file, or dir. Using dirname here would cause errors when fullpath is already just a dirpath ( faulty input ) + $this->directory = new DirectoryModel($fullpath); + } + + return $this->directory; + } + + public function getFileSize() + { + if (! is_null($this->filesize)) + { + return $this->filesize; + } + elseif ($this->exists() && false === $this->is_virtual() ) + { + $this->filesize = filesize($this->fullpath); + return $this->filesize; + } + elseif (true === $this->is_virtual()) + { + return -1; + } + else + return 0; + } + + // Creates an empty file + public function create() + { + if (! $this->exists() ) + { + $fileDir = $this->getFileDir(); + + if (! is_null($fileDir) && $fileDir->exists()) + { + $res = @touch($this->fullpath); + $this->exists = $res; + return $res; + } + } + else + Log::addWarn('Could not create/write file: ' . $this->fullpath); + + return false; + } + + public function append($message) + { + if (! $this->exists() ) + $this->create(); + + if (! $this->is_writable() ) + { + Log::addWarn('File append failed on ' . $this->getFullPath() . ' - not writable'); + return false; + } + $handle = fopen($this->getFullPath(), 'a'); + fwrite($handle, $message); + fclose($handle); + + return true; + } + + + /** Copy a file to somewhere + * + * @param $destination String Full Path to new file. + */ + public function copy(FileModel $destination) + { + $sourcePath = $this->getFullPath(); + $destinationPath = $destination->getFullPath(); + Log::addDebug("Copy from $sourcePath to $destinationPath "); + + if (! strlen($sourcePath) > 0 || ! strlen($destinationPath) > 0) + { + Log::addWarn('Attempted Copy on Empty Path', array($sourcePath, $destinationPath)); + return false; + } + + if (! $this->exists()) + { + Log::addWarn('Tried to copy non-existing file - ' . $sourcePath); + return false; + } + + $is_new = ($destination->exists()) ? false : true; + $status = @copy($sourcePath, $destinationPath); + + if (! $status) + { + Log::addWarn('Could not copy file ' . $sourcePath . ' to' . $destinationPath); + } + else + { + $destination->resetStatus(); + $destination->setFileInfo(); // refresh info. + } + // + do_action('resmush/filesystem/addfile', array($destinationPath, $destination, $this, $is_new)); + return $status; + } + + /** Move a file to somewhere + * This uses copy and delete functions and will fail if any of those fail. + * @param $destination String Full Path to new file. + */ + public function move(FileModel $destination) + { + $result = false; + if ($this->copy($destination)) + { + $result = $this->delete(); + if ($result == false) + { + Log::addError('Move can\'t remove file ' . $this->getFullPath()); + } + + $this->resetStatus(); + $destination->resetStatus(); + } + return $result; + } + + /** Deletes current file + * This uses the WP function since it has a filter that might be useful + */ + public function delete() + { + if ($this->exists()) + { + \wp_delete_file($this->fullpath); // delete file hook via wp_delete_file + } + else + { + Log::addWarn('Trying to remove non-existing file: ' . $this->getFullPath()); + } + + if (! file_exists($this->fullpath)) + { + $this->resetStatus(); + return true; + } + else { + $writable = ($this->is_writable()) ? 'true' : 'false'; + Log::addWarn('File seems not removed - ' . $this->getFullPath() . ' (writable:' . $writable . ')'); + return false; + } + + } + + public function getContents() + { + return file_get_contents($this->getFullPath()); + } + + public function getFullPath() + { + // filename here since fullpath is set unchecked in constructor, but might be a different take + if (is_null($this->filename)) + { + $this->setFileInfo(); + } + + return $this->fullpath; + } + + // Testing this. Principle is that when the plugin is absolutely sure this is a file, not something remote, not something non-existing, get the fullpath without any check. + // This function should *only* be used when processing mega amounts of files while not doing optimization or any processing. + // So far, testing use for file Filter */ + public function getRawFullPath() + { + return $this->rawfullpath; + } + + public function getFileName() + { + if (is_null($this->filename)) + $this->setFileInfo(); + + return $this->filename; + } + + public function getFileBase() + { + if (is_null($this->filebase)) + $this->setFileInfo(); + + return $this->filebase; + } + + + public function getExtension() + { + if (is_null($this->extension)) + $this->setFileInfo(); + + return $this->extension; + } + + public function getMime() + { + if (is_null($this->mime)) + $this->setFileInfo(); + + if ($this->exists() && ! $this->is_virtual() ) + { + $this->mime = wp_get_image_mime($this->fullpath); + if (false === $this->mime) + { + $image_data = wp_check_filetype_and_ext($this->getFullPath(), $this->getFileName()); + if (is_array($image_data) && isset($image_data['type']) && strlen($image_data['type']) > 0) + { + $this->mime = $image_data['type']; + } + + } + } + else + $this->mime = false; + + return $this->mime; + } + + + /* Internal function to check if path is a real path + * - Test for URL's based on http / https + * - Test if given path is absolute, from the filesystem root. + * @param $path String The file path + * @param String The Fixed filepath. + */ + protected function processPath($path) + { + $original_path = $path; + $fs = $this->getFS(); + + if ($fs->pathIsUrl($path)) + { + $path = $this->UrlToPath($path); + } + + if ($path === false) // don't process further + return false; + + //$path = wp_normalize_path($path); + $abspath = $fs->getWPAbsPath(); + + + // Prevent file operation below if trusted. + if (true === self::$TRUSTED_MODE) + { + return $path; + } + + // Check if some openbasedir is active. + if (true === $this->fileIsRestricted($path)) + { + $path = $this->relativeToFullPath($path); + } + + if ( is_file($path) && ! is_dir($path) ) // if path and file exist, all should be okish. + { + return $path; + } + // If attempted file does not exist, but the file is in a dir that exists, that is good enough. + elseif ( ! is_dir($path) && is_dir(dirname($path)) ) + { + return $path; + } + // If path is not in the abspath, it might be relative. + elseif (strpos($path, $abspath->getPath()) === false) + { + // if path does not contain basepath. + //$uploadDir = $fs->getWPUploadBase(); + //$abspath = $fs->getWPAbsPath(); + + $path = $this->relativeToFullPath($path); + } + $path = apply_filters('resmush/filesystem/processFilePath', $path, $original_path); + /* This needs some check here on malformed path's, but can't be test for existing since that's not a requirement. + if (file_exists($path) === false) // failed to process path to something workable. + { + // Log::addInfo('Failed to process path', array($path)); + $path = false; + } */ + + return $path; + } + + protected function checkTrustedMode() + { + // When in trusted mode prevent filesystem checks as much as possible. + if (true === self::$TRUSTED_MODE) + { + + // At this point file info might not be loaded, because it goes w/ construct -> processpath -> urlToPath etc on virtual files. And called via getFileInfo. Using any of the file info functions can trigger a loop. + if (is_null($this->extension)) + { + $extension = pathinfo($this->fullpath, PATHINFO_EXTENSION); + } + else { + $extension = $this->getExtension(); + } + + $this->exists = true; + $this->is_writable = true; + $this->is_directory_writable = true; + $this->is_readable = true; + $this->is_file = true; + // Set mime to prevent lookup in IsImage + $this->mime = 'image/' . $extension; + + if (is_null($this->filesize)) + { + $this->filesize = 0; + } + } + + } + + /** Check if path is allowed within openbasedir restrictions. This is an attempt to limit notices in file funtions if so. Most likely the path will be relative in that case. + * @param String Path as String + */ + private function fileIsRestricted($path) + { + $basedir = ini_get('open_basedir'); + + if (false === $basedir || strlen($basedir) == 0) + { + return false; + } + + $restricted = true; + $basedirs = preg_split('/:|;/i', $basedir); + + foreach($basedirs as $basepath) + { + if (strpos($path, $basepath) !== false) + { + $restricted = false; + break; + } + } + + return $restricted; + } + + /** Resolve an URL to a local path + * This partially comes from WordPress functions attempting the same + * @param String $url The URL to resolve + * @return String/Boolean - False is this seems an external domain, otherwise resolved path. + */ + private function UrlToPath($url) + { + //$uploadDir = wp_upload_dir(); + + // If files is present, high chance that it's WPMU old style, which doesn't have in home_url the /files/ needed to properly replace and get the filepath . It would result in a /files/files path which is incorrect. + if (strpos($url, '/files/') !== false) + { + $uploadDir = wp_upload_dir(); + $site_url = str_replace(array('http:', 'https:'), '', $uploadDir['baseurl']); + } + else { + $site_url = str_replace('http:', '', home_url('', 'http')); + } + + $url = str_replace(array('http:', 'https:'), '', $url); + $fs = $this->getFS(); + + if (strpos($url, $site_url) !== false) + { + // try to replace URL for Path + $abspath = $this->getFS()->getWPAbsPath(); + $path = str_replace($site_url, rtrim($abspath->getPath(),'/'), $url); + + + if (! $fs->pathIsUrl($path)) // test again. + { + return $path; + } + } + + $this->is_virtual = true; + + /* This filter checks if some supplier will be able to handle the file when needed. + * Use translate filter to correct filepath when needed. + * Return could be true, or fileModel virtual constant + */ + $result = apply_filters('resmush/image/urltopath', false, $url); + + if ($result === false) + { + $this->exists = false; + $this->is_readable = false; + $this->is_file = false; + } + else { + $this->exists = true; + $this->is_readable = true; + $this->is_file = true; + } + + // If return is a stateless server, assume that it's writable and all that. + if ($result === self::$VIRTUAL_STATELESS) + { + $this->is_writable = true; + $this->is_directory_writable = true; + $this->virtual_status = self::$VIRTUAL_STATELESS; + } + elseif ($result === self::$VIRTUAL_REMOTE) + { + $this->virtual_status = self::$VIRTUAL_REMOTE; + } + + return false; // seems URL from other server, use virtual mode. + } + + /** Tries to find the full path for a perceived relative path. + * + * Relative path is detected on basis of WordPress ABSPATH. If this doesn't appear in the file path, it might be a relative path. + * Function checks for expections on this rule ( tmp path ) and returns modified - or not - path. + * @param $path The path for the file_exists + * @returns String The updated path, if that was possible. + */ + private function relativeToFullPath($path) + { + $originalPath = $path; // for safe-keeping + + // A file with no path, can never be created to a fullpath. + if (strlen($path) == 0) + return $path; + + // if the file plainly exists, it's usable /** + if (false === $this->fileIsRestricted($path) && file_exists($path)) + { + return $path; + } + + // Test if our 'relative' path is not a path to /tmp directory. + + // This ini value might not exist. + $tempdirini = ini_get('upload_tmp_dir'); + if ( (strlen($tempdirini) > 0) && strpos($path, $tempdirini) !== false) + return $path; + + $tempdir = sys_get_temp_dir(); + if ( (strlen($tempdir) > 0) && strpos($path, $tempdir) !== false) + return $path; + + // Path contains upload basedir. This happens when upload dir is outside of usual WP. + $fs = $this->getFS(); + $uploadDir = $fs->getWPUploadBase(); + $abspath = $fs->getWPAbsPath(); + + if (strpos($path, $uploadDir->getPath()) !== false) // If upload Dir is feature in path, consider it ok. + { + return $path; + } + elseif (file_exists($abspath->getPath() . $path)) // If upload dir is abspath plus return path. Exceptions. + { + return $abspath->getPath() . $path; + } + elseif(file_exists($uploadDir->getPath() . $path)) // This happens when upload_dir is not properly prepended in get_attachment_file due to WP errors + { + return $uploadDir->getPath() . $path; + } + + // this is probably a bit of a sharp corner to take. + // if path starts with / remove it due to trailingslashing ABSPATH + $path = ltrim($path, '/'); + $fullpath = $abspath->getPath() . $path; + + // We can't test for file_exists here, since file_model allows non-existing files. + // Test if directory exists, perhaps. Otherwise we are in for a failure anyhow. + //if (is_dir(dirname($fullpath))) + return $fullpath; + //else + // return $originalPath; + } + + public function getPermissions() + { + if (is_null($this->permissions)) + $this->permissions = fileperms($this->getFullPath()) & 0777; + + return $this->permissions; + } + + // @tozo Lazy IMplementation / copy, should be brought in line w/ other attributes. + public function setPermissions($permissions) + { + @chmod($this->fullpath, $permissions); + } + + + /** Fix for multibyte pathnames and pathinfo which doesn't take into regard the locale. + * This snippet taken from PHPMailer. + */ + private function mb_pathinfo($path, $options = null) + { + $ret = ['dirname' => '', 'basename' => '', 'extension' => '', 'filename' => '']; + $pathinfo = []; + if (preg_match('#^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^.\\\\/]+?)|))[\\\\/.]*$#m', $path, $pathinfo)) { + if (array_key_exists(1, $pathinfo)) { + $ret['dirname'] = $pathinfo[1]; + } + if (array_key_exists(2, $pathinfo)) { + $ret['basename'] = $pathinfo[2]; + } + if (array_key_exists(5, $pathinfo)) { + $ret['extension'] = $pathinfo[5]; + } + if (array_key_exists(3, $pathinfo)) { + $ret['filename'] = $pathinfo[3]; + } + } + switch ($options) { + case PATHINFO_DIRNAME: + case 'dirname': + return $ret['dirname']; + case PATHINFO_BASENAME: + case 'basename': + return $ret['basename']; + case PATHINFO_EXTENSION: + case 'extension': + return $ret['extension']; + case PATHINFO_FILENAME: + case 'filename': + return $ret['filename']; + default: + return $ret; + } + } + + public function __debuginfo() + { + return [ + 'fullpath' => $this->fullpath, + 'filename' => $this->filename, + 'filebase' => $this->filebase, + 'exists' => $this->exists, + 'is_writable' => $this->is_writable, + 'is_readable' => $this->is_readable, + 'is_virtual' => $this->is_virtual, + ]; + } + + +} // FileModel Class diff --git a/build/shortpixel/log/composer.json b/build/shortpixel/log/composer.json new file mode 100644 index 0000000..51c761d --- /dev/null +++ b/build/shortpixel/log/composer.json @@ -0,0 +1,18 @@ +{ + "name": "shortpixel/log", + "description": "ShortPixel Logging", + "version": "1.1.3", + "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Bas", + "email": "bas@weblogmechanic.com" + } + ], + "minimum-stability": "dev", + "require": {}, + "autoload": { + "psr-4": { "ShortPixel\\ShortPixelLogger\\" : "src" } + } +} diff --git a/build/shortpixel/log/src/DebugItem.php b/build/shortpixel/log/src/DebugItem.php new file mode 100644 index 0000000..941b5bf --- /dev/null +++ b/build/shortpixel/log/src/DebugItem.php @@ -0,0 +1,153 @@ +level = $args['level']; + $data = $args['data']; + + $this->message = $message; + $this->time = microtime(true); + + $this->setCaller(); + + // Add message to data if it seems to be some debug variable. + if (is_object($this->message) || is_array($this->message)) + { + $data[] = $this->message; + $this->message = __('[Data]'); + } + if (is_array($data) && count($data) > 0) + { + $dataType = $this->getDataType($data); + if ($dataType == 1) // singular + { + $this->data[] = print_r($data, true); + } + if ($dataType == 2) //array or object. + { + $count = false; + if (gettype($data) == 'array') + $count = count($data); + elseif(gettype($data) == 'object') + $count = count(get_object_vars($data)); + + $firstLine = ucfirst(gettype($data)) . ':'; + if ($count !== false) + $firstLine .= ' (' . $count . ')'; + + $this->data[] = $firstLine; + + foreach($data as $index => $item) + { + if (is_object($item) || is_array($item)) + { + $this->data[] = print_r($index, true) . ' ( ' . ucfirst(gettype($item)) . ') => ' . print_r($item, true); + } + } + } + } // if + elseif (! is_array($data)) // this leaves out empty default arrays + { + $this->data[] = print_r($data, true); + } + } + + public function getData() + { + return array('time' => $this->time, 'level' => $this->level, 'message' => $this->message, 'data' => $this->data, 'caller' => $this->caller); + } + + /** Test Data Array for possible values + * + * Data can be a collection of several debug vars, a single var, or just an normal array. Test if array has single types, + * which is a sign the array is not a collection. + */ + protected function getDataType($data) + { + $single_type = array('integer', 'boolean', 'string'); + if (in_array(gettype(reset($data)), $single_type)) + { + return 1; + } + else + { + return 2; + } + } + + public function getForFormat() + { + $data = $this->getData(); + switch($this->level) + { + case self::LEVEL_ERROR: + $level = 'ERR'; + $color = "\033[31m"; + break; + case self::LEVEL_WARN: + $level = 'WRN'; + $color = "\033[33m"; + break; + case self::LEVEL_INFO: + $level = 'INF'; + $color = "\033[37m"; + break; + case self::LEVEL_DEBUG: + $level = 'DBG'; + $color = "\033[37m"; + break; + + } + $color_end = "\033[0m"; + + $data['color'] = $color; + $data['color_end'] = $color_end; + $data['level'] = $level; + + return $data; + + //return array('time' => $this->time, 'level' => $level, 'message' => $this->message, 'data' => $this->data, 'color' => $color, 'color_end' => $color_end, 'caller' => $this->caller); + + } + + protected function setCaller() + { + if(PHP_VERSION_ID < 50400) { + $debug=debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); + } else { + $debug=debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS,5); + } + + $i = 4; + if (isset($debug[$i])) + { + $info = $debug[$i]; + $line = isset($info['line']) ? $info['line'] : 'Line unknown'; + $file = isset($info['file']) ? basename($info['file']) : 'File not set'; + + $this->caller = array('line' => $line, 'file' => $file, 'function' => $info['function']); + } + + + } + + +} diff --git a/build/shortpixel/log/src/ShortPixelLogger.php b/build/shortpixel/log/src/ShortPixelLogger.php new file mode 100644 index 0000000..ccce68e --- /dev/null +++ b/build/shortpixel/log/src/ShortPixelLogger.php @@ -0,0 +1,463 @@ + array('numargs' => 3), + 'shortpixel_webp_image_base' => array('numargs' => 2), + 'shortpixel_image_urls' => array('numargs' => 2), + ); // @todo monitor hooks, but this should be more dynamic. Do when moving to module via config. +*/ + + // utility + private $namespace; + private $view; + + protected $template = 'view-debug-box'; + + /** Debugger constructor + * Two ways to activate the debugger. 1) Define SHORTPIXEL_DEBUG in wp-config.php. Either must be true or a number corresponding to required LogLevel + * 2) Put SHORTPIXEL_DEBUG in the request. Either true or number. + */ + public function __construct() + { + $this->start_time = microtime(true); + $this->logLevel = DebugItem::LEVEL_WARN; + + $ns = __NAMESPACE__; + $this->namespace = substr($ns, 0, strpos($ns, '\\')); // try to get first part of namespace + + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is not a form + if (isset($_REQUEST['SHORTPIXEL_DEBUG'])) // manual takes precedence over constants + { + $this->is_manual_request = true; + $this->is_active = true; + + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is not a form + if ($_REQUEST['SHORTPIXEL_DEBUG'] === 'true') + { + $this->logLevel = DebugItem::LEVEL_INFO; + } + else { + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is not a form + $this->logLevel = intval($_REQUEST['SHORTPIXEL_DEBUG']); + } + + } + else if ( (defined('SHORTPIXEL_DEBUG') && SHORTPIXEL_DEBUG > 0) ) + { + $this->is_active = true; + if (SHORTPIXEL_DEBUG === true) + $this->logLevel = DebugItem::LEVEL_INFO; + else { + $this->logLevel = intval(SHORTPIXEL_DEBUG); + } + } + + if (defined('SHORTPIXEL_DEBUG_TARGET') && SHORTPIXEL_DEBUG_TARGET || $this->is_manual_request) + { + if (defined('SHORTPIXEL_LOG_OVERWRITE')) // if overwrite, do this on init once. + file_put_contents($this->logPath,'-- Log Reset -- ' .PHP_EOL); + + } + + if ($this->is_active) + { + /* On Early init, this function might not exist, then queue it when needed */ + if (! function_exists('wp_get_current_user')) + add_action('init', array($this, 'initView')); + else + $this->initView(); + } + + if ($this->is_active && count($this->hooks) > 0) + $this->monitorHooks(); + } + + /** Init the view when needed. Private function ( public because of WP_HOOK ) + * Never call directly */ + public function initView() + { + $user_is_administrator = (current_user_can('manage_options')) ? true : false; + + if ($this->is_active && $this->is_manual_request && $user_is_administrator ) + { + + $logPath = $logLink = $this->logPath; // default + $uploads = wp_get_upload_dir(); + + + if ( 0 === strpos( $logPath, $uploads['basedir'] ) ) { // Simple as it should, filepath and basedir share. + // Replace file location with url location. + $logLink = str_replace( $uploads['basedir'], $uploads['baseurl'], $logPath ); + } + + + $this->view = new \stdClass; + $this->view->logLink = 'view-source:' . esc_url($logLink); + add_action('admin_footer', array($this, 'loadView')); + } + } + + public static function getInstance() + { + if ( self::$instance === null) + { + self::$instance = new ShortPixelLogger(); + } + return self::$instance; + } + + public function setLogPath($logPath) + { + $this->logPath = $logPath; + $this->getWriteFile(true); // reset the writeFile here. + } + protected function addLog($message, $level, $data = array()) + { + // $log = self::getInstance(); + + // don't log anything too low or when not active. + if ($this->logLevel < $level || ! $this->is_active) + { + return; + } + + // Force administrator on manuals. + if ( $this->is_manual_request ) + { + if (! function_exists('wp_get_current_user')) // not loaded yet + return false; + + $user_is_administrator = (current_user_can('manage_options')) ? true : false; + if (! $user_is_administrator) + return false; + } + + // Check where to log to. + if ($this->logPath === false) + { + $upload_dir = wp_upload_dir(null,false,false); + $this->logPath = $this->setLogPath($upload_dir['basedir'] . '/' . $this->namespace . ".log"); + } + + $arg = array(); + $args['level'] = $level; + $args['data'] = $data; + + $newItem = new DebugItem($message, $args); + $this->items[] = $newItem; + + if ($this->is_active) + { + $this->write($newItem); + } + } + + /** Writes to log File. */ + protected function write($debugItem, $mode = 'file') + { + $items = $debugItem->getForFormat(); + $items['time_passed'] = round ( ($items['time'] - $this->start_time), 5); + $items['time'] = date('Y-m-d H:i:s', (int) $items['time'] ); + + if ( ($items['caller']) && is_array($items['caller']) && count($items['caller']) > 0) + { + $caller = $items['caller']; + $items['caller'] = $caller['file'] . ' in ' . $caller['function'] . '(' . $caller['line'] . ')'; + } + + $line = $this->formatLine($items); + + $file = $this->getWriteFile(); + + // try to write to file. Don't write if directory doesn't exists (leads to notices) + if ($file ) + { + fwrite($file, $line); +// file_put_contents($this->logPath,$line, FILE_APPEND); + } + else { + // error_log($line); + } + } + + protected function getWriteFile($reset = false) + { + if (! is_null($this->logFile) && $reset === false) + { + return $this->logFile; + } + elseif(is_object($this->logFile)) + { + fclose($this->logFile); + } + + $logDir = dirname($this->logPath); + if (! is_dir($logDir) || ! is_writable($logDir)) + { + error_log('ShortpixelLogger: Log Directory is not writable : ' . $logDir); + $this->logFile = false; + return false; + } + + $file = false; + if (file_exists($this->logPath)) + { + if (! is_writable($this->logPath)) + { + error_log('ShortPixelLogger: File Exists, but not writable: ' . $this->logPath); + $this->logFile = false; + return $file; + } + } + + $file = fopen($this->logPath, 'a'); + + if ($file === false) + { + error_log('ShortpixelLogger: File could not be opened / created: ' . $this->logPath); + $this->logFile = false; + return $file; + } + + $this->logFile = $file; + return $file; + } + + protected function formatLine($args = array() ) + { + $line= $this->format; + foreach($args as $key => $value) + { + if (! is_array($value) && ! is_object($value)) + $line = str_replace('%%' . $key . '%%', $value, $line); + } + + $line .= PHP_EOL; + + if (isset($args['data'])) + { + $data = array_filter($args['data']); + if (count($data) > 0) + { + // @todo This should probably be a formatter function to handle multiple stuff? + foreach($data as $item) + { + if (is_bool($item)) + { + $item = (true === $item) ? 'true' : 'false'; + } + $line .= $item . PHP_EOL; + } + } + } + + return $line; + } + + protected function setLogLevel($level) + { + $this->logLevel = $level; + } + + protected function getEnv($name) + { + if (isset($this->{$name})) + { + return $this->{$name}; + } + else { + return false; + } + } + + + protected function monitorHooks() + { + + foreach($this->hooks as $hook => $data) + { + $numargs = isset($data['numargs']) ? $data['numargs'] : 1; + $prio = isset($data['priority']) ? $data['priority'] : 10; + + add_filter($hook, function($value) use ($hook) { + $args = func_get_args(); + return $this->logHook($hook, $value, $args); }, $prio, $numargs); + } + } + + public function logHook($hook, $value, $args) + { + array_shift($args); + self::addInfo('[Hook] - ' . $hook . ' with ' . var_export($value,true), $args); + return $value; + } + + public function loadView() + { + // load either param or class template. + $template = $this->template; + + $view = $this->view; + $view->namespace = $this->namespace; + $controller = $this; + + $template_path = __DIR__ . '/' . $this->template . '.php'; + if (file_exists($template_path)) + { + + include($template_path); + } + else { + self::addError("View $template for ShortPixelLogger could not be found in " . $template_path, + array('class' => get_class($this))); + } + } + + public function addMemoryLog($message, $args = array()) + { + if (is_null($this->memoryLimit)) + { + $this->memoryLimit = $this->unitToInt(ini_get('memory_limit')); + } + + $usage = memory_get_usage(); + $percentage = round(($usage / $this->memoryLimit) * 100, 2); + $memmsg = sprintf("( %s / %s - %s %%)", + $this->formatBytes($usage), + $this->formatBytes($this->memoryLimit), + $percentage + ); + $level = DebugItem::LEVEL_DEBUG; + $this->addLog($message . ' ' . $memmsg, $level, $args); + + } + + private function unitToInt($s) + { + return (int)preg_replace_callback('/(\-?\d+)(.?)/', function ($m) { + return $m[1] * pow(1024, strpos('BKMG', $m[2])); + }, strtoupper($s)); + } + + private function formatBytes($size, $precision = 2) + { + $base = log($size, 1024); + $suffixes = array('', 'K', 'M', 'G', 'T'); + + if (0 === $size) + { + return 0; + } + + $calculation = pow(1024, $base - floor($base)); + if (is_nan($calculation)) + { + return 0; + } + + return round($calculation, $precision) .' '. $suffixes[floor($base)]; + } + + public static function addError($message, $args = array()) + { + $level = DebugItem::LEVEL_ERROR; + $log = self::getInstance(); + $log->addLog($message, $level, $args); + } + public static function addWarn($message, $args = array()) + { + $level = DebugItem::LEVEL_WARN; + $log = self::getInstance(); + $log->addLog($message, $level, $args); + } + // Alias, since it goes wrong so often. + public static function addWarning($message, $args = array()) + { + self::addWarn($message, $args); + } + public static function addInfo($message, $args = array()) + { + $level = DebugItem::LEVEL_INFO; + $log = self::getInstance(); + $log->addLog($message, $level, $args); + } + public static function addDebug($message, $args = array()) + { + $level = DebugItem::LEVEL_DEBUG; + $log = self::getInstance(); + $log->addLog($message, $level, $args); + } + + public static function addMemory($message, $args = array()) + { + $log = self::getInstance(); + $log->addMemoryLog($message, $args); + } + + /** These should be removed every release. They are temporary only for d'bugging the current release */ + public static function addTemp($message, $args = array()) + { + self::addDebug($message, $args); + } + + public static function logLevel($level) + { + $log = self::getInstance(); + static::addInfo('Changing Log level' . $level); + $log->setLogLevel($level); + } + + public static function getLogLevel() + { + $log = self::getInstance(); + return $log->getEnv('logLevel'); + } + + public static function isManualDebug() + { + $log = self::getInstance(); + return $log->getEnv('is_manual_request'); + } + + public static function getLogPath() + { + $log = self::getInstance(); + return $log->getEnv('logPath'); + } + + /** Function to test if the debugger is active + * @return boolean true when active. + */ + public static function debugIsActive() + { + $log = self::getInstance(); + return $log->getEnv('is_active'); + } + } // class debugController diff --git a/build/shortpixel/log/src/view-debug-box.php b/build/shortpixel/log/src/view-debug-box.php new file mode 100644 index 0000000..9bacb8a --- /dev/null +++ b/build/shortpixel/log/src/view-debug-box.php @@ -0,0 +1,57 @@ + + + + + + + +
+
namespace) ?> Debug Box
+ Logfile +
+ +
+
diff --git a/build/shortpixel/notices/composer.json b/build/shortpixel/notices/composer.json new file mode 100644 index 0000000..0a2bd00 --- /dev/null +++ b/build/shortpixel/notices/composer.json @@ -0,0 +1,31 @@ +{ + "name": "shortpixel/notices", + "description": "ShortPixel WordPress Notice System", + "version": "1.5", + "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Bas", + "email": "bas@weblogmechanic.com" + } + ], + "minimum-stability": "dev", + "require": { + "shortpixel/log" : "1.1.*" + }, + "repositories": [ + { + "packagist.org": false, + "type": "path", + "url": "../modules/", + "options": { + "symlink": true + } + } + ], + + "autoload": { + "psr-4": { "ShortPixel\\Notices\\" : "src" } + } +} diff --git a/build/shortpixel/notices/src/NoticeController.php b/build/shortpixel/notices/src/NoticeController.php new file mode 100644 index 0000000..016cf66 --- /dev/null +++ b/build/shortpixel/notices/src/NoticeController.php @@ -0,0 +1,372 @@ +notice_option = $ns . '-notices'; + + add_action('wp_ajax_' . $this->notice_option, array($this, 'ajax_action')); + + $this->loadNotices(); + //$this->loadConfig(); + } + + public static function getInstance() + { + if ( self::$instance === null) + { + self::$instance = new NoticeController(); + } + + return self::$instance; + } + + /** Reset all notices, before loading them, to ensure on updates / activations one starts fresh */ + public static function resetNotices() + { + $ns = __NAMESPACE__; + $ns = substr($ns, 0, strpos($ns, '\\')); // try to get first part of namespace + $result = delete_option($ns . '-notices'); + } + + /** Load Notices Config File, if any + * + * [ Future Use ] + */ + public function loadConfig() + { + return; + if (file_exists('../notice_config.json')) + { + $config = file_get_contents('../notice_config.json'); + $json_config = json_decode($config); + } + } + + public function loadIcons($icons) + { + foreach($icons as $name => $icon) + NoticeModel::setIcon($name, $icon); + } + + + protected function loadNotices() + { + $notices = get_option($this->notice_option, false); + $cnotice = (is_array($notices)) ? count($notices) : 0; + + if ($notices !== false && is_array($notices)) + { + $checked = array(); + foreach($notices as $noticeObj) + { + if (is_object($noticeObj) && $noticeObj instanceOf NoticeModel) + { + $checked[] = $noticeObj; + } + } + self::$notices = $checked; + $this->has_stored = true; + } + else { + self::$notices = array(); + $this->has_stored = false; + } + $this->countNotices(); + } + + + protected function addNotice($message, $code, $unique) + { + $notice = new NoticeModel($message, $code); + + if ($unique) + { + foreach(self::$notices as $nitem) + { + if ($nitem->message == $notice->message && $nitem->code == $notice->code) // same message. + return $nitem; // return the notice with the same message. + } + } + self::$notices[] = $notice; + $this->countNotices(); + + $this->update(); + return $notice; + } + + /** Update the notices to store, check what to remove, returns count. */ + public function update() + { + if (! is_array(self::$notices) || count(self::$notices) == 0) + { + if ($this->has_stored) + delete_option($this->notice_option); + + return 0; + } + + $new_notices = array(); + foreach(self::$notices as $item) + { + if (! $item->isDone() ) + { + $new_notices[] = $item; + } + } + + update_option($this->notice_option, $new_notices); + self::$notices = $new_notices; + + return $this->countNotices(); + } + + public function countNotices() + { + $this->notice_count = count(self::$notices); + return $this->notice_count; + } + + + public function getNotices() + { + return self::$notices; + } + + public function getNoticesForDisplay() + { + $newNotices = array(); + + foreach(self::$notices as $notice) + { + if ($notice->isDismissed()) // dismissed never displays. + continue; + + if ($notice->isPersistent()) + { + $id = $notice->getID(); + if (! is_null($id) && ! in_array($id, $this->notice_displayed)) + { + $notice->notice_action = $this->notice_option; + $newNotices[] = $notice; + $this->notice_displayed[] = $id; + } + + } + else + $newNotices[] = $notice; + + + } + return $newNotices; + } + + + public function getNoticeByID($id) + { + foreach(self::$notices as $notice) + { + if ($notice->getID() == $id) + return $notice; + } + + return false; + } + + public static function removeNoticeByID($id) + { + $noticeController = self::getInstance(); + + for($i = 0; $i < count(self::$notices); $i++) + { + $item = self::$notices[$i]; + if (is_object($item) && $item->getID() == $id) + { + Log::addDebug('Removing notice with ID ' . $id); + unset(self::$notices[$i]); + } + //if ($notice_item ) + } + $noticeController->update(); + } + + public function ajax_action() + { + $response = array('result' => false, 'reason' => ''); + + if (isset($_POST['nonce']) && wp_verify_nonce( sanitize_key($_POST['nonce']), 'dismiss') ) + { + if (isset($_POST['plugin_action']) && 'dismiss' == $_POST['plugin_action'] ) + { + $id = (isset($_POST['id'])) ? sanitize_text_field( wp_unslash($_POST['id'])) : null; + + if (! is_null($id)) + { + + $notice = $this->getNoticeByID($id); + } + else + { + $notice = false; + } + + if(false !== $notice) + { + $notice->dismiss(); + $this->update(); + $response['result'] = true; + } + else + { + Log::addError('Notice not found when dismissing -> ' . $id, self::$notices); + $response['result'] = false; + $response['reason'] = ' Notice ' . $id . ' not found. '; + } + + } + + } + else + { + Log::addError('Wrong Nonce when dismissed notice. '); + $response['reason'] = 'wrong nonce'; + } + wp_send_json($response); + } + + /** Adds a notice, quick and fast method + * @param String $message The Message you want to notify + * @param Boolean $unique If unique, check to not repeat notice exact same text in notices. Discard if so + * @param int $code A value of messageType as defined in model + * @returm Object Instance of noticeModel + */ + + public static function addNormal($message, $unique = false) + { + $noticeController = self::getInstance(); + $notice = $noticeController->addNotice($message, NoticeModel::NOTICE_NORMAL, $unique); + return $notice; + + } + + public static function addError($message, $unique = false) + { + $noticeController = self::getInstance(); + $notice = $noticeController->addNotice($message, NoticeModel::NOTICE_ERROR, $unique); + return $notice; + + } + + public static function addWarning($message, $unique = false) + { + $noticeController = self::getInstance(); + $notice = $noticeController->addNotice($message, NoticeModel::NOTICE_WARNING, $unique); + return $notice; + } + + public static function addSuccess($message, $unique = false) + { + $noticeController = self::getInstance(); + $notice = $noticeController->addNotice($message, NoticeModel::NOTICE_SUCCESS, $unique); + return $notice; + + } + + public static function addDetail($notice, $detail) + { + $noticeController = self::getInstance(); + $notice->addDetail($detail); + +// $notice_id = spl_object_id($notice); + + $noticeController->update(); + } + + /** Make a regular notice persistent across multiple page loads + * @param $notice NoticeModel The Notice to make Persistent + * @param $key String Identifier of the persistent notice. + * @param $suppress Int When dismissed, time to stay dismissed + * @param $callback Function Callable function + */ + public static function makePersistent($notice, $key, $suppress = -1, $callback = null) + { + $noticeController = self::getInstance(); + $existing = $noticeController->getNoticeByID($key); + + // if this key already exists, don't allow the new notice to be entered into the array. Remove it since it's already created. + if ($existing) + { + for($i = 0; $i < count(self::$notices); $i++) + { + $item = self::$notices[$i]; + + if ($item->message == $notice->message && $item->getID() == null) + { + if ($item->message != $existing->message) // allow the persistent message to be updated, if something else is served on this ID + { + $existing->message = $item->message; + } + unset(self::$notices[$i]); + } + //if ($notice_item ) + } + } + else + { + $notice->setPersistent($key, $suppress, $callback); // set this notice persistent. + } + + $noticeController->update(); + } + + public function admin_notices() + { + if ($this->countNotices() > 0) + { + if (! self::$cssHookLoaded) + { + add_action('admin_print_footer_scripts', array($this, 'printNoticeStyle')); + self::$cssHookLoaded = true; + } + foreach($this->getNoticesForDisplay() as $notice) + { + echo $notice->getForDisplay(); + } + } + $this->update(); // puts views, and updates + } + + + public function printNoticeStyle() + { + if (file_exists(__DIR__ . '/css/notices.css')) + { + echo ''; + } + else { + Log::addDebug('Notices : css/notices.css could not be loaded'); + } + } + + + + +} diff --git a/build/shortpixel/notices/src/NoticeModel.php b/build/shortpixel/notices/src/NoticeModel.php new file mode 100644 index 0000000..c70ec70 --- /dev/null +++ b/build/shortpixel/notices/src/NoticeModel.php @@ -0,0 +1,366 @@ +message = $message; + $this->messageType = $messageType; + } + + public function isDone() + { + // check suppressed + if ($this->is_dismissed && ! is_null($this->suppress_until)) + { + if (time() >= $this->suppress_until) + { + $this->is_persistent = false; // unpersist, so it will be cleaned and dropped. + } + } + + if ($this->viewed && ! $this->is_persistent) + return true; + else + return false; + } + + public function getID() + { + return $this->id; + } + + public function isPersistent() + { + return $this->is_persistent; + } + + public function isDismissed() + { + return $this->is_dismissed; + } + + public function dismiss() + { + $this->is_dismissed = true; + $this->suppress_until = time() + $this->suppress_period; + } + + public function unDismiss() + { + $this->is_dismissed = false; + } + + public function setDismissedUntil($timestamp) + { + $this->suppress_until = $timestamp; + } + + /** Support for extra information beyond the message. + * Can help to not overwhelm users w/ the same message but different file /circumstances. + */ + public function addDetail($detail, $clean = false) + { + if ($clean) + $this->details = array(); + + if (! in_array($detail, $this->details) ) + $this->details[] = $detail; + } + + /** + * @param $method String Include or Exclude + * @param $includes String|Array Screen Names to Include / Exclude either string, or array + */ + public function limitScreens($method, $screens) + { + if ($method == 'exclude') + { + $var = 'exclude_screens'; + } + else { + $var = 'include_screens'; + } + + if (is_array($screens)) + { + $this->$var = array_merge($this->$var, $screens); + } + else { + $this->{$var}[] = $screens; // strange syntax is PHP 5.6 compat. + } + } + + /* Checks if Notice is allowed on this screen + * @param @screen_id String The screen Id to check ( most likely current one, via EnvironmentModel) + */ + public function checkScreen($screen_id) + { + if (in_array($screen_id, $this->exclude_screens)) + { + return false; + } + if (in_array($screen_id, $this->include_screens)) + { + return true; + } + + // if include is set, don't show if not screen included. + if (count($this->include_screens) == 0) + { + return true; + } + else { + return false; + } + } + + + + /** Set a notice persistent. Meaning it shows every page load until dismissed. + * @param $key Unique Key of this message. Required + * @param $suppress When dismissed do not show this message again for X amount of time. When -1 it will just be dropped from the Notices and not suppressed + */ + public function setPersistent($key, $suppress = -1, $callback = null) + { + $this->id = $key; + $this->is_persistent = true; + $this->suppress_period = $suppress; + if ( ! is_null($callback) && is_callable($callback)) + { + $this->callback = $callback; + } + } + + public static function setIcon($notice_type, $icon) + { + switch($notice_type) + { + case 'error': + $type = self::NOTICE_ERROR; + break; + case 'success': + $type = self::NOTICE_SUCCESS; + break; + case 'warning': + $type = self::NOTICE_WARNING; + break; + case 'normal': + default: + $type = self::NOTICE_NORMAL; + break; + } + self::$icons[$type] = $icon; + } + + public function _debug_getvar($var) + { + if (property_exists($this, $var)) + { + return $this->$var; + } + } + + private function checkIncomplete($var) + { + return ($var instanceof \__PHP_Incomplete_Class); + } + + public function getForDisplay() + { + $this->viewed = true; + $class = 'shortpixel shortpixel-notice '; + + $icon = ''; + + if ($this->callback) + { + if (is_array($this->callback)) + { + foreach($this->callback as $part) + { + if ($this->checkIncomplete($part) === true) + { + return false; + } + } + } elseif (is_object($this->callback)) + { + if ($this->checkIncomplete($part) === true) + return false; + } + + if (! is_callable($this->callback)) + { + return; + } + else { + $return = call_user_func($this->callback, $this); + if ($return === false) // don't display is callback returns false explicitly. + return; + + } + } + + switch($this->messageType) + { + case self::NOTICE_ERROR: + $class .= 'notice-error '; + $icon = isset(self::$icons[self::NOTICE_ERROR]) ? self::$icons[self::NOTICE_ERROR] : ''; + //$icon = 'scared'; + break; + case self::NOTICE_SUCCESS: + $class .= 'notice-success '; + $icon = isset(self::$icons[self::NOTICE_SUCCESS]) ? self::$icons[self::NOTICE_SUCCESS] : ''; + break; + case self::NOTICE_WARNING: + $class .= 'notice-warning '; + $icon = isset(self::$icons[self::NOTICE_WARNING]) ? self::$icons[self::NOTICE_WARNING] : ''; + break; + case self::NOTICE_NORMAL: + $class .= 'notice-info '; + $icon = isset(self::$icons[self::NOTICE_NORMAL]) ? self::$icons[self::NOTICE_NORMAL] : ''; + break; + default: + $class .= 'notice-info '; + $icon = ''; + break; + } + + + if ($this->is_removable) + { + $class .= 'is-dismissible '; + } + + if ($this->is_persistent) + { + $class .= 'is-persistent '; + } + + $id = ! is_null($this->id) ? $this->id : uniqid(); + //'id="' . $this->id . '"' + $output = "
" . $icon . " " . $this->message; + if ($this->hasDetails()) + { + $output .= '
+ + '; + + $output .= "

" . $this->parseDetails() . "

"; + $output .= ''; + + $output .= '
'; // detail wrapper + + } + $output .= "
"; + + if ($this->is_removable) + { + $output .= ''; + + if (! $this->is_persistent) + { + $output .= ""; + } + } + + $output .= "
"; + + if ($this->is_persistent && $this->is_removable) + { + $output .= ""; + } + return $output; + + } + + protected function hasDetails() + { + if (is_array($this->details) && count($this->details) > 0) + return true; + else + return false; + } + + protected function parseDetails() + { + return implode('
', $this->details); + } + + private function getDismissJS() + { + + $js = ''; + if (is_null(self::$jsDismissLoaded)) + { + $nonce = wp_create_nonce('dismiss'); + $url = wp_json_encode(admin_url('admin-ajax.php')); + $js = "function shortpixel_notice_dismiss(event) { + event.preventDefault(); + var ev = event.detail; + var target = event.target; + var parent = target.parentElement; + + var data = { + 'plugin_action': 'dismiss', + 'action' : '$this->notice_action', + 'nonce' : '$nonce', + } + data.time = target.getAttribute('data-dismiss'); + data.id = parent.getAttribute('id'); + jQuery.post($url,data); + + jQuery(parent).fadeTo(100,0,function() { + jQuery(parent).slideUp(100, 0, function () { + jQuery(parent).remove(); + }) + }); + }"; + } + + $js .= ' jQuery("#' . $this->id . '").find(".notice-dismiss").on("click", shortpixel_notice_dismiss); '; + + return "\n jQuery(document).ready(function(){ \n" . $js . "\n});"; + } + +} diff --git a/build/shortpixel/notices/src/css/notices.css b/build/shortpixel/notices/src/css/notices.css new file mode 100644 index 0000000..2cbb148 --- /dev/null +++ b/build/shortpixel/notices/src/css/notices.css @@ -0,0 +1,65 @@ +.shortpixel.shortpixel-notice { + min-height: 75px; + padding: 8px; + display: flex; + align-items: center; + background: #fff; + padding: 1px 12px; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04); + border: 1px solid #c3c4c7; + margin: 15px 0; + border-left-width: 4px; + border-left-color: #72aee6; + position: relative; +} +.shortpixel.shortpixel-notice span { + vertical-align: middle; +} +.shortpixel.shortpixel-notice span.icon { + margin: 0 25px 0 0; + width: 80px; +} +.shortpixel.shortpixel-notice span.content { + padding: 8px 0; + word-wrap: break-word; + overflow: hidden; +} +.shortpixel.shortpixel-notice img { + display: inline-block; + margin: 0 25px 0 0; + max-height: 50px; +} +.shortpixel.shortpixel-notice .notice-dismiss { + margin-top: 6px; +} +.shortpixel.shortpixel-notice.notice-success { + border-left-color: #00a32a; +} +.shortpixel.shortpixel-notice.notice-warning { + border-left-color: #dba617; +} +.shortpixel.shortpixel-notice.notice-error { + border-left-color: #ff0000; +} +.shortpixel.shortpixel-notice.notice-info { + border-left-color: #72aee6; +} + +/* In-view notice ( not on top, between the options ) - styled after WP notice */ +.view-notice { + box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1); + border: 4px solid #fff; + padding: 1px 12px; +} +.view-notice p { + margin: 1em 0 !important; +} +.view-notice.warning { + border-left-color: #ffb900; +} + +.view-notice-row { + display: none; +} + +/*# sourceMappingURL=notices.css.map */ diff --git a/build/shortpixel/notices/src/css/notices.css.map b/build/shortpixel/notices/src/css/notices.css.map new file mode 100644 index 0000000..0182154 --- /dev/null +++ b/build/shortpixel/notices/src/css/notices.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["notices.scss"],"names":[],"mappings":"AACA;EAGC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEC;;AACA;EACC;EACA;;AAED;EAEC;EACA;EACA;;AAKA;EAEE;EACA;EACA;;AAEF;EAEE;;AAGH;EAEC;;AAED;EAEC;;AAED;EAEC;;AAED;EAEE;;;AAIJ;AACA;EAGE;EACA;EAEA;;AACA;EACE;;AAEF;EAEE;;;AAIJ;EAEE","file":"notices.css"} \ No newline at end of file diff --git a/build/shortpixel/notices/src/css/notices.scss b/build/shortpixel/notices/src/css/notices.scss new file mode 100644 index 0000000..e851d24 --- /dev/null +++ b/build/shortpixel/notices/src/css/notices.scss @@ -0,0 +1,83 @@ + +.shortpixel.shortpixel-notice +{ + + min-height: 75px; + padding: 8px; + display: flex; + align-items: center; + background: #fff; + padding: 1px 12px; + box-shadow: 0 1px 1px rgba(0,0,0,0.04); + border: 1px solid #c3c4c7; + margin: 15px 0; + border-left-width: 4px; + border-left-color: #72aee6; + position: relative; + + span + { + vertical-align: middle; + &.icon { + margin: 0 25px 0 0; + width: 80px; + } + &.content + { + padding: 8px 0; + word-wrap: break-word; + overflow: hidden; + //display: flex; // magically fixes verticality issues + } + } + + img + { + display:inline-block; + margin: 0 25px 0 0; + max-height: 50px; + } + .notice-dismiss + { + margin-top: 6px; + } + + &.notice-success + { + border-left-color: #00a32a; + } + &.notice-warning + { + border-left-color: #dba617; + } + &.notice-error + { + border-left-color: #ff0000; + } + &.notice-info + { + border-left-color: #72aee6; + } +} + +/* In-view notice ( not on top, between the options ) - styled after WP notice */ +.view-notice +{ + + box-shadow: 0 1px 1px 0 rgba( 0, 0, 0, 0.1 ); + border: 4px solid #fff; + + padding: 1px 12px; + p { + margin: 1em 0 !important; + } + &.warning + { + border-left-color: #ffb900; + } +} + +.view-notice-row +{ + display: none; +} diff --git a/classes/Controller/AdminController.php b/classes/Controller/AdminController.php new file mode 100644 index 0000000..5343c24 --- /dev/null +++ b/classes/Controller/AdminController.php @@ -0,0 +1,231 @@ +initHooks(); + } + + protected function initHooks() + { + + add_action( 'admin_menu', array($this, 'add_menu') ); + add_action( 'admin_init', array($this, 'settings_declare') ); + add_filter( 'manage_media_columns', array($this, 'media_list_add_column') ); + add_filter( 'manage_upload_sortable_columns', array($this,'media_list_sort_column') ); + add_action( 'manage_media_custom_column', array($this,'media_list_add_column_value'), 10, 2 ); + add_filter("attachment_fields_to_edit", array($this, 'image_attachment_add_status_button'), null, 2); + add_action( 'admin_head', array($this,'register_plugin_assets') ); + + add_filter('plugin_action_links_' . plugin_basename(RESMUSH_PLUGIN_FILE), array($this, 'add_plugin_page_settings_link')); + } + + /** + * + * Create menu entries and routing + * + * @param none + * @return none + */ + public function add_menu() { + if ( ! current_user_can( 'manage_options' ) ) { + return; + } + + add_submenu_page( 'options-general.php', 'reSmush.it', 'reSmush.it', 'manage_options', 'resmushit_options', array($this, 'settings_page')); + } + + /** + * + * Declares settings entries + * + * @param none + * @return none + */ + public function settings_declare() { + register_setting( 'resmushit-settings', 'resmushit_on_upload' ); + register_setting( 'resmushit-settings', 'resmushit_qlty' ); + register_setting( 'resmushit-settings', 'resmushit_statistics' ); + register_setting( 'resmushit-settings', 'resmushit_logs' ); + register_setting( 'resmushit-settings', 'resmushit_cron' ); + register_setting( 'resmushit-settings', 'resmushit_preserve_exif' ); + register_setting( 'resmushit-settings', 'resmushit_remove_unsmushed' ); + register_setting( 'resmushit-settings', 'resmushit_notice_close' ); + } + + + + /** + * + * Add Columns to the media panel + * + * @param array $columns + * @return $columns + */ + public function media_list_add_column( $columns ) { + $columns["resmushit_disable"] = __('Disable of reSmush.it', 'resmushit-image-optimizer'); + $columns["resmushit_status"] = __('reSmush.it status', 'resmushit-image-optimizer'); + return $columns; + } + + + + /** + * + * Sort Columns to the media panel + * + * @param array $columns + * @return $columns + */ + public function media_list_sort_column( $columns ) { + $columns["resmushit_disable"] = "resmushit_disable"; + $columns["resmushit_status"] = "resmushit_status"; + return $columns; + } + + + + /** + * + * Add Value to Columns of the media panel + * + * @param string $column_name + * @param string $identifier of the column + * @return none + */ + public function media_list_add_column_value( $column_name, $id ) { + if ( $column_name == "resmushit_disable" ) + reSmushitUI::mediaListCustomValuesDisable($id); + else if ( $column_name == "resmushit_status" ) + reSmushitUI::mediaListCustomValuesStatus($id); + } + + + /** + * + * Add custom field to attachment + * + * @param array $form_fields + * @param object $post + * @return array + */ + public function image_attachment_add_status_button($form_fields, $post) { + if ( !preg_match("/image.*/", $post->post_mime_type) ) + return $form_fields; + + $form_fields["rsmt-disabled-checkbox"] = array( + "label" => __("Disable of reSmush.it", "resmushit-image-optimizer"), + "input" => "html", + "value" => '', + "html" => reSmushitUI::mediaListCustomValuesDisable($post->ID, true) + ); + + $form_fields["rsmt-status-button"] = array( + "label" => __("reSmush.it status", "resmushit-image-optimizer"), + "input" => "html", + "value" => '', + "html" => reSmushitUI::mediaListCustomValuesStatus($post->ID, true) + ); + return $form_fields; + } + + + + /** + * + * Settings page builder + * + * @param none + * @return none + */ + public function settings_page() { + ?> +
+
+ + + + + + +
+
+ + +
+
+ id ) && in_array( $current_page->id, $allowed_pages ) ) { + wp_register_style( 'resmushit-css', plugins_url( 'css/resmushit.css', RESMUSH_PLUGIN_FILE ) ); + wp_enqueue_style( 'resmushit-css' ); + wp_enqueue_style( 'prefix-style', esc_url_raw( 'https://fonts.googleapis.com/css?family=Roboto+Slab:700' ), array(), null ); + + wp_register_script( 'resmushit-js', plugins_url( 'js/script.js?' . hash_file('crc32', RESMUSH_PLUGIN_PATH . '/js/script.js'), RESMUSH_PLUGIN_FILE ) ); + wp_enqueue_script( 'resmushit-js' ); + } + } + + /** + * add 'Settings' link to options page from Plugins + * @param array $links + * @return string + */ + public function add_plugin_page_settings_link($links) { + if(is_string($links)) { + $oneLink = $links; + $links = array(); + $links[] = $oneLink; + } + $links[] = '' . __('Settings', "resmushit-image-optimizer") . ''; + return $links; + } + + +} // class diff --git a/classes/Controller/AjaxController.php b/classes/Controller/AjaxController.php new file mode 100644 index 0000000..ad8bd4d --- /dev/null +++ b/classes/Controller/AjaxController.php @@ -0,0 +1,231 @@ +initHooks(); + } + + protected function initHooks() + { + add_action( 'wp_ajax_resmushit_bulk_process_image', array($this,'bulk_process_image') ); + add_action( 'wp_ajax_resmushit_bulk_get_images', array($this,'bulk_get_images') ); + add_action( 'wp_ajax_resmushit_update_disabled_state', array($this,'update_disabled_state') ); + add_action( 'wp_ajax_resmushit_optimize_single_attachment', array($this,'optimize_single_attachment') ); + add_action( 'wp_ajax_resmushit_update_statistics', array($this,'update_statistics') ); + add_action( 'wp_ajax_resmushit_remove_backup_files', array($this, 'remove_backup_files') ); + add_action( 'wp_ajax_resmushit_restore_backup_files', array($this, 'restore_backup_files') ); + } + + + /** + * + * add Ajax action to optimize a picture according to attachment ID + * + * @param none + * @return boolean + */ + function bulk_process_image() { + if ( !isset($_REQUEST['csrf']) || ! wp_verify_nonce( $_REQUEST['csrf'], 'bulk_process_image' ) ) { + wp_send_json(json_encode(array('error' => 'Invalid CSRF token'))); + die(); + } + if(!is_super_admin() && !current_user_can('administrator')) { + wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); + die(); + } + Log::addInfo('Bulk optimization launched for file : ' . get_attached_file( sanitize_text_field((int)$_POST['data']['ID']) )); + echo esc_html(reSmushit::revert(sanitize_text_field((int)$_POST['data']['ID']))); + die(); + } + + /** + * + * add Ajax action to fetch all unsmushed pictures + * + * @param none + * @return json object + */ + function bulk_get_images() { + if ( !isset($_REQUEST['csrf']) || ! wp_verify_nonce( $_REQUEST['csrf'], 'bulk_resize' ) ) { + wp_send_json(json_encode(array('error' => 'Invalid CSRF token'))); + die(); + } + if(!is_super_admin() && !current_user_can('administrator')) { + wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); + die(); + } + wp_send_json(reSmushit::getNonOptimizedPictures()); + die(); + } + + + /** + * + * add Ajax action to change disabled state for an attachment + * + * @param none + * @return json object + */ + function update_disabled_state() { + if ( !isset($_REQUEST['data']['csrf']) || ! wp_verify_nonce( $_REQUEST['data']['csrf'], 'single_attachment' ) ) { + wp_send_json(json_encode(array('error' => 'Invalid CSRF token'))); + die(); + } + if(!is_super_admin() && !current_user_can('administrator')) { + wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); + die(); + } + if(isset($_POST['data']['id']) && $_POST['data']['id'] != null && isset($_POST['data']['disabled'])){ + echo wp_kses_post(reSmushit::updateDisabledState(sanitize_text_field((int)$_POST['data']['id']), sanitize_text_field($_POST['data']['disabled']))); + } + die(); + } + + + /** + * + * add Ajax action to optimize a single attachment in the library + * + * @param none + * @return json object + */ + public function optimize_single_attachment() { + if ( !isset($_REQUEST['data']['csrf']) || ! wp_verify_nonce( $_REQUEST['data']['csrf'], 'single_attachment' ) ) { + wp_send_json(json_encode(array('error' => 'Invalid CSRF token'))); + die(); + } + if(!is_super_admin() && !current_user_can('administrator')) { + wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); + die(); + } + if(isset($_POST['data']['id']) && $_POST['data']['id'] != null){ + reSmushit::revert(sanitize_text_field((int)$_POST['data']['id'])); + wp_send_json(json_encode(reSmushit::getStatistics(sanitize_text_field((int)$_POST['data']['id'])))); + } + die(); + } + + + + /** + * + * add Ajax action to update statistics + * + * @param none + * @return json object + */ + public function update_statistics() { + if ( !isset($_REQUEST['csrf']) || ! wp_verify_nonce( $_REQUEST['csrf'], 'bulk_process_image' ) ) { + wp_send_json(json_encode(array('error' => 'Invalid CSRF token'))); + die(); + } + if(!is_super_admin() && !current_user_can('administrator')) { + wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); + die(); + } + $output = reSmushit::getStatistics(); + $output['total_saved_size_formatted'] = reSmushitUI::sizeFormat($output['total_saved_size']); + wp_send_json(json_encode($output)); + die(); + } + + + /** + * + * add Ajax action to remove backups (-unsmushed) of the filesystem + * + * @param none + * @return json object + */ + public function remove_backup_files() { + $return = array('success' => 0); + if ( !isset($_REQUEST['csrf']) || ! wp_verify_nonce( $_REQUEST['csrf'], 'remove_backup' ) ) { + wp_send_json(json_encode(array('error' => 'Invalid CSRF token'))); + die(); + } + if(!is_super_admin() && !current_user_can('administrator')) { + wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); + die(); + } + + $files= reSmushit::detect_unsmushed_files(); + + foreach($files as $f) { + if(unlink($f)) { + $return['success']++; + } + } + update_option( 'resmushit_has_no_backup_files', 1); + wp_send_json(json_encode($return)); + + die(); + } + + /** + * + * add Ajax action to restore backups (-unsmushed) from the filesystem + * + * @param none + * @return json object + */ + public function restore_backup_files() { + if ( !isset($_REQUEST['csrf']) || ! wp_verify_nonce( $_REQUEST['csrf'], 'restore_library' ) ) { + wp_send_json(json_encode(array('error' => 'Invalid CSRF token'))); + die(); + } + if(!is_super_admin() && !current_user_can('administrator')) { + wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); + die(); + } + $files= reSmushit::detect_unsmushed_files(); + $return = array('success' => 0); + $wp_upload_dir=wp_upload_dir(); + +Log::addTemp('Detect Files', $files); + foreach($files as $f) { + $dest = str_replace('-unsmushed', '', $f); + $pictureURL = str_replace($wp_upload_dir['basedir'], $wp_upload_dir['baseurl'], $dest); + $attachment_id = reSmushit::resmushit_get_image_id($pictureURL); + + if (false === $attachment_id) + { + Log::addWarn('Restoring - no attachmentID for this URL '. $pictureURL); + continue; + } + + if(reSmushit::revert($attachment_id, true)) { + if(unlink($f)) { + $return['success']++; + } + } + } + wp_send_json(json_encode($return)); + die(); + } + + + + +} // class diff --git a/classes/Controller/CronController.php b/classes/Controller/CronController.php new file mode 100644 index 0000000..97ffe59 --- /dev/null +++ b/classes/Controller/CronController.php @@ -0,0 +1,160 @@ +initHooks(); + $this->checkSchedule(); + } + + protected function initHooks() + { + add_action('update_option_resmushit_cron', array($this,'on_cron_activation'), 100, 2); + add_filter( 'cron_schedules', array($this,'add_cron_interval') ); + add_action('resmushit_optimize', array($this,'cron_process') ); + add_action('update_option_resmushit_remove_unsmushed', array($this,'on_remove_unsmushed_change'), 100, 2); + + + } + + protected function checkSchedule() + { + if(! get_option('resmushit_cron') || get_option('resmushit_cron') === 0) { + if (wp_next_scheduled ( 'resmushit_optimize' )) { + wp_clear_scheduled_hook('resmushit_optimize'); + } + } else { + if (! wp_next_scheduled ( 'resmushit_optimize' )) { + wp_schedule_event(time(), 'resmushit_interval', 'resmushit_optimize'); + } + } + } + + /** + * Trigger when the cron are activated for the first time + * @param mixed old value for cron_activation option + * @param mixed new value for cron_activation option + */ + + public function on_cron_activation($old_value, $value) { + if($value == 1 && (!get_option('resmushit_cron_firstactivation') || get_option('resmushit_cron_firstactivation') === 0)) { + update_option( 'resmushit_cron_firstactivation', time() ); + } + } + + /** + * Declare a new time interval to run Cron + * @param array $schedules + * @return array + */ + public function add_cron_interval( $schedules ) { + $schedules['resmushit_interval'] = array( + 'interval' => RESMUSHIT_CRON_FREQUENCY, + 'display' => esc_html__( __('Every', 'resmushit-image-optimizer') . ' ' . time_elapsed_string(RESMUSHIT_CRON_FREQUENCY) ), + ); + return $schedules; + } + + /** + * Declare a new crontask for optimization bulk + */ + public function cron_process() { + global $is_cron; + $is_cron = TRUE; + + if((time() - get_option('resmushit_cron_lastaction')) < RESMUSHIT_CRON_TIMEOUT) { + Log::addWarn('Another CRON process is running, process aborted.'); + return FALSE; + } + update_option( 'resmushit_cron_lastrun', time() ); + update_option( 'resmushit_cron_lastaction', time() ); + + // required if launch through wp-cron.php + include_once( ABSPATH . 'wp-admin/includes/image.php' ); + + add_filter('wp_generate_attachment_metadata', array(\Resmush()->process(), 'process_images') ); + Log::addDebug('Gathering unoptimized pictures from CRON'); + $unoptimized_pictures = json_decode(reSmushit::getNonOptimizedPictures(TRUE)); + Log::addDebug('Found ' . count($unoptimized_pictures->nonoptimized) . ' attachments'); + + foreach($unoptimized_pictures->nonoptimized as $el) { + if (wp_next_scheduled ( 'resmushit_optimize' )) { + //avoid to collapse two crons + wp_unschedule_event(wp_next_scheduled('resmushit_optimize'), 'resmushit_optimize'); + } + Log::addDebug('CRON Processing attachments #' . $el->ID); + update_option( 'resmushit_cron_lastaction', time() ); + reSmushit::revert((int)$el->ID); + } + } + + /** + * Return the RESMUSHIT CRON status according to last_execution variables + * @return string + */ + public function get_cron_status() { + if(get_option('resmushit_cron') == 0) { + return 'DISABLED'; + } + if(!defined('DISABLE_WP_CRON') OR DISABLE_WP_CRON == false) { + return 'MISCONFIGURED'; + } + + if(get_option('resmushit_cron_lastrun') == 0 && (time() - get_option('resmushit_cron_firstactivation') > 2*RESMUSHIT_CRON_FREQUENCY)) { + return 'NEVER_RUN'; + } + if(get_option('resmushit_cron_lastrun') != 0 && (time() - get_option('resmushit_cron_lastrun') > 2*RESMUSHIT_CRON_FREQUENCY)) { + return 'NO_LATELY_RUN'; + } + return 'OK'; + } + + /** + * Trigger when the cron are activated for the first time + * @param mixed old value for cron_activation option + * @param mixed new value for cron_activation option + */ + + public function on_remove_unsmushed_change($old_value, $value) { + $old_value = (boolean)$old_value; + $value = (boolean)$value; + if($old_value == $value) { + return TRUE; + } else { + //if remove backup is activated + if($value === TRUE) { + if(!resmushit::hasAlreadyRunOnce()) { + update_option( 'resmushit_has_no_backup_files', 1); + } else { + update_option( 'resmushit_has_no_backup_files', 0); + } + } else { + update_option( 'resmushit_has_no_backup_files', 0); + } + } + } + + +} // class diff --git a/classes/Controller/ProcessController.php b/classes/Controller/ProcessController.php new file mode 100644 index 0000000..42efc8f --- /dev/null +++ b/classes/Controller/ProcessController.php @@ -0,0 +1,146 @@ +initHooks(); + } + + protected function initHooks() + { + add_action( 'delete_attachment', array($this,'delete_attachment') ); + + if(get_option('resmushit_on_upload')) + { + add_action('add_attachment', array($this,'get_meta_id') ); + } + + //Automatically optimize images if option is checked + if(get_option('resmushit_on_upload') OR ( isset($_POST['action']) AND ($_POST['action'] === "resmushit_bulk_process_image" OR $_POST['action'] === "resmushit_optimize_single_attachment" )) OR (defined( 'WP_CLI' ) && WP_CLI ) OR ($is_cron) ) + { + Log::addTemp('Gen Attachment metadta filter set'); + add_filter('wp_generate_attachment_metadata', array($this,'process_images') ); + } + } + + /** + * + * Delete also -unsmushed file (ie. Original file) when deleting an attachment + * + * @param int postID + * @return none + */ + public function delete_attachment($postid) { + reSmushit::deleteOriginalFile($postid); + } + + /** + * + * Make current attachment available + * + * @param attachment object + * @return attachment object + */ + public function get_meta_id($result){ + global $attachment_id; + $attachment_id = $result; + } + //Automatically retrieve image attachment ID if option is checked + + /** + * + * Call resmush.it optimization for attachments + * + * @param attachment object + * @param boolean preserve original file + * @return attachment object + */ + public function process_images($attachments, $force_keep_original = TRUE) { + Log::addTemp('Process Images Function'); + global $attachment_id; + $cumulated_original_sizes = 0; + $cumulated_optimized_sizes = 0; + $error = FALSE; + + if(reSmushit::getDisabledState($attachment_id)) + return $attachments; + + if(empty($attachments)) { + Log::addError("Error! Attachment #$attachment_id has no corresponding file on disk.", 'WARNING'); + return $attachments; + } + + $fileInfo = pathinfo(get_attached_file( $attachment_id )); + if(!isset($fileInfo['dirname'])) { + Log::addError("Error! Incorrect file provided." . print_r($fileInfo, TRUE), 'WARNING'); + return $attachments; + } + $basepath = $fileInfo['dirname'] . '/'; + $extension = isset($fileInfo['extension']) ? $fileInfo['extension'] : NULL; + + // Optimize only pictures/files accepted by the API + if( !in_array(strtolower($extension), resmushit::authorizedExtensions()) ) { + return $attachments; + } + + if(!isset($attachments[ 'file' ])) { + Log::addError("Error! Incorrect attachment " . print_r($attachments, TRUE), 'WARNING'); + return $attachments; + } + $basefile = basename($attachments[ 'file' ]); + + $statistics[] = reSmushit::optimize($basepath . $basefile, $force_keep_original ); + + if(!isset($attachments[ 'sizes' ])) { + Log::addError("Error! Unable to find attachments sizes." . print_r($attachments, TRUE), 'WARNING'); + return $attachments; + } + foreach($attachments['sizes'] as $image_style) { + $statistics[] = reSmushit::optimize($basepath . $image_style['file'], FALSE ); + } + + $count = 0; + foreach($statistics as $stat){ + if($stat && !isset($stat->error)){ + $cumulated_original_sizes += $stat->src_size; + $cumulated_optimized_sizes += $stat->dest_size; + $count++; + } else { + $error = TRUE; + } + } + if(!$error) { + $optimizations_successful_count = get_option('resmushit_total_optimized'); + update_option( 'resmushit_total_optimized', $optimizations_successful_count + $count ); + update_post_meta($attachment_id,'resmushed_quality', resmushit::getPictureQualitySetting()); + update_post_meta($attachment_id,'resmushed_cumulated_original_sizes', $cumulated_original_sizes); + update_post_meta($attachment_id,'resmushed_cumulated_optimized_sizes', $cumulated_optimized_sizes); + } + return $attachments; + } + + +} // class diff --git a/classes/Controller/WpCliController.php b/classes/Controller/WpCliController.php new file mode 100644 index 0000000..dee01f9 --- /dev/null +++ b/classes/Controller/WpCliController.php @@ -0,0 +1,33 @@ + 'Resmush/Plugin', + 'description' => 'Resmush AutoLoader', + 'type' => 'function', + 'autoload' => array('psr-4' => array('Resmush' => 'class'), + 'files' => self::getFiles(), + ), + ); + + $f = fopen('class/plugin.json', 'w'); + $result = fwrite($f, json_encode($plugin)); + + + if ($result === false) + echo "!!! Error !!! Could not write Plugin.json"; + + fclose($f); + } + + public static function getFiles() + { + $legacy = array( + 'resmushit.admin.php' + ); + + + echo "Build Plugin.JSON "; + return $legacy; //array_merge($main,$models,$externals); + } + +} diff --git a/classes/Plugin.php b/classes/Plugin.php new file mode 100644 index 0000000..eb6d7b6 --- /dev/null +++ b/classes/Plugin.php @@ -0,0 +1,72 @@ +initHooks(); + + // All hooks init + AjaxController::getInstance(); + AdminController::getInstance(); + CronController::getInstance(); + ProcessController::getInstance(); + } + + + public function initHooks() + { + + } + + public function process() + { + return ProcessController::getInstance(); + } + + public static function checkLogger() + { + $log = Log::getInstance(); + if (Log::debugIsActive()) // upload dir can be expensive, so only do this when log is actually active. + { + $uploaddir = wp_upload_dir(null, false, false); + if (isset($uploaddir['basedir'])) + { + $log->setLogPath($uploaddir['basedir'] . "/resmush_log"); + } + } + } + +} diff --git a/classes/plugin.json b/classes/plugin.json new file mode 100644 index 0000000..2136fe5 --- /dev/null +++ b/classes/plugin.json @@ -0,0 +1 @@ +{"name":"Resmush\/plugin","description":"Resmush.IT","type":"function","autoload":{"psr-4":{"Resmush":"classes/"}}} diff --git a/classes/resmushit.class.php b/classes/resmushit.class.php index 90efe16..8713de8 100644 --- a/classes/resmushit.class.php +++ b/classes/resmushit.class.php @@ -1,9 +1,16 @@ @@ -52,17 +59,17 @@ public static function getPictureQualitySetting() { public static function optimize($file_path = NULL, $is_original = TRUE) { global $wp_version; if(!file_exists($file_path) OR !is_file($file_path)) { - rlog('Error! Picture ' . str_replace(ABSPATH, '/', $file_path) . ' cannot be optimized, file is not found on disk.', 'WARNING'); + Log::addError('Error! Picture ' . str_replace(ABSPATH, '/', $file_path) . ' cannot be optimized, file is not found on disk.'); return false; } if(filesize($file_path) > self::MAX_FILESIZE){ - rlog('Error! Picture ' . str_replace(ABSPATH, '/', $file_path) . ' cannot be optimized, file size is above 5MB ('. reSmushitUI::sizeFormat(filesize($file_path)) .')', 'WARNING'); + Log::addError('Error! Picture ' . str_replace(ABSPATH, '/', $file_path) . ' cannot be optimized, file size is above 5MB ('. reSmushitUI::sizeFormat(filesize($file_path)) .')'); return false; } if(! in_array('curl', get_loaded_extensions())){ return false; } - + $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, RESMUSHIT_ENDPOINT); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); @@ -83,7 +90,7 @@ public static function optimize($file_path = NULL, $is_original = TRUE) { if(get_option( 'resmushit_preserve_exif' ) && get_option( 'resmushit_preserve_exif' ) == 1) { $arg['exif'] = 'true'; } - + $arg['qlty'] = self::getPictureQualitySetting(); curl_setopt($ch, CURLOPT_POSTFIELDS, $arg); @@ -112,14 +119,14 @@ public static function optimize($file_path = NULL, $is_original = TRUE) { copy($file_path, $newPath); } file_put_contents($file_path, $data); - rlog("Optimized file " . str_replace(ABSPATH, '/', $file_path) . " from " . reSmushitUI::sizeFormat($json->src_size) . " to " . reSmushitUI::sizeFormat($json->dest_size)); + Log::addDebug("Optimized file " . str_replace(ABSPATH, '/', $file_path) . " from " . reSmushitUI::sizeFormat($json->src_size) . " to " . reSmushitUI::sizeFormat($json->dest_size)); return $json; } } else { - rlog("Webservice returned the following error while optimizing $file_path : Code #" . $json->error . " - " . $json->error_long, 'ERROR'); + Log::addError("Webservice returned the following error while optimizing $file_path : Code #" . $json->error . " - " . $json->error_long); } } else { - rlog("Cannot establish connection with reSmush.it webservice while optimizing $file_path (timeout of " . RESMUSHIT_TIMEOUT . "sec.)", 'ERROR'); + Log::addError("Cannot establish connection with reSmush.it webservice while optimizing $file_path (timeout of " . RESMUSHIT_TIMEOUT . "sec.)"); } return false; } @@ -141,20 +148,21 @@ public static function revert($id, $generateThumbnails = true) { delete_post_meta($attachment_id, 'resmushed_quality'); delete_post_meta($attachment_id, 'resmushed_cumulated_original_sizes'); - delete_post_meta($attachment_id, 'resmushed_cumulated_optimized_sizes'); + delete_post_meta($attachment_id, 'resmushed_cumulated_optimized_sizes'); $basepath = dirname(get_attached_file( $attachment_id )) . '/'; $fileInfo = pathinfo(get_attached_file( $attachment_id )); - +Log::addTemp('Pathinfo', $fileInfo); $originalFile = $basepath . $fileInfo['filename'] . '-unsmushed.' . $fileInfo['extension']; - rlog('Revert original image for : ' . str_replace(ABSPATH, '/', get_attached_file( $attachment_id ))); - + Log::addDebug('Revert original image for : ' . str_replace(ABSPATH, '/', get_attached_file( $attachment_id ))); + if(file_exists($originalFile)) { copy($originalFile, get_attached_file( $attachment_id )); } //Regenerate thumbnails if($generateThumbnails) { + Log::addTemp('Revert - Generate Metadata'); wp_generate_attachment_metadata($attachment_id, get_attached_file( $attachment_id )); } @@ -175,20 +183,20 @@ public static function deleteOriginalFile($attachment_id) { $fileInfo = pathinfo(get_attached_file( $attachment_id )); $originalFile = $basepath . $fileInfo['filename'] . '-unsmushed.' . $fileInfo['extension']; - rlog('Delete original image for : ' . get_attached_file( $attachment_id )); + Log::addDebug('Delete original image for : ' . get_attached_file( $attachment_id )); if(file_exists($originalFile)) unlink($originalFile); } /** - * + * * Detect if optimization process was already launched one time * * @return boolean */ public static function hasAlreadyRunOnce(){ global $wpdb; - $query = $wpdb->prepare( + $query = $wpdb->prepare( "select count($wpdb->posts.ID) as count from $wpdb->posts @@ -199,7 +207,7 @@ public static function hasAlreadyRunOnce(){ return (boolean)$wpdb->get_var($query); } /** - * + * * Return optimization statistics * * @param int $attachment_id (optional) @@ -212,26 +220,26 @@ public static function getStatistics($attachment_id = null){ if($attachment_id) $extraSQL = "where $wpdb->postmeta.post_id = ". (int)($attachment_id); - $query = $wpdb->prepare( + $query = $wpdb->prepare( "select $wpdb->posts.ID as ID, $wpdb->postmeta.meta_value from $wpdb->posts inner join $wpdb->postmeta on $wpdb->posts.ID = $wpdb->postmeta.post_id and $wpdb->postmeta.meta_key = %s $extraSQL", array('resmushed_cumulated_original_sizes') - ); + ); $original_sizes = $wpdb->get_results($query); $total_original_size = 0; foreach($original_sizes as $s){ $total_original_size += $s->meta_value; } - $query = $wpdb->prepare( + $query = $wpdb->prepare( "select $wpdb->posts.ID as ID, $wpdb->postmeta.meta_value from $wpdb->posts inner join $wpdb->postmeta on $wpdb->posts.ID = $wpdb->postmeta.post_id and $wpdb->postmeta.meta_key = %s $extraSQL", array('resmushed_cumulated_optimized_sizes') - ); + ); $optimized_sizes = $wpdb->get_results($query); $total_optimized_size = 0; foreach($optimized_sizes as $s){ @@ -265,7 +273,7 @@ public static function getStatistics($attachment_id = null){ /** - * + * * Get the count of all pictures * * @param none @@ -274,7 +282,7 @@ public static function getStatistics($attachment_id = null){ public static function getCountAllPictures(){ global $wpdb; - $queryAllPictures = $wpdb->prepare( + $queryAllPictures = $wpdb->prepare( "select Count($wpdb->posts.ID) as count from $wpdb->posts @@ -296,7 +304,7 @@ public static function getCountAllPictures(){ /** - * + * * Get a list of non optimized pictures * * @param none @@ -317,24 +325,24 @@ public static function getNonOptimizedPictures($id_only = FALSE){ $queryUnoptimizedPicture = $wpdb->prepare( "SELECT ATTACHMENTS.* FROM ( - select + select POSTS.ID as ID, METAQLTY.meta_value as qlty, METADISABLED.meta_value as disabled $extra_select from $wpdb->posts as POSTS - inner join - $wpdb->postmeta as METAATTACH on POSTS.ID = METAATTACH.post_id - and METAATTACH.meta_key = %s - left join - $wpdb->postmeta as METAQLTY on POSTS.ID = METAQLTY.post_id + inner join + $wpdb->postmeta as METAATTACH on POSTS.ID = METAATTACH.post_id + and METAATTACH.meta_key = %s + left join + $wpdb->postmeta as METAQLTY on POSTS.ID = METAQLTY.post_id and METAQLTY.meta_key = %s - left join - $wpdb->postmeta as METADISABLED on POSTS.ID = METADISABLED.post_id + left join + $wpdb->postmeta as METADISABLED on POSTS.ID = METADISABLED.post_id and METADISABLED.meta_key = %s - where + where POSTS.post_type = %s and (POSTS.post_mime_type = 'image/jpeg' OR POSTS.post_mime_type = 'image/gif' OR POSTS.post_mime_type = 'image/png') ) as ATTACHMENTS - WHERE + WHERE (ATTACHMENTS.qlty != '%s' OR ATTACHMENTS.qlty IS NULL) AND ATTACHMENTS.disabled IS NULL LIMIT %d", @@ -347,7 +355,7 @@ public static function getNonOptimizedPictures($id_only = FALSE){ $tmp = array(); $tmp['ID'] = $image->ID; $tmp['attachment_metadata'] = isset($image->file_meta) ? unserialize($image->file_meta) : array(); - + if( !file_exists(get_attached_file( $image->ID )) ) { $files_not_found[] = $tmp; continue; @@ -357,7 +365,7 @@ public static function getNonOptimizedPictures($id_only = FALSE){ $files_too_big[] = $tmp; continue; } - + $unsmushed_images[] = $tmp; } return json_encode(array('nonoptimized' => $unsmushed_images, 'filestoobig' => $files_too_big, 'filesnotfound' => $files_not_found)); @@ -365,7 +373,7 @@ public static function getNonOptimizedPictures($id_only = FALSE){ /** - * + * * Return the number of non optimized pictures * * @param none @@ -382,7 +390,7 @@ public static function getCountNonOptimizedPictures(){ /** - * + * * Record in DB new status for optimization disabled state * * @param int $id ID of postID @@ -404,7 +412,7 @@ public static function updateDisabledState($id, $state){ /** - * + * * Get Disabled State * * @param int $attachment_id Post ID @@ -416,10 +424,64 @@ public static function getDisabledState($attachment_id){ return false; } + /** + * + * Detect unsmushed files by browsing the library directory + * + * @param none + * @return none + */ + public static function detect_unsmushed_files() { + $wp_upload_dir=wp_upload_dir(); + return self::glob_recursive($wp_upload_dir['basedir'] . '/*-unsmushed.*'); + } /** - * + * + * Find recursively files based on pattern + * + * @param string $pattern file search + * @param boolean $flags + * @return array + * @author Mike + * @link https://www.php.net/manual/en/function.glob.php#106595 + */ + protected static function glob_recursive($pattern, $flags = 0) { + $files = glob($pattern, $flags); + + foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) + { + $files = array_merge($files, self::glob_recursive($dir.'/'.basename($pattern), $flags)); + } + + return $files; + } + + + + /** + * + * retrieve Attachment ID from Path + * from : https://pippinsplugins.com/retrieve-attachment-id-from-image-url/ + * + * @param imageURL + * @return json object + */ + public static function resmushit_get_image_id($image_url) { + global $wpdb; + $attachment = $wpdb->get_col($wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE guid='%s';", $image_url )); +Log::addTEmp('Attachmnet', $attachment); + if (! isset($attachment[0])) + { + return false; + } + return $attachment[0]; + } + + + /** + * * Get Last Quality Factor attached to a picture * * @param int $attachment_id Post ID @@ -435,7 +497,7 @@ public static function getAttachmentQuality($attachment_id){ /** - * + * * Check if this Attachment was successfully optimized * * @param int $attachment_id Post ID @@ -445,15 +507,19 @@ public static function wasSuccessfullyUpdated($attachment_id){ if( self::getDisabledState( $attachment_id )) return 'disabled'; if (!file_exists(get_attached_file( $attachment_id ))) { - rlog("Error! File " . get_attached_file( $attachment_id ) . " not found on disk.", 'WARNING'); + Log::addError("Error! File " . get_attached_file( $attachment_id ) . " not found on disk."); return 'file_not_found'; } if( filesize(get_attached_file( $attachment_id )) > self::MAX_FILESIZE){ + Log::addDebug('File too big' . $attachment_id); return 'file_too_big'; } if( self::getPictureQualitySetting() != self::getAttachmentQuality( $attachment_id )) + { + Log::addDebug('Quality setting failed'); return 'failed'; + } return 'success'; } } diff --git a/classes/resmushitUI.class.php b/classes/resmushitUI.class.php index d14c593..e27fafb 100644 --- a/classes/resmushitUI.class.php +++ b/classes/resmushitUI.class.php @@ -1,9 +1,16 @@ @@ -19,6 +26,7 @@ * @param string $border Color of the border * @return none */ + // @todo This function only used by one other function .. public static function fullWidthPanel($title = null, $html = null, $border = null) { self::fullWidthPanelWrapper($title, $html, $border); echo wp_kses_post($html); @@ -26,8 +34,6 @@ public static function fullWidthPanel($title = null, $html = null, $border = nul } - - /** * * Create a new panel wrapper (start) @@ -46,9 +52,6 @@ public static function fullWidthPanelWrapper($title = null, $html = null, $borde echo wp_kses_post("

$title

"); } - - - /** * * Create a new panel wrapper (end) @@ -60,9 +63,6 @@ public static function fullWidthPanelEndWrapper() { echo wp_kses_post("
"); } - - - /** * * Generate Header panel @@ -72,13 +72,10 @@ public static function fullWidthPanelEndWrapper() { */ public static function headerPanel() { $html = ""; - self::fullWidthPanel($html); + $html = "By ShortPixel"; + self::fullWidthPanel('ReSmush.it', $html); } - - - - /** * * Generate Settings panel @@ -122,21 +119,22 @@ public static function settingsPanel() {
', $allowed_html); settings_fields( 'resmushit-settings' ); do_settings_sections( 'resmushit-settings' ); - - - echo wp_kses('' + + + echo wp_kses('
' . self::addSetting("text", __("Image quality", 'resmushit-image-optimizer'), __("Default value is 92. The quality factor must be between 0 (very weak) and 100 (best quality)", 'resmushit-image-optimizer'), "resmushit_qlty") . self::addSetting("checkbox", __("Optimize on upload", 'resmushit-image-optimizer'), __("All future images uploaded will be automatically optimized", 'resmushit-image-optimizer'), "resmushit_on_upload") . self::addSetting("checkbox", __("Enable statistics", 'resmushit-image-optimizer'), __("Generates statistics about optimized pictures", 'resmushit-image-optimizer'), "resmushit_statistics") - . self::addSetting("checkbox", __("Enable logs", 'resmushit-image-optimizer'), __("Enable file logging (for developers)", 'resmushit-image-optimizer'), "resmushit_logs") - . self::addSetting("checkbox", $new_label . __("Process optimize on CRON", 'resmushit-image-optimizer'), __("Will perform image optimization process through CRON tasks", 'resmushit-image-optimizer'), "resmushit_cron") + . + /*self::addSetting("checkbox", __("Enable logs", 'resmushit-image-optimizer'), __("Enable file logging (for developers)", 'resmushit-image-optimizer'), "resmushit_logs") + . */ self::addSetting("checkbox", $new_label . __("Process optimize on CRON", 'resmushit-image-optimizer'), __("Will perform image optimization process through CRON tasks", 'resmushit-image-optimizer'), "resmushit_cron") . self::addSetting("checkbox", $new_label . __("Preserve EXIF", 'resmushit-image-optimizer'), __("Will preserve EXIF data during optimization", 'resmushit-image-optimizer'), "resmushit_preserve_exif") . self::addSetting("checkbox", $new_label . __("Do not preserve backups", 'resmushit-image-optimizer'), sprintf(__("Will not preserve a backup of the original file (save space). Read instructions carefully before enabling.", 'resmushit-image-optimizer'), 'https://resmush.it/wordpress/why-keeping-backup-files'), "resmushit_remove_unsmushed") . '
', $allowed_html); submit_button(); echo wp_kses('
', $allowed_html); - self::fullWidthPanelEndWrapper(); + self::fullWidthPanelEndWrapper(); } @@ -152,7 +150,7 @@ public static function bulkPanel() { $dataCountNonOptimizedPictures = reSmushit::getCountNonOptimizedPictures(); $countNonOptimizedPictures = $dataCountNonOptimizedPictures['nonoptimized']; self::fullWidthPanelWrapper(__('Optimize unsmushed pictures', 'resmushit-image-optimizer'), null, 'blue'); - + $additionnalClassNeedOptimization = NULL; $additionnalClassNoNeedOptimization = 'disabled'; if(!$countNonOptimizedPictures) { @@ -163,7 +161,7 @@ public static function bulkPanel() { } echo wp_kses_post("

"); - + if(get_option('resmushit_cron') && get_option('resmushit_cron') == 1) { echo wp_kses_post("$countNonOptimizedPictures " . __('non optimized pictures will be automatically optimized', 'resmushit-image-optimizer') @@ -186,7 +184,7 @@ public static function bulkPanel() { ))); echo wp_kses("

"); - self::fullWidthPanelEndWrapper(); + self::fullWidthPanelEndWrapper(); } @@ -235,8 +233,8 @@ public static function bigFilesPanel() { . "
    "); foreach($getNonOptimizedPictures->filestoobig as $file){ - $fileInfo = pathinfo(get_attached_file( $file->ID )); - $filesize = reSmushitUI::sizeFormat(filesize(get_attached_file( $file->ID ))); + $fileInfo = pathinfo(get_attached_file( $file->ID )); + $filesize = reSmushitUI::sizeFormat(filesize(get_attached_file( $file->ID ))); echo wp_kses_post("
  • '); } echo wp_kses_post('
'); - - self::fullWidthPanelEndWrapper(); + + self::fullWidthPanelEndWrapper(); } @@ -284,7 +282,7 @@ public static function statisticsPanel() { . "/" . $resmushit_stat['total_pictures'] . "

" - . __('Image optimized (including thumbnails) :', 'resmushit-image-optimizer') + . __('Image optimized (including thumbnails) :', 'resmushit-image-optimizer') . " " . $resmushit_stat['files_optimized_with_thumbnails'] . "/" @@ -292,13 +290,13 @@ public static function statisticsPanel() { . "

" . __('Total images optimized :', 'resmushit-image-optimizer') . " " - . $resmushit_stat['total_optimizations'] + . $resmushit_stat['total_optimizations'] . "

"); } else { echo wp_kses_post("

" . __('No picture has been optimized yet ! Add pictures to your Wordpress Media Library.', 'resmushit-image-optimizer') . "

"); } echo wp_kses_post(""); - self::fullWidthPanelEndWrapper(); + self::fullWidthPanelEndWrapper(); } @@ -329,7 +327,7 @@ public static function restorePanel() { . '

' . '' . '', $allowed_html); - self::fullWidthPanelEndWrapper(); + self::fullWidthPanelEndWrapper(); } /** @@ -340,10 +338,11 @@ public static function restorePanel() { * @return none */ public static function newsPanel() { + return; global $wp_version; - + echo wp_kses_post("

"); - + self::fullWidthPanelWrapper(__('News', 'resmushit-image-optimizer'), null, 'red'); if(in_array('curl', get_loaded_extensions())){ $ch = curl_init(); @@ -368,7 +367,7 @@ public static function newsPanel() { . date('d/m/Y', $news->date) . ""); if($news->picture) { - echo wp_kses_post("
"); - - self::fullWidthPanelEndWrapper(); + + self::fullWidthPanelEndWrapper(); } @@ -411,33 +410,38 @@ public static function newsPanel() { * @return none */ public static function alertPanel() { + + $cronController = CronController::getInstance(); + + $cron_status = $cronController->get_cron_status(); + if ( ( get_option('resmushit_remove_unsmushed') == 0 || (get_option('resmushit_remove_unsmushed') == 1 && get_option('resmushit_has_no_backup_files') == 1)) - && (resmushit_get_cron_status() == 'DISABLED' || resmushit_get_cron_status() == 'OK')) { + && ($cron_status == 'DISABLED' || $cron_status == 'OK')) { return TRUE; } self::fullWidthPanelWrapper(__('Important informations', 'resmushit-image-optimizer'), null, 'red'); - if(resmushit_get_cron_status() != 'DISABLED' && resmushit_get_cron_status() != 'OK') { - + if($cron_status != 'DISABLED' && $cron_status != 'OK') { + echo wp_kses_post("
" . "

" . __('Cronjobs seems incorrectly configured', 'resmushit-image-optimizer') . "

"); - if (resmushit_get_cron_status() == 'MISCONFIGURED') { + if ($cron_status == 'MISCONFIGURED') { echo wp_kses_post("

" . __('Cronjobs are not correctly configured. The variable DISABLE_WP_CRON must be set to TRUE in wp-config.php. Please install them by reading the following instruction page.', 'resmushit-image-optimizer') . "

" . __('We advice to disable Remush.it option "Process optimize on CRON" as long as Cron jobs are incorrectly set up.', 'resmushit-image-optimizer') . "

"); - } else if (resmushit_get_cron_status() == 'NEVER_RUN') { + } else if ($cron_status == 'NEVER_RUN') { echo wp_kses_post("

" . __('Cronjobs seems to have never been launched. Please install them by reading the following instruction page.', 'resmushit-image-optimizer') . "

"); - } else if (resmushit_get_cron_status() == 'NO_LATELY_RUN') { + } else if ($cron_status == 'NO_LATELY_RUN') { echo wp_kses_post("

" . __('Cronjobs seems not to have run lately. Please read the following instruction page to install them correctly.', 'resmushit-image-optimizer') . "

  • " . __('Expected Frequency :', 'resmushit-image-optimizer') . " " . __('Every', 'resmushit-image-optimizer') . " " . time_elapsed_string(RESMUSHIT_CRON_FREQUENCY) . "
  • " @@ -447,7 +451,7 @@ public static function alertPanel() { echo wp_kses_post("
"); } if(get_option('resmushit_remove_unsmushed') == 1 && get_option('resmushit_has_no_backup_files') == 0) { - $files_to_delete = count(detect_unsmushed_files()); + $files_to_delete = count(reSmushit::detect_unsmushed_files()); if($files_to_delete) { $allowed_html = array_merge(wp_kses_allowed_html( 'post' ), array( @@ -465,7 +469,7 @@ public static function alertPanel() { . '

' . sprintf(__('Keep these files and turn off "Do not preserve backups" option if you want to restore your unoptimized files in the future. Please read instructions before clicking.', 'resmushit-image-optimizer'), 'https://resmush.it/wordpress/why-keeping-backup-files') . '

' - . sprintf( __( 'We have found %s files ready to be removed', 'resmushit-image-optimizer' ), count(detect_unsmushed_files()) ) + . sprintf( __( 'We have found %s files ready to be removed', 'resmushit-image-optimizer' ), count(reSmushit::detect_unsmushed_files()) ) . '

' . '' . "", $allowed_html); @@ -473,7 +477,7 @@ public static function alertPanel() { } - self::fullWidthPanelEndWrapper(); + self::fullWidthPanelEndWrapper(); } @@ -498,7 +502,7 @@ public static function addSetting($type, $name, $extra, $machine_name) { break; case 'checkbox': $additionnal = null; - if ( 1 == get_option( $machine_name ) ) $additionnal = 'checked="checked"'; + if ( 1 == get_option( $machine_name ) ) $additionnal = 'checked="checked"'; $output .= ""; break; default: @@ -509,9 +513,6 @@ public static function addSetting($type, $name, $extra, $machine_name) { } - - - /** * * Generate checkbox "disabled" on media list @@ -520,20 +521,25 @@ public static function addSetting($type, $name, $extra, $machine_name) { * @return none */ public static function mediaListCustomValuesDisable($id, $return = false) { + + $post = get_post($id); + if ( !preg_match("/image.*/", $post->post_mime_type) ) + return; + global $wpdb; - $query = $wpdb->prepare( + $query = $wpdb->prepare( "select $wpdb->posts.ID as ID, $wpdb->postmeta.meta_value from $wpdb->posts inner join $wpdb->postmeta on $wpdb->posts.ID = $wpdb->postmeta.post_id and $wpdb->postmeta.meta_key = %s and $wpdb->postmeta.post_id = %s", array('resmushed_disabled', $id) - ); + ); $attachment_resmushit_disabled = null; if($wpdb->get_results($query)) $attachment_resmushit_disabled = 'checked'; $output = ''; - + if($return) return $output; @@ -558,6 +564,11 @@ public static function mediaListCustomValuesDisable($id, $return = false) { * @return none */ public static function mediaListCustomValuesStatus($attachment_id, $return = false) { + $post = get_post($attachment_id); + if ( !preg_match("/image.*/", $post->post_mime_type) ) + return; + // + if(reSmushit::getDisabledState($attachment_id)){ $output = '-'; } @@ -566,7 +577,7 @@ public static function mediaListCustomValuesStatus($attachment_id, $return = fal else{ $statistics = reSmushit::getStatistics($attachment_id); $output = __('Reduced by', 'resmushit-image-optimizer') . " ". $statistics['total_saved_size_nice'] ." (". $statistics['percent_reduction'] . ' ' . __('saved', 'resmushit-image-optimizer') . ")"; - $output .= ''; + $output .= '

'; } if($return) @@ -607,4 +618,4 @@ public static function sizeFormat($bytes) { } return $bytes; } -} \ No newline at end of file +} diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..043743f --- /dev/null +++ b/composer.json @@ -0,0 +1,30 @@ +{ + "name": "short-pixel-optimizer/resmush", + "description": "Resmush.it WordPress Plugin", + "repositories": [ + { + "packagist.org": false, + "type": "path", + "url": "../modules/*", + "options": { + "symlink": true + } + } + ], + "require": { + "shortpixel/notices":"@dev", + "shortpixel/build" : "@dev", + "shortpixel/filesystem" : "@dev" + }, + "autoload": { + "psr-4": { "Resmush\\" : "classes"} + }, + "scripts": { + "post-update-cmd" : "\\ShortPixel\\Build\\Build::BuildIt", + "buildLoader": "\\Resmush\\Helper\\BuildAutoLoader::buildJSON", + }, + "extra": { + "targetNamespace" : "Resmush", + "targetFilter" : "resmush" + } +} diff --git a/js/script.js b/js/script.js index 1765531..b7fc955 100644 --- a/js/script.js +++ b/js/script.js @@ -15,12 +15,12 @@ jQuery(document).delegate(".rsmt-notice button.notice-dismiss","mouseup",functio var current = this; var csrf_token = jQuery(current).parent().attr('data-csrf'); jQuery.post( - ajaxurl, { + ajaxurl, { action: 'resmushit_notice_close', csrf: csrf_token - }, + }, function(response) { - var data = jQuery.parseJSON(response); + var data = JSON.parse(response); } ); }); @@ -56,18 +56,18 @@ removeBackupFiles(); restoreBackupFiles(); -/** +/** * recursive function for resizing images */ function resmushit_bulk_process(bulk, item){ - var error_occured = false; + var error_occured = false; var csrf_token = jQuery('.rsmt-bulk').attr('data-csrf'); jQuery.post( - ajaxurl, { - action: 'resmushit_bulk_process_image', + ajaxurl, { + action: 'resmushit_bulk_process_image', data: bulk[item], csrf: csrf_token - }, + }, function(response) { if(response == 'failed') error_occured = true; @@ -77,7 +77,7 @@ function resmushit_bulk_process(bulk, item){ if(!flag_removed){ jQuery('#bulk_resize_target').remove(); container.append('

'); - var results_target = jQuery('#smush_results'); + var results_target = jQuery('#smush_results'); results_target.html('
'); flag_removed = true; } @@ -94,7 +94,7 @@ function resmushit_bulk_process(bulk, item){ jQuery('.non-optimized-wrapper > p').remove(); jQuery('.non-optimized-wrapper > div').remove(); } else if(file_too_big_count){ - + var message = file_too_big_count + ' picture cannot be optimized (> 5MB). All others have been optimized'; if(file_too_big_count > 1) var message = file_too_big_count + ' pictures cannot be optimized (> 5MB). All others have been optimized'; @@ -113,7 +113,7 @@ function resmushit_bulk_process(bulk, item){ } -/** +/** * ajax post to return all images that are candidates for resizing * @param string the id of the html element into which results will be appended */ @@ -127,16 +127,16 @@ function resmushit_bulk_resize(container_id, csrf_token) { target.animate( { height: [100,'swing'] }, - 500, - function() { + 500, + function() { jQuery.post( - ajaxurl, - { action: 'resmushit_bulk_get_images', csrf: csrf_token }, + ajaxurl, + { action: 'resmushit_bulk_get_images', csrf: csrf_token }, function(response) { var images = JSON.parse(response); if (images.hasOwnProperty('error')) { target.html('
' + images.error + '.
'); - } else if (images.hasOwnProperty('nonoptimized') && images.nonoptimized.length > 0) { + } else if (images.hasOwnProperty('nonoptimized') && images.nonoptimized.length > 0) { bulkTotalimages = images.nonoptimized.length; target.html('

' + bulkTotalimages + ' attachment(s) found, starting optimization...
'); flag_removed = false; @@ -151,18 +151,18 @@ function resmushit_bulk_resize(container_id, csrf_token) { } -/** +/** * ajax post to update statistics */ function updateStatistics() { var csrf_token = jQuery('.rsmt-bulk').attr('data-csrf'); jQuery.post( - ajaxurl, { + ajaxurl, { action: 'resmushit_update_statistics', csrf: csrf_token - }, + }, function(response) { - statistics = JSON.parse(response); + statistics = JSON.parse(response); jQuery('#rsmt-statistics-space-saved').text(statistics.total_saved_size_formatted); jQuery('#rsmt-statistics-files-optimized').text(statistics.files_optimized); jQuery('#rsmt-statistics-percent-reduction').text(statistics.percent_reduction); @@ -172,7 +172,7 @@ function updateStatistics() { } -/** +/** * ajax post to disabled status (or remove) */ function updateDisabledState() { @@ -186,10 +186,10 @@ function updateDisabledState() { var csrfToken = jQuery(current).attr('data-csrf'); jQuery.post( - ajaxurl, { + ajaxurl, { action: 'resmushit_update_disabled_state', data: {id: postID, disabled: disabledState, csrf: csrfToken} - }, + }, function(response) { jQuery(current).removeClass('rsmt-disable-loader'); jQuery(current).prop('disabled', false); @@ -204,8 +204,8 @@ function updateDisabledState() { selector.empty().append('-'); } else { selector.empty().append(''); - } - optimizeSingleAttachment(); + } + optimizeSingleAttachment(); } ); }); @@ -213,7 +213,7 @@ function updateDisabledState() { -/** +/** * ajax to Optimize a single picture */ function optimizeSingleAttachment() { @@ -225,14 +225,14 @@ function optimizeSingleAttachment() { var disabledState = jQuery(current).is(':checked'); var postID = jQuery(current).attr('data-attachment-id'); var csrf_token = jQuery(current).attr('data-csrf'); - + jQuery.post( - ajaxurl, { + ajaxurl, { action: 'resmushit_optimize_single_attachment', data: {id: postID, csrf: csrf_token} - }, + }, function(response) { - var statistics = jQuery.parseJSON(response); + var statistics = JSON.parse(response); jQuery(current).parent().empty().append('Reduced by ' + statistics.total_saved_size_nice + ' (' + statistics.percent_reduction + ' saved)'); } ); @@ -240,25 +240,25 @@ function optimizeSingleAttachment() { } -/** +/** * ajax to Optimize a single picture */ function removeBackupFiles() { jQuery(document).delegate(".rsmt-trigger--remove-backup-files","mouseup",function(e){ if ( confirm( "You're about to delete your image backup files. Are you sure to perform this operation ?" ) ) { - + e.preventDefault(); var current = this; jQuery(current).val('Removing backups...'); jQuery(current).prop('disabled', true); var csrf_token = jQuery(current).attr('data-csrf'); jQuery.post( - ajaxurl, { + ajaxurl, { action: 'resmushit_remove_backup_files', csrf: csrf_token - }, + }, function(response) { - var data = jQuery.parseJSON(response); + var data = JSON.parse(response); jQuery(current).val(data.success + ' backup files successfully removed'); setTimeout(function(){ jQuery(current).parent().parent().slideUp() }, 3000); } @@ -268,28 +268,28 @@ function removeBackupFiles() { } -/** +/** * ajax to Optimize a single picture */ function restoreBackupFiles() { jQuery(document).delegate(".rsmt-trigger--restore-backup-files","mouseup",function(e){ if ( confirm( "You're about to restore ALL your original image files. Are you sure to perform this operation ?" ) ) { - + e.preventDefault(); var current = this; jQuery(current).val('Restoring backups...'); jQuery(current).prop('disabled', true); var csrf_token = jQuery(current).attr('data-csrf'); jQuery.post( - ajaxurl, { + ajaxurl, { action: 'resmushit_restore_backup_files', csrf: csrf_token - }, + }, function(response) { - var data = jQuery.parseJSON(response); + var data = JSON.parse(response); jQuery(current).val(data.success + ' images successfully restored'); } ); } }); -} \ No newline at end of file +} diff --git a/languages/resmushit-image-optimizer-fr_FR.mo b/languages/resmushit-image-optimizer-fr_FR.mo deleted file mode 100644 index edfbe3e58818efc30952741ee87534e4275b853d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7182 zcmd6rTWn=j8ON7`f>n`=3V35pL8gT{r_(avOlMl@TuLe(rqdQiBgweV-mB;AnRE6& z>`Obv7Yy;qXf((JPZE5Y`hqVeMhp__g9#=kYQ#(8gCQp3H8F-4jsCv1*FO7{85l^2 zx-)zJXYakP-}nFi-?#ePYcGFXam{gmg!`7aEA<(0&*l8b_0@MMH4T0ZydL~9xDR|u zp5La_jqgjdAwdOoNa z7J(lHzW~a*zX2|Q-ved7%h~iAI0rVs^Pt%27a&woe*pQX{?320?hyu+@fx7m@m>&@ zs#UNJeh!p=KLW+yKLy9Yzkp1su4l0~gAGvja}vZ=Y6HZi>Wdz~4$3~h2@0RT4R*jE zf-+Cz#;bxL86e)F+cHH$kUo<2S=W(iQB2+4^!p$Hbjx zluv9VY1rpEo9HAPdE#ec3yr|Jm$9_kc(q+#-Ae4ozB^{!>a>V;*W|XlIoO}<=YOynS<(*E4z_Z^Hmk+QcHO3U z(#jr+IOqrm{tvx$)UKJLn?ucR0e>=mV5;QmLxt%^`KDeoL7t=oVzz9)A)DH($JpSe z-mvEExHfU9C-?HMW#O;yI&ZB*^mJvO$;0K?Q%YST)JydHC)3u-~cN1rIgg%vXN+|mNhPLuU0WDuuL zIzxG??yi;Z=w~fE_R}OF_H0aeOvii@-mN0f z`PssP8}!iz!CYsDt&X5)i~-eq*_Cuwft9KPcc5zi#f)S|(y5|7hr z5f^A2D(*w`S_zSQ=kdepxUoTG^jzEdp`n-1x(v^lII!wIyRl3D%hY{IWjTU8D+8on z*(Y-@vR4EekQ+N=;vKfn+WGT#!#< z@`>UV`d!U)sSKuzOkAIdtQ3S%ZnCqP9;+mJyvcYBPv{CAT{`p{zr#3sqZ0+4Qf)<2XiDOn=1L%-KPBq(w~KB8YRnya^;ouEIb8U#pV8Oy!l;H)U6Qz<5*_qMbEX6J9T!Xe`@xxRS(; zqi}3mPwkyN(3qTROik&@$?3^`x9=s-jEEjJR?(J>0wGE1xoF~cfe<%Vt?3OtPwTaG z@Ckv}Sl#S1Np8>O6aB7<;)6Qqm=uD{+`l^C*k8Akxz=pjI7S&G zDmtzAx1xOH(+!_2WD!dV%9QJ==2Uav$WpgRO}9aI>1ES8?z_iqX6m3Wf6k1>dR9-4 z9~>cEpb5m~E(=ZgA$5+E@4G;NS~JW){Z|Eagi_XV0b*Bj(#rq2n36 zFmbdNc}IJD*0!X@K*U_{OLvaRC@5j}yGNcVjmr#y8y~X-wkNA@>Xjl|w-38j4ps6Q z<(N3&tvW2c5tE6bYO}pbOR?E{qi0OdppEt%`z)Zbg^3I0;mB{58a89&QtJG7wurL_ zbnY9fU6{!MRZGQ;sip2-gwo_}Av|x&nv4(}ijE-Z^{K0@#&ZM<6?e}R>ulAIYqFZF z!F!gx#u)VoRN};FzF5Lsn+FTFBL$v?$+}&OZZ@W6lA-X}H@`uM{bzhNC!J za20!B-i?>tJ>Sco#kn0Xt8yCM%7#==%|l05z*|wLGN^}Zc+oB8X<9EA|D`*tc=l!_ z;(aM!u3Fu*y%let7iocB!%GlJz!P~S<{oISH;xOFbqdXTLSIz-99Y`PmHOqI%1AD3 za_VaosvcJ@5`{YqUw@+rfe6DPT2=g(L7c?9vLDV;_QMNEE1PEmIh9c7R8;nb|B&Fb zv9k7;P7+}2Q9GtWwXXUv3p(K#t8?049|6=+o5qo|oR1?ZCd(5*xihc7PAbT14)4^* z6Xi|;R{Jx7KMd>{oCcC&-I`*TaKjap;@-I;Cj$_Y!9j&Iyn# zC!B{2iAUEHiHzR%7N>-~vwa?7>A~TlIxdh%eVxxQN~l2sF7w~(eRF4r$}d9=C135{ zafFbeourk2o_ZCTJZUa$BVDR=p_bW)ucAY%{`$-hI9Hk8_IdW0sihRJt{QXKBIRX@e#U5c~pWuBZ@p`2Ml{AqqLI5|07$D}pSk9`CAL@t@tU7+Io2o#$ zn5mJuNaJ`^34%(xD(enTO@R, YEAR. -# -msgid "" -msgstr "" -"Project-Id-Version: \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-12-22 08:03+0100\n" -"PO-Revision-Date: 2019-12-22 11:14+0100\n" -"Last-Translator: \n" -"Language-Team: \n" -"Language: fr\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.2.4\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" - -#: classes/resmushitUI.class.php:90 resmushit.php:269 -msgid "Settings" -msgstr "Paramètres" - -#: classes/resmushitUI.class.php:91 -msgid "New!" -msgstr "Nouveau!" - -#: classes/resmushitUI.class.php:98 -msgid "Image quality" -msgstr "Qualité d’image" - -#: classes/resmushitUI.class.php:98 -msgid "" -"Default value is 92. The quality factor must be between 0 (very weak) and " -"100 (best quality)" -msgstr "" -"La valeur par défaut est de 92. Le facteur de qualité doit être comprise " -"entre 0 (mauvaise) et 100 (meilleure qualité)" - -#: classes/resmushitUI.class.php:99 -msgid "Optimize on upload" -msgstr "Optimiser à l'upload" - -#: classes/resmushitUI.class.php:99 -msgid "All future images uploaded will be automatically optimized" -msgstr "" -"Toutes les futures images téléchargées seront automatiquement optimisées" - -#: classes/resmushitUI.class.php:100 -msgid "Enable statistics" -msgstr "Activer les statistiques" - -#: classes/resmushitUI.class.php:100 -msgid "Generates statistics about optimized pictures" -msgstr "Génère des statistiques à partir des images optimisées via reSmush.it" - -#: classes/resmushitUI.class.php:101 -msgid "Enable logs" -msgstr "Activer les journaux" - -#: classes/resmushitUI.class.php:101 -msgid "Enable file logging (for developers)" -msgstr "Activation de la journalisation d'erreurs (pour développeurs)" - -#: classes/resmushitUI.class.php:102 -msgid "Process optimize on CRON" -msgstr "Optimiser les images via les cronjobs" - -#: classes/resmushitUI.class.php:102 -msgid "Will perform image optimization process through CRON tasks" -msgstr "Optimisera les images lors de l’exécution des tâches planifiées (CRON)" - -#: classes/resmushitUI.class.php:121 -msgid "Optimize unsmushed pictures" -msgstr "Optimiser les images via reSmush.it" - -#: classes/resmushitUI.class.php:136 -msgid "non optimized pictures will be automatically optimized" -msgstr "les images non optimisées le seront automatiquement" - -#: classes/resmushitUI.class.php:138 -msgid "" -"These pictures will be automatically optimized using schedule tasks " -"(cronjobs)." -msgstr "" -"Ces images seront automatiquement optimisées lors de l’exécution des tâches " -"planifiées (cronjobs)" - -#: classes/resmushitUI.class.php:140 -msgid "" -"Image optimization process can be launched manually by clicking on " -"the button below :" -msgstr "" -"L’optimisation des images peut être lancé manuellement en cliquant " -"sur le bouton suivant :" - -#: classes/resmushitUI.class.php:142 -msgid "There is currently" -msgstr "Il y a actuellement" - -#: classes/resmushitUI.class.php:144 -msgid "non optimized pictures" -msgstr "images non optimisées" - -#: classes/resmushitUI.class.php:146 -msgid "" -"This action will resmush all pictures which have not been optimized to the " -"good Image Quality Rate." -msgstr "" -"Cette action va optimiser toutes les images qui ne l'ont pas été avec le " -"nouveau facteur de qualité." - -#: classes/resmushitUI.class.php:152 -msgid "Optimize all pictures manually" -msgstr "Optimiser toutes les images manuellement" - -#: classes/resmushitUI.class.php:154 -msgid "Optimize all pictures" -msgstr "Optimiser toutes les images" - -#: classes/resmushitUI.class.php:159 -msgid "Congrats ! All your pictures are correctly optimized" -msgstr "Félicitations ! Toutes les images ont été correctement optimisées" - -#: classes/resmushitUI.class.php:179 -msgid "Files non optimized" -msgstr "Fichiers non optimisés" - -#: classes/resmushitUI.class.php:190 -msgid "pictures are too big (> 5MB) for the optimizer" -msgstr "images sont trop lourdes (> 5 Mo) pour reSmush.it" - -#: classes/resmushitUI.class.php:192 -msgid "picture is too big (> 5MB) for the optimizer" -msgstr "image est trop lourde (> 5 Mo) pour reSmush.it" - -#: classes/resmushitUI.class.php:195 -msgid "List of files above 5MB" -msgstr "Liste des fichiers de plus de 5 Mo" - -#: classes/resmushitUI.class.php:227 -msgid "Statistics" -msgstr "Statistiques" - -#: classes/resmushitUI.class.php:234 -msgid "Space saved :" -msgstr "Poids gagné :" - -#: classes/resmushitUI.class.php:238 -msgid "Total reduction :" -msgstr "Total réduit :" - -#: classes/resmushitUI.class.php:242 -msgid "Attachments optimized :" -msgstr "Nombre d'attachements optimisés :" - -#: classes/resmushitUI.class.php:248 -msgid "Image optimized (including thumbnails) :" -msgstr "Images optimisées (incluant les vignettes) :" - -#: classes/resmushitUI.class.php:254 -msgid "Total images optimized :" -msgstr "Nombre total de fichiers optimisés :" - -#: classes/resmushitUI.class.php:259 -msgid "" -"No picture has been optimized yet ! Add pictures to your Wordpress Media " -"Library." -msgstr "" -"Aucune image n'a été optimisée pour le moment ! Ajoutez des images à votre " -"médiathèque Wordpress." - -#: classes/resmushitUI.class.php:279 -msgid "News" -msgstr "Actualités" - -#: classes/resmushitUI.class.php:321 -msgid "Visit resmush.it for more informations" -msgstr "Visitez resmush.it pour plus d'informations" - -#: classes/resmushitUI.class.php:326 -msgid "Follow reSmush.it on Twitter" -msgstr "Suivez reSmush.it sur Twitter" - -#: classes/resmushitUI.class.php:347 -msgid "Important informations" -msgstr "Important" - -#: classes/resmushitUI.class.php:352 -msgid "Cronjobs seems incorrectly configured" -msgstr "Les tâches planifiées semblent configurées incorrectement" - -#: classes/resmushitUI.class.php:357 -msgid "" -"Cronjobs are not correctly configured. The variable DISABLE_WP_CRON " -"must be set to TRUE in wp-config.php. Please install them " -"by reading the following instruction page." -msgstr "" -"Les cronjobs semblent mal configurés. La variable DISABLE_WP_CRON " -"doit être définie à la valeur TRUE dans le fichier wp-config." -"php. Se référer à la documentation pour installer " -"les cronjobs correctement." - -#: classes/resmushitUI.class.php:359 -msgid "" -"We advice to disable Remush.it option \"Process optimize on CRON\" as long " -"as Cron jobs are incorrectly set up." -msgstr "" -"Il est recommandé de désactiver l’option \"Optimiser les images via les " -"cronjobs\" tant que ces derniers sont incorrectement configurés." - -#: classes/resmushitUI.class.php:363 -msgid "" -"Cronjobs seems to have never been launched. Please install them by reading " -"the following instruction page." -msgstr "" -"Les tâches planifiées semblent ne s’être jamais exécutées. Installez les en " -"suivant la documentation." - -#: classes/resmushitUI.class.php:367 -msgid "" -"Cronjobs seems not to have run lately. Please read the following instruction page to install them correctly." -msgstr "" -"Les tâches planifiées semblent ne pas s’être lancées récemment. Suivez les " -"instructions de la la documentation pour les installer " -"correctement." - -#: classes/resmushitUI.class.php:368 -msgid "Expected Frequency :" -msgstr "Fréquence :" - -#: classes/resmushitUI.class.php:368 resmushit.php:299 -msgid "Every" -msgstr "Toutes les" - -#: classes/resmushitUI.class.php:369 -msgid "Last run :" -msgstr "Dernière exécution :" - -#: classes/resmushitUI.class.php:369 -msgid "ago" -msgstr "" - -#: classes/resmushitUI.class.php:454 -msgid "Optimize" -msgstr "Optimiser" - -#: classes/resmushitUI.class.php:457 -msgid "Reduced by" -msgstr "Réduction de" - -#: classes/resmushitUI.class.php:457 -msgid "saved" -msgstr "gagné" - -#: classes/resmushitUI.class.php:458 -msgid "Force re-optimize" -msgstr "Forcer la ré-optimisation" - -#: resmushit.admin.php:43 resmushit.admin.php:98 -msgid "Disable of reSmush.it" -msgstr "Désactiver l'optimisation reSmush.it" - -#: resmushit.admin.php:44 resmushit.admin.php:105 -msgid "reSmush.it status" -msgstr "Statut de reSmush.it" - -#: resmushit.inc.php:119 -msgid "year" -msgstr "année" - -#: resmushit.inc.php:120 -msgid "month" -msgstr "mois" - -#: resmushit.inc.php:121 -msgid "week" -msgstr "semaine" - -#: resmushit.inc.php:122 -msgid "day" -msgstr "jour" - -#: resmushit.inc.php:123 -msgid "hour" -msgstr "heure" - -#: resmushit.inc.php:124 -msgid "minute" -msgstr "minute" - -#: resmushit.inc.php:125 -msgid "second" -msgstr "seconde" - -#: resmushit.inc.php:136 -msgid "just now" -msgstr "à l’instant" - -#: resmushit.php:299 -msgid " " -msgstr "" - -#. Plugin Name of the plugin/theme -msgid "reSmush.it Image Optimizer" -msgstr "reSmush.it Image Optimizer" - -#. Plugin URI of the plugin/theme -#. Author URI of the plugin/theme -msgid "https://resmush.it" -msgstr "https://resmush.it" - -#. Description of the plugin/theme -msgid "Image Optimization API. Provides image size optimization" -msgstr "Image Optimization API. Optimisation de la taille des images" - -#. Author of the plugin/theme -msgid "reSmush.it" -msgstr "reSmush.it" diff --git a/languages/resmushit-image-optimizer-it_IT.mo b/languages/resmushit-image-optimizer-it_IT.mo deleted file mode 100644 index db5a216f997c83b3145260a3847ef047d893e62e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3927 zcmai$&5s;M8HWoTAX&bGA$%rK4gv2f%y_++upY}Ge=Tg{wb$!mi3FFL?wXk*JzYar z^={S@oRD%wK%^j0iV0AGh6gnx!I|36_5KKu@)HsLdH6?*ty_zIMDeg@wOe+y;Y>yV-9Z}1j;13nDT z(@EC93{S%6;V0k=a0R{urQZ*r%>R?7{TERB{~9Ln5AdV#>37w3UxlCL_db;QzXLxE zf7tMs@N@kBJ?z7O!;ix!SWNc42{BPU3!lTMyKtZ1KYgU0??3RX{C)%@XK)Y7I=_Q5 z@1NlN;0c^5>z;)2ehte0z6{U9Z@^vnGL#tp9ZLU4-=ox%@HAv=>RI?ncne~xn!^;n z2r)(d1 zWft{;$x2KK`us*;52sdtyEK`LM|y0M=nFk7LlmP%HXd4=>vg?)V2dMtXw3_2+T^J| zyH4B4(ybY~rmnhRMw!)qtP6XaDW-iF)wR5896R1*ell_SM6ZrnBee%M^K)B-wM8f1 zhsAS`prS!!D% zqHoq7XHh1)w7cEcyM;e+DU(zo(}8d-hF86sfy+?oRhK7OnaU31w49A{;R-LQv2-S7+J_0$A{ zM1)!^j%<{iNYh29prfzz~_r9Lej6_o=Skf2&FHJrbj@hCZ5XQH-tg2F;5? zwon-`Q2Q>pNTyXbkkVSRcjm?FoJT2Ip9eLKaXvV6=J4>a-}bFqL(@E~0^CphOdU(+ z)^m*u#U0UmJ#y5_mn1pXszqf-3tJ1d@OM@1Z{5AE$;Kgzpckt1N(!b7stS~%0=~r& z(%VjZ`_w7h9O#ujJNHHG?SzR-dzZ^e=nXy1yEliuD}}9`(YuO|2YO@u>}GHM9Dn-k z=LhG`J-xoMzD~#9o;|>)K7Vk(XX<{}O^CfAX&*AfnZy#;O+G29)!xvWS?BjaySTEm zy>qR#@@#*7g%dK8P`%;N9Alz=F`k)c#^o1uGBri8@#5EpTfNP;pR6^uMekakc&Xxn z-W)OW^S$Og5hHdzl@s+wf4#r4vYVBK$$DEPK^W+KUi}OgH!kS<@#1Q(PhHe!*DkE6 zVad^?IRxE|^Ty>4DSK?0bJ{sd*R-wGV`i$~jey*{+bD=bh)m~TSC>Y0ldDclF$A5^t0;$_ zWKM?zmzDFmjk4hqj5`P*p!o8IiO0nDA*Pd@25I6Wpv;+OSqV7L=vdZ*gg;HAPlS3YS?cB@QtcCC-c(ebcX{Q- zu?bb~E@W#lNw*T!o=XV<9&z$nHFguqx+)xzEgm!qJU7M6kz^h5B9Zo;?3F4&TfUP$*{eMyvL^!9j`&}iw+weB zegvX9!WN0mf#K(KulcOaQ@a#CS-(>va^9%rRNW!&{|@PB+_8$}b5T-Ng5N29)kfT@ F{{oj;as~hZ diff --git a/languages/resmushit-image-optimizer-it_IT.po b/languages/resmushit-image-optimizer-it_IT.po deleted file mode 100644 index f9172c9..0000000 --- a/languages/resmushit-image-optimizer-it_IT.po +++ /dev/null @@ -1,185 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. -# -msgid "" -msgstr "" -"Project-Id-Version: \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-04-04 13:44+0200\n" -"PO-Revision-Date: 2018-04-04 13:45+0200\n" -"Last-Translator: \n" -"Language-Team: \n" -"Language: it\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.0.2\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: classes/resmushitUI.class.php:90 -msgid "Settings" -msgstr "Configurazioni" - -#: classes/resmushitUI.class.php:97 -msgid "Image quality" -msgstr "Qualità dell'immagine" - -#: classes/resmushitUI.class.php:97 -msgid "" -"Default value is 92. The quality factor must be between 0 (very weak) and " -"100 (best quality)" -msgstr "" -"Il valore di Default è 92. Il fattore qualità deve essere tra 0 (qualità " -"pessima) e 100 (massima qualità)" - -#: classes/resmushitUI.class.php:98 -msgid "Optimize on upload" -msgstr "Ottimizza nella fase di upload" - -#: classes/resmushitUI.class.php:98 -msgid "All future images uploaded will be automatically optimized" -msgstr "" -"Tutte le immagini che in futuro verranno caricate verranno automaticamente " -"ottimizzate" - -#: classes/resmushitUI.class.php:99 -msgid "Enable statistics" -msgstr "Abilita le statistiche" - -#: classes/resmushitUI.class.php:99 -msgid "Generates statistics about optimized pictures" -msgstr "Genera le statistiche in merito alle immagini ottimizzate" - -#: classes/resmushitUI.class.php:100 -msgid "Enable logs" -msgstr "Abilita i logs" - -#: classes/resmushitUI.class.php:100 -msgid "Enable file logging (for developers)" -msgstr "Abilita i file di log (per gli sviluppatori)" - -#: classes/resmushitUI.class.php:120 -msgid "Optimize unsmushed pictures" -msgstr "Ottimizza le immagini" - -#: classes/resmushitUI.class.php:125 -msgid "There is currently" -msgstr "Vi è attualmente" - -#: classes/resmushitUI.class.php:125 -msgid "non optimized pictures" -msgstr "immagini non ottiizzate" - -#: classes/resmushitUI.class.php:126 -msgid "" -"This action will resmush all pictures which have not been optimized to the " -"good Image Quality Rate." -msgstr "" -"Questa azione ottimizzerà tutte le immagini che non sono state " -"precedentemente ottimizzate secondo i Parametri di Qualità d'immagine " -"definiti." - -#: classes/resmushitUI.class.php:128 -msgid "Optimize all pictures" -msgstr "Ottimizza tutte le immagini" - -#: classes/resmushitUI.class.php:134 -msgid "Congrats ! All your pictures are correctly optimized" -msgstr "" -"Congratulazioni ! Tutte le immagini sono state ottimizzate correttamente" - -#: classes/resmushitUI.class.php:155 -msgid "Files non optimized" -msgstr "Files non ottimizzati" - -#: classes/resmushitUI.class.php:162 -msgid "pictures are too big (> 5MB) for the optimizer" -msgstr "immagini troppo grandi (> 5MB) per l'ottimizzatore" - -#: classes/resmushitUI.class.php:164 -msgid "picture is too big (> 5MB) for the optimizer" -msgstr "immagine troppo grande (> 5MB) per l'ottimizzatore" - -#: classes/resmushitUI.class.php:168 -msgid "List of files above 5MB" -msgstr "Elenco dei file che superano i 5MB" - -#: classes/resmushitUI.class.php:197 -msgid "Statistics" -msgstr "Statistiche" - -#: classes/resmushitUI.class.php:204 -msgid "Space saved :" -msgstr "Spazio risparmiato:" - -#: classes/resmushitUI.class.php:205 -msgid "Total reduction :" -msgstr "Riduzione totale" - -#: classes/resmushitUI.class.php:206 -msgid "Attachments optimized :" -msgstr "Allegati ottimizzati:" - -#: classes/resmushitUI.class.php:207 -msgid "Image optimized (including thumbnails) :" -msgstr "Immagine ottimizzata (thumbnails inclusi)" - -#: classes/resmushitUI.class.php:208 -msgid "Total images optimized :" -msgstr "Totale immagini ottimizzate:" - -#: classes/resmushitUI.class.php:210 -msgid "" -"No picture has been optimized yet ! Add pictures to your Wordpress Media " -"Library." -msgstr "" -"Nessuna immagine è stata ancora ottimizzata! Aggiungi immagini alla tua " -"Libreria Media di Wordpress" - -#: classes/resmushitUI.class.php:231 -msgid "News" -msgstr "Novità" - -#: classes/resmushitUI.class.php:265 -msgid "Visit resmush.it for more informations" -msgstr "Visita resmush.it per ottenere più informazioni" - -#: classes/resmushitUI.class.php:268 -msgid "Follow reSmush.it on Twitter" -msgstr "Segui reSmush.it su Twitter" - -#: classes/resmushitUI.class.php:352 -msgid "Optimize" -msgstr "Ottimizza" - -#: classes/resmushitUI.class.php:355 -msgid "Reduced by" -msgstr "Ridotto di" - -#: classes/resmushitUI.class.php:355 -msgid "saved" -msgstr "risparmiati" - -#: resmushit.admin.php:37 resmushit.admin.php:64 -msgid "Disable of reSmush.it" -msgstr "Disabilita reSmush.it" - -#: resmushit.admin.php:38 resmushit.admin.php:71 -msgid "reSmush.it status" -msgstr "stato di reSmush.it" - -#. Plugin Name of the plugin/theme -msgid "reSmush.it Image Optimizer" -msgstr "reSmush.it Image Optimizer" - -#. Plugin URI of the plugin/theme -msgid "http://www.resmush.it" -msgstr "https://resmush.it" - -#. Description of the plugin/theme -msgid "Image Optimization API. Provides image size optimization" -msgstr "" -"Image Optimization API. Fornisce l'ottimizzazione della dimensione " -"dell'immagine" diff --git a/languages/resmushit-image-optimizer-sk_SK.mo b/languages/resmushit-image-optimizer-sk_SK.mo deleted file mode 100644 index 24713a3fc6cdc1062f83518e81c882767a56378f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4092 zcmb7`U2I%O6~_l!Aeiq`pnMcgAOx?H-Pmp@?xs$0;ur#P>c(4BRaK?gd&j%uy?180 zGk47z6^SQ=L|#gfiYisC)K&_r-w+a!Yzfv2LOg=R8xlx>1gH`Zh$kfe=kC3Gy-pA? z^7U_b?tGm2pL6Ey@9w+zdjhS3=VN%nHwke8eErS%hxXz(kKJd=*yk|h(|2yEP zz?VTBP5caG9e)YJRPiV9Iq(he-CzW9J^_9m{5bd$$a>rc`P{z-SrzGWZy{0)7)@9e)nuPy8PLc;CN+ zkTGj)A2)u_HgMy;Snp5b;dMDyIF3GphtJK8*Tr$~+HjoA->gB=PT>Qeh5f>f?O-3= zgNN|&c{tWsZ*F|9_u^sQxUrwP!Sz|=IO4S8T!Rc*+_P^^;^BtS$Qt`cEJqP-r9Mp* z=~%XuqqG}Y8LE(WG~P88$<*6edL76p>XYqy9qU~cie>L*(2kYyuI#0{xNJ=;k?1^0 zyn5fJ33YYAdpMHVD6mPQ0zb9birSKCDkM!v^KX>SvKc9|Ta>5`EYYrMFRqxZb4%k* zWLqt5S~R@(l(>dtu}CZlT-CHaMW0=}B-W$~w9G-vEoFi}RcT!& zaMWrdO`ybewd2HfTNqDm>EI-IsI;Q5JjX;B7K0plJC2X9*d**CJ{+y7P)oX|n~6;N zHIW})O+FB!a5BH_g*4;9ExS_V*wu*SBKpJ)6{Z0?ntidMyoVl6Y;tdsH zE~1aK!cmYSUJc?^G}`!zKx9v3=>d~@k13;Qr>%oF1b}+Ra0vn5|U@n!*C1g3gwbazem5Ur4m26W!QDJK$3ca&z|L?=goXiC& zoSujyuQ*{+Co)F~WWYAAkm}X2x`{l+G3zvQLv?N9t81>M!|J89<*E&f?)AqT)ys*> z#Hg-7<2o(O%`aBx&f|~fAF7{!_{`kG+#Cj0Z>SzLwdU^QJ~tkBO*&s~AnaWvaVOPj zO(uvX8vOuwT%aO)G|oCc@5bM2u5)qbnl!Bx>0E6n8UKG%>f|~zYggBy&2J?> z%DP4Vd0ME=)fQ&fqco9GbrqrH>SVgvSGV-g1sZ=`nl(#H^A&mw*KnO?&Bdh!I(?eV zqf6(xa~_=w7iPrfXrO$jkGmZokPOooG9ylkf7@OD{i(38azF8^KI zQDS#v74D(~*`C#^ z!-H580;f3~pk9rum66+#>W&7JJ!M5~_Pb_y8;g`FAfA?aAIcGnq7{XfaIU6JQkumD zO1-0UZHSySR5a^V8>hPdrQGJWZk$1$!#No3& z#Fm!^F*h8v;b)j%sf#aXZk5FXwkMvpyGF)^Sv`pO%Hhq?V7LccWyk*SH4tUlboyen zuVsjBCzkBuX!7vjKPbxu9qF*`kIaByWBeY{h#oy0L`H2>$LP_4(I{3jf`>|F(xWr; zl9}hp=+!BCI41LCENnae9+?TJwxJwn-Cp^c^`81MaZ??6H_t z2)!dQlg}!WmqpB+k1~5%MICH02`@e^$7ZgJ?eQ;J9)sH|Ee}%10U@Cu?)9)ySx#{q zA^Efn^3uy{=}C<($4$Dp8XqmYYGO%d^pq)LY?STros(UAdX%d^+|PENOwO|8EXC{< owx$T*!riR-@g;8EeF?dZp;L>LSJ54X8o!%x+m%1AOUcB)0pfuIr~m)} diff --git a/languages/resmushit-image-optimizer-sk_SK.po b/languages/resmushit-image-optimizer-sk_SK.po deleted file mode 100644 index 14e92dc..0000000 --- a/languages/resmushit-image-optimizer-sk_SK.po +++ /dev/null @@ -1,181 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. -# -msgid "" -msgstr "" -"Project-Id-Version: \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-04-04 13:46+0200\n" -"PO-Revision-Date: 2018-04-04 13:47+0200\n" -"Last-Translator: Martin Šturcel \n" -"Language-Team: Martin Šturcel \n" -"Language: sk\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.0.2\n" -"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" - -#: classes/resmushitUI.class.php:90 -msgid "Settings" -msgstr "Nastavenia" - -#: classes/resmushitUI.class.php:97 -msgid "Image quality" -msgstr "Kvalita obrázkov" - -#: classes/resmushitUI.class.php:97 -msgid "" -"Default value is 92. The quality factor must be between 0 (very weak) and " -"100 (best quality)" -msgstr "" -"Prednastavená hodnota je 92. Hodnota kvality musí byť v rozmedzí od 0 (veľmi " -"slabá) a 100 (najlepšia kvalita)" - -#: classes/resmushitUI.class.php:98 -msgid "Optimize on upload" -msgstr "Optimalizovať pri nahrávaní" - -#: classes/resmushitUI.class.php:98 -msgid "All future images uploaded will be automatically optimized" -msgstr "Všetky vaše novo pridané obrázky budú automaticky optimalizované" - -#: classes/resmushitUI.class.php:99 -msgid "Enable statistics" -msgstr "Zapnúť štatistiku" - -#: classes/resmushitUI.class.php:99 -msgid "Generates statistics about optimized pictures" -msgstr "Generuje štatistiky o optimalizovaných súboroch" - -#: classes/resmushitUI.class.php:100 -msgid "Enable logs" -msgstr "Zapnúť logovanie" - -#: classes/resmushitUI.class.php:100 -msgid "Enable file logging (for developers)" -msgstr "Zapnúť logovanie do súboru (pre vývojárov)" - -#: classes/resmushitUI.class.php:120 -msgid "Optimize unsmushed pictures" -msgstr "Optimalizácia obrázkov" - -#: classes/resmushitUI.class.php:125 -msgid "There is currently" -msgstr "V súčastnosti" - -#: classes/resmushitUI.class.php:125 -msgid "non optimized pictures" -msgstr "neoptimalizovaných obrázkov" - -#: classes/resmushitUI.class.php:126 -msgid "" -"This action will resmush all pictures which have not been optimized to the " -"good Image Quality Rate." -msgstr "" -"Týmto tlačidlom budú spracované všetky obrázky, ktoré neboli ešte " -"optimalizované nastavenej kvalite." - -#: classes/resmushitUI.class.php:128 -msgid "Optimize all pictures" -msgstr "Optimalizovať všetky obrázky" - -#: classes/resmushitUI.class.php:134 -msgid "Congrats ! All your pictures are correctly optimized" -msgstr "" -"Blahoželáme! Všetky vaše obrázky sú optimalizované podľa aktuáneho " -"nastavenia kvality" - -#: classes/resmushitUI.class.php:155 -msgid "Files non optimized" -msgstr "Súbory ktoré neboli optimalizované" - -#: classes/resmushitUI.class.php:162 -msgid "pictures are too big (> 5MB) for the optimizer" -msgstr "obrázky sú príliš veľké pre optimalizáciu, majú viac ako 5MB" - -#: classes/resmushitUI.class.php:164 -msgid "picture is too big (> 5MB) for the optimizer" -msgstr "obrázok je príliš veľký pre optimalizáciu, má viac ako 5MB" - -#: classes/resmushitUI.class.php:168 -msgid "List of files above 5MB" -msgstr "Zoznam súborov väčších ako 5MB" - -#: classes/resmushitUI.class.php:197 -msgid "Statistics" -msgstr "Štatistika" - -#: classes/resmushitUI.class.php:204 -msgid "Space saved :" -msgstr "Ušetrené miesto:" - -#: classes/resmushitUI.class.php:205 -msgid "Total reduction :" -msgstr "Celkovo ušetrené :" - -#: classes/resmushitUI.class.php:206 -msgid "Attachments optimized :" -msgstr "Optimalizované prílohy:" - -#: classes/resmushitUI.class.php:207 -msgid "Image optimized (including thumbnails) :" -msgstr "Optimalizované obrázky (vrátane náhľadov):" - -#: classes/resmushitUI.class.php:208 -msgid "Total images optimized :" -msgstr "Celkom optimalizvaných obrázkov :" - -#: classes/resmushitUI.class.php:210 -msgid "" -"No picture has been optimized yet ! Add pictures to your Wordpress Media " -"Library." -msgstr "" -"Žiadne obrázky zatiaľ neboli optimalizované. Pridajte obrázky do " -"multimediálnej knižnice alebo optimalizujte obrázky." - -#: classes/resmushitUI.class.php:231 -msgid "News" -msgstr "Novinky" - -#: classes/resmushitUI.class.php:265 -msgid "Visit resmush.it for more informations" -msgstr "Navštívte resmush.it pre viac informácii" - -#: classes/resmushitUI.class.php:268 -msgid "Follow reSmush.it on Twitter" -msgstr "Sledovať reSmush.it na Twitteri" - -#: classes/resmushitUI.class.php:352 -msgid "Optimize" -msgstr "Optimalizovať" - -#: classes/resmushitUI.class.php:355 -msgid "Reduced by" -msgstr "Znížená veľkosť o" - -#: classes/resmushitUI.class.php:355 -msgid "saved" -msgstr "ušetrené" - -#: resmushit.admin.php:37 resmushit.admin.php:64 -msgid "Disable of reSmush.it" -msgstr "Vypnúť reSmush.it" - -#: resmushit.admin.php:38 resmushit.admin.php:71 -msgid "reSmush.it status" -msgstr "Stav reSmush.it" - -#. Plugin Name of the plugin/theme -msgid "reSmush.it Image Optimizer" -msgstr "reSmush.it Image Optimizer" - -#. Plugin URI of the plugin/theme -msgid "http://www.resmush.it" -msgstr "https://resmush.it" - -#. Description of the plugin/theme -msgid "Image Optimization API. Provides image size optimization" -msgstr "Image Optimization API. Poskytuje optimalizáciu veľkosti obrázka" diff --git a/languages/resmushit-image-optimizer.pot b/languages/resmushit-image-optimizer.pot deleted file mode 100644 index 06a735e..0000000 --- a/languages/resmushit-image-optimizer.pot +++ /dev/null @@ -1,305 +0,0 @@ -#, fuzzy -msgid "" -msgstr "" -"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" -"Project-Id-Version: reSmush.it Image Optimizer\n" -"POT-Creation-Date: 2019-12-22 08:03+0100\n" -"PO-Revision-Date: 2018-04-04 13:39+0200\n" -"Last-Translator: \n" -"Language-Team: https://resmush.it\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.2.4\n" -"X-Poedit-Basepath: ..\n" -"X-Poedit-Flags-xgettext: --add-comments=translators:\n" -"X-Poedit-WPHeader: resmushit.php\n" -"X-Poedit-SourceCharset: UTF-8\n" -"X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;" -"esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;" -"_n_noop:1,2;_nx_noop:3c,1,2;__ngettext_noop:1,2\n" -"X-Poedit-SearchPath-0: .\n" -"X-Poedit-SearchPathExcluded-0: *.js\n" - -#: classes/resmushitUI.class.php:90 resmushit.php:269 -msgid "Settings" -msgstr "" - -#: classes/resmushitUI.class.php:91 -msgid "New!" -msgstr "" - -#: classes/resmushitUI.class.php:98 -msgid "Image quality" -msgstr "" - -#: classes/resmushitUI.class.php:98 -msgid "" -"Default value is 92. The quality factor must be between 0 (very weak) and " -"100 (best quality)" -msgstr "" - -#: classes/resmushitUI.class.php:99 -msgid "Optimize on upload" -msgstr "" - -#: classes/resmushitUI.class.php:99 -msgid "All future images uploaded will be automatically optimized" -msgstr "" - -#: classes/resmushitUI.class.php:100 -msgid "Enable statistics" -msgstr "" - -#: classes/resmushitUI.class.php:100 -msgid "Generates statistics about optimized pictures" -msgstr "" - -#: classes/resmushitUI.class.php:101 -msgid "Enable logs" -msgstr "" - -#: classes/resmushitUI.class.php:101 -msgid "Enable file logging (for developers)" -msgstr "" - -#: classes/resmushitUI.class.php:102 -msgid "Process optimize on CRON" -msgstr "" - -#: classes/resmushitUI.class.php:102 -msgid "Will perform image optimization process through CRON tasks" -msgstr "" - -#: classes/resmushitUI.class.php:121 -msgid "Optimize unsmushed pictures" -msgstr "" - -#: classes/resmushitUI.class.php:136 -msgid "non optimized pictures will be automatically optimized" -msgstr "" - -#: classes/resmushitUI.class.php:138 -msgid "" -"These pictures will be automatically optimized using schedule tasks " -"(cronjobs)." -msgstr "" - -#: classes/resmushitUI.class.php:140 -msgid "" -"Image optimization process can be launched manually by clicking on " -"the button below :" -msgstr "" - -#: classes/resmushitUI.class.php:142 -msgid "There is currently" -msgstr "" - -#: classes/resmushitUI.class.php:144 -msgid "non optimized pictures" -msgstr "" - -#: classes/resmushitUI.class.php:146 -msgid "" -"This action will resmush all pictures which have not been optimized to the " -"good Image Quality Rate." -msgstr "" - -#: classes/resmushitUI.class.php:152 -msgid "Optimize all pictures manually" -msgstr "" - -#: classes/resmushitUI.class.php:154 -msgid "Optimize all pictures" -msgstr "" - -#: classes/resmushitUI.class.php:159 -msgid "Congrats ! All your pictures are correctly optimized" -msgstr "" - -#: classes/resmushitUI.class.php:179 -msgid "Files non optimized" -msgstr "" - -#: classes/resmushitUI.class.php:190 -msgid "pictures are too big (> 5MB) for the optimizer" -msgstr "" - -#: classes/resmushitUI.class.php:192 -msgid "picture is too big (> 5MB) for the optimizer" -msgstr "" - -#: classes/resmushitUI.class.php:195 -msgid "List of files above 5MB" -msgstr "" - -#: classes/resmushitUI.class.php:227 -msgid "Statistics" -msgstr "" - -#: classes/resmushitUI.class.php:234 -msgid "Space saved :" -msgstr "" - -#: classes/resmushitUI.class.php:238 -msgid "Total reduction :" -msgstr "" - -#: classes/resmushitUI.class.php:242 -msgid "Attachments optimized :" -msgstr "" - -#: classes/resmushitUI.class.php:248 -msgid "Image optimized (including thumbnails) :" -msgstr "" - -#: classes/resmushitUI.class.php:254 -msgid "Total images optimized :" -msgstr "" - -#: classes/resmushitUI.class.php:259 -msgid "" -"No picture has been optimized yet ! Add pictures to your Wordpress Media " -"Library." -msgstr "" - -#: classes/resmushitUI.class.php:279 -msgid "News" -msgstr "" - -#: classes/resmushitUI.class.php:321 -msgid "Visit resmush.it for more informations" -msgstr "" - -#: classes/resmushitUI.class.php:326 -msgid "Follow reSmush.it on Twitter" -msgstr "" - -#: classes/resmushitUI.class.php:347 -msgid "Important informations" -msgstr "" - -#: classes/resmushitUI.class.php:352 -msgid "Cronjobs seems incorrectly configured" -msgstr "" - -#: classes/resmushitUI.class.php:357 -msgid "" -"Cronjobs are not correctly configured. The variable DISABLE_WP_CRON must be set to TRUE in wp-config.php. Please install " -"them by reading the following instruction page." -msgstr "" - -#: classes/resmushitUI.class.php:359 -msgid "" -"We advice to disable Remush.it option \"Process optimize on CRON\" as long " -"as Cron jobs are incorrectly set up." -msgstr "" - -#: classes/resmushitUI.class.php:363 -msgid "" -"Cronjobs seems to have never been launched. Please install them by reading " -"the following instruction page." -msgstr "" - -#: classes/resmushitUI.class.php:367 -msgid "" -"Cronjobs seems not to have run lately. Please read the following instruction page to install them correctly." -msgstr "" - -#: classes/resmushitUI.class.php:368 -msgid "Expected Frequency :" -msgstr "" - -#: classes/resmushitUI.class.php:368 resmushit.php:299 -msgid "Every" -msgstr "" - -#: classes/resmushitUI.class.php:369 -msgid "Last run :" -msgstr "" - -#: classes/resmushitUI.class.php:369 -msgid "ago" -msgstr "" - -#: classes/resmushitUI.class.php:454 -msgid "Optimize" -msgstr "" - -#: classes/resmushitUI.class.php:457 -msgid "Reduced by" -msgstr "" - -#: classes/resmushitUI.class.php:457 -msgid "saved" -msgstr "" - -#: classes/resmushitUI.class.php:458 -msgid "Force re-optimize" -msgstr "" - -#: resmushit.admin.php:43 resmushit.admin.php:98 -msgid "Disable of reSmush.it" -msgstr "" - -#: resmushit.admin.php:44 resmushit.admin.php:105 -msgid "reSmush.it status" -msgstr "" - -#: resmushit.inc.php:119 -msgid "year" -msgstr "" - -#: resmushit.inc.php:120 -msgid "month" -msgstr "" - -#: resmushit.inc.php:121 -msgid "week" -msgstr "" - -#: resmushit.inc.php:122 -msgid "day" -msgstr "" - -#: resmushit.inc.php:123 -msgid "hour" -msgstr "" - -#: resmushit.inc.php:124 -msgid "minute" -msgstr "" - -#: resmushit.inc.php:125 -msgid "second" -msgstr "" - -#: resmushit.inc.php:136 -msgid "just now" -msgstr "" - -#: resmushit.php:299 -msgid " " -msgstr "" - -#. Plugin Name of the plugin/theme -msgid "reSmush.it Image Optimizer" -msgstr "" - -#. Plugin URI of the plugin/theme -#. Author URI of the plugin/theme -msgid "https://resmush.it" -msgstr "" - -#. Description of the plugin/theme -msgid "Image Optimization API. Provides image size optimization" -msgstr "" - -#. Author of the plugin/theme -msgid "reSmush.it" -msgstr "" diff --git a/resmushit.admin.php b/resmushit.admin.php index a03a6d4..b3d9bbc 100644 --- a/resmushit.admin.php +++ b/resmushit.admin.php @@ -1,191 +1 @@ post_mime_type) ) - return $form_fields; - - $form_fields["rsmt-disabled-checkbox"] = array( - "label" => __("Disable of reSmush.it", "resmushit-image-optimizer"), - "input" => "html", - "value" => '', - "html" => reSmushitUI::mediaListCustomValuesDisable($post->ID, true) - ); - - $form_fields["rsmt-status-button"] = array( - "label" => __("reSmush.it status", "resmushit-image-optimizer"), - "input" => "html", - "value" => '', - "html" => reSmushitUI::mediaListCustomValuesStatus($post->ID, true) - ); - return $form_fields; -} -add_filter("attachment_fields_to_edit", "resmushit_image_attachment_add_status_button", null, 2); - - - -/** -* -* Settings page builder -* -* @param none -* @return none -*/ -function resmushit_settings_page() { - ?> -
-
- - - - - - -
-
- - -
-
- id ) && in_array( $current_page->id, $allowed_pages ) ) { - wp_register_style( 'resmushit-css', plugins_url( 'css/resmushit.css', __FILE__ ) ); - wp_enqueue_style( 'resmushit-css' ); - wp_enqueue_style( 'prefix-style', esc_url_raw( 'https://fonts.googleapis.com/css?family=Roboto+Slab:700' ), array(), null ); - - wp_register_script( 'resmushit-js', plugins_url( 'js/script.js?' . hash_file('crc32', dirname(__FILE__) . '/js/script.js'), __FILE__ ) ); - wp_enqueue_script( 'resmushit-js' ); - } -} -add_action( 'admin_head', 'resmushit_register_plugin_assets' ); - - - -/** -* -* Detect unsmushed files by browsing the library directory -* -* @param none -* @return none -*/ -function detect_unsmushed_files() { - $wp_upload_dir=wp_upload_dir(); - return glob_recursive($wp_upload_dir['basedir'] . '/*-unsmushed.*'); -} diff --git a/resmushit.inc.php b/resmushit.inc.php index b87bad7..97d307e 100644 --- a/resmushit.inc.php +++ b/resmushit.inc.php @@ -6,99 +6,11 @@ if ( defined( 'WP_CLI' ) && WP_CLI ) { require('classes/resmushitWPCLI.class.php'); } -require('resmushit.admin.php'); - +//require('resmushit.admin.php'); /** -* -* Embedded file log function * -* @param string $str text to log in file -* @return none -*/ -function rlog($str, $level = 'SUCCESS') { - global $is_cron; - - if(isset($is_cron) && $is_cron) { - switch ($level) { - case 'WARNING': - $prefix = "[\033[33m!\033[0m]"; break; - case 'ERROR': - $prefix = "[\033[31m!\033[0m]"; break; - default: - case 'SUCCESS': - $prefix = "[\033[32m+\033[0m]"; break; - } - echo esc_html("$prefix $str\n"); - } - - if(get_option('resmushit_logs') == 0) - return FALSE; - - if( !is_writable(ABSPATH) ) { - return FALSE; - } - // Preserve file size under a reasonable value - if(file_exists(ABSPATH . RESMUSHIT_LOGS_PATH)){ - if(filesize(ABSPATH . RESMUSHIT_LOGS_PATH) > RESMUSHIT_LOGS_MAX_FILESIZE) { - $logtailed = logtail(ABSPATH . RESMUSHIT_LOGS_PATH, 20); - $fp = fopen(ABSPATH . RESMUSHIT_LOGS_PATH, 'w'); - fwrite($fp, $logtailed); - fclose($fp); - } - } - - $str = "[".date('d-m-Y H:i:s')."] " . $str; - $str = print_r($str, true) . "\n"; - $fp = fopen(ABSPATH . RESMUSHIT_LOGS_PATH, 'a+'); - fwrite($fp, $str); - fclose($fp); -} - - -/** -* -* Tail function for files -* -* @param string $filepath path of the file to tail -* @param string $lines number of lines to keep -* @param string $adaptative will preserve line memory -* @return tailed file -* @author Torleif Berger, Lorenzo Stanco -* @link http://stackoverflow.com/a/15025877/995958 -* @license http://creativecommons.org/licenses/by/3.0/ -*/ -function logtail($filepath, $lines = 1, $adaptive = true) { - - $f = @fopen($filepath, "rb"); - if ($f === false) return false; - if (!$adaptive) $buffer = 4096; - else $buffer = ($lines < 2 ? 64 : ($lines < 10 ? 512 : 4096)); - fseek($f, -1, SEEK_END); - if (fread($f, 1) != "\n") $lines -= 1; - - $output = ''; - $chunk = ''; - - while (ftell($f) > 0 && $lines >= 0) { - $seek = min(ftell($f), $buffer); - fseek($f, -$seek, SEEK_CUR); - $output = ($chunk = fread($f, $seek)) . $output; - fseek($f, -mb_strlen($chunk, '8bit'), SEEK_CUR); - $lines -= substr_count($chunk, "\n"); - } - - while ($lines++ < 0) { - $output = substr($output, strpos($output, "\n") + 1); - } - fclose($f); - return trim($output); -} - - -/** -* * Calculates time ago * * @param string $datetime time input @@ -109,54 +21,37 @@ function logtail($filepath, $lines = 1, $adaptive = true) { * @link https://stackoverflow.com/questions/1416697/converting-timestamp-to-time-ago-in-php-e-g-1-day-ago-2-days-ago */ function time_elapsed_string($duration, $full = false) { - $datetime = "@" . (time() - $duration); - - $now = new DateTime; - $ago = new DateTime($datetime); - $diff = $now->diff($ago); - - $diff->w = floor($diff->d / 7); - $diff->d -= $diff->w * 7; - - $string = array( - 'y' => __('year', 'resmushit-image-optimizer'), - 'm' => __('month', 'resmushit-image-optimizer'), - 'w' => __('week', 'resmushit-image-optimizer'), - 'd' => __('day', 'resmushit-image-optimizer'), - 'h' => __('hour', 'resmushit-image-optimizer'), - 'i' => __('minute', 'resmushit-image-optimizer'), - 's' => __('second', 'resmushit-image-optimizer'), - ); - foreach ($string as $k => &$v) { - if ($diff->$k) { - $v = $diff->$k . ' ' . $v . ($diff->$k > 1 ? 's' : ''); - } else { - unset($string[$k]); - } - } + $datetime = "@" . (time() - $duration); + + $now = new DateTime; + $then = new DateTime( $datetime ); + $diff = (array) $now->diff( $then ); + + $diff['w'] = floor( $diff['d'] / 7 ); + $diff['d'] -= $diff['w'] * 7; + + $string = array( + 'y' => 'year', + 'm' => 'month', + 'w' => 'week', + 'd' => 'day', + 'h' => 'hour', + 'i' => 'minute', + 's' => 'second', + ); + + foreach( $string as $k => & $v ) + { + if ( $diff[$k] ) + { + $v = $diff[$k] . ' ' . $v .( $diff[$k] > 1 ? 's' : '' ); + } + else + { + unset( $string[$k] ); + } + } if (!$full) $string = array_slice($string, 0, 1); return $string ? implode(', ', $string) : __('just now', 'resmushit-image-optimizer'); } - - -/** -* -* Find recursively files based on pattern -* -* @param string $pattern file search -* @param boolean $flags -* @return array -* @author Mike -* @link https://www.php.net/manual/en/function.glob.php#106595 -*/ -function glob_recursive($pattern, $flags = 0) { - $files = glob($pattern, $flags); - - foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) - { - $files = array_merge($files, glob_recursive($dir.'/'.basename($pattern), $flags)); - } - - return $files; -} diff --git a/resmushit.php b/resmushit.php index d7010c4..0df5090 100644 --- a/resmushit.php +++ b/resmushit.php @@ -21,25 +21,46 @@ * Text Domain: resmushit-image-optimizer */ -require('resmushit.inc.php'); +require('resmushit.inc.php'); + +define( 'RESMUSH_PLUGIN_VERSION', '0.5'); +define( 'RESMUSH_PLUGIN_FILE', __FILE__ ); +define( 'RESMUSH_PLUGIN_PATH', plugin_dir_path(__FILE__) ); + + +// The Real stuff +require_once(RESMUSH_PLUGIN_PATH . 'build/shortpixel/autoload.php'); + +$loader = new \Resmush\Build\PackageLoader(); +$loader->setComposerFile(RESMUSH_PLUGIN_PATH . 'classes/plugin.json'); +$loader->load(RESMUSH_PLUGIN_PATH); + + +\Resmush\Plugin::checkLogger(); + +function Resmush() +{ + return \Resmush\Plugin::getInstance(); +} + +Resmush(); /** -* +* * Registering language plugin * * @param none * @return none */ +/* function resmushit_load_plugin_textdomain() { load_plugin_textdomain( 'resmushit', FALSE, plugin_basename( dirname( __FILE__ ) ) . '/languages' ); } add_action( 'plugins_loaded', 'resmushit_load_plugin_textdomain' ); - - - +*/ /** -* +* * Registering settings on plugin installation * * @param none @@ -77,527 +98,43 @@ function resmushit_activate() { add_action( 'admin_init', 'resmushit_activate' ); -/** - * Run using the 'init' action. - */ -function resmushit_init() { - load_plugin_textdomain( 'resmushit-image-optimizer', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' ); -} -add_action( 'admin_init', 'resmushit_init' ); - - -/** -* -* Call resmush.it optimization for attachments -* -* @param attachment object -* @param boolean preserve original file -* @return attachment object -*/ -function resmushit_process_images($attachments, $force_keep_original = TRUE) { - global $attachment_id; - $cumulated_original_sizes = 0; - $cumulated_optimized_sizes = 0; - $error = FALSE; - - if(reSmushit::getDisabledState($attachment_id)) - return $attachments; - - if(empty($attachments)) { - rlog("Error! Attachment #$attachment_id has no corresponding file on disk.", 'WARNING'); - return $attachments; - } - - $fileInfo = pathinfo(get_attached_file( $attachment_id )); - if(!isset($fileInfo['dirname'])) { - rlog("Error! Incorrect file provided." . print_r($fileInfo, TRUE), 'WARNING'); - return $attachments; - } - $basepath = $fileInfo['dirname'] . '/'; - $extension = isset($fileInfo['extension']) ? $fileInfo['extension'] : NULL; - - // Optimize only pictures/files accepted by the API - if( !in_array(strtolower($extension), resmushit::authorizedExtensions()) ) { - return $attachments; - } - - if(!isset($attachments[ 'file' ])) { - rlog("Error! Incorrect attachment " . print_r($attachments, TRUE), 'WARNING'); - return $attachments; - } - $basefile = basename($attachments[ 'file' ]); - - - - $statistics[] = reSmushit::optimize($basepath . $basefile, $force_keep_original ); - - if(!isset($attachments[ 'sizes' ])) { - rlog("Error! Unable to find attachments sizes." . print_r($attachments, TRUE), 'WARNING'); - return $attachments; - } - foreach($attachments['sizes'] as $image_style) { - $statistics[] = reSmushit::optimize($basepath . $image_style['file'], FALSE ); - } - - $count = 0; - foreach($statistics as $stat){ - if($stat && !isset($stat->error)){ - $cumulated_original_sizes += $stat->src_size; - $cumulated_optimized_sizes += $stat->dest_size; - $count++; - } else { - $error = TRUE; - } - } - if(!$error) { - $optimizations_successful_count = get_option('resmushit_total_optimized'); - update_option( 'resmushit_total_optimized', $optimizations_successful_count + $count ); - update_post_meta($attachment_id,'resmushed_quality', resmushit::getPictureQualitySetting()); - update_post_meta($attachment_id,'resmushed_cumulated_original_sizes', $cumulated_original_sizes); - update_post_meta($attachment_id,'resmushed_cumulated_optimized_sizes', $cumulated_optimized_sizes); - } - return $attachments; -} -//Automatically optimize images if option is checked -if(get_option('resmushit_on_upload') OR ( isset($_POST['action']) AND ($_POST['action'] === "resmushit_bulk_process_image" OR $_POST['action'] === "resmushit_optimize_single_attachment" )) OR (defined( 'WP_CLI' ) && WP_CLI ) OR ($is_cron) ) - add_filter('wp_generate_attachment_metadata', 'resmushit_process_images'); - - - - - - -/** -* -* Delete also -unsmushed file (ie. Original file) when deleting an attachment -* -* @param int postID -* @return none -*/ -function resmushit_delete_attachment($postid) { - reSmushit::deleteOriginalFile($postid); -} -add_action( 'delete_attachment', 'resmushit_delete_attachment' ); - - - - - -/** -* -* Make current attachment available -* -* @param attachment object -* @return attachment object -*/ -function resmushit_get_meta_id($result){ - global $attachment_id; - $attachment_id = $result; -} -//Automatically retrieve image attachment ID if option is checked -if(get_option('resmushit_on_upload')) - add_filter('add_attachment', 'resmushit_get_meta_id'); - - - - - -/** -* -* add Ajax action to fetch all unsmushed pictures -* -* @param none -* @return json object -*/ -function resmushit_bulk_get_images() { - if ( !isset($_REQUEST['csrf']) || ! wp_verify_nonce( $_REQUEST['csrf'], 'bulk_resize' ) ) { - wp_send_json(json_encode(array('error' => 'Invalid CSRF token'))); - die(); - } - if(!is_super_admin() && !current_user_can('administrator')) { - wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); - die(); - } - wp_send_json(reSmushit::getNonOptimizedPictures()); - die(); -} -add_action( 'wp_ajax_resmushit_bulk_get_images', 'resmushit_bulk_get_images' ); - - - /** -* -* add Ajax action to change disabled state for an attachment * -* @param none -* @return json object -*/ -function resmushit_update_disabled_state() { - if ( !isset($_REQUEST['data']['csrf']) || ! wp_verify_nonce( $_REQUEST['data']['csrf'], 'single_attachment' ) ) { - wp_send_json(json_encode(array('error' => 'Invalid CSRF token'))); - die(); - } - if(!is_super_admin() && !current_user_can('administrator')) { - wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); - die(); - } - if(isset($_POST['data']['id']) && $_POST['data']['id'] != null && isset($_POST['data']['disabled'])){ - echo wp_kses_post(reSmushit::updateDisabledState(sanitize_text_field((int)$_POST['data']['id']), sanitize_text_field($_POST['data']['disabled']))); - } - die(); -} -add_action( 'wp_ajax_resmushit_update_disabled_state', 'resmushit_update_disabled_state' ); - - - - - -/** -* -* add Ajax action to optimize a single attachment in the library -* -* @param none -* @return json object -*/ -function resmushit_optimize_single_attachment() { - if ( !isset($_REQUEST['data']['csrf']) || ! wp_verify_nonce( $_REQUEST['data']['csrf'], 'single_attachment' ) ) { - wp_send_json(json_encode(array('error' => 'Invalid CSRF token'))); - die(); - } - if(!is_super_admin() && !current_user_can('administrator')) { - wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); - die(); - } - if(isset($_POST['data']['id']) && $_POST['data']['id'] != null){ - reSmushit::revert(sanitize_text_field((int)$_POST['data']['id'])); - wp_send_json(json_encode(reSmushit::getStatistics(sanitize_text_field((int)$_POST['data']['id'])))); - } - die(); -} -add_action( 'wp_ajax_resmushit_optimize_single_attachment', 'resmushit_optimize_single_attachment' ); - - - - - -/** -* -* add Ajax action to optimize a picture according to attachment ID -* -* @param none -* @return boolean -*/ -function resmushit_bulk_process_image() { - if ( !isset($_REQUEST['csrf']) || ! wp_verify_nonce( $_REQUEST['csrf'], 'bulk_process_image' ) ) { - wp_send_json(json_encode(array('error' => 'Invalid CSRF token'))); - die(); - } - if(!is_super_admin() && !current_user_can('administrator')) { - wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); - die(); - } - rlog('Bulk optimization launched for file : ' . get_attached_file( sanitize_text_field((int)$_POST['data']['ID']) )); - echo esc_html(reSmushit::revert(sanitize_text_field((int)$_POST['data']['ID']))); - die(); -} -add_action( 'wp_ajax_resmushit_bulk_process_image', 'resmushit_bulk_process_image' ); - - - - - -/** -* -* add Ajax action to update statistics -* -* @param none -* @return json object -*/ -function resmushit_update_statistics() { - if ( !isset($_REQUEST['csrf']) || ! wp_verify_nonce( $_REQUEST['csrf'], 'bulk_process_image' ) ) { - wp_send_json(json_encode(array('error' => 'Invalid CSRF token'))); - die(); - } - if(!is_super_admin() && !current_user_can('administrator')) { - wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); - die(); - } - $output = reSmushit::getStatistics(); - $output['total_saved_size_formatted'] = reSmushitUI::sizeFormat($output['total_saved_size']); - wp_send_json(json_encode($output)); - die(); -} -add_action( 'wp_ajax_resmushit_update_statistics', 'resmushit_update_statistics' ); - - - - - -/** - * add 'Settings' link to options page from Plugins - * @param array $links - * @return string - */ -function resmushit_add_plugin_page_settings_link($links) { - if(is_string($links)) { - $oneLink = $links; - $links = array(); - $links[] = $oneLink; - } - $links[] = '' . __('Settings', "resmushit-image-optimizer") . ''; - return $links; -} -add_filter('plugin_action_links_'.plugin_basename(__FILE__), 'resmushit_add_plugin_page_settings_link'); - - - -/** - * Trigger when the cron are activated for the first time - * @param mixed old value for cron_activation option - * @param mixed new value for cron_activation option - */ - -function resmushit_on_cron_activation($old_value, $value) { - if($value == 1 && (!get_option('resmushit_cron_firstactivation') || get_option('resmushit_cron_firstactivation') === 0)) { - update_option( 'resmushit_cron_firstactivation', time() ); - } -} -add_action('update_option_resmushit_cron', 'resmushit_on_cron_activation', 100, 2); - - - -/** - * Declare a new time interval to run Cron - * @param array $schedules - * @return array - */ -function resmushit_add_cron_interval( $schedules ) { - $schedules['resmushit_interval'] = array( - 'interval' => RESMUSHIT_CRON_FREQUENCY, - 'display' => esc_html__( __('Every', 'resmushit-image-optimizer') . ' ' . time_elapsed_string(RESMUSHIT_CRON_FREQUENCY) ), - ); - return $schedules; -} -add_filter( 'cron_schedules', 'resmushit_add_cron_interval' ); - -if(!get_option('resmushit_cron') || get_option('resmushit_cron') === 0) { - if (wp_next_scheduled ( 'resmushit_optimize' )) { - wp_clear_scheduled_hook('resmushit_optimize'); - } -} else { - if (! wp_next_scheduled ( 'resmushit_optimize' )) { - wp_schedule_event(time(), 'resmushit_interval', 'resmushit_optimize'); - } -} - - - -/** - * Declare a new crontask for optimization bulk - */ -function resmushit_cron_process() { - global $is_cron; - $is_cron = TRUE; - - if((time() - get_option('resmushit_cron_lastaction')) < RESMUSHIT_CRON_TIMEOUT) { - rlog('Another CRON process is running, process aborted.', 'WARNING'); - return FALSE; - } - update_option( 'resmushit_cron_lastrun', time() ); - update_option( 'resmushit_cron_lastaction', time() ); - - // required if launch through wp-cron.php - include_once( ABSPATH . 'wp-admin/includes/image.php' ); - - add_filter('wp_generate_attachment_metadata', 'resmushit_process_images'); - rlog('Gathering unoptimized pictures from CRON'); - $unoptimized_pictures = json_decode(reSmushit::getNonOptimizedPictures(TRUE)); - rlog('Found ' . count($unoptimized_pictures->nonoptimized) . ' attachments'); - - foreach($unoptimized_pictures->nonoptimized as $el) { - if (wp_next_scheduled ( 'resmushit_optimize' )) { - //avoid to collapse two crons - wp_unschedule_event(wp_next_scheduled('resmushit_optimize'), 'resmushit_optimize'); - } - rlog('CRON Processing attachments #' . $el->ID); - update_option( 'resmushit_cron_lastaction', time() ); - reSmushit::revert((int)$el->ID); - } -} -add_action('resmushit_optimize', 'resmushit_cron_process'); - - - -/** - * Return the RESMUSHIT CRON status according to last_execution variables - * @return string - */ -function resmushit_get_cron_status() { - if(get_option('resmushit_cron') == 0) { - return 'DISABLED'; - } - if(!defined('DISABLE_WP_CRON') OR DISABLE_WP_CRON == false) { - return 'MISCONFIGURED'; - } - - if(get_option('resmushit_cron_lastrun') == 0 && (time() - get_option('resmushit_cron_firstactivation') > 2*RESMUSHIT_CRON_FREQUENCY)) { - return 'NEVER_RUN'; - } - if(get_option('resmushit_cron_lastrun') != 0 && (time() - get_option('resmushit_cron_lastrun') > 2*RESMUSHIT_CRON_FREQUENCY)) { - return 'NO_LATELY_RUN'; - } - return 'OK'; -} - - -/** - * Trigger when the cron are activated for the first time - * @param mixed old value for cron_activation option - * @param mixed new value for cron_activation option - */ - -function resmushit_on_remove_unsmushed_change($old_value, $value) { - $old_value = (boolean)$old_value; - $value = (boolean)$value; - if($old_value == $value) { - return TRUE; - } else { - //if remove backup is activated - if($value === TRUE) { - if(!resmushit::hasAlreadyRunOnce()) { - update_option( 'resmushit_has_no_backup_files', 1); - } else { - update_option( 'resmushit_has_no_backup_files', 0); - } - } else { - update_option( 'resmushit_has_no_backup_files', 0); - } - } -} -add_action('update_option_resmushit_remove_unsmushed', 'resmushit_on_remove_unsmushed_change', 100, 2); - - - - -/** -* -* add Ajax action to remove backups (-unsmushed) of the filesystem -* -* @param none -* @return json object -*/ -function resmushit_remove_backup_files() { - $return = array('success' => 0); - if ( !isset($_REQUEST['csrf']) || ! wp_verify_nonce( $_REQUEST['csrf'], 'remove_backup' ) ) { - wp_send_json(json_encode(array('error' => 'Invalid CSRF token'))); - die(); - } - if(!is_super_admin() && !current_user_can('administrator')) { - wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); - die(); - } - - $files=detect_unsmushed_files(); - - foreach($files as $f) { - if(unlink($f)) { - $return['success']++; - } - } - update_option( 'resmushit_has_no_backup_files', 1); - wp_send_json(json_encode($return)); - - die(); -} -add_action( 'wp_ajax_resmushit_remove_backup_files', 'resmushit_remove_backup_files' ); - - -/** -* -* retrieve Attachment ID from Path -* from : https://pippinsplugins.com/retrieve-attachment-id-from-image-url/ -* -* @param imageURL -* @return json object -*/ -function resmushit_get_image_id($image_url) { - global $wpdb; - $attachment = $wpdb->get_col($wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE guid='%s';", $image_url )); - return $attachment[0]; -} - -/** -* -* add Ajax action to restore backups (-unsmushed) from the filesystem -* -* @param none -* @return json object -*/ -function resmushit_restore_backup_files() { - if ( !isset($_REQUEST['csrf']) || ! wp_verify_nonce( $_REQUEST['csrf'], 'restore_library' ) ) { - wp_send_json(json_encode(array('error' => 'Invalid CSRF token'))); - die(); - } - if(!is_super_admin() && !current_user_can('administrator')) { - wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); - die(); - } - $files=detect_unsmushed_files(); - $return = array('success' => 0); - $wp_upload_dir=wp_upload_dir(); - - foreach($files as $f) { - $dest = str_replace('-unsmushed', '', $f); - $pictureURL = str_replace($wp_upload_dir['basedir'], $wp_upload_dir['baseurl'], $dest); - $attachementID = resmushit_get_image_id($pictureURL); - - if(reSmushit::revert($attachementID, true)) { - if(unlink($f)) { - $return['success']++; - } - } - } - wp_send_json(json_encode($return)); - die(); -} -add_action( 'wp_ajax_resmushit_restore_backup_files', 'resmushit_restore_backup_files' ); - - -/** -* * add Ajax action to close permanently notice * * @param none * @return json object */ +/* function resmushit_notice_close() { - $return = FALSE; - if ( !isset($_REQUEST['csrf']) || ! wp_verify_nonce( $_REQUEST['csrf'], 'notice_close' ) ) { - wp_send_json(json_encode(array('error' => 'Invalid CSRF token'))); - die(); - } - if(!is_super_admin() && !current_user_can('administrator')) { - wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); - die(); - } - if(update_option( 'resmushit_notice_close_eoldec23', 1 )) { - $return = TRUE; - } - wp_send_json(json_encode(array('status' => $return))); - die(); -} + $return = FALSE; + if ( !isset($_REQUEST['csrf']) || ! wp_verify_nonce( $_REQUEST['csrf'], 'notice_close' ) ) { + wp_send_json(json_encode(array('error' => 'Invalid CSRF token'))); + die(); + } + if(!is_super_admin() && !current_user_can('administrator')) { + wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); + die(); + } + if(update_option( 'resmushit_notice_close_eoldec23', 1 )) { + $return = TRUE; + } + wp_send_json(json_encode(array('status' => $return))); + die(); +} add_action( 'wp_ajax_resmushit_notice_close', 'resmushit_notice_close' ); - +*/ /** -* +* * add Notice information for Shortpixel offer * * @param none * @return json object */ -function resmushit_general_admin_notice(){ +/* +function resmushit_general_admin_notice(){ // Expired offer if(time() > strtotime("31 December 2023")) { return FALSE; @@ -608,13 +145,13 @@ function resmushit_general_admin_notice(){ } $allowed_pages = array( 'media_page_resmushit_options', - 'dashboard', - 'upload', + 'dashboard', + 'upload', 'plugins', 'edit-post', 'media', 'attachment'); - + if ( function_exists( 'get_current_screen' ) ) { $current_page = get_current_screen(); } @@ -625,7 +162,7 @@ function resmushit_general_admin_notice(){

🫶Thanks a lot! reSmush.it will continue for now!

First, we'd really like to thank members of the community who have supported us by participating to the patreon. As you may know, over the last months, the cost of servers has increased and we were not able to maintain this service without the community's help. reSmush.it has been provided for FREE during 7 years

-

As we're getting very close to the target, we're able to preserve reSmush.it for now. However, we still need your financial support to enhance new features on reSmush.it, such as faster servers, webp and next generations format support and new exciting features!

+

As we're getting very close to the target, we're able to preserve reSmush.it for now. However, we still need your financial support to enhance new features on reSmush.it, such as faster servers, webp and next generations format support and new exciting features!

So, we're kindly asking our community to participate for those who haven't, in order to preserve blazing fast images optimizations for everyone !

Your help will be deeply appreciated to continue this fabulous adventure! 🚀

@@ -633,19 +170,9 @@ function resmushit_general_admin_notice(){

Charles, founder of reSmush.it

- +
"; } - } add_action('admin_notices', 'resmushit_general_admin_notice'); - - -/** -* -* Declares WPCLI extension if in WP_CLI context -* */ -if( defined( 'WP_CLI' ) && WP_CLI ) { - WP_CLI::add_command( 'resmushit', 'reSmushitWPCLI' ); -} From 698927f2e66299d9a8f21ea710d12d249fe1e295 Mon Sep 17 00:00:00 2001 From: Bas Schuiling Date: Mon, 19 Feb 2024 15:42:50 +0200 Subject: [PATCH 02/21] javacript translations --- classes/Controller/AdminController.php | 21 +++++++++++++++++++++ classes/resmushit.class.php | 2 +- js/script.js | 26 ++++++++++++-------------- 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/classes/Controller/AdminController.php b/classes/Controller/AdminController.php index 5343c24..7f8527d 100644 --- a/classes/Controller/AdminController.php +++ b/classes/Controller/AdminController.php @@ -208,7 +208,28 @@ public function register_plugin_assets(){ wp_enqueue_style( 'prefix-style', esc_url_raw( 'https://fonts.googleapis.com/css?family=Roboto+Slab:700' ), array(), null ); wp_register_script( 'resmushit-js', plugins_url( 'js/script.js?' . hash_file('crc32', RESMUSH_PLUGIN_PATH . '/js/script.js'), RESMUSH_PLUGIN_FILE ) ); + + $translations = array( + 'restore_all_confirm' => __("You're about to restore ALL your original image files. Are you sure to perform this operation ?", "resmushit-image-optimizer"), + 'images_restored' => __('images successfully restored', "resmushit-image-optimizer"), + 'backupfiles_removed' => __('backup files successfully removed', "resmushit-image-optimizer"), + 'remove_backup_confirm' => __("You're about to delete your image backup files. Are you sure to perform this operation ?", "resmushit-image-optimizer"), + 'removing_backups' => __('Removing backups...', "resmushit-image-optimizer"), + 'reduced_by' => __('Reduced by', "resmushit-image-optimizer"), + 'optimizing' => __('Optimizing...', "resmushit-image-optimizer"), + 'attachments_found' => __('attachment(s) found, starting optimization...', "resmushit-image-optimizer"), + 'no_attachments_found' => __('There are no existing attachments that requires optimization.', "resmushit-image-optimizer"), + 'examing_attachments' => __('Examining existing attachments. This may take a few moments...', "resmushit-image-optimizer"), + 'picture_too_big' => __('picture(s) cannot be optimized (> 5MB). All others have been optimized', "resmushit-image-optimizer"), + 'error_webservice' => __('An error occured when contacting webservice. Please try again later.', "resmushit-image-optimizer"), + + ); + wp_enqueue_script( 'resmushit-js' ); + + wp_localize_script('resmushit-js', 'reSmush', array( + 'strings' => $translations, + )); } } diff --git a/classes/resmushit.class.php b/classes/resmushit.class.php index 8713de8..1730bfc 100644 --- a/classes/resmushit.class.php +++ b/classes/resmushit.class.php @@ -471,7 +471,7 @@ protected static function glob_recursive($pattern, $flags = 0) { public static function resmushit_get_image_id($image_url) { global $wpdb; $attachment = $wpdb->get_col($wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE guid='%s';", $image_url )); -Log::addTEmp('Attachmnet', $attachment); +Log::addTemp('Attachment', $attachment); if (! isset($attachment[0])) { return false; diff --git a/js/script.js b/js/script.js index b7fc955..6e34db2 100644 --- a/js/script.js +++ b/js/script.js @@ -90,14 +90,12 @@ function resmushit_bulk_process(bulk, item){ resmushit_bulk_process(bulk, item + 1); else{ if(error_occured){ - jQuery('.non-optimized-wrapper h3').text('An error occured when contacting webservice. Please try again later.'); + jQuery('.non-optimized-wrapper h3').text(reSmush.strings.error_webservice); jQuery('.non-optimized-wrapper > p').remove(); jQuery('.non-optimized-wrapper > div').remove(); } else if(file_too_big_count){ - var message = file_too_big_count + ' picture cannot be optimized (> 5MB). All others have been optimized'; - if(file_too_big_count > 1) - var message = file_too_big_count + ' pictures cannot be optimized (> 5MB). All others have been optimized'; + var message = file_too_big_count + ' ' . reSmush.strings.picture_too_big; jQuery('.non-optimized-wrapper h3').text(message); jQuery('.non-optimized-wrapper > p').remove(); @@ -123,7 +121,7 @@ function resmushit_bulk_resize(container_id, csrf_token) { jQuery('#bulk-resize-examine-button').fadeOut(200); var target = jQuery('#bulk_resize_target'); - target.html('

Examining existing attachments. This may take a few moments...
'); + target.html('

' + reSmush.strings.examing_attachments + '
'); target.animate( { height: [100,'swing'] }, @@ -138,12 +136,12 @@ function resmushit_bulk_resize(container_id, csrf_token) { target.html('
' + images.error + '.
'); } else if (images.hasOwnProperty('nonoptimized') && images.nonoptimized.length > 0) { bulkTotalimages = images.nonoptimized.length; - target.html('

' + bulkTotalimages + ' attachment(s) found, starting optimization...
'); + target.html('

' + bulkTotalimages + ' ' + reSmush.strings.attachments_found + '
'); flag_removed = false; //start treating all pictures resmushit_bulk_process(images.nonoptimized, 0); } else { - target.html('
There are no existing attachments that requires optimization.
'); + target.html('
' + reSmush.strings.no_attachments_found + '
'); } } ); @@ -220,7 +218,7 @@ function optimizeSingleAttachment() { jQuery(document).delegate(".rsmt-trigger--optimize-attachment","mouseup",function(e){ e.preventDefault(); var current = this; - jQuery(current).val('Optimizing...'); + jQuery(current).val(reSmush.strings.optimizing); jQuery(current).prop('disabled', true); var disabledState = jQuery(current).is(':checked'); var postID = jQuery(current).attr('data-attachment-id'); @@ -233,7 +231,7 @@ function optimizeSingleAttachment() { }, function(response) { var statistics = JSON.parse(response); - jQuery(current).parent().empty().append('Reduced by ' + statistics.total_saved_size_nice + ' (' + statistics.percent_reduction + ' saved)'); + jQuery(current).parent().empty().append(reSmush.strings.reduced_by + ' ' + statistics.total_saved_size_nice + ' (' + statistics.percent_reduction + ' saved)'); } ); }); @@ -245,11 +243,11 @@ function optimizeSingleAttachment() { */ function removeBackupFiles() { jQuery(document).delegate(".rsmt-trigger--remove-backup-files","mouseup",function(e){ - if ( confirm( "You're about to delete your image backup files. Are you sure to perform this operation ?" ) ) { + if ( confirm( reSmush.strings.remove_backup_confirm ) ) { e.preventDefault(); var current = this; - jQuery(current).val('Removing backups...'); + jQuery(current).val( reSmush.strings.removing_backups); jQuery(current).prop('disabled', true); var csrf_token = jQuery(current).attr('data-csrf'); jQuery.post( @@ -259,7 +257,7 @@ function removeBackupFiles() { }, function(response) { var data = JSON.parse(response); - jQuery(current).val(data.success + ' backup files successfully removed'); + jQuery(current).val(data.success + ' ' + reSmush.strings.backupfiles_removed); setTimeout(function(){ jQuery(current).parent().parent().slideUp() }, 3000); } ); @@ -273,7 +271,7 @@ function removeBackupFiles() { */ function restoreBackupFiles() { jQuery(document).delegate(".rsmt-trigger--restore-backup-files","mouseup",function(e){ - if ( confirm( "You're about to restore ALL your original image files. Are you sure to perform this operation ?" ) ) { + if ( confirm( reSmush.strings.restore_all_confirm) ) { e.preventDefault(); var current = this; @@ -287,7 +285,7 @@ function restoreBackupFiles() { }, function(response) { var data = JSON.parse(response); - jQuery(current).val(data.success + ' images successfully restored'); + jQuery(current).val(data.success + ' ' + reSmush.strings.images_restored ); } ); } From 971fba1f2163154c053ced083ba807f4ffc122ee Mon Sep 17 00:00:00 2001 From: Bas Schuiling Date: Mon, 19 Feb 2024 17:53:05 +0200 Subject: [PATCH 03/21] - Restore images made functional again - media libr. screen some UI fixes --- classes/Controller/AdminController.php | 40 ++++++++++++++++++------ classes/Controller/AjaxController.php | 16 ++++++++-- classes/Controller/ProcessController.php | 7 +++++ classes/resmushit.class.php | 1 + classes/resmushitUI.class.php | 6 ++-- css/resmush_admin.css | 3 ++ css/resmush_admin.css.map | 1 + css/resmush_media.css | 7 +++++ css/resmush_media.css.map | 1 + scss/resmush_admin.scss | 0 scss/resmush_media.scss | 10 ++++++ 11 files changed, 77 insertions(+), 15 deletions(-) create mode 100644 css/resmush_admin.css create mode 100644 css/resmush_admin.css.map create mode 100644 css/resmush_media.css create mode 100644 css/resmush_media.css.map create mode 100644 scss/resmush_admin.scss create mode 100644 scss/resmush_media.scss diff --git a/classes/Controller/AdminController.php b/classes/Controller/AdminController.php index 7f8527d..919bba1 100644 --- a/classes/Controller/AdminController.php +++ b/classes/Controller/AdminController.php @@ -188,7 +188,7 @@ public function settings_page() { * @return none */ public function register_plugin_assets(){ - $allowed_pages = array( + /*$allowed_pages = array( // 'media_page_resmushit_options', 'settings_page_resmushit_options', 'upload', @@ -198,14 +198,24 @@ public function register_plugin_assets(){ 'edit-post', 'media', 'attachment'); + */ + $admin_pages = array( + 'settings_page_resmushit_options', + ); + + $media_pages = array( + 'upload', + 'post', + 'attachment', + 'media' + ); - if ( function_exists( 'get_current_screen' ) ) { $current_page = get_current_screen(); - } - if ( isset( $current_page->id ) && in_array( $current_page->id, $allowed_pages ) ) { + wp_register_style( 'resmushit-css', plugins_url( 'css/resmushit.css', RESMUSH_PLUGIN_FILE ) ); - wp_enqueue_style( 'resmushit-css' ); - wp_enqueue_style( 'prefix-style', esc_url_raw( 'https://fonts.googleapis.com/css?family=Roboto+Slab:700' ), array(), null ); + + wp_register_style('resmushit-admin-css', plugins_url('css/resmush_admin.css', RESMUSH_PLUGIN_FILE)); + wp_register_style('resmushit-media-css', plugins_url('css/resmush_media.css', RESMUSH_PLUGIN_FILE)); wp_register_script( 'resmushit-js', plugins_url( 'js/script.js?' . hash_file('crc32', RESMUSH_PLUGIN_PATH . '/js/script.js'), RESMUSH_PLUGIN_FILE ) ); @@ -224,13 +234,23 @@ public function register_plugin_assets(){ 'error_webservice' => __('An error occured when contacting webservice. Please try again later.', "resmushit-image-optimizer"), ); - - wp_enqueue_script( 'resmushit-js' ); - wp_localize_script('resmushit-js', 'reSmush', array( 'strings' => $translations, )); - } + + //Admin + if (in_array( $current_page->id, $admin_pages ) ) { + + wp_enqueue_script( 'resmushit-js' ); + wp_enqueue_style( 'resmushit-css' ); + wp_enqueue_style('resmushit-admin-css'); + wp_enqueue_style( 'prefix-style', esc_url_raw( 'https://fonts.googleapis.com/css?family=Roboto+Slab:700' ), array(), null ); + } + elseif (in_array( $current_page->id, $media_pages ) ) + { + wp_enqueue_script('resmushit-js'); + wp_enqueue_style('resmushit-media-css'); + } } /** diff --git a/classes/Controller/AjaxController.php b/classes/Controller/AjaxController.php index ad8bd4d..3c758d9 100644 --- a/classes/Controller/AjaxController.php +++ b/classes/Controller/AjaxController.php @@ -203,6 +203,9 @@ public function restore_backup_files() { $return = array('success' => 0); $wp_upload_dir=wp_upload_dir(); + $processController = ProcessController::getInstance(); + $processController->unHookProcessor(); + Log::addTemp('Detect Files', $files); foreach($files as $f) { $dest = str_replace('-unsmushed', '', $f); @@ -211,8 +214,17 @@ public function restore_backup_files() { if (false === $attachment_id) { - Log::addWarn('Restoring - no attachmentID for this URL '. $pictureURL); - continue; + Log::addTemp('First Try failed - '. $pictureURL); + if (strpos($pictureURL, '-scaled') !== false) + { + $pictureURL = str_replace('-scaled', '', $pictureURL); + $attachment_id = reSmushit::resmushit_get_image_id($pictureURL); + if (false === $attachment_id) + { + Log::addWarn('Restoring - no attachmentID for this URL '. $pictureURL); + continue; + } + } } if(reSmushit::revert($attachment_id, true)) { diff --git a/classes/Controller/ProcessController.php b/classes/Controller/ProcessController.php index 42efc8f..1f627bd 100644 --- a/classes/Controller/ProcessController.php +++ b/classes/Controller/ProcessController.php @@ -46,6 +46,13 @@ protected function initHooks() } } + public function unHookProcessor() + { + Log::addTemp('Unhooking Process Filter'); + remove_filter('wp_generate_attachment_metadata', array($this,'process_images') ); + + } + /** * * Delete also -unsmushed file (ie. Original file) when deleting an attachment diff --git a/classes/resmushit.class.php b/classes/resmushit.class.php index 1730bfc..edd6732 100644 --- a/classes/resmushit.class.php +++ b/classes/resmushit.class.php @@ -474,6 +474,7 @@ public static function resmushit_get_image_id($image_url) { Log::addTemp('Attachment', $attachment); if (! isset($attachment[0])) { + return false; } return $attachment[0]; diff --git a/classes/resmushitUI.class.php b/classes/resmushitUI.class.php index e27fafb..154c7b2 100644 --- a/classes/resmushitUI.class.php +++ b/classes/resmushitUI.class.php @@ -573,11 +573,11 @@ public static function mediaListCustomValuesStatus($attachment_id, $return = fal $output = '-'; } else if(reSmushit::getAttachmentQuality($attachment_id) != reSmushit::getPictureQualitySetting()) - $output = ''; + $output = ''; else{ $statistics = reSmushit::getStatistics($attachment_id); - $output = __('Reduced by', 'resmushit-image-optimizer') . " ". $statistics['total_saved_size_nice'] ." (". $statistics['percent_reduction'] . ' ' . __('saved', 'resmushit-image-optimizer') . ")"; - $output .= '

'; + $output = __('Reduced by', 'resmushit-image-optimizer') . " ". $statistics['total_saved_size_nice'] ."
(". $statistics['percent_reduction'] . ' ' . __('saved', 'resmushit-image-optimizer') . ")"; + $output .= '

'; } if($return) diff --git a/css/resmush_admin.css b/css/resmush_admin.css new file mode 100644 index 0000000..908c480 --- /dev/null +++ b/css/resmush_admin.css @@ -0,0 +1,3 @@ + + +/*# sourceMappingURL=resmush_admin.css.map */ diff --git a/css/resmush_admin.css.map b/css/resmush_admin.css.map new file mode 100644 index 0000000..fc4d5fd --- /dev/null +++ b/css/resmush_admin.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":[],"names":[],"mappings":"","file":"resmush_admin.css"} \ No newline at end of file diff --git a/css/resmush_media.css b/css/resmush_media.css new file mode 100644 index 0000000..9af2df2 --- /dev/null +++ b/css/resmush_media.css @@ -0,0 +1,7 @@ +.column-resmushit_status button.button { + max-width: 100%; + margin: 5px 0; + white-space: unset; +} + +/*# sourceMappingURL=resmush_media.css.map */ diff --git a/css/resmush_media.css.map b/css/resmush_media.css.map new file mode 100644 index 0000000..1842e21 --- /dev/null +++ b/css/resmush_media.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["../scss/resmush_media.scss"],"names":[],"mappings":"AAGG;EACG;EACA;EACA","file":"resmush_media.css"} \ No newline at end of file diff --git a/scss/resmush_admin.scss b/scss/resmush_admin.scss new file mode 100644 index 0000000..e69de29 diff --git a/scss/resmush_media.scss b/scss/resmush_media.scss new file mode 100644 index 0000000..3743c43 --- /dev/null +++ b/scss/resmush_media.scss @@ -0,0 +1,10 @@ + +.column-resmushit_status +{ + button.button { + max-width: 100%; + margin: 5px 0; + white-space: unset; + + } +} From d1ab43f93b0429d6decf819bd6a64cf97facf560 Mon Sep 17 00:00:00 2001 From: Bas Schuiling Date: Mon, 19 Feb 2024 18:55:31 +0200 Subject: [PATCH 04/21] Tab-layout with selector and feedback --- classes/Controller/AdminController.php | 36 +++++++++++++--- classes/Controller/AjaxController.php | 7 ++++ classes/resmushitUI.class.php | 10 +++++ css/resmush_admin.css | 25 ++++++++++- css/resmush_admin.css.map | 2 +- css/resmushit.css | 58 +++++++++++++++++--------- js/script.js | 44 +++++++++++++++++++ resmushit.settings.php | 3 +- scss/resmush_admin.scss | 38 +++++++++++++++++ 9 files changed, 194 insertions(+), 29 deletions(-) diff --git a/classes/Controller/AdminController.php b/classes/Controller/AdminController.php index 919bba1..4f8ddb8 100644 --- a/classes/Controller/AdminController.php +++ b/classes/Controller/AdminController.php @@ -161,19 +161,41 @@ public function image_attachment_add_status_button($form_fields, $post) { */ public function settings_page() { ?> -
-
+
+
+
+
+
+ + + +
-
- - -
+ + + + + +
+

ADS

+
Feedback form

'; + echo wp_kses_post($html); + self::fullWidthPanelEndWrapper(); + + } + /** * diff --git a/css/resmush_admin.css b/css/resmush_admin.css index 908c480..e6eb20c 100644 --- a/css/resmush_admin.css +++ b/css/resmush_admin.css @@ -1,3 +1,26 @@ - +.resmush-settings-ui .nav-block { + background: #fff; +} +.resmush-settings-ui .nav-block .rsmt-tabs-nav { + list-style: none; + margin-top: 50px; +} +.resmush-settings-ui .nav-block .rsmt-tabs-nav li { + font-weight: 700; + background: #fff; + cursor: pointer; + text-align: left; + font-size: 16px; + margin: 10px 0; + padding-left: 30px; +} +.resmush-settings-ui .nav-block .rsmt-tabs-nav li.active { + background-color: rgb(26, 189, 202); + color: #fff; +} +.resmush-settings-ui .nav-block .rsmt-tabs-nav li a { + text-decoration: none; + color: #3c434a; +} /*# sourceMappingURL=resmush_admin.css.map */ diff --git a/css/resmush_admin.css.map b/css/resmush_admin.css.map index fc4d5fd..7a4aa62 100644 --- a/css/resmush_admin.css.map +++ b/css/resmush_admin.css.map @@ -1 +1 @@ -{"version":3,"sourceRoot":"","sources":[],"names":[],"mappings":"","file":"resmush_admin.css"} \ No newline at end of file +{"version":3,"sourceRoot":"","sources":["../scss/resmush_admin.scss"],"names":[],"mappings":"AAIE;EAEE;;AAEA;EAIG;EACA;;AAEA;EACG;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;EACA;;AAGF;EACI;EACA","file":"resmush_admin.css"} \ No newline at end of file diff --git a/css/resmushit.css b/css/resmushit.css index 1645876..29dc52f 100644 --- a/css/resmushit.css +++ b/css/resmushit.css @@ -16,46 +16,64 @@ .rsmt-panels .w100{ width: 100%; } + .rsmt-panels .w75{ + flex-basis: 75%; + } .rsmt-panels .w66{ flex-basis: 66%; } + .rsmt-panels .w60{ + flex-basis: 60%; + } + .rsmt-panels .w50{ + flex-basis: 50%; + } .rsmt-panels .w33{ flex-basis: 33%; } - .rsmt-panels .brdr-green{ + .rsmt-panels .w30{ + flex-basis: 30%; + } + .rsmt-panels .w25{ + flex-basis: 25%; + } + .rsmt-panels .w10{ + flex-basis: 10%; + } + .rsmt-panels .brdr-green{ border-left: 4px solid #277F72 - } - .rsmt-panels .brdr-blue{ + } + .rsmt-panels .brdr-blue{ border-left: 4px solid #5A8BA8 - } - .rsmt-panels .brdr-orange{ + } + .rsmt-panels .brdr-orange{ border-left: 4px solid #DFC02A - } - .rsmt-panels .brdr-red{ + } + .rsmt-panels .brdr-red{ border-left: 4px solid #9E2F29 - } - .rsmt-panels .brdr-grey{ + } + .rsmt-panels .brdr-grey{ border-left: 4px solid #a2a2a2 - } - .rsmt-panels .brdr-black{ + } + .rsmt-panels .brdr-black{ border-left: 4px solid #222222 - } - .rsmt-panels .brdr-dashed{ + } + .rsmt-panels .brdr-dashed{ border: 2px dashed #7cd7e5; padding: 5px 10px; - } + } .rsmt-notice .no-uppercase, .rsmt-panels .no-uppercase { text-transform: none; } .rsmt-notice h4, - .rsmt-panels h2{ + .rsmt-panels h2{ text-transform: uppercase; font-family: 'Roboto Slab', serif; font-size: 1.5em; color:#4B4B4B; } - .rsmt-notice h4{ + .rsmt-notice h4{ text-transform: uppercase; font-family: 'Roboto Slab', serif; font-size: 1.5em; @@ -231,7 +249,7 @@ .rsmt-bigfiles ul{ margin-left:10px; } - + .rsmt-bigfiles ul li *{ display: inline-block; vertical-align: middle; @@ -263,11 +281,11 @@ -moz-box-sizing: border-box; box-sizing: border-box; background: #F4F4F4; - } + } .rsmt-news h3{ margin: 5px 0 3px; font-size: 1.2em; - } + } .rsmt-news h3 a{ text-decoration: none; } @@ -311,4 +329,4 @@ input[type=checkbox].rsmt-disable-loader{ .rsmt-panels{ flex-direction:column; } -} \ No newline at end of file +} diff --git a/js/script.js b/js/script.js index 6e34db2..b9b7aed 100644 --- a/js/script.js +++ b/js/script.js @@ -50,6 +50,50 @@ jQuery( ".list-accordion h4" ).on('click', function(){ } }); +// NAVIGATION + + +function ChangePanelEvent(event) +{ + event.preventDefault(); + var target = event.target; + var tabTarget = target.dataset.tab; + + // This can be done better if something was decided. + var tabNavs = document.querySelectorAll('.rsmt-tabs-nav li'); + for (var i = 0; i < tabNavs.length; i++) + { + tabNavs[i].classList.remove('active'); + if (tabNavs[i].dataset.tab == tabTarget) + { + tabNavs[i].classList.add('active'); + } + } + + var searchClass = 'rsmt-tab-' + tabTarget; + + // Hide everything else. + var tabs = document.querySelectorAll('.rsmt-tab'); + for (var i = 0; i < tabs.length; i++) + { + tabs[i].style.display = 'none'; + tabs[i].classList.remove('active'); + if (tabs[i].classList.contains(searchClass)) + { + tabs[i].style.display = 'block'; + tabs[i].classList.add('active'); + } + } + +} + +var tabNavs = document.querySelectorAll('.rsmt-tabs-nav li'); +for (var i = 0; i < tabNavs.length; i++) +{ + if (tabNavs[i].dataset.tab !== undefined) + tabNavs[i].addEventListener('click', ChangePanelEvent); +} + updateDisabledState(); optimizeSingleAttachment(); removeBackupFiles(); diff --git a/resmushit.settings.php b/resmushit.settings.php index b45fe47..fabf5e8 100644 --- a/resmushit.settings.php +++ b/resmushit.settings.php @@ -7,8 +7,9 @@ define('RESMUSHIT_LOGS_PATH', 'resmushit.log'); define('RESMUSHIT_LOGS_MAX_FILESIZE', '102400'); define('RESMUSHIT_NEWSFEED', 'https://feed.resmush.it/'); +define('RESMUSHIT_FEEDBACK_URL', 'https://resmush.it/contact/'); define('RESMUSHIT_BASE_URL', plugin_dir_url( __FILE__ )); define('RESMUSHIT_CRON_FREQUENCY', 600); define('RESMUSHIT_CRON_TIMEOUT', 60); -global $is_cron; \ No newline at end of file +global $is_cron; diff --git a/scss/resmush_admin.scss b/scss/resmush_admin.scss index e69de29..fb0a3ca 100644 --- a/scss/resmush_admin.scss +++ b/scss/resmush_admin.scss @@ -0,0 +1,38 @@ +// Main settings UI +.resmush-settings-ui +{ + // Tabular navigation + .nav-block + { + background: #fff; + + .rsmt-tabs-nav + { + // width: 50%; +// display: block; + list-style: none; + margin-top: 50px; + + li { + font-weight: 700; + background: #fff; + cursor: pointer; + text-align: left; + font-size:16px; + margin: 10px 0; + padding-left: 30px; + &.active { + background-color: rgb(26, 189, 202); + color: #fff; + + } + a { + text-decoration: none; + color: #3c434a; + } + } + } + + } + +} From 7235bc956e7e2aa0cfb39557bd0446f93c09cee2 Mon Sep 17 00:00:00 2001 From: Bas Schuiling Date: Tue, 20 Feb 2024 10:20:57 +0200 Subject: [PATCH 05/21] Single restore functionality, restore button --- classes/Controller/AdminController.php | 2 ++ classes/Controller/AjaxController.php | 30 ++++++++++++++++++++++- classes/resmushitUI.class.php | 6 ++++- css/resmush_media.css | 2 ++ css/resmush_media.css.map | 2 +- js/script.js | 33 +++++++++++++++++++++++++- scss/resmush_media.scss | 3 ++- 7 files changed, 73 insertions(+), 5 deletions(-) diff --git a/classes/Controller/AdminController.php b/classes/Controller/AdminController.php index 4f8ddb8..03ffc38 100644 --- a/classes/Controller/AdminController.php +++ b/classes/Controller/AdminController.php @@ -254,6 +254,8 @@ public function register_plugin_assets(){ 'examing_attachments' => __('Examining existing attachments. This may take a few moments...', "resmushit-image-optimizer"), 'picture_too_big' => __('picture(s) cannot be optimized (> 5MB). All others have been optimized', "resmushit-image-optimizer"), 'error_webservice' => __('An error occured when contacting webservice. Please try again later.', "resmushit-image-optimizer"), + 'restoring' => __('Restoring...', 'resmushit-image-optimizer'), + '' ); wp_localize_script('resmushit-js', 'reSmush', array( diff --git a/classes/Controller/AjaxController.php b/classes/Controller/AjaxController.php index 0cfd0a9..60c4009 100644 --- a/classes/Controller/AjaxController.php +++ b/classes/Controller/AjaxController.php @@ -33,6 +33,7 @@ protected function initHooks() add_action( 'wp_ajax_resmushit_bulk_get_images', array($this,'bulk_get_images') ); add_action( 'wp_ajax_resmushit_update_disabled_state', array($this,'update_disabled_state') ); add_action( 'wp_ajax_resmushit_optimize_single_attachment', array($this,'optimize_single_attachment') ); + add_action( 'wp_ajax_resmushit_restore_single_attachment', array($this,'restore_single_attachment') ); add_action( 'wp_ajax_resmushit_update_statistics', array($this,'update_statistics') ); add_action( 'wp_ajax_resmushit_remove_backup_files', array($this, 'remove_backup_files') ); add_action( 'wp_ajax_resmushit_restore_backup_files', array($this, 'restore_backup_files') ); @@ -127,6 +128,34 @@ public function optimize_single_attachment() { die(); } + /** + * + * add Ajax action to optimize a single attachment in the library + * + * @param none + * @return json object + */ + public function restore_single_attachment() { + if ( !isset($_REQUEST['data']['csrf']) || ! wp_verify_nonce( $_REQUEST['data']['csrf'], 'single_attachment' ) ) { + wp_send_json(json_encode(array('error' => 'Invalid CSRF token'))); + die(); + } + if(!is_super_admin() && !current_user_can('administrator')) { + wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); + die(); + } + $processController = ProcessController::getInstance(); + $processController->unHookProcessor(); + + + if(isset($_POST['data']['id']) && $_POST['data']['id'] != null){ + reSmushit::revert(sanitize_text_field((int)$_POST['data']['id'])); + + $response = array('status' => true, 'message' => __('Item restored', 'resmushit-image-optimizer')); + wp_send_json($response); + } + die(); + } /** @@ -206,7 +235,6 @@ public function restore_backup_files() { $processController = ProcessController::getInstance(); $processController->unHookProcessor(); -Log::addTemp('Detect Files', $files); foreach($files as $f) { $dest = str_replace('-unsmushed', '', $f); $pictureURL = str_replace($wp_upload_dir['basedir'], $wp_upload_dir['baseurl'], $dest); diff --git a/classes/resmushitUI.class.php b/classes/resmushitUI.class.php index 1d0b09e..b08ed97 100644 --- a/classes/resmushitUI.class.php +++ b/classes/resmushitUI.class.php @@ -587,7 +587,11 @@ public static function mediaListCustomValuesStatus($attachment_id, $return = fal else{ $statistics = reSmushit::getStatistics($attachment_id); $output = __('Reduced by', 'resmushit-image-optimizer') . " ". $statistics['total_saved_size_nice'] ."
(". $statistics['percent_reduction'] . ' ' . __('saved', 'resmushit-image-optimizer') . ")"; - $output .= '

'; + + $output .= '

'; + + $output .= '

'; + } if($return) diff --git a/css/resmush_media.css b/css/resmush_media.css index 9af2df2..493a641 100644 --- a/css/resmush_media.css +++ b/css/resmush_media.css @@ -1,7 +1,9 @@ .column-resmushit_status button.button { max-width: 100%; + width: 80%; margin: 5px 0; white-space: unset; + box-sizing: border-box; } /*# sourceMappingURL=resmush_media.css.map */ diff --git a/css/resmush_media.css.map b/css/resmush_media.css.map index 1842e21..cbd36d3 100644 --- a/css/resmush_media.css.map +++ b/css/resmush_media.css.map @@ -1 +1 @@ -{"version":3,"sourceRoot":"","sources":["../scss/resmush_media.scss"],"names":[],"mappings":"AAGG;EACG;EACA;EACA","file":"resmush_media.css"} \ No newline at end of file +{"version":3,"sourceRoot":"","sources":["../scss/resmush_media.scss"],"names":[],"mappings":"AAGG;EACG;EACA;EACA;EACA;EACA","file":"resmush_media.css"} \ No newline at end of file diff --git a/js/script.js b/js/script.js index b9b7aed..2c43256 100644 --- a/js/script.js +++ b/js/script.js @@ -59,7 +59,7 @@ function ChangePanelEvent(event) var target = event.target; var tabTarget = target.dataset.tab; - // This can be done better if something was decided. + // This can be done better if something was decided. var tabNavs = document.querySelectorAll('.rsmt-tabs-nav li'); for (var i = 0; i < tabNavs.length; i++) { @@ -96,6 +96,7 @@ for (var i = 0; i < tabNavs.length; i++) updateDisabledState(); optimizeSingleAttachment(); +restoreSingleAttachment(); removeBackupFiles(); restoreBackupFiles(); @@ -281,6 +282,36 @@ function optimizeSingleAttachment() { }); } +function restoreSingleAttachment() +{ + jQuery(document).on('click', ".rsmt-trigger--restore-attachment",function(e){ + e.preventDefault(); + var current = this; + jQuery(current).val(reSmush.strings.restoring); + jQuery(current).prop('disabled', true); + var disabledState = jQuery(current).is(':checked'); + var postID = jQuery(current).attr('data-attachment-id'); + var csrf_token = jQuery(current).attr('data-csrf'); + + jQuery.post( + ajaxurl, { + action: 'resmushit_restore_single_attachment', + data: {id: postID, csrf: csrf_token} + }, + function(response) { + // var statistics = JSON.parse(response); + // jQuery(current).parent().empty().append(reSmush.strings.reduced_by + ' ' + statistics.total_saved_size_nice + ' (' + statistics.percent_reduction + ' saved)'); + var message = 'Restored'; + if (response.message) + { + message = response.message; + } + + jQuery(current).parent().empty().append(message); + } + ); + }); +} /** * ajax to Optimize a single picture diff --git a/scss/resmush_media.scss b/scss/resmush_media.scss index 3743c43..0937e59 100644 --- a/scss/resmush_media.scss +++ b/scss/resmush_media.scss @@ -3,8 +3,9 @@ { button.button { max-width: 100%; + width: 80%; margin: 5px 0; white-space: unset; - + box-sizing: border-box; } } From 005fb95adf263e43da684461fdbca92b7d2648b3 Mon Sep 17 00:00:00 2001 From: Pedro Dobrescu Date: Tue, 20 Feb 2024 18:00:31 +0200 Subject: [PATCH 06/21] Update wording --- classes/resmushit.class.php | 22 +- classes/resmushitUI.class.php | 76 ++-- classes/resmushitWPCLI.class.php | 22 +- js/script.js | 591 ++++++++++++++--------------- readme.txt | 622 +++++++++++++++---------------- resmushit.admin.php | 4 +- resmushit.php | 21 +- 7 files changed, 679 insertions(+), 679 deletions(-) diff --git a/classes/resmushit.class.php b/classes/resmushit.class.php index 90efe16..86feaf6 100644 --- a/classes/resmushit.class.php +++ b/classes/resmushit.class.php @@ -26,7 +26,7 @@ public static function authorizedExtensions() { /** * - * Optimize a picture according to a filepath. + * Optimize an image according to a filepath. * * @param string $file_path the path to the file on the server * @return bool TRUE if the resmush operation worked @@ -44,7 +44,7 @@ public static function getPictureQualitySetting() { /** * - * Optimize a picture according to a filepath. + * Optimize an image according to a filepath. * * @param string $file_path the path to the file on the server * @return bool TRUE if the resmush operation worked @@ -250,7 +250,7 @@ public static function getStatistics($attachment_id = null){ $output['percent_reduction'] = 0; else $output['percent_reduction'] = 100*round(($total_original_size - $total_optimized_size)/$total_original_size,4) . ' %'; - //number of thumbnails + original picture + //number of thumbnails + original image $output['files_optimized'] = sizeof($optimized_sizes); $output['files_optimized_with_thumbnails'] = sizeof($optimized_sizes) * (sizeof(get_intermediate_image_sizes()) + 1); @@ -266,10 +266,10 @@ public static function getStatistics($attachment_id = null){ /** * - * Get the count of all pictures + * Get the count of all images * * @param none - * @return json of unsmushed pictures attachments ID + * @return json of unsmushed image attachment IDs */ public static function getCountAllPictures(){ global $wpdb; @@ -297,10 +297,10 @@ public static function getCountAllPictures(){ /** * - * Get a list of non optimized pictures + * Get a list of unoptimized images * * @param none - * @return json of unsmushed pictures attachments ID + * @return json of unsmushed image attachment IDs */ public static function getNonOptimizedPictures($id_only = FALSE){ global $wpdb; @@ -352,7 +352,7 @@ public static function getNonOptimizedPictures($id_only = FALSE){ $files_not_found[] = $tmp; continue; } - //If filesize > 5MB, we do not optimize this picture + //If filesize > 5MB, we do not optimize this image if( filesize(get_attached_file( $image->ID )) > self::MAX_FILESIZE ){ $files_too_big[] = $tmp; continue; @@ -366,10 +366,10 @@ public static function getNonOptimizedPictures($id_only = FALSE){ /** * - * Return the number of non optimized pictures + * Return the number of unoptimized images * * @param none - * @return number of non optimized pictures to the current quality factor + * @return number of unoptimized images to the current quality factor */ public static function getCountNonOptimizedPictures(){ $data = json_decode(self::getNonOptimizedPictures()); @@ -420,7 +420,7 @@ public static function getDisabledState($attachment_id){ /** * - * Get Last Quality Factor attached to a picture + * Get Last Quality Factor attached to an image * * @param int $attachment_id Post ID * @return int quality setting for this attachment diff --git a/classes/resmushitUI.class.php b/classes/resmushitUI.class.php index d14c593..ea52982 100644 --- a/classes/resmushitUI.class.php +++ b/classes/resmushitUI.class.php @@ -126,13 +126,13 @@ public static function settingsPanel() { echo wp_kses('' - . self::addSetting("text", __("Image quality", 'resmushit-image-optimizer'), __("Default value is 92. The quality factor must be between 0 (very weak) and 100 (best quality)", 'resmushit-image-optimizer'), "resmushit_qlty") - . self::addSetting("checkbox", __("Optimize on upload", 'resmushit-image-optimizer'), __("All future images uploaded will be automatically optimized", 'resmushit-image-optimizer'), "resmushit_on_upload") - . self::addSetting("checkbox", __("Enable statistics", 'resmushit-image-optimizer'), __("Generates statistics about optimized pictures", 'resmushit-image-optimizer'), "resmushit_statistics") - . self::addSetting("checkbox", __("Enable logs", 'resmushit-image-optimizer'), __("Enable file logging (for developers)", 'resmushit-image-optimizer'), "resmushit_logs") - . self::addSetting("checkbox", $new_label . __("Process optimize on CRON", 'resmushit-image-optimizer'), __("Will perform image optimization process through CRON tasks", 'resmushit-image-optimizer'), "resmushit_cron") - . self::addSetting("checkbox", $new_label . __("Preserve EXIF", 'resmushit-image-optimizer'), __("Will preserve EXIF data during optimization", 'resmushit-image-optimizer'), "resmushit_preserve_exif") - . self::addSetting("checkbox", $new_label . __("Do not preserve backups", 'resmushit-image-optimizer'), sprintf(__("Will not preserve a backup of the original file (save space). Read instructions carefully before enabling.", 'resmushit-image-optimizer'), 'https://resmush.it/wordpress/why-keeping-backup-files'), "resmushit_remove_unsmushed") + . self::addSetting("text", __("Image quality", 'resmushit-image-optimizer'), __("A lower value means a smaller image size, a higher value means better image quality. A value between 50 and 85 is normally recommended.", 'resmushit-image-optimizer'), "resmushit_qlty") + . self::addSetting("checkbox", __("Optimize on upload", 'resmushit-image-optimizer'), __("Once activated, newly uploaded images are automatically optimized.", 'resmushit-image-optimizer'), "resmushit_on_upload") + . self::addSetting("checkbox", $new_label . __("Preserve EXIF", 'resmushit-image-optimizer'), __("Activate this option to retain the original EXIF data in the images.", 'resmushit-image-optimizer'), "resmushit_preserve_exif") + . self::addSetting("checkbox", $new_label . __("Deactivate backup", 'resmushit-image-optimizer'), sprintf(__("If you select this option, you choose not to keep the original version of the images. This is helpful to save disk space, but we strongly recommend having a backup of the entire website on hand. More information.", "resmushit-image-optimizer"), "https://resmush.it/why-preserving-backup-files/"), "resmushit_remove_unsmushed") + . self::addSetting("checkbox", $new_label . __("Optimize images using CRON", 'resmushit-image-optimizer'), sprintf(__("Image optimization is performed automatically via CRON tasks. More information", 'resmushit-image-optimizer'), 'https://resmush.it/how-to-configure-cronjobs/'), "resmushit_cron") + . self::addSetting("checkbox", __("Activate logs", 'resmushit-image-optimizer'), sprintf(__("Activate logging in a file. Useful for debugging/developers. More information", 'resmushit-image-optimizer'), 'https://resmush.it/features/'), "resmushit_logs") + . self::addSetting("checkbox", __("Activate statistics", 'resmushit-image-optimizer'), __("Generates statistics about optimized images.", 'resmushit-image-optimizer'), "resmushit_statistics") . '
', $allowed_html); submit_button(); echo wp_kses('
', $allowed_html); @@ -151,7 +151,7 @@ public static function settingsPanel() { public static function bulkPanel() { $dataCountNonOptimizedPictures = reSmushit::getCountNonOptimizedPictures(); $countNonOptimizedPictures = $dataCountNonOptimizedPictures['nonoptimized']; - self::fullWidthPanelWrapper(__('Optimize unsmushed pictures', 'resmushit-image-optimizer'), null, 'blue'); + self::fullWidthPanelWrapper(__('Optimize Media Library', 'resmushit-image-optimizer'), null, 'blue'); $additionnalClassNeedOptimization = NULL; $additionnalClassNoNeedOptimization = 'disabled'; @@ -166,17 +166,17 @@ public static function bulkPanel() { if(get_option('resmushit_cron') && get_option('resmushit_cron') == 1) { echo wp_kses_post("$countNonOptimizedPictures " - . __('non optimized pictures will be automatically optimized', 'resmushit-image-optimizer') + . __('unoptimized images are automatically optimized', 'resmushit-image-optimizer') . ".

" - . __('These pictures will be automatically optimized using schedule tasks (cronjobs).', 'resmushit-image-optimizer') + . __('These images are automatically optimized using scheduled tasks (cronjobs).', 'resmushit-image-optimizer') . " " - . __('Image optimization process can be launched manually by clicking on the button below :', 'resmushit-image-optimizer')); + . __('You can also start the image optimization manually by clicking on the button below:', 'resmushit-image-optimizer')); } else { - echo wp_kses_post(__('There is currently', 'resmushit-image-optimizer') + echo wp_kses_post(__('There are currently', 'resmushit-image-optimizer') . " $countNonOptimizedPictures " - . __('non optimized pictures', 'resmushit-image-optimizer') + . __('images that need optimization', 'resmushit-image-optimizer') . ".

" - . __('This action will resmush all pictures which have not been optimized to the good Image Quality Rate.', 'resmushit-image-optimizer')); + . __('This action resmushes all images that have not yet been optimized with the image quality specified in the settings. If the image quality has been changed and backups are activated, images that have already been optimized are resmushed with the new image quality rate.', 'resmushit-image-optimizer')); } $allowed_html = array_merge(wp_kses_allowed_html( 'post' ), array( @@ -188,14 +188,14 @@ public static function bulkPanel() { echo wp_kses("

" . "

" - . __('Congrats ! All your pictures are correctly optimized', 'resmushit-image-optimizer') + . __('Congratulations! All your images are optimized correctly!', 'resmushit-image-optimizer') . "

"); self::fullWidthPanelEndWrapper(); } @@ -215,7 +215,7 @@ public static function bigFilesPanel() { if(!$countfilesTooBigPictures) return false; - self::fullWidthPanelWrapper(__('Files non optimized', 'resmushit-image-optimizer'), null, 'grey'); + self::fullWidthPanelWrapper(__('Unoptimized images', 'resmushit-image-optimizer'), null, 'grey'); $additionnalClass = NULL; if(!$countfilesTooBigPictures) { @@ -226,12 +226,12 @@ public static function bigFilesPanel() {

"); if($countfilesTooBigPictures > 1) { - echo esc_html($countfilesTooBigPictures . ' ' . __('pictures are too big (> 5MB) for the optimizer', 'resmushit-image-optimizer')); + echo esc_html($countfilesTooBigPictures . ' ' . __('images are too large (>5MB) to be optimized', 'resmushit-image-optimizer')); } else { - echo esc_html($countfilesTooBigPictures . ' ' . __('picture is too big (> 5MB) for the optimizer', 'resmushit-image-optimizer')); + echo esc_html($countfilesTooBigPictures . ' ' . __('image is too large (>5MB) to be optimized', 'resmushit-image-optimizer')); } echo wp_kses_post("

" - . __('List of files above 5MB', 'resmushit-image-optimizer') + . __('List of images above 5MB', 'resmushit-image-optimizer') . "

    "); foreach($getNonOptimizedPictures->filestoobig as $file){ @@ -270,32 +270,32 @@ public static function statisticsPanel() { if($resmushit_stat['files_optimized'] != 0) { echo wp_kses_post("

    " - . __('Space saved :', 'resmushit-image-optimizer') + . __('Storage saved:', 'resmushit-image-optimizer') . " " . self::sizeFormat($resmushit_stat['total_saved_size']) . "

    " - . __('Total reduction :', 'resmushit-image-optimizer') + . __('Total reduction:', 'resmushit-image-optimizer') . " " . $resmushit_stat['percent_reduction'] . "

    " - . __('Attachments optimized :', 'resmushit-image-optimizer') + . __('Attachments optimized:', 'resmushit-image-optimizer') . " " . $resmushit_stat['files_optimized'] . "/" . $resmushit_stat['total_pictures'] . "

    " - . __('Image optimized (including thumbnails) :', 'resmushit-image-optimizer') + . __('Optimized images (including thumbnails):', 'resmushit-image-optimizer') . " " . $resmushit_stat['files_optimized_with_thumbnails'] . "/" . $resmushit_stat['total_pictures_with_thumbnails'] . "

    " - . __('Total images optimized :', 'resmushit-image-optimizer') + . __('Total optimized images:', 'resmushit-image-optimizer') . " " . $resmushit_stat['total_optimizations'] . "

    "); } else { - echo wp_kses_post("

    " . __('No picture has been optimized yet ! Add pictures to your Wordpress Media Library.', 'resmushit-image-optimizer') . "

    "); + echo wp_kses_post("

    " . __('No image has been optimized yet! Add images to your WordPress\' Media Library.', 'resmushit-image-optimizer') . "

    "); } echo wp_kses_post("
"); self::fullWidthPanelEndWrapper(); @@ -325,9 +325,9 @@ public static function restorePanel() { echo wp_kses("
" . '

' - . __('Warning! By clicking the button below, you will restore all the original pictures, as before reSmush.it Image Optimizer installation. You will not have your pictures optimized! We strongly advice to be sure to have a complete backup of your website before performing this action', 'resmushit-image-optimizer') + . __('Warning! By clicking the button below, all original images will revert to the state they were in before they were optimized with reSmush.it Image Optimizer!', 'resmushit-image-optimizer') . '

' - . '' + . '' . '

', $allowed_html); self::fullWidthPanelEndWrapper(); } @@ -389,7 +389,7 @@ public static function newsPanel() { . __('No user data nor any information is collected while requesting this news feed.', 'resmushit-image-optimizer') . "

" . "" @@ -418,28 +418,28 @@ public static function alertPanel() { return TRUE; } - self::fullWidthPanelWrapper(__('Important informations', 'resmushit-image-optimizer'), null, 'red'); + self::fullWidthPanelWrapper(__('Important information', 'resmushit-image-optimizer'), null, 'red'); if(resmushit_get_cron_status() != 'DISABLED' && resmushit_get_cron_status() != 'OK') { echo wp_kses_post("

" . "

" - . __('Cronjobs seems incorrectly configured', 'resmushit-image-optimizer') + . __('Cronjobs are not configured correctly', 'resmushit-image-optimizer') . "

"); if (resmushit_get_cron_status() == 'MISCONFIGURED') { echo wp_kses_post("

" - . __('Cronjobs are not correctly configured. The variable DISABLE_WP_CRON must be set to TRUE in wp-config.php. Please install them by reading the following instruction page.', 'resmushit-image-optimizer') + . __('Cronjobs are not configured correctly. The variable DISABLE_WP_CRON should be set to TRUE in wp-config.php. Please configure them using the following documentation.', 'resmushit-image-optimizer') . "

" - . __('We advice to disable Remush.it option "Process optimize on CRON" as long as Cron jobs are incorrectly set up.', 'resmushit-image-optimizer') + . __('We recommend deactivating the option "Optimize images using CRON" until the cronjobs are configured correctly.', 'resmushit-image-optimizer') . "

"); } else if (resmushit_get_cron_status() == 'NEVER_RUN') { echo wp_kses_post("

" - . __('Cronjobs seems to have never been launched. Please install them by reading the following instruction page.', 'resmushit-image-optimizer') + . __('The Cronjobs were never started. Please configure them using the following documentation.', 'resmushit-image-optimizer') . "

"); } else if (resmushit_get_cron_status() == 'NO_LATELY_RUN') { echo wp_kses_post("

" - . __('Cronjobs seems not to have run lately. Please read the following instruction page to install them correctly.', 'resmushit-image-optimizer') + . __('Cronjobs have not been executed recently. Please configure them using the following documentation.', 'resmushit-image-optimizer') . "

  • " . __('Expected Frequency :', 'resmushit-image-optimizer') . " " . __('Every', 'resmushit-image-optimizer') . " " . time_elapsed_string(RESMUSHIT_CRON_FREQUENCY) . "
  • " . "
  • " . __('Last run :', 'resmushit-image-optimizer') . " " . time_elapsed_string(time() - get_option('resmushit_cron_lastrun')) . " " . __('ago', 'resmushit-image-optimizer') . "
" . "

"); @@ -463,7 +463,7 @@ public static function alertPanel() { . __('Backup files can be removed.', 'resmushit-image-optimizer') . "" . '

' - . sprintf(__('Keep these files and turn off "Do not preserve backups" option if you want to restore your unoptimized files in the future. Please read instructions before clicking.', 'resmushit-image-optimizer'), 'https://resmush.it/wordpress/why-keeping-backup-files') + . sprintf(__('Keep these files and turn off the option "Disable backup" if you want to restore your unoptimized files in the future. Please read instructions before clicking.', 'resmushit-image-optimizer'), 'https://resmush.it/why-preserving-backup-files/') . '

' . sprintf( __( 'We have found %s files ready to be removed', 'resmushit-image-optimizer' ), count(detect_unsmushed_files()) ) . '

' @@ -607,4 +607,4 @@ public static function sizeFormat($bytes) { } return $bytes; } -} \ No newline at end of file +} diff --git a/classes/resmushitWPCLI.class.php b/classes/resmushitWPCLI.class.php index bc15f98..f10c50d 100644 --- a/classes/resmushitWPCLI.class.php +++ b/classes/resmushitWPCLI.class.php @@ -81,41 +81,41 @@ function optimize( $args, $assoc_args ) { if(isset($assoc_args['attachment'])) { if((int)$assoc_args['attachment'] != 0) { if(!get_attached_file($assoc_args['attachment'])) { - WP_CLI::error('Attachment not found in database.'); + WP_CLI::error('File not found in the database.'); return; } WP_CLI::log('Optimizing attachment #' . (int)$assoc_args['attachment'] . '...'); update_option( 'resmushit_cron_lastaction', time() ); switch(reSmushit::revert($assoc_args['attachment'])) { case 'success': - WP_CLI::success('1 picture have been optimized.'); + WP_CLI::success('1 image has been optimized.'); break; case 'disabled': - WP_CLI::warning('This attachmend has optimization disabled.'); + WP_CLI::warning('Optimization is deactivated for this image.'); break; case 'file_too_big': - WP_CLI::error('Attachment file is too big (below 5MB)'); + WP_CLI::error('The file is too large (over 5MB)'); break; case 'file_not_found': - WP_CLI::error('File not found on disk.'); + WP_CLI::error('File not found on the disk.'); break; case 'failed': default: - WP_CLI::error('Unexpected error while running optimization.'); + WP_CLI::error('Unexpected error while executing the optimization.'); break; } return; } else { - WP_CLI::error('Incorrect value for parameter `attachment`. Type `wp resmushit help` for more informations.'); + WP_CLI::error('Incorrect value for the `attachment` parameter. Enter `wp resmushit help` for more information.'); return; } } else { - WP_CLI::error('Incorrect parameter. Type `wp resmushit help` for more informations.'); + WP_CLI::error('Incorrect parameter. Enter `wp resmushit help` for more information.'); return; } } - WP_CLI::log('Gathering unoptimized pictures...'); + WP_CLI::log('Gathering unoptimized images...'); $unoptimized_pictures = json_decode(reSmushit::getNonOptimizedPictures(TRUE)); $count_unoptimized_pictures = count($unoptimized_pictures->nonoptimized); @@ -129,9 +129,9 @@ function optimize( $args, $assoc_args ) { $progress->tick(); } $progress->finish(); - WP_CLI::success($count_unoptimized_pictures . ' pictures have been optimized.'); + WP_CLI::success($count_unoptimized_pictures . ' images have been optimized.'); } else { - WP_CLI::success('All pictures have already been optimized.'); + WP_CLI::success('All images have already been optimized.'); } } } diff --git a/js/script.js b/js/script.js index 1765531..9b13b08 100644 --- a/js/script.js +++ b/js/script.js @@ -1,295 +1,296 @@ - -/** - * Bulk Resize admin javascript functions - */ -var bulkCounter = 0; -var bulkTotalimages = 0; -var next_index = 0; -var file_too_big_count = 0; - - -/** - * Notice - */ -jQuery(document).delegate(".rsmt-notice button.notice-dismiss","mouseup",function(e){ - var current = this; - var csrf_token = jQuery(current).parent().attr('data-csrf'); - jQuery.post( - ajaxurl, { - action: 'resmushit_notice_close', - csrf: csrf_token - }, - function(response) { - var data = jQuery.parseJSON(response); - } - ); -}); - - -/** - * Form Validators - */ -jQuery("#rsmt-options-form").submit(function(){ - jQuery("#resmushit_qlty").removeClass('form-error'); - var qlty = jQuery("#resmushit_qlty").val(); - if(!jQuery.isNumeric(qlty) || qlty > 100 || qlty < 0){ - jQuery("#resmushit_qlty").addClass('form-error'); - return false; - } -}); - - -jQuery( ".list-accordion h4" ).on('click', function(){ - if(jQuery(this).parent().hasClass('opened')){ - jQuery(".list-accordion ul").slideUp(); - jQuery('.list-accordion').removeClass('opened'); - - } else { - jQuery(".list-accordion ul").slideDown(); - jQuery('.list-accordion').addClass('opened'); - } -}); - -updateDisabledState(); -optimizeSingleAttachment(); -removeBackupFiles(); -restoreBackupFiles(); - - -/** - * recursive function for resizing images - */ -function resmushit_bulk_process(bulk, item){ - var error_occured = false; - var csrf_token = jQuery('.rsmt-bulk').attr('data-csrf'); - jQuery.post( - ajaxurl, { - action: 'resmushit_bulk_process_image', - data: bulk[item], - csrf: csrf_token - }, - function(response) { - if(response == 'failed') - error_occured = true; - else if(response == 'file_too_big') - file_too_big_count++; - - if(!flag_removed){ - jQuery('#bulk_resize_target').remove(); - container.append('

'); - var results_target = jQuery('#smush_results'); - results_target.html('
'); - flag_removed = true; - } - - bulkCounter++; - jQuery('.resmushit--progress--bar').html('

'+ Math.round((bulkCounter*100/bulkTotalimages)) +'%

'); - jQuery('.resmushit--progress--bar').animate({'width': Math.round((bulkCounter*100/bulkTotalimages))+'%'}, 0); - - if(item < bulk.length - 1) - resmushit_bulk_process(bulk, item + 1); - else{ - if(error_occured){ - jQuery('.non-optimized-wrapper h3').text('An error occured when contacting webservice. Please try again later.'); - jQuery('.non-optimized-wrapper > p').remove(); - jQuery('.non-optimized-wrapper > div').remove(); - } else if(file_too_big_count){ - - var message = file_too_big_count + ' picture cannot be optimized (> 5MB). All others have been optimized'; - if(file_too_big_count > 1) - var message = file_too_big_count + ' pictures cannot be optimized (> 5MB). All others have been optimized'; - - jQuery('.non-optimized-wrapper h3').text(message); - jQuery('.non-optimized-wrapper > p').remove(); - jQuery('.non-optimized-wrapper > div').remove(); - } else{ - jQuery('.non-optimized-wrapper').addClass('disabled'); - jQuery('.optimized-wrapper').removeClass('disabled'); - updateStatistics(); - } - } - } - ); -} - - -/** - * ajax post to return all images that are candidates for resizing - * @param string the id of the html element into which results will be appended - */ -function resmushit_bulk_resize(container_id, csrf_token) { - container = jQuery('#'+container_id); - container.html('
'); - jQuery('#bulk-resize-examine-button').fadeOut(200); - var target = jQuery('#bulk_resize_target'); - - target.html('

Examining existing attachments. This may take a few moments...
'); - - target.animate( - { height: [100,'swing'] }, - 500, - function() { - jQuery.post( - ajaxurl, - { action: 'resmushit_bulk_get_images', csrf: csrf_token }, - function(response) { - var images = JSON.parse(response); - if (images.hasOwnProperty('error')) { - target.html('
' + images.error + '.
'); - } else if (images.hasOwnProperty('nonoptimized') && images.nonoptimized.length > 0) { - bulkTotalimages = images.nonoptimized.length; - target.html('

' + bulkTotalimages + ' attachment(s) found, starting optimization...
'); - flag_removed = false; - //start treating all pictures - resmushit_bulk_process(images.nonoptimized, 0); - } else { - target.html('
There are no existing attachments that requires optimization.
'); - } - } - ); - }); -} - - -/** - * ajax post to update statistics - */ -function updateStatistics() { - var csrf_token = jQuery('.rsmt-bulk').attr('data-csrf'); - jQuery.post( - ajaxurl, { - action: 'resmushit_update_statistics', - csrf: csrf_token - }, - function(response) { - statistics = JSON.parse(response); - jQuery('#rsmt-statistics-space-saved').text(statistics.total_saved_size_formatted); - jQuery('#rsmt-statistics-files-optimized').text(statistics.files_optimized); - jQuery('#rsmt-statistics-percent-reduction').text(statistics.percent_reduction); - jQuery('#rsmt-statistics-total-optimizations').text(statistics.total_optimizations); - } - ); -} - - -/** - * ajax post to disabled status (or remove) - */ -function updateDisabledState() { - jQuery(document).delegate(".rsmt-trigger--disabled-checkbox","change",function(e){ - e.preventDefault(); - var current = this; - jQuery(current).addClass('rsmt-disable-loader'); - jQuery(current).prop('disabled', true); - var disabledState = jQuery(current).is(':checked'); - var postID = jQuery(current).attr('data-attachment-id'); - var csrfToken = jQuery(current).attr('data-csrf'); - - jQuery.post( - ajaxurl, { - action: 'resmushit_update_disabled_state', - data: {id: postID, disabled: disabledState, csrf: csrfToken} - }, - function(response) { - jQuery(current).removeClass('rsmt-disable-loader'); - jQuery(current).prop('disabled', false); - - if(jQuery(current).parent().hasClass('field')){ - var selector = jQuery(current).parent().parent().next('tr').find('td.field'); - } else { - var selector = jQuery(current).parent().next('td'); - } - - if(disabledState == true){ - selector.empty().append('-'); - } else { - selector.empty().append(''); - } - optimizeSingleAttachment(); - } - ); - }); -} - - - -/** - * ajax to Optimize a single picture - */ -function optimizeSingleAttachment() { - jQuery(document).delegate(".rsmt-trigger--optimize-attachment","mouseup",function(e){ - e.preventDefault(); - var current = this; - jQuery(current).val('Optimizing...'); - jQuery(current).prop('disabled', true); - var disabledState = jQuery(current).is(':checked'); - var postID = jQuery(current).attr('data-attachment-id'); - var csrf_token = jQuery(current).attr('data-csrf'); - - jQuery.post( - ajaxurl, { - action: 'resmushit_optimize_single_attachment', - data: {id: postID, csrf: csrf_token} - }, - function(response) { - var statistics = jQuery.parseJSON(response); - jQuery(current).parent().empty().append('Reduced by ' + statistics.total_saved_size_nice + ' (' + statistics.percent_reduction + ' saved)'); - } - ); - }); -} - - -/** - * ajax to Optimize a single picture - */ -function removeBackupFiles() { - jQuery(document).delegate(".rsmt-trigger--remove-backup-files","mouseup",function(e){ - if ( confirm( "You're about to delete your image backup files. Are you sure to perform this operation ?" ) ) { - - e.preventDefault(); - var current = this; - jQuery(current).val('Removing backups...'); - jQuery(current).prop('disabled', true); - var csrf_token = jQuery(current).attr('data-csrf'); - jQuery.post( - ajaxurl, { - action: 'resmushit_remove_backup_files', - csrf: csrf_token - }, - function(response) { - var data = jQuery.parseJSON(response); - jQuery(current).val(data.success + ' backup files successfully removed'); - setTimeout(function(){ jQuery(current).parent().parent().slideUp() }, 3000); - } - ); - } - }); -} - - -/** - * ajax to Optimize a single picture - */ -function restoreBackupFiles() { - jQuery(document).delegate(".rsmt-trigger--restore-backup-files","mouseup",function(e){ - if ( confirm( "You're about to restore ALL your original image files. Are you sure to perform this operation ?" ) ) { - - e.preventDefault(); - var current = this; - jQuery(current).val('Restoring backups...'); - jQuery(current).prop('disabled', true); - var csrf_token = jQuery(current).attr('data-csrf'); - jQuery.post( - ajaxurl, { - action: 'resmushit_restore_backup_files', - csrf: csrf_token - }, - function(response) { - var data = jQuery.parseJSON(response); - jQuery(current).val(data.success + ' images successfully restored'); - } - ); - } - }); -} \ No newline at end of file + +/** + * Bulk Resize admin javascript functions + */ +var bulkCounter = 0; +var bulkTotalimages = 0; +var next_index = 0; +var file_too_big_count = 0; + + +/** + * Notice + */ +jQuery(document).delegate(".rsmt-notice button.notice-dismiss","mouseup",function(e){ + var current = this; + var csrf_token = jQuery(current).parent().attr('data-csrf'); + jQuery.post( + ajaxurl, { + action: 'resmushit_notice_close', + csrf: csrf_token + }, + function(response) { + var data = jQuery.parseJSON(response); + } + ); +}); + + +/** + * Form Validators + */ +jQuery("#rsmt-options-form").submit(function(){ + jQuery("#resmushit_qlty").removeClass('form-error'); + var qlty = jQuery("#resmushit_qlty").val(); + if(!jQuery.isNumeric(qlty) || qlty > 100 || qlty < 0){ + jQuery("#resmushit_qlty").addClass('form-error'); + return false; + } +}); + + +jQuery( ".list-accordion h4" ).on('click', function(){ + if(jQuery(this).parent().hasClass('opened')){ + jQuery(".list-accordion ul").slideUp(); + jQuery('.list-accordion').removeClass('opened'); + + } else { + jQuery(".list-accordion ul").slideDown(); + jQuery('.list-accordion').addClass('opened'); + } +}); + +updateDisabledState(); +optimizeSingleAttachment(); +removeBackupFiles(); +restoreBackupFiles(); + + +/** + * recursive function for resizing images + */ +function resmushit_bulk_process(bulk, item){ + var error_occured = false; + var csrf_token = jQuery('.rsmt-bulk').attr('data-csrf'); + jQuery.post( + ajaxurl, { + action: 'resmushit_bulk_process_image', + data: bulk[item], + csrf: csrf_token + }, + function(response) { + if(response == 'failed') + error_occured = true; + else if(response == 'file_too_big') + file_too_big_count++; + + if(!flag_removed){ + jQuery('#bulk_resize_target').remove(); + container.append('
'); + var results_target = jQuery('#smush_results'); + results_target.html('
'); + flag_removed = true; + } + + bulkCounter++; + jQuery('.resmushit--progress--bar').html('

'+ Math.round((bulkCounter*100/bulkTotalimages)) +'%

'); + jQuery('.resmushit--progress--bar').animate({'width': Math.round((bulkCounter*100/bulkTotalimages))+'%'}, 0); + + if(item < bulk.length - 1) + resmushit_bulk_process(bulk, item + 1); + else{ + if(error_occured){ + jQuery('.non-optimized-wrapper h3').text('An error occured when contacting the API. Please try again later.'); + jQuery('.non-optimized-wrapper > p').remove(); + jQuery('.non-optimized-wrapper > div').remove(); + } else if(file_too_big_count){ + + var message = file_too_big_count + ' image cannot be optimized (>5MB). All others have been optimized.'; + + if(file_too_big_count > 1) + var message = file_too_big_count + ' images cannot be optimized (>5MB). All others have been optimized'; + + jQuery('.non-optimized-wrapper h3').text(message); + jQuery('.non-optimized-wrapper > p').remove(); + jQuery('.non-optimized-wrapper > div').remove(); + } else{ + jQuery('.non-optimized-wrapper').addClass('disabled'); + jQuery('.optimized-wrapper').removeClass('disabled'); + updateStatistics(); + } + } + } + ); +} + + +/** + * ajax post to return all images that are candidates for resizing + * @param string the id of the html element into which results will be appended + */ +function resmushit_bulk_resize(container_id, csrf_token) { + container = jQuery('#'+container_id); + container.html('
'); + jQuery('#bulk-resize-examine-button').fadeOut(200); + var target = jQuery('#bulk_resize_target'); + + target.html('

Checking existing images. This may take a few moments...
'); + + target.animate( + { height: [100,'swing'] }, + 500, + function() { + jQuery.post( + ajaxurl, + { action: 'resmushit_bulk_get_images', csrf: csrf_token }, + function(response) { + var images = JSON.parse(response); + if (images.hasOwnProperty('error')) { + target.html('
' + images.error + '.
'); + } else if (images.hasOwnProperty('nonoptimized') && images.nonoptimized.length > 0) { + bulkTotalimages = images.nonoptimized.length; + target.html('

' + bulkTotalimages + ' image(s) found. Starting optimization...
'); + flag_removed = false; + //start treating all images + resmushit_bulk_process(images.nonoptimized, 0); + } else { + target.html('
There are no images that need to be optimized.
'); + } + } + ); + }); +} + + +/** + * ajax post to update statistics + */ +function updateStatistics() { + var csrf_token = jQuery('.rsmt-bulk').attr('data-csrf'); + jQuery.post( + ajaxurl, { + action: 'resmushit_update_statistics', + csrf: csrf_token + }, + function(response) { + statistics = JSON.parse(response); + jQuery('#rsmt-statistics-space-saved').text(statistics.total_saved_size_formatted); + jQuery('#rsmt-statistics-files-optimized').text(statistics.files_optimized); + jQuery('#rsmt-statistics-percent-reduction').text(statistics.percent_reduction); + jQuery('#rsmt-statistics-total-optimizations').text(statistics.total_optimizations); + } + ); +} + + +/** + * ajax post to disabled status (or remove) + */ +function updateDisabledState() { + jQuery(document).delegate(".rsmt-trigger--disabled-checkbox","change",function(e){ + e.preventDefault(); + var current = this; + jQuery(current).addClass('rsmt-disable-loader'); + jQuery(current).prop('disabled', true); + var disabledState = jQuery(current).is(':checked'); + var postID = jQuery(current).attr('data-attachment-id'); + var csrfToken = jQuery(current).attr('data-csrf'); + + jQuery.post( + ajaxurl, { + action: 'resmushit_update_disabled_state', + data: {id: postID, disabled: disabledState, csrf: csrfToken} + }, + function(response) { + jQuery(current).removeClass('rsmt-disable-loader'); + jQuery(current).prop('disabled', false); + + if(jQuery(current).parent().hasClass('field')){ + var selector = jQuery(current).parent().parent().next('tr').find('td.field'); + } else { + var selector = jQuery(current).parent().next('td'); + } + + if(disabledState == true){ + selector.empty().append('-'); + } else { + selector.empty().append(''); + } + optimizeSingleAttachment(); + } + ); + }); +} + + + +/** + * ajax to Optimize a single image + */ +function optimizeSingleAttachment() { + jQuery(document).delegate(".rsmt-trigger--optimize-attachment","mouseup",function(e){ + e.preventDefault(); + var current = this; + jQuery(current).val('Optimizing...'); + jQuery(current).prop('disabled', true); + var disabledState = jQuery(current).is(':checked'); + var postID = jQuery(current).attr('data-attachment-id'); + var csrf_token = jQuery(current).attr('data-csrf'); + + jQuery.post( + ajaxurl, { + action: 'resmushit_optimize_single_attachment', + data: {id: postID, csrf: csrf_token} + }, + function(response) { + var statistics = jQuery.parseJSON(response); + jQuery(current).parent().empty().append('Reduced by ' + statistics.total_saved_size_nice + ' (' + statistics.percent_reduction + ' saved)'); + } + ); + }); +} + + +/** + * ajax to Optimize a single image + */ +function removeBackupFiles() { + jQuery(document).delegate(".rsmt-trigger--remove-backup-files","mouseup",function(e){ + if ( confirm( "You are about to delete your image backup files. Are you sure you want to perform this operation?" ) ) { + + e.preventDefault(); + var current = this; + jQuery(current).val('Removing backups...'); + jQuery(current).prop('disabled', true); + var csrf_token = jQuery(current).attr('data-csrf'); + jQuery.post( + ajaxurl, { + action: 'resmushit_remove_backup_files', + csrf: csrf_token + }, + function(response) { + var data = jQuery.parseJSON(response); + jQuery(current).val(data.success + ' backup files successfully removed!'); + setTimeout(function(){ jQuery(current).parent().parent().slideUp() }, 3000); + } + ); + } + }); +} + + +/** + * ajax to Optimize a single image + */ +function restoreBackupFiles() { + jQuery(document).delegate(".rsmt-trigger--restore-backup-files","mouseup",function(e){ + if ( confirm( "You are about to restore ALL your original image files. Are you sure you want to perform this operation?" ) ) { + + e.preventDefault(); + var current = this; + jQuery(current).val('Restoring backups...'); + jQuery(current).prop('disabled', true); + var csrf_token = jQuery(current).attr('data-csrf'); + jQuery.post( + ajaxurl, { + action: 'resmushit_restore_backup_files', + csrf: csrf_token + }, + function(response) { + var data = jQuery.parseJSON(response); + jQuery(current).val(data.success + ' images successfully restored!'); + } + ); + } + }); +} diff --git a/readme.txt b/readme.txt index 4a88c34..edb7910 100644 --- a/readme.txt +++ b/readme.txt @@ -1,312 +1,310 @@ -=== reSmush.it : the original free image compressor and optimizer plugin === -Contributors: ShortPixel, resmushit -Tags: image, optimizer, image optimization, resmush.it, smush, jpg, png, gif, optimization, compression, Compress, Images, Pictures, Reduce Image Size, Smush, Smush.it, free image optimization -Requires at least: 4.0.0 -Tested up to: 6.4.3 -Stable tag: 0.4.14 -License: GPLv2 or later -License URI: http://www.gnu.org/licenses/gpl-2.0.html - -reSmush.it is the FREE image compressor and optimizer plugin - use it to optimize your images and improve the SEO and performance of your website. - -== Description == -The reSmush.it Image Optimizer is a **free WordPress image compressor and optimizer** plugin which allows you to smush your website's images so that they load faster. -The plugin is super easy to use (just 2 clicks!), supports JPG, PNG and GIF image formats and can be used to bulk optimize current(past) images and automatically optimize all new images. -You can also adjust the optimization levels and exclude certain images. -Since its launch more than 9 years ago, reSmush.it has become the preferred choice for WordPress image optimization as it allows you to smush the images for free. -reSmush.it image optimization service works on various CMS platforms (WordPress, Drupal, Joomla, Magento, Prestashop, etc.) and is used by **more than 400,000 websites** worldwide. - -reSmush.it has earned the reputation of being the best free, fast and easy image optimization plugin out there :-) - -**Features:** -- Free bulk image compressor -- Automatic image optimization on upload -- Keep or remove EXIF data -- Image quality selector -- Powerful and free image optimizer API -- Customizable settings for image quality -- Automatic image optimization with CRON -- Backup and restore original images -- Image statistics -- File logging for developers - - -== Installation == - -1. Upload `resmushit-image-optimizer` to the `/wp-content/plugins/` directory. -2. Activate the plugin through the 'Plugins' menu in WordPress. -3. All your new pictures will be automatically optimized ! - - -== Frequently Asked Questions == - -= How does reSmush.it Image Optimizer compare to other image optimization plugins (e.g. Smush, Imagify, TinyPNG, Kraken, EWWW, Optimole)? - -reSmush.it Image Optimizer offers advanced image optimization and provides many of the premium features you'll find in competing services for free. -Plus, we've earned a reputation for being the best free, fast and easy image optimization plugin out there:-) - -= How great is reSmush.it? = - -Since we have optimized more than 25,000,000,000 images, we have acquired new skills. Our service is still in development to bring you new useful features. - -= What about WebP and next-generation image formats? = - -We are working on a new offer to give you the best of these new features. Please be patient, it will be coming soon :) - -= Is there a function "Optimize on upload"? = - -Absolutely, this function is activated for all newly added images and can be deactivated if desired. - -= Is there a CRON function? = - -Yes, you can optimize your images with cronjobs for large (and also for small) media libraries. - -= Can I choose an optimization level? = - -Yes, by default the optimization level is set to 92. However, you can further optimize your images by reducing the optimization level. - -= Can I return to my original images? = - -Yes, by excluding/reverting this asset, you will have your original image available again. - -= Is it possible to exclude some images from the optimizer? = - -Yes, since version 0.1.2, you can easily exclude an asset from the optimizer. - -= Am I at risk of losing my existing images? = - -No! reSmush.it Image Optimizer creates a copy of the original images and performs optimizations only on the copies. - -= Is it free? = - -Yes ! Absolutely free, the only restriction is that the images must not be larger than 5 MB. - -== Screenshots == - -1. The simple interface - -== Changelog == -= 0.4.14 = -* Fix Optimize button in listing - -== Changelog == -= 0.4.13 = -* Patreon new message - -= 0.4.12 = -* Patreon display message :( - -= 0.4.11 = -* Missing image - -= 0.4.10 = -* Partnership with Shortpixel -* fix crash bug when uploading non Image document in library (while log enabled) - -= 0.4.9 = -* Compatibility with WP 6.1.0 -* Compatible with PHP 8.1.X -* Fixed issue on Undefined array key "file" in .../resmushit.php on line 114 - -= 0.4.8 = -* Incorrect library imported (fix `PHP Fatal error: Uncaught Error: Undefined constant “SECURE_AUTH_COOKIE” in /wp-includes/pluggable.php:923`) - -= 0.4.7 = -* Security fixes : CSRF protection for Ajax Calls - -= 0.4.6 = -* Security fixes : protection in a WP's way - -= 0.4.5 = -* Security fixes : prevent XSS breachs - -= 0.4.4 = -* Avoid SSL verifications if certificate of remote endpoints fails. -* Security fixes : escape POST, and admin user check for AJAX requests - -= 0.4.3 = -* Compatibility with WP 6.0.1 -* Security fix issues (https://www.pluginvulnerabilities.com/2022/02/01/wordpress-plugin-security-review-resmush-it-image-optimizer/) - * force int to ID in some SQL requests - * check that user is connected as admin/contributor for AJAX actions - * Message to indicate that there's no collection of data in contacting remote feed service - -= 0.4.2 = -* Compatibility with PHP8+WP 5.8.2 - -= 0.4.1 = -* Official support of WP-CLI -* Fix cron context optimization - -= 0.4.0 = -* New option to restore all original pictures - -= 0.3.12 = -* Fix : Default value assignment -* Test on WP 5.7.1 - -= 0.3.11 = -* Fix : Optimize button not working when creating a new post -* Fix : Default value of variables incorrectly initialized -* Test on WP 5.5.1 - -= 0.3.10 = -* hotfix : deprecated function used - -= 0.3.9 = -* Fix : OWASP & Security fix - -= 0.3.8 = -* Fix : Fix warning in variable not set (metadata) -* Fix : Add an extension uppercase check - -= 0.3.7 = -* Fix : CSS+JS load on every admin page, now restricted to reSmush.it pages & medias -* Fix : Links verification format for admin menu - -= 0.3.6 = -* Fix : cron multiple run issue. - -= 0.3.5 = -* New header image, new WP description for plugin page. - -= 0.3.4 = -* Issue in version number - -= 0.3.3 = -* Fix double cron launch. Timeout added -* Fix "Reduce by 0 (0 saved)" message if statistics are disabled -* Return error if attachment file not found on disk - -= 0.3.2 = -* Fix variable check (generate notice) - -= 0.3.1 = -* Fix log write (permission issue) -* Fix "Reduce by 0 (0 saved)" error. Optimize single attachment while "Optimize on upload" is disabled - -= 0.3.0 = -* Add Backup deletion option -* Add script to delete old backups -* Changed JS inclusion - -= 0.2.5 = -* Add Preserve Exif Feature - -= 0.2.4 = -* Fix issue on SQL request for table prefix different from 'wp_' - -= 0.2.3 = -* Version number issue - -= 0.2.2 = -* Fix settings automatically reinitialized. - -= 0.2.1 = -* Complete French translation -* Plugin translation fix - -= 0.2.0 = -* Add CRON feature -* Code refactoring -* Fix issue for big Media library, with a limitation while fetching attachments -* Fix log path issues - -= 0.1.23 = -* Add Settings link to Plugin page -* Limit reSmush.it options to image attachments only -* Fix `RESMUSHIT_QLTY is not defined` - -= 0.1.22 = -* Fix on attachment metadata incorrectly returned (will fix issues with other media libraries) - -= 0.1.21 = -* Wordpress 5.0 compatibility - -= 0.1.20 = -* Fix PHP errors with PHP 7.2 -* Code refacto - -= 0.1.19 = -* Fix JS on "Optimize" button for a single picture -* Provide a new "Force Optimization" for a single picture - -= 0.1.18 = -* Avoid `filesize () : stat failed` errors if a picture file is missing -* Log check file permissions -* Check extensions on upload (avoid using reSmush.it API if it's not a picture) -* Increase API Timeout for big pictures (10 secs) - -= 0.1.17 = -* Fix bug (non-working optimization) on bulk upload when "Optimize on upload" isn't selected -* New header banner for 4 billionth images optimized - -= 0.1.16 = -* Add correction for allow_url_fopen support -* News feed loaded from a SSL URL - -= 0.1.15 = -* Log rotate if file too big - -= 0.1.14 = -* Tested up to Wordpress 4.9.5 -* New contributor (resmushit) -* Translation completion - -= 0.1.13 = -* Tested up to Wordpress 4.9.1 -* New header banner for 3 billionth images optimized :) - -= 0.1.12 = -* Tested up to Wordpress 4.8.1 - -= 0.1.11 = -* New header banner for 2 billionth images optimized :) - -= 0.1.10 = -* Slovak translation fix - -= 0.1.9 = -* Slovak translation fix - -= 0.1.8 = -* Italian translation added (thanks to Cristian R.) -* Description minor correction - -= 0.1.7 = -* Slovak translation added (thanks to Martin S.) - -= 0.1.6 = -* Bug fix when images uploaded > 5MB -* List of files above 5MB -* Translation minor corrections - -= 0.1.5 = -* Error management if webservice not reachable -* Filesize limitation increased from 2MB to 5MB - -= 0.1.4 = -* CSS Fixes - -= 0.1.3 = -* Translation correction -* News feed images correction - -= 0.1.2 = -* Delete also original file when deleting an attachment -* Exclusion of an attachment of the reSmush.it optimization (checkboxes) -* Adding french translation -* Code optimizations -* 4.6.x check -* Minor bugs corrections - -= 0.1.1 = -* Optimize on upload -* Statistics -* Log services -* Interface rebuild -* News feed from feed.resmush.it - -= 0.1.0 = -* plugin base -* bulk optimizer +=== reSmush.it : The original free image compressor and optimizer plugin === +Contributors: ShortPixel, resmushit +Tags: image, optimizer, image optimization, resmush.it, smush, jpg, png, gif, optimization, compression, Compress, Images, Pictures, Reduce Image Size, Smush, Smush.it, free image optimization +Requires at least: 4.0.0 +Tested up to: 6.4.3 +Stable tag: 0.4.14 +License: GPLv2 or later +License URI: http://www.gnu.org/licenses/gpl-2.0.html + +reSmush.it is the FREE image compressor and optimizer plugin - use it to optimize your images and improve the SEO and performance of your website. + +== Description == +The reSmush.it Image Optimizer is a **free WordPress image compressor and optimizer** plugin which allows you to smush your website's images so that they load faster. +The plugin is **super easy to use** (just 2 clicks!), supports JPG, PNG and GIF image formats and can be used to bulk optimize current (past) images and automatically optimize all new images. +You can also adjust the optimization levels and exclude certain images. +Since its launch more than 9 years ago, reSmush.it has become the preferred choice for WordPress image optimization as it allows you to smush the images for free. +reSmush.it image optimization service works on various CMS platforms (WordPress, Drupal, Joomla, Magento, Prestashop, etc.) and is used by **more than 400,000 websites** worldwide. +reSmush.it has earned the reputation of being the best free, fast and easy image optimization plugin out there :-) + +**Features:** +- Free bulk image compressor +- Automatic image optimization on upload +- Keep or remove EXIF data +- Image quality selector +- Powerful and free image optimizer API +- Customizable settings for image quality +- Automatic image optimization with CRON +- Backup and restore original images +- Image statistics +- File logging for developers + + +== Installation == + +1. Upload `resmushit-image-optimizer` to the `/wp-content/plugins/` directory. +2. Activate the plugin through the 'Plugins' menu in WordPress. +3. All your new pictures will be automatically optimized ! + + +== Frequently Asked Questions == + += How does reSmush.it Image Optimizer compare to other image optimization plugins (e.g. Smush, Imagify, TinyPNG, Kraken, EWWW, Optimole)? + +reSmush.it Image Optimizer offers advanced image optimization and provides many of the premium features you'll find in competing services for free. +Plus, we've earned a reputation for being the best free, fast and easy image optimization plugin out there:-) + += How great is reSmush.it? = + +Since we have optimized more than 25,000,000,000 images, we have acquired new skills. Our service is still in development to bring you new useful features. + += What about WebP and next-generation image formats? = + +We are working on a new offer to give you the best of these new features. Please be patient, it will be coming soon :) + += Is there a function "Optimize on upload"? = + +Absolutely, this function is activated for all newly added images and can be deactivated if desired. + += Is there a CRON function? = + +Yes, you can optimize your images with cronjobs for large (and also for small) media libraries. + += Can I choose an optimization level? = + +Yes, by default the optimization level is set to 92. However, you can further optimize your images by reducing the optimization level. + += Can I return to my original images? = + +Yes, by excluding/reverting this asset, you will have your original image available again. + += Is it possible to exclude some images from the optimizer? = + +Yes, since version 0.1.2, you can easily exclude an asset from the optimizer. + += Am I at risk of losing my existing images? = + +No! reSmush.it Image Optimizer creates a copy of the original images and performs optimizations only on the copies. + += Is it free? = + +Yes ! Absolutely free, the only restriction is that the images must not be larger than 5 MB. + +== Screenshots == + +1. The simple interface + +== Changelog == += 0.4.14 = +* Fix Optimize button in listing + += 0.4.13 = +* Patreon new message + += 0.4.12 = +* Patreon display message :( + += 0.4.11 = +* Missing image + += 0.4.10 = +* Partnership with Shortpixel +* fix crash bug when uploading non Image document in library (while log enabled) + += 0.4.9 = +* Compatibility with WP 6.1.0 +* Compatible with PHP 8.1.X +* Fixed issue on Undefined array key "file" in .../resmushit.php on line 114 + += 0.4.8 = +* Incorrect library imported (fix `PHP Fatal error: Uncaught Error: Undefined constant “SECURE_AUTH_COOKIE” in /wp-includes/pluggable.php:923`) + += 0.4.7 = +* Security fixes : CSRF protection for Ajax Calls + += 0.4.6 = +* Security fixes : protection in a WP's way + += 0.4.5 = +* Security fixes : prevent XSS breachs + += 0.4.4 = +* Avoid SSL verifications if certificate of remote endpoints fails. +* Security fixes : escape POST, and admin user check for AJAX requests + += 0.4.3 = +* Compatibility with WP 6.0.1 +* Security fix issues (https://www.pluginvulnerabilities.com/2022/02/01/wordpress-plugin-security-review-resmush-it-image-optimizer/) + * force int to ID in some SQL requests + * check that user is connected as admin/contributor for AJAX actions + * Message to indicate that there's no collection of data in contacting remote feed service + += 0.4.2 = +* Compatibility with PHP8+WP 5.8.2 + += 0.4.1 = +* Official support of WP-CLI +* Fix cron context optimization + += 0.4.0 = +* New option to restore all original pictures + += 0.3.12 = +* Fix : Default value assignment +* Test on WP 5.7.1 + += 0.3.11 = +* Fix : Optimize button not working when creating a new post +* Fix : Default value of variables incorrectly initialized +* Test on WP 5.5.1 + += 0.3.10 = +* hotfix : deprecated function used + += 0.3.9 = +* Fix : OWASP & Security fix + += 0.3.8 = +* Fix : Fix warning in variable not set (metadata) +* Fix : Add an extension uppercase check + += 0.3.7 = +* Fix : CSS+JS load on every admin page, now restricted to reSmush.it pages & medias +* Fix : Links verification format for admin menu + += 0.3.6 = +* Fix : cron multiple run issue. + += 0.3.5 = +* New header image, new WP description for plugin page. + += 0.3.4 = +* Issue in version number + += 0.3.3 = +* Fix double cron launch. Timeout added +* Fix "Reduce by 0 (0 saved)" message if statistics are disabled +* Return error if attachment file not found on disk + += 0.3.2 = +* Fix variable check (generate notice) + += 0.3.1 = +* Fix log write (permission issue) +* Fix "Reduce by 0 (0 saved)" error. Optimize single attachment while "Optimize on upload" is disabled + += 0.3.0 = +* Add Backup deletion option +* Add script to delete old backups +* Changed JS inclusion + += 0.2.5 = +* Add Preserve Exif Feature + += 0.2.4 = +* Fix issue on SQL request for table prefix different from 'wp_' + += 0.2.3 = +* Version number issue + += 0.2.2 = +* Fix settings automatically reinitialized. + += 0.2.1 = +* Complete French translation +* Plugin translation fix + += 0.2.0 = +* Add CRON feature +* Code refactoring +* Fix issue for big Media library, with a limitation while fetching attachments +* Fix log path issues + += 0.1.23 = +* Add Settings link to Plugin page +* Limit reSmush.it options to image attachments only +* Fix `RESMUSHIT_QLTY is not defined` + += 0.1.22 = +* Fix on attachment metadata incorrectly returned (will fix issues with other media libraries) + += 0.1.21 = +* Wordpress 5.0 compatibility + += 0.1.20 = +* Fix PHP errors with PHP 7.2 +* Code refacto + += 0.1.19 = +* Fix JS on "Optimize" button for a single picture +* Provide a new "Force Optimization" for a single picture + += 0.1.18 = +* Avoid `filesize () : stat failed` errors if a picture file is missing +* Log check file permissions +* Check extensions on upload (avoid using reSmush.it API if it's not a picture) +* Increase API Timeout for big pictures (10 secs) + += 0.1.17 = +* Fix bug (non-working optimization) on bulk upload when "Optimize on upload" isn't selected +* New header banner for 4 billionth images optimized + += 0.1.16 = +* Add correction for allow_url_fopen support +* News feed loaded from a SSL URL + += 0.1.15 = +* Log rotate if file too big + += 0.1.14 = +* Tested up to Wordpress 4.9.5 +* New contributor (resmushit) +* Translation completion + += 0.1.13 = +* Tested up to Wordpress 4.9.1 +* New header banner for 3 billionth images optimized :) + += 0.1.12 = +* Tested up to Wordpress 4.8.1 + += 0.1.11 = +* New header banner for 2 billionth images optimized :) + += 0.1.10 = +* Slovak translation fix + += 0.1.9 = +* Slovak translation fix + += 0.1.8 = +* Italian translation added (thanks to Cristian R.) +* Description minor correction + += 0.1.7 = +* Slovak translation added (thanks to Martin S.) + += 0.1.6 = +* Bug fix when images uploaded > 5MB +* List of files above 5MB +* Translation minor corrections + += 0.1.5 = +* Error management if webservice not reachable +* Filesize limitation increased from 2MB to 5MB + += 0.1.4 = +* CSS Fixes + += 0.1.3 = +* Translation correction +* News feed images correction + += 0.1.2 = +* Delete also original file when deleting an attachment +* Exclusion of an attachment of the reSmush.it optimization (checkboxes) +* Adding french translation +* Code optimizations +* 4.6.x check +* Minor bugs corrections + += 0.1.1 = +* Optimize on upload +* Statistics +* Log services +* Interface rebuild +* News feed from feed.resmush.it + += 0.1.0 = +* plugin base +* bulk optimizer diff --git a/resmushit.admin.php b/resmushit.admin.php index a03a6d4..2e688fc 100644 --- a/resmushit.admin.php +++ b/resmushit.admin.php @@ -43,7 +43,7 @@ function resmushit_settings_declare() { * @return $columns */ function resmushit_media_list_add_column( $columns ) { - $columns["resmushit_disable"] = __('Disable of reSmush.it', 'resmushit-image-optimizer'); + $columns["resmushit_disable"] = __('Disable reSmush.it', 'resmushit-image-optimizer'); $columns["resmushit_status"] = __('reSmush.it status', 'resmushit-image-optimizer'); return $columns; } @@ -98,7 +98,7 @@ function resmushit_image_attachment_add_status_button($form_fields, $post) { return $form_fields; $form_fields["rsmt-disabled-checkbox"] = array( - "label" => __("Disable of reSmush.it", "resmushit-image-optimizer"), + "label" => __("Disable reSmush.it", "resmushit-image-optimizer"), "input" => "html", "value" => '', "html" => reSmushitUI::mediaListCustomValuesDisable($post->ID, true) diff --git a/resmushit.php b/resmushit.php index d7010c4..58b7de9 100644 --- a/resmushit.php +++ b/resmushit.php @@ -9,16 +9,17 @@ * @wordpress-plugin * Plugin Name: reSmush.it Image Optimizer * Plugin URI: https://wordpress.org/plugins/resmushit-image-optimizer/ - * Description: Image Optimization API. Provides image size optimization - * Version: 0.4.14 - * Timestamp: 2024.02.12 + * Description: 100% Free Image Optimizer and Compressor plugin. Fast JPEG/PNG and GIF compression. + * Version: 1.0.0 + * Timestamp: 2024.02.21 * Author: reSmush.it * Author URI: https://resmush.it - * Author: Charles Bourgeaux + * Author: Charles Bourgeaux, ShortPixel * License: GPL-2.0+ * License URI: http://www.gnu.org/licenses/gpl-2.0.txt - * Domain Path: /languages - * Text Domain: resmushit-image-optimizer + * GitHub Plugin URI: https://github.com/resmushit/wordpress-plugin + * Domain Path: /languages + * Text Domain: resmushit-image-optimizer */ require('resmushit.inc.php'); @@ -116,7 +117,7 @@ function resmushit_process_images($attachments, $force_keep_original = TRUE) { $basepath = $fileInfo['dirname'] . '/'; $extension = isset($fileInfo['extension']) ? $fileInfo['extension'] : NULL; - // Optimize only pictures/files accepted by the API + // Optimize only images/files accepted by the API if( !in_array(strtolower($extension), resmushit::authorizedExtensions()) ) { return $attachments; } @@ -204,7 +205,7 @@ function resmushit_get_meta_id($result){ /** * -* add Ajax action to fetch all unsmushed pictures +* add Ajax action to fetch all unsmushed images * * @param none * @return json object @@ -283,7 +284,7 @@ function resmushit_optimize_single_attachment() { /** * -* add Ajax action to optimize a picture according to attachment ID +* add Ajax action to optimize an image according to attachment ID * * @param none * @return boolean @@ -411,7 +412,7 @@ function resmushit_cron_process() { include_once( ABSPATH . 'wp-admin/includes/image.php' ); add_filter('wp_generate_attachment_metadata', 'resmushit_process_images'); - rlog('Gathering unoptimized pictures from CRON'); + rlog('Gathering unoptimized images from CRON'); $unoptimized_pictures = json_decode(reSmushit::getNonOptimizedPictures(TRUE)); rlog('Found ' . count($unoptimized_pictures->nonoptimized) . ' attachments'); From e8c59ba184ca0d41010bd2f6c4b1589c89867f77 Mon Sep 17 00:00:00 2001 From: Pedro Dobrescu Date: Tue, 20 Feb 2024 22:24:48 +0200 Subject: [PATCH 07/21] Update more wording --- classes/Controller/AdminController.php | 18 +++++++------- classes/Controller/AjaxController.php | 18 +++++++------- classes/Controller/ProcessController.php | 8 +++---- classes/resmushitWPCLI.class.php | 30 ++++++++++++------------ 4 files changed, 37 insertions(+), 37 deletions(-) diff --git a/classes/Controller/AdminController.php b/classes/Controller/AdminController.php index 03ffc38..d1380ca 100644 --- a/classes/Controller/AdminController.php +++ b/classes/Controller/AdminController.php @@ -242,18 +242,18 @@ public function register_plugin_assets(){ wp_register_script( 'resmushit-js', plugins_url( 'js/script.js?' . hash_file('crc32', RESMUSH_PLUGIN_PATH . '/js/script.js'), RESMUSH_PLUGIN_FILE ) ); $translations = array( - 'restore_all_confirm' => __("You're about to restore ALL your original image files. Are you sure to perform this operation ?", "resmushit-image-optimizer"), - 'images_restored' => __('images successfully restored', "resmushit-image-optimizer"), - 'backupfiles_removed' => __('backup files successfully removed', "resmushit-image-optimizer"), - 'remove_backup_confirm' => __("You're about to delete your image backup files. Are you sure to perform this operation ?", "resmushit-image-optimizer"), + 'restore_all_confirm' => __("You are about to restore ALL your original image files. Are you sure you want to perform this operation?", "resmushit-image-optimizer"), + 'images_restored' => __('images successfully restored!', "resmushit-image-optimizer"), + 'backupfiles_removed' => __('backup files successfully removed!', "resmushit-image-optimizer"), + 'remove_backup_confirm' => __("You are about to delete your image backup files. Are you sure you want to perform this operation?", "resmushit-image-optimizer"), 'removing_backups' => __('Removing backups...', "resmushit-image-optimizer"), 'reduced_by' => __('Reduced by', "resmushit-image-optimizer"), 'optimizing' => __('Optimizing...', "resmushit-image-optimizer"), - 'attachments_found' => __('attachment(s) found, starting optimization...', "resmushit-image-optimizer"), - 'no_attachments_found' => __('There are no existing attachments that requires optimization.', "resmushit-image-optimizer"), - 'examing_attachments' => __('Examining existing attachments. This may take a few moments...', "resmushit-image-optimizer"), - 'picture_too_big' => __('picture(s) cannot be optimized (> 5MB). All others have been optimized', "resmushit-image-optimizer"), - 'error_webservice' => __('An error occured when contacting webservice. Please try again later.', "resmushit-image-optimizer"), + 'attachments_found' => __('image(s) found, starting optimization...', "resmushit-image-optimizer"), + 'no_attachments_found' => __('There are no images that need to be optimized.', "resmushit-image-optimizer"), + 'examing_attachments' => __('Checking existing images. This may take a few moments...', "resmushit-image-optimizer"), + 'picture_too_big' => __('image(s) cannot be optimized (>5MB). All others have been optimized.', "resmushit-image-optimizer"), + 'error_webservice' => __('An error occured when contacting the API. Please try again later.', "resmushit-image-optimizer"), 'restoring' => __('Restoring...', 'resmushit-image-optimizer'), '' diff --git a/classes/Controller/AjaxController.php b/classes/Controller/AjaxController.php index 60c4009..5abc757 100644 --- a/classes/Controller/AjaxController.php +++ b/classes/Controller/AjaxController.php @@ -53,7 +53,7 @@ function bulk_process_image() { die(); } if(!is_super_admin() && !current_user_can('administrator')) { - wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); + wp_send_json(json_encode(array('error' => 'The user must be an administrator to retrieve this data'))); die(); } Log::addInfo('Bulk optimization launched for file : ' . get_attached_file( sanitize_text_field((int)$_POST['data']['ID']) )); @@ -74,7 +74,7 @@ function bulk_get_images() { die(); } if(!is_super_admin() && !current_user_can('administrator')) { - wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); + wp_send_json(json_encode(array('error' => 'The user must be an administrator to retrieve this data'))); die(); } wp_send_json(reSmushit::getNonOptimizedPictures()); @@ -95,7 +95,7 @@ function update_disabled_state() { die(); } if(!is_super_admin() && !current_user_can('administrator')) { - wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); + wp_send_json(json_encode(array('error' => 'The user must be an administrator to retrieve this data'))); die(); } if(isset($_POST['data']['id']) && $_POST['data']['id'] != null && isset($_POST['data']['disabled'])){ @@ -118,7 +118,7 @@ public function optimize_single_attachment() { die(); } if(!is_super_admin() && !current_user_can('administrator')) { - wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); + wp_send_json(json_encode(array('error' => 'The user must be an administrator to retrieve this data'))); die(); } if(isset($_POST['data']['id']) && $_POST['data']['id'] != null){ @@ -141,7 +141,7 @@ public function restore_single_attachment() { die(); } if(!is_super_admin() && !current_user_can('administrator')) { - wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); + wp_send_json(json_encode(array('error' => 'The user must be an administrator to retrieve this data'))); die(); } $processController = ProcessController::getInstance(); @@ -151,7 +151,7 @@ public function restore_single_attachment() { if(isset($_POST['data']['id']) && $_POST['data']['id'] != null){ reSmushit::revert(sanitize_text_field((int)$_POST['data']['id'])); - $response = array('status' => true, 'message' => __('Item restored', 'resmushit-image-optimizer')); + $response = array('status' => true, 'message' => __('Image restored!', 'resmushit-image-optimizer')); wp_send_json($response); } die(); @@ -171,7 +171,7 @@ public function update_statistics() { die(); } if(!is_super_admin() && !current_user_can('administrator')) { - wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); + wp_send_json(json_encode(array('error' => 'The user must be an administrator to retrieve this data'))); die(); } $output = reSmushit::getStatistics(); @@ -195,7 +195,7 @@ public function remove_backup_files() { die(); } if(!is_super_admin() && !current_user_can('administrator')) { - wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); + wp_send_json(json_encode(array('error' => 'The user must be an administrator to retrieve this data'))); die(); } @@ -225,7 +225,7 @@ public function restore_backup_files() { die(); } if(!is_super_admin() && !current_user_can('administrator')) { - wp_send_json(json_encode(array('error' => 'User must be at least administrator to retrieve these data'))); + wp_send_json(json_encode(array('error' => 'The user must be an administrator to retrieve this data'))); die(); } $files= reSmushit::detect_unsmushed_files(); diff --git a/classes/Controller/ProcessController.php b/classes/Controller/ProcessController.php index 1f627bd..36fc41e 100644 --- a/classes/Controller/ProcessController.php +++ b/classes/Controller/ProcessController.php @@ -96,13 +96,13 @@ public function process_images($attachments, $force_keep_original = TRUE) { return $attachments; if(empty($attachments)) { - Log::addError("Error! Attachment #$attachment_id has no corresponding file on disk.", 'WARNING'); + Log::addError("Error! The image #$attachment_id has no corresponding file on disk.", 'WARNING'); return $attachments; } $fileInfo = pathinfo(get_attached_file( $attachment_id )); if(!isset($fileInfo['dirname'])) { - Log::addError("Error! Incorrect file provided." . print_r($fileInfo, TRUE), 'WARNING'); + Log::addError("Error! Incorrect file provided." . print_r($fileInfo, TRUE), 'WARNING'); return $attachments; } $basepath = $fileInfo['dirname'] . '/'; @@ -114,7 +114,7 @@ public function process_images($attachments, $force_keep_original = TRUE) { } if(!isset($attachments[ 'file' ])) { - Log::addError("Error! Incorrect attachment " . print_r($attachments, TRUE), 'WARNING'); + Log::addError("Error! Incorrect image " . print_r($attachments, TRUE), 'WARNING'); return $attachments; } $basefile = basename($attachments[ 'file' ]); @@ -122,7 +122,7 @@ public function process_images($attachments, $force_keep_original = TRUE) { $statistics[] = reSmushit::optimize($basepath . $basefile, $force_keep_original ); if(!isset($attachments[ 'sizes' ])) { - Log::addError("Error! Unable to find attachments sizes." . print_r($attachments, TRUE), 'WARNING'); + Log::addError("Error! Unable to find image sizes." . print_r($attachments, TRUE), 'WARNING'); return $attachments; } foreach($attachments['sizes'] as $image_style) { diff --git a/classes/resmushitWPCLI.class.php b/classes/resmushitWPCLI.class.php index f10c50d..2e9a016 100644 --- a/classes/resmushitWPCLI.class.php +++ b/classes/resmushitWPCLI.class.php @@ -6,7 +6,7 @@ * ## OPTIONS * * - * : can be 'optimize' to run optimization + * : can be 'optimize' to run the optimization (for a single image or bulk) * : can be 'set-quality ' to define a new quality factor * : can be 'help' to display global help * : can be 'version' to retrieve plugin version @@ -30,11 +30,11 @@ * **/ function help() { - WP_CLI::log('reSmush.it Image Optimizer Help '); - WP_CLI::log('Usage:'); - WP_CLI::log('- `wp resmushit set-quality ` : defines the quality level (1-100)'); - WP_CLI::log('- `wp resmushit optimize` : optimize the whole library by batch of ' . reSmushit::MAX_ATTACHMENTS_REQ); - WP_CLI::log('- `wp resmushit optimize --attachment=` : optimize a single attachment.'); + WP_CLI::log('reSmush.it Image Optimizer Help '); + WP_CLI::log('Usage:'); + WP_CLI::log('- `wp resmushit set-quality ` : defines the image quality level (1-100)'); + WP_CLI::log('- `wp resmushit optimize` : optimize the whole media library by batches of ' . reSmushit::MAX_ATTACHMENTS_REQ); + WP_CLI::log('- `wp resmushit optimize --attachment=` : optimizes a single attachment.'); } /** @@ -43,7 +43,7 @@ function help() { * **/ function version() { - WP_CLI::success('reSmush.it Image Optimizer ' . RESMUSHIT_VERSION); + WP_CLI::success('reSmush.it Image Optimizer ' . RESMUSHIT_VERSION); } /** @@ -54,14 +54,14 @@ function version() { **/ function set_quality( $args ) { if(!isset($args[0])) { - WP_CLI::error( 'A Quality value is required for this command. (eg. `wp set-quality 92`). Type `wp resmushit help` for more informations.' ); + WP_CLI::error( 'An image quality value is required for this command. (eg. `wp set-quality 82`). Type `wp resmushit help` for more information.' ); return; } if($args[0] > 0 && $args[0] <= 100) { update_option( 'resmushit_qlty', (int)$args[0] ); - WP_CLI::success( "Quality value set to " . $args[0]); + WP_CLI::success( "The image quality value is set to " . $args[0]); } else { - WP_CLI::error( 'An incorrect quality value is provided (eg. `wp set-quality 92`)' ); + WP_CLI::error( 'An incorrect image quality value was provided (e.g. `wp set-quality 82`)' ); } } @@ -72,7 +72,7 @@ function set_quality( $args ) { **/ function optimize( $args, $assoc_args ) { if(isset($args[0])) { - WP_CLI::error('Incorrect parameter. Type `wp resmushit help` for more informations.'); + WP_CLI::error('Incorrect parameter. Type `wp resmushit help` for more information.'); return; } @@ -81,7 +81,7 @@ function optimize( $args, $assoc_args ) { if(isset($assoc_args['attachment'])) { if((int)$assoc_args['attachment'] != 0) { if(!get_attached_file($assoc_args['attachment'])) { - WP_CLI::error('File not found in the database.'); + WP_CLI::error('The file was not found in the database.'); return; } WP_CLI::log('Optimizing attachment #' . (int)$assoc_args['attachment'] . '...'); @@ -91,7 +91,7 @@ function optimize( $args, $assoc_args ) { WP_CLI::success('1 image has been optimized.'); break; case 'disabled': - WP_CLI::warning('Optimization is deactivated for this image.'); + WP_CLI::warning('Optimization is disabled for this image.'); break; case 'file_too_big': WP_CLI::error('The file is too large (over 5MB)'); @@ -120,8 +120,8 @@ function optimize( $args, $assoc_args ) { $count_unoptimized_pictures = count($unoptimized_pictures->nonoptimized); if($count_unoptimized_pictures > 0) { - WP_CLI::log('Found ' . $count_unoptimized_pictures . ' attachments'); - $progress = \WP_CLI\Utils\make_progress_bar( 'Optimized attachments', count($unoptimized_pictures->nonoptimized) ); + WP_CLI::log('Found ' . $count_unoptimized_pictures . ' images'); + $progress = \WP_CLI\Utils\make_progress_bar( 'Optimized images', count($unoptimized_pictures->nonoptimized) ); foreach($unoptimized_pictures->nonoptimized as $el) { update_option( 'resmushit_cron_lastaction', time() ); From 07132d43333287047f77b1a917e9fb3be8765380 Mon Sep 17 00:00:00 2001 From: Pedro Dobrescu Date: Tue, 20 Feb 2024 22:31:13 +0200 Subject: [PATCH 08/21] Fix settings link and bumb version --- classes/Controller/AdminController.php | 2 +- resmushit.php | 2 +- resmushit.settings.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/classes/Controller/AdminController.php b/classes/Controller/AdminController.php index d1380ca..5d1bea0 100644 --- a/classes/Controller/AdminController.php +++ b/classes/Controller/AdminController.php @@ -290,7 +290,7 @@ public function add_plugin_page_settings_link($links) { $links = array(); $links[] = $oneLink; } - $links[] = '' . __('Settings', "resmushit-image-optimizer") . ''; + $links[] = '' . __('Settings', "resmushit-image-optimizer") . ''; return $links; } diff --git a/resmushit.php b/resmushit.php index 8624b42..d456b3b 100644 --- a/resmushit.php +++ b/resmushit.php @@ -24,7 +24,7 @@ require('resmushit.inc.php'); -define( 'RESMUSH_PLUGIN_VERSION', '0.5'); +define( 'RESMUSH_PLUGIN_VERSION', '1.0.0'); define( 'RESMUSH_PLUGIN_FILE', __FILE__ ); define( 'RESMUSH_PLUGIN_PATH', plugin_dir_path(__FILE__) ); diff --git a/resmushit.settings.php b/resmushit.settings.php index fabf5e8..028d314 100644 --- a/resmushit.settings.php +++ b/resmushit.settings.php @@ -1,8 +1,8 @@ Date: Wed, 21 Feb 2024 13:56:25 +0200 Subject: [PATCH 09/21] Fixes to column and UI QoL --- classes/Controller/AdminController.php | 51 ++++++++++++++++++++++---- classes/Controller/AjaxController.php | 2 +- classes/resmushit.class.php | 16 +++++--- classes/resmushitUI.class.php | 46 +++++++++++------------ css/resmushit.css | 1 + js/script.js | 12 +++--- resmushit.settings.php | 1 - scss/resmush_admin.scss | 2 + 8 files changed, 88 insertions(+), 43 deletions(-) diff --git a/classes/Controller/AdminController.php b/classes/Controller/AdminController.php index 5d1bea0..4e1d87d 100644 --- a/classes/Controller/AdminController.php +++ b/classes/Controller/AdminController.php @@ -24,6 +24,10 @@ public static function getInstance() public function __construct() { + if(!is_super_admin() && !current_user_can('administrator')) { + return; + } + $this->initHooks(); } @@ -33,9 +37,12 @@ protected function initHooks() add_action( 'admin_menu', array($this, 'add_menu') ); add_action( 'admin_init', array($this, 'settings_declare') ); add_filter( 'manage_media_columns', array($this, 'media_list_add_column') ); - add_filter( 'manage_upload_sortable_columns', array($this,'media_list_sort_column') ); + // add_filter( 'manage_upload_sortable_columns', array($this,'media_list_sort_column') ); add_action( 'manage_media_custom_column', array($this,'media_list_add_column_value'), 10, 2 ); - add_filter("attachment_fields_to_edit", array($this, 'image_attachment_add_status_button'), null, 2); + // add_filter("attachment_fields_to_edit", array($this, 'image_attachment_add_status_button'), null, 2); + + add_action( 'add_meta_boxes_attachment', array( $this, 'addMetaBox') ); + add_action( 'admin_head', array($this,'register_plugin_assets') ); add_filter('plugin_action_links_' . plugin_basename(RESMUSH_PLUGIN_FILE), array($this, 'add_plugin_page_settings_link')); @@ -74,7 +81,29 @@ public function settings_declare() { register_setting( 'resmushit-settings', 'resmushit_notice_close' ); } + // Add metabox for editmediaview sie. + public function addMetaBox() + { + add_meta_box( + 'rsi_info_box', // this is HTML id of the box on edit screen + __('Resmush.IT', ''), // title of the box + array( $this, 'displayMetaBox'), // 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 displayMetaBox($post) + { + $post_id = $post->ID; + echo "
"; + reSmushitUI::mediaListCustomValuesStatus($post_id); + echo "

"; + reSmushitUI::mediaListCustomValuesDisable($post_id); + echo "
"; + + } /** * @@ -84,7 +113,7 @@ public function settings_declare() { * @return $columns */ public function media_list_add_column( $columns ) { - $columns["resmushit_disable"] = __('Disable of reSmush.it', 'resmushit-image-optimizer'); +// $columns["resmushit_disable"] = __('Disable of reSmush.it', 'resmushit-image-optimizer'); $columns["resmushit_status"] = __('reSmush.it status', 'resmushit-image-optimizer'); return $columns; } @@ -99,7 +128,7 @@ public function media_list_add_column( $columns ) { * @return $columns */ public function media_list_sort_column( $columns ) { - $columns["resmushit_disable"] = "resmushit_disable"; + // $columns["resmushit_disable"] = "resmushit_disable"; $columns["resmushit_status"] = "resmushit_status"; return $columns; } @@ -115,10 +144,16 @@ public function media_list_sort_column( $columns ) { * @return none */ public function media_list_add_column_value( $column_name, $id ) { - if ( $column_name == "resmushit_disable" ) - reSmushitUI::mediaListCustomValuesDisable($id); - else if ( $column_name == "resmushit_status" ) + + if ($column_name !== 'resmushit_status') + { + return; + } + echo "
"; reSmushitUI::mediaListCustomValuesStatus($id); +echo "
"; + reSmushitUI::mediaListCustomValuesDisable($id); +echo "
"; } @@ -255,7 +290,7 @@ public function register_plugin_assets(){ 'picture_too_big' => __('image(s) cannot be optimized (>5MB). All others have been optimized.', "resmushit-image-optimizer"), 'error_webservice' => __('An error occured when contacting the API. Please try again later.', "resmushit-image-optimizer"), 'restoring' => __('Restoring...', 'resmushit-image-optimizer'), - '' + 'stop_optimization' => __('Stop bulk', 'resmushit-image-optimizer'), ); wp_localize_script('resmushit-js', 'reSmush', array( diff --git a/classes/Controller/AjaxController.php b/classes/Controller/AjaxController.php index 5abc757..529653d 100644 --- a/classes/Controller/AjaxController.php +++ b/classes/Controller/AjaxController.php @@ -89,7 +89,7 @@ function bulk_get_images() { * @param none * @return json object */ - function update_disabled_state() { + public function update_disabled_state() { if ( !isset($_REQUEST['data']['csrf']) || ! wp_verify_nonce( $_REQUEST['data']['csrf'], 'single_attachment' ) ) { wp_send_json(json_encode(array('error' => 'Invalid CSRF token'))); die(); diff --git a/classes/resmushit.class.php b/classes/resmushit.class.php index 593822f..e3fb822 100644 --- a/classes/resmushit.class.php +++ b/classes/resmushit.class.php @@ -273,7 +273,7 @@ public static function getStatistics($attachment_id = null){ /** - * + * * Get the count of all images * * @param none @@ -304,7 +304,7 @@ public static function getCountAllPictures(){ /** - * + * * Get a list of unoptimized images * * @param none @@ -341,14 +341,19 @@ public static function getNonOptimizedPictures($id_only = FALSE){ where POSTS.post_type = %s and (POSTS.post_mime_type = 'image/jpeg' OR POSTS.post_mime_type = 'image/gif' OR POSTS.post_mime_type = 'image/png') + ORDER BY POSTS.post_date desc + ) as ATTACHMENTS WHERE (ATTACHMENTS.qlty != '%s' OR ATTACHMENTS.qlty IS NULL) AND ATTACHMENTS.disabled IS NULL LIMIT %d", - array('_wp_attachment_metadata','resmushed_quality','resmushed_disabled','attachment', self::getPictureQualitySetting(), self::MAX_ATTACHMENTS_REQ) + array('_wp_attachment_metadata','resmushed_quality','resmushed_disabled','attachment', self::getPictureQualitySetting(), self::MAX_ATTACHMENTS_REQ) ); // Get the images in the attachement table + // + Log::addTemp('UnOptimizedPictures Query' . $queryUnoptimizedPicture, debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5)); + $all_images = $wpdb->get_results($queryUnoptimizedPicture); foreach($all_images as $image){ @@ -368,12 +373,12 @@ public static function getNonOptimizedPictures($id_only = FALSE){ $unsmushed_images[] = $tmp; } - return json_encode(array('nonoptimized' => $unsmushed_images, 'filestoobig' => $files_too_big, 'filesnotfound' => $files_not_found)); + return json_encode(array('nonoptimized' => $unsmushed_images, 'filestoobig' => $files_too_big, 'filesnotfound' => $files_not_found, 'totalresult' => count($all_images) )); } /** - * + * * Return the number of unoptimized images * * @param none @@ -385,6 +390,7 @@ public static function getCountNonOptimizedPictures(){ $output['nonoptimized'] = is_array($data->nonoptimized) ? sizeof($data->nonoptimized) : 0; $output['filesnotfound'] = is_array($data->filesnotfound) ? sizeof($data->filesnotfound) : 0; $output['filestoobig'] = is_array($data->filestoobig) ? sizeof($data->filestoobig) : 0; + $output['totalresult'] = property_exists($data, 'totalresult') ? : 0; return $output; } diff --git a/classes/resmushitUI.class.php b/classes/resmushitUI.class.php index 0f63fdc..9f99fcd 100644 --- a/classes/resmushitUI.class.php +++ b/classes/resmushitUI.class.php @@ -114,24 +114,23 @@ public static function settingsPanel() { ); self::fullWidthPanelWrapper(__('Settings', 'resmushit-image-optimizer'), null, 'orange'); - $new_label = "" . __("New!", 'resmushit-image-optimizer') . ""; echo wp_kses('
', $allowed_html); settings_fields( 'resmushit-settings' ); do_settings_sections( 'resmushit-settings' ); - - echo wp_kses('' + + echo '
' . self::addSetting("text", __("Image quality", 'resmushit-image-optimizer'), __("A lower value means a smaller image size, a higher value means better image quality. A value between 50 and 85 is normally recommended.", 'resmushit-image-optimizer'), "resmushit_qlty") . self::addSetting("checkbox", __("Optimize on upload", 'resmushit-image-optimizer'), __("Once activated, newly uploaded images are automatically optimized.", 'resmushit-image-optimizer'), "resmushit_on_upload") - . self::addSetting("checkbox", $new_label . __("Preserve EXIF", 'resmushit-image-optimizer'), __("Activate this option to retain the original EXIF data in the images.", 'resmushit-image-optimizer'), "resmushit_preserve_exif") - . self::addSetting("checkbox", $new_label . __("Deactivate backup", 'resmushit-image-optimizer'), sprintf(__("If you select this option, you choose not to keep the original version of the images. This is helpful to save disk space, but we strongly recommend having a backup of the entire website on hand. More information.", "resmushit-image-optimizer"), "https://resmush.it/why-preserving-backup-files/"), "resmushit_remove_unsmushed") - . self::addSetting("checkbox", $new_label . __("Optimize images using CRON", 'resmushit-image-optimizer'), sprintf(__("Image optimization is performed automatically via CRON tasks. More information", 'resmushit-image-optimizer'), 'https://resmush.it/how-to-configure-cronjobs/'), "resmushit_cron") + . self::addSetting("checkbox", __("Preserve EXIF", 'resmushit-image-optimizer'), __("Activate this option to retain the original EXIF data in the images.", 'resmushit-image-optimizer'), "resmushit_preserve_exif") + . self::addSetting("checkbox", __("Deactivate backup", 'resmushit-image-optimizer'), sprintf(__("If you select this option, you choose not to keep the original version of the images. This is helpful to save disk space, but we strongly recommend having a backup of the entire website on hand. More information.", "resmushit-image-optimizer"), "https://resmush.it/why-preserving-backup-files/"), "resmushit_remove_unsmushed") + . self::addSetting("checkbox", __("Optimize images using CRON", 'resmushit-image-optimizer'), sprintf(__("Image optimization is performed automatically via CRON tasks. More information", 'resmushit-image-optimizer'), 'https://resmush.it/how-to-configure-cronjobs/'), "resmushit_cron") . self::addSetting("checkbox", __("Activate logs", 'resmushit-image-optimizer'), sprintf(__("Activate logging in a file. Useful for debugging/developers. More information", 'resmushit-image-optimizer'), 'https://resmush.it/features/'), "resmushit_logs") . self::addSetting("checkbox", __("Activate statistics", 'resmushit-image-optimizer'), __("Generates statistics about optimized images.", 'resmushit-image-optimizer'), "resmushit_statistics") - . '
', $allowed_html); + . ''; submit_button(); - echo wp_kses('
', $allowed_html); + echo '
'; self::fullWidthPanelEndWrapper(); } @@ -148,16 +147,22 @@ public static function bulkPanel() { $dataCountNonOptimizedPictures = reSmushit::getCountNonOptimizedPictures(); $countNonOptimizedPictures = $dataCountNonOptimizedPictures['nonoptimized']; self::fullWidthPanelWrapper(__('Optimize Media Library', 'resmushit-image-optimizer'), null, 'blue'); - + + $totalresult = $dataCountNonOptimizedPictures['totalresult']; + $limitReached = false; + $additionnalClassNeedOptimization = NULL; $additionnalClassNoNeedOptimization = 'disabled'; if(!$countNonOptimizedPictures) { $additionnalClassNeedOptimization = 'disabled'; $additionnalClassNoNeedOptimization = NULL; - } else if ($countNonOptimizedPictures == reSmushit::MAX_ATTACHMENTS_REQ) { + } else if ($totalresult == reSmushit::MAX_ATTACHMENTS_REQ) { $countNonOptimizedPictures .= '+'; + $limitReached = true; } + + echo wp_kses_post("

"); if(get_option('resmushit_cron') && get_option('resmushit_cron') == 1) { @@ -173,6 +178,10 @@ public static function bulkPanel() { . __('images that need optimization', 'resmushit-image-optimizer') . ".

" . __('This action resmushes all images that have not yet been optimized with the image quality specified in the settings. If the image quality has been changed and backups are activated, images that have already been optimized are resmushed with the new image quality rate.', 'resmushit-image-optimizer')); + if ($limitReached) + { + echo wp_kses_post('

' . __('Maximum item count has been reached. You can optimize the first batch of images, refresh the page and continue', 'resmushit-image-optimizer') . '

'); + } } $allowed_html = array_merge(wp_kses_allowed_html( 'post' ), array( @@ -280,7 +289,7 @@ public static function statisticsPanel() { . "/" . $resmushit_stat['total_pictures'] . "

" - . __('Optimized images (including thumbnails):', 'resmushit-image-optimizer') + . __('Optimized images (including thumbnails):', 'resmushit-image-optimizer') . " " . $resmushit_stat['files_optimized_with_thumbnails'] . "/" @@ -546,24 +555,15 @@ public static function mediaListCustomValuesDisable($id, $return = false) { if($wpdb->get_results($query)) $attachment_resmushit_disabled = 'checked'; - $output = ''; + $output = ''; if($return) return $output; - $allowed_html = array( - 'input' => array( - 'type' => array(), - 'data-*' => array(), - 'checked' => array(), - )); - echo wp_kses($output, $allowed_html); + echo $output; } - - - /** * * Generate status info OR button on media list @@ -578,7 +578,7 @@ public static function mediaListCustomValuesStatus($attachment_id, $return = fal // if(reSmushit::getDisabledState($attachment_id)){ - $output = '-'; + $output = __('Image excluded from optimization','resmushit-image-optimizer'); } else if(reSmushit::getAttachmentQuality($attachment_id) != reSmushit::getPictureQualitySetting()) $output = ''; diff --git a/css/resmushit.css b/css/resmushit.css index 29dc52f..406d8c9 100644 --- a/css/resmushit.css +++ b/css/resmushit.css @@ -180,6 +180,7 @@ height: 25px; position: relative; text-align: center; + margin: 10px 0; } .rsmt-bulk .resmushit--progress--bar p{ font-size: 15px; diff --git a/js/script.js b/js/script.js index 615659b..8aae351 100644 --- a/js/script.js +++ b/js/script.js @@ -11,7 +11,7 @@ var file_too_big_count = 0; /** * Notice */ -jQuery(document).delegate(".rsmt-notice button.notice-dismiss","mouseup",function(e){ +jQuery(document).delegate(".rsmt-notice button.notice-dismiss","click",function(e){ var current = this; var csrf_token = jQuery(current).parent().attr('data-csrf'); jQuery.post( @@ -123,10 +123,12 @@ function resmushit_bulk_process(bulk, item){ jQuery('#bulk_resize_target').remove(); container.append('

'); var results_target = jQuery('#smush_results'); - results_target.html('
'); + results_target.html('
'); flag_removed = true; } + jQuery('#stopbulk').on('click', function () { window.location.reload() }); + bulkCounter++; jQuery('.resmushit--progress--bar').html('

'+ Math.round((bulkCounter*100/bulkTotalimages)) +'%

'); jQuery('.resmushit--progress--bar').animate({'width': Math.round((bulkCounter*100/bulkTotalimages))+'%'}, 0); @@ -260,7 +262,7 @@ function updateDisabledState() { * ajax to Optimize a single picture */ function optimizeSingleAttachment() { - jQuery(document).delegate(".rsmt-trigger--optimize-attachment","mouseup",function(e){ + jQuery(document).delegate(".rsmt-trigger--optimize-attachment","click",function(e){ e.preventDefault(); var current = this; jQuery(current).val(reSmush.strings.optimizing); @@ -317,7 +319,7 @@ function restoreSingleAttachment() * ajax to Optimize a single picture */ function removeBackupFiles() { - jQuery(document).delegate(".rsmt-trigger--remove-backup-files","mouseup",function(e){ + jQuery(document).delegate(".rsmt-trigger--remove-backup-files","click",function(e){ if ( confirm( reSmush.strings.remove_backup_confirm ) ) { e.preventDefault(); @@ -345,7 +347,7 @@ function removeBackupFiles() { * ajax to Optimize a single picture */ function restoreBackupFiles() { - jQuery(document).delegate(".rsmt-trigger--restore-backup-files","mouseup",function(e){ + jQuery(document).delegate(".rsmt-trigger--restore-backup-files","click",function(e){ if ( confirm( reSmush.strings.restore_all_confirm) ) { e.preventDefault(); diff --git a/resmushit.settings.php b/resmushit.settings.php index 028d314..84538e9 100644 --- a/resmushit.settings.php +++ b/resmushit.settings.php @@ -4,7 +4,6 @@ define('RESMUSHIT_VERSION', '1.0.0'); define('RESMUSHIT_DEFAULT_QLTY', '82'); define('RESMUSHIT_TIMEOUT', '10'); -define('RESMUSHIT_LOGS_PATH', 'resmushit.log'); define('RESMUSHIT_LOGS_MAX_FILESIZE', '102400'); define('RESMUSHIT_NEWSFEED', 'https://feed.resmush.it/'); define('RESMUSHIT_FEEDBACK_URL', 'https://resmush.it/contact/'); diff --git a/scss/resmush_admin.scss b/scss/resmush_admin.scss index fb0a3ca..73f0bf1 100644 --- a/scss/resmush_admin.scss +++ b/scss/resmush_admin.scss @@ -35,4 +35,6 @@ } + + } From 4576803f4d82d29385542be95ca410b0498d6d18 Mon Sep 17 00:00:00 2001 From: Bas Schuiling Date: Wed, 21 Feb 2024 17:28:29 +0200 Subject: [PATCH 10/21] Fixes UI / Qol so far --- classes/Controller/AdminController.php | 26 +++++--- classes/resmushitUI.class.php | 56 +++++++++++++---- css/resmush_admin.css | 61 ++++++++++++++++++- css/resmush_admin.css.map | 2 +- css/resmushit.css | 14 +++-- images/shortpixel-text-logo.svg | 83 ++++++++++++++++++++++++++ scss/resmush_admin.scss | 80 ++++++++++++++++++++++++- 7 files changed, 296 insertions(+), 26 deletions(-) create mode 100644 images/shortpixel-text-logo.svg diff --git a/classes/Controller/AdminController.php b/classes/Controller/AdminController.php index 4e1d87d..ee31fb7 100644 --- a/classes/Controller/AdminController.php +++ b/classes/Controller/AdminController.php @@ -196,18 +196,16 @@ public function image_attachment_add_status_button($form_fields, $post) { */ public function settings_page() { ?> -
-
+
-
@@ -229,9 +227,21 @@ public function settings_page() {
-

ADS

+
+ +
    +
  • Unlimited image optimization
  • +
  • Unlimited domains
  • +
  • WebP&AVIF conversion
  • +
  • $9.99 / month
  • +
+
+ Buy now +
+
-
+ +

$title

"); } @@ -71,8 +71,8 @@ public static function fullWidthPanelEndWrapper() { * @return none */ public static function headerPanel() { - $html = ""; - $html = ""; + //$html = ""; + $html = sprintf("", '', ''); self::fullWidthPanel('ReSmush.it', $html); } @@ -121,7 +121,7 @@ public static function settingsPanel() { echo '' - . self::addSetting("text", __("Image quality", 'resmushit-image-optimizer'), __("A lower value means a smaller image size, a higher value means better image quality. A value between 50 and 85 is normally recommended.", 'resmushit-image-optimizer'), "resmushit_qlty") + . self::addSetting("number", __("Image quality", 'resmushit-image-optimizer'), __("A lower value means a smaller image size, a higher value means better image quality. A value between 50 and 85 is normally recommended.", 'resmushit-image-optimizer'), "resmushit_qlty") . self::addSetting("checkbox", __("Optimize on upload", 'resmushit-image-optimizer'), __("Once activated, newly uploaded images are automatically optimized.", 'resmushit-image-optimizer'), "resmushit_on_upload") . self::addSetting("checkbox", __("Preserve EXIF", 'resmushit-image-optimizer'), __("Activate this option to retain the original EXIF data in the images.", 'resmushit-image-optimizer'), "resmushit_preserve_exif") . self::addSetting("checkbox", __("Deactivate backup", 'resmushit-image-optimizer'), sprintf(__("If you select this option, you choose not to keep the original version of the images. This is helpful to save disk space, but we strongly recommend having a backup of the entire website on hand. More information.", "resmushit-image-optimizer"), "https://resmush.it/why-preserving-backup-files/"), "resmushit_remove_unsmushed") @@ -243,6 +243,8 @@ public static function bigFilesPanel() { $fileInfo = pathinfo(get_attached_file( $file->ID )); $filesize = reSmushitUI::sizeFormat(filesize(get_attached_file( $file->ID ))); + echo "
  • " . + sprintf(__('You can optimize these images with %s ShortPixel Image Optimizer %s','resmushit-image-optimizer'), '', '') . "

  • "; echo wp_kses_post("
  • " @@ -308,9 +310,36 @@ public static function statisticsPanel() { public static function feedbackPanel() { - self::fullWidthPanelWrapper(__('Feedback', 'resmushit-image-optimizer'), null, 'green'); + self::fullWidthPanelWrapper(__('Support', 'resmushit-image-optimizer'), null, 'green'); + + + ?> +