Микроразметка рецептов при помощи произвольных полей

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

Введение

Ну понятно, что мы говорим про кулинарный сайт, но здесь другие критерии. Сайт может быть:

  • вновь созданным;
  • действующим с кучей статей.

Отсюда и надо плясать, при внедрении микроразметки и применении одного из способов. А способов может быть несколько, опять же при соблюдении вышеуказанных условий:

1. Если сайт действующий:

  • вручную вводить нужные сущности при редактировании рецепта
  • использовать специальные функции (можно почитать здесь)
  • использовать плагин, который формирует что-то вроде карточки рецепта (например, плагин Easy Recipe)
  • использовать произвольные поля, правда при этом придется все статьи переделывать.

Оптимальный способ, если у вас действующий сайт: использовать специальные функции.

2. Если сайт новый и вы только начали его заполнять

  • можно использовать плагины с произвольными записями (например, плагин плагин Recipe Hero) — это когда создается отдельный вид записей и с помощью него заполняются все рецепты
  • можно использовать произвольные поля, для чего создается одна большая рубрика «Рецепты» и к записям в этой рубрике привязываются нужные произвольные поля

В итоге, у меня получалась вот такая схемка для внедрения микроразметки рецептов через произвольные поля

shemaorgrecipe

Понятно, что при использовании любого способа должно быть некоторое представление о структуре WordPress  и немножко о PHP

Вот с помощью произвольных полей и будет внедряться микроразметка рецептов. Более подробно в видео

к содержанию

Исходные данные

  • Подопытный сайт: MamaCooks.ru
  • Используемая тема: Selfie (обзор темы)

Добавляем произвольные поля

Для прикручивания произвольных полей используется плагин Custom Field Suite. Процедура не сложная, делаем все по видео:

Плагин позволяет импортировать нужные поля, так что можете просто скопировать нижеуказанный код в нужное поле плагина

[{"post_title":"\u0418\u043d\u0433\u0440\u0435\u0434\u0438\u0435\u043d\u0442\u044b","post_name":"ingridienty-i-opisanie","cfs_extras":{"order":"0","context":"normal","hide_editor":"0"},"cfs_fields":[{"id":"8","name":"artabr_recipe_ing_foto","label":"\u0424\u043e\u0442\u043e \u0438\u043d\u0433\u0440\u0435\u0434\u0438\u0435\u043d\u0442\u043e\u0432","type":"file","notes":"","parent_id":0,"weight":0,"options":{"return_value":"url","required":"0"}},{"id":"23","name":"artabr_recipe_ing_title","label":"\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0438\u043d\u0433\u0440\u0435\u0434\u0438\u0435\u043d\u0442\u043e\u0432","type":"text","notes":"\u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0440\u0430\u0437\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0438\u043d\u0433\u0440\u0435\u0434\u0438\u0435\u043d\u0442\u044b (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0434\u043b\u044f \u0440\u0435\u0446\u0435\u043f\u0442\u0430 \u043f\u0438\u0440\u043e\u0433\u0430), \u0442\u043e \u0443\u043a\u0430\u0436\u0438\u0442\u0435 \u0437\u0434\u0435\u0441\u044c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \"\u0414\u043b\u044f \u0442\u0435\u0441\u0442\u0430\"","parent_id":0,"weight":1,"options":{"default_value":"","required":"0"}},{"id":"5","name":"artabr_recipe_ing","label":"\u0418\u043d\u0433\u0440\u0435\u0434\u0438\u0435\u043d\u0442\u044b","type":"loop","notes":"","parent_id":0,"weight":2,"options":{"row_display":"0","row_label":"\u0418\u043d\u0433\u0440\u0435\u0434\u0438\u0435\u043d\u0442\u044b","button_label":"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0438\u043d\u0433\u0440\u0435\u0434\u0438\u0435\u043d\u0442","limit_min":"","limit_max":""}},{"id":"6","name":"artabr_recipe_ing_name","label":"\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0438\u043d\u0433\u0440\u0435\u0434\u0438\u0435\u043d\u0442\u0430","type":"text","notes":"","parent_id":5,"weight":3,"options":{"default_value":"","required":"0"}},{"id":"7","name":"artabr_recipe_ing_count","label":"\u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0438\u043d\u0433\u0440\u0435\u0434\u0438\u0435\u043d\u0442\u0430","type":"text","notes":"","parent_id":5,"weight":4,"options":{"default_value":"","required":"0"}},{"id":"24","name":"artabr_recipe_ing_title_dop","label":"\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445  \u0438\u043d\u0433\u0440\u0435\u0434\u0438\u0435\u043d\u0442\u043e\u0432","type":"text","notes":"\u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0440\u0430\u0437\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0438\u043d\u0433\u0440\u0435\u0434\u0438\u0435\u043d\u0442\u044b (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0434\u043b\u044f \u0440\u0435\u0446\u0435\u043f\u0442\u0430 \u043f\u0438\u0440\u043e\u0433\u0430), \u0442\u043e \u0443\u043a\u0430\u0436\u0438\u0442\u0435 \u0437\u0434\u0435\u0441\u044c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \"\u0414\u043b\u044f \u0442\u0435\u0441\u0442\u0430\"","parent_id":0,"weight":5,"options":{"default_value":"","required":"0"}},{"id":"20","name":"artabr_recipe_ing_dop","label":"\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0438\u043d\u0433\u0440\u0435\u0434\u0438\u0435\u043d\u0442\u044b","type":"loop","notes":"","parent_id":0,"weight":6,"options":{"row_display":"0","row_label":"\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0438\u043d\u0433\u0440\u0435\u0434\u0438\u0435\u043d\u0442\u044b","button_label":"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0438\u043d\u0433\u0440\u0435\u0434\u0438\u0435\u043d\u0442","limit_min":"","limit_max":""}},{"id":"21","name":"artabr_recipe_ing_name_dop","label":"\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0438\u043d\u0433\u0440\u0435\u0434\u0438\u0435\u043d\u0442\u0430","type":"text","notes":"","parent_id":20,"weight":7,"options":{"default_value":"","required":"0"}},{"id":"22","name":"artabr_recipe_ing_count_dop","label":"\u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0438\u043d\u0433\u0440\u0435\u0434\u0438\u0435\u043d\u0442\u0430","type":"text","notes":"","parent_id":20,"weight":8,"options":{"default_value":"","required":"0"}}],"cfs_rules":{"post_types":{"operator":"==","values":["post"]},"term_ids":{"operator":"==","values":["1"]}}},{"post_title":"\u041c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0440\u0435\u0446\u0435\u043f\u0442\u0430","post_name":"metadannye-recepta","cfs_extras":{"order":"0","context":"side","hide_editor":"0"},"cfs_fields":[{"id":"10","name":"artabr_recipe_resultPhoto","label":"\u0424\u043e\u0442\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430","type":"file","notes":"","parent_id":0,"weight":0,"options":{"return_value":"url","required":"0"}},{"id":"11","name":"artabr_recipe_recipeYield","label":"\u041a\u043e\u043b-\u0432\u043e \u043f\u043e\u0440\u0446\u0438\u0439","type":"text","notes":"","parent_id":0,"weight":1,"options":{"default_value":"","required":"0"}},{"id":"12","name":"artabr_recipe_prepTime","label":"\u0412\u0440\u0435\u043c\u044f \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438","type":"text","notes":"","parent_id":0,"weight":2,"options":{"default_value":"","required":"0"}},{"id":"13","name":"artabr_recipe_cookTime","label":"\u0412\u0440\u0435\u043c\u044f \u043f\u0440\u0438\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u0438\u044f","type":"text","notes":"","parent_id":0,"weight":3,"options":{"default_value":"","required":"0"}},{"id":"14","name":"artabr_recipe_cookingMethod","label":"\u041c\u0435\u0442\u043e\u0434 \u043f\u0440\u0438\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u0438\u044f","type":"text","notes":"","parent_id":0,"weight":4,"options":{"default_value":"","required":"0"}},{"id":"15","name":"artabr_recipe_recipeCuisine","label":"\u041a\u0443\u0445\u043d\u044f \u0440\u0435\u0446\u0435\u043f\u0442\u0430","type":"text","notes":"","parent_id":0,"weight":5,"options":{"default_value":"","required":"0"}}],"cfs_rules":{"post_types":{"operator":"==","values":["post"]},"term_ids":{"operator":"==","values":["1"]}}},{"post_title":"\u0418\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f \u043f\u043e \u043f\u0440\u0438\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u0438\u044e","post_name":"instrukciya-po-prigotovleniyu","cfs_extras":{"order":"0","context":"normal","hide_editor":"0"},"cfs_fields":[{"id":"18","name":"artabr_stepbystep","label":"\u0418\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f","type":"loop","notes":"","parent_id":0,"weight":0,"options":{"row_display":"0","row_label":"\u041f\u043e\u0448\u0430\u0433\u043e\u0432\u0430\u044f \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f","button_label":"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0448\u0430\u0433","limit_min":"","limit_max":""}},{"id":"16","name":"artabr_photo_step","label":"\u0424\u043e\u0442\u043e \u0448\u0430\u0433\u0430","type":"file","notes":"","parent_id":18,"weight":1,"options":{"return_value":"url","required":"0"}},{"id":"17","name":"artabr_text_step","label":"\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0448\u0430\u0433\u0430","type":"wysiwyg","notes":"","parent_id":18,"weight":2,"options":{"formatting":"default","required":"0"}},{"id":"19","name":"artabr_\u0441alories_nutrition","label":"\u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043a\u0430\u043b\u043e\u0440\u0438\u0439","type":"text","notes":"","parent_id":0,"weight":3,"options":{"default_value":"","required":"0"}}],"cfs_rules":{"post_types":{"operator":"==","values":["post"]},"term_ids":{"operator":"==","values":["1"]}}}]
Не забудьте указать нужную рубрику!
к содержанию

Внесение данных в поля

Поля созданы, теперь для наглядности надо их заполнить

Вывод полей на странице записи

Весь код выводиться в файле single.php

Всего получилось три вида произвольных полей:

  • текст;
  • загрузка файлов;
  • цикл.

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

к содержанию

Выводим текстовые поля

Объявляем переменную и присваиваем ей значение нужного текстового поля (можно не задавать переменные, просто с ними удобнее)

<?php $recipe_method  = CFS()->get('artabr_recipe_cookingMethod'); ?>

Теперь выводим ее в нужном месте, файла single.php

<?php if ( $recipe_method ) { ?> // вывод поля "Метод приготовления"
	<span class="recipe-method">
		<?php echo 'Метод: '; ?>
		<span class="recipe"><strong itemprop="cookingMethod"><?php echo $recipe_method; ?></strong></span>
	</span>
<?php } ?>
Все поля желательно выводить через условие проверки наличия в этих полях значений. Чтобы не выводился лишний контент, если вдруг поля пустые.

По аналогии выводим другие текстовые поля.

к содержанию

Выводим загруженные картинки

Здесь все просто. При загрузке картинки нам возвращают на нее ссылку, остается только вывести ее в теге img. Для вывода нашей картинки с ингредиентами, вывод полей будет выглядеть так:

<div class="recipe-ingr-img col-xs-6">
       <img itemprop="image" src="<?php echo CFS()->get('artabr_recipe_ing_foto'); ?>">
</div>

Выводим циклы

В нашем случае при помощи циклов выводятся ингредиенты и инструкция по приготовлению. Вообще, любое поле типа «цикл (loop)» можно вывести с помощью перебора. В нашем случае, вывод ингредиентов будет происходить так:

 <?php $recipe_ing = CFS()->get('artabr_recipe_ing');
	foreach ($recipe_ing as $one_ingr) {
		echo $one_ingr['artabr_recipe_ing_count']. ' '. $one_ingr['artabr_recipe_ing_name'];
	} ?>

Чтобы все было красиво, добавляем нужные html-теги. Я обычно использую маркированный список:

 <?php $recipe_ing = CFS()->get('artabr_recipe_ing');
	echo '<ul>';
	foreach ($recipe_ing as $one_ingr) {
		echo '<li><p>'. $one_ingr['artabr_recipe_ing_count']. ' '. $one_ingr['artabr_recipe_ing_name'] .'</p></li>';
	}
	echo '</ul>'; ?>

Цикл инструкции по приготовлению создается аналогично, только еще добавляем вывод картинки шага:

