Skip to content

Commit

Permalink
Merge pull request #97 from springload/feature/blog-page-bed
Browse files Browse the repository at this point in the history
blog page and blog landing page
  • Loading branch information
sarahframe authored Jun 12, 2024
2 parents 4891783 + 95b3324 commit f488bda
Show file tree
Hide file tree
Showing 18 changed files with 402 additions and 154 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 5.0.5 on 2024-06-11 21:08

from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("blog", "0012_alter_blogpost_body"),
]

operations = [
migrations.RenameField(
model_name="blogpost",
old_name="featured_image",
new_name="image",
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Generated by Django 5.0.5 on 2024-06-11 21:17

import wagtail.fields
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("blog", "0013_rename_featured_image_blogpost_image"),
]

operations = [
migrations.AddField(
model_name="blogpost",
name="alt_text",
field=models.CharField(
blank=True,
help_text="Describe the image for screen readers",
max_length=80,
),
),
migrations.AddField(
model_name="blogpost",
name="caption",
field=wagtail.fields.RichTextField(
blank=True, help_text="A short caption for the image.", max_length=180
),
),
migrations.AddField(
model_name="blogpost",
name="credit",
field=wagtail.fields.RichTextField(
blank=True,
help_text="A credit line or attribution for the image.",
max_length=80,
),
),
]
24 changes: 24 additions & 0 deletions cdhweb/blog/migrations/0015_alter_blogpost_description.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 5.0.5 on 2024-06-11 21:21

import wagtail.fields
from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("blog", "0014_blogpost_alt_text_blogpost_caption_blogpost_credit"),
]

operations = [
migrations.AlterField(
model_name="blogpost",
name="description",
field=wagtail.fields.RichTextField(
blank=True,
help_text="Short introduction to the page, aim for max two clear sentences (max. 200 chars).",
max_length=200,
null=True,
verbose_name="Blog description",
),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Generated by Django 5.0.5 on 2024-06-11 21:50

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("blog", "0015_alter_blogpost_description"),
]

operations = [
migrations.AddField(
model_name="blogpost",
name="short_description",
field=models.TextField(
blank=True,
help_text="A short description of the content for promotional or navigation purposes. Displayed on tiles, not on page itself.",
max_length=130,
verbose_name="Short description",
),
),
migrations.AddField(
model_name="blogpost",
name="short_title",
field=models.CharField(
blank=True,
default="",
help_text="Displayed on tiles, breadcrumbs etc., not on page itself. ",
max_length=80,
verbose_name="Short title",
),
),
]
60 changes: 60 additions & 0 deletions cdhweb/blog/migrations/0017_bloglandingpage_and_more.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Generated by Django 5.0.5 on 2024-06-12 04:24

import django.db.models.deletion
import wagtail.fields
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("blog", "0016_blogpost_short_description_blogpost_short_title"),
("cdhpages", "0047_alter_contentpage_body_alter_homepage_body_and_more"),
("wagtailcore", "0089_log_entry_data_json_null_to_object"),
]

operations = [
migrations.CreateModel(
name="BlogLandingPage",
fields=[
(
"page_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="wagtailcore.page",
),
),
(
"description",
wagtail.fields.RichTextField(
blank=True,
help_text="Short introduction to the page, aim for max two clear sentences (max. 200 chars). \n Used to orient the user and help them identify relevancy of the page to meet their needs. ",
max_length=200,
null=True,
verbose_name="Page Summary",
),
),
],
options={
"abstract": False,
},
bases=("wagtailcore.page", models.Model),
),
migrations.RenameModel(
old_name="BlogLinkPage",
new_name="BlogLinkPageArchived",
),
migrations.AddField(
model_name="blogpost",
name="category",
field=models.CharField(
blank=True,
help_text="Category tag to display on tile",
max_length=20,
verbose_name="Category",
),
),
]
122 changes: 94 additions & 28 deletions cdhweb/blog/models.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
from datetime import date

from django.db import models
from django.db.models.fields.related import RelatedField
from django.urls import reverse
from django.utils.dateformat import format
from django.utils.functional import cached_property
from django.utils.text import Truncator
from django.utils.translation import gettext_lazy as _
from modelcluster.contrib.taggit import ClusterTaggableManager
from modelcluster.fields import ParentalKey
from modelcluster.models import ClusterableModel
from taggit.models import TaggedItemBase
from wagtail.admin.panels import FieldPanel, FieldRowPanel, InlinePanel, MultiFieldPanel
from wagtail.fields import RichTextField
from wagtail.models import Orderable, Page, PageManager, PageQuerySet
from wagtail.search import index
from wagtailautocomplete.edit_handlers import AutocompletePanel

from cdhweb.pages.mixin import StandardHeroMixinNoImage
from cdhweb.pages.models import BasePage, LinkPage, PagePreviewDescriptionMixin
from cdhweb.people.models import Person

