Posts tagged ‘code’

We get a lot of submissions to the WordPress.org plugin repository, and so there is often a lot of dangerous code submitted. Usually this isn’t malicious, it’s just by people who honestly don’t know that their code has problems. Understanding those problems is the first step to fixing them.

So here’s one common vulnerability we see in code submissions a lot: SQL Injection

To understand SQL Injection, let’s quote Wikipedia for a moment:

SQL injection is a code injection technique, used to attack data driven applications, in which malicious SQL statements are inserted into an entry field for execution

Here’s a piece of code made for WordPress, which is querying the database for a post:

// bad code, do not use
$results = $wpdb->get_results( "SELECT * FROM $wpdb->posts WHERE ID = $id" );

If you don’t see the problem with this code right away, then you should continue reading this post.

(Yes, this article shows the basics of the prepare() function. If you already know about the prepare() function, you might be shocked at the number of people who do not.)

Continue reading ‘Better Know a Vulnerability: SQL Injection’ »

Shortlink:

Note: Everything I’m talking about here, including the code, is in beta mode. It will be subject to change. I’ll update this post after release to fix any code changes that may occur between now and then. I’m releasing this post now so that theme authors can start looking at their themes and thinking about how they might want to change the way they do options pages.

So, WordPress 3.4 has this nifty new feature you can find on the main Theme selection page. It’s a link next to each theme labeled “Customize”. This is the new Theme Customizer, and it’s way cool.

In fact, you can’t see what it does with a simple picture, so here’s a video. It’s available in HD if you want to go full screen. πŸ™‚

So, now you know what it does, and if you’re a theme author, you’ve probably just gotten some great ideas. Here’s how you can implement those ideas in your theme.

First, note that if you already support the built in Custom Header and Custom Background functionality the WordPress core provides, then those will magically show up and work in the theme customizer. No extra code needed on your part.

Existing Options

Now, the first thing you’ll probably want to do is to take note of how your existing settings in the theme work. You have three main options for theme settings, realistically. I’ll go over them briefly.

1. “Theme mod”. This uses the set_theme_mod and get_theme_mod functions. It’s rare that themes actually use these since I wrote about the Settings API, but it is there and if you use these normally then it is supported by the Theme Customizer (in fact it’s the default).

2. Individual Settings. If you store your theme’s settings in the options table as individual rows, one per setting, then that works fine with the customizer. This is not the preferred way of doing things in themes, however, and not the most common. Still, some themes do this, so if you’re one of them, it’s supported as well.

3. Serialized Settings. This is the way I explained in my Settings API Tutorial and the method recommended by the Theme Review guidelines, as well as the way Chip described in his own tutorial for theme settings. Essentially, you store your settings in an array, then store that array using set_option or get_option, as one row in the database. This method is supported and it’s the way I’ll primarily cover in this article. I’ll briefly mention the other two methods when appropriate.

Once you know how your settings are stored, then you’ll know what to fill in at certain spots in the code. More on this when we get to it.

Object Orientation

Now, the Theme Customizer is very object oriented, and while you don’t necessarily need to understand this to implement the basics of it, you might need to understand it if you’re going to make something completely custom. Just a warning.

First, we’ll look at the left hand side of the customizer screen. Notice that the left hand side is divided into sections. Actually, that’s their name: WP_Customize_Section. In each of these sections is one or more controls; or rather, WP_Customize_Control. Finally, each of these controls one of more settings on the page: aka WP_Customize_Setting.

The Sections organize the controls. The Controls get input and pass it to the settings. The Settings interface with your existing options in the theme.

To make new stuff here for your own custom options, you need to know where to add it. That place is the customize_register action hook.

add_action( 'customize_register', 'themename_customize_register' );
function themename_customize_register($wp_customize) {
	// ... do stuff ...

The function gets a parameter of the main $wp_customize object. This is the interface point where you will do everything like adding sections and controls and such.

Sections

So, first thing to do is to add a section. Here’s one way to do it:

	$wp_customize->add_section( 'themename_color_scheme', array(
		'title'          => __( 'Color Scheme', 'themename' ),
		'priority'       => 35,
	) );

The first parameter is a unique ID for the section that you’ll need later (when you’re putting controls into it). The second parameter is an array of options for the section. Sections don’t have a lot of options, really. You can give them a title, you can give them a “description” if you need some explanatory text in them. The priority setting determines their order in the list.

You can also give sections a “capability” if you have a special case. Generally speaking, most sites require the “edit_theme_options” capability to have users edit this sort of thing, and this is the default capability that the sections use. However, if you have options that anybody can edit, or which should only be managed by administrators, changing this capability will prevent the section from appearing to users who can’t change those settings anyway.

One final thing you can add to a section is a “theme_supports” option. This will make the menu not appear unless the theme supports something. If you’re putting this code in a theme itself, then you already know what the theme supports, so it doesn’t make much sense. The core uses this to not show the header and background options if the theme doesn’t support them.

Settings

Next, let’s configure some settings. Yes, the settings, not the controls. See, the controls need to know what settings they’re changing, so we have to attach the settings up first.

To declare a setting, you do it like this:

	$wp_customize->add_setting( 'themename_theme_options[color_scheme]', array(
		'default'        => 'some-default-value',
		'type'           => 'option',
		'capability'     => 'edit_theme_options',
	) );

In this case, I’ve declared that the setting I’m interested in is in an option, the option is named “themename_theme_options” in the database, and it’s serialized, and the actual array key in there is “color_scheme”. Remember that talk we had before about the Settings API and how you store your settings? This was method 3.

Here’s method 2 (one option per database entry):

	$wp_customize->add_setting( 'themename_color_scheme', array(
		'default'        => 'some-default-value',
		'type'           => 'option',
		'capability'     => 'edit_theme_options',
	) );

And here’s method 1 (using theme_mod):

	$wp_customize->add_setting( 'color_scheme', array(
		'default'        => 'some-default-value',
		'type'           => 'theme_mod',
		'capability'     => 'edit_theme_options',
	) );

This setting basically tells the theme customizer where the option is stored, and how to change it’s value so that your theme displays with the changed option.

Here’s the good bit about this: You’re telling the theme customizer where the option is. You don’t have to change the way the existing option works at all.

You already have a theme options page, right? So somehow, you’re saving those options. And in the theme, it’s reading those options using get_theme_mod or get_option, right? The way the theme customizer works is that it intercepts that call using a filter, changes the option for the previewer case only, and then passes the new option along to the theme. So the theme has no idea that the value it’s getting isn’t in the database, but one the user just selected. That’s the magic trick and why themes don’t have to dramatically change to support this sort of thing. All they have to do to make custom sections is to tell the theme customizer code what options they’re using and how, and it changes those options directly for the previewer.

(Note of clarification here: The “default” setting above should be a default value, not the current value. The difference is a subtle one, but the point is that you don’t actually need to get the current value of the option from the DB and put it in here. The WP_Customize_Setting takes care of all that jazz for you. The “default” is what should be used if the value doesn’t exist in the DB at all.)

There’s one more bit to the add_setting call that we’ll come back to later when I get around to explaining postMessage.

Controls

Finally, we come to the controls. Controls can look one of a lot of ways, obviously. The simplest controls are just checkboxes, or text fields. However, colors are something that change a lot, so there’s color wheel controls too. In fact, WordPress defines a number of possible controls. Let’s go over a few:

A radio selection:

	$wp_customize->add_control( 'themename_color_scheme', array(
		'label'      => __( 'Color Scheme', 'themename' ),
		'section'    => 'themename_color_scheme',
		'settings'   => 'themename_theme_options[color_scheme]',
		'type'       => 'radio',
		'choices'    => array(
			'value1' => 'Choice 1',
			'value2' => 'Choice 2',
			'value3' => 'Choice 3',
			),
	) );

Pretty simple. It’s referencing the section it’s in, the setting that it’s going to change, and then it has the radio type and the list of choices along with their associated values.

How about a checkbox instead? This one comes straight from core:

	$wp_customize->add_control( 'display_header_text', array(
		'settings' => 'header_textcolor',
		'label'    => __( 'Display Header Text' ),
		'section'  => 'header',
		'type'     => 'checkbox',
	) );

A checkbox is on or off, true or false. It needs no real values.

How about a selection dropdown box? Here’s an example:

	$wp_customize->add_control( 'example_select_box', array(
		'label'   => 'Select Something:',
		'section' => 'nav',
		'type'    => 'select',
		'choices'    => array(
			'value1' => 'Choice 1',
			'value2' => 'Choice 2',
			'value3' => 'Choice 3',
			),
	) );

The default type of control is actually type = ‘text’, and it creates a text box control. One more type of control is the “dropdown-pages” type, which creates a dropdown list of the WordPress Pages.

But that’s not all. There’s actually several more, but because they’re so custom, they’re declared differently. Here’s where we get all object oriented on ya…

	$wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'link_color', array(
		'label'   => __( 'Link Color', 'themename' ),
		'section' => 'themename_color_scheme',
		'settings'   => 'themename_theme_options[link_color]',
	) ) );

