diff --git a/senat_campaign/migrations/0006_auto_20200601_1819.py b/senat_campaign/migrations/0006_auto_20200601_1819.py new file mode 100644 index 0000000000000000000000000000000000000000..2f28277e69678e9ce4d59a1bed865f3042586e8d --- /dev/null +++ b/senat_campaign/migrations/0006_auto_20200601_1819.py @@ -0,0 +1,63 @@ +# Generated by Django 3.0.6 on 2020-06-01 16:19 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("wagtailimages", "0022_uploadedimage"), + ("senat_campaign", "0005_delete_senatcampaignwebsettings"), + ] + + operations = [ + migrations.AddField( + model_name="senatcampaigncookiespage", + name="search_image", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="wagtailimages.Image", + verbose_name="Search image", + ), + ), + migrations.AddField( + model_name="senatcampaignhomepage", + name="search_image", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="wagtailimages.Image", + verbose_name="Search image", + ), + ), + migrations.AddField( + model_name="senatcampaignnewsindexpage", + name="search_image", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="wagtailimages.Image", + verbose_name="Search image", + ), + ), + migrations.AddField( + model_name="senatcampaignprogrampage", + name="search_image", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="wagtailimages.Image", + verbose_name="Search image", + ), + ), + ] diff --git a/senat_campaign/models.py b/senat_campaign/models.py index 73855641ea1001b41218fb7f9d34c495f0ef89f9..2500019a57f8cd1353bf40d7559017070d0e0702 100644 --- a/senat_campaign/models.py +++ b/senat_campaign/models.py @@ -12,8 +12,33 @@ from wagtail.core.models import Page from wagtail.documents.blocks import DocumentChooserBlock from wagtail.images.blocks import ImageChooserBlock from wagtail.images.edit_handlers import ImageChooserPanel +from wagtailmetadata.models import MetadataPageMixin from calendar_utils.models import CalendarMixin +from tuning import help + +HELP_COMBINED_TITLE = ( + "Pokud není zadán <strong>Titulek stránky</strong>, použije se " + "<strong>Název</strong> (tab obsah) doplněný o jméno kandidáta." +) + + +class SubpageMixin: + """Must be used in class definition before MetadataPageMixin!""" + + @property + def root_page(self): + if not hasattr(self, "_root_page"): + self._root_page = self.get_parent().specific + return self._root_page + + def get_meta_image(self): + return self.search_image or self.root_page.get_meta_image() + + def get_meta_title(self): + if self.seo_title: + return self.seo_title + return f"{self.title} | {self.root_page.full_name}" class ContactBlock(blocks.StructBlock): @@ -28,7 +53,7 @@ class ContactBlock(blocks.StructBlock): label = "kontaktní osoba" -class SenatCampaignHomePage(Page, CalendarMixin): +class SenatCampaignHomePage(Page, MetadataPageMixin, CalendarMixin): # top section headline = models.CharField("podtitulek pod jménem", max_length=250, blank=True) top_photo = models.ForeignKey( @@ -123,12 +148,15 @@ class SenatCampaignHomePage(Page, CalendarMixin): promote_panels = [ MultiFieldPanel( [ - HelpPanel( - "Název stránky na předchozím tabu slouží k rozlišení stránek " - "v Majáku. V prohlížeči se zobrazí tento titulek." - ), FieldPanel("seo_title"), FieldPanel("search_description"), + ImageChooserPanel("search_image"), + HelpPanel( + help.build( + help.IMPORTANT_TITLE, + "Pokud není zadán <strong>Search image</strong>, použije se úvodní foto kandidáta.", + ) + ), ], gettext_lazy("Common page configuration"), ), @@ -165,6 +193,9 @@ class SenatCampaignHomePage(Page, CalendarMixin): def root_page(self): return self + def get_meta_image(self): + return self.search_image or self.top_photo + @property def full_name(self): return f"{self.first_name} {self.last_name}" @@ -236,7 +267,7 @@ class SenatCampaignHomePage(Page, CalendarMixin): return context -class SenatCampaignNewsIndexPage(Page): +class SenatCampaignNewsIndexPage(Page, SubpageMixin, MetadataPageMixin): parent_page_types = ["senat_campaign.SenatCampaignHomePage"] subpage_types = ["senat_campaign.SenatCampaignNewsPage"] @@ -246,6 +277,8 @@ class SenatCampaignNewsIndexPage(Page): FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), + ImageChooserPanel("search_image"), + HelpPanel(help.build(HELP_COMBINED_TITLE, help.NO_SEARCH_IMAGE)), ], gettext_lazy("Common page configuration"), ), @@ -259,12 +292,6 @@ class SenatCampaignNewsIndexPage(Page): class Meta: verbose_name = "Aktuality" - @property - def root_page(self): - if not hasattr(self, "_root_page"): - self._root_page = self.get_parent().specific - return self._root_page - def get_context(self, request): context = super().get_context(request) articles = self.get_children().live().order_by("-senatcampaignnewspage__date") @@ -272,7 +299,7 @@ class SenatCampaignNewsIndexPage(Page): return context -class SenatCampaignNewsPage(Page): +class SenatCampaignNewsPage(Page, SubpageMixin, MetadataPageMixin): date = models.DateField("datum") perex = models.TextField("perex") body = RichTextField("článek", blank=True) @@ -283,6 +310,8 @@ class SenatCampaignNewsPage(Page): null=True, blank=True, ) + # we will use photo as search image + search_image = None content_panels = Page.content_panels + [ FieldPanel("date"), @@ -297,6 +326,12 @@ class SenatCampaignNewsPage(Page): FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), + HelpPanel( + help.build( + HELP_COMBINED_TITLE, + "Pokud není zadán <strong>Popis vyhledávání</strong>, použije se prvních 150 znaků <strong>Perexu</strong> (tab obsah).", + ) + ), ], gettext_lazy("Common page configuration"), ), @@ -311,14 +346,6 @@ class SenatCampaignNewsPage(Page): class Meta: verbose_name = "Aktualita" - @property - def root_page(self): - if not hasattr(self, "_root_page"): - self._root_page = ( - self.get_ancestors().type(SenatCampaignHomePage).specific().get() - ) - return self._root_page - def get_context(self, request): context = super().get_context(request) context["related_articles"] = ( @@ -328,6 +355,24 @@ class SenatCampaignNewsPage(Page): ) return context + @property + def root_page(self): + if not hasattr(self, "_root_page"): + self._root_page = ( + self.get_ancestors().type(SenatCampaignHomePage).specific().get() + ) + return self._root_page + + def get_meta_image(self): + return self.photo + + def get_meta_description(self): + if self.search_description: + return self.search_description + if len(self.perex) > 150: + return str(self.perex)[:150] + "..." + return self.perex + class ProgramBlock(blocks.StructBlock): title = blocks.CharBlock(label="titulek") @@ -340,7 +385,7 @@ class ProgramBlock(blocks.StructBlock): label = "programový bod" -class SenatCampaignProgramPage(Page): +class SenatCampaignProgramPage(Page, SubpageMixin, MetadataPageMixin): committee_preference = StreamField( [("committee", blocks.CharBlock(label="výbor či komise"))], verbose_name="preferované výbory a komise", @@ -361,6 +406,8 @@ class SenatCampaignProgramPage(Page): FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), + ImageChooserPanel("search_image"), + HelpPanel(help.build(HELP_COMBINED_TITLE, help.NO_SEARCH_IMAGE)), ], gettext_lazy("Common page configuration"), ), @@ -377,14 +424,8 @@ class SenatCampaignProgramPage(Page): class Meta: verbose_name = "Program" - @property - def root_page(self): - if not hasattr(self, "_root_page"): - self._root_page = self.get_parent().specific - return self._root_page - -class SenatCampaignCookiesPage(Page): +class SenatCampaignCookiesPage(Page, SubpageMixin, MetadataPageMixin): body = RichTextField("obsah", blank=True) content_panels = Page.content_panels + [ @@ -397,6 +438,8 @@ class SenatCampaignCookiesPage(Page): FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), + ImageChooserPanel("search_image"), + HelpPanel(help.build(HELP_COMBINED_TITLE, help.NO_SEARCH_IMAGE)), ], gettext_lazy("Common page configuration"), ), @@ -412,9 +455,3 @@ class SenatCampaignCookiesPage(Page): class Meta: verbose_name = "Cookies" - - @property - def root_page(self): - if not hasattr(self, "_root_page"): - self._root_page = self.get_parent().specific - return self._root_page diff --git a/senat_campaign/templates/senat_campaign/base.html b/senat_campaign/templates/senat_campaign/base.html index 091d15a07b807ced7b2f095db0cbd77be14e8785..2cf07267aa1d819c992d2aa4c486308251230f76 100644 --- a/senat_campaign/templates/senat_campaign/base.html +++ b/senat_campaign/templates/senat_campaign/base.html @@ -1,4 +1,4 @@ -{% load static wagtailuserbar wagtailcore_tags wagtailimages_tags %} +{% load static wagtailuserbar wagtailcore_tags wagtailimages_tags wagtailmetadata_tags %} <!doctype html> <html lang="cs"> <head> @@ -21,29 +21,10 @@ <!-- Meta --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - <meta name="description" content="{% firstof page.search_description page.perex|truncatechars:150 %}"> - <meta name="author" content="Piráti"> - {% if page.seo_title %} - <title>{{ page.seo_title }}</title> - {% else %} - <title>{{ page.title }} | {{ page.root_page.full_name }}</title> - {% endif %} - - <!-- OpenGraph info --> - <meta property="og:title" content="{% firstof page.seo_title page.title page.root_page.full_name %}" /> - <meta property="og:type" content="website" /> - <meta property="og:locale" content="cs_CZ" /> - <meta property="og:url" content="{{ page.full_url }}" /> - {# TODO #} - <meta property="og:image" content="{% static "shared/img/og_image.jpg" %}" /> - <meta property="og:description" content="{% firstof page.search_description page.perex %}" /> + {% meta_tags %} <!-- Favicon --> - <link rel="icon" type="image/png" href="{% static "shared/favicon/favicon-196.png" %}" sizes="196x196"> - <link rel="icon" type="image/png" href="{% static "shared/favicon/favicon-128.png" %}" sizes="128x128"> - <link rel="icon" type="image/png" href="{% static "shared/favicon/favicon-96.png" %}" sizes="96x96"> - <link rel="icon" type="image/png" href="{% static "shared/favicon/favicon-32.png" %}" sizes="32x32"> - <link rel="icon" type="image/png" href="{% static "shared/favicon/favicon-16.png" %}" sizes="16x16"> + {% include "shared/favicon_snippet.html" %} <!-- Bootstrap CSS --> <link rel="stylesheet" href="{% static "shared/vendor/bootstrap-4.4.1/css/bootstrap.min.css" %}">