WebP Express CloudHost.es Fix v0.25.9-cloudhost

 Fixed bulk conversion getting stuck on missing files
 Added robust error handling and timeout protection
 Improved JavaScript response parsing
 Added file existence validation
 Fixed missing PHP class imports
 Added comprehensive try-catch error recovery

🔧 Key fixes:
- File existence checks before conversion attempts
- 30-second timeout protection per file
- Graceful handling of 500 errors and JSON parsing issues
- Automatic continuation to next file on failures
- Cache busting for JavaScript updates

🎯 Result: Bulk conversion now completes successfully even with missing files

🚀 Generated with Claude Code (https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-09-23 10:22:32 +02:00
commit 37cf714058
553 changed files with 55249 additions and 0 deletions

44
lib/migrate/migrate.php Normal file
View File

@@ -0,0 +1,44 @@
<?php
use \WebPExpress\Config;
use \WebPExpress\Messenger;
use \WebPExpress\Option;
use \WebPExpress\State;
/*
In 0.4.0, we had a 'webp-express-configured' option.
As long as there are still users on 0.4 or below, we must do the following:
*/
if (Option::getOption('webp-express-configured', false)) {
State::setState('configured', true);
}
/*
In 0.1, we did not have the 'webp-express-configured' option.
To determine if WebP Express was configured in 0.1, we can test the (now obsolete) webp_express_converters option
As long as there are still users on 0.1, we must do the following:
*/
if (!Option::getOption('webp-express-configured', false)) {
if (!is_null(Option::getOption('webp_express_converters', null))) {
State::setState('configured', true);
}
}
if (!(State::getState('configured', false))) {
// Options has never has been saved, so no migration is needed.
// We can set migrate-version to current
Option::updateOption('webp-express-migration-version', WEBPEXPRESS_MIGRATION_VERSION);
} else {
for ($x = intval(Option::getOption('webp-express-migration-version', 0)); $x < WEBPEXPRESS_MIGRATION_VERSION; $x++) {
if (intval(Option::getOption('webp-express-migration-version', 0)) == $x) {
// run migration X+1, which upgrades from X to X+1
// It must take care of updating the "webp-express-migration-version" option to X+1, - if successful.
// If unsuccessful, it must leaves the option unaltered, which will prevent
// newer migrations to run, until the problem with that migration is fixed.
include __DIR__ . '/migrate' . ($x + 1) . '.php';
}
}
}
//KeepEwwwSubscriptionAlive::keepAliveIfItIsTime($config);

204
lib/migrate/migrate1.php Normal file
View File

@@ -0,0 +1,204 @@
<?php
namespace WebPExpress;
use \WebPExpress\Config;
use \WebPExpress\HTAccess;
use \WebPExpress\Messenger;
use \WebPExpress\Option;
use \WebPExpress\Paths;
// On successful migration:
// Option::updateOption('webp-express-migration-version', '1', true);
function webp_express_migrate1_createFolders()
{
if (!Paths::createContentDirIfMissing()) {
Messenger::printMessage(
'error',
'For migration to 0.5.0, WebP Express needs to create a directory "webp-express" under your wp-content folder, but does not have permission to do so.<br>' .
'Please create the folder manually, or change the file permissions of your wp-content folder.'
);
return false;
} else {
if (!Paths::createConfigDirIfMissing()) {
Messenger::printMessage(
'error',
'For migration to 0.5.0, WebP Express needs to create a directory "webp-express/config" under your wp-content folder, but does not have permission to do so.<br>' .
'Please create the folder manually, or change the file permissions.'
);
return false;
}
if (!Paths::createCacheDirIfMissing()) {
Messenger::printMessage(
'error',
'For migration to 0.5.0, WebP Express needs to create a directory "webp-express/webp-images" under your wp-content folder, but does not have permission to do so.<br>' .
'Please create the folder manually, or change the file permissions.'
);
return false;
}
}
return true;
}
function webp_express_migrate1_createDummyConfigFiles()
{
// TODO...
return true;
}
function webpexpress_migrate1_migrateOptions()
{
$converters = json_decode(Option::getOption('webp_express_converters', '[]'), true);
foreach ($converters as &$converter) {
unset ($converter['id']);
}
$options = [
'image-types' => intval(Option::getOption('webp_express_image_types_to_convert', 1)),
'max-quality' => intval(Option::getOption('webp_express_max_quality', 80)),
'fail' => Option::getOption('webp_express_failure_response', 'original'),
'converters' => $converters,
'forward-query-string' => true
];
if ($options['max-quality'] == 0) {
$options['max-quality'] = 80;
if ($options['image-types'] == 0) {
$options['image-types'] = 1;
}
}
if ($options['converters'] == null) {
$options['converters'] = [];
}
// TODO: Save
//Messenger::addMessage('info', 'Options: <pre>' . print_r($options, true) . '</pre>');
// $htaccessExists = Config::doesHTAccessExists();
$config = $options;
//$htaccessExists = Config::doesHTAccessExists();
//$rules = HTAccess::generateHTAccessRulesFromConfigObj($config);
if (Config::saveConfigurationFile($config)) {
$options = Config::generateWodOptionsFromConfigObj($config);
if (Config::saveWodOptionsFile($options)) {
Messenger::addMessage(
'success',
'WebP Express has successfully migrated its configuration to 0.5.0'
);
//Config::saveConfigurationAndHTAccessFilesWithMessages($config, 'migrate');
//$rulesResult = HTAccess::saveRules($config); // Commented out because rules are going to be saved in migrate12
/*
'mainResult' // 'index', 'wp-content' or 'failed'
'minRequired' // 'index' or 'wp-content'
'pluginToo' // 'yes', 'no' or 'depends'
'pluginFailed' // true if failed to write to plugin folder (it only tries that, if pluginToo == 'yes')
'pluginFailedBadly' // true if plugin failed AND it seems we have rewrite rules there
'overidingRulesInWpContentWarning' // true if main result is 'index' but we cannot remove those in wp-content
'rules' // the rules that were generated
*/
/*
$mainResult = $rulesResult['mainResult'];
$rules = $rulesResult['rules'];
if ($mainResult != 'failed') {
Messenger::addMessage(
'success',
'WebP Express has successfully migrated its configuration and updated the rewrite rules to 0.5.0'
);
} else {
Messenger::addMessage(
'warning',
'WebP Express has successfully migrated its configuration.' .
'However, WebP Express could not update the rewrite rules<br>' .
'You need to change some permissions. Head to the ' .
'<a href="' . Paths::getSettingsUrl() . '">settings page</a> ' .
'and try to save the settings there (it will provide more information about the problem)'
);
}
*/
} else {
Messenger::addMessage(
'error',
'For migration to 0.5.0, WebP Express failed saving options file. ' .
'You must grant us write access to your wp-config folder.<br>' .
'Tried to save to: "' . Paths::getWodOptionsFileName() . '"' .
'Fix the file permissions and reload<br>'
);
return false;
}
} else {
Messenger::addMessage(
'error',
'For migration to 0.5.0, WebP Express failed saving configuration file.<br>' .
'You must grant us write access to your wp-config folder.<br>' .
'Tried to save to: "' . Paths::getConfigFileName() . '"' .
'Fix the file permissions and reload<br>'
);
return false;
}
//saveConfigurationFile
//return $options;
return true;
}
function webpexpress_migrate1_deleteOldOptions() {
$optionsToDelete = [
'webp_express_max_quality',
'webp_express_image_types_to_convert',
'webp_express_failure_response',
'webp_express_converters',
'webp-express-inserted-rules-ok',
'webp-express-configured',
'webp-express-pending-messages',
'webp-express-just-activated',
'webp-express-message-pending',
'webp-express-failed-inserting-rules',
'webp-express-deactivate',
'webp_express_fail_action',
'webp_express_method',
'webp_express_quality'
];
foreach ($optionsToDelete as $i => $optionName) {
Option::deleteOption($optionName);
}
}
/* helper. Remove dir recursively. No warnings - fails silently */
function webpexpress_migrate1_rrmdir($dir) {
if (@is_dir($dir)) {
$objects = @scandir($dir);
foreach ($objects as $object) {
if ($object != "." && $object != "..") {
if (@is_dir($dir."/".$object))
webpexpress_migrate1_rrmdir($dir."/".$object);
else
@unlink($dir."/".$object);
}
}
@rmdir($dir);
}
}
function webpexpress_migrate1_deleteOldWebPImages() {
$upload_dir = wp_upload_dir();
$destinationRoot = trailingslashit($upload_dir['basedir']) . 'webp-express';
webpexpress_migrate1_rrmdir($destinationRoot);
}
if (webp_express_migrate1_createFolders()) {
if (webp_express_migrate1_createDummyConfigFiles()) {
if (webpexpress_migrate1_migrateOptions()) {
webpexpress_migrate1_deleteOldOptions();
webpexpress_migrate1_deleteOldWebPImages();
Option::updateOption('webp-express-migration-version', '1');
}
}
}

68
lib/migrate/migrate10.php Normal file
View File

@@ -0,0 +1,68 @@
<?php
namespace WebPExpress;
use \WebPExpress\Config;
use \WebPExpress\Messenger;
function webpexpress_migrate10() {
$config = Config::loadConfigAndFix(false); // false, because we do not need to test if quality detection is working
$converters = &$config['converters'];
if (is_array($converters)) {
// Change specific converter options
foreach ($converters as &$converter) {
if (!isset($converter['converter'])) {
continue;
}
$options = &$converter['options'];
switch ($converter['converter']) {
case 'wpc':
if (isset($options['api-version'])) {
$options['api-version'] = intval($options['api-version']);
} else {
$options['api-version'] = 1;
}
break;
case 'cwebp':
if (isset($options['method'])) {
$options['method'] = intval($options['method']);
} else {
$options['method'] = 6;
}
if (isset($options['size-in-percentage'])) {
$options['size-in-percentage'] = intval($options['size-in-percentage']);
}
break;
}
}
}
// Save both configs.
// The reason we do it is that we need to update wod-options.json, so the scripts can access the newly available
// "enable-redirection-to-converter" and "enable-redirection-to-webp-realizer" options
$forceHtaccessRegeneration = false;
$result = Config::saveConfigurationAndHTAccess($config, $forceHtaccessRegeneration);
if ($result['saved-both-config']) {
Messenger::addMessage(
'info',
'Successfully migrated <i>WebP Express</i> options for 0.14.9.'
);
Option::updateOption('webp-express-migration-version', '10');
} else {
Messenger::addMessage(
'error',
'Failed migrating webp express options to 0.14.9. Probably you need to grant write permissions in your wp-content folder.'
);
}
}
webpexpress_migrate10();

77
lib/migrate/migrate11.php Normal file
View File

@@ -0,0 +1,77 @@
<?php
namespace WebPExpress;
use \WebPExpress\Config;
use \WebPExpress\Messenger;
function webpexpress_migrate11() {
$config = Config::loadConfigAndFix(false); // false, because we do not need to test if quality detection is working
// There is a new option: "scope"
// We want to set it to match current setup as closely as possible.
$rootsWithRulesIn = HTAccess::getRootsWithWebPExpressRulesIn();
if (in_array('index', $rootsWithRulesIn)) {
$scope = ['index', 'plugins', 'themes', 'uploads', 'wp-content'];
} elseif (in_array('wp-content', $rootsWithRulesIn)) {
$scope = ['plugins', 'themes', 'uploads', 'wp-content'];
} else {
$scope = ['themes', 'uploads'];
}
// However, if some of the roots cannot be used, we remove these.
$scope2 = [];
foreach ($scope as $rootId) {
if (Paths::canWriteHTAccessRulesInDir($rootId)) {
$scope2[] = $rootId;
}
}
if (count($scope2) == 0) {
Messenger::addMessage(
'warning',
'WebP Express cannot update the .htaccess rules that it needs to. ' .
'Please go to WebP Express settings and click "Save settings and force new .htaccess rules".'
);
$scope2 = ['themes', 'uploads'];
}
$config['scope'] = $scope2;
if (in_array('index', $config['scope'])) {
DismissableMessages::addDismissableMessage('0.15.0/new-scope-setting-index');
} elseif (in_array('wp-content', $config['scope'])) {
DismissableMessages::addDismissableMessage('0.15.0/new-scope-setting-content');
} elseif (!in_array('uploads', $config['scope'])) {
DismissableMessages::addDismissableMessage('0.15.0/new-scope-setting-no-uploads');
}
/*
error_log('roots with rules:' . implode(',', $rootsWithRulesIn));
error_log('scope:' . implode(',', $config['scope']));
error_log('scope2:' . implode(',', $scope2));*/
$forceHtaccessRegeneration = true;
$result = Config::saveConfigurationAndHTAccess($config, $forceHtaccessRegeneration);
if ($result['saved-both-config']) {
Messenger::addMessage(
'info',
'Successfully migrated <i>WebP Express</i> options for 0.15.0.'
);
Option::updateOption('webp-express-migration-version', '11');
} else {
Messenger::addMessage(
'error',
'Failed migrating webp express options to 0.15.0. Probably you need to grant write permissions in your wp-content folder.'
);
}
}
webpexpress_migrate11();

40
lib/migrate/migrate12.php Normal file
View File

@@ -0,0 +1,40 @@
<?php
namespace WebPExpress;
use \WebPExpress\Config;
use \WebPExpress\Messenger;
use \WebPExpress\Option;
function webpexpress_migrate12() {
$config = Config::loadConfigAndFix(false); // false, because we do not need to test if quality detection is working
/*
if (($config['destination-extension'] == 'set') && ($config['destination-folder'] == 'mingled')) {
DismissableMessages::addDismissableMessage('0.15.1/problems-with-mingled-set');
Messenger::addMessage(
'error',
'WebP Express is experiencing technical problems with your particular setup. ' .
'Please <a href="' . Paths::getSettingsUrl() . '">go to the settings page</a> to fix.'
);
}*/
$forceHtaccessRegeneration = true;
$result = Config::saveConfigurationAndHTAccess($config, $forceHtaccessRegeneration);
if ($result['saved-both-config']) {
Option::updateOption('webp-express-migration-version', '12');
} else {
Messenger::addMessage(
'error',
'Failed migrating webp express options to 0.15.1. Probably you need to grant write permissions in your wp-content folder.'
);
}
}
webpexpress_migrate12();

42
lib/migrate/migrate13.php Normal file
View File

@@ -0,0 +1,42 @@
<?php
namespace WebPExpress;
function webpexpress_migrate13_add_ffmpeg_message_if_relevant()
{
$config = Config::loadConfigAndFix(false); // false, because we do not need to test if quality detection is working
$config = Config::updateConverterStatusWithFreshTest($config); // Test all converters (especially we are excited to learn if the new ffmpeg converter is working)
$workingConverterIds = ConvertersHelper::getWorkingAndActiveConverterIds($config);
if (!in_array('ffmpeg', $workingConverterIds)) {
// ffmpeg is not working on the host, so no need to announce ffmpeg
return;
}
$betterConverterIds = ['cwebp', 'vips', 'imagemagick', 'graphicsmagick', 'imagick', 'gmagick', 'wpc'];
$workingAndBetter = array_intersect($workingConverterIds, $betterConverterIds);
if (count($workingAndBetter) > 0) {
// the user already has a better conversion method working. No reason to disturb
return;
}
if (in_array('gd', $workingConverterIds)) {
DismissableGlobalMessages::addDismissableMessage('0.19.0/meet-ffmpeg-better-than-gd');
} elseif (in_array('ewww', $workingConverterIds)) {
DismissableGlobalMessages::addDismissableMessage('0.19.0/meet-ffmpeg-better-than-ewww');
} else {
DismissableGlobalMessages::addDismissableMessage('0.19.0/meet-ffmpeg-a-working-conversion-method');
}
}
function webpexpress_migrate13() {
Option::updateOption('webp-express-migration-version', '13');
webpexpress_migrate13_add_ffmpeg_message_if_relevant();
}
webpexpress_migrate13();

36
lib/migrate/migrate14.php Normal file
View File

@@ -0,0 +1,36 @@
<?php
namespace WebPExpress;
use \WebPExpress\Config;
use \WebPExpress\Messenger;
use \WebPExpress\Option;
function webpexpress_migrate14() {
// Update migrate version right away to minimize risk of running the update twice in a multithreaded environment
Option::updateOption('webp-express-migration-version', '14');
$config = Config::loadConfigAndFix(false); // false means we do not need the check if quality detection is supported
if (($config['enable-redirection-to-converter']) || ($config['redirect-to-existing-in-htaccess'])) {
// We need to regenerate .htaccess files in case redirection to webp is enabled. Two reasons:
// 1: WebP On Demand rules needs fixing (#520)
// 2: The new escape hatch (#522), which is needed for the File Manager (#521)
wp_schedule_single_event(time() + 10, 'webp_express_task_regenerate_config_and_htaccess');
} else {
/*
if (isset($config['alter-html']) && $config['alter-html']['enabled']) {
// Schedule to regenate config, because we need to update autoloaded options in order to
// autoload the new alter-html/prevent-using-webps-larger-than-original option
// (hm, actually it defaults to true, so it should be neccessary...)
wp_schedule_single_event(time() + 10, 'webp_express_task_regenerate_config');
}*/
}
// Schedule bulk update dummy files
wp_schedule_single_event(time() + 30, 'webp_express_task_bulk_update_dummy_files');
}
webpexpress_migrate14();

67
lib/migrate/migrate2.php Normal file
View File

@@ -0,0 +1,67 @@
<?php
namespace WebPExpress;
use \WebPExpress\Messenger;
use \WebPExpress\Option;
use \WebPExpress\Paths;
use \WebPExpress\TestRun;
/* helper. Remove dir recursively. No warnings - fails silently
Set $removeTheDirItself to false if you want to empty the dir
*/
function webpexpress_migrate2_rrmdir($dir, $removeTheDirItself = true) {
if (@is_dir($dir)) {
$objects = @scandir($dir);
foreach ($objects as $object) {
if ($object != "." && $object != "..") {
$file = $dir . "/" . $object;
if (@is_dir($file)) {
webpexpress_migrate2_rrmdir($file);
} else {
@unlink($file);
}
}
}
if ($removeTheDirItself) {
@rmdir($dir);
}
}
}
$testResult = TestRun::getConverterStatus();
if ($testResult) {
$workingConverters = $testResult['workingConverters'];
if (in_array('imagick', $workingConverters)) {
webpexpress_migrate2_rrmdir(Paths::getCacheDirAbs(), false);
Messenger::addMessage(
'info',
'WebP Express has emptied the image cache. In previous versions, the imagick converter ' .
'was generating images in poor quality. This has been fixed. As your system meets the ' .
'requirements of the imagick converter, it might be that you have been using that. So ' .
'to be absolutely sure you do not have inferior conversions in the cache dir, it has been emptied.'
);
}
if (in_array('gmagick', $workingConverters)) {
Messenger::addMessage(
'info',
'Good news! WebP Express is now able to use the gmagick extension for conversion - ' .
'and your server meets the requirements!'
);
}
if (in_array('cwebp', $workingConverters)) {
Messenger::addMessage(
'info',
'WebP Express added several options for the cwebp conversion method. ' .
'<a href="' . Paths::getSettingsUrl() . '">Go to the settings page to check it out</a>.'
);
}
}
Messenger::addMessage(
'info',
'WebP Express can now be configured to cache the webp images. You might want to ' .
'<a href="' . Paths::getSettingsUrl() . '">do that</a>.'
);
Option::updateOption('webp-express-migration-version', '2');

119
lib/migrate/migrate3.php Normal file
View File

@@ -0,0 +1,119 @@
<?php
namespace WebPExpress;
use \WebPExpress\FileHelper;
use \WebPExpress\Messenger;
use \WebPExpress\Option;
use \WebPExpress\Paths;
use \WebPExpress\PathHelper;
if ( ! function_exists('webp_express_glob_recursive'))
{
// Does not support flag GLOB_BRACE
function webp_express_glob_recursive($pattern, $flags = 0)
{
$files = glob($pattern, $flags);
foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir)
{
$files = array_merge($files, webp_express_glob_recursive($dir.'/'.basename($pattern), $flags));
}
return $files;
}
}
function webpexpress_migrate3() {
$dirs = glob(PathHelper::canonicalize(Paths::getCacheDirAbs()) . '/doc-root*');
$movedAtLeastOneFile = false;
$failedMovingAtLeastOneFile = false;
$atLeastOneFileMustBeMoved = false;
$failedRemovingAtLeastOneDir = false;
foreach ($dirs as $dir) {
if (preg_match('/\/doc-root$/i', $dir)) {
// do not process the "doc-root" dir
continue;
}
$files = webp_express_glob_recursive($dir . '/*.webp');
foreach ($files as $file) {
$atLeastOneFileMustBeMoved = true;
$newName = preg_replace('/\/doc-root(.*)$/', '/doc-root/$1', $file);
$dirName = FileHelper::dirName($newName);
if (!file_exists($dirName)) {
mkdir($dirName, 0775, true);
}
if (@rename($file, $newName)) {
$movedAtLeastOneFile = true;
} else {
$failedMovingAtLeastOneFile = true;
}
}
if (!FileHelper::rrmdir($dir)) {
$failedRemovingAtLeastOneDir = true;
}
}
if ($atLeastOneFileMustBeMoved) {
if ($movedAtLeastOneFile && !$failedMovingAtLeastOneFile && !$failedRemovingAtLeastOneDir) {
Messenger::addMessage(
'info',
'Successfully fixed cache directory structure. Dont know what its all about? Never mind, all is okay.'
);
} else {
if ($failedRemovingAtLeastOneDir) {
Messenger::addMessage(
'warning',
'A minor bug caused the cache directory structure to be wrong on your system ' .
'(<a href="https://github.com/rosell-dk/webp-express/issues/96" target="_blank">issue #96</a>). ' .
'The bug has been fixed, but unfortunately the file permissions does not allow WebP Convert to clean up the file structure. ' .
'To clean up manually, delete all folders in your wp-content/webp-express/webp-images folder beginning with "doc-root" (but not the "doc-root" folder itself)'
);
}
}
}
// Show "Whats new" message.
// We test the version, because we do not want a whole lot of "whats new" messages
// to show when updating many versions in one go. Just the recent, please.
if (WEBPEXPRESS_MIGRATION_VERSION == '3') {
Messenger::addMessage(
'info',
'<i>New in WebP Express 0.8.0:</i>' .
'<ul style="list-style-type:disc;margin-left:20px">' .
'<li>New conversion method, which calls imagick binary directly</li>' .
'<li>Made sure not to trigger LFI warning i Wordfence (to activate, click the force .htaccess button)</li>' .
"<li>Imagick can now be configured to set quality to auto on systems where the auto option isn't generally available</li>" .
'<li><a href="https://github.com/rosell-dk/webp-express/issues?q=is%3Aclosed+milestone%3A0.8.0">and more...</a></li>' .
'</ul>' .
'</ul>' .
'<br><i>Roadmap / wishlist:</i>' .
'<ul style="list-style-type:disc;margin-left:20px">' .
'<li>Rule in .htaccess to serve already converted images immediately (optional)</li>' .
'<li>Better NGINX support (print rules that needs to be manually inserted in nginx.conf)</li>' .
'<li>Diagnose button</li>' .
'<li>A file explorer for viewing converted images, reconverting them, and seeing them side by side with the original</li>' .
'<li>IIS support, WAMP support, Multisite support</li>' .
'<li><a href="https://github.com/rosell-dk/webp-express/issues">and more...</a></li>' .
'</ul>' .
'<b>Please help me making this happen faster / happen at all by donating even a small sum. ' .
'<a href="https://ko-fi.com/rosell" target="_blank" >Buy me a coffee</a>, ' .
'or support me on <a href="http://www.patreon.com/rosell" target="_blank" >patreon.com</a>' .
'</b>'
);
}
// PSST: When creating new migration files, remember to update WEBPEXPRESS_MIGRATION_VERSION in admin.php
Option::updateOption('webp-express-migration-version', '3');
}
webpexpress_migrate3();

