Since I've seen so many poor solutions to this problem I thought I'd share mine. Here's how I make printer friendly pages.

1. Add a method in your base class that looks like this:

 def getMainTemplate(self):
      """ return the suitable METAL header object """
      # assuming zpt/main_template.zpt
      template_obj = self.main_template

      # assuming the "first" line of main_template.zpt to
      # look like this:
      # <metal:block metal:define-macro="master">
      return template_obj.macros['master']

2. Change all your Page Templates to refer to a method rather than a macro directly so that pages like index_html.zpt start like this:

<html metal:use-macro="here/getMainTemplate">

I've seen the hard coded way too many times where people do something like this <html metal:use-macro="here/main_template/macros/master"> which gives you no flexibility.

3. Now make a copy of main_template.zpt called print_main_template.zpt and the most important change is to make print.css load by default. Here's what it should look like this somewhere inside the <head> tag:

<link rel="stylesheet" type="text/css" href="/screen.css" media="screen" />
<link rel="stylesheet" type="text/css" href="/print.css" />

Note how the print.css link tag is now not conditional. Before in main_template.zpt it should have looked like this:

<link rel="stylesheet" type="text/css" href="/print.css" media="print" /> 
<link rel="stylesheet" type="text/css" href="/screen.css" media="screen" />

And note how the order is stacked just to be extra safe to weird browsers that don't understand the media condition.

As a last optional feature you should add is to add these lines at the bottom of the template 'print_main_template.zpt':

<script type="text/javascript">
window.print();
</script>
</body>
</html>

Another tip is to add something like this to the footer because it becomes useful when you look at a printed copy:

<div id="footer">
   Printed from <span tal:replace="here/absolute_url"></span> on 
   <span tal:replace="python:here.ZopeTime().strftime('%Y/%m/%d')"></span>

4. Now rewrite the method getMainTemplate() to become usefully intelligent:

  def getMainTemplate(self):
      """ return the suitable METAL header object """
      if self.REQUEST.get('print-version'):
          # assuming zpt/print_main_template.zpt
          template_obj = self.print_main_template
      else:
          # assuming zpt/main_template.zpt
          template_obj = self.main_template

      # assuming the "first" line of main_template.zpt to
      # look like this:
      # <metal:block metal:define-macro="master">
      return template_obj.macros['master']

5. Prepare the interface now for the printer friendly page. This can be done in two different ways. One way is to put a link in the footer or byline like this:

<a href="?print-version=1">Print this page</a>

Or if you want to force a particular page to always be printer friendly, for example print_invoice.zpt then write it like this:

<tal:item define="dummy python:request.set('print-version',1)"
          replace="nothing" 
 /><html metal:use-macro="here/getMainTemplate">

As a final point; how you solve your web design with screen.css and print.css varies. One way is to define multiple css files each suitable for individual things like this example shows:

<link rel="stylesheet" type="text/css" href="/typography.css" /> 
<link rel="stylesheet" type="text/css" href="/print.css" media="print" /> 
<link rel="stylesheet" type="text/css" href="/screen.css" media="screen" />

An alternative solution is to don't expect print.css to stand on its own two legs but only be a supplement of the general css file. When doing this you're probably just going to want to override some things and hide some other things like this example from a 'print.css':

body {
   width:100% !important
}

form#login, #navigation, .also-online {
  display:none
}

To conclude

This gives you a robust framework for enabling printer friendly pages that are quite different from the main template and doing it like this means that you don't have add conditional hacks to your main template that displays certain things if in printer friendly mode or not.

Most importantly, this gives you the framework for adding other versions of main template. For example these:

  • mobile_main_template.zpt (guess what for)
  • minimal_main_template.zpt (for things like Help page popups)

A healthy and fair use of METAL macros is also key to asserting that you don't have to repeat yourself too much in the copies of main_template.pt.

Good luck!



Your email will never ever be published