<?php $recipe_step = CFS()->get('artabr_stepbystep');
	$i=0;
	echo '<ul>';
	foreach ($recipe_step as $step) {
		$i++;
		echo '<li class="row" ><h4>Шаг '.$i.' </h4><span class="img-step col-xs-6 col-md-4"><a href="'. $step['artabr_photo_step']. '"><img src="'. $step['artabr_photo_step']. '" class="gallery-item" alt="'. esc_html($step['artabr_text_step']) .'" title="'. esc_html($step['artabr_text_step']) .'" width="214" height="143"></a></span><span class="img-text col-xs-12 col-md-8" >'. $step['artabr_text_step'] .'</span></li>';
	}
	echo '</ul>'; ?>

Переменная $i — просто счетчик, чтобы считать шаги. В итоге получаем: шаг 1, шаг 2 и т.д.

к содержанию

Выводим время подготовки и время приготовления

Если вы внимательно смотрели третью серию, то знаете, что время надо указывать в минутах. Ну а чтобы эти минуты преобразовать в штатный формат — часы-минуты используем такие функции:

Пересчет времени из минут в часы

/**
 * Пересчет времени из минут в часы
 */
if ( ! function_exists( 'artabr_convert_minute_hour' ) ) {
	function artabr_convert_minute_hour( $time ) {
		$hours_postfix = '&nbsp;час';
		$minutes_postfix = '&nbsp;мин';
	    settype( $time, 'integer' );
	    if ( $time < 1 ) {
	        return;
	    }
	    $hours = floor( $time / 60 );
	    $minutes = $time % 60;
	    if ( $time < 60 ) {
	    	$content = $minutes . $minutes_postfix;
	    } else {
   		$content = $hours . $hours_postfix . '&ensp;' . $minutes . $minutes_postfix;
	    }
	    return $content;
	}
}

Подсчет общего времени

Данная функция понадобиться для внедрения микроразметки, значения функции нигде не выводяться
/**
 * Подсчет общего времени
 */
if ( ! function_exists( 'artabr_calc_total_cook_time' ) ) {
	function artabr_calc_total_cook_time() {
		global $post;
		$prep_time = (int) ( CFS()->get('artabr_recipe_prepTime'));
		$cook_time = (int) ( CFS()->get('artabr_recipe_cookTime') );
		$total_time = $prep_time + $cook_time;
		return $total_time;
	}
}

Функции добавляем в файл functions.php и теперь надо полученные значения вывести на странице рецепта

/* Передаем на вход функции пересчета времени значения полей времени и записываем их в переменные */
$prep_time = artabr_convert_minute_hour( CFS()->get('artabr_recipe_prepTime') ); // время подготовки
$cook_time = artabr_convert_minute_hour( CFS()->get('artabr_recipe_cookTime') ); // время приготовления

/* Выводим в нужном месте*/
/* Время на подготовку*/
<?php if ( $prep_time ) { ?>
	<span class="prep-time">
		<?php echo 'Время на подготовку: '; ?>
		<span class="the-time"><strong><span class="dashicons dashicons-clock"></span> <?php echo $prep_time; ?></strong></span>
	</span>
<?php } ?>
/* Время на приготовление*/
<?php if ( $cook_time ) { ?>
	<span class="cook-time">
		<?php echo 'Время приготовления: '; ?>
		<span class="the-time"><strong><span class="dashicons dashicons-clock"></span> <?php echo $cook_time; ?></strong></span>
	</span>
<?php } ?>
к содержанию

Внедряем микроразметку

Внедрение микроразметки очень похоже на расстановку тегов. Требуется только расставить нужные теги (по другому — сущности) в нужных местах…

Единственный момент — это необходимо написать условие для вывода записей относящихся к разным рубрикам:

  • для рецептов должно выводиться itemscope itemtype="http://schema.org/Recipe"
  • для остальных записей itemscope itemtype="http://schema.org/Article"

Выглядит это примерно так

<?php if (in_category(1)) { ?> // указываем ID нужной рубрики
<div itemscope itemtype="http://schema.org/Recipe">
          <!-- Цикл вывода страницы записи рецептов-->
</div>
<?php } else { ?>
<div itemscope itemtype="http://schema.org/Article">
	 <!-- Цикл вывода страницы записи рецептов-->
</div>		
<? } ?>
к содержанию

Нужные сущности схемы Recipe

Рецепт itemscope itemtype="http://schema.org/Recipe"
	Метаданные рецепта
		Название itemprop="name"
		Автор itemprop="author"
		Дата публикации itemprop="datePublished"
		Фото результат itemprop="resultPhoto"
		Количество порций itemprop="recipeYield"
		Время на подготовку itemprop="prepTime"
		Время приготовления itemprop="cookTime"
		Общее время itemprop="totalTime"
		Метод приготовления itemprop="cookingMethod"
		Национальная кухня itemprop="recipeCuisine"
		Рубрика рецепта itemprop="recipeCategory"
	Основные данные рецепта 
		Описание рецепта itemprop="description"
		Ингредиенты рецепта itemprop="ingredients"
к содержанию

Места для расстановки

к содержанию

Микроразметка даты и времени

«Финт ушами» для микроразметки даты

Для микроразметки даты лучше использовать финт ушами и применять скрытый тег.

<time datetime="<?php the_time('Y-m-d') ?>" itemprop="datePublished"></time>

Подставлять его надо рядом с функцией вывода даты

Функции конвертирования времени в формат ISO8601

Для пересчета времени используются похожие функции, что были описаны выше

Функция конвертирования минут в часы для микроразметки
/**
 * Пересчет времени в формат ISO8601
 */
if ( ! function_exists( 'schema_convert_minute_hour' ) ) {
	function schema_convert_minute_hour( $time ) {
		$hours_postfix = 'h';
		$minutes_postfix = 'm';
	    settype( $time, 'integer' );
	    if ( $time < 1 ) {
	        return;
	    }
	    $hours = floor( $time / 60 );
	    $minutes = $time % 60;
	    if ( $time < 60 ) {
	    	$content = $minutes . $minutes_postfix;
	    } else {
	   		$content = $hours . $hours_postfix . ' ' . $minutes . $minutes_postfix;
	    }
	    return $content;
	}
}
Пересчет времени подготовки
/**
 * Пересчет времени подготовки в формат ISO8601
 */
if ( ! function_exists( 'schema_prep_time' ) ) {
	function schema_prep_time() {
		global $post;
		$prep_time = schema_convert_minute_hour( CFS()->get('artabr_recipe_prepTime') );
		$prep_time_alt = strtoupper( str_replace( array( ' ', '-', ',' ), array( '' ), $prep_time ) );
		$prep_time_schema = 'PT' . $prep_time_alt;
		return $prep_time_schema;
	}
}
Конвертирование времени приготовления
/**
 * Время приготовления в формат ISO8601
 */
if ( ! function_exists( 'schema_cook_time' ) ) {
	function schema_cook_time() {
		global $post;
		$cook_time = schema_convert_minute_hour( CFS()->get('artabr_recipe_cookTime') );
		$cook_time_alt = strtoupper( str_replace( array( ' ', '-', ',' ), array( '' ), $cook_time ) );
		$cook_time_schema  = 'PT' . $cook_time_alt;
		return $cook_time_schema;
	}
}
Пересчет общего времени
/**
 * Пересчет общего времени в формат ISO8601
 */
if ( ! function_exists( 'schema_total_time' ) ) {
	function schema_total_time() {
		global $post;
		$total_time = schema_convert_minute_hour ( artabr_calc_total_cook_time() );
		$total_time_alt = strtoupper( str_replace( array( ' ', '-', ',' ), array( '' ), $total_time ) );
		$total_time_schema = 'PT' . $total_time_alt;
		return $total_time_schema;
	}
}

Вывод функций времени на странице рецепта

Результаты данных функций следует выводить в теге meta. Что не даст дублировать контент на странице рецепта. Примерно так

Время подготовки
<meta itemprop="prepTime" content="<?php echo schema_prep_time(); ?>">
Время приготовления
<meta itemprop="cookTime" content="<?php echo schema_cook_time(); ?>">
Общее время
<meta itemprop="totalTime" content="<?php echo schema_total_time(); ?>">
к содержанию

Заключение и нужные ссылки

к содержанию

Документация и ссылки

Плагин Custom Field Suite

Есть вопросы? Пишем в комментариях.

Всегда ваш, Артем