DH
David Hellmann
2017/09/20

Craft CMS — Create custom share images with your company logo

Craft Square Logo

On our Agency Website we thought about how we could watermark our share images to get them a bit more fancy. When a user shares a post on Facebook, now the image has a small watermark in the right top corner. In our case it’s the agency logo. How did we do that? It sounds simple but you need some stuff to get the shit done.

First you need two plugins installed for this solution. These two are — in my view — indispensable for Craft CMS.

A third plugin is not essential but nice to have. Just copy and paste fields and stuff like that from one Craft CMS site to another one.

OK, now when you’ve installed the plugins we‘ve to start creating some fields that we need. I pasted the architect exported code here, you can simply paste it into your site with some modifications (naming…) or you create these fields on your own. As you like. All the paths and naming things are for my installation here. Please check and modify.

The Fields

Global: Logo
This is the logo field where we store the logo that we put later in the layer above the image.

      
        {
    "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"
                ]
            }
        }
    ]
}
      
    

Single: Image Entry

This is the field that is included in each entry. Maybe you know it from WordPress as the Post Thumbnail. It's nearly the same. An image that describes the entry.

      
        {
    "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": ""
            }
        }
    ]
}
      
    

So, now we have the fields and the globals created. You have to assign the Single Image Entry to all the Posts where you need custom share images. So, lets take a look into the code…

The Coding Part

First we check if the Single Image Entry, the default Seo Image and also the Global Logo are all defined and filled. If that's the case we are going further.

      
        {% 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 %} 
      
    

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

      
          {# -- 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 %}
      
    

Next step is to check the Single Image Entry if it's filled and when this is true, we save it to the image variable. If not, we use the default Seo Image and save it to the image variable. Now we set the width and height, the jpegQuality and the cropping position for this image. This is also made with imager. Now we store the URL for this image in our imageEntry variable.

      
          {# -- 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 %}
      
    

Next step is to merge the two images. Nothing special here. Again we use imager to do that. We set our image size and use the watermark function for positioning our logo above the image. In our case at the top right corner with 30px margin to the edges. We also save this Url to a variable  shareIamge.

      
          {# -- 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 %}
      
    

Last part is to check if the shareImage variable is filled, if it's true we overwrite some of the Seomatic Data. In our case the og:image, the seoImage and the twitter image. That's it!

      
          {# -- 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 %}
      
    

If you did everything right your output is an Image like this:

Custom Shared Image
Custom Shared Image

The Final Code

This code hast to be included before you trigger "Seomatic". That's important!

      
        {# -- 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 %} 
      
    

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

comments powered by Disqus

Maybe interesting…

UP