Completed
Push — add/tracks ( a0fac3...1c285b )
by
unknown
09:13
created

Jetpack_Recipes::recipe_shortcode_html()   F

Complexity

Conditions 13
Paths 272

Size

Total Lines 83
Code Lines 42

Duplication

Lines 21
Ratio 25.3 %

Importance

Changes 0
Metric Value
cc 13
eloc 42
nc 272
nop 2
dl 21
loc 83
rs 3.7737
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Embed recipe 'cards' in post, with basic styling and print functionality
5
 *
6
 * To Do
7
 * - defaults settings
8
 * - basic styles/themecolor styles
9
 * - validation/sanitization
10
 * - print styles
11
 */
12
class Jetpack_Recipes {
13
14
	private $scripts_and_style_included = false;
15
16
	function __construct() {
17
		add_action( 'init', array( $this, 'action_init' ) );
18
19
		// Add itemprop to allowed tags for wp_kses_post, so we can use it for better Schema compliance.
20
		global $allowedposttags;
21
		$tags = array( 'li', 'ol', 'img' );
22
		foreach ( $tags as $tag ) {
23
			if ( ! is_array( $allowedposttags[ $tag ] ) ) {
24
				$allowedposttags[ $tag ] = array();
25
			}
26
			$allowedposttags[ $tag ]['itemprop'] = array();
27
		}
28
	}
29
30
	function action_init() {
31
		// Enqueue styles if [recipe] exists
32
		add_action( 'wp_head', array( $this, 'add_scripts' ), 1 );
33
34
		// Render [recipe], along with other shortcodes that can be nested within.
35
		add_shortcode( 'recipe', array( $this, 'recipe_shortcode' ) );
36
		add_shortcode( 'recipe-notes', array( $this, 'recipe_notes_shortcode' ) );
37
		add_shortcode( 'recipe-ingredients', array( $this, 'recipe_ingredients_shortcode' ) );
38
		add_shortcode( 'recipe-directions', array( $this, 'recipe_directions_shortcode' ) );
39
	}
40
41
	/**
42
	 * Enqueue scripts and styles
43
	 */
44
	function add_scripts() {
45
		if ( empty( $GLOBALS['posts'] ) || ! is_array( $GLOBALS['posts'] ) ) {
46
			return;
47
		}
48
49 View Code Duplication
		foreach ( $GLOBALS['posts'] as $p ) {
50
			if ( has_shortcode( $p->post_content, 'recipe' ) ) {
51
				$this->scripts_and_style_included = true;
52
				break;
53
			}
54
		}
55
56
		if ( ! $this->scripts_and_style_included ) {
57
			return;
58
		}
59
60
		if ( is_rtl() ) {
61
			wp_enqueue_style( 'jetpack-recipes-style', plugins_url( '/css/rtl/recipes-rtl.css', __FILE__ ), array(), '20130919' );
62
		} else {
63
			wp_enqueue_style( 'jetpack-recipes-style', plugins_url( '/css/recipes.css', __FILE__ ), array(), '20130919' );
64
		}
65
66
		wp_add_inline_style( 'jetpack-recipes-style', self::themecolor_styles() ); // add $themecolors-defined styles
67
68
		wp_enqueue_script( 'jetpack-recipes-printthis', plugins_url( '/js/recipes-printthis.js', __FILE__ ), array( 'jquery' ), '20131230' );
69
		wp_enqueue_script( 'jetpack-recipes-js',        plugins_url( '/js/recipes.js', __FILE__ ), array( 'jquery', 'jetpack-recipes-printthis' ), '20131230' );
70
71
		$title_var     = wp_title( '|', false, 'right' );
72
		$print_css_var = plugins_url( '/css/recipes-print.css', __FILE__ );
73
74
		wp_localize_script( 'jetpack-recipes-js', 'jetpack_recipes_vars', array( 'pageTitle' => $title_var, 'loadCSS' => $print_css_var ) );
75
	}
76
77
	/**
78
	 * Our [recipe] shortcode.
79
	 * Prints recipe data styled to look good on *any* theme.
80
	 *
81
	 * @return string HTML for recipe shortcode.
82
	 */
83
	static function recipe_shortcode( $atts, $content = '' ) {
84
		$atts = shortcode_atts(
85
			array(
86
				'title'       => '', //string
87
				'servings'    => '', //intval
88
				'time'        => '', //string
89
				'difficulty'  => '', //string
90
				'print'       => '', //string
91
				'image'       => '', //string
92
				'description' => '', //string
93
			), $atts, 'recipe'
94
		);
95
96
		return self::recipe_shortcode_html( $atts, $content );
97
	}
98
99
	/**
100
	 * The recipe output
101
	 *
102
	 * @return string HTML output
103
	 */
104
	static function recipe_shortcode_html( $atts, $content = '' ) {
105
		// Add itemprop to allowed tags for wp_kses_post, so we can use it for better Schema compliance.
106
		global $allowedtags;
107
		$allowedtags['li'] = array( 'itemprop' => array () );
108
109
		$html = '<div class="hrecipe jetpack-recipe" itemscope itemtype="http://schema.org/Recipe">';
110
111
		// Print the recipe title if exists
112
		if ( '' !== $atts['title'] ) {
113
			$html .= '<h3 class="jetpack-recipe-title" itemprop="name">' . esc_html( $atts['title'] ) . '</h3>';
114
		}
115
116
		// Print the recipe meta if exists
117
		if ( '' !== $atts['servings'] || '' != $atts['time'] || '' != $atts['difficulty'] || '' != $atts['print'] ) {
118
			$html .= '<ul class="jetpack-recipe-meta">';
119
120 View Code Duplication
			if ( '' !== $atts['servings'] ) {
121
				$html .= sprintf(
122
					'<li class="jetpack-recipe-servings" itemprop="recipeYield"><strong>%1$s: </strong>%2$s</li>',
123
					esc_html_x( 'Servings', 'recipe', 'jetpack' ),
124
					esc_html( $atts['servings'] )
125
				);
126
			}
127
128 View Code Duplication
			if ( '' !== $atts['time'] ) {
129
				$html .= sprintf(
130
					'<li class="jetpack-recipe-time" itemprop="totalTime"><strong>%1$s: </strong>%2$s</li>',
131
					esc_html_x( 'Time', 'recipe', 'jetpack' ),
132
					esc_html( $atts['time'] )
133
				);
134
			}
135
136 View Code Duplication
			if ( '' !== $atts['difficulty'] ) {
137
				$html .= sprintf(
138
					'<li class="jetpack-recipe-difficulty"><strong>%1$s: </strong>%2$s</li>',
139
					esc_html_x( 'Difficulty', 'recipe', 'jetpack' ),
140
					esc_html( $atts['difficulty'] )
141
				);
142
			}
143
144
			if ( 'false' !== $atts['print'] ) {
145
				$html .= sprintf(
146
					'<li class="jetpack-recipe-print"><a href="#">%1$s</a></li>',
147
					esc_html_x( 'Print', 'recipe', 'jetpack' )
148
				);
149
			}
150
151
			$html .= '</ul>';
152
		}
153
154
		// Output the image, if we have one.
155
		if ( '' !== $atts['image'] ) {
156
			$html .= sprintf(
157
				'<img class="jetpack-recipe-image" itemprop="thumbnailUrl" src="%1$s" />',
158
				esc_url( $atts['image'] )
159
			);
160
		}
161
162
		// Output the description, if we have one.
163
		if ( '' !== $atts['description'] ) {
164
			$html .= sprintf(
165
				'<p class="jetpack-recipe-description">%1$s</p>',
166
				esc_html( $atts['description'] )
167
			);
168
		}
169
170
		// Print content between codes
171
		$html .= '<div class="jetpack-recipe-content">' . do_shortcode( $content ) . '</div>';
172
173
		// Close it up
174
		$html .= '</div>';
175
176
		// If there is a recipe within a recipe, remove the shortcode
177
		if ( has_shortcode( $html, 'recipe' ) ) {
178
			remove_shortcode( 'recipe' );
179
		}
180
181
		// Sanitize html
182
		$html = wp_kses_post( $html );
183
184
		// Return the HTML block
185
		return $html;
186
	}
187
188
	/**
189
	 * Our [recipe-notes] shortcode.
190
	 * Outputs notes, styled in a div.
191
	 *
192
	 * @return string HTML for recipe notes shortcode.
193
	 */
194 View Code Duplication
	static function recipe_notes_shortcode( $atts, $content = '' ) {
195
		$atts = shortcode_atts( array(
196
			'title' => '', //string
197
		), $atts, 'recipe-notes' );
198
199
		$html ='';
200
201
		// Print a title if one exists.
202
		if ( '' !== $atts['title'] ) {
203
			$html .= '<h4 class="jetpack-recipe-notes-title">' . esc_html( $atts['title'] ) . '</h4>';
204
		}
205
206
		$html .= '<div class="jetpack-recipe-notes">';
207
208
		// Format content using list functionality, if desired.
209
		$html .= self::output_list_content( $content, 'notes' );
210
211
		$html .= '</div>';
212
213
		// Sanitize html.
214
		$html = wp_kses_post( $html );
215
216
		// Return the HTML block.
217
		return $html;
218
	}
219
220
	/**
221
	 * Our [recipe-ingredients] shortcode.
222
	 * Outputs notes, styled in a div.
223
	 *
224
	 * @return string HTML for recipe ingredients shortcode.
225
	 */
226 View Code Duplication
	static function recipe_ingredients_shortcode( $atts, $content = '' ) {
227
		$atts = shortcode_atts( array(
228
			'title' => esc_html_x( 'Ingredients', 'recipe', 'jetpack' ), //string
229
		), $atts, 'recipe-ingredients' );
230
231
		$html = '<div class="jetpack-recipe-ingredients">';
232
233
		// Print a title unless the user has opted to exclude it.
234
		if ( 'false' !== $atts['title'] ) {
235
			$html .= '<h4 class="jetpack-recipe-ingredients-title">' . esc_html( $atts['title'] ) . '</h4>';
236
		}
237
238
		// Format content using list functionality.
239
		$html .= self::output_list_content( $content, 'ingredients' );
240
241
		$html .= '</div>';
242
243
		// Sanitize html.
244
		$html = wp_kses_post( $html );
245
246
		// Return the HTML block.
247
		return $html;
248
	}
249
250
	/**
251
	 * Reusable function to check for shortened formatting.
252
	 * Basically, users can create lists with the following shorthand:
253
	 * - item one
254
	 * - item two
255
	 * - item three
256
	 * And we'll magically convert it to a list. This has the added benefit
257
	 * of including itemprops for the recipe schema.
258
	 *
259
	 * @return string content formatted as a list item
260
	 */
261
	static function output_list_content( $content, $type ) {
262
		$html ='';
263
264
		switch ( $type ) {
265
			case 'directions' :
266
				$list_item_replacement = '<li class="jetpack-recipe-directions">${1}</li>';
267
				$itemprop              = ' itemprop="recipeInstructions"';
268
				$listtype              = 'ol';
0 ignored issues
show
Unused Code introduced by
$listtype is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
269
				break;
270
			case 'ingredients' :
271
				$list_item_replacement = '<li class="jetpack-recipe-ingredient">${1}</li>';
272
				$itemprop              = ' itemprop="recipeIngredient"';
273
				$listtype              = 'ul';
0 ignored issues
show
Unused Code introduced by
$listtype is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
274
				break;
275
			default:
276
				$list_item_replacement = '<li class="jetpack-recipe-notes">${1}</li>';
277
				$itemprop              = '';
278
				$listtype              = 'ul';
0 ignored issues
show
Unused Code introduced by
$listtype is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
279
		}
280
281
		// Check to see if the user is trying to use shortened formatting.
282
		if (
283
			strpos( $content, '&#8211;' ) !== false ||
284
			strpos( $content, '&#8212;' ) !== false ||
285
			strpos( $content, '-' )       !== false ||
286
			strpos( $content, '*' )       !== false ||
287
			strpos( $content, '#' )       !== false ||
288
			strpos( $content, '–' )   !== false || // ndash
289
			strpos( $content, '—' )   !== false || // mdash
290
			preg_match( '/\d+\.\s/', $content )
291
		) {
292
			// Remove breaks and extra whitespace
293
			$content = str_replace( "<br />\n", "\n", $content );
294
			$content = trim( $content );
295
296
			$ul_pattern = '/(?:^|\n|\<p\>)+(?:[\-–—]+|\&#8211;|\&#8212;|\*)+\h+(.*)/mi';
297
			$ol_pattern = '/(?:^|\n|\<p\>)+(?:\d+\.|#+)+\h+(.*)/mi';
298
299
			preg_match_all( $ul_pattern, $content, $ul_matches );
300
			preg_match_all( $ol_pattern, $content, $ol_matches );
301
302
			if ( 0 !== count( $ul_matches[0] ) || 0 !== count( $ol_matches[0] ) ) {
303
304
				if ( 0 !== count( $ol_matches[0] ) ) {
305
					$listtype = 'ol';
306
					$list_item_pattern = $ol_pattern;
307
				} else {
308
					$listtype = 'ul';
309
					$list_item_pattern = $ul_pattern;
310
				}
311
				$html .= '<' . $listtype . $itemprop . '>';
312
				$html .= preg_replace( $list_item_pattern, $list_item_replacement, $content );
313
				$html .= '</' . $listtype . '>';
314
315
				// Strip out any empty <p> tags and stray </p> tags, because those are just silly.
316
				$empty_p_pattern = '/(<p>)*\s*<\/p>/mi';
317
				$html = preg_replace( $empty_p_pattern, '', $html );
318
			} else {
319
				$html .= do_shortcode( $content );
320
			}
321
		} else {
322
			$html .= do_shortcode( $content );
323
		}
324
325
		// Return our formatted content.
326
		return $html;
327
	}
328
329
	/**
330
	 * Our [recipe-directions] shortcode.
331
	 * Outputs notes, styled in a div.
332
	 *
333
	 * @return string HTML for recipe notes shortcode.
334
	 */
335 View Code Duplication
	static function recipe_directions_shortcode( $atts, $content = '' ) {
336
		$atts = shortcode_atts( array(
337
				'title' => esc_html_x( 'Directions', 'recipe', 'jetpack' ), //string
338
		), $atts, 'recipe-directions' );
339
340
		$html = '<div class="jetpack-recipe-directions">';
341
342
		// Print a title unless the user has specified to exclude it.
343
		if ( 'false' !== $atts['title'] ) {
344
			$html .= '<h4 class="jetpack-recipe-directions-title">' . esc_html( $atts['title'] ) . '</h4>';
345
		}
346
347
		// Format content using list functionality.
348
		$html .= self::output_list_content( $content, 'directions' );
349
350
		$html .= '</div>';
351
352
		// Sanitize html.
353
		$html = wp_kses_post( $html );
354
355
		// Return the HTML block.
356
		return $html;
357
	}
358
359
	/**
360
	 * Use $themecolors array to style the Recipes shortcode
361
	 *
362
	 * @print style block
363
	 * @return string $style
364
	 */
365
	function themecolor_styles() {
366
		global $themecolors;
367
		$style = '';
368
369
		if ( isset( $themecolors ) ) {
370
			$style .= '.jetpack-recipe { border-color: #' . esc_attr( $themecolors['border'] ) . '; }';
371
			$style .= '.jetpack-recipe-title { border-bottom-color: #' . esc_attr( $themecolors['link'] ) . '; }';
372
		}
373
374
		return $style;
375
	}
376
377
}
378
379
new Jetpack_Recipes();
380