Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 6.0.2 on 2026-03-11 17:11

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("roadmap", "0005_add_new_imageblock"),
]

operations = [
migrations.AddField(
model_name="milestoneitem",
name="contributions_url",
field=models.URLField(
blank=True,
help_text="Custom URL to use for the 'Contribute' label",
verbose_name="Contributions URL",
),
),
]
18 changes: 17 additions & 1 deletion wagtailio/roadmap/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,18 @@ def get_context(self, request, *args, **kwargs):
class MilestoneItem(Orderable):
NEEDS_SPONSORSHIP_LABEL = "needs sponsorship"
SPONSORED_LABEL = "sponsored"
NEEDS_CONTRIBUTIONS_LABEL = "needs contributions"

sponsorship_url = models.URLField(
blank=True,
verbose_name="Sponsorship URL",
help_text="Custom URL to use for the 'Sponsor this' label",
)
contributions_url = models.URLField(
blank=True,
verbose_name="Contributions URL",
help_text="Custom URL to use for the 'Contribute' label",
)
number = models.IntegerField(
unique=True,
editable=False,
Expand All @@ -100,6 +106,7 @@ class MilestoneItem(Orderable):

panels = [
FieldPanel("sponsorship_url"),
FieldPanel("contributions_url"),
MultiFieldPanel(
[
FieldPanel("title", widget=readonly),
Expand Down Expand Up @@ -130,7 +137,12 @@ def labels_set(self):
@cached_property
def labels_list(self):
return sorted(
self.labels_set - {self.NEEDS_SPONSORSHIP_LABEL, self.SPONSORED_LABEL},
self.labels_set
- {
self.NEEDS_SPONSORSHIP_LABEL,
self.SPONSORED_LABEL,
self.NEEDS_CONTRIBUTIONS_LABEL,
},
key=str.lower,
)

Expand All @@ -142,6 +154,10 @@ def needs_sponsorship(self):
def sponsored(self):
return self.SPONSORED_LABEL in self.labels_set

@cached_property
def needs_contributions(self):
return self.NEEDS_CONTRIBUTIONS_LABEL in self.labels_set


class Milestone(ClusterableModel):
number = models.IntegerField(
Expand Down
43 changes: 28 additions & 15 deletions wagtailio/roadmap/templates/roadmap/roadmap_page.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,28 +41,41 @@ <h3 class="milestone-item__heading teaser-intro" id="milestone-item-{{ item.numb
{% endfor %}
</div>
</div>
{% if item.needs_sponsorship or item.sponsored %}
{% if item.needs_sponsorship or item.sponsored or item.needs_contributions %}
{% comment %}
Fallback to item.url (GitHub URL) to avoid crashing
if the sponsorship_page foreign key is unset.
{% endcomment %}
{% pageurl page.sponsorship_page item.url as sponsor_url %}
<a
class="milestone-item__sponsor-label mini-meta"
aria-describedby="milestone-item-{{ item.number }}"
href="{% firstof item.sponsorship_url sponsor_url %}"
{% if item.sponsorship_url or not page.sponsorship_page %}
{% if item.needs_sponsorship or item.sponsored %}
<a
class="milestone-item__sponsor-label mini-meta"
aria-describedby="milestone-item-{{ item.number }}"
href="{% firstof item.sponsorship_url sponsor_url %}"
{% if item.sponsorship_url or not page.sponsorship_page %}
target="_blank" rel="noreferrer"
{% endif %}
>
{% if item.needs_sponsorship %}
Sponsor this
{% include "patterns/components/icon/icon.html" with icon="arrow" variant="simple" %}
{% elif item.sponsored %}
Sponsored
{% include "patterns/components/icon/icon.html" with icon="heart" variant="simple" %}
{% endif %}
</a>
{% endif %}
{% if item.needs_contributions %}
<a
class="milestone-item__sponsor-label mini-meta"
aria-describedby="milestone-item-{{ item.number }}"
href="{% firstof item.contributions_url item.url %}"
target="_blank" rel="noreferrer"
{% endif %}
>
{% if item.needs_sponsorship %}
Sponsor this
>
Contribute
{% include "patterns/components/icon/icon.html" with icon="arrow" variant="simple" %}
{% elif item.sponsored %}
Sponsored
{% include "patterns/components/icon/icon.html" with icon="heart" variant="simple" %}
{% endif %}
</a>
</a>
{% endif %}
{% endif %}
</div>
{% endfor %}
Expand Down