diff --git a/hub/services/admin/__init__.py b/hub/services/admin/__init__.py index 3c79092..75c0d33 100644 --- a/hub/services/admin/__init__.py +++ b/hub/services/admin/__init__.py @@ -1,7 +1,6 @@ # Admin module initialization # Import all admin classes to register them with Django admin -from .articles import * from .base import * from .content import * from .leads import * diff --git a/hub/services/admin/articles.py b/hub/services/admin/articles.py deleted file mode 100644 index e6dad8c..0000000 --- a/hub/services/admin/articles.py +++ /dev/null @@ -1,90 +0,0 @@ -""" -Admin configuration for Article model -""" - -from django.contrib import admin -from django.utils.html import format_html -from django import forms -from django.core.exceptions import ValidationError - - -from ..models import Article - - -class ArticleAdminForm(forms.ModelForm): - """Custom form for Article admin with validation""" - - class Meta: - model = Article - fields = "__all__" - - def clean_title(self): - """Validate title length""" - title = self.cleaned_data.get("title") - if title and len(title) > 50: - raise ValidationError("Title must be 50 characters or less.") - return title - - def clean_excerpt(self): - """Validate excerpt length""" - excerpt = self.cleaned_data.get("excerpt") - if excerpt and len(excerpt) > 200: - raise ValidationError("Excerpt must be 200 characters or less.") - return excerpt - - -@admin.register(Article) -class ArticleAdmin(admin.ModelAdmin): - """Admin configuration for Article model""" - - form = ArticleAdminForm - - list_display = ( - "title", - "author", - "image_preview", - "is_published", - "is_featured", - "created_at", - ) - list_filter = ( - "is_published", - "is_featured", - "author", - "related_service", - "related_consulting_partner", - "related_cloud_provider", - "created_at", - ) - search_fields = ("title", "excerpt", "content", "meta_keywords") - prepopulated_fields = {"slug": ("title",)} - readonly_fields = ("created_at", "updated_at") - - def image_preview(self, obj): - """Display image preview in admin list view""" - if obj.image: - return format_html( - '', obj.image.url - ) - return "No image" - - image_preview.short_description = "Image" - - def related_to_display(self, obj): - """Display what this article is related to""" - return obj.related_to - - related_to_display.short_description = "Related To" - - def get_queryset(self, request): - """Optimize queries by selecting related objects""" - return ( - super() - .get_queryset(request) - .select_related( - "author", - "related_service", - "related_consulting_partner", - "related_cloud_provider", - ) - ) diff --git a/hub/services/migrations/0034_article.py b/hub/services/migrations/0034_article.py deleted file mode 100644 index e485625..0000000 --- a/hub/services/migrations/0034_article.py +++ /dev/null @@ -1,118 +0,0 @@ -# Generated by Django 5.2 on 2025-06-06 07:47 - -import django.db.models.deletion -import hub.services.models.base -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("services", "0033_vshnappcatprice_public_display_enabled_and_more"), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name="Article", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("title", models.CharField(max_length=200)), - ("slug", models.SlugField(max_length=250, unique=True)), - ( - "excerpt", - models.TextField( - help_text="Brief description of the article", max_length=500 - ), - ), - ("content", models.TextField()), - ( - "meta_keywords", - models.CharField( - blank=True, - help_text="SEO keywords separated by commas", - max_length=255, - ), - ), - ( - "image", - models.ImageField( - help_text="Title picture for the article", - upload_to="article_images/", - validators=[hub.services.models.base.validate_image_size], - ), - ), - ( - "is_published", - models.BooleanField( - default=False, - help_text="Only published articles are visible to users", - ), - ), - ( - "is_featured", - models.BooleanField( - default=False, - help_text="Featured articles appear prominently in listings", - ), - ), - ("created_at", models.DateTimeField(auto_now_add=True)), - ("updated_at", models.DateTimeField(auto_now=True)), - ( - "author", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="articles", - to=settings.AUTH_USER_MODEL, - ), - ), - ( - "related_cloud_provider", - models.ForeignKey( - blank=True, - help_text="Link this article to a cloud provider", - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="articles", - to="services.cloudprovider", - ), - ), - ( - "related_consulting_partner", - models.ForeignKey( - blank=True, - help_text="Link this article to a consulting partner", - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="articles", - to="services.consultingpartner", - ), - ), - ( - "related_service", - models.ForeignKey( - blank=True, - help_text="Link this article to a specific service", - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="articles", - to="services.service", - ), - ), - ], - options={ - "verbose_name": "Article", - "verbose_name_plural": "Articles", - "ordering": ["-created_at"], - }, - ), - ] diff --git a/hub/services/models/__init__.py b/hub/services/models/__init__.py index b29a71e..f5c3107 100644 --- a/hub/services/models/__init__.py +++ b/hub/services/models/__init__.py @@ -1,4 +1,3 @@ -from .articles import * from .base import * from .content import * from .leads import * diff --git a/hub/services/models/articles.py b/hub/services/models/articles.py deleted file mode 100644 index 781c54c..0000000 --- a/hub/services/models/articles.py +++ /dev/null @@ -1,94 +0,0 @@ -from django.db import models -from django.urls import reverse -from django.utils.text import slugify -from django.contrib.auth.models import User -from django_prose_editor.fields import ProseEditorField -from .base import validate_image_size -from .services import Service -from .providers import CloudProvider, ConsultingPartner - - -class Article(models.Model): - title = models.CharField(max_length=200) - slug = models.SlugField(max_length=250, unique=True) - excerpt = models.TextField( - max_length=500, help_text="Brief description of the article" - ) - content = ProseEditorField() - meta_keywords = models.CharField( - max_length=255, blank=True, help_text="SEO keywords separated by commas" - ) - image = models.ImageField( - upload_to="article_images/", - help_text="Title picture for the article", - ) - author = models.ForeignKey(User, on_delete=models.CASCADE, related_name="articles") - - # Relations to other models - related_service = models.ForeignKey( - Service, - on_delete=models.SET_NULL, - null=True, - blank=True, - related_name="articles", - help_text="Link this article to a specific service", - ) - related_consulting_partner = models.ForeignKey( - ConsultingPartner, - on_delete=models.SET_NULL, - null=True, - blank=True, - related_name="articles", - help_text="Link this article to a consulting partner", - ) - related_cloud_provider = models.ForeignKey( - CloudProvider, - on_delete=models.SET_NULL, - null=True, - blank=True, - related_name="articles", - help_text="Link this article to a cloud provider", - ) - - # Publishing controls - is_published = models.BooleanField( - default=False, help_text="Only published articles are visible to users" - ) - is_featured = models.BooleanField( - default=False, help_text="Featured articles appear prominently in listings" - ) - - created_at = models.DateTimeField(auto_now_add=True) - updated_at = models.DateTimeField(auto_now=True) - - class Meta: - ordering = ["-created_at"] - verbose_name = "Article" - verbose_name_plural = "Articles" - - def __str__(self): - return self.title - - def save(self, *args, **kwargs): - # Auto-generate slug from title if not provided - if not self.slug: - self.slug = slugify(self.title) - counter = 1 - while Article.objects.filter(slug=self.slug).exists(): - self.slug = f"{slugify(self.title)}-{counter}" - counter += 1 - super().save(*args, **kwargs) - - def get_absolute_url(self): - return reverse("services:article_detail", kwargs={"slug": self.slug}) - - @property - def related_to(self): - """Returns a string describing what this article is related to""" - if self.related_service: - return f"Service: {self.related_service.name}" - elif self.related_consulting_partner: - return f"Partner: {self.related_consulting_partner.name}" - elif self.related_cloud_provider: - return f"Provider: {self.related_cloud_provider.name}" - return "General" diff --git a/hub/services/templates/base.html b/hub/services/templates/base.html index 93d9364..b549e08 100644 --- a/hub/services/templates/base.html +++ b/hub/services/templates/base.html @@ -55,7 +55,6 @@ diff --git a/hub/services/templates/services/article_detail.html b/hub/services/templates/services/article_detail.html deleted file mode 100644 index 051967c..0000000 --- a/hub/services/templates/services/article_detail.html +++ /dev/null @@ -1,178 +0,0 @@ -{% extends 'base.html' %} -{% load static %} -{% load contact_tags %} - -{% block title %}{{ article.title }}{% endblock %} -{% block meta_description %}{{ article.excerpt }}{% endblock %} -{% block meta_keywords %}{{ article.meta_keywords }}{% endblock %} - -{% block content %} -
-
-
-

{{ article.title }}

-
-

{{ article.excerpt }}

-
- By {{ article.author.get_full_name|default:article.author.username }} - - {{ article.created_at|date:"M d, Y" }} - {% if article.updated_at != article.created_at %} - {% endif %} -
-
-
-
-
- -{% if article.image %} -
-
-
- {{ article.title }} -
-
-
-{% endif %} - -
-
-
-
-
-
- {{ article.content|safe }} -
-
- - - {% if article.related_service or article.related_consulting_partner or article.related_cloud_provider %} -
-

Related Links

-
- {% if article.related_service %} -
-
-
-
Service
- {% if article.related_service.logo %} -
- {{ article.related_service.name }} logo -
- {% endif %} -

{{ article.related_service.name }}

- View Service -
-
-
- {% endif %} - {% if article.related_consulting_partner %} -
-
-
-
Partner
- {% if article.related_consulting_partner.logo %} -
- {{ article.related_consulting_partner.name }} logo -
- {% endif %} -

{{ article.related_consulting_partner.name }}

- View Partner -
-
-
- {% endif %} - {% if article.related_cloud_provider %} -
-
-
-
Provider
- {% if article.related_cloud_provider.logo %} -
- {{ article.related_cloud_provider.name }} logo -
- {% endif %} -

{{ article.related_cloud_provider.name }}

- View Provider -
-
-
- {% endif %} -
-
- {% endif %} - - - {% if related_articles %} -
-

Related Articles

-
- {% for related_article in related_articles %} -
-
- {% if related_article.image %} - {{ related_article.title }} - {% endif %} -
-
{{ related_article.title }}
-

{{ related_article.excerpt|truncatewords:15 }}

- {{ related_article.created_at|date:"M d, Y" }} -
-
-
- {% endfor %} -
-
- {% endif %} - - -
-
- - - - - - Back to Articles - -
- - -
-
-
-
-
-
-
- -
-
-
-
- -
-
-
-

Questions about this article?

-
-

Have questions or need more information about the topics covered in this article? Get in touch with us!

-
-
- {% embedded_contact_form source="Article Inquiry" %} -
-
-
-
-
-
-{% endblock %} \ No newline at end of file diff --git a/hub/services/templates/services/article_list.html b/hub/services/templates/services/article_list.html deleted file mode 100644 index edb0989..0000000 --- a/hub/services/templates/services/article_list.html +++ /dev/null @@ -1,217 +0,0 @@ -{% extends 'base.html' %} -{% load static %} -{% load contact_tags %} - -{% block title %}Articles{% endblock %} -{% block meta_description %}Explore all articles on Servala, covering cloud services, consulting partners, and cloud provider insights.{% endblock %} - -{% block content %} -
-
-
-

Articles

-
-

Discover insights, guides, and updates about cloud services, consulting partners, and technology trends.

-
-
-
-
- -
-
-
- -
- -
- -
- -
-
- - - - - - - - - - - -
- -
-
- -
- - - -
- - -
-
- -
-
- -
-
- - -
-
- -
-
- -
-
- - -
-
- -
-
- -
-
- - -
- Clear -
-
-
-
-
- - -
-
- {% for article in articles %} -
- -
- {% empty %} -
-
- No articles found matching your criteria. -
-
- {% endfor %} -
-
-
-
-
- -
-
-
-
- -
-
-
-

Looking for specific content?

-
-

Can't find what you're looking for? Let us know what topics you'd like to see covered!

-
-
- {% embedded_contact_form source="Article Request" %} -
-
-
-
-
-
-{% endblock %} \ No newline at end of file diff --git a/hub/services/templates/services/offering_detail.html b/hub/services/templates/services/offering_detail.html index f44dddc..134dc2f 100644 --- a/hub/services/templates/services/offering_detail.html +++ b/hub/services/templates/services/offering_detail.html @@ -94,50 +94,6 @@ {% endif %} - - - {% if service_articles %} -
-

Articles about {{ offering.service.name }}