Whoa, what’s with the new class? The WP_Customize_Color_Control is a class that is extending the built in WP_Customize_Control class. It adds the color wheel jazz to places where color selection is needed. Note that the class is being created here with new, and so it has to get the $wp_customize passed to it directly, so it knows where to hook in. (Note: This may change before final 3.4 release.)

Other controls of note:

  • WP_Customize_Upload_Control – This gives you an upload box, for allowing file uploads. However, you probably won’t use this directly, you’ll extend it for other things… like:
  • WP_Customize_Image_Control – This gives the image picker and the uploader box. It extends the upload controller. You can see it in action on the custom background piece, where a user can upload a new file to be the background image.
  • WP_Customize_Header_Image_Control – Because of the resizing action of the header piece, it needs a bit of special handling and display, so the WP_Customize_Header_Image_Control extends the WP_Customize_Image_Control to add that functionality. You can see it in action on the custom header piece, where a user can upload a new file to be the header image.

So, the way to create a custom controller to do whatever you want is to make a new class of your own which extends WP_Customize_Control and adds the bits you want. How to do that is a bit complex, so I’ll save that for another tutorial. For now, you’ve got image handling, color wheels, text boxes, radios, dropdowns, and checkboxes. I think that should be enough to get started with.

End of tutorial?

Not quite. Everything I went over above is enough to add new sections to the customizer, put controls in them, and then to have the preview show your changes after a slight delay when the page refreshes. All you have to do is to call those functions with the proper parameters, in the proper place, and it’ll work.

However, note that I said “when the page refreshes”… C’mon… this is the year 2012. We don’t have flying cars, and we still have to wait a whole second or two?

Nope.

Enter postMessage

Back when I mentioned the $wp_customize->add_setting function call, I mentioned “one more bit”. That one more bit is the option called “transport”.

Transport defines how your setting change gets from the place where you changed it into the preview pane. The default setting for this is “refresh”. An alternative setting is named “postMessage”.

The postMessage transport makes it such that the setting is instantly sent into the other frame, where javascript can adjust the page on-the-fly using this new information.

An example:

Let’s say we have a setting to change the colors of the titles. All the titles on the page are in some tag that has a class of posttitle, perhaps. The option normally just saves the HTML color chosen, then outputs some inline CSS in the header.php to basically do this:

.posttitle {
	color: #abcdef;
}

Or whatever the option actually is for that color.

We have hooked our setting to that option, and hooked our WP_Customize_Color_Control up to it, and now when we change it, it works and we can see the color change. Note that this is easiest to do with already working customizer options, so the best way to do it is to get it working normally first, then add on this next bit.

Now, we have the working option in the customizer, so to take away that refresh delay, we’ll add this new option to the add_setting call:

	'transport'         => 'postMessage',

This tells the customizer that the setting will be sent directly to the frame via javascript. However, for that setting to work, we need javascript in the frame itself to receive it.

So, back in our main function… remember that? It started like this:

add_action( 'customize_register', 'themename_customize_register' );
function themename_customize_register($wp_customize) {
	// ... do stuff ...

Right at the end of that function, we’re going to add this code:

	if ( $wp_customize->is_preview() && ! is_admin() )
		add_action( 'wp_footer', 'themename_customize_preview', 21);

This is going to add a new function call to our preview frame’s footer. It only gets added with the preview frame, so the live site and others won’t see it, because they don’t need to see it. This is where we’re going to output our javascript to make things happen in real-time.

Here’s our function:

function themename_customize_preview() {
	?>
	<script type="text/javascript">
	( function( $ ){
	wp.customize('setting_name',function( value ) {
		value.bind(function(to) {
			$('.posttitle').css('color', to ? to : '' );
		});
	});
	} )( jQuery )
	</script>
	<?php 
} 

As you can see, it just outputs a bit of javascript. This code won’t change much, ever, so let’s go over just two pieces of importance:

  • ‘setting_name’ is the name of the setting, as added by the $wp_customize->add_setting call.
  • The entire line starting with jQuery(‘.posttitle’) is our custom bit of code. It gets the “to” variable, which will be the color chosen by the user, and it sets the posttitles on the page to have that color, using the css modifying functionality of jquery.

Those are the only two bits you need to change, really. The rest is pretty copy-pasta. For each real-time setting, you can dupe this bit of code in the script.

Here’s another thing: You can change pre-existing refresh settings to be postMessage ones. Take the Site Title and Tagline elements in the Header section, for example. These are refresh settings, and the reason they are is because each theme implements them differently. There’s no way for the core to know the javascript code needed for any particular theme.

But if you’re a theme author, then you’re not writing for a generic theme. You’re writing for your particular theme. You know how the site title and tagline are displayed. There’s no reason you can’t make those update in real time. And while you’re at it, the header_textcolor setting can be real time too, since you know the theme code.

In your main function again, add these three lines of code:

	$wp_customize->get_setting('blogname')->transport='postMessage';
	$wp_customize->get_setting('blogdescription')->transport='postMessage';
	$wp_customize->get_setting('header_textcolor')->transport='postMessage';

That changes the transport on those core settings to be postMessage. Now you need to add the javascript code to actually do the refreshing in your theme. Here’s an example of TwentyEleven doing this (with the patch I wrote for it):

function twentyeleven_customize_preview() {
	?>
	<script type="text/javascript">
	( function( $ ){
	wp.customize('blogname',function( value ) {
		value.bind(function(to) {
			$('#site-title a').html(to);
		});
	});
	wp.customize('blogdescription',function( value ) {
		value.bind(function(to) {
			$('#site-description').html(to);
		});
	});
	wp.customize( 'header_textcolor', function( value ) {
		value.bind( function( to ) {
			$('#site-title a, #site-description').css('color', to ? to : '' );
		});
	});
	} )( jQuery )
	</script>
	<?php
}

For the blogname, it changes the HTML inside the “#site-title a” link. For the description, it changes the tag with #sitedescription. For the color of those, it simply targets both of them and alters their CSS.

Core has to try to be generic across all themes. But themes have more knowledge of how they work and can change things to target themselves in better ways. A theme adding controls knows what those controls change, so if it’s something simple like CSS or even something more complex like HTML, if you can write javascript code to make that modification in real time, then you can use postMessage and eliminate that refresh delay.

Hopefully this explains some of the theme customizer. Was it as clear as mud? Take a look at my patch to Twenty Eleven to add some of the theme options from its existing options screen into the customizer. You can find it on this ticket: http://core.trac.wordpress.org/ticket/20448.

Shortlink:

In trying to figure out what to talk about at WordCamp Atlanta, I remembered a question put to me in WordCamp Birmingham. The question was how can a theme developer easily make a plugin-dependency in their theme?

I wrote some code to do this sort of thing, just as an example/test/demonstration, but then after looking over the schedule, I found that Thomas Griffin had beat me to it. After looking over his slides and having him walk me through his code, I realized that his solution was much more fully featured than mine, so I’m glad I didn’t present anything on this topic. (I ended up just doing an answer session where I tried to answer any question put to me, and frankly that was much more fun than having slides, so I’m probably just going to do that from now on.)

You can find his cool library here, BTW: http://tgmpluginactivation.com/

However, his solution is highly complex. The class he came up with is well done and fully-featured. He has capabilities for making notifications in the header space on the admin section, lightbox popups, bulk installs, forced activation, custom skinning, etc. It’s a big thing. While that’s great for a lot of people in terms of having code you can just drop-in and use, I thought that it doesn’t do much to teach how one can DIY it.

See, the code I wrote was tiny. It basically just provides some minor functionality to show a theme author how to detect installed plugins, how to detect when they’re active, how to build install and activate links, etc. It doesn’t do any pretty stuff. No custom skinning. No lightbox popups. All these things are possible, but if somebody hands you a hunk of library code to do them, then you know how to use that library, not how it works. I dislike using libraries for this reason.

So here’s the small class I wrote to do the same sort of thing, but in a very bare-bones style.

/* 

Simple class to let themes add dependencies on plugins in ways they might find useful

Example usage:

	$test = new Theme_Plugin_Dependency( 'simple-facebook-connect', 'http://ottopress.com/wordpress-plugins/simple-facebook-connect/' );
	if ( $test->check_active() ) 
		echo 'SFC is installed and activated!';
	else if ( $test->check() ) 
		echo 'SFC is installed, but not activated. <a href="'.$test->activate_link().'">Click here to activate the plugin.</a>';
	else if ( $install_link = $test->install_link() )
		echo 'SFC is not installed. <a href="'.$install_link.'">Click here to install the plugin.</a>';
	else 
		echo 'SFC is not installed and could not be found in the Plugin Directory. Please install this plugin manually.';

*/
if (!class_exists('Theme_Plugin_Dependency')) {
	class Theme_Plugin_Dependency {
		// input information from the theme
		var $slug;
		var $uri;

		// installed plugins and uris of them
		private $plugins; // holds the list of plugins and their info
		private $uris; // holds just the URIs for quick and easy searching

		// both slug and PluginURI are required for checking things
		function __construct( $slug, $uri ) {
			$this->slug = $slug;
			$this->uri = $uri;
			if ( empty( $this->plugins ) ) 
				$this->plugins = get_plugins();
			if ( empty( $this->uris ) ) 
				$this->uris = wp_list_pluck($this->plugins, 'PluginURI');
		}

		// return true if installed, false if not
		function check() {
			return in_array($this->uri, $this->uris);
		}

		// return true if installed and activated, false if not
		function check_active() {
			$plugin_file = $this->get_plugin_file();
			if ($plugin_file) return is_plugin_active($plugin_file);
			return false;
		}

		// gives a link to activate the plugin
		function activate_link() {
			$plugin_file = $this->get_plugin_file();
			if ($plugin_file) return wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin='.$plugin_file), 'activate-plugin_'.$plugin_file);
			return false;
		}

		// return a nonced installation link for the plugin. checks wordpress.org to make sure it's there first.
		function install_link() {
			include_once ABSPATH . 'wp-admin/includes/plugin-install.php';

			$info = plugins_api('plugin_information', array('slug' => $this->slug ));

			if ( is_wp_error( $info ) ) 
				return false; // plugin not available from wordpress.org

			return wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=' . $this->slug), 'install-plugin_' . $this->slug);
		}

		// return array key of plugin if installed, false if not, private because this isn't needed for themes, generally
		private function get_plugin_file() {
			return array_search($this->uri, $this->uris);
		}
	}
}

Obviously, for theme authors wanting to do something, they’re going to want to make much prettier means of displaying things and installing things. Thus, this code is meant as an example, to show the basics of how to detect such things.

So, use it directly if you like (it works), but more importantly, if you want to put plugin dependancies in your theme, then I suggest reading it and figuring out how it works instead. Then you can see how plugins can be detected and how to build simple install and activation links.

(BTW, note that I used the slug and the PluginURI for a reason. Plugins should be using a unique URL for the plugin in their code, and that URL is very likely to be the most unique thing about the plugin, and therefore the best way to check for a plugin already being there or not. Slugs can be duplicated by accident or design, but URLs are generally going to be unique and specific to a particular plugin.)

Shortlink:

Have you ever looked at the add_action function in WordPress? Here it is:

function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
	return add_filter($tag, $function_to_add, $priority, $accepted_args);
}

I know, right? Some people’s minds just got blown.

What are Filters?

A filter is defined as a function that takes in some kind of input, modifies it, and then returns it. This is an extremely handy little concept that PHP itself uses in a ton of different ways. About half the string functions qualify as a ‘filter’ function.

Look at strrev(). It’s a simple-stupid example. It takes a string as an argument, and then returns the reverse of that string. You could use it as a filter function in WordPress, easily. Like, to reverse all your titles.

add_filter('the_title', 'strrev');

Some filters take more than one argument, but the first argument is always the thing to be modified and returned. PHP adheres to this concept too. Take the substr() function. The first argument is the string, the second and third are the start and optional length values. The returned value is the part of the string you want.

What are Actions?

An action is just a place where you call a function, and you don’t really care what it returns. The function is performing some kind of action just by being called. If you hook a function to the init action, then it runs whenever do_action(‘init’) is called.

Now, some actions have arguments too, but again, there’s still no return value.

So in a sense, a WordPress action is just a filter without the first argument and without a return value.

So why have them both?

Because there is still a conceptual difference between an action and a filter.

Filters filter things. Actions do not. And this is critically important when you’re writing a filter.

A filter function should never, ever, have unexpected side effects.

Take a quick example. Here’s a thread on the WordPress support forums where a person found that using my own SFC plugin in combination with a contact form emailer plugin caused the email from the form to be sent 3-5 times.