64
lib/migrate/migrate4.php Normal file
View File

@@ -0,0 +1,64 @@
<?php
namespace WebPExpress;
use \WebPExpress\Config;
use \WebPExpress\Messenger;
use \WebPExpress\Option;
function webpexpress_migrate4() {
$config = Config::loadConfig();
if ($config !== false) {
if (isset($config['cache-control'])) {
switch ($config['cache-control']) {
case 'no-header':
break;
case 'custom':
break;
default:
$config['cache-control-max-age'] = $config['cache-control'];
$config['cache-control'] = 'set';
$config['cache-control-public'] = true;
Config::saveConfigurationFile($config);
}
}
if (isset($config['fail']) && ($config['fail'] != 'original')) {
$config['operation-mode'] = 'tweaked';
if (Config::saveConfigurationFile($config)) {
Messenger::addMessage(
'info',
'WebP Express 0.10 introduces <i>operation modes</i>. Your configuration <i>almost</i> fits the mode called ' .
'<i>Standard</i>, however as you have set the <i>Response on failure</i> option to something other than ' .
'<i>Original</i>, your setup has been put into <i>Tweaked</i> mode. ' .
'<a href="' . Paths::getSettingsUrl() . '">You might want to go and change that</a>.'
);
}
}
if (isset($config['redirect-to-existing-in-htaccess']) && ($config['redirect-to-existing-in-htaccess'])) {
Messenger::addMessage(
'info',
'In WebP Express 0.10, the <i>.htaccess</i> rules has been altered a bit: The Cache-Control header is now set when ' .
'redirecting directly to an existing webp image.<br>' .
'You might want to <a href="' . Paths::getSettingsUrl() . '">go to the options page</a> and re-save settings in order to regenerate the <i>.htaccess</i> rules.'
);
}
if (!isset($config['redirect-to-existing-in-htaccess'])) {
Messenger::addMessage(
'info',
'In WebP Express 0.10, the "Redirect directly to converted image when available" option is no longer in beta. ' .
'You might want to <a href="' . Paths::getSettingsUrl() . '">go and activate it</a>.'
);
}
}
// PSST: When creating new migration files, remember to update WEBPEXPRESS_MIGRATION_VERSION in admin.php
Option::updateOption('webp-express-migration-version', '4');
}
webpexpress_migrate4();

