Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ authors:
given-names: Justin
- family-names: Tresova
given-names: Armand
version: 1.16.1
version: 1.16.2
doi: 10.5281/zenodo.1171250
date-released: 2017-05-08
url: "https://github.com/XjSv/cooked"
354 changes: 142 additions & 212 deletions bun.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"nutrition"
],
"homepage": "https://wordpress.org/plugins/cooked/",
"version": "1.16.1",
"version": "1.16.2",
"type": "wordpress-plugin",
"license": "GPL-2.0-or-later",
"authors": [
Expand Down
6 changes: 3 additions & 3 deletions cooked.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
* Description: A recipe plugin for WordPress.
* Author: Gora Tech
* Author URI: https://goratech.dev
* Version: 1.16.1
* Version: 1.16.2
* Text Domain: cooked
* Domain Path: /languages
* License: GPLv2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Requires at least: 6.8
* Tested up to: 7.1
* Requires PHP: 7.4
* Contributors: xjsv, boxystudio
* Contributors: xjsv, mgiannopoulos24, boxystudio
* Tags: recipe, recipes, food, cooking, nutrition
*
* Cooked is free software: you can redistribute it and/or modify
Expand All @@ -40,7 +40,7 @@
require_once __DIR__ . '/vendor/autoload.php';

define( 'COOKED_DEV', false );
define( 'COOKED_VERSION', '1.16.1' );
define( 'COOKED_VERSION', '1.16.2' );

if ( ! class_exists( 'Cooked_Plugin' ) ) :

Expand Down
28 changes: 28 additions & 0 deletions includes/class.cooked-measurements.php
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,35 @@ public function get_fraction_array() {
return $fraction_array;
}

/**
* Coerce a stored cook/prep/total time to minutes.
*
* @param mixed $value Raw time value.
* @return int|float Minutes, or 0.
*/
public static function normalize_minutes( $value ) {
if ( ! is_scalar( $value ) || is_bool( $value ) || '' === $value ) {
return 0;
}

if ( is_numeric( $value ) ) {
$minutes = (float) $value;
} elseif ( is_string( $value ) && preg_match( '/-?\d+(?:[.,]\d+)?/', $value, $matches ) ) {
$minutes = (float) str_replace( ',', '.', $matches[0] );
} else {
return 0;
}

if ( $minutes < 0 ) {
return 0;
}

return $minutes == (int) $minutes ? (int) $minutes : $minutes;
}

public static function time_format( $minutes, $format = 'default' ) {
$minutes = self::normalize_minutes( $minutes );

ob_start();

if ( $minutes < 60 ):
Expand Down
22 changes: 18 additions & 4 deletions includes/class.cooked-recipe-meta.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ public static function meta_cleanup( $recipe_settings ) {
} elseif ( $key === 'seo_description' ) {
$decoded_val = wp_specialchars_decode( $val, ENT_QUOTES );
$_recipe_settings[ $key ] = wp_strip_all_tags( $decoded_val );
} elseif ( in_array( $key, [ 'prep_time', 'cook_time', 'total_time' ], true ) ) {
$minutes = Cooked_Measurements::normalize_minutes( $val );
$_recipe_settings[ $key ] = $minutes ? $minutes : '';
} else {
if ($key === "post_title") {
// Decode HTML entities first so wp_kses_post can see actual HTML tags
Expand Down Expand Up @@ -1690,22 +1693,32 @@ function cooked_render_recipe_fields( $post_id ) {
</div>
</div>
<div class="cooked-setting-column-12">
<p class="cooked-bm-5"><strong>"title"</strong></p>
<p class="cooked-bm-10"><?php esc_html_e( 'Set the heading text for the related recipes section.','cooked'); ?></p>
<p class="cooked-bm-5"><strong>"include_ids"</strong></p>
<p class="cooked-bm-10"><?php esc_html_e( 'Comma-separated recipe IDs to pin at the start of the grid. Remaining slots are filled with related recipes.','cooked'); ?></p>
<div class="cooked-bm-20 cooked-block">
<input class='cooked-shortcode-field' type='text' readonly value='title="You May Also Like"' />
<input class='cooked-shortcode-field' type='text' readonly value='include_ids="101,102"' />
</div>
</div>
</div>

<div class="cooked-clearfix">
<div class="cooked-setting-column-12">
<p class="cooked-bm-5"><strong>"title"</strong></p>
<p class="cooked-bm-10"><?php esc_html_e( 'Set the heading text for the related recipes section.','cooked'); ?></p>
<div class="cooked-bm-20 cooked-block">
<input class='cooked-shortcode-field' type='text' readonly value='title="You May Also Like"' />
</div>
</div>
<div class="cooked-setting-column-12">
<p class="cooked-bm-5"><strong>"limit"</strong></p>
<p class="cooked-bm-10"><?php esc_html_e( 'Number of recipes to display (default: 4).','cooked'); ?></p>
<div class="cooked-bm-20 cooked-block">
<input class='cooked-shortcode-field' type='text' readonly value='limit="4"' />
</div>
</div>
</div>

<div class="cooked-clearfix">
<div class="cooked-setting-column-12">
<p class="cooked-bm-5"><strong>"columns"</strong></p>
<p class="cooked-bm-10"><?php esc_html_e( 'Number of columns in the grid (default: 2).','cooked'); ?></p>
Expand Down Expand Up @@ -1758,6 +1771,7 @@ function cooked_render_recipe_fields( $post_id ) {
<p class="cooked-bm-10 cooked-tm-10"><strong class="cooked-heading"><?php esc_html_e( 'Available Variables','cooked' ); ?></strong></p>
<p class="cooked-bm-10">
<strong>id</strong> (<?php esc_html_e( 'Recipe ID','cooked' ); ?>)<br>
<strong>include_ids</strong> (<?php esc_html_e( 'Pinned recipe IDs','cooked' ); ?>)<br>
<strong>title</strong> (<?php esc_html_e( 'Section heading','cooked' ); ?>)<br>
<strong>limit</strong> (<?php esc_html_e( 'Number of recipes','cooked' ); ?>)<br>
<strong>columns</strong> (<?php esc_html_e( 'Grid columns','cooked' ); ?>)<br>
Expand All @@ -1768,7 +1782,7 @@ function cooked_render_recipe_fields( $post_id ) {
</p>
<p class="cooked-bm-10 cooked-tm-10"><strong class="cooked-heading"><?php esc_html_e( 'Example','cooked' ); ?></strong></p>
<p class="cooked-bm-10">
<code>[cooked-related-recipes limit="4" columns="2" title="Related Recipes"]</code>
<code>[cooked-related-recipes include_ids="101,102" limit="4" columns="2" title="Related Recipes"]</code>
</p>
</div>

Expand Down
127 changes: 81 additions & 46 deletions includes/class.cooked-related-recipes.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class Cooked_Related_Recipes {
public static function get_default_atts() {
$default_atts = [
'id' => false,
'include_ids' => false,
'title' => __( 'Related Recipes', 'cooked' ),
'limit' => 4,
'columns' => 2,
Expand Down Expand Up @@ -72,64 +73,68 @@ public static function get_related_recipes( $recipe_id, $atts ) {
}

/**
* Find related recipes: one WP_Query with tax_query (all taxonomies OR) and orderby rand.
* Find related recipes: pinned include_ids first, then one WP_Query with
* tax_query (all taxonomies OR) and orderby rand to fill remaining slots.
*
* @param array $source_recipe Source recipe data.
* @param array $atts Shortcode attributes.
* @return array [ ['id' => int], ... ]
*/
public static function find_related_recipes( $source_recipe, $atts ) {
$recipe_id = $source_recipe['id'];
$limit = isset( $atts['limit'] ) ? max( 1, (int) $atts['limit'] ) : 4;

// Build OR clause for each taxonomy that is enabled via match_* and where the source recipe has terms.
$clauses = [];
$taxonomy_atts = [
'cp_recipe_category' => 'match_categories',
'cp_recipe_cuisine' => 'match_cuisines',
'cp_recipe_cooking_method' => 'match_cooking_methods',
'cp_recipe_tags' => 'match_tags',
'cp_recipe_diet' => 'match_diets',
];
foreach ( $taxonomy_atts as $taxonomy => $att_key ) {
if ( empty( $atts[ $att_key ] ) || $atts[ $att_key ] === 'false' ) {
continue;
$recipe_id = $source_recipe['id'];
$limit = isset( $atts['limit'] ) ? max( 1, (int) $atts['limit'] ) : 4;
$include_ids = array_slice( self::parse_include_ids( $atts, $recipe_id ), 0, $limit );
$remaining = $limit - count( $include_ids );
$related_ids = [];

if ( $remaining > 0 ) {
$clauses = [];
$taxonomy_atts = [
'cp_recipe_category' => 'match_categories',
'cp_recipe_cuisine' => 'match_cuisines',
'cp_recipe_cooking_method' => 'match_cooking_methods',
'cp_recipe_tags' => 'match_tags',
'cp_recipe_diet' => 'match_diets',
];
foreach ( $taxonomy_atts as $taxonomy => $att_key ) {
if ( ! isset( $atts[ $att_key ] ) || ! wp_validate_boolean( $atts[ $att_key ] ) ) {
continue;
}
$terms = self::get_recipe_terms( $recipe_id, $taxonomy );
if ( ! empty( $terms ) ) {
$clauses[] = [ 'taxonomy' => $taxonomy, 'field' => 'term_id', 'terms' => $terms ];
}
}
$terms = self::get_recipe_terms( $recipe_id, $taxonomy );
if ( ! empty( $terms ) ) {
$clauses[] = [ 'taxonomy' => $taxonomy, 'field' => 'term_id', 'terms' => $terms ];
}
}

if ( empty( $clauses ) ) {
return [];
}

$tax_query = array_merge( [ 'relation' => 'OR' ], $clauses );

$query_args = [
'post_type' => 'cp_recipe',
'post_status' => 'publish',
'post__not_in' => [ $recipe_id ],
'posts_per_page' => $limit,
'orderby' => 'rand',
'fields' => 'ids',
];

$query_args['tax_query'] = $tax_query;
if ( empty( $clauses ) && empty( $include_ids ) ) {
return [];
}

$current_language = false;
if ( class_exists( 'Cooked_Multilingual' ) && Cooked_Multilingual::is_multilingual_active() ) {
$current_language = Cooked_Multilingual::get_current_language();
if ( ! empty( $clauses ) ) {
$query_args = [
'post_type' => 'cp_recipe',
'post_status' => 'publish',
'post__not_in' => array_merge( [ $recipe_id ], $include_ids ),
'posts_per_page' => $remaining,
'orderby' => 'rand',
'fields' => 'ids',
'tax_query' => array_merge( [ 'relation' => 'OR' ], $clauses ),
];

$current_language = false;
if ( class_exists( 'Cooked_Multilingual' ) && Cooked_Multilingual::is_multilingual_active() ) {
$current_language = Cooked_Multilingual::get_current_language();
}
$query_args = apply_filters( 'cooked_related_recipes_query_args', $query_args, $current_language );

$query = new \WP_Query( $query_args );
$related_ids = ! empty( $query->posts ) ? $query->posts : [];
wp_reset_postdata();
}
}
$query_args = apply_filters( 'cooked_related_recipes_query_args', $query_args, $current_language );

$query = new \WP_Query( $query_args );
$ids = ! empty( $query->posts ) ? $query->posts : [];
wp_reset_postdata();

$result = [];
foreach ( $ids as $id ) {
foreach ( array_merge( $include_ids, $related_ids ) as $id ) {
$result[] = [ 'id' => (int) $id ];
}

Expand All @@ -145,6 +150,36 @@ public static function find_related_recipes( $source_recipe, $atts ) {
return apply_filters( 'cooked_related_recipes_result', $result, $source_recipe, $atts );
}

/**
* Parse include_ids into unique positive IDs, excluding the source recipe.
*
* @param array $atts Shortcode attributes.
* @param int $recipe_id Source recipe ID.
* @return int[]
*/
private static function parse_include_ids( $atts, $recipe_id ) {
if ( empty( $atts['include_ids'] ) ) {
return [];
}

$raw = $atts['include_ids'];
if ( ! is_array( $raw ) ) {
$raw = explode( ',', str_replace( ' ', '', (string) $raw ) );
}

$ids = [];
$recipe_id = (int) $recipe_id;
foreach ( $raw as $id ) {
$id = absint( $id );
if ( ! $id || $id === $recipe_id || in_array( $id, $ids, true ) ) {
continue;
}
$ids[] = $id;
}

return $ids;
}

/**
* Get recipe term IDs for a taxonomy.
*
Expand Down
4 changes: 2 additions & 2 deletions includes/class.cooked-seo.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ public static function schema_values( $recipe = false ) {
endif;
endif;

$cook_time = isset($recipe['cook_time']) && $recipe['cook_time'] ? esc_html( $recipe['cook_time'] ) : 0;
$prep_time = isset($recipe['prep_time']) && $recipe['prep_time'] ? esc_html( $recipe['prep_time'] ) : 0;
$cook_time = isset($recipe['cook_time']) ? Cooked_Measurements::normalize_minutes( $recipe['cook_time'] ) : 0;
$prep_time = isset($recipe['prep_time']) ? Cooked_Measurements::normalize_minutes( $recipe['prep_time'] ) : 0;
$total_time = $cook_time + $prep_time;

$unsaturatedFatAmount = (isset($recipe['nutrition']['monounsaturated_fat']) && $recipe['nutrition']['monounsaturated_fat'] ? $recipe['nutrition']['monounsaturated_fat'] : 0) + (isset($recipe['nutrition']['polyunsaturated_fat']) && $recipe['nutrition']['polyunsaturated_fat'] ? $recipe['nutrition']['polyunsaturated_fat'] : 0);
Expand Down
Loading
Loading