Expand Down Expand Up @@ -54,40 +59,107 @@ class BlogPostTag(TaggedItemBase):
)


class BlogPost(BasePage, ClusterableModel, PagePreviewDescriptionMixin):
class BlogPost(BasePage, ClusterableModel):
"""A Blog post, implemented as a Wagtail page."""

featured_image = models.ForeignKey(
template = "blog/blog_post.html"

description = RichTextField(
max_length=200,
blank=True,
null=True,
features=["bold", "italic"],
verbose_name="Blog description",
help_text="Short introduction to the page, aim for max two clear sentences (max. 200 chars).",
)

image = models.ForeignKey(
"wagtailimages.image",
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="+",
help_text="Appears on the homepage carousel when post is featured.",
)
caption = RichTextField(
features=[
"italic",
"bold",
"link",
],
help_text="A short caption for the image.",
blank=True,
max_length=180,
)

credit = RichTextField(
features=[
"italic",
"bold",
"link",
],
help_text="A credit line or attribution for the image.",
blank=True,
max_length=80,
)

alt_text = models.CharField(
help_text="Describe the image for screen readers",
blank=True,
max_length=80,
)
tags = ClusterTaggableManager(through=BlogPostTag, blank=True)
featured = models.BooleanField(
default=False, help_text="Show the post in the carousel on the homepage."
)
people = models.ManyToManyField(Person, through="blog.Author", related_name="posts")

category = models.CharField(
verbose_name="Category",
help_text="Category tag to display on tile",
blank=True,
max_length=20,
)

# can only be created underneath special link page
parent_page_types = ["blog.BlogLinkPage"]
parent_page_types = ["blog.BlogLinkPageArchived", "blog.BlogLandingPage"]
# no allowed subpages
subpage_types = []

# admin edit configuration
content_panels = Page.content_panels + [
FieldRowPanel((FieldPanel("featured_image"), FieldPanel("featured"))),
FieldPanel("description"),
MultiFieldPanel(
[
FieldPanel("image"),
FieldPanel("caption"),
FieldPanel("credit"),
FieldPanel("alt_text"),
],
heading="Hero Image",
),
MultiFieldPanel(
[InlinePanel("authors", [AutocompletePanel("person")], label="Author")],
heading="Authors",
),
FieldPanel("category"),
FieldPanel("body"),
FieldPanel("attachments"),
]
promote_panels = Page.promote_panels + [FieldPanel("tags")]
promote_panels = (
[
MultiFieldPanel(
[
FieldPanel("short_title"),
FieldPanel("short_description"),
FieldPanel("feed_image"),
],
"Share Page",
),
]
+ BasePage.promote_panels
+ [FieldPanel("tags")]
)

# index description in addition to body content
search_fields = BasePage.search_fields + [
Expand All @@ -104,34 +176,16 @@ class BlogPost(BasePage, ClusterableModel, PagePreviewDescriptionMixin):
# custom manager/queryset logic
objects = BlogPostManager()

# configure template path for wagtail preview
template = "blog/blogpost_detail.html"

@property
def short_title(self):
"""Shorter title with ellipsis."""
return Truncator(self.title).chars(65)

@property
def short_description(self):
"""Shorter description with ellipsis."""
return Truncator(self.get_description()).chars(250)
@cached_property
def breadcrumbs(self):
ancestors = self.get_ancestors().live().public().specific()
return ancestors[1:] # removing root

@property
def author_list(self):
"""Comma-separated list of author names."""
return ", ".join(str(author.person) for author in self.authors.all())

def __str__(self):
# string is used for logging actions on drafts,
# needs to handle cases where first published date is not set
if self.first_published_at:
pubdate = format(self.first_published_at, "F j, Y")
else:
pubdate = "draft"

return '"%s" (%s)' % (self.short_title, pubdate)

def get_url_parts(self, *args, **kwargs):
"""Custom blog post URLs of the form /updates/2014/03/01/my-post."""
url_parts = super().get_url_parts(*args, **kwargs)
Expand Down Expand Up @@ -162,7 +216,7 @@ def get_sitemap_urls(self, request):
return urls


class BlogLinkPage(LinkPage):
class BlogLinkPageArchived(LinkPage):
"""Container page that defines where blog posts can be created."""

# NOTE this page can't be created in the page editor; it is only ever made
Expand All @@ -171,3 +225,15 @@ class BlogLinkPage(LinkPage):
# NOTE the only allowed child page type is a BlogPost; this is so that
# Events made in the admin automatically are created here.
subpage_types = [BlogPost]


class BlogLandingPage(StandardHeroMixinNoImage, Page):
"""Container page that defines where Event pages can be created."""

content_panels = StandardHeroMixinNoImage.content_panels

search_fields = StandardHeroMixinNoImage.search_fields

settings_panels = Page.settings_panels

subpage_types = [BlogPost]
Loading

0 comments on commit f488bda

Please sign in to comment.