50
lib/migrate/migrate5.php Normal file
View File

@@ -0,0 +1,50 @@
<?php
namespace WebPExpress;
use \WebPExpress\CacheMover;
use \WebPExpress\Config;
use \WebPExpress\Messenger;
use \WebPExpress\Option;
function webpexpress_migrate5() {
// Regenerate configuration file and wod-options.json.
// By regenerating the config, we ensure that Config::updateAutoloadedOptions() is called,
// By regenerating wod-options.json, we ensure that the new "paths" option is there, which is required in "mingled" mode for
// determining if an image resides in the uploads folder or not.
$config = Config::loadConfigAndFix(false); // false, because we do not need to test if quality detection is working
if ($config['operation-mode'] == 'just-convert') {
$config['operation-mode'] = 'no-varied-responses';
}
if ($config['operation-mode'] == 'standard') {
$config['operation-mode'] = 'varied-responses';
}
if (Config::saveConfigurationFileAndWodOptions($config)) {
// Moving destination in v0.10 might have created bad permissions. - so lets fix the permissions
//CacheMover::chmodFixSubDirs(CacheMover::getUploadFolder($config['destination-folder']));
CacheMover::chmodFixSubDirs(Paths::getCacheDirAbs(), true);
CacheMover::chmodFixSubDirs(Paths::getUploadDirAbs(), false);
Messenger::addMessage(
'info',
'Successfully migrated <i>WebP Express</i> options for 0.11+'
);
// PSST: When creating new migration files, remember to update WEBPEXPRESS_MIGRATION_VERSION in admin.php
Option::updateOption('webp-express-migration-version', '5');
} else {
Messenger::addMessage(
'error',
'Failed migrating WebP Express options to 0.11+. Probably you need to grant write permissions in your wp-content folder.'
);
}
}
webpexpress_migrate5();

