Using content representations to create OG images
Have you ever wondered why some links when shared on social media have a link preview and some do not? The magic behind this is the Open Graph protocol, and this recipe provides a boilerplate to easily create OG images for your Kirby website with content representations.
Open Graph introduction
The Open Graph protocol was originally created by Meta (formerly Facebook). The protocol enables any web page to become a rich object in a social graph. For instance, this is used on Social Media to standardize the use of metadata within a webpage to represent the content of a page.
HTML markup
The basic HTML markup within the <head>
element looks like the following:
<meta property="og:site_name" content="Kirby CMS">
<meta property="og:url" content="https://getkirby.com/docs/cookbook/content/dynamic-og-images">
<meta property="og:type" content="website">
<meta property="og:title" content="Using content representations to create OG images">
<meta property="og:description" content="Dynamic creation of Open Graph images for social sharing">
<meta property="og:image" content="https://getkirby.com/docs/cookbook/content/dynamic-og-images/opengraph.png">
Image preview
The code snippet above is the same as the one that used for this cookbook recipe, and when you share it on social media, the link preview will look something like this:
![Open Graph image generated from getkirby.com website](https://v38.getkirby.com/media/pages/docs/cookbook/content/dynamic-og-images/6152f39d9a-1704284612/kirby-opengraph-960x.png)
Content representations
While the above example works great on the Kirby CMS website with a custom plugin (check it out on GitHub), a simplified approach is to use content representations to generate these OG images. This approach works well if you only need custom OG images for a single page type.
There is a great guide about content representations you should check out first.
Requirements
Using content representations for OG image generation will only work if you use a dedicated template, e.g. for your blog articles.
See the templates guide in case you are not familar with templates yet.
site
templates
- article.php
- note.php
- default.php
In case you are already using template files and your filesystem looks like the example above you are good to go!
Setup
First, create a new content representations template file, e.g. article.png.php
. This allows you to create various OG images with .png
extension for the given template.
site
templates
- article.php
- article.png.php
- note.php
Image rendering
There are tons of possibilities now to create and manipulate images with PHP. Check out the GD and Image Functions of PHP. The only limit is your creativity!
- Let's start with defining the canvas size for the image:
$canvas = imagecreatetruecolor(1200, 628);
The recommended aspect ratio for an OG image is 1.91:1, but many tutorials out there refer to a format of 1200x630 pixels. However, 1200x628 yields a closer aspect ratio and is therefore preferred.
- Define some variables, e.g. for colors or fonts:
$backgroundColor = imagecolorallocate($canvas, 255, 255, 255); // white
$textColor = imagecolorallocate($canvas, 66, 66, 66);
$fontFile = './assets/fonts/oswald.ttf';
- Set the background color:
imagefill($canvas, 0, 0, $backgroundColor);
- Print the page title to the image:
$title = $page->title()->toString();
$title = wordwrap($title, 30); // default value for third parameter $break = "\n"
imagefttext($canvas, 50, 0, 150, 185, $textColor, $fontFile, $title);
- Finally, return the
.png
image:
imagepng($canvas);
imagedestroy($canvas); // This function has no effect. Before PHP 8.0.0, this function was used to close the resource.
The basic OG image using only text will look like this:
![Open Graph image with only text generated with content representations](https://v38.getkirby.com/media/pages/docs/cookbook/content/dynamic-og-images/8fcbf0cc43-1704284612/textonly-opengraph-960x.png)
Add more flavor to the image
For example, a colored rectangle:
$brandColor = imagecolorallocate($canvas, 246, 211, 85);
imagefilledrectangle($canvas, 100, 100, 115, 525, $brandColor);
And a logo:
$logoFile = './assets/kirby-logo.png';
$logo = imagecreatefrompng($logoFile);
imagecopyresampled($canvas, $logo, 975, 400, 0, 0, imagesx($logo), imagesy($logo), imagesx($logo), imagesy($logo));
![Open Graph image generated with content representations](https://v38.getkirby.com/media/pages/docs/cookbook/content/dynamic-og-images/315bd4bbe7-1704284612/flavour-opengraph-960x.png)
Finally, adjust the markup of your HTML head
<meta property="og:site_name" content="<?= $site->title()->html() ?>">
<meta property="og:url" content="<?= $page->url() ?>">
<meta property="og:type=" content="website">
<meta property="og:title" content="<?= $page->title()->html() ?>">
<meta property="og:description" content="<?= $page->description()->html() ?>">
<meta property="og:image:type" content="image/png">
<!-- Use og:image for your template or a fallback image -->
<meta property="og:image" content="<?= e($page->template()->name() === 'article', $page->url() . '.png', 'https://yourdomain.tld/opengraph.png') ?>">
Full template code
<?php
// Define canvas size
$canvas = imagecreatetruecolor(1200, 628);
// Define colors
$brandColor = imagecolorallocate($canvas, 246, 211, 85);
$backgroundColor = imagecolorallocate($canvas, 255, 255, 255);
$textColor = imagecolorallocate($canvas, 66, 66, 66);
// Set background
imagefill($canvas, 0, 0, $backgroundColor);
// Draw rectangle
imagefilledrectangle($canvas, 100, 100, 115, 525, $brandColor);
// Path to .ttf font file
$fontFile = './assets/fonts/arial.ttf';
// Write page title to canvas
$title = $page->title()->toString();
$title = wordwrap($title, 30);
imagefttext($canvas, 50, 0, 150, 185, $textColor, $fontFile, $title);
// Place logo in the corner
$logoFile = './assets/kirby-logo.png';
$logo = imagecreatefrompng($logoFile);
imagecopyresampled($canvas, $logo, 975, 400, 0, 0, imagesx($logo), imagesy($logo), imagesx($logo), imagesy($logo));
// Output image to the browser
imagepng($canvas);
imagedestroy($canvas);
Make sure that all paths to fonts and files as well as fieldnames used actually exist in your installation, otherwise this will not work as expected.