Skip to content

Commit

Permalink
#101 Moved recipe structured data to blade
Browse files Browse the repository at this point in the history
  • Loading branch information
MGHollander committed Jul 3, 2024
1 parent c93a8e8 commit 282fcc5
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 63 deletions.
60 changes: 60 additions & 0 deletions app/Http/Controllers/Recipe/RecipeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use App\Http\Resources\StructuredData\Recipe\InstructionsResource;
use App\Http\Traits\FillableAttributes;
use App\Models\Recipe;
use Artesaos\SEOTools\Facades\JsonLd;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\URL;
Expand Down Expand Up @@ -84,6 +85,8 @@ public function show(Request $request, string $slug)
return $this->notFound($request, $slug);
}

$this->setJsonLdData($recipe);

return Inertia::render('Recipes/Show', [
'recipe' => [
'id' => $recipe->id,
Expand Down Expand Up @@ -235,4 +238,61 @@ private function saveMedia(Request $request, Recipe $recipe): void
$media->save();
}
}

// @see https://developers.google.com/search/docs/appearance/structured-data/recipe
private function setJsonLdData(Recipe $recipe): void
{
JsonLd::setType('Recipe');
JsonLd::setTitle($recipe->title);

if ($recipe->summary) {
JsonLd::setDescription(strip_tags($recipe->summary));
}

JsonLd::addValues([
'datePublished' => $recipe->created_at,
'recipeYield' => $recipe->servings,
'ingredients' => new StructuredDataIngredientsResource($recipe->ingredients),
'recipeInstructions' => new InstructionsResource($recipe->instructions),
]);

$image = $recipe->getFirstMediaUrl('recipe_image', 'show');
if ($image) {
JsonLd::addImage($image);
}

// prepTime and cookTime should be used together according to the Google specs.
// Therefore, only add if both of them are available.
if ($recipe->preparation_minutes && $recipe->cooking_minutes) {
JsonLd::addValues([
'prepTime' => $this->minutesToISODuration($recipe->preparation_minutes),
'cookTime' => $this->minutesToISODuration($recipe->cooking_minutes),
]);
}

if ($recipe->preparation_minutes || $recipe->cooking_minutes) {
JsonLd::addValue('totalTime', $this->minutesToISODuration(($recipe->preparation_minutes ?? 0) + ($recipe->cooking_minutes ?? 0)));
}

if ($recipe->tags->count() > 0) {
JsonLd::addValue('keywords', implode(',', $recipe->tags->pluck('name')->toArray()));
}

}

/*
* Transform minutes into an ISO 8601 duration string.
* @see https://en.wikipedia.org/wiki/ISO_8601#Durations
*/
private function minutesToISODuration($minutes): string|null
{
$isoHours = (int) $minutes > 59 ? floor($minutes / 60) . 'H' : '';
$isoMinutes = (int) $minutes % 60 ? ($minutes % 60) . 'M' : '';

if (empty($isoMinutes) && empty($isoHours)) {
return null;
}

return 'PT' . $isoHours . $isoMinutes;
}
}
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"require": {
"php": "^8.2.0",
"ext-dom": "*",
"artesaos/seotools": "^1.3",
"brick/structured-data": "^0.1.1",
"guzzlehttp/guzzle": "^7.2",
"inertiajs/inertia-laravel": "^0.6.0",
Expand Down
74 changes: 73 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions config/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@
/*
* Package Service Providers...
*/
Artesaos\SEOTools\Providers\SEOToolsServiceProvider::class,

/*
* Application Service Providers...
Expand Down
60 changes: 0 additions & 60 deletions resources/js/Components/StructuredJson/Recipe.vue

This file was deleted.

2 changes: 0 additions & 2 deletions resources/js/Pages/Recipes/Show.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { computed, reactive, ref } from "vue";
import Button from "@/Components/Button.vue";
import Dropdown from "@/Components/Dropdown.vue";
import DropdownLink from "@/Components/DropdownLink.vue";
import StructuredRecipe from "@/Components/StructuredJson/Recipe.vue";
import DefaultLayout from "@/Layouts/Default.vue";
const props = defineProps({
Expand Down Expand Up @@ -61,7 +60,6 @@ const toggleStrike = (ingredient) => {

<template>
<Head :title="localRecipe.title" />
<StructuredRecipe :recipe="localRecipe" />

<DefaultLayout>
<div class="overflow-hidden bg-white sm:rounded-lg sm:shadow-lg">
Expand Down
2 changes: 2 additions & 0 deletions resources/views/layout.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
@endforeach
@endif

{!! JsonLd::generate() !!}

@yield('head')
</head>
<body class="font-sans antialiased min-w-80">
Expand Down

0 comments on commit 282fcc5

Please sign in to comment.