- -
- {% endif %} - - - {% if provider_articles %} -
-

Articles about {{ offering.cloud_provider.name }}

- -
- {% endif %} @@ -446,6 +402,4 @@ - - {% endblock %} \ No newline at end of file diff --git a/hub/services/templates/services/partner_detail.html b/hub/services/templates/services/partner_detail.html index 7e90b82..866302f 100644 --- a/hub/services/templates/services/partner_detail.html +++ b/hub/services/templates/services/partner_detail.html @@ -119,28 +119,6 @@ {% endif %} - - - {% if related_articles %} -
-

Related Articles

- -
- {% endif %} diff --git a/hub/services/templates/services/provider_detail.html b/hub/services/templates/services/provider_detail.html index 151c986..ade6e12 100644 --- a/hub/services/templates/services/provider_detail.html +++ b/hub/services/templates/services/provider_detail.html @@ -119,28 +119,6 @@ {% endif %} - - - {% if related_articles %} -
-

Related Articles

- -
- {% endif %} diff --git a/hub/services/templates/services/provider_list.html b/hub/services/templates/services/provider_list.html index 5484b7e..b343f80 100644 --- a/hub/services/templates/services/provider_list.html +++ b/hub/services/templates/services/provider_list.html @@ -98,12 +98,10 @@
- {% if provider.logo %} {{ provider.name }} - {% endif %}

diff --git a/hub/services/templates/services/service_detail.html b/hub/services/templates/services/service_detail.html index 5054d61..ca73351 100644 --- a/hub/services/templates/services/service_detail.html +++ b/hub/services/templates/services/service_detail.html @@ -93,28 +93,6 @@ {% endif %} - - - {% if related_articles %} -
-

Related Articles

