Skip to content

Social Overrides

This solution uses a custom Python plugin that:

Identifies pages with custom images in their metadata Processes the HTML after it's generated Finds and replaces the social plugin's meta tags with your custom image URLs

This approach is robust because:

It works with any version of mkdocs-material It doesn't rely on JavaScript that might not be executed by social media crawlers It directly modifies the final HTML output It only affects pages where you've defined a custom image

To add custom images to any page, simply include the image property in the page's front matter:

Installation

in the plugins folder create two files:

plugins/init.py plugins/social_overview.py

Setup

Place the following code into setup.py in the project root (not in docs)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from setuptools import setup, find_packages

setup(
    name='social_override',
    version='0.1',
    packages=find_packages(),
    entry_points={
        'mkdocs.plugins': [
            'social_override = plugins.social_override:SocialOverridePlugin',
        ]
    }
)

Run the setup:

1
pip install -e . 

Sample terminal log:

1
2
3
4
5
6
7
8
9
Obtaining file:///Users/danmccreary/Documents/ws/mkdocs-material-social
  Preparing metadata (setup.py) ... done
Installing collected packages: social-override
  Attempting uninstall: social-override
    Found existing installation: social-override 0.1
    Uninstalling social-override-0.1:
      Successfully uninstalled social-override-0.1
  Running setup.py develop for social-override
Successfully installed social-override-0.1

Page Setup

Add the following to your markdown file that you DO NOT want the social card to be used. This will use a file called my-custom-image.png in the img directory.

1
2
3
4
5
---
title: Page Title
description: Page description
image: img/my-custom-image.png
---

Note that the file should have a width to height ratio of 1.91 to 1. You can use the src/resize program to resize the image to have a white background to get the correct ratio.

Testing

After you run mkdocs gh-deploy you can test the social card previews with these tools:

SocialSharePreview.com

Metatags.io

Source Code for Social Override Plugin (no debug)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
from mkdocs.plugins import BasePlugin
import re

class SocialOverridePlugin(BasePlugin):
    def on_page_context(self, context, page, config, **kwargs):
        """Save custom image path from page metadata if it exists"""
        if page.meta and 'image' in page.meta:
            page.custom_image = page.meta['image']
        return context

    def on_post_page(self, html, page, config, **kwargs):
        """Replace social plugin meta tags with our custom image"""
        # Only process pages with custom image
        if not hasattr(page, 'custom_image'):
            return html

        # Build the full URL for the custom image
        site_url = config['site_url'].rstrip('/')
        image_path = '/' + page.custom_image.lstrip('/')
        full_image_url = site_url + image_path

        # Find and replace OpenGraph image tags
        og_tags = re.findall(r'<meta\s+property="og:image"[^>]*?>', html)
        for tag in og_tags:
            if '/assets/images/social/' in tag:
                new_tag = f'<meta property="og:image" content="{full_image_url}">'
                html = html.replace(tag, new_tag)

        # Find and replace Twitter image tags
        twitter_tags = re.findall(r'<meta\s+name="twitter:image"[^>]*?>', html)
        for tag in twitter_tags:
            if '/assets/images/social/' in tag:
                new_tag = f'<meta name="twitter:image" content="{full_image_url}">'
                html = html.replace(tag, new_tag)

        return html

# Make the plugin available to MkDocs
def get_plugin():
    return SocialOverridePlugin()

Social Override With Debug

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
from mkdocs.plugins import BasePlugin
import re
import os

class SocialOverridePlugin(BasePlugin):
    def on_page_context(self, context, page, config, **kwargs):
        """Save custom image path from page metadata if it exists"""
        if page.meta and 'image' in page.meta:
            page.custom_image = page.meta['image']
            # print(f"DEBUG: Found custom image in {page.file.src_path}: {page.custom_image}")
        return context

    def on_post_page(self, html, page, config, **kwargs):
        """Replace social plugin meta tags with our custom image"""
        # Only process pages with custom image
        if not hasattr(page, 'custom_image'):
            return html

        # Build the full URL for the custom image
        site_url = config['site_url'].rstrip('/')
        image_path = '/' + page.custom_image.lstrip('/')
        full_image_url = site_url + image_path

        # print(f"DEBUG: Processing page {page.file.src_path} with custom image: {full_image_url}")

        # Check if social plugin tags exist in the HTML
        if '/assets/images/social/' in html:
            print(f"DEBUG: Found social plugin tags in HTML for {page.file.src_path}")
        else:
            print(f"DEBUG: No social plugin tags found in HTML for {page.file.src_path}")

        # Direct approach with simpler tag finding
        og_tags = re.findall(r'<meta\s+property="og:image"[^>]*?>', html)
        twitter_tags = re.findall(r'<meta\s+name="twitter:image"[^>]*?>', html)

        print(f"DEBUG: Found {len(og_tags)} og:image tags and {len(twitter_tags)} twitter:image tags")

        # Replace og:image tags
        for tag in og_tags:
            if '/assets/images/social/' in tag:
                new_tag = f'<meta property="og:image" content="{full_image_url}">'
                html = html.replace(tag, new_tag)
                print(f"DEBUG: Replaced og:image tag")

        # Replace twitter:image tags
        for tag in twitter_tags:
            if '/assets/images/social/' in tag:
                new_tag = f'<meta name="twitter:image" content="{full_image_url}">'
                html = html.replace(tag, new_tag)
                print(f"DEBUG: Replaced twitter:image tag")

        return html

# Make the plugin available to MkDocs
def get_plugin():
    return SocialOverridePlugin()

Claude Dialog

Claud Override Trials and Final Plugin - a log of the dozens of solutions we tried with Claude using overrides.