68
lib/migrate/migrate6.php Normal file
View File

@@ -0,0 +1,68 @@
<?php
namespace WebPExpress;
use \WebPExpress\Config;
use \WebPExpress\Messenger;
use \WebPExpress\HTAccess;
use \WebPExpress\Paths;
use \WebPExpress\Option;
/**
* Fix records - if possible
*/
function webpexpress_migrate6_fixHtaccessRecordsForDir($dirId) {
$haveRules = HTAccess::haveWeRulesInThisHTAccess(Paths::getAbsDirById($dirId) . '/.htaccess');
// PS: $haveRules may be null, meaning "maybe"
if ($haveRules === true) {
HTAccess::addToActiveHTAccessDirsArray($dirId);
}
if ($haveRules === false) {
HTAccess::removeFromActiveHTAccessDirsArray($dirId);
}
}
function webpexpress_migrate6() {
// Regenerate .htaccess file if placed in root (so rewrites does not apply in wp-admin area)
if (HTAccess::isInActiveHTAccessDirsArray('index')) {
if (Config::isConfigFileThere()) {
$config = Config::loadConfigAndFix(false); // false, because we do not need to test if quality detection is working
$rules = HTAccess::generateHTAccessRulesFromConfigObj($config, 'index');
$success = (HTAccess::saveHTAccessRulesToFile(Paths::getIndexDirAbs() . '/.htaccess', $rules, true));
if ($success) {
Messenger::addMessage(
'info',
'Fixed .htaccess rules in root (the old rules were also applying to wp-admin folder. In some cases this resulted in problems with the media library).'
);
} else {
Messenger::addMessage(
'warning',
'Tried to fix .htaccess rules in root folder (the old rules applied to wp-admin, which in some cases resulted in problems with media library). However, the attempt failed.'
);
}
}
}
// The records about which .htaccess files that contains rules were not correct.
// Correct them if possible (haveWeRulesInThisHTAccess() may return null, if we cannot determine)
// https://github.com/rosell-dk/webp-express/issues/169
$dirsToFix = [
'index',
'home',
'wp-content',
'plugins',
'uploads'
];
foreach ($dirsToFix as $dirId) {
webpexpress_migrate6_fixHtaccessRecordsForDir($dirId);
}
Option::updateOption('webp-express-migration-version', '6');
}
webpexpress_migrate6();