- -
- {% endif %} diff --git a/hub/services/templatetags/social_meta_tags.py b/hub/services/templatetags/social_meta_tags.py index 03fe0cb..d8eb107 100644 --- a/hub/services/templatetags/social_meta_tags.py +++ b/hub/services/templatetags/social_meta_tags.py @@ -59,68 +59,18 @@ def social_meta_tags(context): else description ) - elif view_name == "services:article_detail" and "article" in context: - article = context["article"] - title = f"Servala - {article.title}" - description = article.excerpt - # Use article image if available, otherwise default - if article.image: - image_url = request.build_absolute_uri(article.image.url) - - # Determine og:type based on view - og_type = "website" # default - if view_name == "services:article_detail" and "article" in context: - og_type = "article" - # Generate the HTML for meta tags tags = f""" - + + + + + """ - # Add article-specific meta tags if this is an article detail page - if view_name == "services:article_detail" and "article" in context: - article = context["article"] - - # Add article-specific Open Graph tags - article_tags = f""" - - - - """ - - # Add article section if related to service, partner, or provider - if article.related_service: - article_tags += ( - f'\n ' - ) - elif article.related_consulting_partner: - article_tags += ( - f'\n ' - ) - elif article.related_cloud_provider: - article_tags += ( - f'\n ' - ) - else: - article_tags += f'\n ' - - # Add meta keywords as article tags if available - if article.meta_keywords: - keywords = [ - keyword.strip() - for keyword in article.meta_keywords.split(",") - if keyword.strip() - ] - for keyword in keywords: - article_tags += ( - f'\n ' - ) - - tags += article_tags - return mark_safe(tags) diff --git a/hub/services/urls.py b/hub/services/urls.py index 2ead4b0..552ead5 100644 --- a/hub/services/urls.py +++ b/hub/services/urls.py @@ -18,8 +18,6 @@ urlpatterns = [ ), path("provider//", views.provider_detail, name="provider_detail"), path("partner//", views.partner_detail, name="partner_detail"), - path("articles/", views.article_list, name="article_list"), - path("article//", views.article_detail, name="article_detail"), path("contact/", views.leads.contact, name="contact"), path("contact/thank-you/", views.thank_you, name="thank_you"), path("contact-form/", views.contact_form, name="contact_form"), diff --git a/hub/services/views/__init__.py b/hub/services/views/__init__.py index 56d2142..0af9c30 100644 --- a/hub/services/views/__init__.py +++ b/hub/services/views/__init__.py @@ -1,4 +1,3 @@ -from .articles import * from .leads import * from .offerings import * from .partners import * diff --git a/hub/services/views/articles.py b/hub/services/views/articles.py deleted file mode 100644 index 6589d6f..0000000 --- a/hub/services/views/articles.py +++ /dev/null @@ -1,176 +0,0 @@ -from django.shortcuts import render, get_object_or_404 -from django.db.models import Q -from hub.services.models import ( - Article, - Service, - ConsultingPartner, - CloudProvider, -) - - -def article_list(request): - """View for listing articles with filtering capabilities""" - # Get basic filter parameters - search_query = request.GET.get("search", "") - service_id = request.GET.get("service", "") - consulting_partner_id = request.GET.get("consulting_partner", "") - cloud_provider_id = request.GET.get("cloud_provider", "") - - # Start with all published articles - all_articles = Article.objects.filter(is_published=True) - articles = all_articles - - # Apply filters based on request parameters - if search_query: - articles = articles.filter( - Q(title__icontains=search_query) - | Q(excerpt__icontains=search_query) - | Q(content__icontains=search_query) - | Q(meta_keywords__icontains=search_query) - ) - - if service_id: - articles = articles.filter(related_service__id=service_id) - - if consulting_partner_id: - articles = articles.filter(related_consulting_partner__id=consulting_partner_id) - - if cloud_provider_id: - articles = articles.filter(related_cloud_provider__id=cloud_provider_id) - - # Order articles: featured first, then by creation date (newest first) - articles = articles.order_by( - "-is_featured", # Featured first (True before False) - "-created_at", # Newest first - ) - - # Create base querysets for each filter type that apply all OTHER current filters - # This way, each filter shows options that would return results if selected - - # For service filter options, apply all other filters except service - service_filter_base = all_articles - if search_query: - service_filter_base = service_filter_base.filter( - Q(title__icontains=search_query) - | Q(excerpt__icontains=search_query) - | Q(content__icontains=search_query) - | Q(meta_keywords__icontains=search_query) - ) - if consulting_partner_id: - service_filter_base = service_filter_base.filter( - related_consulting_partner__id=consulting_partner_id - ) - if cloud_provider_id: - service_filter_base = service_filter_base.filter( - related_cloud_provider__id=cloud_provider_id - ) - - # For consulting partner filter options, apply all other filters except consulting_partner - cp_filter_base = all_articles - if search_query: - cp_filter_base = cp_filter_base.filter( - Q(title__icontains=search_query) - | Q(excerpt__icontains=search_query) - | Q(content__icontains=search_query) - | Q(meta_keywords__icontains=search_query) - ) - if service_id: - cp_filter_base = cp_filter_base.filter(related_service__id=service_id) - if cloud_provider_id: - cp_filter_base = cp_filter_base.filter( - related_cloud_provider__id=cloud_provider_id - ) - - # For cloud provider filter options, apply all other filters except cloud_provider - cloud_filter_base = all_articles - if search_query: - cloud_filter_base = cloud_filter_base.filter( - Q(title__icontains=search_query) - | Q(excerpt__icontains=search_query) - | Q(content__icontains=search_query) - | Q(meta_keywords__icontains=search_query) - ) - if service_id: - cloud_filter_base = cloud_filter_base.filter(related_service__id=service_id) - if consulting_partner_id: - cloud_filter_base = cloud_filter_base.filter( - related_consulting_partner__id=consulting_partner_id - ) - - # Get available services, consulting partners and cloud providers that would return results if selected - available_services = Service.objects.filter( - disable_listing=False, - id__in=service_filter_base.values_list( - "related_service__id", flat=True - ).distinct(), - ).distinct() - - available_consulting_partners = ConsultingPartner.objects.filter( - disable_listing=False, - id__in=cp_filter_base.values_list( - "related_consulting_partner__id", flat=True - ).distinct(), - ).distinct() - - available_cloud_providers = CloudProvider.objects.filter( - disable_listing=False, - id__in=cloud_filter_base.values_list( - "related_cloud_provider__id", flat=True - ).distinct(), - ).distinct() - - context = { - "articles": articles, - "available_services": available_services, - "available_consulting_partners": available_consulting_partners, - "available_cloud_providers": available_cloud_providers, - "search_query": search_query, - } - - return render(request, "services/article_list.html", context) - - -def article_detail(request, slug): - """View for displaying article details""" - article = get_object_or_404( - Article.objects.select_related( - "author", - "related_service", - "related_consulting_partner", - "related_cloud_provider" - ).filter(is_published=True), - slug=slug, - ) - - # Get related articles (same service, partner, or provider) - related_articles = Article.objects.filter( - is_published=True - ).exclude(id=article.id) - - if article.related_service: - related_articles = related_articles.filter( - related_service=article.related_service - ) - elif article.related_consulting_partner: - related_articles = related_articles.filter( - related_consulting_partner=article.related_consulting_partner - ) - elif article.related_cloud_provider: - related_articles = related_articles.filter( - related_cloud_provider=article.related_cloud_provider - ) - else: - # If no specific relation, get other general articles - related_articles = related_articles.filter( - related_service__isnull=True, - related_consulting_partner__isnull=True, - related_cloud_provider__isnull=True - ) - - related_articles = related_articles.order_by("-created_at")[:3] - - context = { - "article": article, - "related_articles": related_articles, - } - return render(request, "services/article_detail.html", context) \ No newline at end of file diff --git a/hub/services/views/offerings.py b/hub/services/views/offerings.py index 2c876a6..4730b4a 100644 --- a/hub/services/views/offerings.py +++ b/hub/services/views/offerings.py @@ -129,20 +129,10 @@ def offering_detail(request, provider_slug, service_slug): except VSHNAppCatPrice.DoesNotExist: pass - # Get related articles for both cloud provider and service - provider_articles = offering.cloud_provider.articles.filter( - is_published=True - ).order_by("-created_at")[:3] - service_articles = offering.service.articles.filter(is_published=True).order_by( - "-created_at" - )[:3] - context = { "offering": offering, "pricing_data_by_group_and_service_level": pricing_data_by_group_and_service_level, "price_calculator_enabled": price_calculator_enabled, - "provider_articles": provider_articles, - "service_articles": service_articles, } return render(request, "services/offering_detail.html", context) diff --git a/hub/services/views/partners.py b/hub/services/views/partners.py index ac3668e..4645c69 100644 --- a/hub/services/views/partners.py +++ b/hub/services/views/partners.py @@ -84,14 +84,8 @@ def partner_detail(request, slug): slug=slug, ) - # Get related articles for this partner - related_articles = partner.articles.filter(is_published=True).order_by( - "-created_at" - )[:3] - context = { "partner": partner, "services": partner.services.all(), - "related_articles": related_articles, } return render(request, "services/partner_detail.html", context) diff --git a/hub/services/views/providers.py b/hub/services/views/providers.py index 376d8df..3e8b965 100644 --- a/hub/services/views/providers.py +++ b/hub/services/views/providers.py @@ -64,15 +64,9 @@ def provider_detail(request, slug): ) ) - # Get related articles for this cloud provider - related_articles = provider.articles.filter(is_published=True).order_by( - "-created_at" - )[:3] - context = { "provider": provider, "services": services, "ordered_offerings": ordered_offerings, - "related_articles": related_articles, } return render(request, "services/provider_detail.html", context) diff --git a/hub/services/views/services.py b/hub/services/views/services.py index b9dd1da..fc6d275 100644 --- a/hub/services/views/services.py +++ b/hub/services/views/services.py @@ -153,13 +153,7 @@ def service_detail(request, slug): slug=slug, ) - # Get related articles for this service - related_articles = service.articles.filter(is_published=True).order_by( - "-created_at" - )[:3] - context = { "service": service, - "related_articles": related_articles, } return render(request, "services/service_detail.html", context) diff --git a/hub/settings.py b/hub/settings.py index 68452ad..7ffec5a 100644 --- a/hub/settings.py +++ b/hub/settings.py @@ -244,8 +244,6 @@ JAZZMIN_SETTINGS = { "url": "https://servala.com", "new_window": True, }, - {"name": "Articles", "url": "/admin/services/article/"}, - {"name": "FAQs", "url": "/admin/services/websitefaq/"}, ], "show_sidebar": True, "navigation_expanded": True,