Archive for May 2005

Caching is good for you

I’ve asked [Apache][] to start sending out Cache-Control and Expires headers for PNG and JPEG images. They are set to expire after one week — this means that your browser wont even try to load the images from my server until a week has passed. This should give you a more smooth browsing experience because the browser only fetches the [XHTML][].

The trick is very simple, just add the following to a .htaccess file:

<IfModule mod_expires.c>
    ExpiresActive on
    ExpiresByType image/jpeg "now plus 1 week"
    ExpiresByType image/png "now plus 1 week"
</IfModule>

Also, I’ve turned indexes on in the /downloads/ directory — this is also very simple, just make a .htaccess file with

Options +Indexes

No more `showsource.php`

Some 250 people (this month alone) have tried to access my old script to show the source of [PHP][] scripts. Showing the source of a PHP script in a colorful way is trivial using the highlight_file() function, which is a built-in PHP function.

My little script had just a small amount of extra functionality: it tried to find URLs and file names and substituted them with links. Unfortunately this is such a crude hack that I’ve removed the file.

For much better replacements, please see the PEAR Text_Highlighter class (support for 11 languages) or the Generic Syntax Highlighter (support for 35 languages).

Hmm, all this reminds me that I still haven’t installed a plugin to let me do syntax highlighting in my own posts…

Global variables in WordPress

[WordPress logo][wordpress] In my critique of the code in WordPress I talked about the frequent use of global variables, something this I think it a bad practice. In response Owen Winkler writes that:

Global variables are used in WordPress in many places to make things simpler for a novice end-user to design. [...]

The point is that novice plugin and template designers shouldn’t have to worry about object-oriented syntax, and therefore lots of object members are put into the global scope.

It might be easy, but I still find this a poor way to pass information around in an application. The global variables obscure the relationship between functions. Take my example from the original rant, the mysql2date() function — it’s the second function (or third, depending on whether or not you expect Gettext to be active) in wp-includes/functions.php.

The first line in the body declares four global variables named $month, $weekday, $month_abbrev, and $weekday_abbrev. So this function is obviously somehow dependent on those variables being initialized. So the first question is: can I always call mysql2date()? Do I first have to call some initialization function, or is this guaranteed to be done for me when I want to use mysql2date() in some plugin or template?

It’s not such a big mystery to figure out where the variables come from: a quick grep reveals that they are defined in locale.php. But who takes care of including locale.php? Another grep, and one sees that this is done by wp-settings.php — I guess that file is always loaded, and thus one can be sure that $month and the other globals are indeed initialized before a call to mysql2date().

No wait! On close inspection of wp-settings.php one sees that locale.php is loaded after the active plugins are loaded, and after a call to do_action('plugins_loaded'). So does this mean that a

plugin that attaches itself to the plugins_loaded action cannot call mysql2date()? I believe it does!

In my installation I found no other references to the plugins_loaded action, and so this could explain why this bug wasn’t found earlier. But in any case — if the developers had taken the time to properly document this dependency between locale.php and functions.php, then the problem should never have occurred in the first place.

This potential bug wasn’t the reason for my initial worries about the use of global variables: I had been trying to get the Smart link plugin working. It uses a global $comments variable to know which comments to process, but the comments.php template doesn’t define it to be global — in fact the $comments variable is a local variable in the comments_template() function in comment-functions.php. This function includes comments.php, and thus $comments has the local scope in that file. (These scope rule games in PHP are just so annoying!)

I now see that the problem that triggered my anger against the global variables was in fact a use of a non-global variable, expecting it to be global. A bit ironic that I were to find a problem with a totally different function, mysql2date(), while initially being started by a mistake in a plugin…

Feedback on my rant

My rant about the quality of the WordPress code caused some discussion, both here and on the WP hackers mailinglist.

I understand if my comments seemed harsh, especially because I’m quite new to [WordPress][], but I still think they were justified. Especially the point about having comments in the code, where I think that (I’m quoting myself here):

[...] the idea that there can be such a thing as well-written code containing no comments is bogus: it is only in small toy examples that the function and argument names are enough to determine what a function does.

Comments are very important in a weakly-typed language like [PHP][] where you cannot tell anything at all from looking at the function.

Fix your Markdown comments

If you — like me — are using the [PHP Markdown][] plugin to make it easy and fast to write posts without dealing with heavy-duty [XHTML][] markup, then you’ll need an additional plugin: Denis de Bernardy’s Markdown fix plugin.

Even with the latest version of PHP Markdown this plugin is needed to ensure that comments are treated properly. Without the fix all comments will be treated as a single paragraph, lists and verbatim sections wont work, and people will generally have a hard time of making coherent comments in your blog!