Six Feet Up loves Plone, but using Plone as a blogging tool has never been a strong point. Blogging isn't something that we felt that Plone did well out of the box. Much like most Plone products, you have to add in various third party products or create your own products if you want to get some of the really nice features that many of the typical blogging platforms like WordPress offer today like pingbacks. We had tried quite a few of these ways of stuffing blogging into Plone and ran into various issues of dependencies or incompatibilities along the way so we decided to go for a solution that wasn't in Plone.
Zine is a blogging platform written in Python and supports being deployed as a WSGI application, so it seemed like the perfect fit. Zine is basically a python clone of WordPress and has all the nice goodies and plugins that modern blogging platforms have come to enjoy. It is also relatively easy to theme and write plugins to extend its behavior.
We can also run Plone as a WSGI application by using the Repoze application repoze.zope2 instead of the standard Zope ZPublisher. The big benefit is that we can run multiple WSGI applications in a single process and utilize WSGI middleware like Deliverance to theme all of the applications as they are delivered. This type of setup can simplify deployment greatly and all works well with buildout, which we have a lot of knowledge about already.
Let's start by getting repoze.zope2, zine and deliverance added to our buildout. I added four additional parts to our existing buildout profile to get this process started.
[buildout]
...
parts =
...
repoze # this needs to be before the zope2 part or plone won't work
...
deliverance # these have to go at the end or paster won't get all the right eggs listed
zine-deps
zine
I also added this to the [buildout] section to pin the version of the zopelib:
find-links =
...
http://dist.repoze.org/zope2/latest/zopelib-2.10.7.0.tar.gz
...
versions=versions
[versions]
zopelib = 2.10.7.0
In these four new parts we will add in the new bits required to host the full WSGI stack for our deployment. Here are the parts we added:
[repoze]
recipe = zc.recipe.egg
eggs =
PasteScript
WSGIUtils
repoze.zope2
${plone:eggs}
index = http://dist.repoze.org/plone/latest/simple
[deliverance]
recipe = infrae.subversion
as_eggs = true
urls =
http://codespeak.net/svn/z3/deliverance/trunk deliverance
[zine-deps]
recipe = zc.recipe.egg
extra-paths = parts/zine/lib/zine
interpreter = python
eggs = Paste
PasteScript
PasteDeploy
${instance:eggs}
${repoze:eggs}
${deliverance:eggs}
SQLAlchemy>=0.5.0
Jinja2>=2.1.0
Werkzeug>=0.4
simplejson
html5lib
pytz
Babel>=0.9.4
lxml>=2.0
Pygments>=0.9
docutils==0.5
zinebuildout>=0.4
MySQL-python
[zine]
recipe = zc.recipe.cmmi
url = http://zine.pocoo.org/releases/Zine-0.1.2.tar.gz
extra_options = --python=python
With all of that added to your buildout profile you need to re-run buildout and it will download and install all the needed parts for you.
Before we can start up the new WSGI stack with paster
, we will need to create a paster.ini
for the WSGI stack and a rules.xml
file for deliverance to use.
You can put both of these files in the root of your buildout. The paste.ini
is using the zinebuildout egg to allow us to use Zine as an application in our paster stack. It is configured in the [app:zine] section. You will need to make an empty zine
directory in your buildout that will contain the zine.ini
once Zine has been configured through the web.
The paste.ini
file configures two pipelines, one for each application. The blog pipeline has the deliverance filter applied to it so you get the Plone theme applied to the Zine blog.
paste.ini
[DEFAULT]
debug = True
[app:zine]
use = egg:zinebuildout
instance_folder = %(here)s/zine
[app:zope2]
paste.app_factory = repoze.obob.publisher:make_obob
repoze.obob.get_root = repoze.zope2.z2bob:get_root
repoze.obob.initializer = repoze.zope2.z2bob:initialize
repoze.obob.helper_factory = repoze.zope2.z2bob:Zope2ObobHelper
zope.conf = %(here)s/parts/instance/etc/zope.conf
[filter:errorlog]
use = egg:repoze.errorlog#errorlog
path = /__error_log__
keep = 20
ignore = paste.httpexceptions:HTTPUnauthorized
paste.httpexceptions:HTTPNotFound
paste.httpexceptions:HTTPFound
[pipeline:zope]
pipeline = egg:Paste#cgitb
egg:Paste#httpexceptions
egg:repoze.retry#retry
egg:repoze.tm#tm
egg:repoze.vhm#vhm_xheaders
errorlog
zope2
[pipeline:blog]
pipeline = egg:Paste#cgitb
egg:Paste#httpexceptions
errorlog
deliverance
zine
[filter:deliverance]
use = egg:deliverance#main
rule_filename = %(here)s/rules.xml
[server:main]
use = egg:repoze.zope2#zserver
host = localhost
port = 51047
[composite:main]
use = egg:Paste#urlmap
/blog = blog
/zope = zope
Deliverance is configured in the rules.xml
file and points to the Plone application's main_template to get the look and feel. The rest of the rules drop bits that aren't needed and throw the Zine portlets and content into the right places in the Plone theme. We created a Zine plugin to wrap the Zine portlets with a more Plone like structure so that they blend right into the Plone theme.
rules.xml
<ruleset>
<theme href="/zope/Plone/main_template" />
<rule>
<prepend theme="//head" content="//head/link" nocontent="ignore" />
<prepend theme="//head" content="//head/style" nocontent="ignore" />
<append theme="//head" content="//head/script" nocontent="ignore" />
<append theme="//head" content="//head/meta" nocontent="ignore" />
<replace theme="//head/title" content="//head/title" nocontent="ignore" />
<!-- we don't need the reddit zine links -->
<drop content="//div[@class='reddit']"/>
<!-- let's drop the breadcrumbs from the plone theme -->
<drop theme="#portal-breadcrumbs"/>
<!-- let's drop the plone login box -->
<drop theme="//td[@id='portal-column-one']/div/div"/>
<!-- put the zine portlets in column one -->
<append theme="//td[@id='portal-column-one']/div" content="//div[@class='sidebar']/*" nocontent="ignore"/>
<!-- put the body of the zine in the content region -->
<append theme="children:#region-content" content="children://div[@class='contents']" nocontent="ignore" />
<!-- put the administrative links in column two -->
<prepend theme="children:#portal-column-two" content="//div[@class='body']/ul" nocontent="ignore"/>
<!-- make sure the login box has a spot when we need it -->
<append theme="#viewlet-above-content" content="//div[@class='login-box']" nocontent="ignore"/>
</rule>
</ruleset>
Once these are all in place and you have created the zine
directory at the root of your buildout, we can start the paster server. It is started like this:
bin/paster serve paste.ini
Now in your browser you can go to http://localhost:8080/zope to see the Zope/Plone instance. You will need to add a Plone Site to your instance. In my demo I gave it an id of "Plone". If you have a Plone Site with a different id, you will need to change the path to the in your rules.xml.
Now, when you go to http://localhost:8080/blog you will be presented with the Zine setup screens. If all went well, the screens should look like your Plone Site theme. At this point you will need to setup a MySQL database to hold the blog data and provide connection information as you go through the Zine setup wizard.
Now you can fix up and modify the rules.xml and theme in your Plone site to make the Zine blog blend into your site seamlessly. Enjoy!