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

Как в 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'],
			],
		];
	}

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

    Смотрите с любых устройств видео на hot24hd.com

    hot24hd.com

7 комментов
  • Алексей

    Прекрасная статья, всё написано очень подробно! Кстати svg не всегда были запрещены для загрузки галка в элементоре решала проблеу, но я заметил что сейчас это не так.

    В закладки)

    Ответить3 мес назад #
  • Функцию желательно вешать на фильтр "mime_types" - так написано в ядре smile

    прочесть можно в теле функции function wp_get_mime_types(), а фильтр "upload_mimes" использовать при удалении типов медиа.

    Ответить3 мес назад #
    • Kama7770

      Можно и где-то это даже наверное правильнее с точки зрения педантичности, но зачем? Задача у нас связана с загрузкой поэтому хук upload_mimes как раз нужный нам. Если просто заменить хук upload_mimes на mime_types, то код работать не будет потому что ранее в ядре на хук upload_mimes вешается функция check_upload_mimes(), которая как раз и срезает все лишнее из списка MIME типов оставляя только картинки.

      Т.е. если делать через хук mime_types, как ты предлагаешь, то надо будет:

      1. Добавить миме тип хуком через mime_types.
      2. Один фиг заюзать хук upload_mimes, где еще раз сделать тоже самое что в пункте 2.
      3. Добавить хук на поправку миме типа.

      Получается придется писать еще один лишний хук. А для чего?

      Ответить3 мес назад #
      • Тимур, все верно, но факт остается фактом ... thank_you

        -1
        Ответить3 мес назад #
        • Kama7770

          Факт: удобнее делать как написано в статье.

          Факт: нет ни одной причины делать через хук mime_types.

          Функцию желательно вешать на фильтр "mime_types" - так написано в ядре

          Факт: такого в ядре нет - там написано не надо удалять миме типы на хуке mime_types. Цитата с хука mime_types: "This filter should be used to add, not remove, mime types. To remove mime types, use the {@see 'upload_mimes'} filter." Где тут написано что не нужно добавлять миме типы на хуке upload_mimes? Суть этой заметки в том, что это фундаментальный массив миме типов, который используется повсеместно в ядре и если из него удалить миме тип решая свою какую-то отдельную задачу - это может повлиять на другие участки кода, поэтому удалять с него нельзя ничего.

          О каком факте ты говоришь?

          Ответить3 мес назад #
          • Я по моему не сказал что ваш код негоден или неудобен. Я просто написал "желательно", . А причина простая. Если кто то будет писать код и использовать функцию $mt = wp_get_mime_types(); что бы получить разрешенные медиа , то вашего там не обнаружит. Только и всего. И читателям это нужно учесть

            Ответить3 мес назад #
            • Kama7770

              Ты так ни слова и не сказал почему "желательно", а на мои аргументы о том что нет никакого "желательно" про какой-то несуществующий факт начал говорить. Так какой факт фактом остается?

              А причина простая. Если кто то будет писать код и использовать функцию $mt = wp_get_mime_types(); что бы получить разрешенные медиа...

              wp_get_mime_types() не предоставляет разрешенные медиа, в ней список разных/всех миметипов используемых в WP, а список разрешенных медиа получается функцией get_allowed_mime_types() в которой все будет получено как нужно!

              1
              Ответить3 мес назад #