| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- """
- 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,
- }
|