PluginProbe
Cooked – Recipe Management / 1.16.1
Cooked – Recipe Management v1.16.1
1.16.1 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 All 37 releases
cooked / includes / class.cooked-recipes.php

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

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