Why did it do this? Basically, because the contact form plugin is sending an email inside a filter function.

One of the things SFC does is to build a description meta from the content on the page. It also looks through that content for images and video, in order to build meta information to send to Facebook. In order for this to happen at the right time, the plugin must call the_content filter.

See, what if somebody puts a link to a Flickr picture on their page? In that case, oEmbed will kick in and convert that link into a nice and pretty embedded image. Same for YouTube videos. Or maybe somebody is using a gallery and there’s lots of pictures on the resulting page, but the only thing in the post_content is the gallery shortcode.

In order to get those images from the content, SFC has to do apply_filters(‘the_content’,$post_content). This makes all the other plugins and all the other bits of the system process that $post_content and return the straight HTML. Then it can go and look for images, look for video, even make a pretty 1000 character excerpt to send to Facebook.

But SFC can’t possibly know that doing apply_filters(‘the_content’,…) will cause some other plugin to go and send a freakin’ email. That’s totally unexpected. It’s just trying to filter some content. That would be like calling the strrev() function and having it make a phone call. Totally crazy.

Shortcodes

Shortcodes are a type of filter. They take in content from the shortcode, they return replacement content of some sort. They are filters, by definition. Always, always keep that in mind.

Also keep in mind that shortcodes are supposed to return the replacement content, not just echo it out.

Conclusion

So plugin authors, please, please, I’m begging you, learn this lesson well.

Filters are supposed to filter. Actions are supposed to take action.

When you mix the two up, then you cause pain for the rest of the world trying to interact with your code. My desk is starting to get covered in dents from me repeatedly banging my head into it because of this.

Shortlink:

First, WordPress plugin authors: Please don’t do this.

if ( isset($_GET['resource']) && !empty($_GET['resource']) ) {
	$resources = array(
		'icon1.png' => '... base 64 encoded code ...',
		'icon2.png' => '... base 64 encoded code ...',
		);

	if ( array_key_exists($_GET['resource'], $resources) ) {
		$content = base64_decode($resources[ $_GET['resource'] ]);
                header('Content-Length: '.strlen($content));
                header('Content-Type: image/png');
            	echo $content;
		exit;
	}
}

I’ve seen a few different versions of this, and while the idea is nice, this is really the wrong way to go about it.

The idea is to include small icons or images in the plugin file itself, instead of as separate files. This sort of code then lets you reference them by calling a URL of ?resource=icon1.png or whatever. When that resource variable is detected, the plugin kicks in and serves up the image instead of the site.

Advantages to this sort of thing:

  • No need for extra icon files

Disadvantages to this sort of thing:

  • Now every http request to get an icon file on your admin page results in loading up the WordPress code, causing extra CPU usage.

Here’s a better way. It’s called the Data URI.

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot" />

Here’s that code in action, right here: Red dot

Why this is better:

  • Same benefits as before, no need for extra icon files
  • No extra CPU load from loading WordPress to get that icon file
  • No extra HTTP requests at all, in fact, since the data for the tiny icon is contained right there in the code

Disadvantage:

  • Doesn’t work in IE7. You can work around this by detecting IE7 and serving up the image separately, if you really want. Or you can just ignore it like most people do. Seriously. IE7 is insecure (link, link) and nobody should be using it, anywhere. WordPress itself will probably drop IE7 support in the admin in the next couple of versions.

So use Data URIs for small images (under 32KB in size). They’re fast and easy. They’re an idea whose time has come.

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: