""" Helpers SEO pour le blog Django Génération automatique de métadonnées structurées et optimisées """ from django.utils.html import strip_tags from django.utils.text import Truncator from django.urls import reverse class SEOMetadata: """Classe pour gérer les métadonnées SEO d'une page""" def __init__(self, request, obj=None): self.request = request self.obj = obj self.site_name = "Mr Duhaz" self.site_url = "https://www.duhaz.fr" def get_absolute_url(self, path=''): """Génère une URL absolue""" if path: return f"{self.site_url}{path}" return self.request.build_absolute_uri() def clean_description(self, text, max_length=160): """Nettoie et tronque une description pour le SEO""" if not text: return "" # Supprime les balises HTML clean_text = strip_tags(text) # Tronque intelligemment return Truncator(clean_text).chars(max_length, truncate='...') def get_blog_metadata(self, article): """Génère les métadonnées complètes pour un article de blog""" if not article: return self.get_default_metadata() # URL absolue de l'article article_url = self.get_absolute_url( reverse('blog_play', args=[article.b_titre_slugify]) ) # Image de l'article (ou image par défaut) image_url = article.b_description_img if article.b_description_img else \ f"{self.site_url}/static/logo-txt-Mrduhaz.png" # Description nettoyée description = self.clean_description(article.b_description, 160) # Catégories pour les keywords categories = [cat.cb_titre for cat in article.b_cat.all()] keywords = article.b_mots_clefs if article.b_mots_clefs else ', '.join(categories) # Date de publication au format ISO 8601 published_time = article.b_publdate.isoformat() if article.b_publdate else None metadata = { # Basiques 'title': f"{article.b_titre} | {self.site_name}", 'description': description, 'keywords': keywords, 'canonical_url': article_url, 'image': image_url, # Open Graph (Facebook) 'og': { 'type': 'article', 'title': article.b_titre, 'description': description, 'url': article_url, 'image': image_url, 'site_name': self.site_name, 'locale': 'fr_FR', 'article:published_time': published_time, 'article:author': 'Mr Duhaz', 'article:section': categories[0] if categories else 'Blog', 'article:tag': categories, }, # Twitter Cards 'twitter': { 'card': 'summary_large_image', 'title': article.b_titre, 'description': description, 'image': image_url, 'site': '@mrduhaz', # Remplacer par votre handle Twitter }, # Schema.org JSON-LD 'schema': self.get_article_schema(article, article_url, image_url, description), } return metadata def get_article_schema(self, article, url, image, description): """Génère le schema JSON-LD pour un article""" categories = [cat.cb_titre for cat in article.b_cat.all()] schema = { "@context": "https://schema.org", "@type": "BlogPosting", "headline": article.b_titre, "description": description, "image": image, "author": { "@type": "Person", "name": "Mr Duhaz", "url": self.site_url }, "publisher": { "@type": "Organization", "name": self.site_name, "logo": { "@type": "ImageObject", "url": f"{self.site_url}/static/logo-txt-Mrduhaz.png" } }, "url": url, "datePublished": article.b_publdate.isoformat() if article.b_publdate else None, "dateModified": article.b_publdate.isoformat() if article.b_publdate else None, "articleSection": categories[0] if categories else "Blog", "keywords": article.b_mots_clefs if article.b_mots_clefs else ', '.join(categories), "wordCount": len(strip_tags(article.b_contenu).split()), "articleBody": self.clean_description(article.b_contenu, 500), } return schema def get_listing_metadata(self, category=None): """Génère les métadonnées pour la page de listing""" if category: title = f"Articles dans {category.cb_titre} | {self.site_name}" description = f"Découvrez tous les articles de la catégorie {category.cb_titre} sur le blog de {self.site_name}" url = self.get_absolute_url(reverse('blog_tag', args=[category.cb_titre_slgify])) else: title = f"Blog | {self.site_name}" description = f"Découvrez tous les articles du blog de {self.site_name} : tutoriels, actualités et guides" url = self.get_absolute_url(reverse('blog_index')) metadata = { 'title': title, 'description': description, 'canonical_url': url, 'og': { 'type': 'website', 'title': title, 'description': description, 'url': url, 'image': f"{self.site_url}/static/logo-txt-Mrduhaz.png", 'site_name': self.site_name, 'locale': 'fr_FR', }, 'twitter': { 'card': 'summary', 'title': title, 'description': description, 'image': f"{self.site_url}/static/logo-txt-Mrduhaz.png", }, } return metadata def get_default_metadata(self): """Métadonnées par défaut du site""" return { 'title': self.site_name, 'description': "Blog de Mr Duhaz : développement web, tutoriels et astuces", 'canonical_url': self.site_url, }