add sitemap and open graph
This commit is contained in:
parent
b836d38e70
commit
a07d1fc4e2
9 changed files with 176 additions and 0 deletions
BIN
hub/services/static/img/servala-social-share.png
Normal file
BIN
hub/services/static/img/servala-social-share.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 680 KiB |
|
@ -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" %}'>
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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">
|
||||||
|
|
72
hub/services/templatetags/social_meta_tags.py
Normal file
72
hub/services/templatetags/social_meta_tags.py
Normal 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)
|
|
@ -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
62
hub/sitemaps.py
Normal 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
|
34
hub/urls.py
34
hub/urls.py
|
@ -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)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue