Archive for the ‘Code’ Category.

Saw a few tweets by @lastraw today, asking Matt and others if they could make the Add Audio function in the WordPress editor work.

Well, @lastraw, the audio function does actually work, it just doesn’t do what you expect it to do.

Basically, the WordPress uploader does provide a few different kinds of uploader buttons: image, video, audio, and media. All of these buttons behave in different ways. The Audio button in particular lets you upload an audio file, and then insert a link to that file in your post.

WordPress upload buttons in the post editor

However, the link it inserts is just a bare link. This is because WordPress doesn’t come with a flash audio player, and HTML 5 hasn’t gotten standard enough to allow sane use of the <audio> tags.

Still, plugins can modify things to make audio files embed. I just wrote a quick plugin to take those bare audio links and turn them into embedded audio players using Google’s flash audio player. This is the same player they use on Google Voice and in several other locations in the Google-o-sphere.

Example:

Example Audio File

How did I do that? Easy, I activated my plugin, then used the Add Audio button to just insert the plain link to my audio file (which I uploaded). Naturally, this audio player will only show up on your site. People reading through an RSS reader or some other method won’t see it, they’ll just see the plain audio link and can download the file.

Couple limitations on this: It only handles MP3 formats. You could conceivably use a player that could handle more formats, I only made this as an example. MP3 is the most common format in use anyway, and I didn’t want to go searching for a more complicated player to use. Also, I made it only handle links on lines by themselves. If you put an audio link inline into a paragraph or something, it won’t convert it.

Here’s the plugin code if you want to use it or modify it or whatever. It’s not the best code in the world, but then it only took 5 minutes to create, so what do you expect? 😉

<?php
/*
Plugin Name: Google MP3 Player
Plugin URI: http://ottodestruct.com/
Description: Turn MP3 links into an embedded audio player
Author: Otto
Version: 1.0
Author URI: http://ottodestruct.com
*/

add_filter ( 'the_content', 'googlemp3_embed' );
function googlemp3_embed($text) {
	// change links created by the add audio link system
	$text = preg_replace_callback ('#^(<p>)?<a.*href=[\'"](http://.*/.*\.mp3)[\'"].*>.*</a>(</p>|<br />)?#im', 'googlemp3_callback', $text);

	return $text;
}

function googlemp3_callback($match) {
	// edit width and height here
	$width = 400;
	$height = 27;
	return "{$match[1]}
<embed src='http://www.google.com/reader/ui/3523697345-audio-player.swf' flashvars='audioUrl={$match[2]}' width='{$width}' height='{$height}' pluginspage='http://www.macromedia.com/go/getflashplayer'></embed><br />
<a href='{$match[2]}'>Download MP3 file</a>
{$match[3]}";
}

This is mainly intended as a demo. There’s more full featured plugins for this sort of thing in the plugins directory. If you need to embed audio, using one of them might be a better way to go.

Shortlink:

Update: Forget this plugin. Go install Jetpack instead.

WordPress.com rolled out a nifty new feature called “Gravatar Hovercards” today. Basically it changes gravatar images into popups showing more info when the user hovers over them. In the comments, Andy Peatling mentioned bringing them to self-hosted WordPress blogs soon.

I didn’t feel like waiting.

<?php
/* 
Plugin Name: Gravatar Hovercards
*/
function gravatar_hovercards() {
	wp_enqueue_script( 'gprofiles', 'http://s.gravatar.com/js/gprofiles.js', array( 'jquery' ), 'e', true );
}
add_action('wp_enqueue_scripts','gravatar_hovercards');

This is not official.
It’s not supported.
It may not even work for you.
It certainly won’t work if they change things.

Still, this blog is about fun things I do with WordPress, so I saw no reason not to post it. I expect they’ll come out with their own plugin soon, but I’d be rather surprised if it’s much more than this. Maybe some extra options or something. I dunno. Switch to that script when it comes out.

But for those people who like experimenting and playing with WordPress on the edge, here you go.

And for you Javascript inclined people, take a look at their code. It’s got some tricks in it that are pretty neat.

Enjoy. 🙂

(Updated as per several comments)

Shortlink:

I recently acquired a short domain name, otto42.com (the otto.com domain is owned by a German company, and I use Otto42 as my alias a lot on sites as “Otto” is usually already taken). So I decided to use it to make my own URL shortener.

I looked at various methods for this, including simply writing my own (honestly, it ain’t that hard), but I wanted to see what was already available first.

First thing I looked at was the shortlinks system built into Google Apps. I’ve used it before, and it’s fairly nifty. They even have an API available for interfacing it to other things. And hey, the redirections would be served up by Google’s servers, which you can’t beat for reliability. Sadly, after screwing around with this for a while, and trying out some example code, I was totally unable to get their API to work. The whole thing is written in Python, which I have an intense dislike of (whitespace my ass!), and when trying to access the thing via direct calls, it gave me nothing but errors and annoyances.

So I searched around a bit more, and was relegated to building my own, when a tweet by @ozh mentioned that he’d put a blog up on yourls.org. This looked promising, as I know Ozh is active in WordPress, and so of course it would have a plugin. After investigating, I went with it. It works pretty well, actually.

How to do it

First thing I did was to point my short domain at a directory on my hosting account. If it’s going to run code, it needs to have a place to do it from. So I made a yourls directory and pointed the domain to it using my hosting control panel.

Next, I grabbed a copy of the yourls code and installed it there. 300+ files to FTP? Yikes. Complex. A quick bit of reading told me that it needed a database and a config file. Very similar to WordPress in this respect, except the config file resides in the includes subdirectory for some reason. Not so obvious, but whatever.

I toyed with the idea of using the same database for yourls that I already use for WordPress, but ended up creating another one for it. I’m now thinking that it might be worth merging them though, as that way, VaultPress would probably back up the yourls tables too.

After some hosting weirdness, the thing was up and running.

Plugin

Installing the WordPress plugin is a snap. Just find it in the Add New Plugin interface and hit install. After Network Activating it for all my sites, I went to configure it. I had to configure it on each site separately, but no big deal.

Configuration is fairly straightforward. Tell it URL of the API interface, give it my username and password, and voila. Worked first try.

There’s a bunch of Twitter stuff there as well which I only set up to make it stop bothering me about it. I don’t want this plugin to send out my tweets on new posts, as I already use my own Simple Twitter Connect for that. Still, it bugs you with an error message if you don’t set it up, so I did. Thankfully, there’s checkboxes to turn the autotweeting on and off, so I just leave these turned off. Honestly, I think this whole Twitter thing should be removed from the plugin, but I can understand the “easy” factor here for new users. Making them totally optional would be a nice enhancement though.

At first, I was confused because when I turned it on, I saw no way to make it back-populate my old posts into the shortener. Turns out I didn’t need to, it started doing it all by itself shortly afterwards. I think it actually does shortening on an on-demand basis, creating a shortlink whenever there isn’t one already there for a post.

The plugin also hooks into the Shortlink API, meaning that my Twitter plugin will automagically use the new shortlink. You can see that the shortlink box below this post has the otto42.com shortlink in it. I had to make zero changes to make that work. Isn’t interoperability fun?

One other thing I did have to do was to turn off the old wp.me shortlinks I used. These are provided by the WordPress.com Stats plugin, and there’s a checkbox in its options page to turn them off. No big deal.

Final thought

So yeah, if you have a short domain and want to make your own shortlinks, then YOURLS is a pretty good choice. I haven’t played with the stats gathering part of it yet, for the simple reason that I only just turned it on and thus have no stats to view. Still very easy to do, on the whole. Of course, if it could be entirely a WordPress plugin, then I might think it much cooler. 🙂

Update: There is a minor problem in the way the YOURLS plugin handles the WP Shortlink API. I’ve reported it upstream, hopefully it can be fixed soon. Still, it’s a minor issue. The workaround for now is to call wp_get_shortlink(get_the_ID()) when you want to get the shortlink for a post inside the Loop.

Shortlink:

I’m about half done with this, and just wanted to give an update to those people I know who are awaiting it.

I’m ditching the multiple-plugin thing. Too many complaints and too much confusion. Also, the plugin directory and updaters don’t support it well. So 1.0 will have a checkbox area where you can select the pieces you want instead.

It’s using the new Javascript SDK. All this stuff is currently working great.

Login works. Register needs some more work.

Automatic publishing now works for both Fan Pages and Applications! I just worked out how to make Application posts through the Graph API properly. Manual publishing isn’t quite there yet.

Widgets are largely unchanged, but will all be rolled into one sub-module.

Fan box got replaced by the Like box, which is the same thing with a different name. So I’m going to keep calling it the Fan Box in the interface.

The bookmark widget is going away, because it doesn’t work properly anymore anyway.

New widgets for the Facebook Social Plugins are working.

Like and Share will remain unchanged, although the Like now uses the XFBML to do its thing. Doesn’t really make a whole heck of a lot of difference, though.

Comments pull-back from Facebook is possible. I know how to do it. I’m debating whether or not to turn them into “full-fledged” comments or just display them separately.

Comments push *to* Facebook is also possible. Meaning that if somebody leaves a comment using FB and clicks the share checkbox, it will send it to Facebook (no popup) and also include the text of their comment (or an excerpt, at least). This is not done yet, but it’s actually quite easy to add now.

All dependence on the FB-Connect library will be gone. Ditto for their PHP library. I’m writing this with pure calls to the Graph API and XFBML. PHP 5 is still required, and there’s still an activation check for that.

One last thing: Upgrading from old versions to the new one will be a hassle. Things will just stop working properly when you upgrade. Can’t be helped. So I recommend deactivating SFC and all sub-plugins entirely before upgrading, then reactivating it afterwards. There will be a note to this effect on the WP plugins screen.

Shortlink:

A while back, I wrote a post detailing why it was a bad idea to generate Javascripts using PHP in WordPress plugins. In that post, I mentioned a couple of better ways to do it.

At the time, I didn’t know about the third, and best way, to accomplish this. Mike’s comment over there reminded me of it. WordPress has it built in.

If you already know about wp_localize_script, you can stop reading now.

The wp_localize_script function was made in order to allow for WordPress translations to be able to also translate some of the JS files inside WordPress. Thus the name “localize”. The way it works is to load up the translated versions of text from the translation files and then include them into the resulting HTML output as a Javascript object. The scripts then use that object to produce any text output they need to produce.

Turns out that’s really similar to our goal of sending arbitrary parameters from WordPress to be used by Javascript code.

How to do it:

1. Make your script static (instead of generated) and enqueue your script as per normal. Example:

wp_enqueue_script('my-script','/path/to/whatever.js',…);

No real changes there. You’ll have to come back and modify your script to use these parameters it’s getting passed, but we’ll get to that in a minute.

2. Build an array of your parameters that you want to send to the script.

$params = array(
  'foo' => 'bar',
  'setting' => 123,
);

Note that my parameters are simple examples, but this is PHP code. You can get your parameters however you like. Such as get_option to pull them from the database, perhaps.

3. Call wp_localize_script and give your parameters a unique name.

wp_localize_script( 'my-script', 'MyScriptParams', $params );

What this will do is make WordPress output an inline script with your parameters (properly encoded) just before the enqueue outputs the script tag that loads your script in the first place. So then those parameters will be available to your script as an instance of an object with “MyScriptParams” (from my example).

This means that Javascript code can now reference them as attributes of the name you gave.

So, step 4. Modify your script to use those parameters. In my example, I used “MyScriptParams” and the parameter names are “foo” and “setting”. In my Javascript code I can use them as “MyScriptParams.foo” and “MyScriptParams.setting”.

Much cleaner. One static and unchanging JS file to cache. Parameters get put into your HTML itself as a one-liner. You can deal with the parameters using a normal PHP array before passing them over. No need to screw around with generating Javascript from PHP or looking for wp-load or even messing with tricky actions.

Perfect.

Shortlink:

So I added the new Tweet button to Simple Twitter Connect yesterday, and was going through the documentation they provided for it. One thing I noticed was a mention of the “count API”.

Now, Twitter says that the count API is private, but come on.. Seriously? You’re sending count information to every Tweet button being displayed anywhere, how private can that really be?

Turns out it’s not private at all. It’s just hidden.

To get the tweet count for any URL, simply do a GET for this:

http://urls.api.twitter.com/1/urls/count.json?url=URL-TO-GET-COUNT-FOR

What you’ll get back will look like this:

twttr.receiveCount({"count":123,"url":"URL-TO-GET-COUNT-FOR"})

Some of you may recognize that as a JSON callback. Basically, they’re using part of their @anywhere system to receive the count and update the button accordingly. Not surprising, the whole tweet button is built on top of the anywhere code. But it’s kinda useless to us in this format, since we need to be able to define our callback appropriately instead of using theirs. No worries, just add a callback parameter yourself:

http://urls.api.twitter.com/1/urls/count.json?url=URL-TO-GET-COUNT-FOR&callback=bob

bob({"count":123,"url":"URL-TO-GET-COUNT-FOR"})

Obviously, they didn’t release this information because they’re concerned about scaling, and probably rightfully so. Still, if you want that count, you can get it. Just don’t abuse it.

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:

I found a really stupid mistake in the STC-Publish plugin this morning, so I went ahead and pushed the fix and all the other changes out as well. Here’s a quick rundown of the new features:

  • STC-Publish now doesn’t have that weird case where it posts to Twitter without the shortlink.
  • Followers Widget is available. This shows a random selection your followers on Twitter. In order to use it, you have to have the “AutoTweet” user set using the publish plugin, so it knows which user to look at. You don’t actually have to use AutoTweeting though, just have it set to a user. Also, this widget is unstyled, so you’ll have to add styling for it to your theme to make it not look terrible. There’s a sample set of styling rules at the top of the plugin code. Only advanced users should probably use this widget.
  • The Follow widget now has a shortcode for use in posts. Just put (tweetfollow user=”username”) to put a follow button into a post. There’s also the stc_follow_button() function for advanced users who want to integrate it into their theme.
  • If you have a Multi-Site configuration set up and you want all your sites to use it, then you can define the STC_CONSUMER_KEY and/or STC_CONSUMER_SECRET in your wp-config file.
  • John Bloch sent me a Dashboard widget for Tweeting. After suitable modification, it’s in there too.
  • The Tweet boxes in the Publish widget and the Dashboard widget now use javascript to resize themselves to the correct sizes.

So there you go. Enjoy!

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: