Skip to content

Add customizable social media cards to blog posts #2028

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 17, 2025

Conversation

bmispelon
Copy link
Member

@bmispelon bmispelon commented Apr 11, 2025

I've tested the changes locally using this tool: https://github.com/rafaelmardojai/share-preview

@@ -15,6 +15,7 @@ class EntryAdmin(admin.ModelAdmin):
list_filter = ("is_active",)
exclude = ("summary_html", "body_html")
prepopulated_fields = {"slug": ("headline",)}
raw_id_fields = ["social_media_card"]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A raw id field is not an ideal widget for it, but it should be good enough for now ™️

(Ideally I'd like something with an image preview, along with controls to search/add/delete like you get without the raw_id_fields)

blog/models.py Outdated
Comment on lines 214 to 221
"og:type": "article",
"og:title": self.headline,
"og:description": _("Posted by {author} on {pub_date}").format(
author=self.author, pub_date=self.pub_date_localized
),
"og:article:published_time": self.pub_date.isoformat(),
"og:article:author": self.author,
"og:image": static("img/logos/django-logo-negative.png"),
"og:image:alt": "Django logo",
"og:image:type": "image/png",
"og:url": self.get_absolute_url(),
"og:site_name": "Django Project",
"twitter:card": "summary",
"twitter:creator": "djangoproject",
"twitter:site": "djangoproject",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Compared to the opengraph tags defined in base.html, here's the difference:

  • ➕ Added og:type=article
  • ➖ Removed og:image:height and og:image:width (they don't seem to be needed)
  • ➕ Added og:article:author and og:article:published_time (we have the information so it's easy enough to add)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will be interesting to see if different platforms will pick up those bits of metadata, of so we might be able to switch og:description to something else.

@bmispelon bmispelon marked this pull request as ready for review April 11, 2025 13:04
@bmispelon bmispelon requested a review from thibaudcolas April 11, 2025 13:04
@thibaudcolas thibaudcolas linked an issue Apr 16, 2025 that may be closed by this pull request
Copy link
Member

@thibaudcolas thibaudcolas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drive-by review, hopefully more later :l this seems great

blog/models.py Outdated
tags |= {
"og:image": card.full_url,
"og:image:alt": card.alt_text,
"og:image:type": card.mimetype,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think this is actually needed? I couldn’t find any indication that it is.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. I've tested it with the share-preview tool I mentioned in the PR description and none of the sites in that tool complained about the lack of og:image:type.
I've pushed a commit to remove it.

blog/models.py Outdated
Comment on lines 214 to 221
"og:type": "article",
"og:title": self.headline,
"og:description": _("Posted by {author} on {pub_date}").format(
author=self.author, pub_date=self.pub_date_localized
),
"og:article:published_time": self.pub_date.isoformat(),
"og:article:author": self.author,
"og:image": static("img/logos/django-logo-negative.png"),
"og:image:alt": "Django logo",
"og:image:type": "image/png",
"og:url": self.get_absolute_url(),
"og:site_name": "Django Project",
"twitter:card": "summary",
"twitter:creator": "djangoproject",
"twitter:site": "djangoproject",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will be interesting to see if different platforms will pick up those bits of metadata, of so we might be able to switch og:description to something else.

Copy link
Member

@carltongibson carltongibson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this @bmispelon. It LGTM except I’m not sure about the details for the OG tags method. (It’s not something I’m even remotely an expert on.)

@bmispelon bmispelon force-pushed the feat/blog-social-card branch from ffda3e9 to d820204 Compare April 16, 2025 17:32
Copy link
Member

@thibaudcolas thibaudcolas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question about unit tests

@@ -150,6 +177,10 @@ def is_published(self):

is_published.boolean = True

@property
def pub_date_localized(self):
return date_format(self.pub_date)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems to be equivalent to the previous pub_date=object.pub_date|date:"DATE_FORMAT" in templates? Makes sense.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it should. I've added a unit test to confirm it 👍🏻

return self.image.url
host = get_host()
hostname = reverse_host(host)
return f"{host.scheme}{hostname}{host.port}{self.image.url}"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of all the aspects of the additions I think this one probably warrants unit tests? I have no knowledge of django_hosts so I don’t know if this implementation is commensurate with our needs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, I've added a test 👍🏻

Comment on lines +218 to +221
"og:site_name": "Django Project",
"twitter:card": "summary",
"twitter:creator": "djangoproject",
"twitter:site": "djangoproject",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It’s a bit weird that those are in the block we have to override to start with? I don’t see why we would ever want them to be different from one page to another. What do you think, should we refactor this out of the og_tags or proceed like this? 🤔

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't see a reason why those tags should vary from page to page, but the current implementation is a result of copying the existing behavior of the base.html template. If we'd want to change it, we'd have to overhaul the base template and that's not something I'm personally ready to tackle right now.

TLDR: I vote "proceed like this" 😁

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let’s!

entry = Entry(pub_date=date(2005, 7, 21))
self.assertEqual(entry.pub_date_localized, "July 21, 2005")
with translation.override("nn"):
self.assertEqual(entry.pub_date_localized, "21. juli 2005")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yay!

@bmispelon bmispelon force-pushed the feat/blog-social-card branch from 6586b41 to b64bcb6 Compare April 17, 2025 07:43
@bmispelon bmispelon merged commit f382469 into django:main Apr 17, 2025
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Social meta images for blog content
3 participants