PluginProbe
Cooked – Recipe Management / trunk
Cooked – Recipe Management vtrunk
1.16.0 1.15.0 trunk 1.10.0 1.11.0 1.11.1 1.11.2 1.11.3 1.11.4 1.12.0 1.13.0 1.14.0 1.7.10 1.7.11 1.7.12 1.7.13 1.7.15.1 1.7.15.3 1.7.15.4 1.8.0 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 All 36 releases
cooked / includes / class.cooked-recipes.php

class.cooked-recipes.php in Cooked – Recipe Management trunk, at includes/class.cooked-recipes.php

1,635 lines 81.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Cooked Recipe-Specific Functions
4 *
5 * @package Cooked
6 * @subpackage Recipe-Specific Functions
7 * @since 1.0.0
8 */
9
10 // Exit if accessed directly
11 if ( ! defined( 'ABSPATH' ) ) exit;
12
13 /**
14 * Cooked_Recipe_Meta Class
15 *
16 * This class handles the Cooked Recipe Meta Box creation.
17 *
18 * @since 1.0.0
19 */
20 class Cooked_Recipes {
21
22 public function __construct() {
23 add_filter( 'cooked_recipe_content_filter', [&$this, 'vendor_checks'], 1, 1 );
24 add_filter( 'the_content', [&$this, 'recipe_template'], 10 );
25
26 add_filter( 'parse_query', [&$this, 'custom_taxonomy_in_query'], 10 );
27
28 add_action( 'template_redirect', [&$this, 'print_recipe_template'], 10 );
29 add_action( 'cooked_check_recipe_query', [&$this, 'check_recipe_query'], 10 );
30 add_action( 'pre_get_posts', [&$this, 'cooked_pre_get_posts'], 10, 1 );
31 add_action( 'restrict_manage_posts', [&$this, 'filter_recipes_by_taxonomy'], 10 );
32
33 add_filter('get_canonical_url', [&$this, 'modify_browse_page_canonical_url'], 20, 2);
34 add_filter( 'post_thumbnail_id', [ __CLASS__, 'filter_default_recipe_thumbnail' ], 10, 2 );
35 }
36
37 public static function filter_default_recipe_thumbnail( $thumbnail_id, $post ) {
38 if ( $thumbnail_id ) {
39 return $thumbnail_id;
40 }
41
42 if ( is_admin() && ! wp_doing_ajax() ) {
43 return $thumbnail_id;
44 }
45
46 $post = get_post( $post );
47
48 if ( ! $post || $post->post_type !== 'cp_recipe' ) {
49 return $thumbnail_id;
50 }
51
52 global $_cooked_settings;
53
54 if ( empty( $_cooked_settings ) ) {
55 $_cooked_settings = Cooked_Settings::get();
56 }
57
58 $default_image_id = isset( $_cooked_settings['default_recipe_image'] ) ? absint( $_cooked_settings['default_recipe_image'] ) : 0;
59
60 if ( $default_image_id && wp_attachment_is_image( $default_image_id ) ) {
61 return $default_image_id;
62 }
63
64 return $thumbnail_id;
65 }
66
67 public static function get( $args = false, $single = false, $ids_only = false, $limit = false, $ids_and_titles_only = false, $post_status = 'publish' ) {
68 $recipes = [];
69 $counter = 0;
70
71 // Get by Recipe ID
72 if ( $args && !is_array($args) ):
73
74 $recipe_id = $args;
75 $args = [
76 'post_type' => 'cp_recipe',
77 'post__in' => [$recipe_id],
78 'post_status' => $post_status
79 ];
80
81 // Default Query
82 elseif ( !$args || !is_array($args) ):
83
84 $args = [
85 'post_type' => 'cp_recipe',
86 'posts_per_page' => -1,
87 'post_status' => $post_status,
88 'orderby' => 'name',
89 'order' => 'ASC'
90 ];
91
92 if ( $ids_only || $ids_and_titles_only ):
93 $args['fields'] = 'ids';
94 endif;
95
96 if ( $limit ):
97 $args['posts_per_page'] = $limit;
98 endif;
99
100 // Search Query
101 elseif ( $args && isset($args['s']) && isset($args['meta_query']) ):
102
103 $meta_query = $args['meta_query'];
104 $recipe_ids = [];
105
106 $pre_search_args = $args;
107 $pre_search_args['posts_per_page'] = -1;
108 $pre_search_args['fields'] = 'ids';
109
110 unset($pre_search_args['meta_query']);
111
112 $recipes_pre_search = new WP_Query($pre_search_args);
113 if ( $recipes_pre_search->have_posts() ):
114 $recipe_ids = $recipes_pre_search->posts;
115 endif;
116
117 $pre_search_args['meta_query'] = $meta_query;
118 unset($pre_search_args['s']);
119
120 $recipes_pre_search = new WP_Query($pre_search_args);
121 if ( $recipes_pre_search->have_posts() ):
122 $rposts = $recipes_pre_search->posts;
123 $recipe_ids = !empty($recipe_ids) ? array_merge( $recipe_ids, $rposts ) : $rposts;
124 endif;
125
126 $recipe_ids = array_unique( $recipe_ids );
127
128 if ( !empty($recipe_ids) ):
129 unset($args['s']);
130 unset($args['meta_query']);
131 $args['post__in'] = $recipe_ids;
132 endif;
133
134 endif;
135
136 $recipes_results = new WP_Query($args);
137
138 if ( $recipes_results->have_posts() ) {
139 if ( $ids_only ) {
140 return $recipes_results->posts;
141 } elseif ( $ids_and_titles_only ) {
142 while ( $recipes_results->have_posts() ) {
143 $recipes_results->the_post();
144 $recipes[$counter]['id'] = $recipes_results->post->ID;
145 $recipes[$counter]['title'] = $recipes_results->post->post_title;
146
147 $counter++;
148 }
149 } else {
150 while ( $recipes_results->have_posts() ) {
151 $recipes_results->the_post();
152 $recipes[$counter]['id'] = $recipes_results->post->ID;
153 $recipes[$counter]['title'] = $recipes_results->post->post_title;
154 $recipe_settings = self::get_settings($recipes_results->post->ID);
155
156 foreach ($recipe_settings as $key => $setting) {
157 $recipes[$counter][$key] = $setting;
158 }
159
160 $counter++;
161 }
162 }
163 } else {
164 wp_reset_postdata();
165 return;
166 }
167
168 $recipes['raw'] = $recipes_results;
169
170 if ( $single && isset( $recipes[0] ) ):
171 $recipes = $recipes[0];
172 endif;
173
174 wp_reset_postdata();
175
176 return $recipes;
177 }
178
179 public static function get_settings( $post_id, $bc = true ) {
180 if ( !$post_id ) return;
181
182 $recipe_settings = get_post_meta( $post_id, '_recipe_settings', true );
183
184 if ( !is_array( $recipe_settings ) || empty($recipe_settings) ) {
185 $recipe_settings = [];
186 }
187
188 $recipe_settings['title'] = get_the_title( $post_id );
189
190 $recipe_post = get_post($post_id);
191 $wp_excerpt = $recipe_post->post_excerpt;
192
193 // Check for excerpt/content
194 // if ( isset($recipe_settings['excerpt']) && !$recipe_settings['excerpt'] && !$wp_excerpt || !isset($recipe_settings['excerpt']) ) {
195 // wp_update_post(['ID' => $post_id, 'post_excerpt' => $recipe_settings['title']] );
196 // }
197
198 // Check for nutrition data
199 if ( !isset($recipe_settings['nutrition']) ):
200 $recipe_settings['nutrition'] = [];
201 $recipe_settings['nutrition']['servings'] = 1;
202 endif;
203
204 // Backwards Compatibility with Cooked 2.x
205 if ( !isset($recipe_settings['cooked_version']) && $bc ):
206 $c2_recipe_settings = self::get_c2_recipe_meta( $post_id );
207 $recipe_settings = self::sync_c2_recipe_settings( $c2_recipe_settings, $post_id );
208 endif;
209
210 // Get the author information
211 $recipe_settings['author'] = Cooked_Users::get( $recipe_post->post_author, true );
212
213 // Include the Post ID
214 $recipe_settings['id'] = $post_id;
215
216 $recipe_settings = apply_filters( 'cooked_single_recipe_settings', $recipe_settings, $post_id );
217
218 return $recipe_settings;
219 }
220
221 public function check_recipe_query() {
222 global $_cooked_settings, $recipe_query;
223
224 if ( !isset($recipe_query['cp_recipe_category']) ):
225 $recipe_query['cp_recipe_category'] = ( isset($_GET['cp_recipe_category']) && $_GET['cp_recipe_category'] ? intval($_GET['cp_recipe_category']) : ( isset($_cooked_settings['browse_default_cp_recipe_category']) && $_cooked_settings['browse_default_cp_recipe_category'] ? $_cooked_settings['browse_default_cp_recipe_category'] : false ) );
226 endif;
227 }
228
229 public static function cooked_pre_get_posts( $q ) {
230 if ( $title = $q->get( '_cooked_title' ) ) {
231 add_filter( 'get_meta_sql', function( $sql ) use ( $title ) {
232 global $wpdb, $cooked_modified_where;
233
234 if ( $cooked_modified_where ) return $sql;
235 $cooked_modified_where = 1;
236
237 // Modified WHERE
238 $sql['where'] = sprintf(
239 " AND ( %s OR %s ) ",
240 apply_filters( 'cooked_query_where_filter', $wpdb->prepare( "{$wpdb->posts}.post_title like '%%%s%%'", $wpdb->esc_like( $title ) ) ),
241 mb_substr( $sql['where'], 5, mb_strlen( $sql['where'] ) )
242 );
243
244 return $sql;
245 });
246 }
247 }
248
249 public static function recipe_list( $orderby = 'date', $show = 5, $recipes = false, $width = false, $hide_image = false, $hide_author = false ) {
250 global $_cooked_settings;
251
252 $width = !$width ? '100%' : $width;
253 $pixel_width = stristr( $width, 'px', true );
254 $percent_width = stristr( $width, '%', true );
255 $width = $pixel_width ? $pixel_width . 'px' : ( $percent_width ? $percent_width . '%' : ( is_numeric( $width ) ? $width . 'px' : '100%' ) );
256
257 $args = [
258 'post_type' => 'cp_recipe',
259 'posts_per_page' => $show,
260 'post_status' => 'publish',
261 'orderby' => $orderby,
262 'order' => 'DESC'
263 ];
264
265 if ( !empty($recipes) ) {
266 $args['posts_per_page'] = -1;
267 $args['orderby'] = 'post__in';
268 $args['order'] = 'ASC';
269 $args['post__in'] = $recipes;
270 }
271
272 $recipes = Cooked_Recipes::get( $args );
273
274 if ( isset($recipes['raw']) ): unset( $recipes['raw'] ); endif;
275 $recipe_list = [];
276
277 if ( !empty($recipes) ):
278
279 echo '<div class="cooked-shortcode-recipe-list">';
280
281 foreach ( $recipes as $key => $recipe ):
282
283 $rid = $recipe['id'];
284 $has_image_class = has_post_thumbnail($rid) && !$hide_image ? ' cooked-srl-has-image' : '';
285
286 echo '<div class="cooked-srl-single' . esc_attr( $has_image_class ) . '" style="width:100%; max-width:' . esc_attr( $width ) . '">';
287
288 echo has_post_thumbnail($rid) && !$hide_image ? '<div class="cooked-srl-image"><a href="' . esc_url( get_permalink($rid) ) . '">' . get_the_post_thumbnail( $rid, 'thumbnail' ) . '</a></div>' : '';
289
290 echo '<div class="cooked-srl-content">';
291
292 echo '<div class="cooked-srl-title"><a href="' . esc_url( get_permalink($rid) ) . '">' . esc_html( $recipe['title'] ) . '</a></div>';
293
294 if ( in_array('author', $_cooked_settings['recipe_info_display_options']) && !$hide_author ):
295 echo '<div class="cooked-srl-author">';
296 $author = $recipe['author'];
297 /* translators: stating the recipe author with a "By" in front of it. (ex: "By John Smith") */
298 echo sprintf( __( 'By %s', 'cooked' ), '<strong>' . wp_kses_post( $author['name'] ) . '</strong>' );
299 echo '</div>';
300 endif;
301
302 echo '</div>';
303
304 echo '</div>';
305 endforeach;
306
307 echo '</div>';
308
309 endif;
310
311 }
312
313 public static function card( $rid, $width = false, $hide_image = false, $hide_title = false, $hide_excerpt = false, $hide_author = false, $style = false ) {
314 global $_cooked_settings;
315
316 $recipe = self::get( $rid, true );
317 $style_class = $style ? ' cooked-recipe-card-' . esc_attr($style) : '';
318
319 $width = !$width ? '100%' : $width;
320 $pixel_width = stristr( $width, 'px', true );
321 $percent_width = stristr( $width, '%', true );
322 $width = $pixel_width ? $pixel_width . 'px' : ( $percent_width ? $percent_width . '%' : ( is_numeric( $width ) ? $width . 'px' : '100%' ) );
323
324 ob_start();
325
326 echo '<a href="' . esc_url( get_permalink($rid) ) . '" class="cooked-recipe-card' . esc_attr( $style_class ) . '" style="width:100%; max-width:' . esc_attr( $width ) . '">';
327
328 do_action( 'cooked_recipe_grid_before_recipe', $recipe );
329
330 do_action( 'cooked_recipe_grid_before_image', $recipe );
331
332 echo has_post_thumbnail($rid) && !$hide_image ? '<span class="cooked-recipe-card-image" style="background-image:url(' . get_the_post_thumbnail_url( $recipe['id'], 'cooked-medium' ) . ');"></span>' : '';
333
334 //do_action( 'cooked_recipe_grid_after_image', $recipe );
335
336 echo '<span class="cooked-recipe-card-content">';
337
338 do_action( 'cooked_recipe_grid_before_name', $recipe );
339
340 echo !$hide_title ? '<span class="cooked-recipe-card-title">' . esc_html( $recipe['title'] ) . '</span>' : '';
341
342 do_action( 'cooked_recipe_grid_after_name', $recipe );
343
344 if ( $hide_excerpt && !$hide_title && !$hide_author ): echo '<span class="cooked-recipe-card-sep"></span>'; endif;
345
346 do_action( 'cooked_recipe_grid_before_author', $recipe );
347
348 if ( in_array('author',$_cooked_settings['recipe_info_display_options']) && !$hide_author ):
349 echo '<span class="cooked-recipe-card-author">';
350 $author = $recipe['author'];
351 /* translators: stating the recipe author with a "By" in front of it. (ex: "By John Smith") */
352 echo sprintf( __( 'By %s', 'cooked' ), '<strong>' . $author['name'] . '</strong>' );
353 echo '</span>';
354 endif;
355
356 do_action( 'cooked_recipe_grid_after_author', $recipe );
357
358 if ( !$hide_excerpt && !$hide_title || !$hide_excerpt && !$hide_author ): echo '<span class="cooked-recipe-card-sep"></span>'; endif;
359
360 do_action( 'cooked_recipe_grid_before_excerpt', $recipe );
361
362 echo !$hide_excerpt ? '<span class="cooked-recipe-card-excerpt">' . wp_kses_post( $recipe['excerpt'] ) . '</span>' : '';
363
364 do_action( 'cooked_recipe_grid_after_excerpt', $recipe );
365
366 echo '</span>';
367
368 do_action( 'cooked_recipe_grid_after_recipe', $recipe );
369
370 echo '</a>';
371
372 return ob_get_clean();
373 }
374
375 public function print_recipe_template() {
376 if ( is_singular('cp_recipe') && isset($_GET['print']) ):
377 load_template( COOKED_DIR . 'templates/front/recipe-print.php', false);
378 exit;
379 endif;
380 }
381
382 public static function print_logo() {
383 global $_cooked_settings;
384
385 $print_view_options = isset( $_cooked_settings['print_view_display_options'] ) && is_array( $_cooked_settings['print_view_display_options'] )
386 ? $_cooked_settings['print_view_display_options']
387 : [];
388
389 if ( ! in_array( 'site_logo', $print_view_options, true ) ) {
390 return;
391 }
392
393 echo '<div id="cooked-print-logo">';
394
395 $logo_id = get_theme_mod( 'custom_logo' );
396 if ( $logo_id ) {
397 echo wp_get_attachment_image(
398 $logo_id,
399 'full',
400 false,
401 [
402 'alt' => get_bloginfo( 'name' ),
403 'class' => 'cooked-print-logo-image',
404 ]
405 );
406 } else {
407 echo '<span class="cooked-print-logo-text">' . esc_html( get_bloginfo( 'name' ) ) . '</span>';
408 }
409
410 echo '</div>';
411 }
412
413 public static function vendor_checks( $content ) {
414 global $wp_query, $post;
415
416 // WooCommerce Memberships
417 if ( function_exists('wc_memberships_user_can') && function_exists('wc_memberships_is_post_content_restricted') && function_exists('wc_memberships_user_can') ):
418
419 if ( !is_user_logged_in() && wc_memberships_is_post_content_restricted() ):
420 return WC_Memberships_User_Messages::get_message_html( 'content_restricted', ['post' => $post] );
421 elseif ( is_user_logged_in() ):
422 $_user = wp_get_current_user();
423 if ( !wc_memberships_user_can( $_user->ID, 'view', ['cp_recipe' => $post->ID] ) ):
424 return WC_Memberships_User_Messages::get_message_html( 'content_restricted', ['post' => $post] );
425 endif;
426 endif;
427
428 endif;
429
430 return $content;
431 }
432
433 public function filter_recipes_by_taxonomy() {
434 global $typenow, $cooked_taxonomies_shown;
435 $taxonomies = apply_filters( 'cooked_active_taxonomies', ['cp_recipe_category'] );
436 if ( $typenow == 'cp_recipe' ):
437 foreach ( $taxonomies as $taxonomy ):
438 if ( is_array($cooked_taxonomies_shown) && !in_array( $taxonomy, $cooked_taxonomies_shown ) || !is_array($cooked_taxonomies_shown) ):
439 $cooked_taxonomies_shown[] = $taxonomy;
440 $selected = isset($_GET[$taxonomy]) ? sanitize_title($_GET[$taxonomy]) : '';
441 $info_taxonomy = get_taxonomy($taxonomy);
442 $taxonomy_label = $info_taxonomy->label;
443
444 /* translators: For showing "All" of a taxonomy (ex: "All Burgers") */
445 $all_string = sprintf( __( "All %s", "cooked" ), $taxonomy_label );
446
447 wp_dropdown_categories([
448 'show_option_all' => $all_string,
449 'taxonomy' => $taxonomy,
450 'name' => $taxonomy,
451 'orderby' => 'name',
452 'selected' => $selected,
453 'show_count' => true,
454 'hide_empty' => true,
455 ]);
456 endif;
457 endforeach;
458 endif;
459 }
460
461 public function custom_taxonomy_in_query($query) {
462 global $pagenow;
463 $taxonomies = apply_filters( 'cooked_active_taxonomies', ['cp_recipe_category'] );
464 $q_vars = &$query->query_vars;
465
466 foreach ( $taxonomies as $taxonomy ):
467 if ( $pagenow == 'edit.php' && isset($q_vars['post_type']) && $q_vars['post_type'] == 'cp_recipe' && isset($q_vars[$taxonomy]) && is_numeric($q_vars[$taxonomy]) && $q_vars[$taxonomy] != 0 ):
468 $term = get_term_by('id', $q_vars[$taxonomy], $taxonomy);
469 $q_vars[$taxonomy] = $term->slug;
470 endif;
471 endforeach;
472 }
473
474 public static function list_view( $list_atts = false ) {
475 global $wp_query, $recipe_query, $atts, $_cooked_settings, $recipes, $recipe_args, $current_recipe_page;
476
477 // Get the attributes for this view
478 $atts = array_change_key_case( (array) $list_atts, CASE_LOWER );;
479 $ls_method = 'list_style_grid';
480 $ls_class = 'Cooked_Recipes';
481
482 // Change the recipe layout
483 if ( $atts['layout'] ) {
484 $recipe_list_style = apply_filters( 'cooked_recipe_list_style', [ 'grid' => 'Cooked_Recipes' ], $atts['layout'] );
485 $list_style = esc_html( key( $recipe_list_style ) );
486 $ls_method = 'list_style_' . $list_style;
487 $ls_class = current( $recipe_list_style );
488
489 $_cooked_settings['recipe_list_style'] = $list_style;
490 }
491
492 $recipe_query = $wp_query->query;
493 $tax_query = [];
494
495 do_action( 'cooked_check_recipe_query' );
496
497 if ( isset($_cooked_settings['recipe_taxonomies']) && !empty($_cooked_settings['recipe_taxonomies']) ):
498 foreach ( $_cooked_settings['recipe_taxonomies'] as $taxonomy ):
499 if ( isset($recipe_query[$taxonomy]) && $recipe_query[$taxonomy] ):
500 $field_type = is_numeric($recipe_query[$taxonomy]) ? 'id' : 'slug';
501 $tax_query['relation'] = 'AND';
502 $tax_query[] = [
503 'taxonomy' => $taxonomy,
504 'field' => $field_type,
505 'terms' => array_map('trim', explode(',', esc_html($recipe_query[$taxonomy])))
506 ];
507 endif;
508 endforeach;
509
510 if ( empty($tax_query) ):
511 foreach ( $_cooked_settings['recipe_taxonomies'] as $taxonomy ):
512 if ( isset( $_cooked_settings['browse_default_' . $taxonomy] ) && $_cooked_settings['browse_default_' . $taxonomy] ):
513 $tax_query['relation'] = 'AND';
514 $tax_query[] = [
515 'taxonomy' => $taxonomy,
516 'field' => 'id',
517 'terms' => [esc_html($_cooked_settings['browse_default_' . $taxonomy])]
518 ];
519 endif;
520 endforeach;
521 endif;
522 endif;
523
524 if ( empty($tax_query) ):
525
526 if ( $atts['category'] ):
527 $tax_query['relation'] = 'AND';
528 $tax_query[] = [
529 'taxonomy' => 'cp_recipe_category',
530 'field' => (is_numeric($atts['category']) ? 'id' : 'slug'),
531 'terms' => array_map('trim', explode(',', esc_html($atts['category'])))
532 ];
533 endif;
534
535 $tax_query = apply_filters( 'cooked_tax_query_filter', $tax_query, $atts );
536
537 endif;
538
539 $sorting_type = get_query_var('cooked_browse_sort_by', isset($_cooked_settings['browse_default_sort']) && $_cooked_settings['browse_default_sort'] ? $_cooked_settings['browse_default_sort'] : 'date_desc' );
540 $sorting_type = sanitize_key($sorting_type);
541 $sorting_types = explode('_', $sorting_type);
542
543 $text_search = get_query_var('cooked_search_s', '');
544 $text_search = urldecode($text_search);
545 $text_search = esc_html($text_search);
546 $recipes_per_page = ( $atts['show'] ? $atts['show'] : ( isset($_cooked_settings['recipes_per_page']) && $_cooked_settings['recipes_per_page'] ? $_cooked_settings['recipes_per_page'] : get_option( 'posts_per_page' ) ) );
547 $current_recipe_page = Cooked_Recipes::current_page();
548
549 $orderby = $atts['orderby'] ? esc_html( $atts['orderby'] ) : $sorting_types[0];
550 $meta_sort = false;
551
552 $post_status = 'publish';
553 if ( isset($atts['public_recipes']) && $atts['public_recipes'] == false ):
554 $post_status = ['publish', 'pending', 'draft'];
555 endif;
556
557 $recipe_args = [
558 'paged' => $current_recipe_page,
559 'post_type' => 'cp_recipe',
560 'posts_per_page' => $recipes_per_page,
561 'post_status' => $post_status,
562 'orderby' => $orderby,
563 'order' => ($atts['order'] ? esc_html($atts['order']) : $sorting_types[1])
564 ];
565
566 if ( isset($atts['exclude']) && $atts['exclude'] ):
567 $exclude = explode( ',', str_replace( ' ', '', $atts['exclude'] ) );
568 $recipe_args['post__not_in'] = $exclude;
569 endif;
570
571 if ( $text_search ):
572 // Replace [+] [,] [;] with spaces
573 $prep_text = str_replace(['+', ',', ';'], ' ', $text_search);
574
575 // Replace duplicate spaces
576 $prep_text = preg_replace('/\s+/', ' ', $prep_text);
577
578 // Explode into an array of search terms
579 $words = explode( ' ', $prep_text );
580
581 if ( !empty($words) ):
582 $meta_query['relation'] = 'AND';
583 foreach ( $words as $word ):
584 $meta_query[] = [
585 'key' => '_recipe_settings',
586 'value' => $word,
587 'compare' => 'LIKE'
588 ];
589 endforeach;
590 else:
591 $meta_query[] = [
592 'key' => '_recipe_settings',
593 'value' => $text_search,
594 'compare' => 'LIKE'
595 ];
596 endif;
597 $recipe_args['_cooked_title'] = $prep_text;
598 $recipe_args['s'] = $prep_text;
599 $recipe_args['meta_query'] = $meta_query;
600
601 endif;
602
603 if ( !empty($tax_query) ):
604 $recipe_args['tax_query'] = $tax_query;
605 endif;
606
607 if ( $atts['author'] && is_numeric( $atts['author'] ) ):
608 $recipe_args['author'] = $atts['author'];
609 elseif ( $atts['author'] ):
610 $recipe_args['author_name'] = $atts['author'];
611 endif;
612
613 if ( isset( $atts['include'] ) && !empty($atts['include']) ):
614 $recipe_args['post__in'] = $atts['include'];
615 endif;
616
617 $recipe_args = apply_filters( 'cooked_recipe_query_args', $recipe_args, $atts, $sorting_types );
618 if ( !isset($atts['public_recipes']) || isset($atts['public_recipes']) && $atts['public_recipes'] ):
619 $recipe_args = apply_filters( 'cooked_recipe_public_query_filters', $recipe_args );
620 endif;
621
622 wp_suspend_cache_addition(true);
623
624 ob_start();
625 $recipes = Cooked_Recipes::get( $recipe_args );
626 ( $theme_template_override = locate_template( 'recipe-list.php')) ? load_template( $theme_template_override, false ) : load_template( COOKED_DIR . 'templates/front/recipe-list.php', false );
627 wp_reset_postdata();
628 Cooked_Settings::reset();
629
630 wp_suspend_cache_addition(false);
631
632 return ob_get_clean();
633 }
634
635 public static function list_style_grid($atts = []) {
636 load_template(COOKED_DIR . 'templates/front/recipe-single.php', false, $atts);
637 }
638
639 public static function current_page() {
640 return get_query_var( 'paged' ) ? max( 1, get_query_var('paged') ) : ( get_query_var( 'page' ) ? max( 1, get_query_var('page') ) : 1 );
641 }
642
643 public static function pagination( $recipe_query, $recipe_args ) {
644 global $_cooked_settings, $current_recipe_page, $paged, $atts;
645
646 $paged = self::current_page();
647 $total_recipe_pages = $recipe_query->max_num_pages;
648 $pagination = '';
649
650 if ( $total_recipe_pages > 1) {
651 do_action( 'cooked_init_pagination', $recipe_args, $current_recipe_page, $total_recipe_pages, $atts );
652
653 $pagination_style = apply_filters( 'cooked_pagination_style', ['numbered_pagination' => 'Cooked_Recipes'] );
654 $p_method = key( $pagination_style );
655 $p_class = current( $pagination_style );
656
657 $pagination = $p_class::$p_method( $current_recipe_page, $total_recipe_pages );
658 }
659
660 return $pagination;
661 }
662
663 public static function numbered_pagination( $current_recipe_page, $total_recipe_pages ) {
664 if ( get_option('permalink_structure') ) {
665 $format = '?paged=%#%';
666 } else {
667 $format = 'page/%#%/';
668 }
669
670 $big = 999999999;
671 $base = $format =='?paged=%#%' ? $base = str_replace( $big, '%#%', get_pagenum_link( $big ) ) : $base = @add_query_arg('paged','%#%');
672
673 $recipe_pagination = apply_filters( 'cooked_pagination_args', [
674 'base' => $base,
675 'format' => $format,
676 'mid-size' => 1,
677 'current' => $current_recipe_page,
678 'total' => $total_recipe_pages,
679 'prev_next' => true,
680 'prev_text' => '<i class="cooked-icon cooked-icon-angle-left"></i>',
681 'next_text' => '<i class="cooked-icon cooked-icon-angle-right"></i>',
682 ]);
683 return '<div class="cooked-pagination-numbered cooked-clearfix">' . paginate_links( $recipe_pagination ) . '</div>';
684 }
685
686 public static function content_has_self_recipe_embed_shortcode( $content, $recipe_id ) {
687 if ( ! is_string( $content ) || ! $recipe_id ) {
688 return false;
689 }
690
691 $recipe_id = intval( $recipe_id );
692
693 if ( ! preg_match_all( '#\[cooked-recipe\b[^\]]*\bid\s*=\s*["\']?(\d+)#i', $content, $matches ) ) {
694 return false;
695 }
696
697 foreach ( $matches[1] as $embedded_id ) {
698 if ( intval( $embedded_id ) === $recipe_id ) {
699 return true;
700 }
701 }
702
703 return false;
704 }
705
706 public static function settings_have_self_recipe_embed_shortcode( $recipe_settings, $post_id ) {
707 if ( ! is_array( $recipe_settings ) || empty( $recipe_settings ) || ! $post_id ) {
708 return false;
709 }
710
711 $fields = [ 'content', 'notes', 'excerpt' ];
712 foreach ( $fields as $field ) {
713 if ( ! empty( $recipe_settings[ $field ] ) && self::content_has_self_recipe_embed_shortcode( $recipe_settings[ $field ], $post_id ) ) {
714 return true;
715 }
716 }
717
718 if ( ! empty( $recipe_settings['directions'] ) && is_array( $recipe_settings['directions'] ) ) {
719 foreach ( $recipe_settings['directions'] as $direction ) {
720 if ( ! empty( $direction['content'] ) && self::content_has_self_recipe_embed_shortcode( $direction['content'], $post_id ) ) {
721 return true;
722 }
723 }
724 }
725
726 return false;
727 }
728
729 public static function default_content() {
730 return apply_filters( 'cooked_default_content', '<p>[cooked-info left="author,taxonomies,difficulty" right="print,fullscreen"]</p><p>[cooked-excerpt]</p><p>[cooked-image]</p><p>[cooked-info left="servings" right="prep_time,cook_time,total_time"]</p><p>[cooked-info left="allergens"]</p><p>[cooked-ingredients]</p><p>[cooked-directions]</p><p>[cooked-notes show_header=true]</p><p>[cooked-gallery]</p>' );
731 }
732
733 public static function print_content() {
734 return apply_filters( 'cooked_print_content', '<p>[cooked-info include="servings,prep_time,cook_time,total_time"]</p><p>[cooked-excerpt]</p><p>[cooked-image]</p><p>[cooked-ingredients]</p><p>[cooked-directions]</p><p>[cooked-notes show_header=true]</p><p>[cooked-nutrition]</p>' );
735 }
736
737 public static function fsm_content() {
738 return apply_filters( 'cooked_fsm_content', '
739 <div class="cooked-fsm-ingredients cooked-fsm-content cooked-active" data-nosnippet aria-hidden="false">
740 <div class="cooked-panel"><h2>' . __('Ingredients', 'cooked') . '</h2>[cooked-ingredients]</div>
741 </div>
742 <div class="cooked-fsm-directions-wrap cooked-fsm-content" data-nosnippet aria-hidden="true">
743 <div class="cooked-fsm-directions cooked-fsm-content">
744 <div class="cooked-panel"><h2>' . __('Directions', 'cooked') . '</h2>[cooked-directions]</div>
745 </div>
746 <div class="cooked-fsm-notes cooked-fsm-content" data-nosnippet aria-hidden="true">
747 <div class="cooked-panel"><h2>' . __('Notes', 'cooked') . '</h2>[cooked-notes]</div>
748 </div>
749 </div>
750 ' );
751 }
752
753 /**
754 * Returns the fullscreen modal (FSM) markup for a recipe.
755 * Used by the recipe template and by the Elementor filter when appending FSM.
756 *
757 * @param int $recipe_id Recipe post ID.
758 * @param array $settings Recipe settings (from get_settings() or global $recipe_settings).
759 * @return string FSM HTML block.
760 */
761 public static function get_fsm_markup( $recipe_id, array $settings ) {
762 $recipe_id = intval( $recipe_id );
763 if ( ! $recipe_id || empty( $settings['title'] ) ) {
764 return '';
765 }
766 global $recipe_settings;
767 $recipe_settings = $settings;
768 $markup = '<div id="cooked-fsm-' . $recipe_id . '" class="cooked-fsm" data-recipe-id="' . $recipe_id . '">';
769 $markup .= do_shortcode( self::fsm_content() );
770 $markup .= '<div class="cooked-fsm-top">' . esc_html( $settings['title'] ) . '<a href="#" class="cooked-close-fsm"><i class="cooked-icon cooked-icon-close"></i></a></div>';
771 $markup .= '<div class="cooked-fsm-mobile-nav">';
772 $markup .= '<a href="#ingredients" data-nav-id="ingredients" class="cooked-fsm-nav-ingredients cooked-active">' . __( 'Ingredients', 'cooked' ) . '</a>';
773 $markup .= '<a href="#directions" data-nav-id="directions" class="cooked-fsm-nav-directions">' . __( 'Directions', 'cooked' ) . '</a>';
774 $markup .= '</div>';
775 $markup .= '</div>';
776 return $markup;
777 }
778
779 /**
780 * Checks whether the recipe content includes the fullscreen option in a [cooked-info] shortcode.
781 * Looks at left, right, and include attributes.
782 *
783 * @param int $recipe_id Recipe post ID.
784 * @param string $content Raw recipe layout content (shortcodes).
785 * @return bool True if fullscreen is present in at least one [cooked-info] shortcode.
786 */
787 public static function recipe_has_fullscreen( $recipe_id, $content ) {
788 $recipe_id = intval( $recipe_id );
789 if ( ! $recipe_id ) {
790 return false;
791 }
792 if ( empty( $content ) || strpos( $content, 'cooked-info' ) === false ) {
793 return false;
794 }
795 $regex = get_shortcode_regex( [ 'cooked-info' ] );
796 if ( ! preg_match_all( '/' . $regex . '/s', $content, $matches, PREG_SET_ORDER ) ) {
797 return false;
798 }
799 $check_values = function ( $attr_string ) {
800 if ( empty( $attr_string ) ) {
801 return false;
802 }
803 $atts = shortcode_parse_atts( $attr_string );
804 if ( ! is_array( $atts ) ) {
805 return false;
806 }
807 foreach ( [ 'left', 'right', 'include' ] as $key ) {
808 if ( empty( $atts[ $key ] ) ) {
809 continue;
810 }
811 $parts = array_map( 'trim', explode( ',', $atts[ $key ] ) );
812 if ( in_array( 'fullscreen', $parts, true ) ) {
813 return true;
814 }
815 }
816 return false;
817 };
818 foreach ( $matches as $m ) {
819 $attr_string = isset( $m[3] ) ? $m[3] : '';
820 if ( $check_values( $attr_string ) ) {
821 return true;
822 }
823 }
824 return false;
825 }
826
827 public static function difficulty_levels() {
828 return apply_filters( 'cooked_difficulty_levels', [
829 1 => __('Beginner', 'cooked'),
830 2 => __('Intermediate', 'cooked'),
831 3 => __('Advanced', 'cooked')
832 ]);
833 }
834
835 public static function get_by_slug($slug = false) {
836 if ($slug):
837 if (!function_exists('ctype_digit') || function_exists('ctype_digit') && !ctype_digit($slug)):
838 $recipe_query = new WP_Query(['name' => $slug, 'post_type' => 'cp_recipe'] );
839 if ($recipe_query->have_posts()):
840 $recipe_query->the_post();
841 return get_the_ID();
842 else:
843 return false;
844 endif;
845 else:
846 return $slug;
847 endif;
848 else:
849 return false;
850 endif;
851 }
852
853 public static function gallery_types() {
854
855 $gallery_types = apply_filters( 'cooked_gallery_types', [
856 'cooked' => [
857 'title' => __('Cooked Gallery', 'cooked'),
858 'required_class' => ''
859 ],
860 'envira' => [
861 'title' => __('Envira Gallery', 'cooked'),
862 'required_class' => 'Envira_Gallery'
863 ],
864 'soliloquy' => [
865 'title' => __('Soliloquy Slider', 'cooked'),
866 'required_class' => 'Soliloquy'
867 ],
868 'revslider' => [
869 'title' => __('Slider Revolution', 'cooked'),
870 'required_class' => 'RevSlider'
871 ]
872 ]);
873
874 foreach ( $gallery_types as $slug => $gtype ):
875
876 $results = [];
877
878 if ( $gtype['required_class'] && class_exists($gtype['required_class']) ):
879
880 if ( $slug == 'revslider' ):
881
882 $slider = new RevSlider();
883 $arrSliders = $slider->getArrSliders();
884 if (!empty($arrSliders)):
885 foreach($arrSliders as $slider):
886 $results[ $slider->getAlias() ] = $slider->getTitle();
887 endforeach;
888 endif;
889
890 else:
891
892 $args = apply_filters( 'cooked_gallery_type_' . $slug . '_query', [
893 'post_type' => $slug,
894 'post_status' => 'publish',
895 'posts_per_page' => -1
896 ]);
897 $gallery_query = new WP_Query( $args );
898 if ( $gallery_query->have_posts() ):
899 while( $gallery_query->have_posts() ):
900 $gallery_query->the_post();
901 $results[$gallery_query->post->ID] = get_the_title();
902 endwhile;
903 endif;
904
905 endif;
906
907 if ( !empty($results) ):
908 $gallery_types[$slug]['posts'] = $results;
909 else:
910 unset( $gallery_types[$slug] );
911 endif;
912
913 else:
914
915 if ( $slug != 'cooked' ): unset( $gallery_types[$slug] ); endif;
916
917 endif;
918
919 endforeach;
920
921 wp_reset_query();
922 wp_reset_postdata();
923
924 return $gallery_types;
925 }
926
927 public static function measurement_system_switcher() {
928 global $_cooked_settings, $post;
929 $switcher_enabled = ( isset( $_cooked_settings['advanced'] ) && in_array( 'enable_measurement_switcher', $_cooked_settings['advanced'] ) ? true : false );
930 $printing = ( is_singular('cp_recipe') && isset($_GET['print']) );
931
932 if ( !$printing && $switcher_enabled ):
933 $current = esc_html( get_query_var( 'measurement_system', '' ) );
934 $labels = [
935 '' => __( 'Default', 'cooked' ),
936 'metric' => __( 'Metric', 'cooked' ),
937 'imperial' => __( 'Imperial', 'cooked' ),
938 ];
939 $current_label = isset( $labels[ $current ] ) ? $labels[ $current ] : $labels[''];
940 echo '<span class="cooked-measurement-system"><span class="cooked-measurement-system-icon"><i class="cooked-icon cooked-icon-gear"></i></span>';
941 echo '<strong class="cooked-meta-title">' . __( 'Units', 'cooked' ) . '</strong>';
942 echo '<a aria-label="' . esc_attr( $current_label ) . '" href="#">' . esc_html( $current_label ) . '</a>';
943 echo '<label for="cooked-measurement-system-changer" class="screen-reader-text">' . __( 'Measurement System', 'cooked' ) . '</label>';
944 echo '<select id="cooked-measurement-system-changer" name="measurement_system" class="cooked-measurement-system-changer">';
945 echo '<option value=""' . selected( $current, '', false ) . '>' . __( 'Default', 'cooked' ) . '</option>';
946 echo '<option value="metric"' . selected( $current, 'metric', false ) . '>' . __( 'Metric', 'cooked' ) . '</option>';
947 echo '<option value="imperial"' . selected( $current, 'imperial', false ) . '>' . __( 'Imperial', 'cooked' ) . '</option>';
948 echo '</select>';
949 echo '</span>';
950 endif;
951 }
952
953 public static function serving_size_switcher( $servings ) {
954 global $_cooked_settings, $post;
955 $switcher_disabled = ( isset( $_cooked_settings['advanced'] ) && in_array( 'disable_servings_switcher', $_cooked_settings['advanced'] ) ? true : false );
956 $printing = ( is_singular('cp_recipe') && isset($_GET['print']) );
957
958 if ( !$printing && !$switcher_disabled ):
959 $default = $servings;
960 $servings = (float)esc_html( get_query_var( 'servings', $servings ) );
961 $servings = ( !$servings ? $default : $servings );
962 $counter = 1;
963
964 $quarter = $default / 4;
965 $half = $default / 2;
966 $double = $default * 2;
967 $triple = $default * 3;
968
969 /* translators: singular and plural quarter "serving" size */
970 $quarter_string = sprintf( esc_html( _n('Quarter (%s Serving)','Quarter (%s Servings)',$quarter,'cooked')),$quarter );
971
972 /* translators: singular and plural quarter "serving" size */
973 $half_string = sprintf( esc_html( _n('Half (%s Serving)','Half (%s Servings)',$half,'cooked')),$half );
974
975 /* translators: singular and plural quarter "serving" size */
976 $default_string = sprintf( esc_html( _n('Default (%s Serving)','Default (%s Servings)',$default,'cooked')),$default );
977
978 /* translators: singular and plural quarter "serving" size */
979 $double_string = sprintf( __( 'Double (%s Servings)','cooked'),$double );
980
981 /* translators: singular and plural quarter "serving" size */
982 $triple_string = sprintf( __( 'Triple (%s Servings)','cooked'),$triple );
983
984 $servings_array = apply_filters( 'cooked_servings_switcher_options', [
985 'quarter' => ['name' => $quarter_string, 'value' => $quarter],
986 'half' => ['name' => $half_string, 'value' => $half],
987 'default' => ['name' => $default_string, 'value' => $default],
988 'double' => ['name' => $double_string, 'value' => $double],
989 'triple' => ['name' => $triple_string, 'value' => $triple],
990 ], $quarter, $half, $default, $double, $triple );
991 else:
992 $servings_array = [];
993 endif;
994
995 echo '<span class="cooked-servings"><span class="cooked-servings-icon"><i class="cooked-icon cooked-icon-recipe-icon"></i></span>';
996 echo '<strong class="cooked-meta-title">' . __('Yields','cooked') . '</strong>';
997 if ( !$printing && !$switcher_disabled ):
998
999 /* translators: singular and plural "serving" sizes */
1000 $servings_string = sprintf( esc_html( _n( '%s Serving', '%s Servings', $servings, 'cooked' ) ), $servings );
1001
1002 echo '<a aria-label="' . $servings_string . '" href="#">' . $servings_string . '</a>';
1003 echo '<label for="cooked-servings-changer" class="screen-reader-text">' . __('Servings', 'cooked') . '</label>';
1004 echo '<select id="cooked-servings-changer" name="servings" class="cooked-servings-changer">';
1005 foreach ( $servings_array as $stype ):
1006 echo '<option value="' . $stype['value'] . '"' . ( $stype['value'] == $servings ? ' selected' : '' ) . '>' . esc_attr( $stype['name'] ) . '</option>';
1007 endforeach;
1008 echo '</select>';
1009 else:
1010 /* translators: singular and plural "serving" sizes */
1011 echo '<span>' . sprintf( esc_html( _n( '%s Serving', '%s Servings', $servings, 'cooked' ) ), $servings ) . '</span>';
1012 endif;
1013 echo '</span>';
1014
1015 }
1016
1017 public static function single_ingredient( $ing, $checkboxes = true, $plain_text = false ) {
1018 global $recipe_settings;
1019
1020 $Cooked_Measurements = new Cooked_Measurements();
1021 $measurements = $Cooked_Measurements->get();
1022
1023 ob_start();
1024
1025 if ( isset($ing['section_heading_name']) && $ing['section_heading_name'] ) {
1026
1027 if ( $plain_text ) {
1028 return $ing['section_heading_name'];
1029 } else {
1030 $valid_elements = ['div', 'h2', 'h3', 'h4', 'h5', 'h6'];
1031 global $_cooked_settings;
1032 $default_element = isset($_cooked_settings['section_heading_default_html_tag']) ? $_cooked_settings['section_heading_default_html_tag'] : 'div';
1033
1034 $element = (isset($ing['section_heading_element']) && in_array($ing['section_heading_element'], $valid_elements, true))
1035 ? ($ing['section_heading_element'] === 'div' ? $default_element : $ing['section_heading_element'])
1036 : $default_element;
1037
1038 echo '<' . $element . ' class="cooked-single-ingredient cooked-heading">' . esc_html($ing['section_heading_name']) . '</' . $element . '>';
1039 }
1040
1041 } elseif ( isset($ing['name']) && $ing['name'] ) {
1042
1043 $default_serving_size = ( isset($recipe_settings['nutrition']['servings']) && $recipe_settings['nutrition']['servings'] ? $recipe_settings['nutrition']['servings'] : 1 );
1044 $multiplier = (float)esc_html( get_query_var( 'servings', $recipe_settings['nutrition']['servings'] ) );
1045 $multiplier = ( !$multiplier ? $default_serving_size : $multiplier );
1046
1047 if ( !$multiplier || $multiplier == $default_serving_size ) {
1048 $multiplier = 1;
1049 } else {
1050 $multiplier = $multiplier / $default_serving_size;
1051 }
1052
1053 if ($multiplier === 1) {
1054 $amount = ( isset($ing['amount']) && $ing['amount'] ? esc_html( $ing['amount'] ) : false );
1055 $amount = $Cooked_Measurements->cleanup_amount($amount);
1056 $format = ( strpos($amount, '/') === false ? ( strpos($amount, '.') !== false || strpos($amount, ',') !== false ? 'decimal' : 'fraction' ) : 'fraction' );
1057 $float_amount = $Cooked_Measurements->calculate( $amount, 'decimal' );
1058 $amount = $Cooked_Measurements->format_amount( $float_amount, $format );
1059 } else {
1060 $amount = ( isset($ing['amount']) && $ing['amount'] ? esc_html( $ing['amount'] ) : false );
1061 $amount = $Cooked_Measurements->cleanup_amount($amount);
1062 $format = ( strpos($amount, '/') === false ? ( strpos($amount, '.') !== false || strpos($amount, ',') !== false ? 'decimal' : 'fraction' ) : 'fraction' );
1063 $float_amount = $Cooked_Measurements->calculate( $amount, 'decimal' );
1064
1065 if ($float_amount) {
1066 $float_amount = $float_amount * $multiplier;
1067 $amount = $Cooked_Measurements->format_amount( $float_amount, $format );
1068 }
1069 }
1070
1071 $measurement_key = ( isset($ing['measurement']) && $ing['measurement'] ? esc_html( $ing['measurement'] ) : false );
1072
1073 $measurement_system = get_query_var( 'measurement_system', '' );
1074 if ( $measurement_system && $measurement_key && $float_amount && isset( $measurements[ $measurement_key ]['system'] ) ) {
1075 $source_system = $measurements[ $measurement_key ]['system'];
1076 if ( $source_system && $source_system !== $measurement_system ) {
1077 $target = Cooked_Unit_Converter::get_target_unit( $measurement_key );
1078 $result = $target ? Cooked_Unit_Converter::convert( $float_amount, $measurement_key, $target ) : null;
1079 if ( $result ) {
1080 $float_amount = $result['amount'];
1081 $measurement_key = $result['unit'];
1082 if ( $float_amount > 10 ) {
1083 $format = 'decimal';
1084 }
1085 $amount = $Cooked_Measurements->format_amount( $float_amount, $format );
1086 }
1087 }
1088 }
1089
1090 $measurement = ( $measurement_key && $float_amount && isset( $measurements[ $measurement_key ] ) ? $Cooked_Measurements->singular_plural( $measurements[ $measurement_key ]['singular_abbr'], $measurements[ $measurement_key ]['plural_abbr'], $float_amount ) : false );
1091
1092 $name = ( isset($ing['name']) && $ing['name'] ? apply_filters( 'cooked_ingredient_name', wp_kses_post( $ing['name'] ), $ing ) : false );
1093
1094 // Substitution Logic
1095 $sub_name = ( isset($ing['sub_name']) && $ing['sub_name'] ? wp_kses_post( $ing['sub_name'] ) : false );
1096 $sub_amount = false;
1097 $sub_measurement = false;
1098 $sub_float_amount = 0;
1099
1100 if ( $sub_name ) {
1101 if ($multiplier === 1) {
1102 $sub_amount = ( isset($ing['sub_amount']) && $ing['sub_amount'] ? esc_html( $ing['sub_amount'] ) : false );
1103 $sub_amount = $Cooked_Measurements->cleanup_amount($sub_amount);
1104 $sub_format = ( strpos($sub_amount, '/') === false ? ( strpos($sub_amount, '.') !== false || strpos($sub_amount, ',') !== false ? 'decimal' : 'fraction' ) : 'fraction' );
1105 $sub_float_amount = $Cooked_Measurements->calculate( $sub_amount, 'decimal' );
1106 $sub_amount = $Cooked_Measurements->format_amount( $sub_float_amount, $sub_format );
1107 } else {
1108 $sub_amount = ( isset($ing['sub_amount']) && $ing['sub_amount'] ? esc_html( $ing['sub_amount'] ) : false );
1109 $sub_amount = $Cooked_Measurements->cleanup_amount($sub_amount);
1110 $sub_format = ( strpos($sub_amount, '/') === false ? ( strpos($sub_amount, '.') !== false || strpos($sub_amount, ',') !== false ? 'decimal' : 'fraction' ) : 'fraction' );
1111 $sub_float_amount = $Cooked_Measurements->calculate( $sub_amount, 'decimal' );
1112
1113 if ($sub_float_amount) {
1114 $sub_float_amount = $sub_float_amount * $multiplier;
1115 $sub_amount = $Cooked_Measurements->format_amount( $sub_float_amount, $sub_format );
1116 }
1117 }
1118
1119 $sub_measurement_key = ( isset($ing['sub_measurement']) && $ing['sub_measurement'] ? esc_html( $ing['sub_measurement'] ) : false );
1120
1121 if ( $measurement_system && $sub_measurement_key && $sub_float_amount && isset( $measurements[ $sub_measurement_key ]['system'] ) ) {
1122 $sub_source_system = $measurements[ $sub_measurement_key ]['system'];
1123 if ( $sub_source_system && $sub_source_system !== $measurement_system ) {
1124 $sub_target = Cooked_Unit_Converter::get_target_unit( $sub_measurement_key );
1125 $sub_result = $sub_target ? Cooked_Unit_Converter::convert( $sub_float_amount, $sub_measurement_key, $sub_target ) : null;
1126 if ( $sub_result ) {
1127 $sub_float_amount = $sub_result['amount'];
1128 $sub_measurement_key = $sub_result['unit'];
1129 if ( $sub_float_amount > 10 ) {
1130 $sub_format = 'decimal';
1131 }
1132 $sub_amount = $Cooked_Measurements->format_amount( $sub_float_amount, $sub_format );
1133 }
1134 }
1135 }
1136
1137 $sub_measurement = ( $sub_measurement_key && $sub_float_amount && isset($measurements[$sub_measurement_key]) ? $Cooked_Measurements->singular_plural( $measurements[ $sub_measurement_key ]['singular_abbr'], $measurements[ $sub_measurement_key ]['plural_abbr'], $sub_float_amount ) : false );
1138 }
1139
1140 if ( $plain_text ) {
1141 $output = ( $amount ? $amount . ' ' : '' ) . ( $measurement ? $measurement . ' ' : '' ) . ( $name ? $name : '' );
1142 if ( $sub_name ) {
1143 $output .= ' (' . __('or', 'cooked') . ' ' . ( $sub_amount ? $sub_amount . ' ' : '' ) . ( $sub_measurement ? $sub_measurement . ' ' : '' ) . $sub_name . ')';
1144 }
1145 return $output;
1146 } else {
1147 echo '<div itemprop="recipeIngredient" class="cooked-single-ingredient cooked-ingredient' . ( !$checkboxes ? ' cooked-ing-no-checkbox' : '' ) . '">';
1148 echo ( $checkboxes ? '<span class="cooked-ingredient-checkbox">&nbsp;</span>' : '' );
1149 do_action( 'cooked_ingredient_after_checkbox', $ing );
1150 echo ( $amount ? '<span class="cooked-ing-amount" data-decimal="' . esc_html($float_amount) . '">' . wp_kses_post($amount) . '</span> <span class="cooked-ing-measurement">' . wp_kses_post( $measurement ) . '</span> ' : '' );
1151 do_action( 'cooked_ingredient_after_amount', $ing );
1152 echo ( $name ? '<span class="cooked-ing-name">' . wp_kses_post( $name ) . '</span>' : '' );
1153 do_action( 'cooked_ingredient_after_name', $ing );
1154
1155 if ( $sub_name ) {
1156 echo '<span class="cooked-ingredient-substitution">';
1157 echo ' <span class="cooked-ing-sub-label">' . __('or', 'cooked') . '</span> ';
1158 echo ( $sub_amount ? '<span class="cooked-ing-amount" data-decimal="' . esc_html($sub_float_amount) . '">' . wp_kses_post($sub_amount) . '</span> <span class="cooked-ing-measurement">' . wp_kses_post( $sub_measurement ) . '</span> ' : '' );
1159 echo '<span class="cooked-ing-name">' . wp_kses_post( $sub_name ) . '</span>';
1160 echo '</span>';
1161 }
1162 echo '</div>';
1163 }
1164 }
1165
1166 $ing_html = ob_get_clean();
1167 echo apply_filters( 'cooked_single_ingredient_html', $ing_html, $ing, $checkboxes, $plain_text );
1168 }
1169
1170 public static function single_direction($dir, $number = false, $plain_text = false, $step = false, $atts = false) {
1171 global $recipe_settings;
1172
1173 if (isset($dir['section_heading_name']) && $dir['section_heading_name']) {
1174
1175 if ($plain_text) {
1176 return $dir['section_heading_name'];
1177 } else {
1178 $valid_elements = ['div', 'h2', 'h3', 'h4', 'h5', 'h6'];
1179 global $_cooked_settings;
1180 $default_element = isset($_cooked_settings['section_heading_default_html_tag']) ? $_cooked_settings['section_heading_default_html_tag'] : 'div';
1181
1182 $element = (isset($dir['section_heading_element']) && in_array($dir['section_heading_element'], $valid_elements, true))
1183 ? ($dir['section_heading_element'] === 'div' ? $default_element : $dir['section_heading_element'])
1184 : $default_element;
1185
1186 echo '<' . $element . ' class="cooked-single-direction cooked-heading">' . esc_html($dir['section_heading_name']) . '</' . $element . '>';
1187 }
1188
1189 } elseif ( !empty($dir['content']) || !empty($dir['image']) || !empty($dir['video']) ) {
1190
1191 $dir_image_size = apply_filters( 'cooked_direction_image_size', 'large' );
1192 $image = !empty($dir['image']) ? wp_get_attachment_image( $dir['image'], $dir_image_size, false, ['title' => esc_attr(get_the_title($dir['image']))] ) : '';
1193 $content = !empty($dir['content']) ? Cooked_Recipes::format_content($dir['content']) : '';
1194 $video = !empty($dir['video']) ? wp_get_attachment_url($dir['video']) : '';
1195
1196 $image = apply_filters('cooked_direction_image_html', $image, $atts);
1197
1198 if ($plain_text) {
1199 return $content;
1200 } else {
1201 /* translators: singular and plural "steps" */
1202 $step_string = sprintf( __( 'Step %d', 'cooked' ), $step );
1203
1204 echo '<div id="cooked-single-direction-step-'. $number .'" class="cooked-single-direction cooked-direction' . ($image ? ' cooked-direction-has-image' : '') . ( $number ? ' cooked-direction-has-number' . ( $number > 9 ? '-wide' : '' ) : '' ) . '"' . ( $step ? ' data-step="' . $step_string . '"' : '' ) . '>';
1205 echo $number ? '<span class="cooked-direction-number">' . esc_html($number) . '</span>' : '';
1206 echo '<div class="cooked-dir-content">' . do_shortcode($content) . ($image ? wpautop($image) : '') . ($video ? '<video class="cooked-direction-video" src="' . esc_url($video) . '" controls preload="metadata" playsinline></video>' : '') . '</div>';
1207 echo '</div>';
1208 }
1209 }
1210 }
1211
1212 public static function format_content($content) {
1213 return wpautop(wp_kses_post(html_entity_decode($content)));
1214 }
1215
1216 public static function difficulty_level($level) {
1217 $level_names = self::difficulty_levels();
1218 $level_text = isset($level_names[$level]) ? $level_names[$level] : false;
1219 return $level_text ? '<span class="cooked-difficulty-level-' . esc_attr($level) . '">' . wp_kses_post($level_text) . '</span>' : '';
1220 }
1221
1222 public static function recipe_search_box( $options = false ) {
1223 global $_cooked_settings, $recipe_args, $tax_col_count, $active_taxonomy;
1224
1225 $tax_col_count = 0;
1226 $filters_set = [];
1227 $taxonomy_search_fields = '';
1228
1229 if ( isset($recipe_args['tax_query']) ):
1230 foreach ( $recipe_args['tax_query'] as $query ):
1231 // Only process inclusion queries (default operator or explicit 'IN')
1232 // Skip exclusion queries ('NOT IN') and other complex operators
1233 $operator = isset($query['operator']) ? $query['operator'] : 'IN';
1234 if ( $operator === 'IN' && isset($query['taxonomy']) && isset($query['terms']) ):
1235 $filters_set[$query['taxonomy']] = implode( ',', $query['terms'] );
1236 endif;
1237 endforeach;
1238
1239 if ( isset($filters_set) ):
1240 foreach ( $filters_set as $taxonomy => $filter ):
1241 $this_tax = get_term_by( 'slug', $filter, $taxonomy );
1242 $this_tax = $this_tax ? $this_tax : get_term_by( 'id', $filter, $taxonomy );
1243 if ( $this_tax && !is_wp_error($this_tax) ):
1244 $filters_set[$taxonomy] = $this_tax->term_id;
1245 $active_taxonomy = !isset($active_taxonomy) ? $this_tax->name : $active_taxonomy;
1246 endif;
1247 endforeach;
1248 endif;
1249 endif;
1250
1251 $total_taxonomies = 0;
1252
1253 $inline_browse = isset($options['inline_browse']) && $options['inline_browse'] ? true : false;
1254
1255 ob_start();
1256 if ( !empty($_cooked_settings['recipe_taxonomies']) ):
1257
1258 if ( !$inline_browse ):
1259
1260 echo '<div class="cooked-field-wrap cooked-field-wrap-select' . ( isset($active_taxonomy) ? ' cooked-taxonomy-selected' : '' ) . '">';
1261 echo '<span class="cooked-browse-select">';
1262 echo '<span class="cooked-field-title">' . ( isset($active_taxonomy) ? esc_html( $active_taxonomy ) : __('Browse','cooked') ) . '</span>';
1263 echo '<span class="cooked-browse-select-block cooked-clearfix">';
1264
1265 endif;
1266
1267 ob_start();
1268
1269 do_action( 'cooked_before_search_filter_columns' );
1270
1271 if ( isset($active_taxonomy) ):
1272 $recipes_page_id = Cooked_Multilingual::get_browse_page_id();
1273 $recipes_page_id = $recipes_page_id ? $recipes_page_id : get_the_ID();
1274 $view_all_recipes_url = get_permalink( $recipes_page_id );
1275 else:
1276 $view_all_recipes_url = false;
1277 endif;
1278
1279 if ( in_array( 'cp_recipe_category', $_cooked_settings['recipe_taxonomies']) ):
1280 $terms_array = Cooked_Settings::terms_array( 'cp_recipe_category', false, __('No categories','cooked'), true, true, false );
1281 if ( !empty($terms_array) ):
1282 echo '<span class="cooked-tax-column">';
1283 echo '<span class="cooked-tax-column-title">' . __('Categories','cooked') . '</span>';
1284 echo '<div class="cooked-tax-scrollable">';
1285 echo ( $view_all_recipes_url ? '<a href="' . esc_url( $view_all_recipes_url ) . '">' . __( 'All Categories','cooked' ) . '</a>' : '' );
1286 foreach ( $terms_array as $key => $val ):
1287 if ( $key ):
1288 $term = get_term( $key );
1289 $term_link = ( !empty($term) ? get_term_link( $term ) : false );
1290 $term_name = apply_filters( 'cooked_term_name', $term->name, $term->ID, $term->taxonomy );
1291 echo ( $term_link ? ( isset($active_taxonomy) && $active_taxonomy == $val ? '<strong><i class="cooked-icon cooked-icon-angle-right"></i>&nbsp;&nbsp;' : '' ) . '<a href="' . esc_url($term_link) . '">' . esc_html($term_name) . '</a>' . ( isset($active_taxonomy) && $active_taxonomy == $val ? '</strong>' : '' ) : '' );
1292 $total_taxonomies++;
1293 $sub_terms_array = Cooked_Settings::terms_array( 'cp_recipe_category', false, false, true, false, $key );
1294 if ( !empty($sub_terms_array) ):
1295 foreach ( $sub_terms_array as $sub_key => $sub_val ):
1296 if ( $sub_key ):
1297 $sub_term = get_term( $sub_key );
1298 $sub_term_link = ( !empty($sub_term) ? get_term_link( $sub_term ) : false );
1299 $sub_term_name = apply_filters( 'cooked_term_name', $sub_term->name, $sub_term->ID, $sub_term->taxonomy );
1300 echo ( $sub_term_link ? '<span class="cooked-tax-sub-item">' . ( isset($active_taxonomy) && $active_taxonomy == $sub_val ? '<strong><i class="cooked-icon cooked-icon-angle-right"></i>&nbsp;&nbsp;' : '' ) . '<a href="' . esc_url($sub_term_link) . '">' . esc_html($sub_term_name) . '</a>' . ( isset($active_taxonomy) && $active_taxonomy == $sub_val ? '</strong>' : '' ) . '</span>' : '' );
1301 $total_taxonomies++;
1302 endif;
1303 endforeach;
1304 endif;
1305 endif;
1306 endforeach;
1307 $tax_col_count++;
1308 echo '</div>';
1309 echo '</span>';
1310 endif;
1311 endif;
1312
1313 do_action( 'cooked_after_search_filter_columns' );
1314
1315 $browse_html = ob_get_clean();
1316
1317 if ( !$inline_browse ):
1318
1319 echo wp_kses_post( $browse_html );
1320 echo '</span></span></div>';
1321
1322 endif;
1323
1324 endif;
1325
1326 if ( $total_taxonomies ):
1327 $taxonomy_search_fields = ob_get_clean();
1328 else:
1329 ob_clean();
1330 $taxonomy_search_fields = false;
1331 endif;
1332
1333 $page_id = Cooked_Multilingual::get_browse_page_id();
1334 $page_id = $page_id ? $page_id : get_the_ID();
1335 $form_redirect = get_permalink($page_id);
1336
1337 $cooked_search_s = get_query_var('cooked_search_s', '');
1338 $cooked_search_s = urldecode($cooked_search_s);
1339 $cooked_search_s = Cooked_Functions::sanitize_text_field( $cooked_search_s );
1340
1341 ob_start();
1342
1343 echo '<section class="cooked-recipe-search cooked-clearfix' . ( isset( $options['compact'] ) && $options['compact'] ? ' cooked-search-compact' : '' ) . ( isset( $options['hide_sorting'] ) && $options['hide_sorting'] ? ' cooked-search-no-sorting' : '' ) . ( isset( $options['hide_browse'] ) && $options['hide_browse'] ? ' cooked-search-no-browse' : '' ) . '">';
1344
1345 echo '<form action="' . esc_url( $form_redirect ) . '" method="get">';
1346
1347 echo '<input type="hidden" name="page_id" value="' . intval( $page_id ) . '">';
1348 if ( isset($recipe_args['tax_query'][0]['taxonomy']) ):
1349 echo '<input type="hidden" name="' . esc_attr( $recipe_args['tax_query'][0]['taxonomy'] ) . '" value="' . esc_attr( $recipe_args['tax_query'][0]['terms'][0] ) . '">';
1350 endif;
1351
1352 echo '<div class="cooked-fields-wrap cooked-' . esc_attr( $tax_col_count ) . '-search-fields">';
1353
1354 echo !$options['hide_browse'] && $taxonomy_search_fields ? $taxonomy_search_fields : '';
1355
1356 echo '<input aria-label="' . __('Find a recipe...', 'cooked') . '" class="cooked-browse-search" type="text" name="cooked_search_s" value="' . ( !empty($cooked_search_s) ? $cooked_search_s : '' ) . '" placeholder="' . __('Find a recipe...','cooked') . '" />';
1357
1358 echo '<a aria-label="' . __('Search', 'cooked') . '" href="#" class="cooked-browse-search-button"><i class="cooked-icon cooked-icon-search"></i></a>';
1359
1360 echo '</div>';
1361
1362 if ( isset( $recipe_args['orderby'] ) && is_array( $recipe_args['orderby'] ) ):
1363 $sorting_type = key($recipe_args['orderby']) . '_' . current( $recipe_args['orderby'] );
1364 else:
1365 $sorting_type = ( isset( $recipe_args['orderby'] ) && isset( $recipe_args['order'] ) ? $recipe_args['orderby'] . '_' . $recipe_args['order'] : 'date_desc' );
1366 endif;
1367
1368 $sorting_types = apply_filters( 'cooked_browse_sorting_types', [
1369 'date_desc' => [
1370 'slug' => 'date_desc',
1371 'name' => __("Newest first", "cooked")
1372 ],
1373 'date_asc' => [
1374 'slug' => 'date_asc',
1375 'name' => __("Oldest first", "cooked")
1376 ],
1377 'title_asc' => [
1378 'slug' => 'title_asc',
1379 'name' => __("Alphabetical (A-Z)", "cooked")
1380 ],
1381 'title_desc' => [
1382 'slug' => 'title_desc',
1383 'name' => __("Alphabetical (Z-A)", "cooked")
1384 ]
1385 ], $sorting_type );
1386
1387 if ( !$options['hide_sorting'] ):
1388
1389 echo '<span class="cooked-sortby-wrap"><select class="cooked-sortby-select" name="cooked_browse_sort_by">';
1390 foreach ( $sorting_types as $value => $type ):
1391 echo '<option value="' . esc_attr( $value ) . '"' . ( $sorting_type == $type['slug'] ? ' selected' : '' ) . '>' . esc_attr( $type['name'] ) . '</option>';
1392 endforeach;
1393 echo '</select></span>';
1394
1395 endif;
1396
1397 echo '</form>';
1398
1399 echo '</section>';
1400
1401 if ( $inline_browse ):
1402 echo '<div class="cooked-browse-select-inline-block cooked-clearfix">';
1403 echo wp_kses_post( $browse_html );
1404 echo '</div>';
1405 endif;
1406
1407 return ob_get_clean();
1408 }
1409
1410 public function recipe_template( $content ) {
1411 global $wp_query, $post, $_cooked_content_unfiltered;
1412
1413 if ( post_password_required() ):
1414 return $content;
1415 endif;
1416
1417 if ( is_singular('cp_recipe') && is_main_query() && $_cooked_content_unfiltered == false ):
1418 ob_start();
1419
1420 include COOKED_DIR . 'templates/front/recipe.php';
1421 // load_template( COOKED_DIR . 'templates/front/recipe.php', false );
1422
1423 $recipe_content = ob_get_clean();
1424 global $cooked_recipe_layout_content;
1425 $layout_content = isset( $cooked_recipe_layout_content ) ? $cooked_recipe_layout_content : null;
1426 return shortcode_unautop( apply_filters( 'cooked_recipe_content_filter', $recipe_content, $content, $post->ID, $layout_content ) );
1427
1428 endif;
1429
1430 return $content;
1431 }
1432
1433 /**
1434 * Cooked Classic 2.x Backwards Compatibility
1435 *
1436 * @since 1.0.0
1437 */
1438
1439 // Get and return the Cooked 2.x Classic recipe meta information
1440 public static function get_c2_recipe_meta( $post_id ) {
1441 $recipe_meta = [];
1442 $revised_array = [];
1443 $recipe_cs2_meta = get_post_meta($post_id);
1444
1445 if ( isset($recipe_cs2_meta['_cp_recipe_ingredients']) ):
1446
1447 foreach($recipe_cs2_meta as $key => $content):
1448 $revised_array[$key] = $content[0];
1449 endforeach;
1450
1451 $recipe_cs2_meta = $revised_array;
1452
1453 $recipe_meta['_cp_recipe_title'] = get_the_title( $post_id );
1454 $recipe_meta['_cp_recipe_ingredients'] = isset($recipe_cs2_meta['_cp_recipe_ingredients']) ? $recipe_cs2_meta['_cp_recipe_ingredients'] : false;
1455 $recipe_meta['_cp_recipe_detailed_ingredients'] = isset($recipe_cs2_meta['_cp_recipe_detailed_ingredients']) ? $recipe_cs2_meta['_cp_recipe_detailed_ingredients'] : false;
1456 $recipe_meta['_cp_recipe_directions'] = isset($recipe_cs2_meta['_cp_recipe_directions']) ? $recipe_cs2_meta['_cp_recipe_directions'] : false;
1457 $recipe_meta['_cp_recipe_detailed_directions'] = isset($recipe_cs2_meta['_cp_recipe_detailed_directions']) ? $recipe_cs2_meta['_cp_recipe_detailed_directions'] : false;
1458 $recipe_meta['_cp_recipe_external_video'] = isset($recipe_cs2_meta['_cp_recipe_external_video']) ? $recipe_cs2_meta['_cp_recipe_external_video'] : false;
1459 $recipe_meta['_cp_recipe_short_description'] = isset($recipe_cs2_meta['_cp_recipe_short_description']) ? $recipe_cs2_meta['_cp_recipe_short_description'] : false;
1460 $recipe_meta['_cp_recipe_excerpt'] = isset($recipe_cs2_meta['_cp_recipe_excerpt']) ? $recipe_cs2_meta['_cp_recipe_excerpt'] : false;
1461 $recipe_meta['_cp_recipe_difficulty_level'] = isset($recipe_cs2_meta['_cp_recipe_difficulty_level']) ? $recipe_cs2_meta['_cp_recipe_difficulty_level'] : false;
1462 $recipe_meta['_cp_recipe_prep_time'] = isset($recipe_cs2_meta['_cp_recipe_prep_time']) ? $recipe_cs2_meta['_cp_recipe_prep_time'] : false;
1463 $recipe_meta['_cp_recipe_cook_time'] = isset($recipe_cs2_meta['_cp_recipe_cook_time']) ? $recipe_cs2_meta['_cp_recipe_cook_time'] : false;
1464 $recipe_meta['_cp_recipe_additional_notes'] = isset($recipe_cs2_meta['_cp_recipe_additional_notes']) ? $recipe_cs2_meta['_cp_recipe_additional_notes'] : false;
1465 $recipe_meta['_cp_recipe_admin_rating'] = isset($recipe_cs2_meta['_cp_recipe_admin_rating']) ? $recipe_cs2_meta['_cp_recipe_admin_rating'] : false;
1466 $recipe_meta['_cp_recipe_yields'] = isset($recipe_cs2_meta['_cp_recipe_yields']) ? $recipe_cs2_meta['_cp_recipe_yields'] : false;
1467 $recipe_meta['_cp_recipe_nutrition_servingsize'] = isset($recipe_cs2_meta['_cp_recipe_nutrition_servingsize']) ? $recipe_cs2_meta['_cp_recipe_nutrition_servingsize'] : false;
1468 $recipe_meta['_cp_recipe_nutrition_calories'] = isset($recipe_cs2_meta['_cp_recipe_nutrition_calories']) ? $recipe_cs2_meta['_cp_recipe_nutrition_calories'] : false;
1469 $recipe_meta['_cp_recipe_nutrition_fat'] = isset($recipe_cs2_meta['_cp_recipe_nutrition_fat']) ? $recipe_cs2_meta['_cp_recipe_nutrition_fat'] : false;
1470 $recipe_meta['_cp_recipe_nutrition_satfat'] = isset($recipe_cs2_meta['_cp_recipe_nutrition_satfat']) ? $recipe_cs2_meta['_cp_recipe_nutrition_satfat'] : false;
1471 $recipe_meta['_cp_recipe_nutrition_transfat'] = isset($recipe_cs2_meta['_cp_recipe_nutrition_transfat']) ? $recipe_cs2_meta['_cp_recipe_nutrition_transfat'] : false;
1472 $recipe_meta['_cp_recipe_nutrition_cholesterol'] = isset($recipe_cs2_meta['_cp_recipe_nutrition_cholesterol']) ? $recipe_cs2_meta['_cp_recipe_nutrition_cholesterol'] : false;
1473 $recipe_meta['_cp_recipe_nutrition_sodium'] = isset($recipe_cs2_meta['_cp_recipe_nutrition_sodium']) ? $recipe_cs2_meta['_cp_recipe_nutrition_sodium'] : false;
1474 $recipe_meta['_cp_recipe_nutrition_potassium'] = isset($recipe_cs2_meta['_cp_recipe_nutrition_potassium']) ? $recipe_cs2_meta['_cp_recipe_nutrition_potassium'] : false;
1475 $recipe_meta['_cp_recipe_nutrition_carbs'] = isset($recipe_cs2_meta['_cp_recipe_nutrition_carbs']) ? $recipe_cs2_meta['_cp_recipe_nutrition_carbs'] : false;
1476 $recipe_meta['_cp_recipe_nutrition_fiber'] = isset($recipe_cs2_meta['_cp_recipe_nutrition_fiber']) ? $recipe_cs2_meta['_cp_recipe_nutrition_fiber'] : false;
1477 $recipe_meta['_cp_recipe_nutrition_sugar'] = isset($recipe_cs2_meta['_cp_recipe_nutrition_sugar']) ? $recipe_cs2_meta['_cp_recipe_nutrition_sugar'] : false;
1478 $recipe_meta['_cp_recipe_nutrition_protein'] = isset($recipe_cs2_meta['_cp_recipe_nutrition_protein']) ? $recipe_cs2_meta['_cp_recipe_nutrition_protein'] : false;
1479
1480 if ( !$recipe_meta['_cp_recipe_excerpt'] ):
1481 $recipe_meta['_cp_recipe_excerpt'] = $recipe_meta['_cp_recipe_short_description'];
1482 $recipe_meta['_cp_recipe_short_description'] = false;
1483 endif;
1484
1485 return $recipe_meta;
1486
1487 endif;
1488
1489 return [];
1490 }
1491
1492 // Sync up the Cooked 2.x Classic recipe meta fields to the new Cooked 3.x meta fields
1493 public static function sync_c2_recipe_settings( $c2_recipe_settings, $recipe_id ) {
1494 $recipe_settings = [];
1495 $ingredients = [];
1496 $directions = [];
1497
1498 $recipe_settings['title'] = isset($c2_recipe_settings['_cp_recipe_title']) ? $c2_recipe_settings['_cp_recipe_title'] : '';
1499 $recipe_settings['content'] = isset($c2_recipe_settings['_cp_recipe_short_description']) ? wpautop( $c2_recipe_settings['_cp_recipe_short_description'] . ($c2_recipe_settings['_cp_recipe_short_description'] ? '<br><br>' : '') . Cooked_Recipes::default_content() . ($c2_recipe_settings['_cp_recipe_additional_notes'] ? '<br><br>' : '') . $c2_recipe_settings['_cp_recipe_additional_notes'] ) : '';
1500 $recipe_settings['excerpt'] = isset($c2_recipe_settings['_cp_recipe_excerpt']) ? $c2_recipe_settings['_cp_recipe_excerpt'] : '';
1501 $recipe_settings['difficulty_level'] = isset($c2_recipe_settings['_cp_recipe_difficulty_level']) ? $c2_recipe_settings['_cp_recipe_difficulty_level'] : '';
1502 $recipe_settings['prep_time'] = isset($c2_recipe_settings['_cp_recipe_prep_time']) ? $c2_recipe_settings['_cp_recipe_prep_time'] : '';
1503 $recipe_settings['cook_time'] = isset($c2_recipe_settings['_cp_recipe_cook_time']) ? $c2_recipe_settings['_cp_recipe_cook_time'] : '';
1504
1505 // Ingredients
1506 if ( !empty($c2_recipe_settings['_cp_recipe_ingredients']) && empty($c2_recipe_settings['_cp_recipe_detailed_ingredients']) ):
1507 $ingredients = explode("\n", $c2_recipe_settings['_cp_recipe_ingredients']);
1508 elseif ( !empty($c2_recipe_settings['_cp_recipe_detailed_ingredients']) ):
1509 $ingredients = unserialize( $c2_recipe_settings['_cp_recipe_detailed_ingredients'] );
1510 endif;
1511
1512 if ( !empty($ingredients) ):
1513 foreach( $ingredients as $ing ):
1514 $rand_id = wp_rand( 1000000,9999999 );
1515 if ( isset($ing['type']) && $ing['type'] == 'ingredient' ):
1516 $recipe_settings['ingredients'][$rand_id]['amount'] = $ing['amount'];
1517 $recipe_settings['ingredients'][$rand_id]['measurement'] = $ing['measurement'];
1518 $recipe_settings['ingredients'][$rand_id]['name'] = $ing['name'];
1519 $recipe_settings['ingredients'][$rand_id]['sub_amount'] = '';
1520 $recipe_settings['ingredients'][$rand_id]['sub_measurement'] = '';
1521 $recipe_settings['ingredients'][$rand_id]['sub_name'] = '';
1522 elseif ( isset($ing['type']) && $ing['type'] == 'section' ):
1523 $recipe_settings['ingredients'][$rand_id]['section_heading_name'] = $ing['value'];
1524 else:
1525 if ( substr($ing, 0, 2) == '--' ):
1526 $recipe_settings['ingredients'][$rand_id]['section_heading_name'] = substr($ing, 2);
1527 else:
1528 $recipe_settings['ingredients'][$rand_id]['amount'] = false;
1529 $recipe_settings['ingredients'][$rand_id]['measurement'] = false;
1530 $recipe_settings['ingredients'][$rand_id]['name'] = $ing;
1531 $recipe_settings['ingredients'][$rand_id]['sub_amount'] = '';
1532 $recipe_settings['ingredients'][$rand_id]['sub_measurement'] = '';
1533 $recipe_settings['ingredients'][$rand_id]['sub_name'] = '';
1534 endif;
1535 endif;
1536 endforeach;
1537 endif;
1538
1539 // Directions
1540 if ( !empty($c2_recipe_settings['_cp_recipe_directions']) && empty($c2_recipe_settings['_cp_recipe_detailed_directions']) ):
1541 $directions = explode("\n", $c2_recipe_settings['_cp_recipe_directions']);
1542 elseif ( !empty($c2_recipe_settings['_cp_recipe_detailed_directions']) ):
1543 $directions = unserialize( $c2_recipe_settings['_cp_recipe_detailed_directions'] );
1544 endif;
1545
1546 if ( !empty($directions) ):
1547
1548 foreach( $directions as $dir ):
1549 $rand_id = wp_rand( 1000000,9999999 );
1550 if ( isset($dir['type']) && $dir['type'] == 'direction' ):
1551 $recipe_settings['directions'][$rand_id]['image'] = $dir['image_id'];
1552 $recipe_settings['directions'][$rand_id]['content'] = $dir['value'];
1553 elseif ( isset($dir['type']) && $dir['type'] == 'section' ):
1554 $recipe_settings['directions'][$rand_id]['section_heading_name'] = $dir['value'];
1555 else:
1556 if ( substr($dir, 0, 2) == '--' ):
1557 $recipe_settings['directions'][$rand_id]['section_heading_name'] = substr($dir, 2);
1558 else:
1559 $recipe_settings['directions'][$rand_id]['image'] = false;
1560 $recipe_settings['directions'][$rand_id]['content'] = $dir;
1561 endif;
1562 endif;
1563 endforeach;
1564
1565 endif;
1566
1567 if ( isset($c2_recipe_settings['_cp_recipe_external_video']) && $c2_recipe_settings['_cp_recipe_external_video'] && wp_oembed_get( $c2_recipe_settings['_cp_recipe_external_video'] ) ):
1568 $recipe_settings['gallery']['video_url'] = $c2_recipe_settings['_cp_recipe_external_video'];
1569 else:
1570 $recipe_settings['gallery']['video_url'] = false;
1571 $recipe_settings['gallery']['type'] = 'cooked';
1572 endif;
1573
1574 $recipe_settings['nutrition']['serving_size'] = ( isset($c2_recipe_settings['_cp_recipe_yields']) && $c2_recipe_settings['_cp_recipe_yields'] ? $c2_recipe_settings['_cp_recipe_yields'] : false );
1575 $recipe_settings['nutrition']['servings'] = ( isset($c2_recipe_settings['_cp_recipe_nutrition_servingsize']) && $c2_recipe_settings['_cp_recipe_nutrition_servingsize'] ? preg_replace("/[^0-9]/","",$c2_recipe_settings['_cp_recipe_nutrition_servingsize']) : false );
1576 $recipe_settings['nutrition']['calories'] = ( isset($c2_recipe_settings['_cp_recipe_nutrition_calories']) && $c2_recipe_settings['_cp_recipe_nutrition_calories'] ? preg_replace("/[^0-9]/","",$c2_recipe_settings['_cp_recipe_nutrition_calories']) : false );
1577 $recipe_settings['nutrition']['fat'] = ( isset($c2_recipe_settings['_cp_recipe_nutrition_fat']) && $c2_recipe_settings['_cp_recipe_nutrition_fat'] ? preg_replace("/[^0-9]/","",$c2_recipe_settings['_cp_recipe_nutrition_fat']) : false );
1578 $recipe_settings['nutrition']['sat_fat'] = ( isset($c2_recipe_settings['_cp_recipe_nutrition_satfat']) && $c2_recipe_settings['_cp_recipe_nutrition_satfat'] ? preg_replace("/[^0-9]/","",$c2_recipe_settings['_cp_recipe_nutrition_satfat']) : false );
1579 $recipe_settings['nutrition']['trans_fat'] = ( isset($c2_recipe_settings['_cp_recipe_nutrition_transfat']) && $c2_recipe_settings['_cp_recipe_nutrition_transfat'] ? preg_replace("/[^0-9]/","",$c2_recipe_settings['_cp_recipe_nutrition_transfat']) : false );
1580 $recipe_settings['nutrition']['cholesterol'] = ( isset($c2_recipe_settings['_cp_recipe_nutrition_cholesterol']) && $c2_recipe_settings['_cp_recipe_nutrition_cholesterol'] ? preg_replace("/[^0-9]/","",$c2_recipe_settings['_cp_recipe_nutrition_cholesterol']) : false );
1581 $recipe_settings['nutrition']['sodium'] = ( isset($c2_recipe_settings['_cp_recipe_nutrition_sodium']) && $c2_recipe_settings['_cp_recipe_nutrition_sodium'] ? preg_replace("/[^0-9]/","",$c2_recipe_settings['_cp_recipe_nutrition_sodium']) : false );
1582 $recipe_settings['nutrition']['potassium'] = ( isset($c2_recipe_settings['_cp_recipe_nutrition_potassium']) && $c2_recipe_settings['_cp_recipe_nutrition_potassium'] ? preg_replace("/[^0-9]/","",$c2_recipe_settings['_cp_recipe_nutrition_potassium']) : false );
1583 $recipe_settings['nutrition']['carbs'] = ( isset($c2_recipe_settings['_cp_recipe_nutrition_carbs']) && $c2_recipe_settings['_cp_recipe_nutrition_carbs'] ? preg_replace("/[^0-9]/","",$c2_recipe_settings['_cp_recipe_nutrition_carbs']) : false );
1584 $recipe_settings['nutrition']['fiber'] = ( isset($c2_recipe_settings['_cp_recipe_nutrition_fiber']) && $c2_recipe_settings['_cp_recipe_nutrition_fiber'] ? preg_replace("/[^0-9]/","",$c2_recipe_settings['_cp_recipe_nutrition_fiber']) : false );
1585 $recipe_settings['nutrition']['sugars'] = ( isset($c2_recipe_settings['_cp_recipe_nutrition_sugar']) && $c2_recipe_settings['_cp_recipe_nutrition_sugar'] ? preg_replace("/[^0-9]/","",$c2_recipe_settings['_cp_recipe_nutrition_sugar']) : false );
1586 $recipe_settings['nutrition']['protein'] = ( isset($c2_recipe_settings['_cp_recipe_nutrition_protein']) && $c2_recipe_settings['_cp_recipe_nutrition_protein'] ? preg_replace("/[^0-9]/","",$c2_recipe_settings['_cp_recipe_nutrition_protein']) : false );
1587
1588 $_nutrition_facts = Cooked_Measurements::nutrition_facts();
1589 foreach( $_nutrition_facts as $nutrition_facts ):
1590 foreach( $nutrition_facts as $slug => $nf ):
1591
1592 if ( !isset($recipe_settings[$slug]) ): $recipe_settings[$slug] = false; endif;
1593 if ( isset($nf['subs']) ):
1594 foreach( $nf['subs'] as $sub_slug => $sub_nf ):
1595 if ( !isset($recipe_settings[$sub_slug]) ): $recipe_settings[$sub_slug] = false; endif;
1596 endforeach;
1597 endif;
1598 endforeach;
1599 endforeach;
1600
1601 return apply_filters( 'cooked_sync_c2_recipe_settings', $recipe_settings, $recipe_id );
1602 }
1603
1604 public function modify_browse_page_canonical_url($canonical_url, $post = null) {
1605 global $_cooked_settings, $wp_query;
1606
1607 if (!is_page()) {
1608 return $canonical_url;
1609 }
1610
1611 $browse_page_id = Cooked_Multilingual::get_browse_page_id();
1612
1613 // Only modify for browse page with category.
1614 if (is_page($browse_page_id) &&
1615 isset($wp_query->query['cp_recipe_category']) &&
1616 taxonomy_exists('cp_recipe_category') &&
1617 term_exists($wp_query->query['cp_recipe_category'], 'cp_recipe_category')) {
1618
1619 // Build the canonical URL based on permalink structure.
1620 if (get_option('permalink_structure')) {
1621 $new_canonical = untrailingslashit(get_permalink($browse_page_id)) . '/' . $_cooked_settings['recipe_category_permalink'] . '/' . $wp_query->query['cp_recipe_category'];
1622 } else {
1623 $new_canonical = add_query_arg('cp_recipe_category', $wp_query->query['cp_recipe_category'], get_permalink($browse_page_id));
1624 }
1625
1626 return $new_canonical;
1627 }
1628
1629 return $canonical_url;
1630 }
1631 }
1632
1633 global $Cooked_Recipes;
1634 $Cooked_Recipes = new Cooked_Recipes();
1635