Массовое изменение изображений в WordPress

Вчера (25.01.2018) на своем блоге о фильмах film4life.ru решил поменять все изображения с png формата на jpg, причина тому долгая загрузка страниц, и как следствие понижение ранжирования со стороны поисковых систем, а также плохие поведенческие факторы со стороны пользователей. Потратил примерно 4 часа, но можно было обойтись несколькими минутами, сейчас расскажу))

Для начала я провел тесты, оказалось что аналогичные jpg файлы весят от 1,5 до 5 раз меньше нежели png файлы, причем без потери качества. Прозрачность в картинках мне не нужна поэтому решил все перевести на jpg.

Но на сайте оказалось около 1000 картинок, не считая превью. Поэтому ручной вариант не подходит. А для автоматического варианта необходимо:

  • изменить базу данных
  • конвертировать все изображения на сервере

Обновление базы данных

Это был самый долгий момент, из-за незнания структуры базы данных WordPress.

Оказалось все дело в 5 SQL запросах, однако умеючи можно и меньше.

Для того чтобы сделать SQL запрос, необходимо войти в веб интерфейс phpMyAdmin соответствующей базы данных, затем перейти во вкладку SQL:

Веб интерфейс SQL запроса в phpMyAdmin
Веб интерфейс SQL запроса в phpMyAdmin

Таблица wp_posts

Замена значений post_mime_type и расширения в guid (видимо ссылка на изображение) у всех постов с post_type равным attachment и post_mime_type равным image/png:

UPDATE `wp_posts` SET `post_mime_type`='image/jpg', `guid`=REPLACE(`guid`, '.png', '.jpg') WHERE `post_type`='attachment' and `post_mime_type`='image/png'

Затем, замена во всех постах расширения в ссылках на изображения:

UPDATE `wp_posts` SET `post_content`=REPLACE(`post_content`, '.png', '.jpg') WHERE `post_type`='post'

Таблица wp_postmeta

Замена расширения файлов в meta_value у тех строк таблицы то имеют meta_key равным _wp_attached_file:

UPDATE `wp_postmeta` SET `meta_value`=REPLACE(`meta_value`, '.png', '.jpg') WHERE `meta_key`='_wp_attached_file'

Замена расширения файлов в meta_value у тех строк таблицы то имеют meta_key равным _wp_attachment_metadata:

UPDATE `wp_postmeta` SET `meta_value`=REPLACE(`meta_value`, '.png', '.jpg') WHERE `meta_key`='_wp_attachment_metadata'

Оба запроса выше можно объединить в один, но я делал раздельно.

Замена значения meta_value у тех строк таблицы то имеют meta_key равным _wp_attachment_metadata:

UPDATE `wp_postmeta` SET `meta_value`=REPLACE(`meta_value`, 'image/png', 'image/jpg') WHERE `meta_key`='_wp_attachment_metadata'

Конвертирование файлов на сервере

Затем необходимо конвертировать все изображения на сервере и изменить расширения. для этого я использовал php скрипт extensionedit.php который разместил в директории wp-content:

<?php

set_time_limit(0);

//! пути относительно скрипта, откуда берем картинки
$g_aSrcPath = array(
	"uploads/2017",
	"uploads/2018"
	);

//! 
$g_sExtCurr = "png";
$g_sExtNew = "jpg";

//**************************************************************************

//! сканируем директорию, на выходе получаем все пути до файлов (в том числе и вложенных)
function ScanPath($dir)
{
	$d = array();
	$arr = opendir($dir);
 
	while($v = readdir($arr))
	{
		if($v == '.' or $v == '..') continue;
		if(!is_dir($dir.DIRECTORY_SEPARATOR.$v)) 
			$d[] = $v;
		if(is_dir($dir.DIRECTORY_SEPARATOR.$v)) 
		{
			$aArr = ScanPath($dir.DIRECTORY_SEPARATOR.$v);
					
			for($i=0, $il=count($aArr); $i<$il; ++$i)
			{
				$d[] = $v.DIRECTORY_SEPARATOR.$aArr[$i];
			}
		}
	}
 
	return $d;
}

//! загрузка изображения, возвращает resource
function LoadImg($sPath)
{
	return imagecreatefromstring(file_get_contents($sPath));
}

function GetExtension($sFile) 
{
	return substr(strrchr($sFile, '.'), 1);
}

//**************************************************************************

//
if(!empty($g_sExtCurr) && !empty($g_sExtNew))
{
	$iCountEdit = 0;
	
	//проходимся по всем указанным путям, ищем изображения
	for($i=0, $il=count($g_aSrcPath); $i<$il; ++$i)
	{
		//получаем список файлов (с путями)
		$aFiles = ScanPath($g_aSrcPath[$i]);
		
		//проходимся по списку файлов
		for($k=0, $kl=count($aFiles); $k<$kl; ++$k)
		{
			if(mb_stripos($aFiles[$k], "favicon") !== false)
				continue;
			
			
			$sSrcParh = $g_aSrcPath[$i].DIRECTORY_SEPARATOR.$aFiles[$k];
			
			//echo $sSrcParh . "|" . GetExtension($sSrcParh) . "
";
			
			if(GetExtension($sSrcParh) == $g_sExtCurr)
			{
				$sFileName = basename($sSrcParh, "." . $g_sExtCurr);
				$sNewParh = dirname($sSrcParh);
				$sNewParh = $sNewParh.DIRECTORY_SEPARATOR.$sFileName.".".$g_sExtNew;
				
				$hSrcImg = LoadImg($sSrcParh);
				rename($sSrcParh,$sNewParh);
				imagejpeg($hSrcImg, $sNewParh, 100);
				++$iCountEdit;
			}
		}
	}

	echo "Edit extension " . $iCountEdit . " files";
}
else
{
	http_response_code(404);
	die;
}
?>

Не элегантное решение, но рабочее. Запрос конкретно для моего блога: film4life.ru/wp-content/extensionedit.php конвертирует все файлы с расширением png в jpg без сжатия jpg, который находятся в относительных директориях указанных в $g_aSrcPath массиве.

Ссылки на картинки на сторонних сайтах

В моей ситуации внешних ссылок было мало, но будет плохо если они станут битыми, поэтому пришлось сделать чтобы они стали доступный, но с редиректом.

В директории wp-content необходимо создать 2 файла.

.htaccess:

AddDefaultCharset utf-8

<IfModule mod_rewrite.c>
RewriteEngine On
Options +FollowSymlinks
RewriteBase /
 
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /wp-content/uploads/oldimages.php?q=$1 [L,QSA]
</IfModule>

oldimages.php:

<?php

function LoadPage($sUrl)
{	
	$sHeaders = array(
		"User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0",
	); 
	
	$hCurl = curl_init();
    curl_setopt($hCurl, CURLOPT_URL, $sUrl);
	
	curl_setopt($hCurl, CURLOPT_SSL_VERIFYHOST, 0);
	curl_setopt($hCurl, CURLOPT_SSL_VERIFYPEER, 0);
	
    curl_setopt($hCurl, CURLOPT_RETURNTRANSFER, true);
	curl_setopt($hCurl, CURLOPT_TIMEOUT, 60);
	curl_setopt($hCurl, CURLOPT_HTTPHEADER, $sHeaders); 
	
    $result = curl_exec($hCurl);
	$info = curl_getinfo($hCurl);
	
	$tries = 0;
	while(curl_errno($hCurl) != 0 && $tries++ < 10)
	{
		$result = curl_exec($hCurl);
		$info = curl_getinfo($hCurl);
		sleep(1);
	}
 
	curl_close($hCurl);
	return($result); 
} 

//**************************************************************************

$sQuery = $_GET['q']; 
$sFileName = basename($sQuery, ".png"); 
$sNewPath = dirname($sQuery); 
$sNewPath = $sNewPath.DIRECTORY_SEPARATOR.$sFileName.".jpg"; 
if(!is_file($sNewPath)) 
{ 
	http_response_code(404); 
	echo LoadPage("https://film4life.ru/404"); 
	die; 
} 

header("Location: " . $sFileName.".jpg", true, 301); 
die; 
?>

Конечно не самое элегантное решение, но на что хватило ума. Вкратце:

  • в случае отсутсвия файла, направляем запрос на скрипт oldomages.php
  • если скрипт находит аналогичное изображение с png расширением то редиректит на него, иначе загружает 404 страницу WordPress и показывает ее пользователю, отправляя при этом код ошибки.

Update. Выяснилось что можно сделать все намного проще, для этого в файл .htaccess нужно добавить (перед всеми правилами):

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(wp\-content/uploads/.*)\.png$ /$1.jpg [L,QSA]

Мой итоговый .htaccess:

# BEGIN WordPress
&lt;IfModule mod_rewrite.c&gt;
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(wp\-content/uploads/.*)\.png$ /$1.jpg [L,QSA]
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
&lt;/IfModule&gt;

# END WordPress

Теперь все изображения доступны и по адресу в котором png расширение, однако с редиректом.

Может возникнуть вопрос, зачем загружать 404 страницу WordPress? Думаю что лучше уж пользователь увидит 404 страницу WordPress с хоть каким-то контентом сайта нежели просто пустую страницу)

Итог

Размер до конвертирования: 1,64 гб.

Размер после конвертирования: 926 мб.

Экономия места: 753 мб.

Коэффициент сжатия: 1,81.

Страницы стали загружаться быстрее, субъективно. В целом думаю это были вполне оправданные действия, результаты которых проявятся дальше.

Поделиться:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*

*

code