add sitemap and open graph

This commit is contained in:
Tobias Brunner 2025-03-03 15:57:08 +01:00
parent b836d38e70
commit a07d1fc4e2
No known key found for this signature in database
9 changed files with 176 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 680 KiB

View file

@ -1,13 +1,17 @@
{% load static %} {% load static %}
{% load canonical_tags %} {% load canonical_tags %}
{% load social_meta_tags %}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="{% block meta_description %}Servala connects businesses, developers, and cloud service providers on one unique hub with secure, scalable, and easy-to-use cloud-native services.{% endblock %}">
<title>Servala - {% block title %}{% endblock %}</title> <title>Servala - {% block title %}{% endblock %}</title>
<link rel="canonical" href="{% canonical_url %}" /> <link rel="canonical" href="{% canonical_url %}" />
<link rel="icon" type="image/x-icon" href="{% static "img/favicon.ico" %}"> <link rel="icon" type="image/x-icon" href="{% static "img/favicon.ico" %}">
<link rel="sitemap" type="application/xml" title="Sitemap" href="/sitemap.xml">
{% social_meta_tags %}
<link rel="stylesheet" href='{% static "css/bootstrap-icons.min.css" %}'> <link rel="stylesheet" href='{% static "css/bootstrap-icons.min.css" %}'>
<link rel="stylesheet" type="text/css" href='{% static "css/servala-main.css" %}'> <link rel="stylesheet" type="text/css" href='{% static "css/servala-main.css" %}'>

View file

@ -3,6 +3,7 @@
{% load contact_tags %} {% load contact_tags %}
{% block title %}Consulting Partners{% endblock %} {% block title %}Consulting Partners{% endblock %}
{% block meta_description %}Browse our network of expert consulting partners on Servala who can help you implement and optimize cloud services for your business.{% endblock %}
{% block content %} {% block content %}
<section class="section bg-primary-subtle"> <section class="section bg-primary-subtle">

View file

@ -3,6 +3,7 @@
{% load contact_tags %} {% load contact_tags %}
{% block title %}Service Providers{% endblock %} {% block title %}Service Providers{% endblock %}
{% block meta_description %}Discover cloud providers on Servala offering reliable infrastructure and innovative cloud computing solutions for businesses of all sizes.{% endblock %}
{% block content %} {% block content %}
<section class="section bg-primary-subtle"> <section class="section bg-primary-subtle">

View file

@ -3,6 +3,7 @@
{% load contact_tags %} {% load contact_tags %}
{% block title %}Services{% endblock %} {% block title %}Services{% endblock %}
{% block meta_description %}Explore all available cloud services on Servala, with new services added regularly to help businesses find the right solutions.{% endblock %}
{% block content %} {% block content %}
<section class="section bg-primary-subtle"> <section class="section bg-primary-subtle">

View file

@ -0,0 +1,72 @@
from django import template
from django.urls import resolve
from django.utils.safestring import mark_safe
register = template.Library()
@register.simple_tag(takes_context=True)
def social_meta_tags(context):
"""
Generates appropriate Open Graph and Twitter Card meta tags based on the current page.
"""
request = context["request"]
current_url = request.path
resolved_view = resolve(current_url)
view_name = resolved_view.url_name
# Default values (used for listing pages)
title = context.get("self.title", "Servala")
if hasattr(context.get("self"), "title"):
title = context["self"].title
description = context.get(
"self.meta_description",
"Servala connects businesses, developers, and cloud service providers on one unique hub",
)
image_url = request.build_absolute_uri("/static/img/servala-social-share.png")
# Customize based on page type
if view_name == "service_detail" and "service" in context:
service = context["service"]
title = f"Servala Managed Service: {service.name}"
description = (
f"Managed {service.name} on any cloud provider trusted by Servala."
)
elif view_name == "provider_detail" and "provider" in context:
provider = context["provider"]
title = f"Servala trusted Cloud Provider: {provider.name}"
description = f"Managed services on {provider.name} via Servala"
elif view_name == "partner_detail" and "partner" in context:
partner = context["partner"]
title = f"Servala trusted Consulting Partner: {partner.name}"
description = (
f"Consulting services from {partner.name} for services available on Servala"
)
elif view_name == "offering_detail" and "offering" in context:
offering = context["offering"]
title = f"{offering.service.name} on {offering.cloud_provider.name}"
description = (
offering.short_description[:160]
if offering.short_description
else description
)
# Generate the HTML for meta tags
tags = f"""
<meta property="og:site_name" content="Servala">
<meta property="og:title" content="{title}">
<meta property="og:description" content="{description}">
<meta property="og:type" content="website">
<meta property="og:url" content="{request.build_absolute_uri()}">
<meta property="og:image" content="{image_url}">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="{title}">
<meta name="twitter:description" content="{description}">
<meta name="twitter:image" content="{image_url}">
"""
return mark_safe(tags)