91
lib/migrate/migrate7.php Normal file
View File

@@ -0,0 +1,91 @@
<?php
namespace WebPExpress;
use \WebPExpress\Config;
use \WebPExpress\HTAccess;
use \WebPExpress\Messenger;
use \WebPExpress\Option;
function webpexpress_migrate7() {
$config = Config::loadConfigAndFix(false); // false, because we do not need to test if quality detection is working
if ($config['operation-mode'] == 'just-redirect') {
$config['operation-mode'] = 'no-conversion';
}
if ($config['operation-mode'] == 'no-varied-responses') {
$config['operation-mode'] = 'cdn-friendly';
}
if ($config['operation-mode'] == 'varied-responses') {
$config['operation-mode'] = 'varied-image-responses';
}
if (isset($config['do-not-pass-source-in-query-string'])) {
unset($config['do-not-pass-source-in-query-string']);
}
// Migrate some configurations to the new "No conversion" mode
if ((!$config['enable-redirection-to-webp-realizer']) && (!$config['enable-redirection-to-converter']) && ($config['destination-folder'] == 'mingled') && ($config['operation-mode'] == 'cdn-friendly') && (!($config['web-service']['enabled']))) {
$config['operation-mode'] = 'no-conversion';
}
// In next migration, we can remove do-not-pass-source-in-query-string
// unset($config['do-not-pass-source-in-query-string']);
// and also do: grep -r 'do-not-pass' .
if (Config::saveConfigurationFileAndWodOptions($config)) {
$msg = 'Successfully migrated <i>WebP Express</i> options for 0.12. ';
// The webp realizer rules where errornous, so recreate rules, if necessary. (see issue #195)
if (($config['enable-redirection-to-webp-realizer']) && ($config['destination-folder'] != 'mingled')) {
//HTAccess::saveRules($config); // Commented out because rules are going to be saved in migrate12
$msg .= 'Also fixed <a target="_blank" href="https://github.com/rosell-dk/webp-express/issues/195">buggy</a> <i>.htaccess</i> rules. ';
}
if (!$config['alter-html']['enabled']) {
if ($config['operation-mode'] == 'varied-responses') {
$msg .= '<br>In WebP Express 0.12, the <i>Alter HTML</i> option is no longer in beta. ' .
'<i>You should consider to go and <a href="' . Paths::getSettingsUrl() . '">activate it</a></i> - ' .
'It works great in <i>Varied Image Responses</i> mode too. ';
} else {
$msg .= '<br>In WebP Express 0.12, Alter HTML is no longer in beta. ' .
'<i>Now would be a good time to <a href="' . Paths::getSettingsUrl() . '">go and activate it!</a></i>. ';
}
}
// Display announcement. But only show while it is fresh news (we don't want this to show when one is upgrading from 0.11 to 0.14 or something)
// - the next release with a migration in it will not show the announcement
if (WEBPEXPRESS_MIGRATION_VERSION == 7) {
$msg .= '<br><br>Btw: From this release and onward, WebP Express is <i>multisite compliant</i>.';
}
Messenger::addMessage(
'info',
$msg
);
if ($config['operation-mode'] == 'no-conversion') {
Messenger::addMessage(
'info',
'WebP Express introduces a new operation mode: "No conversion". ' .
'Your configuration has been migrated to this mode, because your previous settings matched that mode (nothing where set up to trigger a conversion).'
);
}
// PSST: When creating new migration files, remember to update WEBPEXPRESS_MIGRATION_VERSION in admin.php
Option::updateOption('webp-express-migration-version', '7');
// Not completely sure if this could fail miserably, so commented out.
// We should probably do it in upcoming migrations
// \WebPExpress\KeepEwwwSubscriptionAlive::keepAliveIfItIsTime($config);
} else {
Messenger::addMessage(
'error',
'Failed migrating webp express options to 0.12+. Probably you need to grant write permissions in your wp-content folder.'
);
}
}
webpexpress_migrate7();

