�PNG  IHDR22?�� pHYs  �� OiCCPPhotoshop ICC profilexڝSgTS�=���BK���KoR RB���&*! J�!��Q�EEȠ�����Q, � ��!���������{�kּ������>���� �H3Q5� �B�������.@� $p�d!s�#�~<<+"��x� �M��0���B�\���t�8K�@z�B�@F���&S�`�cb�P-`'������{[�!�� e�Dh;��V�EX0fK�9�-0IWfH���� � 0Q��){`�##x��F�W<�+��*x��<�$9E�[-qWW.(�I+6aa�@.�y�2�4���������x����6��_-��"bb���ϫp@�t~��,/��;�m��%�h^ �u��f�@����W�p�~<�5�j>{�-�]c�K'Xt����o��(�h���w��?�G�%�fI�q^D$.Tʳ?�D��*�A��,���� �`6�B$��BB d�r`)��B(�Ͱ*`/�@4�Qh��p.�U�=p�a��(�� A�a!ڈb�X#����!�H�$ ɈQ"K�5H1R�T UH�=r9�\F��;�2����G1���Q=� �C��7�F� �dt1�����r�=�6��Ыhڏ>C�0��3�l0.��B�8, �c˱"� ���V����cϱw�E� 6wB aAHXLXN�H� $4� 7 �Q�'"��K�&���b21�XH,#��/{�C�7$�C2'��I��T��F�nR#�,��4H#���dk�9�, +ȅ����3��!�[ �b@q��S�(R�jJ��4�e�2AU��Rݨ�T5�ZB���R�Q��4u�9̓IK�����hh�i��t�ݕN��W���G���w ��Ljg(�gw��L�Ӌ�T071���oUX*�*|�� �J�&�*/T����ު U�U�T��^S}�FU3S� Ԗ�U��P�SSg�;���g�oT?�~Y��Y�L�OC�Q��_�� c�x,!k ��u�5�&���|v*�����=���9C3J3W�R�f?�q��tN �(���~���)�)�4L�1e\k����X�H�Q�G�6������E�Y��A�J'\'Gg����S�Sݧ �M=:��.�k���Dw�n��^��Lo��y���}/�T�m���G X� $� �<�5qo</���QC]�@C�a�a�ᄑ��<��F�F�i�\�$�m�mƣ&&!&KM�M�RM��)�;L;L���͢�֙5�=1�2��כ߷`ZxZ,����eI��Z�Yn�Z9Y�XUZ]�F���%ֻ�����N�N���gð�ɶ�����ۮ�m�}agbg�Ů��}�}��= ���Z~s�r:V:ޚΜ�?}����/gX���3��)�i�S��Ggg�s�󈋉K��.�>.���Ƚ�Jt�q]�z���������ۯ�6�i�ܟ�4�)�Y3s���C�Q��? ��0k߬~OCO�g��#/c/�W�װ��w��a�>�>r��>�<7�2�Y_�7��ȷ�O�o�_��C#�d�z����%g��A�[��z|!��?:�e����A���AA�������!h�쐭!��Α�i�P~���a�a��~ '���W�?�p�X�1�5w��Cs�D�D�Dޛg1O9�-J5*>�.j<�7�4�?�.fY��X�XIlK9.*�6nl������� �{�/�]py�����.,:�@L�N8��A*��%�w%� y��g"/�6ш�C\*N�H*Mz�쑼5y$�3�,幄'���L Lݛ:��v m2=:�1����qB�!M��g�g�fvˬe����n��/��k���Y- �B��TZ(�*�geWf�͉�9���+��̳�ې7�����ᒶ��KW-X潬j9�������(�x��oʿ�ܔ���Ĺd�f�f���-�[����n �ڴ �V����E�/��(ۻ��C���<��e����;?T�T�T�T6��ݵa��n��{��4���[���>ɾ�UUM�f�e�I���?�������m]�Nmq����#�׹���=TR��+�G�����w- 6 U����#pDy��� �� :�v�{���vg/jB��F�S��[b[�O�>����z�G��499�?r����C�d�&����ˮ/~�����јѡ�򗓿m|������������x31^�V���w�w��O�| (�h���SЧ��������c3-� cHRMz%������u0�`:�o�_�F5IDATx��ytUս�?�;���fN$$��@B�!�k��� -*�gE���j�O�kQ�ʠ`U�B_ �AÐ0%�Ȕ�@r3ޛ;߳��$�@��v����^�s����������$��ߢ !�W��5�̱'-٘������4�>�Rƫ$�G��0U�H}�_ _� #��k�MJ/=�9Du *ڲ�k�PQ;0��j|�*�$�^컂脛y���>�z×� B��� ��(�:$�ʔ_�6��C!B����MVx��a��ζyY����j��ƋY2�9�F�{r��r�딟F��Q��hY6��� x��[l��RC��������nt@��;P��3��� F�w��7��:�P���ɋ'���mj���Bƪ�$�Q�L��y��߷g��\���z����v5�p�v$�v櫻�`6~K �Y�X����,�:��"�o�e0II"(��,������l_�C���/4�+f�E�!q��:����u����c��樼.UE�@� �]K�W���$-�h]�JG���Dz)�`��.�A/ ���mᏣc�3jK� �!�>���$�Q�!�_�? \�C2(E �M$Z I{�U���s�ǣ���=��@Բe ޻��W�����@ �w����}�9v,)��.}*|"�s��di���,���G�]W�AC�������|<����[��ߕ������K�*�G nߴ!��‹��J�!��6(L�a)��Am��������;adf��:�xm��nh�;֦I��(���o�C~ډa?�=��s����h��E������xp����)���_���t��W�����´;8���`dz=(��@@�+,�;�`�fhl��XȌ�3,uI�~z(J����� �ZX�A����H'�À�㜦�82|��a�n�z2��I���� ���EY�h�ε<�0�q�{��C��v�˅��?"@��χ�x�WS+��N�~�KQ�J�8ل�� _.W��� !TU{�����,��"�� �;�������HI S� ��))�o�1�H�D� ���� (� ;����"Ҕ��,���� �F=���O��&�Ph>�`���y��߲ &S��P�<��'��1s�1cĂ�N����2)����@�u��tv��<�+�-&�����h��[!FSG���' � z z0��<����8d&�����E0�,��<��"!P�b4��� �{S�����X����.�囤���T��hEF��X�q0"-<����h���]�Py*����F⩍��@v�˂�Y08�� .q��a��s����(!<̫1�3�L�H��7sYW�`��qtu�\7��?�@�Y�� %Ka�x�GZ�*W�P��y�����N0r9��Z�c�%���q,��k�����!!,��>���IB��� �x1�Xu�Y���v-���ֺ��N������JP��a�2`�e5��w��u;�6�i���̃��(K���ťa��(l51��JL��O'%���]���ٖ뿉!��{*�p+f ���i8��D�ȑ���ܩ�M��V��ӟz��x�7Z�1i}�^͜���6e����x��)u�d�ˏ�V�eG�\�X1�����=n�U'�~Y����L�\,�(d!x ,�:�TW8� M`r���@��r+v�Q0��>^;˴�VbF��('����� �*O��i��j�Ӆ����^�S3&� ���{������.ی�� N;��NU%d0�Ce\r"�C�b��&t7N�7��� �ȪD�[%l�۪�$��'m?�A9tI�9>��NVL ��� 6v~M�����ъ�B���0����9$&=ώm��W�0���L���&��E���f�f��'+�9��hv��7,���M��6�D�&�^� �����8 D֮�����o��k^z��O��hP�8q�5d*��YVq3�{��������#LX4�?��jP=3�~�؅c�ݰ�̱�ұ��8̲��2�G�����j��έ�9��w7���U�X�w�85C��?!I&���o&����L���I#�^�eV�,�^t5�k� �xs˛\��U�8��."���{���ǵ�l4��ݼ�;��r"���G�/~���gJV�N糦��ZZ^k+NN�D��I$�=OE�z����|*�*{��%k���G��>�`9��b;�s���8,�qs��c��.b��q�%�>r��n�R�Ƨ�%�,�A��le#�8���}; 21�0�b�&�QX�f���q�00����$>�h�N�'�a3��A���/�r ��L5�8�GԲ'�����w;��c#�q1���h$*��V^�k��QĽ�b:i������� ����H F#�_���,��]g����Ը����`RUU���� ��"�qD���>-��ϤI�~��3�̴�����NZ[[555�eeek7�m����YF#[��Đ��R��i��L�H�r ��@��J-�Pŝ��_|�-��6y��ks�V�U~��6���w.����(��0A� 4��f��� /���C�xŊ�ٳ����z=6�����rg���mKo��o�/����a�g���?'9%9��P��斓��~���L{�� �H��{AW��B��$����v�1b�&Mb�ر��ر#�0`�`xMBp! )Z�Nmo�mZ�g�}�eذaWTVV ���'99��C5��&�&+5�bT>|8��PUUETT����&���t��~TE%��'������b�tEGG;RSS�S�N�v��ѯ��t����u1@�ޚ"f��͈���r'L�Ph��m��ƌ�74o��`�x�q�P���NRSS�X,�����l&&&��MFFA!-��`��ҷ�n��Yuu�����x<I�LB%����KԒ50�!�3�bz�����ʸKL���;---�l6[��`��������Ȏ;�����egg4��!D�T��jWujyZ��������K����%����p�^���X,6��sV=�ܖ����6�3�X ���4ҿ��A2�&����_k�;d�� �VfOIEND�B`�
Warning: session_start(): Session cannot be started after headers have already been sent in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 124

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 130

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 131

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 132

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 133

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 134

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 135
0x0x
PHP 8.2.31
Preview: recipe.php Size: 18.83 KB
/home/m/c/i/mciraet/www/wp-content/plugins/jetpack/modules/shortcodes/recipe.php
<?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileName

use Automattic\Jetpack\Assets;

if ( ! defined( 'ABSPATH' ) ) {
	exit( 0 );
}

/**
 * Embed recipe 'cards' in post, with basic styling and print functionality
 *
 * To Do
 * - defaults settings
 * - basic styles/themecolor styles
 * - validation/sanitization
 * - print styles
 *
 * @package automattic/jetpack
 */

/**
 * Register and display Recipes in posts.
 *
 * @phan-constructor-used-for-side-effects
 */
class Jetpack_Recipes {

	/**
	 * Have scripts and styles been enqueued already.
	 *
	 * @var bool
	 */
	private $scripts_and_style_included = false;

	/**
	 * Constructor
	 */
	public function __construct() {
		add_action( 'init', array( $this, 'action_init' ) );
	}

	/**
	 * Returns KSES tags with Schema-specific attributes.
	 *
	 * @since 8.0.0
	 *
	 * @return array Array to be used by KSES.
	 */
	private static function kses_tags() {
		$allowedtags = wp_kses_allowed_html( 'post' );
		// Create an array of all the tags we'd like to add the itemprop attribute to.
		$tags = array( 'li', 'ol', 'ul', 'img', 'p', 'h3', 'time', 'span' );
		foreach ( $tags as $tag ) {
			if ( ! isset( $allowedtags[ $tag ] ) ) {
				$allowedtags[ $tag ] = array();
			}
			$allowedtags[ $tag ]['class']    = array();
			$allowedtags[ $tag ]['itemprop'] = array();
			$allowedtags[ $tag ]['datetime'] = array();
		}

		// Allow the handler <a on=""> in AMP.
		$allowedtags['a']['on'] = array();

		// Allow itemscope and itemtype for divs.
		if ( ! isset( $allowedtags['div'] ) ) {
			$allowedtags['div'] = array();
		}
		$allowedtags['div']['class']     = array();
		$allowedtags['div']['itemscope'] = array();
		$allowedtags['div']['itemtype']  = array();
		return $allowedtags;
	}

	/**
	 * Register our shortcode and enqueue necessary files.
	 */
	public function action_init() {
		// Enqueue styles if [recipe] exists.
		add_action( 'wp_head', array( $this, 'add_scripts' ), 1 );

		// Render [recipe], along with other shortcodes that can be nested within.
		add_shortcode( 'recipe', array( $this, 'recipe_shortcode' ) );
		add_shortcode( 'recipe-notes', array( $this, 'recipe_notes_shortcode' ) );
		add_shortcode( 'recipe-ingredients', array( $this, 'recipe_ingredients_shortcode' ) );
		add_shortcode( 'recipe-directions', array( $this, 'recipe_directions_shortcode' ) );
		add_shortcode( 'recipe-nutrition', array( $this, 'recipe_nutrition_shortcode' ) );
		add_shortcode( 'recipe-image', array( $this, 'recipe_image_shortcode' ) );
	}

	/**
	 * Enqueue scripts and styles
	 */
	public function add_scripts() {
		if ( empty( $GLOBALS['posts'] ) || ! is_array( $GLOBALS['posts'] ) ) {
			return;
		}

		foreach ( $GLOBALS['posts'] as $p ) {
			if ( isset( $p->post_content ) && has_shortcode( $p->post_content, 'recipe' ) ) {
				$this->scripts_and_style_included = true;
				break;
			}
		}

		if ( ! $this->scripts_and_style_included ) {
			return;
		}

		wp_enqueue_style( 'jetpack-recipes-style', plugins_url( '/css/recipes.css', __FILE__ ), array(), '20130919' );
		wp_style_add_data( 'jetpack-recipes-style', 'rtl', 'replace' );

		// add $themecolors-defined styles.
		wp_add_inline_style( 'jetpack-recipes-style', self::themecolor_styles() );

		if ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() ) {
			return;
		}

		wp_register_script(
			'jetpack-shortcode-deps',
			plugins_url( '_inc/build/shortcodes/js/dependencies.min.js', JETPACK__PLUGIN_FILE ),
			array( 'jquery' ),
			'20250905',
			true
		);

		wp_enqueue_script(
			'jetpack-recipes-js',
			Assets::get_file_url_for_environment( '_inc/build/shortcodes/js/recipes.min.js', 'modules/shortcodes/js/recipes.js' ),
			array( 'jquery', 'jetpack-shortcode-deps' ),
			'20131230',
			false
		);

		$title_var     = wp_title( '|', false, 'right' );
		$rtl           = is_rtl() ? '-rtl' : '';
		$print_css_var = plugins_url( "/css/recipes-print{$rtl}.css", __FILE__ );

		wp_localize_script(
			'jetpack-recipes-js',
			'jetpack_recipes_vars',
			array(
				'pageTitle' => $title_var,
				'loadCSS'   => $print_css_var,
			)
		);
	}

	/**
	 * Our [recipe] shortcode.
	 * Prints recipe data styled to look good on *any* theme.
	 *
	 * @param array  $atts    Array of shortcode attributes.
	 * @param string $content Post content.
	 *
	 * @return string HTML for recipe shortcode.
	 */
	public static function recipe_shortcode( $atts, $content = '' ) {
		$atts = shortcode_atts(
			array(
				'title'       => '', // string.
				'servings'    => '', // intval.
				'time'        => '', // strtotime-compatible time description.
				'difficulty'  => '', // string.
				'print'       => '', // URL for external print version.
				'source'      => '', // string.
				'sourceurl'   => '', // URL string. Only used if source set.
				'image'       => '', // URL or attachment ID.
				'description' => '', // string.
				'cooktime'    => '', // strtotime-compatible time description.
				'preptime'    => '', // strtotime-compatible time description.
				'rating'      => '', // string.
			),
			$atts,
			'recipe'
		);

		return self::recipe_shortcode_html( $atts, $content );
	}

	/**
	 * The recipe output
	 *
	 * @param array  $atts    Array of shortcode attributes.
	 * @param string $content Post content.
	 *
	 * @return string HTML output
	 */
	private static function recipe_shortcode_html( $atts, $content = '' ) {

		$html = '<div class="hrecipe h-recipe jetpack-recipe" itemscope itemtype="https://schema.org/Recipe">';

		// Print the recipe title if exists.
		if ( '' !== $atts['title'] ) {
			$html .= '<h3 class="p-name jetpack-recipe-title fn" itemprop="name">' . esc_html( $atts['title'] ) . '</h3>';
		}

		// Print the recipe meta if exists.
		if (
			'' !== $atts['servings']
			|| '' !== $atts['time']
			|| '' !== $atts['difficulty']
			|| '' !== $atts['print']
			|| '' !== $atts['preptime']
			|| '' !== $atts['cooktime']
			|| '' !== $atts['rating']
		) {
			$html .= '<ul class="jetpack-recipe-meta">';

			if ( '' !== $atts['servings'] ) {
				$html .= sprintf(
					'<li class="jetpack-recipe-servings p-yield yield" itemprop="recipeYield"><strong>%1$s: </strong>%2$s</li>',
					esc_html_x( 'Servings', 'recipe', 'jetpack' ),
					esc_html( $atts['servings'] )
				);
			}

			$time_types = array( 'preptime', 'cooktime', 'time' );
			foreach ( $time_types as $time_type ) {
				if ( '' === $atts[ $time_type ] ) {
					continue;
				}
				$html .= self::output_time( $atts[ $time_type ], $time_type );
			}

			if ( '' !== $atts['difficulty'] ) {
				$html .= sprintf(
					'<li class="jetpack-recipe-difficulty"><strong>%1$s: </strong>%2$s</li>',
					esc_html_x( 'Difficulty', 'recipe', 'jetpack' ),
					esc_html( $atts['difficulty'] )
				);
			}

			if ( '' !== $atts['rating'] ) {
				$html .= sprintf(
					'<li class="jetpack-recipe-rating">
						<strong>%1$s: </strong>
						<span itemprop="contentRating">%2$s</span>
					</li>',
					esc_html_x( 'Rating', 'recipe', 'jetpack' ),
					esc_html( $atts['rating'] )
				);
			}

			if ( '' !== $atts['source'] ) {
				$html .= sprintf(
					'<li class="jetpack-recipe-source"><strong>%1$s: </strong>',
					esc_html_x( 'Source', 'recipe', 'jetpack' )
				);

				if ( '' !== $atts['sourceurl'] ) :
					// Show the link if we have one.
					$html .= sprintf(
						'<a href="%2$s">%1$s</a>',
						esc_html( $atts['source'] ),
						esc_url( $atts['sourceurl'] )
					);
				else :
					// Skip the link.
					$html .= sprintf(
						'%1$s',
						esc_html( $atts['source'] )
					);
				endif;

				$html .= '</li>';
			}

			if ( 'false' !== $atts['print'] ) {
				$is_amp       = class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request();
				$print_action = $is_amp ? 'on="tap:AMP.print"' : '';
				$print_text   = $is_amp ? esc_html__( 'Print page', 'jetpack' ) : esc_html_x( 'Print', 'recipe', 'jetpack' );
				$html        .= sprintf(
					'<li class="jetpack-recipe-print"><a href="#" %1$s>%2$s</a></li>',
					$print_action,
					$print_text
				);
			}

			$html .= '</ul>';
		}

		// Output the image if we have one and it's not shown elsewhere.
		if ( '' !== $atts['image'] ) {
			if ( ! has_shortcode( $content, 'recipe-image' ) ) {
				$html .= self::output_image_html( $atts['image'] );
			}
		}

		// Output the description, if we have one.
		if ( '' !== $atts['description'] ) {
			$html .= sprintf(
				'<p class="jetpack-recipe-description" itemprop="description">%1$s</p>',
				esc_html( $atts['description'] )
			);
		}

		// Print content between codes.
		$html .= '<div class="jetpack-recipe-content">' . do_shortcode( $content ) . '</div>';

		// Close it up.
		$html .= '</div>';

		// If there is a recipe within a recipe, remove the shortcode.
		if ( has_shortcode( $html, 'recipe' ) ) {
			remove_shortcode( 'recipe' );
		}

		// Sanitize html.
		$html = wp_kses( $html, self::kses_tags() );

		// Return the HTML block.
		return $html;
	}

	/**
	 * Our [recipe-image] shortcode.
	 * Controls placement of image in recipe.
	 *
	 * @param array $atts Array of shortcode attributes.
	 *
	 * @return string HTML for recipe notes shortcode.
	 */
	public static function recipe_image_shortcode( $atts ) {
		$atts = shortcode_atts(
			array(
				'image' => '', // string.
				0       => '', // string.
			),
			$atts,
			'recipe-image'
		);
		$src  = $atts['image'];
		if ( ! empty( $atts[0] ) ) {
			$src = $atts[0];
		}
		return self::output_image_html( $src );
	}

	/**
	 * Our [recipe-notes] shortcode.
	 * Outputs ingredients, styled in a div.
	 *
	 * @param array  $atts    Array of shortcode attributes.
	 * @param string $content Post content.
	 *
	 * @return string HTML for recipe notes shortcode.
	 */
	public static function recipe_notes_shortcode( $atts, $content = '' ) {
		$atts = shortcode_atts(
			array(
				'title' => '', // string.
			),
			$atts,
			'recipe-notes'
		);

		$html = '';

		// Print a title if one exists.
		if ( '' !== $atts['title'] ) {
			$html .= '<h4 class="jetpack-recipe-notes-title">' . esc_html( $atts['title'] ) . '</h4>';
		}

		$html .= '<div class="jetpack-recipe-notes">';

		// Format content using list functionality, if desired.
		$html .= self::output_list_content( $content, 'notes' );

		$html .= '</div>';

		// Sanitize html.
		$html = wp_kses( $html, self::kses_tags() );

		// Return the HTML block.
		return $html;
	}

	/**
	 * Our [recipe-ingredients] shortcode.
	 * Outputs notes, styled in a div.
	 *
	 * @param array  $atts    Array of shortcode attributes.
	 * @param string $content Post content.
	 *
	 * @return string HTML for recipe ingredients shortcode.
	 */
	public static function recipe_ingredients_shortcode( $atts, $content = '' ) {
		$atts = shortcode_atts(
			array(
				'title' => esc_html_x( 'Ingredients', 'recipe', 'jetpack' ), // string.
			),
			$atts,
			'recipe-ingredients'
		);

		$html = '<div class="jetpack-recipe-ingredients">';

		// Print a title unless the user has opted to exclude it.
		if ( 'false' !== $atts['title'] ) {
			$html .= '<h4 class="jetpack-recipe-ingredients-title">' . esc_html( $atts['title'] ) . '</h4>';
		}

		// Format content using list functionality.
		$html .= self::output_list_content( $content, 'ingredients' );

		$html .= '</div>';

		// Sanitize html.
		$html = wp_kses( $html, self::kses_tags() );

		// Return the HTML block.
		return $html;
	}

	/**
	 * Our [recipe-nutrition] shortcode.
	 * Outputs notes, styled in a div.
	 *
	 * @param array  $atts    Array of shortcode attributes.
	 * @param string $content Post content.
	 *
	 * @return string HTML for recipe nutrition shortcode.
	 */
	public static function recipe_nutrition_shortcode( $atts, $content = '' ) {
		$atts = shortcode_atts(
			array(
				'title' => esc_html_x( 'Nutrition', 'recipe', 'jetpack' ), // string.
			),
			$atts,
			'recipe-nutrition'
		);

		$html = '<div class="jetpack-recipe-nutrition p-nutrition nutrition">';

		// Print a title unless the user has opted to exclude it.
		if ( 'false' !== $atts['title'] ) {
			$html .= '<h4 class="jetpack-recipe-nutrition-title">' . esc_html( $atts['title'] ) . '</h4>';
		}

		// Format content using list functionality.
		$html .= self::output_list_content( $content, 'nutrition' );

		$html .= '</div>';

		// Sanitize html.
		$html = wp_kses( $html, self::kses_tags() );

		// Return the HTML block.
		return $html;
	}

	/**
	 * Reusable function to check for shortened formatting.
	 * Basically, users can create lists with the following shorthand:
	 * - item one
	 * - item two
	 * - item three
	 * And we'll magically convert it to a list. This has the added benefit
	 * of including itemprops for the recipe schema.
	 *
	 * @param string $content HTML content.
	 * @param string $type    Type of list.
	 *
	 * @return string content formatted as a list item
	 */
	private static function output_list_content( $content, $type ) {
		$html = '';

		switch ( $type ) {
			case 'directions':
				$list_item_replacement = '<li class="jetpack-recipe-directions">${1}</li>';
				$itemprop              = ' itemprop="recipeInstructions"';
				$listtype              = 'ol';
				break;
			case 'ingredients':
				$list_item_replacement = '<li class="jetpack-recipe-ingredient p-ingredient ingredient" itemprop="recipeIngredient">${1}</li>';
				$itemprop              = '';
				$listtype              = 'ul';
				break;
			case 'nutrition':
				$list_item_replacement = '<li class="jetpack-recipe-nutrition">${1}</li>';
				$itemprop              = ' itemprop="nutrition"';
				$listtype              = 'ul';
				break;
			default:
				$list_item_replacement = '<li class="jetpack-recipe-notes">${1}</li>';
				$itemprop              = '';
				$listtype              = 'ul';
		}

		// Check to see if the user is trying to use shortened formatting.
		if (
			str_contains( $content, '&#8211;' ) ||
			str_contains( $content, '&#8212;' ) ||
			str_contains( $content, '-' ) ||
			str_contains( $content, '*' ) ||
			str_contains( $content, '#' ) ||
			str_contains( $content, '–' ) || // ndash.
			str_contains( $content, '—' ) || // mdash.
			preg_match( '/\d+\.\s/', $content )
		) {
			// Remove breaks and extra whitespace.
			$content = str_replace( "<br />\n", "\n", $content );
			$content = trim( $content );

			$ul_pattern = '/(?:^|\n|\<p\>)+(?:[\-–—]+|\&#8211;|\&#8212;|\*)+\h+(.*)/mi';
			$ol_pattern = '/(?:^|\n|\<p\>)+(?:\d+\.|#+)+\h+(.*)/mi';

			preg_match_all( $ul_pattern, $content, $ul_matches );
			preg_match_all( $ol_pattern, $content, $ol_matches );

			if ( ( is_countable( $ul_matches[0] ) && count( $ul_matches[0] ) > 0 ) || ( is_countable( $ol_matches[0] ) && count( $ol_matches[0] ) > 0 ) ) {

				if ( is_countable( $ol_matches[0] ) && count( $ol_matches[0] ) > 0 ) {
					$listtype          = 'ol';
					$list_item_pattern = $ol_pattern;
				} else {
					$listtype          = 'ul';
					$list_item_pattern = $ul_pattern;
				}
				$html .= '<' . $listtype . $itemprop . '>';
				$html .= preg_replace( $list_item_pattern, $list_item_replacement, $content );
				$html .= '</' . $listtype . '>';

				// Strip out any empty <p> tags and stray </p> tags, because those are just silly.
				$empty_p_pattern = '/(<p>)*\s*<\/p>/mi';
				$html            = preg_replace( $empty_p_pattern, '', $html );
			} else {
				$html .= do_shortcode( $content );
			}
		} else {
			$html .= do_shortcode( $content );
		}

		// Return our formatted content.
		return $html;
	}

	/**
	 * Our [recipe-directions] shortcode.
	 * Outputs directions, styled in a div.
	 *
	 * @param array  $atts    Array of shortcode attributes.
	 * @param string $content Post content.
	 *
	 * @return string HTML for recipe directions shortcode.
	 */
	public static function recipe_directions_shortcode( $atts, $content = '' ) {
		$atts = shortcode_atts(
			array(
				'title' => esc_html_x( 'Directions', 'recipe', 'jetpack' ), // string.
			),
			$atts,
			'recipe-directions'
		);

		$html = '<div class="jetpack-recipe-directions e-instructions">';

		// Print a title unless the user has specified to exclude it.
		if ( 'false' !== $atts['title'] ) {
			$html .= '<h4 class="jetpack-recipe-directions-title">' . esc_html( $atts['title'] ) . '</h4>';
		}

		// Format content using list functionality.
		$html .= self::output_list_content( $content, 'directions' );

		$html .= '</div>';

		// Sanitize html.
		$html = wp_kses( $html, self::kses_tags() );

		// Return the HTML block.
		return $html;
	}

	/**
	 * Outputs time meta tag.
	 *
	 * @param string $time_str  Raw time to output.
	 * @param string $time_type Type of time to show.
	 *
	 * @return string HTML for recipe time meta.
	 */
	private static function output_time( $time_str, $time_type ) {
		// Get a time that's supported by Schema.org.
		$duration = WPCOM_JSON_API_Date::format_duration( $time_str );
		// If no duration can be calculated, let's output what the user provided.
		if ( ! $duration ) {
			$duration = $time_str;
		}

		switch ( $time_type ) {
			case 'cooktime':
				$title    = _x( 'Cook Time', 'recipe', 'jetpack' );
				$itemprop = 'cookTime';
				break;
			case 'preptime':
				$title    = _x( 'Prep Time', 'recipe', 'jetpack' );
				$itemprop = 'prepTime';
				break;
			default:
				$title    = _x( 'Time', 'recipe', 'jetpack' );
				$itemprop = 'totalTime';
				break;
		}

		return sprintf(
			'<li class="jetpack-recipe-%3$s">
				<time itemprop="%4$s" datetime="%5$s"><strong>%1$s:</strong> <span class="%3$s">%2$s</span></time>
			</li>',
			esc_html( $title ),
			esc_html( $time_str ),
			esc_attr( $time_type ),
			esc_attr( $itemprop ),
			esc_attr( $duration )
		);
	}

	/**
	 * Outputs image tag for recipe.
	 *
	 * @param string $src The image source.
	 *
	 * @return string
	 */
	private static function output_image_html( $src ) {
		// Exit if there is no provided source.
		if ( ! $src ) {
			return '';
		}

		$image_attrs = array(
			'class'    => 'jetpack-recipe-image u-photo photo',
			'itemprop' => 'image',
		);

		if ( wp_lazy_loading_enabled( 'img', 'wp_get_attachment_image' ) ) {
			$image_attrs['loading'] = 'lazy';
		}

		// If it's numeric, this may be an attachment.
		if ( is_numeric( $src ) ) {
			return wp_get_attachment_image(
				$src,
				'full',
				false,
				$image_attrs
			);
		}

		// Check if it's an absolute or relative URL, and return if not.
		if (
			! str_starts_with( $src, '/' )
			&& false === filter_var( $src, FILTER_VALIDATE_URL )
		) {
			return '';
		}

		$image_attrs_markup = '';
		foreach ( $image_attrs as $name => $value ) {
			$image_attrs_markup .= sprintf(
				' %1$s="%2$s"',
				esc_attr( $name ),
				esc_attr( $value )
			);
		}

		return sprintf(
			'<img%1$s src="%2$s" />',
			$image_attrs_markup,
			esc_url( $src )
		);
	}

	/**
	 * Use $themecolors array to style the Recipes shortcode
	 *
	 * @print style block
	 * @return string $style
	 */
	public function themecolor_styles() {
		global $themecolors;
		$style = '';

		if ( isset( $themecolors['border'] ) ) {
			$style .= '.jetpack-recipe { border-color: #' . esc_attr( $themecolors['border'] ) . '; }';
		}
		if ( isset( $themecolors['link'] ) ) {
			$style .= '.jetpack-recipe-title { border-bottom-color: #' . esc_attr( $themecolors['link'] ) . '; }';
		}

		return $style;
	}
}

new Jetpack_Recipes();

Directory Contents

Dirs: 4 × Files: 55
Name Size Perms Modified Actions
css DIR
- drwxr-xr-x 2026-08-21 10:05:50
Edit Download
images DIR
- drwxr-xr-x 2026-08-21 10:05:50
Edit Download
img DIR
- drwxr-xr-x 2026-08-21 10:05:50
Edit Download
js DIR
- drwxr-xr-x 2026-08-21 10:05:50
Edit Download
3.41 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
5.15 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
3.36 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
7.79 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
8.81 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
850 B lrw-r--r-- 2026-08-21 10:05:50
Edit Download
13.17 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
312 B lrw-r--r-- 2026-08-21 10:05:50
Edit Download
22.04 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
15.37 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
3.10 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
7.13 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
430 B lrw-r--r-- 2026-08-21 10:05:50
Edit Download
9.50 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
7.64 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
8.47 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
9.94 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
9.22 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
1.08 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
6.18 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
967 B lrw-r--r-- 2026-08-21 10:05:50
Edit Download
1.19 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
14.61 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
2.49 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
7.04 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
3.27 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
3.66 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
2.11 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
1.84 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
14.57 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
9.20 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
18.83 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
2.49 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
955 B lrw-r--r-- 2026-08-21 10:05:50
Edit Download
609 B lrw-r--r-- 2026-08-21 10:05:50
Edit Download
3.83 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
9.66 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
3.74 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
8.79 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
3.30 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
3.62 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
5.07 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
2.59 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
1.98 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
2.60 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
3.33 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
2.50 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
1.73 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
3.18 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
470 B lrw-r--r-- 2026-08-21 10:05:50
Edit Download
11.59 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
2.66 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
4.93 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
3.43 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
23.54 KB lrw-r--r-- 2026-08-21 10:05:50
Edit Download
If ZipArchive is unavailable, a .tar will be created (no compression).
© 2026 0xNothings — Secure File Manager. All rights reserved. Built with ❤️ & Tailwind x Dark UI