Skip to content

Instantly share code, notes, and snippets.

@vardumper
Last active February 11, 2023 22:12
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save vardumper/926bb5938efbbf9f596460f5c06db187 to your computer and use it in GitHub Desktop.
Save vardumper/926bb5938efbbf9f596460f5c06db187 to your computer and use it in GitHub Desktop.
Convert Wordpress User Uploads to WebP and update DB references
<?php
declare(strict_types = 1);
use WebPConvert\WebPConvert;
set_time_limit(0);
chdir(dirname(__DIR__)); // one level up to project root
// check requirements
if (! is_file('vendor/autoload.php')) {
echo "File vendor/autoload.php not found. Is the path correct?";
exit();
}
require ('vendor/autoload.php');
// Neither is CLI nor CLI-Server: Execution is forbidden (for HTTP). This is superuser stuff
if (! in_array(php_sapi_name(), [
'cli',
'cli-server'
])) {
http_response_code(403);
header('Content-Type: text/plain');
echo 'Forbidden.';
exit();
}
if (! extension_loaded('gd') && ! extension_loaded('imagick') && ! extension_loaded('gmagick')) {
echo "WebP is not supported. You need one at least GD or one of ImageMagick, Gmagick, cwebp, etc";
exit();
}
if (! class_exists('WebPConvert\WebPConvert')) {
echo "WebPConvert class not found. Run `composer require rosell-dk/webp-convert` to add it to your composer.json\n";
exit();
}
// recursive file search by pattern in a given folder
function rsearch(string $folder, string $pattern): array
{
$dir = new RecursiveDirectoryIterator($folder);
$ite = new RecursiveIteratorIterator($dir);
$files = new RegexIterator($ite, $pattern, RegexIterator::GET_MATCH);
$fileList = array();
foreach ($files as $file) {
$fileList = array_merge($fileList, $file);
}
return $fileList;
}
// find (or guess) wordpress path
function get_wordpress_path(): string
{
if (! is_file('vendor/composer/installed.json')) {
throw new \Exception('Is your project based on composer?');
}
// find
$installed = json_decode(file_get_contents('vendor/composer/installed.json'), true);
if (isset($installed['versions']['johnpbloch/wordpress-core']['install-path'])) {
return realpath($installed['versions']['johnpbloch/wordpress-core']['install-path']);
}
// or guess
if (is_dir('wp-admin')) {
return getcwd();
}
if (is_dir('wordpress/wp-admin')) {
return getcwd() . '/wordpress';
}
return '.';
}
// WebP configuration
$webp_options = [
'metadata' => 'none',
'encoding' => 'lossless',
'show-report' => true,
'preset' => 'photo',
'alpha-quality' => 100,
'default-quality' => 100,
'max-quality' => 100,
'quality' => 100
];
$wordpress_path = get_wordpress_path();
// load wordpress, especially for $wpdb and functions
define('WP_USE_THEMES', false);
require_once $wordpress_path . '/wp-load.php';
require_once $wordpress_path . '/wp-admin/includes/ajax-actions.php';
$paths = [
$wordpress_path . '/wp-content/uploads',
$wordpress_path . '/another/directory'
];
echo "Scanning folders for images...\n";
$matches = [];
foreach ($paths as $path) {
if (! is_dir($path)) {
printf("Path %s not found.\n", $path);
continue;
}
$files = rsearch($path, '/^.*\.(jpe?g|png|bmp|tiff)$/i');
$matches = array_merge($matches, $files);
}
$matches = array_filter($matches, "is_file");
printf("Found %s images.\n", count($matches));
$existed = 0;
$converted = 0;
foreach ($matches as $file) {
$pathinfo = pathinfo($file);
if ( is_file($pathinfo['dirname'] . '/' . $pathinfo['filename'] . '.webp')) {
$existed ++;
continue;
}
if (! is_writeable($pathinfo['dirname'])) {
echo $pathinfo['dirname'] . " not writeable.\n";
continue;
}
// create WebP version of image
WebPConvert::convert($file, $pathinfo['dirname'] . '/' . $pathinfo['filename'] . '.webp', $webp_options);
$results = $wpdb->get_results(sprintf("SELECT ID, post_content, post_excerpt FROM {$wpdb->posts} WHERE (`post_content` LIKE '%s' OR `post_excerpt` LIKE '%s') AND `post_type` IN ('post','page','product','product_variation');", "%" . $wpdb->esc_like($pathinfo['basename']) . "%", "%" . $wpdb->esc_like($pathinfo['basename']) . "%"), ARRAY_A);
if (count($results)) {
$sql = sprintf("UPDATE {$wpdb->posts} SET post_content = REPLACE(post_content, '%s', '%s'), post_excerpt = REPLACE(post_excerpt, '%s', '%s') WHERE (`post_content` LIKE '%s' OR `post_excerpt` LIKE '%s') AND `post_type` IN ('post','page','product','product_variation');", $pathinfo['basename'], $pathinfo['filename'] . '.webp', $pathinfo['basename'], $pathinfo['filename'] . '.webp', "%" . $wpdb->esc_like($pathinfo['basename']) . "%", "%" . $wpdb->esc_like($pathinfo['basename']) . "%");
$wpdb->query($sql);
printf("Updated image references in %s posts.\n", count($results));
}
$results = $wpdb->get_results(sprintf("SELECT `ID`, `guid`, `post_mime_type` FROM {$wpdb->posts} WHERE `guid` LIKE '%s' AND `post_type` = 'attachment';", "%" . $wpdb->esc_like($pathinfo['basename']) . "%"), ARRAY_A);
if (count($results)) {
$sql = sprintf("UPDATE {$wpdb->posts} SET `guid` = REPLACE(`guid`, '%s', '%s'), `post_mime_type` = 'image/webp' WHERE `guid` LIKE '%s' AND `post_type` = 'attachment';", $pathinfo['basename'], $pathinfo['filename'] . '.webp', '%' . $wpdb->esc_like($pathinfo['basename']) . '%');
$wpdb->query($sql);
printf("Updated guid, post_mime_type in %s attachments.\n", count($results));
}
$wpdb->query(sprintf("UPDATE {$wpdb->postmeta} SET `meta_value` = REPLACE(`meta_value`, '%s', '%s') WHERE `meta_value` LIKE '%s' AND `meta_key` = '_wp_attached_file';", $pathinfo['basename'], $pathinfo['filename'] . '.webp', "%" . $wpdb->esc_like($pathinfo['basename']) . "%"));
$_wp_attachment_metadata = $wpdb->get_row(sprintf("SELECT `post_id`, `meta_value` FROM {$wpdb->postmeta} WHERE `meta_value` LIKE '%s' AND `meta_key` = '_wp_attachment_metadata';", '%' . $wpdb->esc_like($pathinfo['basename']) . '%'), ARRAY_A);
if (! is_null($_wp_attachment_metadata)) {
$old = unserialize($_wp_attachment_metadata['meta_value']);
$new = $old;
$new['file'] = is_string($new['file']) ? str_replace($pathinfo['basename'], $pathinfo['filename'] . '.webp', $new['file']) : $new['file'];
foreach ($new['sizes'] as $sizename => $size) {
$new['sizes'][$sizename]['file'] = is_string($size['file']) ? str_replace($pathinfo['basename'], $pathinfo['filename'] . '.webp', $size['file']) : $size['file'];
if ($old['sizes'][$sizename]['file'] !== $new['sizes'][$sizename]['file']) {
$new['sizes'][$sizename]['mime-type'] = 'image/webp';
}
}
$wpdb->query(sprintf("UPDATE {$wpdb->postmeta} SET `meta_value` = '%s' WHERE `post_id` = %s AND `meta_key` = '_wp_attachment_metadata';", $wpdb->escape(serialize($new)), $_wp_attachment_metadata['post_id']));
}
$converted ++;
}
printf("Converted %s images and skipped %s that already existed.\n", $converted, $existed);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment