-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #8 from goatbytes/develop
meta: Improve generating proper meta tags for open graph and X (Twitter)
- Loading branch information
Showing
3 changed files
with
107 additions
and
45 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,57 +1,119 @@ | ||
from typing import Dict, List, Optional, Tuple | ||
from mkdocs.plugins import BasePlugin | ||
from mkdocs.config import config_options | ||
import os | ||
|
||
|
||
class DefaultMetaPlugin(BasePlugin): | ||
# A mapping for special case language names | ||
SPECIAL_CASES = { | ||
'typescript': 'TypeScript', | ||
'javascript': 'JavaScript', | ||
'csharp': 'C#', | ||
'objective-c': 'Objective-C', | ||
""" | ||
An MkDocs plugin that automatically generates and updates meta tags | ||
for pages with enhanced descriptions, keywords, and Open Graph properties. | ||
""" | ||
|
||
LANGUAGES: Dict[str, str] = { | ||
'cpp': 'C++', 'c': 'C', 'csharp': 'C#', 'css': 'CSS', 'dart': 'Dart', 'go': 'Go', | ||
'html': 'HTML', 'java': 'Java', 'javascript': 'JavaScript', 'json': 'JSON', | ||
'kotlin': 'Kotlin', 'markdown': 'Markdown', 'objective-c': 'Objective-C', | ||
'php': 'PHP', 'python': 'Python', 'ruby': 'Ruby', 'rust': 'Rust', 'scala': 'Scala', | ||
'shell': 'Shell', 'sql': 'SQL', 'swift': 'Swift', 'typescript': 'TypeScript', | ||
} | ||
|
||
PAGE_TITLES: Dict[str, str] = { | ||
'index': 'Home', 'about': 'About', 'contributing': 'Contributing', | ||
'foundation': 'Foundational Code Standards', | ||
} | ||
|
||
def format_language_name(self, filename): | ||
DEFAULT_KEYWORDS: List[str] = [ | ||
'Coding Standards', 'Programming Best Practices', 'Coding Guidelines', | ||
'Software Development', 'Code Quality', 'Software Engineering Principles', | ||
'Code Review Standards', 'Code Style', 'Source Code formatting', | ||
'Programming Language Style', 'Clean Code Principles', 'Development Guidelines', | ||
'Best Coding Practices', 'Coding Style Guides', 'Software Craftsmanship', | ||
'Code Consistency', 'GoatBytes.IO', 'GoatStyles', 'GoatBytes', | ||
] | ||
|
||
SITE_DESC: str = ("GoatStyles is an authoritative resource dedicated to promoting " | ||
"best practices and consistency in coding across various programming " | ||
"languages. As a comprehensive style guide repository created by " | ||
"GoatBytes.IO, it aims to elevate code quality and readability for " | ||
"developers worldwide.") | ||
|
||
def __init__(self): | ||
self.site_url: Optional[str] = None | ||
self.keywords: List[str] = [] | ||
|
||
def on_config(self, config): | ||
"""Handles configuration to set site-wide settings.""" | ||
self.site_url = config.get('site_url', 'https://styles.goatbytes.io') | ||
# Reset keywords to default at the start of each build to avoid accumulation | ||
self.keywords = self.DEFAULT_KEYWORDS.copy() | ||
|
||
def format_language_name(self, filename: str) -> str: | ||
"""Format language name correctly based on filename.""" | ||
language = os.path.splitext(filename)[0] | ||
return self.SPECIAL_CASES.get(language, language.capitalize()) | ||
|
||
def on_page_markdown(self, markdown, page, config, files): | ||
# Basic site info | ||
site_url = config.get('site_url', 'https://styles.goatbytes.io') | ||
default_image = f"{site_url}assets/img/social.jpg" | ||
|
||
# Extract and format the language name from the file name | ||
language = self.format_language_name(os.path.basename(page.file.src_path)) | ||
custom_title = f"{language} Code Style Guide | GoatStyles" | ||
custom_description = f"The official {language} code style guide used by GoatBytes.IO." | ||
|
||
# Default meta tags with dynamic title and description | ||
defaults = [ | ||
{'name': 'description', 'content': custom_description}, | ||
{'property': 'og:type', 'content': 'website'}, | ||
{'property': 'og:title', 'content': custom_title}, | ||
{'property': 'og:description', 'content': custom_description}, | ||
{'property': 'og:image', 'content': default_image}, | ||
{'property': 'og:url', 'content': site_url}, | ||
{'name': 'twitter:card', 'content': 'summary_large_image'}, | ||
{'name': 'twitter:title', 'content': custom_title}, | ||
{'name': 'twitter:description', 'content': custom_description}, | ||
{'name': 'twitter:image', 'content': default_image}, | ||
base = os.path.splitext(filename)[0] | ||
return self.LANGUAGES.get(base, base.capitalize()) | ||
|
||
def get_language_keywords(self, language: str) -> List[str]: | ||
"""Generate keywords specific to a programming language.""" | ||
return [ | ||
f"{language} Style Guide", | ||
f"{language} Syntax Rules", | ||
f"{language} Coding Conventions" | ||
] | ||
|
||
# Initialize or update page meta | ||
if 'meta' not in page.meta: | ||
page.meta['meta'] = defaults | ||
def format_page_title_and_description(self, filename: str) -> Tuple[str, str]: | ||
"""Generate title and description based on filename.""" | ||
base, _ = os.path.splitext(filename) | ||
if base in self.PAGE_TITLES: | ||
title = self.PAGE_TITLES[base] | ||
description = self.SITE_DESC | ||
elif base in self.LANGUAGES: | ||
lang = self.LANGUAGES[base] | ||
# Extend keywords list with language-specific keywords | ||
self.keywords.extend(self.get_language_keywords(lang)) | ||
title = f"{lang} Code Style Guide" | ||
description = (f"Explore the official {lang} coding conventions " | ||
"and best practices used by GoatBytes.IO.") | ||
else: | ||
# Update existing tags or add defaults if missing | ||
existing_tags = {tag.get('name') or tag.get('property'): tag for tag in page.meta['meta']} | ||
for default in defaults: | ||
key = default.get('name') or default.get('property') | ||
if key not in existing_tags: | ||
page.meta['meta'].append(default) | ||
elif key in ['description', 'og:title', 'og:description', 'twitter:title', 'twitter:description']: | ||
# Update content for specific tags if they already exist | ||
existing_tags[key]['content'] = default['content'] | ||
title = 'GoatStyles Documentation' | ||
description = self.SITE_DESC | ||
return title, description | ||
|
||
def on_page_markdown(self, markdown: str, page, config, files) -> str: | ||
"""Add meta tags to page based on content.""" | ||
default_image = f"{self.site_url}/assets/img/goatstyles.png" | ||
page_title, custom_description = self.format_page_title_and_description( | ||
os.path.basename(page.file.src_path) | ||
) | ||
|
||
# Ensure proper formatting and prevent duplication of meta tags | ||
defaults = self.generate_default_meta(page_title, custom_description, default_image) | ||
|
||
# Initialize or update page meta | ||
page.meta.setdefault('meta', []).extend( | ||
[tag for tag in defaults if tag not in page.meta['meta']] | ||
) | ||
|
||
return markdown | ||
|
||
def generate_default_meta(self, title: str, description: str, image: str) -> List[Dict]: | ||
"""Generates a list of default meta tags.""" | ||
|
||
# Ensure the image URL does not have double slashes (except after "http:") | ||
image = image.replace("//assets", "/assets") | ||
return [ | ||
{'name': 'description', 'content': description}, | ||
{'name': 'keywords', 'content': ', '.join(self.keywords)}, | ||
{'property': 'og:type', 'content': 'website'}, | ||
{'property': 'og:url', 'content': self.site_url}, | ||
{'property': 'og:site_name', 'content': 'GoatStyles'}, | ||
{'property': 'og:title', 'content': title}, | ||
{'property': 'og:description', 'content': description}, | ||
{'property': 'og:image', 'content': image}, | ||
{'property': 'og:image:type', 'content': 'image/png'}, | ||
{'property': 'og:image:width', 'content': '1200'}, | ||
{'property': 'og:image:height', 'content': '620'}, | ||
{'name': 'twitter:card', 'content': 'summary_large_image'}, | ||
{'name': 'twitter:title', 'content': title}, | ||
{'name': 'twitter:description', 'content': description}, | ||
{'name': 'twitter:image', 'content': image}, | ||
] |