---
title: "Craft CMS — Create custom share images with your company logo"
date: "9/20/2017, 10:52 PM"
category: "Development"
topics: ["craft cms", "tutorial", "twig", "sharing"]
canonical: "https://sveltekit.davidhellmann.com/blog/craft-cms-create-custom-share-images-with-your-company-logo"
section: "blog"
---

# Craft CMS — Create custom share images with your company logo

<p>We considered watermarking the images we shared on our agency website to make them more fancy. When a user shares a post on Facebook, now the image has a small watermark in the top right corner. In our case, it’s the agency logo. How did we do that? It sounds simple, but you need some stuff to complete it.</p><p>First, you need to install two plugins for this solution. These two are indispensable for Craft CMS. </p><ul><li><a href="https://github.com/nystudio107/seomatic/">SEOmatic</a></li><li><a href="https://github.com/aelvan/Imager-Craft">Imager</a></li></ul><p>A third plugin is not essential but is nice to have. You can copy and paste fields and stuff like that from one Craft CMS site to another.</p><ul><li><a href="https://github.com/Pennebaker/craftcms-thearchitect">The Architect</a></li></ul><p>OK, now that you’ve installed the plugins, we‘ve got to start creating some fields that we need. I pasted the architect's exported code here. You can simply paste it into your site with some modifications (naming…), or you can create these fields on your own, as you like. All the paths and naming things are for my installation here. Please check and modify.</p><h2>The Fields</h2><p><strong>Global: Logo</strong><br />This is the logo field where we store the logo that we put later in the layer above the image. </p>

```json
{
    "groups": [
        "Globals"
    ],
    "fields": [
        {
            "group": "Globals",
            "name": "Global: Logo",
            "handle": "globalLogo",
            "instructions": "",
            "required": false,
            "type": "Assets",
            "typesettings": {
                "useSingleFolder": 1,
                "sources": "*",
                "defaultUploadLocationSource": "siteImages",
                "defaultUploadLocationSubpath": "",
                "singleUploadLocationSource": "siteGraphics",
                "singleUploadLocationSubpath": "",
                "restrictFiles": 1,
                "allowedKinds": [
                    "image"
                ],
                "limit": 1,
                "viewMode": "large",
                "selectionLabel": ""
            }
        }
    ],
    "globals": [
        {
            "name": "Logo",
            "handle": "logo",
            "fieldLayout": {
                "Content": [
                    "globalLogo"
                ]
            }
        }
    ]
}
```

<p><strong>Single: Image Entry</strong></p><p>This is the field that is included in each entry. Maybe you know it from WordPress as the <strong>Post Thumbnail</strong>. It's nearly the same. An image that describes the entry. </p>

```json
{
    "groups": [
        "Singles"
    ],
    "fields": [
        {
            "group": "Singles",
            "name": "Single: Image Entry",
            "handle": "singleImageEntry",
            "instructions": "",
            "required": false,
            "type": "Assets",
            "typesettings": {
                "useSingleFolder": 1,
                "sources": "*",
                "defaultUploadLocationSource": "siteImages",
                "defaultUploadLocationSubpath": "",
                "singleUploadLocationSource": "siteImages",
                "singleUploadLocationSubpath": "",
                "restrictFiles": 1,
                "allowedKinds": [
                    "image"
                ],
                "limit": 1,
                "viewMode": "list",
                "selectionLabel": ""
            }
        }
    ]
}
```

<p>Now that we have the fields and globals created, you have to assign the <strong>Single Image Entry</strong> to all the Posts where you need custom share images. Let's take a look at the code…</p><h2>The Coding Part</h2><p>First, we check if the <strong>Single Image Entry</strong>, the default <strong>SEO image,</strong> and the <strong>Global Logo</strong> are all defined and filled. If that's the case, we proceed.</p>

