DEV Frissítve: #40 Forrás: GitHub
OG-kép generálás Laravelben — 523service/laravel-og-image
Lépésről lépésre: így kösd be és üzemeltesd a saját 523service/laravel-og-image csomagot egy Laravel-projektben. Aláírt URL, GD-vel rajzolt, fájlba cache-elt 1200×630-as Open Graph kép minden oldalhoz, headless böngésző nélkül, shared hostingon is.
1. Mire jó, mikor használd? Hivatkozás erre a szakaszra
A 523service/laravel-og-image minden oldalhoz saját, 1200×630-as Open Graph képet készít egy közös dizájnból. A képet az első kéréskor GD rajzolja meg, és fájlba menti, utána a webszerver statikus fájlként adja ki. Nem kell hozzá headless böngésző, ezért shared hostingon is működik. Akkor használd, ha nem akarsz minden oldalhoz kézzel megosztási képet gyártani, de azt szeretnéd, hogy Facebookon vagy LinkedInen minden link saját címmel jelenjen meg.
Hogyan működik:
- Az oldal csak az URL-t írja ki:
/og/{kulcs}.{png|jpg}?title=…&kicker=…&path=…. A kulcs a paraméterek HMAC-aláírása (titok:OG_IMAGE_SECRET, alapból azAPP_KEY-ből), és egyben a fájlnév is. Hibás vagy hiányzó aláírásra 403 a válasz. - Első kérés (crawler vagy
og:warm): a csomag ellenőrzi az aláírást, fájlzárral megrajzolja a képet, atomikusan apublic/og/{kulcs}.{fmt}fájlba írja, és mellé tesz egy.htaccess-t hosszúCache-Control-lal. - A további kéréseket már a webszerver szolgálja ki PHP nélkül (a Laravel alap
public/.htaccess-e, nginx-néltry_files). - A route a
webmiddleware nélkül fut (nincs session és cookie), ésroute:cache-sel is működik. - A képen: háttérszín vagy háttérfotó átmenetes sötétítéssel, logó (szöveg vagy képfájl), kicker (nagybetűs alcím a kiemelőszínnel), a cím (automatikusan 1–4 sorba tördelve, illesztett betűmérettel, túlcsordulásnál „…”-tal), lábléc bal oldalt a hosttal és az útvonallal (hosszú útvonal középen rövidítve), jobb oldalt egy tetszőleges szöveggel (pl. telefonszám).
Licenc: MIT. A mellékelt Montserrat betűtípus SIL OFL 1.1 licencű, a magyar ékezeteket rendben megjeleníti.
2. Követelmények Hivatkozás erre a szakaszra
- PHP 8.2+
ext-gdFreeType- és JPEG/PNG-támogatással (WebP háttérképhez WebP-támogatás is kell)- Laravel 11 vagy 12
Ellenőrzés a szerveren:
php -r 'print_r(gd_info());'
A FreeType Support, JPEG Support és PNG Support értéke legyen 1 (WebP háttérképnél a WebP Support is).
3. Telepítés Hivatkozás erre a szakaszra
A csomag nincs fent a Packagisten, ezért VCS-repóként kell felvenni.
-
Vedd fel a repót a
composer.json-ba:Bash composer config repositories.og-image vcs https://github.com/523service/laravel-og-image -
Telepítsd:
Bash composer require 523service/laravel-og-image:^1.0A service provider és az
OgImagefacade automatikusan regisztrálódik (package discovery). -
Publikáld a configot. Ez létrehozza a
config/og-image.phpfájlt:Bash php artisan vendor:publish --tag=og-image-config -
Tedd a legenerált képeket a
.gitignore-ba:GITIGNORE /public/og/ -
Opcionálisan állíts be változókat a
.env-ben (csak a nevük, értéket ne commitolj):.env OG_IMAGE_SECRET= OG_IMAGE_VERSION=1 OG_IMAGE_URL=Ha a
.env-ben nincsenek beállítva: a titok azAPP_KEY-ből származik, a verzió1, a kép-URL-ek alapja azAPP_URL.
Éles szerveren, ha nincs globális composer:
php composer.phar ….
4. Konfiguráció Hivatkozás erre a szakaszra
Teljes példa-preset Hivatkozás erre a szakaszra
Szöveges logó, háttérfotó és telefonszám a láblécben, a config/og-image.php megfelelő kulcsai:
// JPG: fotós háttérnél kb. 120 KB, a PNG kb. 400 KB.
'default_format' => 'jpg',
// Háttérképek: kulcs => fájl. URL-ből csak a KULCS adható meg, útvonal soha.
'images' => [
'hero' => public_path('img/hero.webp'),
],
// Ezt használja, ha az URL-ben nincs `p` paraméter (és ilyenkor a `p` ki is marad az URL-ből).
'default_preset' => 'brand',
'presets' => [
'brand' => [
'background' => '02243f', // háttérszín (6 jegyű hex, # nélkül)
'foreground' => 'ffffff', // cím színe
'accent' => 'bff230', // kicker / kiemelés színe
'muted' => 'd5dee8', // lábléc, tagline színe
'image' => 'hero', // háttérkép KULCSA az `images` tömbből (null = csak szín)
'overlay' => [ // átmenetes sötétítés a fotó fölött
'color' => '02243f',
'from' => 0.95, // átlátszatlanság az egyik oldalon
'to' => 0.62, // ... és a másikon
],
'logo' => [ // szöveges logó
'type' => 'text',
'text' => 'ACME',
'tagline' => "Sor 1\nSor 2",
],
// vagy képes logó:
// 'logo' => ['type' => 'image', 'path' => public_path('logo.png'), 'height' => 64],
'host' => null, // null = az APP_URL hostja „www.” nélkül
'footer' => '+36 1 234 5678', // jobb alsó szöveg; ha változik, emeld a `version`-t!
],
],
Fontos kulcsok Hivatkozás erre a szakaszra
| Kulcs | Alapérték | Mire való |
|---|---|---|
secret |
OG_IMAGE_SECRET, ennek hiányában az APP_KEY-ből |
az URL-ek HMAC-aláírásának titka |
version |
OG_IMAGE_VERSION, '1' |
dizájnváltáskor emeld: minden URL és kép új lesz. Akkor is, ha a képre égetett adat (pl. telefonszám a footer-ben) változik |
url |
OG_IMAGE_URL, null = APP_URL |
a kép-URL-ek alapja (nem a kérés hostja, így queue-ból és CLI-ből is helyes) |
route.prefix |
og |
a kép-route előtagja |
route.middleware |
[] |
a kép-route middleware-jei |
cache_path |
public_path('og') |
hová kerülnek a képek. A prefix public mappája legyen, különben a webszerver nem tudja statikusan kiszolgálni őket |
cache_control |
public, max-age=31536000, immutable |
a mentett képek mellé írt .htaccess fejlécértéke |
formats |
['png', 'jpg'] |
engedélyezett formátumok |
default_format |
png |
fotós háttérnél a jpg ajánlott |
jpg_quality |
88 |
JPEG-minőség |
width / height |
1200 / 630 |
képméret |
limits |
title 140, kicker 40, path 160 karakter | az url() a hosszabbat levágja |
fonts |
null = mellékelt Montserrat ExtraBold / SemiBold |
statikus TTF kell, variable fonttal a GD rosszul rajzol |
images |
[] |
háttérképek kulcs → útvonal (biztonsági okból URL-ben csak kulcs) |
default_preset / presets |
default |
elnevezett dizájnok, lásd fent |
5. Bekötés a layoutba Hivatkozás erre a szakaszra
Alap: Blade-komponens a <head>-ben
Hivatkozás erre a szakaszra
<x-og-image::meta
:title="$title"
kicker="Blog"
:path="request()->getPathInfo()"
/>
Ez kiírja az og:image-et (+ og:image:type, width, height, alt), valamint a twitter:card=summary_large_image és a twitter:image tagot.
A komponens további propjai: preset, alt, format, overrides (pl. ['accent' => 'ff6600']).
Fix (nem generált) képnél:
<x-og-image::meta :url="asset('kep.jpg')" :title="$title" />
PHP-ból Hivatkozás erre a szakaszra
og_image_url('Cím', kicker: 'Blog', path: '/blog/x');
OgImage::url(['title' => 'Cím', 'kicker' => 'Blog', 'p' => 'dark', 'accent' => 'ff6600'], 'png');
URL-paraméterek: title (kötelező), kicker, path, p (preset), bg, fg, accent (6 jegyű hex), img (háttérkép-kulcs).
Bevált minta: og_title / og_kicker szekciók
Hivatkozás erre a szakaszra
Az oldalak opcionálisan megadják a képre kerülő szöveget:
{{-- resources/views/pages/szolgaltatasok.blade.php --}}
@extends('layouts.site')
@section('title', 'Szolgáltatásaink | Márka')
@section('og_kicker', 'Szolgáltatások')
@section('og_title', 'Minden, amire a projektednek szüksége van')
A layout ezekből, illetve a <title>-ből (a „ | Márka” utótag levágásával) és a canonical URL útvonalából építi a képet. Ha van adminban beállított fix OG-kép, az elsőbbséget kap:
{{-- resources/views/layouts/site.blade.php, <head> --}}
@php
$pageTitle = trim($__env->yieldContent('title'));
$ogTitle = trim($__env->yieldContent('og_title')) ?: \Illuminate\Support\Str::beforeLast($pageTitle, ' | ');
$ogKicker = trim($__env->yieldContent('og_kicker')) ?: null;
$canonical = url()->current();
@endphp
<link rel="canonical" href="{{ $canonical }}">
@if (filled($fixedOgImage ?? null)) {{-- pl. adminban feltöltött kép --}}
<x-og-image::meta :url="$fixedOgImage" :title="$ogTitle" />
@else
<x-og-image::meta
:title="$ogTitle"
:kicker="$ogKicker"
:path="parse_url($canonical, PHP_URL_PATH) ?: '/'"
/>
@endif
A
$fixedOgImagecsak példanév; ott a saját admin-meződ értékét használd. Élő referencia: a reszecskeszuro projektresources/views/layouts/site.blade.phpfájlja.
Tesztelés a host projektben Hivatkozás erre a szakaszra
Tesztben a cache_path mutasson ideiglenes mappára, és a teszt végén takarítsd ki:
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
beforeEach(function () {
config(['og-image.cache_path' => storage_path('framework/testing/og-'.Str::random(8))]);
});
afterEach(function () {
File::deleteDirectory(config('og-image.cache_path'));
});
it('aláírt og:image URL-t ír ki', function () {
$this->get('/')
->assertOk()
->assertSee('property="og:image"', false)
->assertSee('/og/', false);
});
6. Deploy és üzemeltetés Hivatkozás erre a szakaszra
-
Deploy után generáld le előre a képeket, így az első megosztás már kész fájlt talál:
Bash php artisan og:warm # APP_URL/sitemap.xml alapján php artisan og:warm https://example.com/sitemap.xml --limit=200A parancs minden sitemap-oldalt lekér, kiolvassa az
og:image-et, és helyben megrajzolja (alapértelmezett limit: 500 oldal). Sitemap-indexet egy szint mélységig követ. Feltétele egy működősitemap.xml. -
Régi képek törlése:
Bash php artisan og:clear # minden tárolt kép php artisan og:clear --older-than=90 # csak a 90 napja nem módosultakA törölt képek a következő kéréskor újra elkészülnek.
-
Dizájnváltás (szín, logó, háttér, footer-szöveg): emeld a
version-t (OG_IMAGE_VERSION), majd futtasd:php artisan config:cache,og:clear,og:warm. Új URL nélkül a közösségi oldalak a régi képet mutatják. -
Jogosultságok (shared hosting, suPHP/suEXEC): a csoport által írható fájlok 500-as hibát adnak. Deploy után futtasd a
chmod -R go-w .parancsot, de apublic/oga saját felhasználónak maradjon írható. -
Git és deploy: a
public/ogne kerüljön gitbe (.gitignore), és a deploy-szkript ne törölje.
7. Ellenőrzőlista — kész, ha… Hivatkozás erre a szakaszra
-
composer show 523service/laravel-og-imagea v1.x verziót mutatja, és vanconfig/og-image.php. - A
.gitignore-ban szerepel a/public/og/. - Az oldal forrásában az
og:imageegy aláírthttps://<domain>/og/<32 hex>.jpg?title=…URL (nemlocalhost, nem rosszwww). - Az URL megnyitva 200-at ad
image/jpeg(vagyimage/png) típussal, és a kép jól néz ki (ékezetek, tördelés, logó). - Létrejött a
public/og/<kulcs>.jpgés mellette apublic/og/.htaccess; a második kérés már statikus fájl (curl -Imutatja a hosszúCache-Control-t). - Egy aláírás nélküli vagy módosított URL 403-at ad.
- A
php artisan og:warmhiba nélkül lefut („… rendered, … already cached”). - A Facebook Sharing Debugger és a LinkedIn Post Inspector mutatja a képet.
8. Hibaelhárítás Hivatkozás erre a szakaszra
| Tünet | Ok | Megoldás |
|---|---|---|
| 403 a kép URL-jén | hibás vagy hiányzó aláírás (kézzel módosított query, megváltozott OG_IMAGE_SECRET / APP_KEY), ismeretlen preset (p), érvénytelen szín (nem 6 jegyű hex), ismeretlen img-kulcs |
Az URL-t mindig a komponenssel vagy a helperrel generáld. Ellenőrizd a preset nevét, a színeket és az images kulcsait, titokváltás után pedig futtasd a config:cache és az og:warm parancsot. |
| 500 a kép URL-jén | jogosultság (suPHP: group-writable fájl, vagy nem írható public/og), hiányzó GD vagy FreeType |
chmod -R go-w, public/og írható a saját usernek. php -r 'print_r(gd_info());'. Nézd meg a storage/logs/laravel.log-ot. |
| Minden kérés PHP-n megy át, nincs statikus kiszolgálás | a cache_path nem a route.prefix public mappája, vagy hiányzik a public/.htaccess rewrite-ja vagy az nginx try_files |
cache_path = public_path(<prefix>). Nginx: try_files $uri $uri/ /index.php?$query_string; |
| A közösségi oldal a régi képet mutatja | a crawler cache-eli a régi URL-t | Emeld a version-t (OG_IMAGE_VERSION), majd a Sharing Debuggerben nyomd meg a „Scrape Again” gombot. |
localhost vagy rossz www a kép-URL-ben |
rossz APP_URL, vagy cache-elt config |
Állítsd be az APP_URL-t (vagy az OG_IMAGE_URL-t), utána php artisan config:cache. |
| Ékezetek helyén négyzetek, vagy rossz betűvastagság | saját, ékezet nélküli vagy variable font | Statikus TTF kell, vagy maradj a mellékelt Montserratnál (fonts => null). |
| Túl nagy kép (~400 KB) | PNG fotós háttérrel | 'default_format' => 'jpg' (~120 KB) |
og:warm: „No pages found” |
nincs vagy üres a sitemap.xml |
Adj meg sitemap-URL-t argumentumként, vagy készíts sitemapet. |
composer require: a csomag nem található |
nincs felvéve a VCS-repó | Futtasd: composer config repositories.og-image vcs https://github.com/523service/laravel-og-image |
9. Hivatkozások Hivatkozás erre a szakaszra
- GitHub-repó: https://github.com/523service/laravel-og-image (README,
config/og-image.php, CHANGELOG — v1.0.0, 2026-10-22) - Referencia-projekt (reszecskeszuro):
config/og-image.php: éles presetresources/views/layouts/site.blade.php:og_title/og_kickerminta, fix kép elsőbbségetests/Feature/OgImageMetaTest.php: teszt ideiglenescache_path-szal
- Ellenőrzők: Facebook Sharing Debugger · LinkedIn Post Inspector
10. Claude Code prompt — bemásolható Hivatkozás erre a szakaszra
Ha a telepítést és a beállítást Claude Code-dal csinálod, nyisd meg a célprojektben, és másold be ezt a promptot. Előtte érdemes kitölteni a végén lévő három adatot (szín, logó, lábléc); ha üresen hagyod, a Claude rákérdez.
Task: install and configure the 523service/laravel-og-image package in THIS Laravel project, so that every public page gets its own signed, file-cached 1200x630 Open Graph image (rendered with GD, no headless browser).
Source of truth: https://github.com/523service/laravel-og-image (README.md, config/og-image.php, CHANGELOG.md). Step-by-step guide: https://523.hu/knowledge/laravel-og-image-beallitasa. Read the repo README and config before changing anything. Do not invent options, parameters or commands that are not in the package.
1. Investigate first (read-only):
- Follow this project's CLAUDE.md / conventions (tests, formatter, docs, commit rules).
- Check PHP >= 8.2, Laravel 11 or 12, and that ext-gd has FreeType + JPEG/PNG support (php -r "print_r(gd_info());"). Stop and tell me if something is missing.
- Find the public layout(s) and how <title>, meta description and canonical URL are built. List any existing og:image / twitter:image tags and any admin field for a fixed share image.
- Check whether a sitemap.xml exists (needed by og:warm).
- Look for brand colours, logo files and contact data (phone) in the CSS, config and views.
2. Install (the package is NOT on Packagist, use the VCS repository):
composer config repositories.og-image vcs https://github.com/523service/laravel-og-image
composer require 523service/laravel-og-image:^1.0
php artisan vendor:publish --tag=og-image-config
Add /public/og/ to .gitignore.
Add OG_IMAGE_VERSION=1 to .env.example (and OG_IMAGE_SECRET= / OG_IMAGE_URL= empty, with a short comment). Never write real secret values anywhere.
3. Configure config/og-image.php:
- Create one preset for the brand and set it as default_preset: background, foreground, accent, muted (6-digit hex without #), optional background photo via the images key map (key => public_path(...), only keys in URLs), overlay, logo (text logo with optional tagline, or image logo with path + height), host (null = APP_URL host without www), footer (e.g. phone number).
- Use default_format jpg if the preset has a photo background, otherwise png is fine.
- Keep the bundled Montserrat fonts unless the project already ships STATIC TTF fonts (no variable fonts).
- Keep cache_path as the public directory of route.prefix.
4. Wire it into the layout <head>:
- Use <x-og-image::meta :title="..." :kicker="..." :path="..." />.
- Pattern: pages may define @section('og_title') and @section('og_kicker'); otherwise the title comes from the page <title> with the " | Brand" suffix stripped, and the path from the canonical URL.
- If the project has a fixed / admin-uploaded share image, it takes priority: <x-og-image::meta :url="..." :title="..." />.
- Remove the old, duplicated og:image / twitter:image / twitter:card tags. Keep og:title, og:description etc.
- Add og_kicker (and og_title where the page title is too long or too generic) to the main public pages.
5. Tests (in this project's test framework and style):
- In tests, point og-image.cache_path to a temporary directory (e.g. storage_path('framework/testing/og-<random>')) and delete it afterwards.
- Cover: the layout prints a signed /og/<32 hex>.<jpg|png> og:image URL and twitter:card=summary_large_image; og_title / og_kicker are used; the fixed image wins when set; the image URL returns 200 with the right content type and writes the file; a tampered URL returns 403.
- Run only the affected test files, run the code formatter, and fix failures.
6. Finish:
- Update the project docs/changelog if the project rules require it.
- Do NOT commit, push or deploy unless I ask. Tell me the deploy steps instead:
php artisan config:cache; php artisan og:warm (needs sitemap.xml); keep public/og writable and out of git, the deploy must not delete it; on suPHP/suEXEC shared hosting run chmod -R go-w after deploy (group-writable files give 500); bump OG_IMAGE_VERSION whenever the design or burned-in data (e.g. the footer phone number) changes, then og:clear + og:warm; check with the Facebook Sharing Debugger and LinkedIn Post Inspector.
- Report: changed files, the chosen preset values, and anything you could not verify.
Stop and ask me if: the layout structure is unclear, there are several unrelated layouts, an existing OG image solution conflicts with this one, or brand values below are missing and cannot be found in the project.
Brand values (fill in or leave empty):
- Colours (background / foreground / accent / muted):
- Logo (text + tagline, or image file path):
- Footer text (e.g. phone number):
Forrás
GitHub