""" Utilitaires SEO pour le blog Génère les métadonnées structurées et optimise le référencement """ from django.conf import settings from django.urls import reverse from datetime import datetime import json def generate_article_schema(article, request): """ Génère le schema.org JSON-LD pour un article de blog Format Article pour Google Rich Results """ # URL absolue de l'article article_url = request.build_absolute_uri( 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 \ request.build_absolute_uri(settings.STATIC_URL + 'logo-txt-Mrduhaz.png') schema = { "@context": "https://schema.org", "@type": "BlogPosting", "headline": article.b_titre, "description": article.b_description[:160] if article.b_description else "", "image": image_url, "datePublished": article.b_publdate.isoformat() if article.b_publdate else "", "dateModified": article.b_publdate.isoformat() if article.b_publdate else "", "author": { "@type": "Person", "name": "Mr Duhaz", "url": request.build_absolute_uri('/') }, "publisher": { "@type": "Organization", "name": "Duhaz Blog", "url": request.build_absolute_uri('/'), "logo": { "@type": "ImageObject", "url": request.build_absolute_uri(settings.STATIC_URL + 'logo-txt-Mrduhaz.png') } }, "mainEntityOfPage": { "@type": "WebPage", "@id": article_url }, "wordCount": len(article.b_contenu.split()) if article.b_contenu else 0, "articleSection": [cat.cb_titre for cat in article.b_cat.all()], "keywords": article.b_mots_clefs, "inLanguage": "fr-FR" } return json.dumps(schema, ensure_ascii=False) def generate_breadcrumb_schema(items, request): """ Génère le schema.org pour le fil d'Ariane (breadcrumb) items: liste de tuples (nom, url) """ schema = { "@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [] } for position, (name, url) in enumerate(items, start=1): schema["itemListElement"].append({ "@type": "ListItem", "position": position, "name": name, "item": request.build_absolute_uri(url) if url else None }) return json.dumps(schema, ensure_ascii=False) def generate_website_schema(request): """ Génère le schema.org pour le site web principal """ schema = { "@context": "https://schema.org", "@type": "WebSite", "name": "Duhaz Blog", "url": request.build_absolute_uri('/'), "description": "Blog tech et développement par Mr Duhaz", "inLanguage": "fr-FR", "potentialAction": { "@type": "SearchAction", "target": { "@type": "EntryPoint", "urlTemplate": request.build_absolute_uri(reverse('blog_index')) + "?b_search={search_term_string}" }, "query-input": "required name=search_term_string" } } return json.dumps(schema, ensure_ascii=False) def generate_og_tags(article, request): """ Génère les balises Open Graph pour le partage sur réseaux sociaux """ article_url = request.build_absolute_uri( reverse('blog_play', args=[article.b_titre_slugify]) ) image_url = article.b_description_img if article.b_description_img else \ request.build_absolute_uri(settings.STATIC_URL + 'logo-txt-Mrduhaz.png') return { 'og:type': 'article', 'og:title': article.b_titre, 'og:description': article.b_description[:160] if article.b_description else "", 'og:url': article_url, 'og:image': image_url, 'og:site_name': 'Duhaz Blog', 'og:locale': 'fr_FR', 'article:published_time': article.b_publdate.isoformat() if article.b_publdate else "", 'article:author': 'Mr Duhaz', 'article:section': ', '.join([cat.cb_titre for cat in article.b_cat.all()]), 'article:tag': article.b_mots_clefs } def generate_twitter_cards(article, request): """ Génère les balises Twitter Card pour le partage sur Twitter """ article_url = request.build_absolute_uri( reverse('blog_play', args=[article.b_titre_slugify]) ) image_url = article.b_description_img if article.b_description_img else \ request.build_absolute_uri(settings.STATIC_URL + 'logo-txt-Mrduhaz.png') return { 'twitter:card': 'summary_large_image', 'twitter:title': article.b_titre, 'twitter:description': article.b_description[:160] if article.b_description else "", 'twitter:image': image_url, 'twitter:url': article_url } def get_canonical_url(request): """ Retourne l'URL canonical pour éviter le duplicate content """ return request.build_absolute_uri(request.path)