Ok sorry, another esoteric post about software to interrupt my usual musings, but it may help out someone who runs into this issue in the future and goes googling for an answer (since I tried doing so myself unsuccessfully)…
In writing my previous post, about Twitter Widget Pro, I needed to embed some software into the text to illustrate the code changes I’d made, and that meant finding a way to format the text of the software appropriately. A little poking around revealed several plugins for WordPress that offer this capability, two of which seemed to be the most likely candidates, SyntaxHighlighter Evolved and WP-Syntax. The first seemed to have a few more features, but I did a little checking and discovered a few “cool kids” who were using WP-Syntax, so I decided to give that a try.
As with other plugins I’ve used, installation was no problem. I downloaded the plugin’s zip file, unpacked it and uploaded it to my blog’s plugin directory on the server. From the WordPress plugin admin screen I activated the plugin and I was good to go. Or so I thought.
When writing the text of a blog post in ‘html’ edit mode, the WP-Syntax plugin is used to format a chunk of code by wrapping the text of the code with <pre> and </pre> tags and specifying the language and optionally the starting line number as attributes. So something like this –
<pre lang="php"> <?php $sometext = "Hello World"; ?> <\pre>
will generate this –
<?php $sometext = "Hello World"; ?>
This is all good. However I ran into a couple of problems. Initially the text of the code being displayed in the box was way larger than I intended it to be. The reason was that the styling for the <pre> tags was coming from the stylesheet for my WordPress theme, rather than that associated with the plugin.
It wasn’t immediately obvious to me why this was so since I could see from firebug that the plugin’s stylesheet was being loaded correctly, after the theme’s stylesheet. However, eventually I realized that there was an issue with the specificity of the rules in each stylesheet.
The plugin stylesheet is located at <root>/wp-content/plugins/wp-syntax/wp-syntax.css. The blog uses a child theme derived from the standard WordPress “Twenty-ten” theme and so styling for the theme as a whole is controlled by two stylesheets, the parent located at <root>/wp-content/themes/twentyten/style.css and the child located at <root>/wp-content/themes/markmthomson/style.css (the latter imports the former and is the one that is explicitly loaded by the browser).
The plugin stylesheet and the Twenty-ten parent theme’s stylesheet both had rules with conflicting style specifications pointing at elements within the <pre>…</pre> code block. However many of the relevant rules in the Twenty-ten theme’s stylesheet are defined in the context of the ‘#content’ id, e.g. –
#content pre { font-size: 15px; line-height: 21px; }
In contrast the rules in the plugin’s stylesheet were defined in the context of the ‘.wp-syntax’ class, e.g. –
.wp_syntax pre { ... font-size: 12px; line-height: 1.333; ... }
When two style rules apply to the same element, in general there are several factors that determine which one has precedence. There’s a reasonably full discussion of the issue in this TechRepublic article, while the official W3C explanation is here, but the short version is that when multiple rules apply to the same element, e.g. from different stylesheets, the specificity of the rules (which I’ll explain in a moment) is evaluated first and the most specific rule is the one that’s applied. If multiple rules have the same specificity, the one declared last will apply (and the exact meaning of ‘last’ is explained in the TechRepublic article).
There is a good explanation of specificity here. Basically, each css rule’s selector (e.g. like ‘.wp_syntax pre‘ in the earlier example) is assigned a numerical value that reflects the specific combination of html elements, ids and classes that make up the selector. In determining this value, each html element contributes a value of 1, each class adds 10 and each id adds 100 (in whatever numerical base is chosen). The higher the total for a given rule, the more specific that rule is considered to be.
Based on this, it’s clear that theme rules containing the #content id in their selectors will outweigh those from the WP-Syntax plugin that contain only the .wp-syntax class. This is why the formatted code blocks were being styled by the theme and not by the plugin.
The solution to this problem has two parts. First, it is necessary to modify the plugin’s css rules so that they each include the #content context in their selector as well as .wp-syntax. For example –
#content .wp_syntax pre { ... font-size: 12px; line-height: 1.333; ... }
According to the plugin’s usage documentation, customization of the plugin’s style can be accomplished by copying the css file from the plugin into the blog theme’s template directory and making modifications to it there. However a complication not mentioned in the documentation arises when the theme is a child of another one, as it is in my case.
In principle, one would want to apply such modifications to the child theme rather than the parent. I discovered, however, that placing a modified plugin css file in the child theme’s template directory did not have the desired effect. Instead, it turned out to be necessary to add wp-syntax.css to the directory for the parent Twenty-ten theme and make the required modifications there.
Although this worked, it’s not a perfect solution. Part of the point of the way WordPress child themes work is to decouple modifications in style from the definition of the original theme. Adding the wp-syntax style sheet to the parent violates this principle.
I posted a query on the WordPress support forum to see if anyone had run into this issue and had a better solution and sure enough someone (the anonymous OddOneOut) was able to recommend a much better approach.
The cause of the problem is the way WP-Syntax defines where the browser should look for the plugin’s stylesheet. This happens in a php function wp_syntax_head() defined in the file wp-syntax.php, which is located in <root>/wp-content/plugins/wp-syntax/. The code for this function looks like this –
function wp_syntax_head() { $css_url = WP_PLUGIN_URL . "/wp-syntax/wp-syntax.css"; if (file_exists(TEMPLATEPATH . "/wp-syntax.css")) { $css_url = get_bloginfo("template_url") . "/wp-syntax.css"; } echo "\n".'<link rel="stylesheet" href="' . $css_url . '" type="text/css" media="screen" />'."\n"; }
What’s happening here is that the plugin checks to see if there is a wp-syntax.css file within the theme’s template directory, and if there is it creates the correct link to that file and inserts it into the html file that will be read by the browser. However the constant TEMPLATEPATH refers to the parent theme’s template, not that of the child. Similarly, the function get_bloginfo(“template_url”) returns the uri for that directory.
We need, instead, to check whether there is a wp-syntax.css file in the theme’s actual template directory, which in my case will be that for the child theme. The constant STYLESHEETPATH refers to that directory, and the function get_bloginfo(“stylesheet_directory”) returns the uri for that directory. The code should therefore be modified as follows –
function wp_syntax_head() { $css_url = WP_PLUGIN_URL . "/wp-syntax/wp-syntax.css"; if (file_exists(STYLESHEETPATH . "/wp-syntax.css")) { $css_url = get_bloginfo("stylesheet_directory") . "/wp-syntax.css"; } echo "\n".'<link rel="stylesheet" href="' . $css_url . '" type="text/css" media="screen" />'."\n"; }
With this change, the customized plugin css file can now be placed in the child theme’s template directory, and the formatted code block will be styled correctly.