Skin layers, portal_skins and CMFCore.SkinsTool are old-fashioned way to manage Plone templates.
Skin files are put under skins folder in your add-on product.
The structure looks like:
GenericSetup skins.xml:
<?xml version="1.0"?>
<object name="portal_skins" meta_type="Plone Skins Tool">
<object name="headeranimation" meta_type="Filesystem Directory View"
directory="plone.app.headeranimation:skins/headeranimation"/>
<skin-path name="*">
<layer name="headeranimation" insert-after="custom"/>
</skin-path>
</object>
ZCML to register the layer:
<configure
...
xmlns:cmf="http://namespaces.zope.org/cmf">
<cmf:registerDirectory name="skins" directory="skins" recursive="True" />
</configure>
If you test templates in your unit testing code you might need to call PloneTestCase._refreshSkinData():
def afterSetUp(self):
# Must be called to load our add-on skins folders
# for unit testing
self._refreshSkinData()
Templates must be bound to context object before rendering. Plone acquisition magic maps templates as acquired attributes of all contentish objects.
Example:
# Any page object
doc = portal.doc
# portal_skins/plone_content/document_view.pt template bound to document
doc.document_view
# Resulting HTML is rendered when template object is called
doc.document_view()
Below is some example code how templates behave.
Example:
(Pdb) doc
<ATDocument at /plone/doc>
(Pdb) template = doc.document_view
(Pdb) template
<FSPageTemplate at /plone/document_view used for /plone/doc>
(Pdb) template._filepath
'/home/moo/workspace2/plone.app.headeranimation/plone/app/headeranimation/skins/headeranimation/document_view.pt'