View file

@ -64,6 +64,7 @@ INSTALLED_APPS = [
"django.contrib.sessions", "django.contrib.sessions",
"django.contrib.messages", "django.contrib.messages",
"django.contrib.staticfiles", "django.contrib.staticfiles",
"django.contrib.sitemaps",
# 3rd party # 3rd party
"django_prose_editor", "django_prose_editor",
"rest_framework", "rest_framework",

62
hub/sitemaps.py Normal file
View file

@ -0,0 +1,62 @@
from django.contrib.sitemaps import Sitemap
from django.urls import reverse
from hub.services.models import (
Service,
CloudProvider,
ConsultingPartner,
ServiceOffering,
)
class StaticSitemap(Sitemap):
changefreq = "monthly"
priority = 1.0
def items(self):
return ["services:homepage", "services:contact"]
def location(self, item):
return reverse(item)
class ServiceSitemap(Sitemap):
changefreq = "weekly"
priority = 1.0
def items(self):
return Service.objects.filter(disable_listing=False).exclude(
is_coming_soon=True
)
def lastmod(self, obj):
return obj.updated_at
class OfferingSitemap(Sitemap):
changefreq = "weekly"
priority = 0.7
def items(self):
return ServiceOffering.objects.filter(disable_listing=False)
def lastmod(self, obj):
return obj.updated_at
class CloudProviderSitemap(Sitemap):
changefreq = "weekly"
priority = 0.7
def items(self):
return CloudProvider.objects.filter(disable_listing=False)
class ConsultingPartnerSitemap(Sitemap):
changefreq = "weekly"
priority = 0.7
def items(self):
return ConsultingPartner.objects.filter(disable_listing=False)
def lastmod(self, obj):
return obj.updated_at

View file

@ -4,13 +4,40 @@ from django.conf.urls.static import static
from django.contrib import admin from django.contrib import admin
from django.shortcuts import render from django.shortcuts import render
from django.urls import path, include from django.urls import path, include
from django.contrib.sitemaps.views import sitemap
from django.http import HttpResponse
from hub.services.views.errors import bad_request, page_not_found, server_error from hub.services.views.errors import bad_request, page_not_found, server_error
from .sitemaps import (
StaticSitemap,
ServiceSitemap,
OfferingSitemap,
CloudProviderSitemap,
ConsultingPartnerSitemap,
)
def robots_txt(request):
content = """User-agent: *
Allow: /
Sitemap: https://serva.la/sitemap.xml
"""
return HttpResponse(content, content_type="text/plain")
handler400 = "hub.services.views.errors.bad_request" handler400 = "hub.services.views.errors.bad_request"
handler404 = "hub.services.views.errors.page_not_found" handler404 = "hub.services.views.errors.page_not_found"
handler500 = "hub.services.views.errors.server_error" handler500 = "hub.services.views.errors.server_error"
sitemaps = {
"static": StaticSitemap,
"services": ServiceSitemap,
"offerings": OfferingSitemap,
"providers": CloudProviderSitemap,
"partners": ConsultingPartnerSitemap,
}
urlpatterns = [ urlpatterns = [
path("admin/", admin.site.urls), path("admin/", admin.site.urls),
path("", include("hub.services.urls")), path("", include("hub.services.urls")),
@ -23,5 +50,12 @@ if settings.DEBUG:
path("test-400/", lambda request: render(request, "400.html"), name="test_400"), path("test-400/", lambda request: render(request, "400.html"), name="test_400"),
path("test-404/", lambda request: render(request, "404.html"), name="test_404"), path("test-404/", lambda request: render(request, "404.html"), name="test_404"),
path("test-500/", lambda request: render(request, "500.html"), name="test_500"), path("test-500/", lambda request: render(request, "500.html"), name="test_500"),
path(
"sitemap.xml",
sitemap,
{"sitemaps": sitemaps},
name="django.contrib.sitemaps.views.sitemap",
),
path("robots.txt", robots_txt, name="robots_txt"),
] ]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)