WordPress как на ладони
Недорогой хостинг для сайтов на WordPress: wordpress.jino.ru Авторские Темы для WordPress

Как в WordPress загрузить SVG

По умолчанию в WordPress нельзя загружать SVG в целях безопасности. Но что делать, когда очень надо? Решение есть!

При попытке загрузить SVG появляется сообщение "Извините, этот тип файла недопустим по соображениям безопасности."

О том, будет ли разрешена загрузка SVG в WordPress по умолчанию и почему разработчики этого избегают, читайте в тикете #24251 Reconsider SVG inclusion to get_allowed_mime_types.

Для решения этой задачи через плагин, устанавливайте Safe SVG.

Шаг 1 - Включение SVG в список разрешенных для загрузки файлов

Для этого воспользуемся хуком upload_mimes, позволяющим изменять список доступных для загрузки файлов по MIME-типу.

add_filter( 'upload_mimes', 'svg_upload_allow' );

# Добавляет SVG в список разрешенных для загрузки файлов.
function svg_upload_allow( $mimes ) {
	$mimes['svg']  = 'image/svg+xml';

	return $mimes;
}

Иногда этого кода достаточно, но не для всех svg файлов. Разберемся почему так.

Реальный MIME тип svg файла, который в WP определятся php функцией finfo_file() (см. код wp_check_filetype_and_ext() ) может быть двух вариантов:

  • image/svg+xml — когда в коде svg есть xml заголовок.
  • image/svg — когда в коде svg есть только тег <svg>, без каких либо заголовков.

Сюда нужно добавить оба эти варианта, но добавить можно только один, поэтому только этого кода недостаточно и нужен второй шаг.

Шаг 2 - Подмена mime типа SVG

Как описано выше предыдущего кода для решения проблемы недостаточно. Точнее, в результате проверки и несовпадения указанного MIME типа и реального (полученного самим WP) MIME тип будет просто обнулен. Вернуть его обратно нам поможет хук wp_check_filetype_and_ext.

add_filter( 'wp_check_filetype_and_ext', 'fix_svg_mime_type', 10, 5 );

# Исправление MIME типа для SVG файлов.
function fix_svg_mime_type( $data, $file, $filename, $mimes, $real_mime = '' ){

	// WP 5.1 +
	if( version_compare( $GLOBALS['wp_version'], '5.1.0', '>=' ) )
		$dosvg = in_array( $real_mime, [ 'image/svg', 'image/svg+xml' ] );
	else
		$dosvg = ( '.svg' === strtolower( substr($filename, -4) ) );

	// mime тип был обнулен, поправим его
	// а также проверим право пользователя
	if( $dosvg ){

		// разрешим
		if( current_user_can('manage_options') ){

			$data['ext']  = 'svg';
			$data['type'] = 'image/svg+xml';
		}
		// запретим
		else {
			$data['ext'] = $type_and_ext['type'] = false;
		}

	}

	return $data;
}

Если из кода выше убрать проверку на право администратора, то код станет небезопасным и потенциально открывает дыру в защите сайта.

В коде выше добавлена проверка на версию WP. С WP 5.1.0 благодаря тикету автора этого сайта в хуке появился параметр $real_mime. Он позволяет сделать более надежную проверку файла — на уровне определения MIME типа файла по его коду, а не расширению.

Также рекомендую ограничить размер загружаемого svg файла, например не более 50кб. SVG файлы как правило маленькие и большой размер может говорить о том, что в файле какой-либо нехороший код.

Кода выше достаточно, чтобы WоrdPress разрешил загружать SVG в медиабиблиотеку. Следующий шаг чисто визуальный.

Отображение SVG в медиабиблиотеке

После проделанных шагов SVG файлы будут отображаться как документы, а не изображения:

За разметку этих блоков с изображениями отвечает код, генерируемый функцией wp_print_media_templates() из файла wp-includes/media-template.php:

<div class="thumbnail">
	<# if ( data.uploading ) { #>
		<div class="media-progress-bar"><div style="width: {{ data.percent }}%"></div></div>
	<# } else if ( 'image' === data.type && data.sizes ) { #>
		<div class="centered">
			<img src="{{ data.size.url }}" draggable="false" alt="" />
		</div>
	<# } else { #>
		<div class="centered">
			<# if ( data.image && data.image.src && data.image.src !== data.icon ) { #>
				<img src="{{ data.image.src }}" class="thumbnail" draggable="false" alt="" />
			<# } else if ( data.sizes && data.sizes.medium ) { #>
				<img src="{{ data.sizes.medium.url }}" class="thumbnail" draggable="false" alt="" />
			<# } else { #>
				<img src="{{ data.icon }}" class="icon" draggable="false" alt="" />
			<# } #>
		</div>
		<div class="filename">
			<div>{{ data.filename }}</div>
		</div>
	<# } #>
</div>

Смысл кода в том, что он отобразит изображение, если

  • у него есть свойство src (ссылка на изображение) и оно не равно ссылке на иконку документа (любой файл по сути документ);
  • или если у изображения есть размер medium (svg файл вообще не кропается).

Файл SVG не имеет ни первого ни второго, поэтому нам нужно сымитировать самостоятельно один из этих вариантов и в этом нам поможет фильтр wp_prepare_attachment_for_js, используйте любой из вариантов по вкусу.

Вариант 1 - С выводом названия файла

add_filter( 'wp_prepare_attachment_for_js', 'show_svg_in_media_library' );

# Формирует данные для отображения SVG как изображения в медиабиблиотеке.
function show_svg_in_media_library( $response ) {

	if ( $response['mime'] === 'image/svg+xml' ) {

		// С выводом названия файла
		$response['image'] = [
			'src' => $response['url'],
		];
	}

	return $response;
}

Вариант 2 - Без вывода названия файла

add_filter( 'wp_prepare_attachment_for_js', 'show_svg_in_media_library' );

# Формирует данные для отображения SVG как изображения в медиабиблиотеке.
function show_svg_in_media_library( $response ) {

	if ( $response['mime'] === 'image/svg+xml' ) {

		// Без вывода названия файла
		$response['sizes'] = [
			'medium' => [
				'url' => $response['url'],
			],
			// при редактирования картинки
			'full' => [
				'url' => $response['url'],
			],
		];
	}

	return $response;
}
campusboy 3835youtube.com/c/wpplus
Создатель YouTube канала wp-plus, на котором делюсь своим опытом. Активный пользователь wp-kama.ru. WordPress-разработчик. Разработка сайтов и лендингов. Доработка существующих проектов. Сопровождение ресурсов.
Редакторы: Kama 8243
11 комментов
    Войти