renamed category to topic, updated all references in code. (#8812)
* renamed blogpagecategory to blogpagetopic, updated all references and routes to match. * renamed migrations * squashed migrations * updated migrations * updated bpc to blog_page_topic to be more descriptive * updated migrations * updated cards to show topic * updated more templates to show categories * updated classname from category to topic * updated migrations * feedback from PR
This commit is contained in:
Родитель
6dd8563880
Коммит
7f95567329
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -15,7 +15,7 @@ from factory import (
|
|||
from networkapi.wagtailpages.models import (
|
||||
BlogAuthors,
|
||||
BlogPage,
|
||||
BlogPageCategory,
|
||||
BlogPageTopic,
|
||||
BlogIndexPage,
|
||||
Profile,
|
||||
)
|
||||
|
@ -44,9 +44,9 @@ blog_body_streamfield_fields = [
|
|||
]
|
||||
|
||||
|
||||
def add_category(post):
|
||||
categories = BlogPageCategory.objects.all()
|
||||
post.category.add(choice(categories))
|
||||
def add_topic(post):
|
||||
topic_choices = BlogPageTopic.objects.all()
|
||||
post.topics.add(choice(topic_choices))
|
||||
post.save()
|
||||
|
||||
|
||||
|
@ -109,7 +109,7 @@ def generate(seed):
|
|||
post = BlogPageFactory.create(parent=blog_namespace, title=title)
|
||||
|
||||
add_tags(post)
|
||||
add_category(post)
|
||||
add_topic(post)
|
||||
add_authors(post)
|
||||
|
||||
for i in range(6):
|
||||
|
@ -122,7 +122,7 @@ def generate(seed):
|
|||
post = BlogPageFactory.create(parent=blog_namespace, title=title)
|
||||
|
||||
add_tags(post)
|
||||
add_category(post)
|
||||
add_topic(post)
|
||||
add_authors(post)
|
||||
|
||||
for post in BlogPage.objects.all():
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -48,8 +48,8 @@ from .pagemodels.blog.blog import (
|
|||
BlogPage,
|
||||
)
|
||||
|
||||
from .pagemodels.blog.blog_category import (
|
||||
BlogPageCategory
|
||||
from .pagemodels.blog.blog_topic import (
|
||||
BlogPageTopic
|
||||
)
|
||||
|
||||
from .pagemodels.blog.blog_index import (
|
||||
|
@ -121,7 +121,7 @@ __all__ = [
|
|||
BlogAuthors,
|
||||
BlogIndexPage,
|
||||
BlogPage,
|
||||
BlogPageCategory,
|
||||
BlogPageTopic,
|
||||
BuyersGuidePage,
|
||||
CampaignIndexPage,
|
||||
CampaignPage,
|
||||
|
|
|
@ -36,7 +36,7 @@ from ...utils import (
|
|||
)
|
||||
|
||||
from networkapi.wagtailpages.models import Profile
|
||||
from .blog_category import BlogPageCategory
|
||||
from .blog_topic import BlogPageTopic
|
||||
from .blog_index import BlogIndexPage
|
||||
|
||||
base_fields = [
|
||||
|
@ -118,11 +118,11 @@ class BlogPage(FoundationMetadataPageMixin, Page):
|
|||
block_counts={'typeform': {'max_num': 1}},
|
||||
)
|
||||
|
||||
category = ParentalManyToManyField(
|
||||
BlogPageCategory,
|
||||
help_text='Which blog categories is this blog page associated with?',
|
||||
topics = ParentalManyToManyField(
|
||||
BlogPageTopic,
|
||||
help_text='Which blog topics is this blog page associated with?',
|
||||
blank=True,
|
||||
verbose_name='Categories',
|
||||
verbose_name='Topics',
|
||||
)
|
||||
|
||||
tags = ClusterTaggableManager(through=BlogPageTag, blank=True)
|
||||
|
@ -164,7 +164,7 @@ class BlogPage(FoundationMetadataPageMixin, Page):
|
|||
],
|
||||
heading='Author(s)'
|
||||
),
|
||||
FieldPanel('category'),
|
||||
FieldPanel('topics'),
|
||||
MultiFieldPanel(
|
||||
[
|
||||
FieldPanel("hero_video"),
|
||||
|
|
|
@ -18,7 +18,7 @@ from networkapi.wagtailpages.utils import (
|
|||
from sentry_sdk import capture_exception, push_scope
|
||||
|
||||
from ..index import IndexPage
|
||||
from .blog_category import BlogPageCategory
|
||||
from .blog_topic import BlogPageTopic
|
||||
|
||||
|
||||
class FeaturedBlogPages(WagtailOrderable, models.Model):
|
||||
|
@ -47,7 +47,7 @@ class FeaturedBlogPages(WagtailOrderable, models.Model):
|
|||
class BlogIndexPage(IndexPage):
|
||||
"""
|
||||
The blog index is specifically for blog pages,
|
||||
with additional logic to explore categories.
|
||||
with additional logic to explore topics.
|
||||
"""
|
||||
|
||||
subpage_types = [
|
||||
|
@ -88,43 +88,44 @@ class BlogIndexPage(IndexPage):
|
|||
def filter_entries(self, entries, context):
|
||||
entries = super().filter_entries(entries, context)
|
||||
|
||||
if context['filtered'] == 'category':
|
||||
entries = self.filter_entries_for_category(entries, context)
|
||||
if context['filtered'] == 'topic':
|
||||
entries = self.filter_entries_for_topic(entries, context)
|
||||
context['total_entries'] = len(entries)
|
||||
|
||||
return entries
|
||||
|
||||
def filter_entries_for_category(self, entries, context):
|
||||
category = self.filtered.get('category')
|
||||
def filter_entries_for_topic(self, entries, context):
|
||||
|
||||
# The following code first updates page share metadata when filtered by category.
|
||||
topic = self.filtered.get('topic')
|
||||
|
||||
# The following code first updates page share metadata when filtered by topic.
|
||||
# First, updating metadata that is not localized
|
||||
#
|
||||
# make sure we bypass "x results for Y"
|
||||
context['no_filter_ui'] = True
|
||||
|
||||
# and that we don't show the primary tag/category
|
||||
# and that we don't show the primary tag/topic
|
||||
context['hide_classifiers'] = True
|
||||
|
||||
# store the base category name
|
||||
context['terms'] = [category.name, ]
|
||||
# store the base topic name
|
||||
context['terms'] = [topic.name, ]
|
||||
|
||||
# then explicitly set all the metadata that can be localized, making
|
||||
# sure to use the localized category for those fields:
|
||||
# sure to use the localized topic for those fields:
|
||||
locale = get_locale_from_request(context['request'])
|
||||
try:
|
||||
localized_category = category.get_translation(locale)
|
||||
localized_topic = topic.get_translation(locale)
|
||||
except ObjectDoesNotExist:
|
||||
localized_category = category
|
||||
localized_topic = topic
|
||||
|
||||
context['index_intro'] = localized_category.intro
|
||||
context['index_title'] = titlecase(f'{localized_category.name} {self.title}')
|
||||
context['index_intro'] = localized_topic.intro
|
||||
context['index_title'] = titlecase(f'{localized_topic.name} {self.title}')
|
||||
|
||||
if localized_category.title:
|
||||
context['index_title'] = localized_category.title
|
||||
if localized_topic.title:
|
||||
context['index_title'] = localized_topic.title
|
||||
|
||||
# update seo fields
|
||||
self.set_seo_fields_from_category(localized_category)
|
||||
self.set_seo_fields_from_topic(localized_topic)
|
||||
|
||||
# This code is not efficient, but its purpose is to get us logs
|
||||
# that we can use to figure out what's going wrong more than
|
||||
|
@ -133,20 +134,20 @@ class BlogIndexPage(IndexPage):
|
|||
# See https://github.com/mozilla/foundation.mozilla.org/issues/6255
|
||||
#
|
||||
|
||||
in_category = []
|
||||
in_topics = []
|
||||
|
||||
try:
|
||||
for entry in entries.specific():
|
||||
if hasattr(entry, 'category'):
|
||||
entry_categories = entry.category.all()
|
||||
if hasattr(entry, 'topics'):
|
||||
entry_topics = entry.topics.all()
|
||||
try:
|
||||
if category in entry_categories:
|
||||
in_category.append(entry)
|
||||
if topic in entry_topics:
|
||||
in_topics.append(entry)
|
||||
except Exception as e:
|
||||
if settings.SENTRY_ENVIRONMENT is not None:
|
||||
push_scope().set_extra(
|
||||
'reason',
|
||||
f'entry_categories has an iteration problem; {str(entry_categories)}'
|
||||
f'entry_topics has an iteration problem; {str(entry_topics)}'
|
||||
)
|
||||
capture_exception(e)
|
||||
|
||||
|
@ -155,92 +156,82 @@ class BlogIndexPage(IndexPage):
|
|||
push_scope().set_extra('reason', 'entries.specific threw')
|
||||
capture_exception(e)
|
||||
|
||||
entries = in_category
|
||||
|
||||
# Original code is as follows:
|
||||
#
|
||||
# entries = [
|
||||
# entry
|
||||
# for
|
||||
# entry in entries.specific()
|
||||
# if
|
||||
# hasattr(entry, 'category')
|
||||
# and
|
||||
# category in entry.category.all()
|
||||
# ]
|
||||
entries = in_topics
|
||||
|
||||
return entries
|
||||
|
||||
def set_seo_fields_from_category(self, category):
|
||||
if category.title:
|
||||
setattr(self, 'seo_title', category.title)
|
||||
elif category.name:
|
||||
setattr(self, 'seo_title', category.name)
|
||||
def set_seo_fields_from_topic(self, topic):
|
||||
if topic.title:
|
||||
setattr(self, 'seo_title', topic.title)
|
||||
elif topic.name:
|
||||
setattr(self, 'seo_title', topic.name)
|
||||
|
||||
# If description not set, default to category's "intro" text.
|
||||
# If description not set, default to topic's "intro" text.
|
||||
# If "intro" is not set, use the foundation's default meta description.
|
||||
if category.share_description:
|
||||
setattr(self, 'search_description', category.share_description)
|
||||
elif category.intro:
|
||||
setattr(self, 'search_description', category.intro)
|
||||
if topic.share_description:
|
||||
setattr(self, 'search_description', topic.share_description)
|
||||
elif topic.intro:
|
||||
setattr(self, 'search_description', topic.intro)
|
||||
|
||||
# If the category has a search image set, update page metadata.
|
||||
if category.share_image:
|
||||
setattr(self, 'search_image_id', category.share_image_id)
|
||||
# If the topic has a search image set, update page metadata.
|
||||
if topic.share_image:
|
||||
setattr(self, 'search_image_id', topic.share_image_id)
|
||||
|
||||
# helper function to resolve category slugs to actual objects
|
||||
def get_category_object_for_slug(self, category_slug):
|
||||
# helper function to resolve topic slugs to actual objects
|
||||
def get_topic_object_for_slug(self, topic_slug):
|
||||
(DEFAULT_LOCALE, DEFAULT_LOCALE_ID) = get_default_locale()
|
||||
|
||||
english_categories = BlogPageCategory.objects.filter(
|
||||
english_topics = BlogPageTopic.objects.filter(
|
||||
locale_id=DEFAULT_LOCALE_ID
|
||||
)
|
||||
|
||||
# We can't use .filter for @property fields,
|
||||
# so we have to run through all categories =(
|
||||
for bpc in english_categories:
|
||||
if bpc.slug == category_slug:
|
||||
category_object = bpc
|
||||
# so we have to run through all topics =(
|
||||
for blog_page_topic in english_topics:
|
||||
|
||||
if blog_page_topic.slug == topic_slug:
|
||||
topic_object = blog_page_topic
|
||||
break
|
||||
else:
|
||||
category_object = None
|
||||
topic_object = None
|
||||
|
||||
return category_object
|
||||
return topic_object
|
||||
|
||||
# helper function for /category/... subroutes
|
||||
def extract_category_information(self, category_slug):
|
||||
category_object = self.get_category_object_for_slug(category_slug)
|
||||
# helper function for /topic/... subroutes
|
||||
def extract_topic_information(self, topic_slug):
|
||||
|
||||
if category_object is None:
|
||||
topic_object = self.get_topic_object_for_slug(topic_slug)
|
||||
|
||||
if topic_object is None:
|
||||
raise ObjectDoesNotExist
|
||||
|
||||
self.filtered = {
|
||||
'type': 'category',
|
||||
'category': category_object
|
||||
'type': 'topic',
|
||||
'topic': topic_object
|
||||
}
|
||||
|
||||
@route(r'^category/(?P<category>.+)/entries/')
|
||||
def generate_category_entries_set_html(self, request, category, *args, **kwargs):
|
||||
@route(r'^topic/(?P<topic>.+)/entries/')
|
||||
def generate_topic_entries_set_html(self, request, topic, *args, **kwargs):
|
||||
"""
|
||||
JSON endpoint for getting a set of (pre-rendered) category entries
|
||||
JSON endpoint for getting a set of (pre-rendered) topic entries
|
||||
"""
|
||||
try:
|
||||
self.extract_category_information(category)
|
||||
self.extract_topic_information(topic)
|
||||
|
||||
except ObjectDoesNotExist:
|
||||
return redirect(self.full_url)
|
||||
|
||||
return self.generate_entries_set_html(request, *args, **kwargs)
|
||||
|
||||
@route(r'^category/(?P<category>.+)/')
|
||||
def entries_by_category(self, request, category, *args, **kwargs):
|
||||
@route(r'^topic/(?P<topic>.+)/')
|
||||
def entries_by_topic(self, request, topic, *args, **kwargs):
|
||||
"""
|
||||
If this page was called with `/category/...` as suffix, extract
|
||||
the category to filter prior to rendering this page. Only one
|
||||
category can be specified (unlike tags)
|
||||
If this page was called with `/topic/...` as suffix, extract
|
||||
the topic to filter prior to rendering this page. Only one
|
||||
topic can be specified (unlike tags)
|
||||
"""
|
||||
try:
|
||||
self.extract_category_information(category)
|
||||
self.extract_topic_information(topic)
|
||||
|
||||
except ObjectDoesNotExist:
|
||||
return redirect(self.full_url)
|
||||
|
|
|
@ -10,14 +10,14 @@ from networkapi.wagtailpages.pagemodels.customblocks.base_rich_text_options impo
|
|||
|
||||
|
||||
@register_snippet
|
||||
class BlogPageCategory(TranslatableMixin, models.Model):
|
||||
class BlogPageTopic(TranslatableMixin, models.Model):
|
||||
name = models.CharField(
|
||||
max_length=50
|
||||
)
|
||||
|
||||
title = models.TextField(
|
||||
blank=True,
|
||||
help_text='Optional title that will apear on the page and when category page is shared. '
|
||||
help_text='Optional title that will apear on the page and when topic page is shared. '
|
||||
'If not set, will default to "name" text.'
|
||||
)
|
||||
|
||||
|
@ -27,7 +27,7 @@ class BlogPageCategory(TranslatableMixin, models.Model):
|
|||
)
|
||||
share_description = models.TextField(
|
||||
blank=True,
|
||||
help_text='Optional description that will apear when category page is shared. '
|
||||
help_text='Optional description that will apear when topic page is shared. '
|
||||
'If not set, will default to "intro" text.'
|
||||
)
|
||||
share_image = models.ForeignKey(
|
||||
|
@ -36,7 +36,7 @@ class BlogPageCategory(TranslatableMixin, models.Model):
|
|||
blank=True,
|
||||
on_delete=models.SET_NULL,
|
||||
verbose_name='Share Image',
|
||||
help_text='Optional image that will apear when category page is shared.',
|
||||
help_text='Optional image that will apear when topic page is shared.',
|
||||
)
|
||||
|
||||
panels = [
|
||||
|
@ -47,7 +47,7 @@ class BlogPageCategory(TranslatableMixin, models.Model):
|
|||
ImageChooserPanel("share_image"),
|
||||
]
|
||||
|
||||
def get_categories():
|
||||
def get_topics():
|
||||
"""
|
||||
WARNING: this function is referenced by two migrations:
|
||||
|
||||
|
@ -79,5 +79,5 @@ class BlogPageCategory(TranslatableMixin, models.Model):
|
|||
return self.name
|
||||
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
verbose_name = "Blog Page Category"
|
||||
verbose_name_plural = "Blog Page Categories"
|
||||
verbose_name = "Blog Page Topic"
|
||||
verbose_name_plural = "Blog Page Topics"
|
|
@ -4,7 +4,7 @@ from django.template.defaultfilters import slugify
|
|||
from wagtail.core import blocks
|
||||
|
||||
from networkapi.wagtailpages.utils import get_locale_from_request
|
||||
from ..blog.blog_category import BlogPageCategory
|
||||
from ..blog.blog_topic import BlogPageTopic
|
||||
|
||||
|
||||
class RecentBlogEntries(blocks.StructBlock):
|
||||
|
@ -18,11 +18,11 @@ class RecentBlogEntries(blocks.StructBlock):
|
|||
help_text='Test this filter at foundation.mozilla.org/blog/tags/',
|
||||
)
|
||||
|
||||
category_filter = blocks.ChoiceBlock(
|
||||
label='Filter by Category',
|
||||
topic_filter = blocks.ChoiceBlock(
|
||||
label='Filter by Topic',
|
||||
required=False,
|
||||
choices=BlogPageCategory.get_categories(),
|
||||
help_text='Test this filter at foundation.mozilla.org/blog/category/',
|
||||
choices=BlogPageTopic.get_topics(),
|
||||
help_text='Test this filter at foundation.mozilla.org/blog/topic/',
|
||||
)
|
||||
|
||||
top_divider = blocks.BooleanBlock(
|
||||
|
@ -35,7 +35,7 @@ class RecentBlogEntries(blocks.StructBlock):
|
|||
help_text='Optional divider below content block.',
|
||||
)
|
||||
|
||||
# TODO: add in validation so that if there are no tags or category
|
||||
# TODO: add in validation so that if there are no tags or topic
|
||||
# filled in we don't allow the page to be saved, with a wagtail
|
||||
# error indication what's wrong.
|
||||
|
||||
|
@ -47,7 +47,7 @@ class RecentBlogEntries(blocks.StructBlock):
|
|||
blog_page = BlogIndexPage.objects.get(title__iexact="blog", locale=locale)
|
||||
|
||||
tag = value.get("tag_filter", False)
|
||||
category = value.get("category_filter", False)
|
||||
topic = value.get("topic_filter", False)
|
||||
|
||||
# default filter and query
|
||||
type = "tags"
|
||||
|
@ -55,26 +55,26 @@ class RecentBlogEntries(blocks.StructBlock):
|
|||
entries = []
|
||||
|
||||
# If only tag_filter is chosen we want to load entries by tag and update the url accordingly
|
||||
if tag and not category:
|
||||
if tag and not topic:
|
||||
tag = slugify(tag)
|
||||
query = tag
|
||||
blog_page.extract_tag_information(tag)
|
||||
entries = blog_page.get_entries(context)
|
||||
|
||||
'''
|
||||
If category_filter is chosen at all, we want to load entries by category and
|
||||
If topic_filter is chosen at all, we want to load entries by topic and
|
||||
update the url accordingly. Once we add validation, we'll be able to remove
|
||||
the prioritization of category and instead notify the user that they must/can
|
||||
the prioritization of topic and instead notify the user that they must/can
|
||||
only choose one filter option.
|
||||
'''
|
||||
if category and category != "All":
|
||||
type = "category"
|
||||
query = slugify(category)
|
||||
if topic and topic != "All":
|
||||
type = "topic"
|
||||
query = slugify(topic)
|
||||
try:
|
||||
# verify this category exists, and set up a filter for it
|
||||
category_object = BlogPageCategory.objects.get(name=category)
|
||||
blog_page.extract_category_information(category_object.slug)
|
||||
except BlogPageCategory.DoesNotExist:
|
||||
# verify this topic exists, and set up a filter for it
|
||||
topic_object = BlogPageTopic.objects.get(name=topic)
|
||||
blog_page.extract_topic_information(topic_object.slug)
|
||||
except BlogPageTopic.DoesNotExist:
|
||||
# do nothing
|
||||
pass
|
||||
|
||||
|
|
|
@ -223,7 +223,7 @@ class IndexPage(FoundationMetadataPageMixin, RoutablePageMixin, Page):
|
|||
|
||||
hide_classifiers = False
|
||||
if hasattr(self, 'filtered'):
|
||||
if self.filtered.get('type') == 'category':
|
||||
if self.filtered.get('type') == 'topic':
|
||||
hide_classifiers = True
|
||||
|
||||
html = loader.render_to_string(
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
{% if page.last_published_at %}
|
||||
<meta property="article:modified" content="{{ page.last_published_at|date:"DATE_FORMAT" }}"/>
|
||||
{% endif %}
|
||||
{% with category=page.specific.category.first %}
|
||||
{% if category %}
|
||||
<meta property="article:section" content="{{ category }}" />
|
||||
{% with topic=page.specific.topics.first %}
|
||||
{% if topic %}
|
||||
<meta property="article:section" content="{{ topic }}" />
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
{% if show_full_info %}
|
||||
| {% if blog_page.first_published_at %}{{ blog_page.first_published_at|date:"DATE_FORMAT" }}
|
||||
{% else %}not published yet{% endif %}
|
||||
{% with category=page.specific.category.first %}
|
||||
{% if category and blog_index %}
|
||||
{% localized_version category as localized_category %}
|
||||
| <a class="category tw-text-inherit" href="{{blog_index.localized.url}}category/{{category.slug}}">{{ localized_category }}</a>
|
||||
{% with topic=page.specific.topics.first %}
|
||||
{% if topic and blog_index %}
|
||||
{% localized_version topic as localized_topic %}
|
||||
| <a class="topic tw-text-inherit" href="{{blog_index.localized.url}}topic/{{topic.slug}}">{{ localized_topic }}</a>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
|
|
|
@ -13,12 +13,12 @@ each blog page's dominant tag)
|
|||
|
||||
{% block tags %}
|
||||
{% if hide_classifiers != True %}
|
||||
{% with category=page.specific.category.first %}
|
||||
{% if category %}
|
||||
{% localized_version category as localized_category %}
|
||||
{% with topic=page.specific.topics.first %}
|
||||
{% if topic %}
|
||||
{% localized_version topic as localized_topic %}
|
||||
{% get_root_or_page as parent_page %}
|
||||
{# If we have a "root" context variable, we know this card is generated on an index page (or index page subroute) #}
|
||||
<a class="tw-h6-heading d-block mt-3 mb-0" href="{% localizedroutablepageurl parent_page "entries_by_category" category.slug %}">{{ localized_category }}</a>
|
||||
<a class="tw-h6-heading d-block mt-3 mb-0" href="{% localizedroutablepageurl parent_page "entries_by_topic" topic.slug %}">{{ localized_topic }}</a>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
|
||||
<div class="tw-flex tw-flex-col tw-flex-1 tw-border-b-4 tw-border-gray-05 -tw-mt-5 tw-bg-white tw-relative tw-mx-2 medium:tw-mx-5 tw-p-4">
|
||||
<p class="tw-h6-heading tw-mb-2">
|
||||
{% for category in blog.localized.category.all %}
|
||||
{% localized_version category as localized_category %}
|
||||
<a href="/blog/category/{{category.slug}}">{{ localized_category }}</a>{% if not forloop.last %}, {% endif %}
|
||||
{% for topic in blog.localized.topics.all %}
|
||||
{% localized_version topic as localized_topic %}
|
||||
<a href="/blog/topic/{{topic.slug}}">{{ localized_topic }}</a>{% if not forloop.last %}, {% endif %}
|
||||
{% endfor %}
|
||||
</p>
|
||||
<h5 class="tw-mb-2 tw-h3-heading">
|
||||
|
|
|
@ -32,10 +32,10 @@
|
|||
<img src="{% image_url first.get_meta_image "fill-1000x500" %}" alt="{{ first.title }}">
|
||||
</div>
|
||||
<div class="feature-content align-self-center">
|
||||
{% if first.category.count %}
|
||||
{% with category=first.category.first %}
|
||||
{% localized_version category as localized_category %}
|
||||
<a class="tw-h6-heading d-block mb-2" href="/{{ lang_code }}/blog/category/{{ category.slug }}">{{ localized_category }}</a>
|
||||
{% if first.topics.count %}
|
||||
{% with topic=first.topics.first %}
|
||||
{% localized_version topic as localized_topic %}
|
||||
<a class="tw-h6-heading d-block mb-2" href="/{{ lang_code }}/blog/topic/{{ topic.slug }}">{{ localized_topic }}</a>
|
||||
{% endwith %}
|
||||
{% else %}
|
||||
<div class="tw-h6-heading d-md-block d-none mb-2"> </div>
|
||||
|
@ -64,10 +64,10 @@
|
|||
<div class="bg-white">
|
||||
<img src="{% image_url localized.get_meta_image "fill-700x394" %}" alt="" class="embed-responsive-item">
|
||||
<div class="p-4">
|
||||
{% if localized.category.count %}
|
||||
{% with category=localized.category.first %}
|
||||
{% localized_version category as localized_category %}
|
||||
<a class="tw-h6-heading d-block mb-1" href="/{{ lang_code }}/blog/category/{{ category.slug }}">{{ localized_category }}</a>
|
||||
{% if localized.topics.count %}
|
||||
{% with topic=localized.topics.first %}
|
||||
{% localized_version topic as localized_topic %}
|
||||
<a class="tw-h6-heading d-block mb-1" href="/{{ lang_code }}/blog/topic/{{ topic.slug }}">{{ localized_topic }}</a>
|
||||
{% endwith %}
|
||||
{% else %}
|
||||
<div class="tw-h6-heading d-md-block d-none mb-1"> </div>
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
a.category {
|
||||
a.topic {
|
||||
@include hover-focus-active {
|
||||
color: $dark-blue;
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ http://localhost:8000/en/who-we-are
|
|||
http://localhost:8000/en/blog
|
||||
http://localhost:8000/en/blog/tags/iot
|
||||
http://localhost:8000/en/blog/tags/randomnonsensetagthatdoesntexist
|
||||
http://localhost:8000/en/blog/category/mozilla-festival
|
||||
http://localhost:8000/en/blog/category/randomnonsensecateogrythatdoesntexist
|
||||
http://localhost:8000/en/blog/topic/mozilla-festival
|
||||
http://localhost:8000/en/blog/topic/randomnonsensecateogrythatdoesntexist
|
||||
http://localhost:8000/en/blog/initial-test-blog-post-with-fixed-title
|
||||
http://localhost:8000/en/opportunity/single-page-opportunity/
|
||||
http://localhost:8000/en/opportunity/multi-page-opportunity/
|
||||
|
|
|
@ -7,7 +7,7 @@ module.exports = {
|
|||
"Blog index (filtered on tag)": "/blog/tags/iot",
|
||||
"Blog index (non-existent tag)":
|
||||
"/blog/tags/randomnonsensetagthatdoesntexist",
|
||||
"Blog index (filtered on category)": "/blog/category/mozilla-festival",
|
||||
"Blog index (filtered on topic)": "/blog/topic/mozilla-festival",
|
||||
"Fixed blog post": "/blog/initial-test-blog-post-with-fixed-title",
|
||||
"Campaign index": "/campaigns",
|
||||
"Single-page campaign": "/campaigns/single-page",
|
||||
|
|
Загрузка…
Ссылка в новой задаче