Skip to content

Commit

Permalink
Add Twitter Cards metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
rodfersou committed Jun 9, 2016
1 parent 39cb837 commit 2934378
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 1 deletion.
4 changes: 4 additions & 0 deletions CHANGES.rst
Expand Up @@ -6,6 +6,9 @@ There's a frood who really knows where his towel is.
2.4.2 (unreleased)
^^^^^^^^^^^^^^^^^^

- Add Twitter Cards metadata (closes `#65`_).
[rodfersou]

- Use Plone's registry instead of the ``portal_properties`` tool to store package configuration (closes `#1`_).
[hvelarde]

Expand Down Expand Up @@ -283,3 +286,4 @@ There's a frood who really knows where his towel is.
.. _`#38`: https://github.com/collective/sc.social.like/issues/38
.. _`#39`: https://github.com/collective/sc.social.like/issues/39
.. _`#56`: https://github.com/collective/sc.social.like/issues/56
.. _`#65`: https://github.com/collective/sc.social.like/issues/65
4 changes: 4 additions & 0 deletions sc/social/like/plugins/facebook/browser.py
Expand Up @@ -44,6 +44,10 @@ def __init__(self, context, request):
self.image = get_content_image(context, width=1200, height=630)
self.typebutton # XXX: needed to initialize self.width

def metadata_enabled(self):
"""Disable metadata on Plone 5"""
return not api.env.plone_version().startswith('5')

def fbjs(self):
js_source = """
(function() {
Expand Down
2 changes: 1 addition & 1 deletion sc/social/like/plugins/facebook/templates/metadata.pt
@@ -1,4 +1,4 @@
<tal:fb>
<tal:fb condition="view/metadata_enabled">
<meta property="og:site_name" tal:attributes="content view/portal_title" />
<meta property="og:url" tal:attributes="content view/url" />
<meta property="og:type" tal:attributes="content view/type" />
Expand Down
15 changes: 15 additions & 0 deletions sc/social/like/plugins/twitter/browser.py
Expand Up @@ -6,6 +6,7 @@
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
from Products.PythonScripts.standard import url_quote
from sc.social.like.interfaces import ISocialLikeSettings
from sc.social.like.utils import get_content_image
from sc.social.like.utils import get_language
from urllib import urlencode
from zope.component import getMultiAdapter
Expand All @@ -22,6 +23,8 @@ class PluginView(BrowserView):

def __init__(self, context, request):
self.context = context
self.title = context.title
self.description = context.Description()
self.request = request
# FIXME: the following could rise unexpected exceptions
# move it to a new setup() method
Expand All @@ -33,6 +36,7 @@ def __init__(self, context, request):
self.portal_title = self.portal_state.portal_title()
self.url = context.absolute_url()
self.language = get_language(context)
self.image = get_content_image(context)
self.urlnoscript = (
u'http://twitter.com/home?status=' +
url_quote(u'{0} - {1} via {2}'.format(
Expand All @@ -42,6 +46,10 @@ def __init__(self, context, request):
)
)

def metadata_enabled(self):
"""Disable metadata on Plone 5"""
return not api.env.plone_version().startswith('5')

@property
def typebutton(self):
record = ISocialLikeSettings.__identifier__ + '.typebutton'
Expand All @@ -68,3 +76,10 @@ def share_link(self):

url = 'https://twitter.com/intent/tweet?' + urlencode(params)
return url

def image_url(self):
""" Return url to image
"""
img = self.image
if img:
return img.url
7 changes: 7 additions & 0 deletions sc/social/like/plugins/twitter/templates/metadata.pt
@@ -0,0 +1,7 @@
<tal:twitter condition="view/metadata_enabled">
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image" tal:attributes="content view/image_url" tal:condition="view/image_url" />
<meta name="twitter:site" tal:attributes="content string:@${view/via}" />
<meta name="twitter:title" tal:attributes="content view/title" />
<meta name="twitter:description" tal:attributes="content view/description" />
</tal:twitter>
15 changes: 15 additions & 0 deletions sc/social/like/tests/api_hacks.py
@@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
"""Hacks to work around API inconsistencies between Archetypes and Dexterity."""


def set_image_field(obj, image, content_type):
"""Set image field in object on both, Archetypes and Dexterity."""
from plone.namedfile.file import NamedBlobImage
try:
obj.setImage(image) # Archetypes
except AttributeError:
# Dexterity
data = image if type(image) == str else image.getvalue()
obj.image = NamedBlobImage(data=data, contentType=content_type)
finally:
obj.reindexObject()
31 changes: 31 additions & 0 deletions sc/social/like/tests/test_plugin_twitter.py
@@ -1,11 +1,14 @@
# -*- coding: utf-8 -*-
from plone import api
from plone.app.testing import setRoles
from plone.app.testing import TEST_USER_ID
from plone.registry.interfaces import IRegistry
from sc.social.like.interfaces import ISocialLikeLayer
from sc.social.like.interfaces import ISocialLikeSettings
from sc.social.like.plugins.interfaces import IPlugin
from sc.social.like.testing import INTEGRATION_TESTING
from sc.social.like.testing import load_image
from sc.social.like.tests.api_hacks import set_image_field
from zope.component import getUtilitiesFor
from zope.component import getUtility
from zope.interface import alsoProvides
Expand Down Expand Up @@ -62,10 +65,38 @@ def setUp(self):
self.plugins = dict(getUtilitiesFor(IPlugin))
self.plugin = self.plugins[name]

with api.env.adopt_roles(['Manager']):
self.image = api.content.create(
self.portal, 'Image', id='test-image')

set_image_field(self.image, load_image(1024, 768), 'image/png')

def setup_content(self, portal):
portal.invokeFactory('Document', 'my-document')
self.document = portal['my-document']

def test_plugin_view_metadata(self):
plugin = self.plugin
image = self.image
plugin_view = plugin.view()
view = image.restrictedTraverse(plugin_view)
view.title = 'Twitter Title'
view.description = 'Twitter Description'
record = ISocialLikeSettings.__identifier__ + '.twitter_username'
api.portal.set_registry_record(record, 'plone')

metadata = view.metadata()
self.assertIn(
'<meta name="twitter:card" content="summary_large_image" />', metadata)
self.assertIn(
'<meta name="twitter:image" content="http://nohost/plone/test-image/@@images', metadata)
self.assertIn(
'<meta name="twitter:site" content="@plone" />', metadata)
self.assertIn(
'<meta name="twitter:title" content="Twitter Title" />', metadata)
self.assertIn(
'<meta name="twitter:description" content="Twitter Description" />', metadata)

def test_plugin_view_html(self):
plugin = self.plugin
document = self.document
Expand Down
1 change: 1 addition & 0 deletions setup.py
Expand Up @@ -67,6 +67,7 @@
'plone.browserlayer',
'plone.app.robotframework',
'plone.app.testing [robot] >=4.2.2',
'plone.namedfile [blobs]',
'robotsuite',
],
'develop': ['docutils'],
Expand Down

0 comments on commit 2934378

Please sign in to comment.