98
lib/migrate/migrate8.php Normal file
View File

@@ -0,0 +1,98 @@
<?php
namespace WebPExpress;
use \WebPExpress\Config;
use \WebPExpress\Messenger;
use \WebPExpress\Option;
use \WebPExpress\Paths;
function webpexpress_migrate8() {
$config = Config::loadConfigAndFix(false); // false, because we do not need to test if quality detection is working
$converters = $config['converters'];
if (is_array($converters)) {
$firstActiveAndWorking;
foreach ($converters as $converter) {
if (isset($converter['deactivated']) && $converter['deactivated']) {
continue;
}
if (isset($converter['working']) && !$converter['working']) {
continue;
}
$firstActiveAndWorking = $converter;
break;
}
if (isset($firstActiveAndWorking)) {
if (isset($firstActiveAndWorking['converter']) && $firstActiveAndWorking['converter'] == 'gd') {
// First working converter is Gd.
if (isset($firstActiveAndWorking['options']) && $firstActiveAndWorking['options']['skip-pngs'] === false) {
// And it is set up to convert PNG's
Messenger::addMessage(
'info',
'Service notice from WebP Express:<br>' .
'You have been using <i>Gd</i> to convert PNGs. ' .
'However, due to a bug, in some cases transparency was lost in the webp. ' .
'It is recommended that you delete and reconvert all PNGs. ' .
'There are new buttons for doing just that on the ' .
'<a href="' . Paths::getSettingsUrl() . '">settings screen</a> (look below the conversion methods).'
);
} else {
Messenger::addMessage(
'info',
'Service notice from WebP Express:<br>' .
'You have configured <i>Gd</i> to skip converting PNGs. ' .
'However, the <i>Gd</i> conversion method has been fixed and is doing ok now!'
);
}
}
}
}
if (WEBPEXPRESS_MIGRATION_VERSION == '8') {
Messenger::addMessage(
'info',
'New in WebP Express 0.13.0:' .
'<ul style="list-style-type:disc; list-style-position: inside">' .
'<li>Bulk Conversion</li>' .
'<li>New option to automatically convert images upon upload</li>' .
'<li>Better support for Windows servers</li>' .
'<li>- <a href="https://github.com/rosell-dk/webp-express/milestone/16?closed=1" target="_blank">and more</a></li>' .
'</ul>'
);
}
Option::updateOption('webp-express-migration-version', '8');
// Find out if Gd is the first active and working converter.
// We check wod options, because it has already filtered out the disabled converters.
/*
$options = Config::loadWodOptions();
if ($options !== false) {
$converters = $options['converters'];
if (is_array($converters) && count($converters) > 0) {
if ($converters[0]['converter'] == 'gd') {
if (isset($converters[0]['options']) && ($converters[0]['options']['skip-pngs'] === true)) {
//
}
}
}
}
if ($config['operation-mode'] != 'no-conversion') {
Config::getConverterByName('gd')
}*/
}
webpexpress_migrate8();

204
lib/migrate/migrate9.php Normal file
View File

@@ -0,0 +1,204 @@
<?php
namespace WebPExpress;
use \WebPExpress\Config;
use \WebPExpress\ConvertersHelper;
use \WebPExpress\DismissableMessages;
use \WebPExpress\Messenger;
use \WebPExpress\Option;
use \WebPExpress\Paths;
/**
* Move a converter to the top
* @return boolean
*/
function webpexpress_migrate9_moveConverterToTop(&$config, $converterId) {
if (!isset($config['converters'])) {
return false;
}
if (!is_array($config['converters'])) {
return false;
}
// find index of vips
$indexOfVips = -1;
$vips = null;
foreach ($config['converters'] as $i => $c) {
if ($c['converter'] == $converterId) {
$indexOfVips = $i;
$vips = $c;
break;
}
}
if ($indexOfVips > 0) {
// remove vips found
array_splice($config['converters'], $indexOfVips, 1);
// Insert vips at the top
array_unshift($config['converters'], $vips);
}
return false;
}
function webpexpress_migrate9() {
$config = Config::loadConfigAndFix(false); // false, because we do not need to test if quality detection is working
$converters = &$config['converters'];
if (is_array($converters)) {
foreach ($converters as $i => $converter) {
if (!isset($converter['converter'])) {
continue;
}
if ($converter['converter'] == 'gmagickbinary') {
$converters[$i]['converter'] = 'graphicsmagick';
}
if ($converter['converter'] == 'imagickbinary') {
$converters[$i]['converter'] = 'imagemagick';
}
}
// Change specific converter options
foreach ($converters as &$converter) {
if (!isset($converter['converter'])) {
continue;
}
if (!isset($converter['options'])) {
// #273
$converter['options'] = [];
continue;
}
$options = &$converter['options'];
switch ($converter['converter']) {
case 'gd':
if (isset($options['skip-pngs'])) {
$options['png'] = [
'skip' => $options['skip-pngs']
];
unset($options['skip-pngs']);
}
break;
case 'wpc':
if (isset($options['url'])) {
$options['api-url'] = $options['url'];
unset($options['url']);
}
break;
case 'ewww':
if (isset($options['key'])) {
$options['api-key'] = $options['key'];
unset($options['key']);
}
if (isset($options['key-2'])) {
$options['api-key-2'] = $options['key-2'];
unset($options['key-2']);
}
break;
}
}
$firstActiveAndWorkingConverterId = ConvertersHelper::getFirstWorkingAndActiveConverterId($config);
// If it aint cwebp, move vips to the top!
if ($firstActiveAndWorkingConverterId != 'cwebp') {
$vips = webpexpress_migrate9_moveConverterToTop($config, 'vips');
}
/*
if ($config['image-types'] == 1) {
Messenger::addStickyMessage(
'info',
'WebP Express 0.14 handles PNG to WebP conversions quite well. Perhaps it is time to enable PNGs? ' .
'Go to the <a href="' . Paths::getSettingsUrl() . '">options</a> page to change the "Image types to work on" option.',
2,
'Got it!'
);
}*/
if ($config['image-types'] == 1) {
DismissableMessages::addDismissableMessage('0.14.0/suggest-enable-pngs');
}
DismissableMessages::addDismissableMessage('0.14.0/suggest-wipe-because-lossless');
DismissableMessages::addDismissableMessage('0.14.0/say-hello-to-vips');
/*
$convertersSupportingEncodingAuto = ['cwebp', 'vips', 'imagick', 'imagemagick', 'gmagick', 'graphicsmagick'];
if (in_array($firstActiveAndWorkingConverterId, $convertersSupportingEncodingAuto)) {
Messenger::addStickyMessage(
'info',
'WebP Express 0.14 has new options for the conversions. Especially, it can now produce lossless webps, and ' .
'it can automatically try both lossy and lossless and select the smallest. You can play around with the ' .
'new options when your click "test" next to a converter. Once satisfied, dont forget to ' .
'wipe your existing converted files (there is a "Delete converted files" button for that on the ' .
'<a href="' . Paths::getSettingsUrl() . '">options page</a>)',
1,
'Got it!'
);
} else {
//error_log('working converters: ' . print_r(ConvertersHelper::getWorkingConverterIds($config), true));
$workingIds = ConvertersHelper::getWorkingConverterIds($config);
if ($firstActiveAndWorkingConverterId == 'gd') {
foreach ($workingIds as $workingId) {
if (in_array($workingId, $convertersSupportingEncodingAuto)) {
Messenger::addStickyMessage(
'info',
'WebP Express 0.14 has new options for the conversions. Especially, it can now produce lossless webps, and ' .
'it can automatically try both lossy and lossless and select the smallest. You can play around with the ' .
'new options when your click "test" next to a converter. Once satisfied, dont forget to ' .
'wipe your existing converted files (there is a "Delete converted files" button for that on the ' .
'<a href="' . Paths::getSettingsUrl() . '">options page</a>). ' .
'<br><br>Btw: The "gd" conversion method that you are using does not support lossless encoding ' .
'(in fact Gd only supports very few conversion options), but fortunately, you have the ' .
'"' . $workingId . '" conversion method working, so you can simply start using that instead.',
1,
'Got it!'
);
break;
}
}
}
//
}
*/
}
// #235
$config['cache-control-custom'] = preg_replace('#max-age:#', 'max-age=', $config['cache-control-custom']);
// #272
if ($config['fail'] == 'report-as-image') {
$config['fail'] = 'report';
}
// Force htaccess ?
$forceHtaccessRegeneration = $config['redirect-to-existing-in-htaccess'];
// Save both configs and perhaps also htaccess
$result = Config::saveConfigurationAndHTAccess($config, $forceHtaccessRegeneration);
if ($result['saved-both-config']) {
Messenger::addMessage(
'info',
'Successfully migrated <i>WebP Express</i> options for 0.14. '
);
Option::updateOption('webp-express-migration-version', '9');
} else {
Messenger::addMessage(
'error',
'Failed migrating webp express options to 0.14+. Probably you need to grant write permissions in your wp-content folder.'
);
}
}
webpexpress_migrate9();