```twig
{% if (
  (entry.singleImageEntry is defined and entry.singleImageEntry | length) or
  (seomaticSiteMeta.siteSeoImage is defined and seomaticSiteMeta.siteSeoImage | length )
  ) and (logo.globalLogo is defined and logo.globalLogo | length) %}


{% endif %} 
```

<p>Next, we query the <strong>Global Logo</strong> and set the <strong>width</strong> and <strong>height</strong> of the image, and get the URL of this one to save it into the <strong>watermarkImage</strong> variable. The image creation is made with imager.</p>

```twig
  {# -- Set Logo -- #}
  {% set logo = logo.globalLogo.first() %}

  {# -- Imager: Watermark Image -- #}
  {% set watermarkImage = craft.imager.transformImage(logo, [
    {
      width: 100,
      height: 100
    }])
  %}

  {# -- Watermark Image URL -- #}
  {% set watermarkImage = watermarkImage[0].url %}
```

<p>The next step is to check the <strong>Single Image Entry</strong> to see if it's filled, and when this is true, we save it to the <strong>image</strong> variable. If not, we save the default <strong>Seo Image</strong> to the <strong>image</strong> variable. Now, we set this image's <strong>width</strong> and <strong>height</strong>, the <strong>jpeg quality,</strong> and the cropping position. This is also made with imager. Now, we store the URL for this image in our <strong>imageEntry</strong> variable.</p>

```twig
  {# -- Check if Entry Image exists or use the default SEO Image -- #}
  {% if entry.singleImageEntry | length %}
    {% set image = entry.singleImageEntry.first() %}
  {% else %}
    {% set image = seomaticSiteMeta.siteSeoImage %}
  {% endif %}

  {# -- Imager: Entry / Default Image -- #}
  {% set imageEntry = craft.imager.transformImage(image, [
    {
      width: 1200,
      height: 630
    }], {
      jpegQuality: 100,
      mode: 'crop',
      position: '50% 50%'
    })
  %}

  {# -- Entry / Default Image URL -- #}
  {% set imageEntry = imageEntry[0].url %}
```

<p>The next step is to merge the two images. Nothing special here. Again, we use an imager to do that. We set our image size and use the <strong>watermark</strong> function to position our logo above the image. In our case, at the top right corner with a 30px margin to the edges. We also save this URL to a variable:  shareIamge.</p>

```twig
  {# -- Imager: Share Image -- #}
  {% set shareIamge = craft.imager.transformImage(imageEntry, [
    {
      width: 1200,
      height: 630
    }], {
      jpegQuality: 100,
      mode: 'crop',
      watermark: {
        image: watermarkImage,
        width: 100,
        height: 100,
        position: {
          left: 30,
          bottom: 30,
          opacity: 0.8
        }
      }
    })
  %}

  {# -- Share Image URL -- #}
  {% set shareIamge = shareIamge[0].url %}
```

<p>The last part checks if the <strong>shareImage</strong> variable is filled out, and if it's true, we overwrite some of the Seomatic Data. In our case, the <strong>og:image</strong>, the <strong>seoImage,</strong> and the <strong>twitter image</strong>. That's it!</p>

```twig
  {# -- If Share Image exists -- #}
  {% if shareIamge | length %}

    {# -- Set Twitter Share Image -- #}
    {% if seomaticMeta.twitter is defined and seomaticMeta.twitter is not empty %}
      {% set twitter = seomaticMeta.twitter %}
      {% set twitter = twitter | merge({'image': siteUrl|trim('/', 'right') ~ shareIamge}) %}
      {% set seomaticMeta = seomaticMeta | merge({'twitter': twitter}) %}
    {% endif %}

    {# -- Set Default Share Image -- #}
    {% set seomaticMeta = seomaticMeta | merge({'seoImage': siteUrl|trim('/', 'right') ~ shareIamge}) %}

    {# -- Set Facebook Share Image -- #}
    {% if seomaticMeta.og is defined and seomaticMeta.og is not empty %}
      {% set og = seomaticMeta.og %}
      {% set og = og | merge({
        'image': siteUrl|trim('/', 'right') ~ shareIamge,
        'image:width': '1200',
        'image:height': '630',
        'image:type': 'image/jpeg'
      }) %}
      {% set seomaticMeta = seomaticMeta | merge({'og': og}) %}
    {% endif %}
  {% endif %}
```

<p>If you did everything right your output is an Image like this:</p>

![Custom shared image](https://static.davidhellmann.com/assets/com_davidhellmann/images/blog/craft-cms-create-custom-share-images-with-your-company-logo/custom-shared-image.jpg)

<h2>The Final Code</h2><p>This code has to be included before you trigger "Seomatic". That's important!</p>

```twig
{# -- Custom Social Image -- #}
{% if (
  (entry.singleImageEntry is defined and entry.singleImageEntry | length) or
  (seomaticSiteMeta.siteSeoImage is defined and seomaticSiteMeta.siteSeoImage | length )
  ) and (logo.globalLogo is defined and logo.globalLogo | length) %}

  {# -- Set Logo -- #}
  {% set logo = logo.globalLogo.first() %}

  {# -- Imager: Watermark Image -- #}
  {% set watermarkImage = craft.imager.transformImage(logo, [
    {
      width: 100,
      height: 100
    }])
  %}

  {# -- Watermark Image URL -- #}
  {% set watermarkImage = watermarkImage[0].url %}

  {# -- Check if Entry Image exists or use the default SEO Image -- #}
  {% if entry.singleImageEntry | length %}
    {% set image = entry.singleImageEntry.first() %}
  {% else %}
    {% set image = seomaticSiteMeta.siteSeoImage %}
  {% endif %}

  {# -- Imager: Entry / Default Image -- #}
  {% set imageEntry = craft.imager.transformImage(image, [
    {
      width: 1200,
      height: 630
    }], {
      jpegQuality: 100,
      mode: 'crop',
      position: '50% 50%'
    })
  %}

  {# -- Entry / Default Image URL -- #}
  {% set imageEntry = imageEntry[0].url %}

  {# -- Imager: Share Image -- #}
  {% set shareIamge = craft.imager.transformImage(imageEntry, [
    {
      width: 1200,
      height: 630
    }], {
      jpegQuality: 100,
      mode: 'crop',
      watermark: {
        image: watermarkImage,
        width: 100,
        height: 100,
        position: {
          right: 30,
          top: 30,
          opacity: 0.8
        }
      }
    })
  %}

  {# -- Share Image URL -- #}
  {% set shareIamge = shareIamge[0].url %}

  {# -- If Share Image exists -- #}
  {% if shareIamge | length %}

    {# -- Set Twitter Share Image -- #}
    {% if seomaticMeta.twitter is defined and seomaticMeta.twitter is not empty %}
      {% set twitter = seomaticMeta.twitter %}
      {% set twitter = twitter | merge({'image': siteUrl|trim('/', 'right') ~ shareIamge}) %}
      {% set seomaticMeta = seomaticMeta | merge({'twitter': twitter}) %}
    {% endif %}

    {# -- Set Default Share Image -- #}
    {% set seomaticMeta = seomaticMeta | merge({'seoImage': siteUrl|trim('/', 'right') ~ shareIamge}) %}

    {# -- Set Facebook Share Image -- #}
    {% if seomaticMeta.og is defined and seomaticMeta.og is not empty %}
      {% set og = seomaticMeta.og %}
      {% set og = og | merge({
        'image': siteUrl|trim('/', 'right') ~ shareIamge,
        'image:width': '1200',
        'image:height': '630',
        'image:type': 'image/jpeg'
      }) %}
      {% set seomaticMeta = seomaticMeta | merge({'og': og}) %}
    {% endif %}
  {% endif %}
{% endif %} 
```

<p>Maybe someone has another (better) approach for this kind of „problem“. Drop me a line. I’m interested in other solutions. </p>
