New in WordPress 2.9: Post Thumbnail Images
Many WordPress themes, especially those with “magazine-like” layouts, use an image to represent each post. It might just be on the front page. It might be alone, or alongside an excerpt. Until now, there was no standardized way to do this. Many themes would require you to tediously enter a Custom Field with the value being the URL you wanted to use. Often you had to do cropping yourself. With WordPress 2.9, theme authors can easily enable Post Thumbnail selection UI and call those image using simple template tags.
![]()
First, in the theme’s functions.php, declare that your theme supports this feature. This will enable the UI in the WP Admin.
add_theme_support( 'post-thumbnails' );
That will enable Post Thumbnail UI for both Post and Page content types. If you’d only like to add it to one, you can do it like this:
add_theme_support( 'post-thumbnails', array( 'post' ) ); // Add it for posts add_theme_support( 'post-thumbnails', array( 'page' ) ); // Add it for pages
Simply remove the one you don’t want to support.
Next, you should specify the dimensions of your post thumbnails. You have two options here: box-resizing and hard-cropping. Box resizing shrinks an image proportionally (that is, without distorting it), until it fits inside the “box” you’ve specified with your width and height parameters. For example, a 100×50 image in a 50×50 box would be resized to 50×25. The benefit here is that the entire image shows. The downside is that the image produced isn’t always the same size. Sometimes it will be width-limited, and sometimes it will be height-limited. If you’d like to limit images to a certain width, but don’t care how tall they are, you can specify your width and then specify a height of 9999 or something ridiculously large that will never be hit.
set_post_thumbnail_size( 50, 50 ); // 50 pixels wide by 50 pixels tall, box resize mode
Your second option is hard-cropping. In this mode, the image is cropped to match the target aspect ratio, and is then shrunk to fit in the specified dimensions exactly. The benefit is that you get what you ask for. If you ask for a 50×50 thumbnail, you get a 50×50 thumbnail. The downside is that your image will be cropped (either from the sides, or from the top and bottom) to fit the target aspect ratio, and that part of the image won’t show up in the thumbnail.
set_post_thumbnail_size( 50, 50, true ); // 50 pixels wide by 50 pixels tall, hard crop mode
Now, you can make use of the template functions to display these images in the theme. These functions should be used in the loop.
has_post_thumbnail() returns true/false and indicates whether the current post has a manually-chosen Post Thumbnail (in the loop):
<?php
if ( has_post_thumbnail() ) {
// the current post has a thumbnail
} else {
// the current post lacks a thumbnail
}
?>
the_post_thumbnail() outputs the Post Thumbnail, if it exists (in the loop):
<?php the_post_thumbnail(); ?>
Those are the basics. How about some advanced stuff?
What if you want to use a small 50×50 hard-cropped image for the home page, but want to use a 400 pixel-wide (unlimited height) image on the post’s permalink page? You’re in luck. You can specify additional custom sizes! Here’s the code:
functions.php
add_theme_support( 'post-thumbnails' ); set_post_thumbnail_size( 50, 50, true ); // Normal post thumbnails add_image_size( 'single-post-thumbnail', 400, 9999 ); // Permalink thumbnail size
home.php or index.php, depending on your theme structure (in the loop):
<?php the_post_thumbnail(); ?>
single.php (in the loop):
<?php the_post_thumbnail( 'single-post-thumbnail' ); ?>
That’s it! set_post_thumbnail_size() just calls add_image_size( 'post-thumbnail' ) — the default Post Thumbnail “handle.” But as you can see, you can add additional ones by calling add_image_size( $handle, $width, $height, {$hard_crop_switch} );, and then you use that new size by passing the handle to the_post_thumbnail( $handle );
If you want your theme to support earlier versions of WordPress, you’ll have to use function_exists() to keep from calling these new functions in those versions. I’ve omitted that code to keep these examples as simple as possible. Here would be the functions.php example with the wrapper code:
if ( function_exists( 'add_theme_support' ) ) { // Added in 2.9
add_theme_support( 'post-thumbnails' );
set_post_thumbnail_size( 50, 50, true ); // Normal post thumbnails
add_image_size( 'single-post-thumbnail', 400, 9999 ); // Permalink thumbnail size
}
There is one caveat for this feature in WordPress 2.9 — it only works fully for new image uploads. We can’t yet resize images on the fly, although I’m strongly considering it for a future version. If you call the template functions on a post that has a Post Thumbnail that was uploaded prior to your theme having declared the new sizes, you won’t be able to do hard-cropping, and the box-resize will be done in the browser. As a temporary solution, Viper007Bond has a great plugin that will go back and create missing image sizes for you: Regenerate Thumbnails.
I’m looking forward to see what kinds of sites you can build with this feature!
How should “Post updated. View Post” links open?
We’ve gone back and forth on this. How should the “View Post” link that shows up next to the “Post updated” (or similar) text work? Should it open in the same window/tab, or should it open in a new window/tab?

The problem with this question is that the people who have really strong opinions in favor of opening the tab in the same window are all power users. They’re people like me. I don’t think I can give an objective answer on this, because manually opening a window in a new tab is a skill that I don’t even think about, I use it so much. I realize that’s probably not the case for many WordPress users.
We’re going to use the honor system on this, so be honest:
Do not vote in this poll if your mouse has more features than two buttons and a scroll wheel, and you know how to use them. Do not vote in this poll if you know what “middle-clicking” is.
I’m abstaining from voting, as my mouse has 7 buttons, one 4-way scroll wheel, and another two-way thumb wheel.
Excluding your plugin or theme from update checks
There has been a vigorous discussion going on regarding what data WordPress installs send to WordPress.org when doing update checks. Because WordPress (the software) doesn’t know whether a theme or plugin is listed in the WordPress.org repositories, it has to check them all, and let the repository sort it out. Some have expressed concern that private plugins developed for a single client could contain sensitive information in their headers, like contact information for the developer, etc.
If you, as a plugin or theme developer, would like to exclude one of your plugins or themes from the update array, the following code will do the trick.
For plugins:
function cws_hidden_plugin_12345( $r, $url ) {
if ( 0 !== strpos( $url, 'http://api.wordpress.org/plugins/update-check' ) )
return $r; // Not a plugin update request. Bail immediately.
$plugins = unserialize( $r['body']['plugins'] );
unset( $plugins->plugins[ plugin_basename( __FILE__ ) ] );
unset( $plugins->active[ array_search( plugin_basename( __FILE__ ), $plugins->active ) ] );
$r['body']['plugins'] = serialize( $plugins );
return $r;
}
add_filter( 'http_request_args', 'cws_hidden_plugin_12345', 5, 2 );
Just change the cws_hidden_plugin_12345 string (two instances) to a namespaced function name for your plugin, and you’re good to go.
For themes:
function cws_hidden_theme_12345( $r, $url ) {
if ( 0 !== strpos( $url, 'http://api.wordpress.org/themes/update-check' ) )
return $r; // Not a theme update request. Bail immediately.
$themes = unserialize( $r['body']['themes'] );
unset( $themes[ get_option( 'template' ) ] );
unset( $themes[ get_option( 'stylesheet' ) ] );
$r['body']['themes'] = serialize( $themes );
return $r;
}
add_filter( 'http_request_args', 'cws_hidden_theme_12345', 5, 2 );
Put this in your theme’s functions.php Again, just change the cws_hidden_theme_12345 string (two instances) to a namespaced function name for your theme. Do not that this will only hide the ACTIVE theme. This code doesn’t get run if the theme isn’t active. If you want to hide non-active themes, you’ll have to put this code in a plugin and instead of using get_option( 'template' ) or get_option( 'stylesheet' ) you’d hardcode the values for the inactive theme you want to hide.
Just a note: I don’t want the comments to turn into another battlefield for the update check debate. I’m putting my code where my mouth is and showing you how you can keep private plugins/themes from contacting WordPress.org if you so wish. Comments about this code are welcomed!
Interview with Deutsche Welle on WordPress Security
I recently did a short interview with Deutsche Welle about WordPress security. Listen to it here.
To expand on the topic, here are some of the details that didn’t make it into the final cut of the interview:
If your blog is compromised, you should install the latest version of WordPress, but first you should remove your old files. This is to prevent a hacker from leaving a back door (something like wp-give-hacker-access-forever.php in your WordPress directory. Just dropping the new version over the old version wouldn’t replace a new file that a hacker may have added, which is the reason for getting rid of the old files. Once you’ve done that (being careful to back up your wp-config.php and all your wp-content files), upload a clean install of WordPress. Restore your custom files. Next, look for any user accounts that weren’t there before, or that have higher access than they should. Sort that out. And lastly, scan through your theme/plugin files looking for backdoors or hidden links. This is mostly a manual process, but there are some common things to look for. Most backdoors use the eval() function, so be on the lookout for that!
The best way to keep your blog safe is to stay updated with the latest WordPress version! We’ve tried to make it as easy as possible to update (one-click!), and we have big plans for making it even easier in the future.
I’ve never had one of my WordPress blogs compromised, and I don’t do anything “fancy.” I just stay updated.
Reminder: if you’re using WordPress.com or another “hosted” blog solution, they take care of security updates for you. The only thing you need to worry about is choosing an unguessable, complex password.
PHP $_SERVER variables are not safe for use in forms, links
A common security mistake I see WordPress plugin authors (and PHP coders in general) make is using $_SERVER['PHP_SELF'] or $_SERVER['REQUEST_URI'] as the action of a form or part of an anchor’s href attribute. This is not safe to do, and opens your code up to XSS (cross-site scripting) exploits.
Common example:
<form action="<?php echo $_SERVER['PHP_SELF']; ?>">
Another example:
<a href="<?php echo $_SERVER['PHP_SELF']' ?>?foo=bar">link title</a>
Here are my two rules regarding $_SERVER['PHP_SELF'] or $_SERVER['REQUEST_URI'] in forms:
- Do not use them
- If you use one of them, escape it with
esc_url()
Most uses of $_SERVER['PHP_SELF'] and $_SERVER['REQUEST_URI'] are in HTML forms. If you want the action attribute to point to the current URL, leave it blank. URI references that are blank point to the current resource.
<form action="">
If you do want to specify the action (and there are good reasons for wanting to do that, such as stripping the query string from the current URL), you must run it through esc_url().
<form action="<?php echo esc_url( $_SERVER['PHP_SELF'] ); ?>">
The same applies to links… run the href attribute through esc_url().
<a href="<?php echo esc_url( $_SERVER['PHP_SELF'] . '?foo=bar' ); ?>">link title</a>
A quick search through the WordPress Plugin Directory showed that this problem is far too common.
Updates:
Examples of URLs that could exploit this for double-quoted actions:
script.php/"%20onmouseover='alert(document.cookie)'
And single-quoted actions:
script.php/'%20onmouseover='alert(document.cookie)'
No, just using a plain old htmlentities() wrapper is not going to help! That’s still vulnerable to XSS in certain situations. If you’re not using WordPress, you should copy the WordPress escaping functions (just remove the apply_filters() portions).
If you are using the base tag, Safari will apply that base to the blank action attribute. So if you use the base tag (I never do), a blank action isn’t going to be for you. Use what you’ve been using, but escape it.
Lester Chan has a handy snippet for the form action of WordPress plugin settings pages:
<form action="<?php echo admin_url( 'admin.php?page=' . plugin_basename( __FILE__ ) ); ?>">
admin_url() takes care of escaping for you, and is an easy way to create a full WP admin URL from a wp-admin-relative URL.
Public response to Chris Anderson’s “Free” on WordPress
I got a tip that Chris Anderson’s upcoming book Free has the following to say about WordPress:
2. Feature limited (Basic version free, more sophisticated version paid. This is the WordPress model.)
- Upside: Best way to maximize reach. When customers convert to paid, they’re doing it for the right reason (they understand the value of what they’re paying for) and are likely to be more loyal and less price sensitive.
- Downside: Need to create two versions of the product. If you put too many features in the free version, not enough people will convert. If you put too few, not enough will use it long enough to convert.
This is most assuredly not the WordPress model. Anyone and everyone can go to wordpress.org and download a completely free, completely unrestricted, and completely feature-complete version of WordPress to run for any purpose. There is no feature limited version of WordPress.
Chris might be getting confused by WordPress.com, which is a hosted WordPress solution (the biggest one, but certainly not the only one). It is true that WordPress.com charges money for certain features, such as CSS editing capabilities. But this is completely within the rights of Automattic, the company which operates the WordPress.com service. That one company is charging for certain aspects of a hosted WordPress solution does not change the fact that WordPress itself is free/open source software and has no monetization model and no tiered versioning system.
As we talked about at SXSW, Chris, it is WordPress services that are the “freemium” portion of WordPress. We give the software away, and thus create a vibrant market for third party WordPress services (this marketplace, to quote this blog’s quite literal catchphrase, puts food on my table).
Note that it would be correct to say that this is the Movable Type model, whereby Movable Type Pro and Movable Type Enterprise get features not available in the free/open source version of Movable Type.
Update: Chris fixed this error in the electronic version of Free, and it stands to reason that future print editions will have the correction. Thanks, Chris!
Escaping API updates for WordPress 2.8
The WordPress escaping API functions have been updated. Escaping is a way of using untrusted text that “neuters” anything that could do damage. Escaping is used in WordPress to avoid SQL injection and cross-site scripting/script injection (XSS), among other things.
The old functions still work, so if you were using the old ones, you’re fine. The new ones just offer you an easier to remember, more concise, and more flexible way of securing your WordPress code.
Here’s an example. Say you wanted to translate a string, escape it for use in a quoted HTML attribute, and then echo it out. In WP 2.7, you’d have to do this:
<?php echo attribute_escape( __( 'Untranslated text' ) ); ?>
In WordPress 2.8, you can just do this:
<?php esc_attr_e( 'Untranslated text' ); ?>
Shorter, plus we killed the echo and the extra pair of parenthesis! But let’s break it down.

esc_is the prefix for the new WP escaping functions.attris the context (in this case, attribute). The available contexts for 2.8 areattr,html,js,sql,url, andurl_raw._eis the optional translation suffix. The available suffixes for 2.8 are__, and_e. If you omit the suffix, no translation is performed, and your string is just returned.
More about contexts
attrmeans an HTML attribute.htmlmeans text within an HTML node, but not within an attributesqlis an alias to$wpdb->escape().urlmeans URLs for use in HTML attributes.url_rawmeans URLs for use in redirects or storage in the database (does not entity-encode).jsmeans JS, for using PHP to populate a Javascript var.
More about suffixes
Suffixes work just like the function they’re named after.
__translates the string and returns it._etranslates the string and echoes it.- The suffix is optional. A blank suffix will just return.
- Suffixes are currently only available for
htmlandattrcontexts.
Functions with translation suffixes also accept an option second parameter of a translation domain, for use in plugins.
Enjoy! Go forth and write more succinct code.
8 steps to get started as a freelance WordPress developer
I’ve had a bunch of people ask me how they could get started as a WordPress developer or consultant. Rather than answer them all individually and privately, I’m putting it up for all to see.
Become involved with the development community
Join the wp-hackers mailing list. Participate when you have something useful to say, or an interesting question/problem to pose to other WP developers. Dive in at the WP support forums. Find someone with an interesting problem, and solve it for them. If it’s a notable issue, write a blog post about how to solve the issue. Which brings me to the next task…
Blog about WordPress
I’m doing this right now! Not only is it deliciously “meta,” it can raise your profile and help you connect with other WordPress developers and users. Write about a problem you solved, or a challenge you’d like to see addressed by WordPress core or a WordPress plugin. And don’t forget to blog about the plugins you write…
Write a bunch of useful plugins
This is probably the best thing you can do to get noticed by clients. Write a useful plugin and you’ll be getting business leads for years to come. You don’t have to write a really big, complicated plugin. Write something that will make using WordPress easier, more fun, more efficient, and people will remember you. It might be good to have one more ambitious plugin to serve as an example of your skills, but certainly don’t shy away from brevity. Some of the favorite things I’ve written are between 1 and 50 lines of code. Users don’t care about how big a plugin is. They just want it to serve a need. Go ahead and scratch their itch. Hint: monitor Google or Twitter for people saying “I want a WordPress plugin…” to get an idea of the sorts of needs that are currently unfulfilled.
Contribute to WordPress core
Contributing to the WordPress core software helps you in two ways. First, it provides continuing education. WordPress is constantly evolving, and you need to stay sharp! This is a great way to learn about (and influence) the direction of the WordPress codebase. Second, it raises your profile in the WordPress community (both the developer and user communities). Be sure to blog about your WordPress core contributions. Trac is a great place to start. Maintain a calm demeanor, and don’t get too big for your britches. Don’t be the person who comes in and embarrasses themselves by closing a ticket as “WONTFIX” that was opened by a seasoned developer! Watch how other tickets evolve and you’ll figure out how it works.
Stay in contact with more seasoned developers
A lot of us are busy, but we try to make time to mentor people. We’re all well-served by a vibrant development marketplace. Don’t be afraid to contact a more experienced developer for advice. The worst that will happen is that you’ll get ignored — apologies to anyone who is in my e-mail limbo… resend it if it’s been more than a few weeks!
And as you get more experienced:
Speak at WordCamps and other events
Once you’ve gained enough kudos in the WP community, you’ll likely be asked to talk at a WordCamp event. And if you haven’t, and you think you could bring something special to the event, go ahead and ask if they need any more speakers! This will raise your profile further, introduce you to really cool people, and provide you with a bunch of business leads. BarCamps, social media gatherings, and other such events are also worth attending. The point isn’t to get up there and give a business pitch. In fact, your life might be in danger if you pull that stunt at a BarCamp. The point is to impart knowledge, connect with people, while letting your skills expose themselves naturally. And pitch away when you’re chatting up potential leads between sessions.
Charge according to your skill set and experience
Several years ago, I had the quasi-embarrassing surprise of being given a voluntary 75% per-hour raise by a client. I think they were afraid that my skills had outpaced my rate, and that I was going to get wooed away by a new client at a higher rate. Don’t make the mistake of charging too little. In fact, publish higher rates than you actually think you’re worth, and allow people to haggle you down (a little). And every time you get booked up and have to turn away business, raise your rate. If you’re in that much demand, you’re not charging enough.
Find a niche
But not WordPress security. That’s mine.
A WordPress development niche is a niche within a niche. And that means you can charge more for your more specialized skills. Examples: migrating data to WordPress. Feed kung-fu. Re-implementing a design from another system. Custom write-panel plugins. Sidebar widgets.
Force CSS changes to “go live” immediately
If you update your WordPress theme’s style.css, you may have noticed that you have to “force-reload” your site in your browser to see the changes. This is because your browser keeps a copy of the CSS cached on your hard drive. Depending on how your server is set up, it may not check for a new version of the stylesheet for a couple hours, or longer! And even if you force-reload to see the changes, visitors who have previously accessed your site may still get the old CSS. One way to solve this is to “version” your CSS file, by adding ?v=123 to the URL in the <link /> to your stylesheet. This is rather a pain to have to do by hand every time, so here is a much better way:
<link rel="stylesheet" href="<?php bloginfo('stylesheet_url'); echo '?' . filemtime( get_stylesheet_directory() . '/style.css'); ?>" type="text/css" media="screen, projection" />
This automatically updates the ?12345678 ending part every time you modify the file. Boom. Now everyone instantly sees your changes.
Typographica relaunches on WordPress
Typographica, the excellent blog for typographical nerds, has just relaunched on WordPress with a great new design by Chris Hamamoto. Asked why they switched from Movable Type to WordPress, Stephen Coles replied:
For me, it seemed an obvious switch given WordPress’ wide adoption in recent years. We’ve often had trouble getting assistance with MT, whether it’s documentation or expert advice. Because WordPress is so common, the help resources and useful plugins are simply much more accessible.
WordPress’ killer features are its community and its marketplace: thousands of free plugins, thousands of free themes, and hundreds of agencies and freelancers providing every possible WordPress development and support service you can imagine.



Block-level comments trick
with 28 comments
Block-level comments are useful for commenting out an entire block of code in PHP, CSS, and other code contexts.
The only problem with this is that when you go to re-activate this code, you have to change both the opening and closing comment markers. That’s a pain.
While I was at WordCamp NYC last week, I saw Daisy Olsen using a very clever trick in her lightning round talk.
See what she did there? The closing comment marker is preceded by another opening marker. Because comment blocks can’t be nested, this second opening comment marker is ignored. This enabled her to re-enable this code by removing the opening marker.
Brilliant! I can’t believe I haven’t seen this before. The one downside to this is that you are deleting two characters and destroying the opening marker. Here’s an even better method.
By adding a slash in front of the opening comment marker, I comment out the comment marker. It only takes one key press, and the corpse of the original opening marker is retained, allowing you to reinstate it with the deletion of a single character.
Props to Aleem Bawany for the second trick (he uses
//*/as the closing comment, which works pretty much the same way).What other commenting tricks do you know?
Written by Mark Jaquith
November 21, 2009 at 12:49 am
Posted in wordpress
Tagged with coding, commenting, CSS, php, tip, trick