No more global definitions in templates
It is good practice in most cases to let the templates in your product use the main_template.pt of Plone. Until Plone 3.x this used to make a lot of variable definitions available directly in your template, as the main template pulled in definitions from the global_defines.pt template. This was handy, but the downside was that for every template lots of these variables were calculated but never used. The Plone developers decided that this was too expensive (when thinking in terms of processor time) and removed the global defines. This makes Plone faster, but it does ask for some changes in your product.
How do you know if your product needs changes? The theoretical approach would be to open all your templates in an editor and check if every variable that is used in a TALES expression (like tal:content or tal:define) has been defined earlier in that same template. Note that some variables are still globally available, the most important being context, view and template. A more practical approach is simply to try out your product in Plone 4, visit all pages that belong to your product and see if any errors occur. An error would look like this:
NameError: name 'templateId' is not defined
Look at this example changeset from CMFPlone itself to see the kind of changes that are needed.
How do you know what definition you should add to your template? The canonical place to look this up is the @@plone view from Plone 3 (not Plone 4). This is the file Products/CMFPlone/browser/ploneview.py, specifically the method _initializeData.
The most common variables that are now missing, including their definitions, are these:
<div tal:define="template_id template/getId; normalizeString nocall:context/@@plone/normalizeString; toLocalizedTime nocall:context/@@plone/toLocalizedTime; portal_properties context/portal_properties; site_properties context/portal_properties/site_properties; here_url context/@@plone_context_state/object_url; portal context/@@plone_portal_state/portal; isAnon context/@@plone_portal_state/anonymous; member context/@@plone_portal_state/member; actions python:context.portal_actions.listFilteredActionsFor(context); mtool context/portal_membership; wtool context/portal_workflow; wf_state context/@@plone_context_state/workflow_state; default_language context/@@plone_portal_state/default_language; is_editable context/@@plone_context_state/is_editable; isContextDefaultPage context/@@plone_context_state/is_default_page; object_title context/@@plone_context_state/object_title; putils context/plone_utils; ztu modules/ZTUtils; acl_users context/acl_users; ifacetool context/portal_interface; syntool context/portal_syndication;"> </div>
These changes are compatible with Plone 3.
Watch out for 'exists'!
A very sneaky thing can go wrong when you use the 'exists' keyword. Say you have a condition like this in your template: