class ThesisSimple(Page): top_image = models.ForeignKey( "wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) top_image_heading = models.CharField( max_length=255, null=True, blank=True, help_text= "Text displayed over the image. It is applicable only if an image is selected.", ) body = StreamField([ ("heading", blocks.CharBlock(classname="full title")), ("paragraph", blocks.RichTextBlock()), ("image", ImageChooserBlock()), ("embed", EmbedBlock()), ("rawHtml", blocks.RawHTMLBlock()), ( "medailon", blocks.StructBlock( [ ("title", blocks.CharBlock(required=True)), ("pic", ImageChooserBlock(required=True)), ("description", blocks.RichTextBlock(required=True)), ], template="blocks/medailon.html", icon="user", ), ), ]) content_panels = Page.content_panels + [ MultiFieldPanel( [ImageChooserPanel("top_image"), FieldPanel("top_image_heading")], heading="Top image settings", ), StreamFieldPanel("body"), ] parent_page_types = ["theses.ThesisIndexPage"] @staticmethod def build_mail_content_contact(data): return dedent(""" Name: {contact_name}, Contact email: {contact_email}, --------Message-------- {content} """.format(**data)) def serve(self, request): if request.method == "POST": form_slug = request.POST.get("formSlug") if "simpleContactForm" == form_slug: form = SimpleContactForm(request.POST) if form.is_valid(): form.clean() send_mail( "Contacting using Contact Form", self.build_mail_content_contact(form.cleaned_data), THESES_MAILS, # recipient email form.cleaned_data["contact_email"], ) return JsonResponse({ "message": "Thank you for your interest! " "We will let get back to you soon!" }) else: return super(ThesisSimple, self).serve(request) def get_context(self, request): context = super(ThesisSimple, self).get_context(request) context["contactForm"] = SimpleContactForm return context
class BlogPage(Page): date = models.DateField("Post date") intro = models.CharField(max_length=250) body = StreamField([ ('paragraph', blocks.RichTextBlock()), ('html_paragraph', blocks.RawHTMLBlock()), ('quote', blocks.BlockQuoteBlock()), ('image', ImageChooserBlock()), ]) tags = ClusterTaggableManager(through=BlogPageTag, blank=True) def main_image(self): gallery_item = self.gallery_images.first() if gallery_item: return gallery_item.image else: return None def serve(self, request): from .forms import CommentForm post = self.blogpage comments = post.comments.filter(active=True, parent__isnull=True) new_comment = None # Comment posted if request.method == 'POST': comment_form = CommentForm(request.POST) if comment_form.is_valid(): parent_obj = None # get parent comment id from hidden input try: # id integer e.g. 15 parent_id = int(request.POST.get('parent_id')) except: parent_id = None # if parent_id has been submitted get parent_obj id if parent_id: parent_obj = Comment.objects.get(id=parent_id) # if parent object exist if parent_obj: # create reply comment object reply_comment = comment_form.save(commit=False) # assign parent_obj to reply comment reply_comment.parent = parent_obj # normal comment # Create Comment object but don't save to database yet new_comment = comment_form.save(commit=False) # Assign the current post to the comment new_comment.post_id = self.id # Save the comment to the database new_comment.save() return render( request, self.template, { 'page': self, 'new_comment': new_comment, 'comments': comments, }) else: comment_form = CommentForm() return render( request, self.template, { 'page': self, 'new_comment': new_comment, 'comments': comments, 'comment_form': comment_form, }) search_fields = Page.search_fields + [ index.SearchField('intro'), index.SearchField('body'), index.SearchField('tags'), ] content_panels = Page.content_panels + [ MultiFieldPanel([ FieldPanel('date'), FieldPanel('tags'), ], heading="Blog information"), FieldPanel('intro'), StreamFieldPanel('body'), InlinePanel('gallery_images', label="Gallery images"), ]
('paragraph', blocks.RichTextBlock(features=[ 'bold', 'italic', 'h2', 'h3', 'h4', 'h5', 'ol', 'ul', 'link', 'image', 'hr', ])), ('image_text', customblocks.ImageTextBlock()), ('image', ImageChooserBlock()), ('figure', customblocks.FigureBlock()), ('figuregrid', customblocks.FigureGridBlock()), ('video', customblocks.VideoBlock()), ('iframe', customblocks.iFrameBlock()), ('linkbutton', customblocks.LinkButtonBlock()), ('spacer', customblocks.BootstrapSpacerBlock()), ] class ModularPage(MetadataPageMixin, Page): """ The base class offers universal component picking """ header = models.CharField(max_length=250, blank=True)
class ImageBlock(blocks.StructBlock): image = ImageChooserBlock() class Meta: icon = 'image' template = 'article/blocks/image.html'
class InfoBlock(StructBlock): title = CharBlock(required=True) photo = ImageChooserBlock(required=True) summary = RichTextBlock(required=True) action = CharBlock(required=False) url = URLBlock(required=False)
class BustoutBlock(StructBlock): image = ImageChooserBlock() text = RichTextBlock() class Meta: icon = "pick"
class ProjectPage( ArchiveablePageAbstract, BasicPageAbstract, ContentPage, FeatureablePageAbstract, ShareablePageAbstract, ): body = StreamField( BasicPageAbstract.body_default_blocks + BasicPageAbstract.body_poster_block + [ ('igc_timeline', StructBlock([ ('date', CharBlock(required=True)), ('title', CharBlock(required=False)), ('body', RichTextBlock(required=False)), ('location', CharBlock(required=False)), ('countries_represented', ImageChooserBlock(required=False)), ('outcomes', StreamBlock( [ ('outcome', StructBlock([ ('date', DateBlock(required=False)), ('text', RichTextBlock(required=False)), ])), ], required=False, )), ('witnesses', StreamBlock( [ ('witness_date', StructBlock([ ('date', DateBlock(required=False)), ('witnesses', StreamBlock([ ('witnesses_full_session', StructBlock([ ('title', CharBlock(required=False)), ('witness_transcript', URLBlock(required=False)), ('witness_video', URLBlock(required=False)), ])), ('witness', StructBlock([ ('name', CharBlock(required=False)), ('title', CharBlock(required=False)), ('witness_transcript', URLBlock(required=False)), ('witness_video', URLBlock(required=False)), ])), ], )), ])), ], required=False, )), ])), ], blank=True, ) project_contacts = StreamField( [ ('contact', PageChooserBlock(required=True, page_type='people.PersonPage')), ], blank=True, ) project_leads = StreamField( [ ('project_lead', PageChooserBlock(required=True, page_type='people.PersonPage')), ('external_project_lead', CharBlock(required=True)), ], blank=True, ) project_members = StreamField( [ ('project_member', PageChooserBlock(required=True, page_type='people.PersonPage')), ('external_project_member', CharBlock(required=True)), ], blank=True, ) project_types = ParentalManyToManyField('research.ProjectType', blank=True) related_files = StreamField( [ ('file', DocumentChooserBlock()), ], blank=True, ) # Reference field for the Drupal-Wagtail migrator. Can be removed after. drupal_node_id = models.IntegerField(blank=True, null=True) content_panels = [ BasicPageAbstract.title_panel, BasicPageAbstract.body_panel, MultiFieldPanel( [ FieldPanel('publishing_date'), FieldPanel('project_types'), ], heading='General Information', classname='collapsible', ), MultiFieldPanel( [ StreamFieldPanel('project_leads'), StreamFieldPanel('project_members'), StreamFieldPanel('project_contacts'), ], heading='People', classname='collapsible collapsed', ), MultiFieldPanel( [ ImageChooserPanel('image_hero'), ], heading='Images', classname='collapsible collapsed', ), MultiFieldPanel( [ FieldPanel('topics'), StreamFieldPanel('related_files'), ], heading='Related', classname='collapsible collapsed', ), ] promote_panels = Page.promote_panels + [ FeatureablePageAbstract.feature_panel, ShareablePageAbstract.social_panel, ] settings_panels = Page.settings_panels + [ ArchiveablePageAbstract.archive_panel, ] parent_page_types = ['core.BasicPage', 'research.ProjectListPage'] subpage_types = [] templates = 'research/project_page.html' class Meta: verbose_name = 'Project' verbose_name_plural = 'Projects'
class RelatedStoryBlock(blocks.StructBlock): heading = blocks.CharBlock(required=False) copy = blocks.TextBlock(required=False) image = ImageChooserBlock(required=False)
class CandidateBlock(StructBlock): image = ImageChooserBlock() caption = RichTextBlock(features=["italic"], required=False)
class ExperiencePage(Page, CommentsMixIn): name = models.CharField(blank=True, default='', max_length=MAX_LENGTH) email = models.EmailField(blank=True, default='', max_length=MAX_LENGTH) user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name='experience_pages') posted = models.DateTimeField(default=timezone.now) experience = StreamField([ ('heading', blocks.CharBlock(classname="full title")), ('paragraph', blocks.RichTextBlock()), ('image', ImageChooserBlock()), ('document', DocumentChooserBlock()), ]) importance = models.CharField(max_length=6, choices=IMPORTANCE_CHOICES, default=NA) data_reliability = models.CharField(max_length=6, choices=IMPORTANCE_CHOICES, default=NA) action = StreamField([ ('heading', blocks.CharBlock(classname="full title")), ('paragraph', blocks.RichTextBlock()), ('image', ImageChooserBlock()), ('document', DocumentChooserBlock()), ], blank=True) ranking_panels = [ FieldPanel('importance'), FieldPanel('data_reliability'), StreamFieldPanel('action'), ] content_panels = Page.content_panels + [ FieldPanel('name'), FieldPanel('email'), AutocompletePanel('user', target_model=settings.AUTH_USER_MODEL), FieldPanel('posted'), StreamFieldPanel('experience'), InlinePanel('comments', label="Comments"), ] search_fields = Page.search_fields + [ index.SearchField('experience'), ] subpage_types = [ ] # parent_page_types = [ # 'experiment.ExperimentPage', # 'homepage.ContentPage', # ] edit_handler = TabbedInterface( [ ObjectList(content_panels, heading='Content'), ObjectList(ranking_panels, heading="Ranking"), ObjectList(Page.promote_panels, heading='Promote'), ObjectList(Page.settings_panels, heading='Settings'), ] ) def __str__(self): return f'Experience Page {self.slug}' def serve(self, request): from .forms import CommentForm return self.add_comments_and_return(request, CommentForm)
class ImageCaptionBlock(blocks.StructBlock): image = ImageChooserBlock(help_text='high quality image') paragraph = blocks.RichTextBlock( features=configurations.RICHTEXT_FEATURES, required=False, )
class Lesson(Page): order = models.IntegerField(blank=True, default=0) short_description = RichTextField() lesson_type = models.CharField( choices=[(FREE, 'Free'), (PRO, 'Pro')], null=True, default='free', max_length=16, ) image = models.ImageField(upload_to='uploads/', default='static/img/lesson.jpg') tags = ClusterTaggableManager(through=LessonTag, blank=True) script = RichTextField(blank=True) # absolete: to be removed (replaced by similar_lessons) related_lessons = models.ManyToManyField( "self", blank=True, related_name='related_lessons', ) content = StreamField([('paragraph', blocks.RichTextBlock()), ('pro_paragraph', blocks.RichTextBlock()), ('image', ImageChooserBlock()), ('pro_image', ImageChooserBlock()), ('embed', EmbedBlock()), ('pro_embed', EmbedBlock()), ('code', CodeBlock()), ('pro_code', CodeBlock()), ('note', NoteBlock())], blank=True) content_panels = Page.content_panels + [ FieldPanel('order'), FieldPanel('lesson_type'), FieldPanel('first_published_at'), FieldPanel('image'), FieldPanel('short_description'), FieldPanel('tags'), FieldPanel('script'), StreamFieldPanel('content'), # https://goonan.io/manytomany-relationships-in-wagtail/ InlinePanel('similar_lessons', label="Similar Lessons") ] def __str__(self): return f"#{self.order} {self.title}" def save(self, *args, **kwargs): if not self.order: self.order = Lesson.next_order() super().save(*args, **kwargs) # Call the "real" save() method. def get_absolute_url(self): return reverse('lesson', kwargs={ 'order': self.order, 'slug': self.slug }) def get_next_lesson_obj(self): current_order = self.order ret = Lesson.objects.filter(live=True).filter(order=current_order + 1).first() return ret def get_prev_lesson_obj(self): current_order = self.order ret = Lesson.objects.filter(live=True).filter(order=current_order - 1).first() return ret def next_order(): lessons = [obj.order for obj in Lesson.objects.all()] if len(lessons) == 0: return 1 return max(lessons) + 1
class MagazineArticle(Page): teaser = RichTextField(blank=True) body = StreamField([ ("heading", blocks.CharBlock(classname="full title")), ( "paragraph", blocks.RichTextBlock(features=[ "h2", "h3", "h4", "bold", "italic", "ol", "ul", "hr", "link", "document-link", "image", "superscript", "superscript", "strikethrough", "blockquote", ]), ), ("image", ImageChooserBlock()), ("pullquote", blocks.BlockQuoteBlock()), ]) body_migrated = models.TextField( help_text="Used only for content from old Drupal website.", null=True, blank=True, ) department = models.ForeignKey( MagazineDepartment, null=True, blank=True, on_delete=models.SET_NULL, related_name="articles", ) tags = ClusterTaggableManager(through=MagazineArticleTag, blank=True) search_template = "search/magazine_article.html" search_fields = Page.search_fields + [index.SearchField("body")] content_panels = Page.content_panels + [ FieldPanel("teaser", classname="full"), StreamFieldPanel("body", classname="full"), FieldPanel("body_migrated", classname="full"), InlinePanel( "authors", heading="Authors", help_text= "Select one or more authors, who contributed to this article", ), MultiFieldPanel( [ PageChooserPanel("department", "magazine.MagazineDepartment"), FieldPanel("tags"), ], heading="Article information", ), ] parent_page_types = ["MagazineIssue"] subpage_types = [] def get_sitemap_urls(self): return [{ "location": self.full_url, "lastmod": self.latest_revision_created_at, "priority": 1, }] @property def is_public_access(self): """ Check whether article should be accessible to all readers or only subscribers based on issue publication date. """ parent_issue = self.get_parent() today = arrow.utcnow() six_months_ago = today.shift(months=-6).date() # Issues older than six months are public access return parent_issue.specific.publication_date <= six_months_ago def get_context(self, request, *args, **kwargs): context = super().get_context(request) # Subscribers and superusers can always view full articles # everyone can view public access articles # user can view full article if any of these conditions is True context["user_can_view_full_article"] = (request.user.is_subscriber or request.user.is_superuser or self.is_public_access) return context
class LogoItem(blocks.StructBlock): logo = ImageChooserBlock(required=True, help_text=_("Logo of supporter")) url = blocks.URLBlock(max_length=250, help_text=_("URL of supporter")) logo_description = blocks.CharBlock( max_length=250, help_text=_("Alt description for the image"))
class PhotoGridBlock(StructBlock): images = ListBlock(ImageChooserBlock()) class Meta: icon = "grip"
class GalleryPhotoBlock(StructBlock): image = ImageChooserBlock() caption = RichTextBlock(features=["italic"], required=False)
class PullQuoteImageBlock(StructBlock): quote = CharBlock() attribution = CharBlock() image = ImageChooserBlock(required=False)
class StreamModel(models.Model): body = StreamField([ ('text', CharBlock()), ('rich_text', RichTextBlock()), ('image', ImageChooserBlock()), ])
class WideImage(StructBlock): image = ImageChooserBlock() class Meta: icon = "image"
class Steps_StepBlock(blocks.StructBlock): step_image = ImageChooserBlock(null=True, blank=False, required=False, help_text="Image fitting this step") step_head = blocks.CharBlock(null=True, blank=False, required=False, classname="full title", help_text="Bold header text") step_subhead = blocks.RichTextBlock(null=True, blank=False, required=False, help_text="Short introduction to the following paragraph", classname="full") step_paragraph = blocks.RichTextBlock(null=True, blank=False, required=False, help_text="Step paragraph", classname="full")
class CarouselImageBlock(blocks.StructBlock): class Meta: template = "streams/carousel_image_block.html" image = ImageChooserBlock()
class Trusted_PartnerBlock(blocks.StructBlock): partner_logo = ImageChooserBlock(null=True, blank=False, required=False, help_text="Image fitting this step") partner_link = blocks.URLBlock(null=True, blank=False, required=False, help_text="Important! Format https://www.domain.tld/xyz")
class ImageCarouselBlock(StructBlock): image = ImageChooserBlock() caption = TextBlock(required=False) class Meta: icon = 'image'
class _H_HeroBlock(blocks.StructBlock): slide_image = ImageChooserBlock(null=True, blank=False, required=False, help_text="Big, high resolution slider image") slide_loadimage = blocks.BooleanBlock(null=True, blank=False, required=False, default=True, help_text="Whether or not to load the slide image from CMS (Unchecked is better for performance, only check if you want to test a new image)") slide_button = SnippetChooserBlock(Button, null=True, blank=False, required=False, help_text="The button displayed at the frontpage slider")
class LoguePage(Page): date = models.DateField("Post date") header_image = models.ForeignKey( "wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) intro = models.CharField(max_length=250) body = StreamField( [ ("richtext_section", blocks.RichTextBlock()), ("image", ImageChooserBlock()), ("code_block", CodeBlock()), ("embed", EmbedBlock()), ("html", blocks.RawHTMLBlock()), ("related_content", blocks.PageChooserBlock()), ("cards", CardBlock()), ], null=True, ) tags = ClusterTaggableManager(through=LoguePageTag, blank=True) categories = ParentalManyToManyField("logue.LogueCategory", blank=True) feed_image = models.ForeignKey( "wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) def main_image(self): gallery_item = self.gallery_images.first() if gallery_item: return gallery_item.image else: return None search_fields = Page.search_fields + [ index.SearchField("intro"), index.SearchField("body"), index.FilterField("date"), ] content_panels = Page.content_panels + [ MultiFieldPanel( [ InlinePanel( "logue_authors", label="Author", min_num=1, max_num=6), FieldPanel("date"), FieldPanel("tags"), FieldPanel("categories", widget=forms.CheckboxSelectMultiple), ], heading="Logue information", ), ImageChooserPanel("header_image"), FieldPanel("intro"), StreamFieldPanel("body"), InlinePanel("gallery_images", label="Gallery images"), InlinePanel("related_links", label="Related links"), ] promote_panels = [ImageChooserPanel("feed_image")]
class Why_ColumnBlock(blocks.StructBlock): Column_image = ImageChooserBlock(null=True, blank=False, required=False, help_text="Icon representating the below content") Column_head = blocks.CharBlock(null=True, blank=False, required=False, classname="full title", help_text="The bold header text at the frontpage slider") Column_subhead = blocks.RichTextBlock(null=True, blank=False, required=False, help_text="The content of the frontpage slider element", classname="full") Column_paragraph = blocks.RichTextBlock(null=True, blank=False, required=False, help_text="Formatted text", classname="full")
class TraineePage(Page): CATEGORY_CHOICES = ( ('story', '蜕变故事'), ('picture', '瑜伽图片'), ('video', '光影瑜伽'), ) date = models.DateField('发表日期') category = models.CharField('类别', choices=CATEGORY_CHOICES, max_length=16, default='picture') name = models.CharField('姓名', max_length=32, blank=True) age = models.CharField('年龄', max_length=8, default='保密') occupation = models.CharField('职业', max_length=16, default='自由职业者') intro = RichTextField('简介', max_length=128, blank=True) body = StreamField([ ('标题', blocks.CharBlock(classname="full title")), ('段落', blocks.RichTextBlock()), ('图片', ImageChooserBlock()), ]) tags = ClusterTaggableManager(through=TraineePageTag, blank=True) class Meta: verbose_name = '学员详情页' verbose_name_plural = verbose_name def thumbnail_image(self): gallery_item = self.gallery_images.first() if gallery_item: return gallery_item.image else: return None def main_doc(self): gallery_item = self.gallery_docs.first() if gallery_item: return gallery_item.doc else: return None search_fields = Page.search_fields + [ index.SearchField('name'), index.SearchField('intro'), index.SearchField('body'), ] content_panels = Page.content_panels + [ MultiFieldPanel([ FieldPanel('date'), FieldPanel('tags'), ], heading="内容属性"), MultiFieldPanel([ FieldPanel('name'), FieldPanel('age'), FieldPanel('occupation'), FieldPanel('intro'), FieldPanel('category'), ], heading='学员简介'), StreamFieldPanel('body'), InlinePanel('gallery_images', label='Gallery images'), InlinePanel('gallery_docs', label='Gallery documents') ] def get_context(self, request): wallpaper = Image.objects.filter( tags__name="学员壁纸").order_by('-created_at')[0] # Update template context context = super().get_context(request) context['wallpaper'] = wallpaper return context
class BlogPage(Page): author = models.CharField("Author", max_length=150) date = models.DateField("Post date") body = StreamField( [ ("title", blocks.CharBlock(classname="blog-title")), ("paragraph", blocks.RichTextBlock()), ("image", ImageChooserBlock()), ("image_w_caption", ImageCaptionBlock()), ("two_images", TwoImageBlock()), ] ) tags = ClusterTaggableManager(through=BlogPageTag, blank=True) categories = ParentalManyToManyField("blog.BlogCategory", blank=True) def blog_preview(self): for block in self.body: if block.block_type == "paragraph": return block.value else: return "No Preview for this blog" def preview_image(self): for block in self.body: # IF we have a block that is the image type if block.block_type == "image": return block.value # If we have a block that is an image with a caption elif block.block_type == "image_w_caption": return block.value["image"] # If we have a two image block elif block.block_type == "two_images": # Get the left image stream block left_image = block.value["left_image"] # If the first image (because there should only ever be one) # in the left image is an image block if left_image[0].block_type == "image": return left_image[0].value # If the first image (because there should only ever be one) # in the left image is an image block with a caption, grap the image return left_image[0].value["image"] else: return None search_fields = Page.search_fields + [ index.SearchField("title"), index.SearchField("author"), index.SearchField("body"), index.RelatedFields( "tags", [ index.RelatedFields( "tag", [index.SearchField("name", partial_match=True, boost=10)], ) ], ), index.RelatedFields("categories", [index.SearchField("name"),]), ] content_panels = Page.content_panels + [ MultiFieldPanel( [ FieldPanel("author"), FieldPanel("date"), FieldPanel("tags"), FieldPanel("categories", widget=forms.CheckboxSelectMultiple), ], heading="Blog information", ), StreamFieldPanel("body"), ]
class ColumnWithTitleIconTextBlock(HeadingContentBaseBlock): icon = ImageChooserBlock(required=False) image_alt = blocks.CharBlock(required=False)
class SublandingPage(CFGOVPage): portal_topic = models.ForeignKey( 'v1.PortalTopic', blank=True, null=True, related_name='portal_pages', on_delete=models.SET_NULL, help_text='Select a topic if this is a MONEY TOPICS portal page.') header = StreamField([ ('hero', molecules.Hero()), ], blank=True) content = StreamField([ ('text_introduction', molecules.TextIntroduction()), ('notification', molecules.Notification()), ('featured_content', organisms.FeaturedContent()), ('full_width_text', organisms.FullWidthText()), ('info_unit_group', organisms.InfoUnitGroup()), ('well', organisms.Well()), ('snippet_list', organisms.ResourceList()), ('post_preview_snapshot', organisms.PostPreviewSnapshot()), ('contact', organisms.MainContactInfo()), ('table_block', organisms.AtomicTableBlock( table_options={'renderer': 'html'} )), ('reg_comment', organisms.RegComment()), ('feedback', v1_blocks.Feedback()), ], blank=True) sidebar_breakout = StreamField([ ('slug', blocks.CharBlock(icon='title')), ('heading', blocks.CharBlock(icon='title')), ('paragraph', blocks.RichTextBlock(icon='edit')), ('breakout_image', blocks.StructBlock([ ('image', ImageChooserBlock()), ('is_round', blocks.BooleanBlock(required=False, default=True, label='Round?')), ('icon', blocks.CharBlock(help_text='Enter icon class name.')), ('heading', blocks.CharBlock(required=False, label='Introduction Heading')), ('body', blocks.TextBlock(required=False, label='Introduction Body')), ], heading='Breakout Image', icon='image')), ('related_posts', organisms.RelatedPosts()), ('job_listing_list', JobListingList()), ], blank=True) # General content tab content_panels = CFGOVPage.content_panels + [ StreamFieldPanel('header'), StreamFieldPanel('content'), FieldPanel('portal_topic'), ] sidebar_panels = [ StreamFieldPanel('sidebar_breakout'), ] + CFGOVPage.sidefoot_panels # Tab handler interface edit_handler = TabbedInterface([ ObjectList(content_panels, heading='General Content'), ObjectList(sidebar_panels, heading='Sidebar'), ObjectList(CFGOVPage.settings_panels, heading='Configuration'), ]) template = 'sublanding-page/index.html' objects = PageManager() search_fields = CFGOVPage.search_fields + [ index.SearchField('content'), index.SearchField('header') ] def get_browsefilterable_posts(self, limit): filter_pages = [p.specific for p in self.get_appropriate_descendants() if 'FilterablePage' in p.specific_class.__name__ and 'archive' not in p.title.lower()] posts_list = [] for page in filter_pages: eligible_children = AbstractFilterPage.objects.live().filter( CFGOVPage.objects.child_of_q(page) ) form = FilterableListForm(filterable_pages=eligible_children, wagtail_block=None) for post in form.get_page_set(): posts_list.append(post) return sorted(posts_list, key=lambda p: p.date_published, reverse=True)[:limit]