<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>mattdorn.com &#187; plone</title>
	<atom:link href="http://www.mattdorn.com/content/tag/plone/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.mattdorn.com</link>
	<description>Generously funded by Matt Dorn</description>
	<lastBuildDate>Sun, 07 Feb 2010 00:07:14 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Plone i18n: a brief tutorial</title>
		<link>http://www.mattdorn.com/content/plone-i18n-a-brief-tutorial/</link>
		<comments>http://www.mattdorn.com/content/plone-i18n-a-brief-tutorial/#comments</comments>
		<pubDate>Fri, 20 Apr 2007 12:47:54 +0000</pubDate>
		<dc:creator>mdorn</dc:creator>
				<category><![CDATA[technology]]></category>
		<category><![CDATA[i18n]]></category>
		<category><![CDATA[plone]]></category>

		<guid isPermaLink="false">http://67.207.132.145/wordpress/?p=44</guid>
		<description><![CDATA[


The following tutorial details the steps I took to internationalize (starting with a Spanish translation) the interface of Plone Translation Hub, a Plone Archetypes-based product.

Contents

Basic Plone i18n with i18ndude
Advanced Plone i18n
Translating workflow states and transitions
Accessing the Plone translation machinery directly


Resources



Basic Plone i18n with i18ndude
First, processing your UML model via ArchGenXML (assuming you have i18ndude installed) [...]]]></description>
			<content:encoded><![CDATA[
<div class="document">
<!-- -*- mode: rst -*- -->
<p>The following tutorial details the steps I took to internationalize (starting with a Spanish translation) the interface of <a class="reference" href="http://plonexl8.textmethod.com">Plone Translation Hub</a>, a Plone Archetypes-based product.</p>
<div class="contents topic">
<p class="topic-title first"><a id="contents" name="contents">Contents</a></p>
<ul class="simple">
<li><a class="reference" href="#basic-plone-i18n-with-i18ndude" id="id1" name="id1">Basic Plone i18n with i18ndude</a></li>
<li><a class="reference" href="#advanced-plone-i18n" id="id2" name="id2">Advanced Plone i18n</a><ul>
<li><a class="reference" href="#translating-workflow-states-and-transitions" id="id3" name="id3">Translating workflow states and transitions</a></li>
<li><a class="reference" href="#accessing-the-plone-translation-machinery-directly" id="id4" name="id4">Accessing the Plone translation machinery directly</a></li>
</ul>
</li>
<li><a class="reference" href="#resources" id="id5" name="id5">Resources</a></li>
</ul>
</div>
<div class="section">
<h2><a class="toc-backref" href="#id1" id="basic-plone-i18n-with-i18ndude" name="basic-plone-i18n-with-i18ndude">Basic Plone i18n with i18ndude</a></h2>
<p>First, processing your UML model via ArchGenXML (assuming you have <a class="reference" href="http://plone.org/products/i18ndude">i18ndude</a> installed) will produce a file called <tt class="docutils literal"><span class="pre">generated.pot</span></tt> and place it in your product&#8217;s <tt class="docutils literal"><span class="pre">i18n</span></tt> directory, which is where all translations must go.  Plone makes somewhat customized use of a the GNU <a class="reference" href="http://oriya.sarovar.org/docs/gettext/">gettext</a> architecture for i18n of applications.  So <tt class="docutils literal"><span class="pre">generated.pot</span></tt> is a template that contains the labels and text for your Archetypes objects.</p>
<p>Before you can begin translating, though, you&#8217;ll need to ensure that the elements in your your page templates that expose text to the user are tagged for translation by the Plone translation architecture.  First you want to make sure that you specify the <tt class="docutils literal"><span class="pre">domain</span></tt> element in the template&#8217;s root (<tt class="docutils literal"><span class="pre">html</span></tt>) element to correspond to your product:</p>
<pre class="literal-block">
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;en&quot;
    lang=&quot;en&quot;
    metal:use-macro=&quot;here/main_template/macros/master&quot;
    i18n:domain=&quot;PRODUCT_NAME&quot;&gt;
</pre>
<p>Next, for field labels, help indicators, etc.&#8211;any text that&#8217;s visible to your user&#8211;you&#8217;ll need to apply the <tt class="docutils literal"><span class="pre">i18n:translate</span></tt> attribute:</p>
<pre class="literal-block">
&lt;label for=&quot;my_field&quot; i18n:translate=&quot;PRODUCT_NAME_label_my_field&quot;&gt;Enter your name&lt;/label&gt;
</pre>
<p>Once you&#8217;ve finished applying this attribute in your page templates, if your product is fairly simple, you&#8217;re nearly finished.  All you need to do is merge the original PO file from your Archetypes product with your new translatable items from your page templates.  Assuming i18ndude is in your path, from your product&#8217;s root directory, execute it like so:</p>
<pre class="literal-block">
i18ndude rebuild-pot --pot i18n/PRODUCT_NAME.pot --create PRODUCT_NAME --merge i18n/generated.pot skins/PRODUCT_NAME/*.pt
</pre>
<p>Then create an empty PO file for the language(s) you want to create.  E.g., for Spanish, you&#8217;d want:</p>
<pre class="literal-block">
touch i18n/PRODUCT_NAME-es.po
</pre>
<p>Finally, to populate the PO file with the text from the original template so that you can translate it:</p>
<pre class="literal-block">
i18ndude sync --pot i18n/PRODUCT_NAME.pot i18n/PRODUCT_NAME-es.po
</pre>
<p>You can now perform your translations with a tool like <a class="reference" href="http://www.poedit.net/">POEdit</a>.</p>
</div>
<div class="section">
<h2><a class="toc-backref" href="#id2" id="advanced-plone-i18n" name="advanced-plone-i18n">Advanced Plone i18n</a></h2>
<div class="section">
<h3><a class="toc-backref" href="#id3" id="translating-workflow-states-and-transitions" name="translating-workflow-states-and-transitions">Translating workflow states and transitions</a></h3>
<p>Now, if your product has its own workflow states and transitions, you&#8217;ll want to translate those as well.  Enabling those translations is not included in the above process.  You&#8217;ll need to create a separate file with a name reflecting the &quot;plone&quot; domain:</p>
<pre class="literal-block">
touch i18n/plone-PRODUCT_NAME-es.po
</pre>
<p>(Note also that the PO file header includes a &quot;Domain&quot; key to which you&#8217;ll want to assign the value &quot;plone&quot;.)</p>
<p>Essentially you&#8217;ll need to edit this file by hand, assigning the <tt class="docutils literal"><span class="pre">msgid</span></tt> key with the original text and the <tt class="docutils literal"><span class="pre">msgstr</span></tt> with your translation:</p>
<pre class="literal-block">
msgid &quot;Open&quot;
msgstr &quot;Abierto&quot;

msgid &quot;Closed&quot;
msgstr &quot;Cerrado&quot;
</pre>
</div>
<div class="section">
<h3><a class="toc-backref" href="#id4" id="accessing-the-plone-translation-machinery-directly" name="accessing-the-plone-translation-machinery-directly">Accessing the Plone translation machinery directly</a></h3>
<p>You may have some text in your application that appears neither in your page templates nor in your workflow (obviously a situation that you want to avoid if possible).  If so, you may need to access the Plone translation machinery directly, which is best illustrated with an example taken from an External Method used by my product:</p>
<pre class="literal-block">
from Products.CMFCore.utils import getToolByName
...
translation_service = getToolByName(self, 'translation_service')
msg = translation_service.utranslate(domain='PloneXL8',
                                     msgid='You have taken ownership of this translation.',
                                     default='You have taken ownership of this translation.',
                                     context=self)
msg = msg.encode('utf-8')
</pre>
<p>Note that you&#8217;ll need to add the <tt class="docutils literal"><span class="pre">msgid</span></tt> and <tt class="docutils literal"><span class="pre">msgstr</span></tt> for such into your PRODUCT_NAME.pot and/or PRODUCT_NAME-xx.po file by hand.</p>
</div>
</div>
<div class="section">
<h2><a class="toc-backref" href="#id5" id="resources" name="resources">Resources</a></h2>
<p>Some helpful links:</p>
<ul class="simple">
<li><a class="reference" href="http://docs.neuroinf.de/programming-plone/i18n">Basic Plone i18n</a></li>
<li><a class="reference" href="http://plone.org/products/archgenxml/documentation/how-to/handling-i18n-translation-files-with-archgenxml-and-i18ndude">Archetypes and i18ndude</a></li>
<li><a class="reference" href="http://plone.org/documentation/manual/plone-developer-reference/patterns/referencemanual-all-pages">Plone best practices</a></li>
<li><a class="reference" href="http://plone.org/development/teams/i18n/datetime">Date and time localization</a></li>
</ul>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.mattdorn.com/content/plone-i18n-a-brief-tutorial/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Updating Plone user roles programatically</title>
		<link>http://www.mattdorn.com/content/updating-plone-user-roles-programatically/</link>
		<comments>http://www.mattdorn.com/content/updating-plone-user-roles-programatically/#comments</comments>
		<pubDate>Mon, 12 Mar 2007 13:35:46 +0000</pubDate>
		<dc:creator>mdorn</dc:creator>
				<category><![CDATA[technology]]></category>
		<category><![CDATA[plone]]></category>

		<guid isPermaLink="false">http://67.207.132.145/wordpress/?p=42</guid>
		<description><![CDATA[


Today for a site using Plone Translation Hub I had to programatically update the roles for all users who had logged in since March 9th, given that this group was known to be responsible enough to be worthy of the &#34;Reviewer&#34; role.  One of the site managers asked that I simply run a &#34;SQL [...]]]></description>
			<content:encoded><![CDATA[
<div class="document">
<!-- -*- mode: rst -*- -->
<p>Today for a site using <a class="reference" href="http://plonexl8.textmethod.com/">Plone Translation Hub</a> I had to programatically update the roles for all users who had logged in since March 9th, given that this group was known to be responsible enough to be worthy of the &quot;Reviewer&quot; role.  One of the site managers asked that I simply run a &quot;SQL query&quot; to do this&#8211;if only it were that easy!  Actually it&#8217;s not that much harder with the ZODB, but it took me a while to find the &quot;userFolderEditUser&quot; method that I needed to do this, which was frustrating.  I ended up simply using a temporary script object placed in the root of the portal:</p>
<pre class="literal-block">
recent_date=DateTime('2007/03/09')
total=0
recent=0

mship = context.portal_membership
acl_users = context.acl_users
for user in mship.listMembers():
    login_time=DateTime(user.last_login_time)
    roles = list(user.getRoles())
    if login_time.greaterThanEqualTo(recent_date) and 'Reviewer' not in roles:
        roles.append('Reviewer')
        acl_users.userFolderEditUser(user.id, None, roles, user.getDomains())
        recent += 1
    total += 1
print &quot;Recent users: &quot; + str(recent)
print &quot;Total users: &quot; + str(total)
return printed
</pre>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.mattdorn.com/content/updating-plone-user-roles-programatically/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Getting AWStats to show Plone-authenticated users</title>
		<link>http://www.mattdorn.com/content/getting-awstats-to-show-plone-authenticated-users/</link>
		<comments>http://www.mattdorn.com/content/getting-awstats-to-show-plone-authenticated-users/#comments</comments>
		<pubDate>Sun, 15 Oct 2006 19:12:36 +0000</pubDate>
		<dc:creator>mdorn</dc:creator>
				<category><![CDATA[technology]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[awstats]]></category>
		<category><![CDATA[plone]]></category>
		<category><![CDATA[zope]]></category>

		<guid isPermaLink="false">http://67.207.132.145/wordpress/?p=36</guid>
		<description><![CDATA[


I&#8217;m using AWStats to track usage on a Plone site that&#8217;s essentially a portal for collaborative document translation.  That means that most users of the site need to login to do anything useful, and I want to see who&#8217;s logging in along with the rest of the stats on my site.
For hosting the site, [...]]]></description>
			<content:encoded><![CDATA[
<div class="document">
<!-- -*- mode: rst -*- -->
<p>I&#8217;m using AWStats to track usage on a Plone site that&#8217;s essentially a portal for collaborative document translation.  That means that most users of the site need to login to do anything useful, and I want to see who&#8217;s logging in along with the rest of the stats on my site.</p>
<p>For hosting the site, I&#8217;m using the recommended setup which uses Zope&#8217;s Virtual Host Monser to route requests and responses between Apache and the Zope application server appropriately.  I.e., I include the following two key lines in my Apache directive:</p>
<pre class="literal-block">
RewriteEngine On
RewriteRule ^/(.*) http://localhost:8080/VirtualHostBase/http/%{SERVER_NAME}:80/MyApp/VirtualHostRoot/$1 [NC,P,L]
</pre>
<p>Since I&#8217;m going thru Apache, I can record requests in log files as with any other site.  Unfortunately, Zope/Plone does not pass information about the users who authenticate via its own system to the HTTP headers.  Taking a cue from <a class="reference" href="http://mail.zope.org/pipermail/zope/2006-May/166316.html">this thread</a>, I came up with the following solution.  It&#8217;s tested on Plone 2.1.3, but probably won&#8217;t work on Plone 2.5, given the latter&#8217;s use of Pluggable Authentication Service.</p>
<p>First, I found a place in the Plone page rendering mechanism that gets executed on each page view.  I suppose the place that I chose was somewhat arbitrary, but in the &quot;authenticate&quot; method of the file <tt class="docutils literal"><span class="pre">GroupUserFolder/GroupUserFolder.py</span></tt>, I set a header called <tt class="docutils literal"><span class="pre">X-PloneUser</span></tt>, as shown in the following patch, available for your use:</p>
<pre class="literal-block">
1020,1022d1019
&lt;         # PATCH FOR TRACKING AUTH USER IN APACHE LOGS --mdorn:
&lt;         if name is not None:
&lt;             request.RESPONSE.setHeader('X-PloneUser', name)
</pre>
<p>In my Apache configuration, I had to change <tt class="docutils literal"><span class="pre">LogFormat</span></tt> from &quot;combined&quot; to something more specific, and reference the label in the <tt class="docutils literal"><span class="pre">CustomLog</span></tt>:</p>
<pre class="literal-block">
LogFormat &quot;%h %l %{X-Ploneuser}o %t \&quot;%r\&quot; %&gt;s %b \&quot;%{Referer}i\&quot; \&quot;%{User-agent}i\&quot;&quot; plone
CustomLog &quot;|/usr/local/sbin/cronolog /home/httpd/MYDOMAIN/logs/%m-%Y/access_log&quot; plone
</pre>
<p>To see authenticated users in your AWStats configuration file, you&#8217;ll need to change the default value for that setting:</p>
<pre class="literal-block">
ShowAuthenticatedUsers=1
</pre>
<p>That&#8217;s it.  Next time AWStats processes your logs, assuming you had visits from authenticated users, you&#8217;ll now see them in the appropriate location on your AWStats report.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.mattdorn.com/content/getting-awstats-to-show-plone-authenticated-users/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Optimizing Plone performance with caching</title>
		<link>http://www.mattdorn.com/content/optimizing-plone-performance-with-caching/</link>
		<comments>http://www.mattdorn.com/content/optimizing-plone-performance-with-caching/#comments</comments>
		<pubDate>Fri, 09 Sep 2005 15:07:01 +0000</pubDate>
		<dc:creator>mdorn</dc:creator>
				<category><![CDATA[technology]]></category>
		<category><![CDATA[mattdorn.com]]></category>
		<category><![CDATA[plone]]></category>
		<category><![CDATA[web development]]></category>

		<guid isPermaLink="false">http://67.207.132.145/wordpress/?p=15</guid>
		<description><![CDATA[


NOTE: This document is something of a brain-dump.  I&#8217;m still experimenting with various caching techniques, and would like to organize it somewhat better, so it&#8217;s currently a work in progress.
I&#8217;ve long been a big fan of the Plone CMS, which powers this very Web site.  Any ambivalent feelings I may have had about [...]]]></description>
			<content:encoded><![CDATA[
<div class="document">
<!-- -*- mode: rst -*- -->
<p>NOTE: This document is something of a brain-dump.  I&#8217;m still experimenting with various caching techniques, and would like to organize it somewhat better, so it&#8217;s currently a work in progress.</p>
<p>I&#8217;ve long been a big fan of the Plone CMS, which powers this very Web site.  Any ambivalent feelings I may have had about it have generally derived from its sometimes brutal tendency to hog resources.  Throw in some Zope- and ZWiki-related memory leaks while you&#8217;re trying to run this thing on a machine with only 400 MB of RAM and you&#8217;re going to run into problems (this very scenario was the source of major headaches for me over the last year).</p>
<p>But Plone is a powerful, elegantly-designed, object-oriented system.  These attributes don&#8217;t come for free&#8211;they can require heavy-duty hardware resources.  When you don&#8217;t necessarily have them, the trick is to find a workaround.</p>
<p>In this case, that workaround is server-side caching.  That&#8217;s something I&#8217;ve known for a long time, but for whatever reason, its implementation remained more or less a mystery to me despite having read up on it in a few different sources, <a class="reference" href="http://docs.neuroinf.de/PloneBook">The Definitive Guide to Plone</a> among them.  It wasn&#8217;t until I created this site, refamiliarizing myself with Plone, and then began to reinvestigate the subject that it finally clicked in a way that made me feel silly for not being able to solve this problem in short order on the sites on that poor, memory-challenged server.  Revisiting the Definitive Guide and reading through a <a class="reference" href="http://plone.org/documentation/tutorial/optimizing-plone/introduction">tutorial</a> on plone.org got me to where I wanted to be.  One of the fundamental realizations I made was that the only thing the Plone HTTP Cache Manager really does is apply a cache-related headers to server reponses so that Apache, if in fact it&#8217;s being used, can do something with them.  It doesn&#8217;t do any caching itself at all, unlike the RAM Cache manager (more on that below).</p>
<p>So here&#8217;s what I did:</p>
<p>I&#8217;m running Plone 2.1, fronted by Apache 2.0  on the server.  I knew that what I needed to do to cut back on unnecessary performance hits was to keep requests from ever getting to the Zope server to begin with&#8211;i.e., those requests would need to grab a copy of the resource from a cache.  For most sites, this one included, anonymous users of the site don&#8217;t really need to see brand spanking-new content more than once per hour, so the idea would be that each resource on a site is cached for up to an hour: the first user to grab a page at, say, 5:45 PM will get it fresh from the Zope server, while any subsequent user will get a static copy of that content from the caching server, rather than from the Zope DB, until 6:45 PM, at which point it may have changed, and a new copy will be retrieved from Zope upon the next request for it.</p>
<p>(Incidentally, here&#8217;s another consideration to keep in mind: while a listing of recent content might change a few times per day on this site, an individual document will almost never change.  If you have the ability to distinguish between these types of pages for caching purposes, it may be worthwhile to do so&#8211;i.e., you could expire the content listing every hour, but expire an individual content page once per day.)</p>
<p>Anyway, I think part of my previous problem involved the notion that I had that any kind of caching would necessarily have to involve learning yet another major server-side application, the Squid proxy server.  But as it turns out both Apache 1.3 and Apache 2.0 include proxy server caching capabilities.  With mod_cache, and the new modules mod_disk_cache and mod_memory_cache, Apache 2.0 can either manage cached items on disk or in memory.  Because memory seems to be the resource that&#8217;s in short supply in most server environments I find myself in, I stick with mod_disk_cache.</p>
<p>To enable caching on the Apache side, what I ended up with was an Apache entry that looks something like this:</p>
<pre class="literal-block">
&lt;VirtualHost *&gt;
ServerName www.mysite.com
RewriteEngine On
RewriteRule ^/(.*) http://localhost:8080/VirtualHostBase
   /http/mysite.com:80/mdorn/VirtualHostRoot/$1 [NC,P,L]
CacheRoot &quot;/var/cache/apache2/proxy&quot;
CacheEnable disk /
CacheSize 10000
CacheDefaultExpire 1
&lt;/VirtualHost&gt;
</pre>
<p>Essentially I&#8217;m identifying and enabling a cache directory that will accommodate 10 MB of items.  I believe that <tt class="docutils literal"><span class="pre">CacheDefaultExpire</span> <span class="pre">1</span></tt> applies a one hour expiration policy to any item that has been signaled for caching, but without specifying a time period.  That&#8217;s probably irrelevant for Plone caching.  There are several other related directives that I don&#8217;t include here because after reading up a bit in the Apache docs, the default values seem fine for my purposes.</p>
<p>Once you&#8217;ve got Apache running with these new directives, go into your default HTTP Cache Manager in your Plone site.  Now, for anything that you want to cache that&#8217;s in the ZODB (e.g., in the &quot;custom&quot; directory of portal_skins) you&#8217;ll need to undertake the tedious process of associating those items with the cache object in the &quot;Associate&quot; tab.  But if the items that you want to cache are filesystem objects (and ideally they will be), you&#8217;ll need to create a &quot;.metadata&quot; file associating them with your HTTPCache object.  For example. if you have a page template called &quot;my_template.zpt&quot;, you&#8217;d create a file in the same directory called &quot;my_template.zpt.metadata&quot; with the following contents:</p>
<pre class="literal-block">
[default]
title = My Page Template
cache = HTTPCache
</pre>
<p>You <em>can</em> &quot;associate&quot; them in the ZMI, but your settings are lost when Zope is restarted.</p>
<p>It&#8217;s also worth noting here that there are probably some objects that you want to cache <em>always</em>.  These would probably include images, JavaScript and CSS.  By default, many stock Plone objects of these types have metadata files to do just that, but it may make sense simply to add the following directives to your Apache entry to avoid having to manage this in Plone at all:</p>
<pre class="literal-block">
ExpiresActive On
ExpiresByType image/gif A3600
ExpiresByType image/png A3600
ExpiresByType image/jpeg A3600
ExpiresByType text/css A3600
ExpiresByType text/javascript A3600
ExpiresByType application/x-javascript A3600
</pre>
<p>By default, HTTPCache is set to expire all your cacheable items 3600 seconds (i.e., one hour) after first access.  As I mention above, it would be nice to be able to distinguish between content types and vary that number accordingly.  By creating a caching policy (as per page 452 of the Definitive Guide), you can apparently do exactly that, as well as make other kinds of distinctions using any Python expression, but I think I will start with a global expiration time, of any content that I happen to be caching, of one hour.  (Note: I couldn&#8217;t get this to work properly by following The Definitive Guide Example anyway.)</p>
<p>In order to test that things were working, before implementing caching, I ran Apache benchmark (ab) like so:</p>
<pre class="literal-block">
/usr/sbin/ab -n 100 http://mattdorn/
</pre>
<p>which sent 100 requests to the server&#8211;each one went to get the content from Zope, and it took nearly a minute.  Afterward, I associated the main template that&#8217;s used by my home page, which happens to be atct_topic_view, with the HTTP cache.  Once I thus had caching implemented, the same benchmark was nearly instantaneous, after the first page access, as you&#8217;d probably expect, given that it&#8217;s just Apache grabbing some static files out of a cache directory at this point.</p>
<p>I also changed the interval to 30 seconds, and issued requests within and after that time period while tailing $INSTANCE/log/Z2.log to see whether requests were being received by Zope appropriately (i.e., only after the interval had expired).  It, too, worked as expected.</p>
<p>So what if your site is a little more dynamic than this one, and you want to be able to, say, keep one of the portlets updated in real time, while you&#8217;re fine with the content in the main column only being updated every hour?  Well, that requires a somewhat different strategy that involves using the RAM cache (which has nothing to do with HTTP headers at all), and probably some reprogramming of your site.  Additionally, you won&#8217;t get <em>nearly</em> the performance advantages you realize by the global HTTP caching strategy.  The Definitive Guide provides a very good example of RAM Cache use by pointing to the author&#8217;s site, ZopeZen.org.  On the home page of that site, a Python script generates the Web log entries, with a tally of comments for each entry.  That&#8217;s a quite expensive call, as it turns out.  The site&#8217;s owner decides he can live with this listing only being updated every 30 minutes, and so he assigns the script that produces this information to the RAM cache, achieving a five-fold performance advantage.  I considered trying this method by assigning my &quot;folder_contents_custom&quot; template, which controls the portion of the page that displays my Web log entries (i.e., it&#8217;s called by atct_topic_view), but as far as I can tell, only Python scripts and External Methods can be used with a RAM cache.  I suppose I could reprogram my site to do all of the heavy lifting within a Python script rather than within the ZPT if I really needed this.</p>
<p>One final thing to note is that by default, Plone&#8217;s HTTP Cache object doesn&#8217;t send cache headers when you&#8217;re authenticated.  That&#8217;s a good thing, because when you&#8217;re editing content, you implicitly need server responses to be fully dynamic.  So content editing sessions will be the only time that your server is put under the standard stress that a Plone site is capable of inflicting.</p>
<p>In retrospect, my discoveries and conclusions here are consistent with a <a class="reference" href="http://www.ifpeople.net/resources/downloads/PlonePerformance.pdf">report</a> that I myself commissioned, but in order for me to really understand what was going on, I had to have a real-life scenario to play with.  Guess that&#8217;s not too surprising.</p>
<p>Unfortunately, the caching procedures described here have not been implemented on this site as of this writing, because I do not adminster the box that it runs on.  I&#8217;m sure I&#8217;ll get it done in short order.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.mattdorn.com/content/optimizing-plone-performance-with-caching/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Launching the site</title>
		<link>http://www.mattdorn.com/content/launching-the-site/</link>
		<comments>http://www.mattdorn.com/content/launching-the-site/#comments</comments>
		<pubDate>Tue, 06 Sep 2005 04:17:36 +0000</pubDate>
		<dc:creator>mdorn</dc:creator>
				<category><![CDATA[mattdorn.com]]></category>
		<category><![CDATA[plone]]></category>

		<guid isPermaLink="false">http://67.207.132.145/wordpress/?p=13</guid>
		<description><![CDATA[


Welcome to my third or fourth attempt at a site resembling a Web log!  This one runs on a state-of-the-art Python-based, open source Content Management System called Plone.  Certainly far more more firepower than any Web log needs, but I&#8217;m thinking that using this as a platform will have spillover effects that create [...]]]></description>
			<content:encoded><![CDATA[
<div class="document">
<!-- -*- mode: rst -*- -->
<p>Welcome to my third or fourth attempt at a site resembling a Web log!  This one runs on a state-of-the-art <a class="reference" href="http://www.python.org/">Python</a>-based, open source Content Management System called <a class="reference" href="http://www.plone.org/">Plone</a>.  Certainly far more more firepower than any Web log needs, but I&#8217;m thinking that using this as a platform will have spillover effects that create learning opportunities for messing around with other technologies.  Also, I can no longer imagine composing documents in anything else other than Restructured Text, which is native to Plone (though I&#8217;m sure I could have modified any simpler Web log software to let me use that).  Probably the biggest drawback I can see is the fact that the main CSS file is 111 KB.  Even with a fairly fast connection, first accesses to this site will be unacceptably slow.  Once the stylesheet is cached on the client side, it&#8217;s fine, but I&#8217;m worried about situations where caching may not be taking place.</p>
<p>Anyway, probably the biggest deal (and a big motivator for me to get a site going again), is being able to use this great skin, a Product called &quot;Plix&quot;&#8211;look for it on the Plone site.</p>
<p>The first release of this site consists of one folder to contain all the content, and three &quot;smart folders&quot; to display the content on the basis of its subject matter.  &quot;Smart folders&quot; used to be called &quot;topics&quot; in Plone, and essentially they&#8217;re canned queries that enable you to set a series of criteria for filtering content by content type, location, subject, etc.  In Plone 2.1, you can control the order, forward or reverse, in which the results are shown, based on various criteria including creation date, which is what I use here. Another nice aspect of Smart Folders is the built-in batch control, where you can select how many records to show on a page.  In my case, I&#8217;ve got it set up for 5.</p>
<p>I wanted this site to basically consist of two Web logs, separated because the different content matter (information technology and international relations) is unlikely to be of interest to the same audience.  In fact what I&#8217;ve decided to do is let the home page mix the two types by simply being a running, chronological log, while maintaining them separate via the &quot;tech&quot; and &quot;ideas&quot; part of the site&#8217;s URL.  This reduces the utility of the home page, I suppose, and is a policy that will probably will be revisited.</p>
<p>Rather than using one of the Blog products available for Plone (e.g., Quills), it struck me as best to use a tried-and-true standard Plone content type, the &quot;News&quot; item.  All I needed to do was modify the template that displays the items (&quot;folder_listing&quot; from &quot;plone_templates&quot;) to be more Blog like, which for me meant to display the entire body of the News item on the pages that serve as the Web log.  Note that I also sometimes post &quot;Page&quot; content, which tends to be longer, more polished content, like an essay.  I conditionalize on the content type to only show the item description if the item is something other than News.  Because my Plone stills had become rusty from lack of use, these issues were a little more complicated than I&#8217;d thought, but in retrospect involved some pretty simple changes.  I also changed the ATContentTypes template &quot;atct_topic_view&quot; to use my own &quot;folder_listing_custom&quot; customization of &quot;folder_listing&quot;, so that the normal Plone &quot;folder_listing&quot; template is used for any non-bloggish folders.</p>
<p>As soon as I get a chance to turn my modifications into a filesystem product, I&#8217;ll post the results of that effort in the &quot;Open&quot; section of this site.</p>
<p>Some other changes that were made:</p>
<div class="section">
<h2><a id="language" name="language">Language</a></h2>
<p>For now, there will be no multilingual content on the site, so I wanted to override the Plone default behavior of translating navigation elements into the browser&#8217;s language.  For this I installed Plone Language Tool (which now comes with Plone), and disabled &quot;Use browser language request negotiation.&quot;</p>
<p>Tabs</p>
<hr class="docutils" />
<p>In &quot;Navigation Settings&quot;, I clicked off &quot;Automatically generate tabs&quot;.  I set these manually in portal_actions in the ZMI.  &quot;Tech&quot; for example appears in the tab navigation, because I added an action of category &quot;portal_tabs&quot;, set the permissions so that anyone with &quot;view&quot; priveleges (which includes anonymous users) can see it, and gave it a URL that would point to my &quot;tech&quot; Smart Folder, which displays all content relating to information technology.  A &quot;Contents&quot; tab appears only to the portal manager, when he logs in.  It&#8217;s the folder that contains all the content.</p>
<p>Properties</p>
<hr class="docutils" />
<ul class="simple">
<li>In the properties of the Plone object itself, I made the default_page my &quot;home_listing&quot; Smart Folder which gets all News Items and Documents and sorts and batches them appropriately.</li>
<li>In portal_registration, I made the &quot;join&quot; action invisible.</li>
<li>In portal_properties -&gt; site_properties, I changed localTimeFormat and localLongTimeFormat for maximally human-readable dates.</li>
</ul>
<p>RSS Syndication</p>
<hr class="docutils" />
<ul class="simple">
<li>In the ZMI, click the portal_syndication tool.</li>
<li>Activate syndication in the &quot;properties&quot; tab.</li>
<li>Now go to your Plone site and notice that there&#8217;s a new &quot;syndication&quot; tab on any folderish objects, which include &quot;smart folders&quot; or queries.  When you enable syndication for your selected folders a new &quot;RSS&quot; icon will appear with a link that can be used as the RSS feed.</li>
</ul>
<p>Language</p>
<p>Random Weirdness</p>
<hr class="docutils" />
<p>At some point the portal catalog got completely hosed and would not return search results correctly&#8211;each item was assigned a 1% relevant rating upon any advanced search, and a simple search would return no results at all.  I ended up having to transplant the content to a new Plone site and reconfigure the stuff described above.  Hope it doesn&#8217;t happen again.</p>
<p>Granted, I did a lot of the development on a release candidate version.  I noticed that other random weirdness, not noted here, was resolved by upgrading the final release.</p>
<p>TO DO</p>
<hr class="docutils" />
<ul class="simple">
<li>Turn everything in the portal_skins &quot;custom&quot; directory into a filesystem product.</li>
<li>Fix CSS of quick search form so that it shows up in I.E. (currently only appears in Firefox).</li>
<li>del.icio.us links portlet</li>
<li>Make calendar dates link to content.  Otherwise do away with the calendar entirely.</li>
<li>Enable comments, ensuring comments spam can&#8217;t happen.</li>
<li>Make RSS syndication put the first paragraph (or 250 words or whatever) of the entry into the &quot;description&quot; field&#8211;I don&#8217;t usually supply a separate &quot;description&quot; for my entries.</li>
<li>Figure out how to make Restructured Text the default type.</li>
<li>Implement ATAmazon portlet, since books are a big focus of the &quot;ideas&quot; section.  Also book cover graphics give the site a lot more character.</li>
</ul>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.mattdorn.com/content/launching-the-site/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
