I think I've done enough of these that I can convey upon you my limited expertise.  :) [This one's for Val.]

For today's exercise (which will take me no more than an hour to explain in writing), we're going to make a plugin that is like the acronym plugin, except it's going to display an image popup instead of text. 
To begin, you're going to need a text editor.  I recommend one of the syntax-highlighting variety.  My commercial editors of choice at the moment are TextPad or EditPad Pro.  Notepad doesn't syntax-highlight, but it works fine.  Macintosh users are on their own with this, but I've heard the word BBEdit uttered more than once.  Whatever you use, open a blank file.  The first thing to do is to name and document the plugin so that it appears in the WordPress administration console.  We're going to call our plugin "AcroPop".  The plugin header tells WordPress what to do with the plugin file.  Insert something to this effect at the top of your plugin file, placing the appropriate information in the appropriate fields:

<?php /* Plugin Name: AcroPop Plugin URI: http://www.asymptomatic.net/wp-hacks Description: A plugin that pops-up images when you mouse-over certain words.  Author: Owen Winkler Version: 1.0 Author URI: http://www.asymptomatic.net */ ?>

Some notes about the plugin header: All of the header info is inside of a block comment.  That's because none of it is executable.  WordPress scans the plugins directory for files that contain this header information.  When it finds the headers, it includes the plugin file.  No header, no include.  The Plugin URI is the URI of the plugin, where users can expect to find a link to the latest downloadable version.  The Author URI is the URI of your site, where users can find out more information about the person in the Author field.  In recent versions of WordPress you can no longer put full HTML in your Description field, however, it seems that anchor tags (you know, <a href="http://www.example.com">) do work.  If you want to direct users to a configuration page for your plugin, you might figure out how to put it here.  (Note that this tutorial isn't going to cover assembly of a configuration page.)

Save your work because you're not a fool for the power company, and continue on to the next page, where we talk about plugin hooks. 
Plugin hooks are the main way to get plugins to "go" in WordPress.  Spread throughout the WordPress code are hooks that can call your plugin code.  There is one that is called whenever a user posts a comment.  There is one that is called whenever a new user registers.  Pretty much any WordPress action you can think of has a plugin hook waiting for plugins to take advantage of.  You can get a list of hooks over at the WordPress Codex.  This list is currently in-production, but will fill out in time.  There are two types of hooks, Actions and Filters.  Actions are triggered when a specific WordPress action takes place, like when a new post is submitted.  WordPress doesn't ask for any information back from the plugin, it just tells the plugin "this thing happened" and moves on.  With Filters, WordPress expects that your plugin is going to process a certain chunk of data and return it, like displaying the text of a post.  WordPress will pass the text of the post into the plugin, the plugin will process the text and return it, and WordPress will display the processed text.  Since more than one plugin can attach to the same hook, each plugin can make the changes it needs to the filtered text.  We want to a Filters because we're going to cause some specific text in the post to pop up an image.  We're going to do this by putting some tags around the text.  Using the "the_content" filter is our best bet.  Here's how to plug into a hook.  Add this under your plugin header:

<?php add_filter('the_content', 'acropop_the_content'); function acropop_the_content($content) { return $content; } ?>

This code adds a "sink" (think about where heat goes - into a "heatsink") to the filter event "the_content" so that any time WordPress wants to display post content, it will pass the post content to a function named "acropop_the_content".  This is called "registering a plugin sink".  You can see the empty acropop_the_content() function, too.  The function acropop_the_content() is a sink for the "the_content" hook.  I mention this just so that we all know what we're talking about.  Note that this plugin will now run, although it doesn't actually do any processing.  Just upload it to your plugins directory (/wp-content/plugins) and activate it in your WordPress admin console.  If you remove the return $content; what do you think will happen?  All of your post text will appear to have been deleted.  Don't panic!  Remember that WordPress expects filters to return their values so that they can be sent to the browser.  Just put that line back and everything will be fine.  Try this for fun: Replace return $content; with return "Kumquat";.  See what it does?  I think you may be starting to get the idea.  When you're done playing with your posts, move on to the next page, where we'll discuss finding "acronyms" to pop. 
Well, now all we need to do is change the post content so that the text we're looking for is wrapped with a special "popup" tag.  We have the content of the post, as passed into our function by WordPress as the variable $content.  All we need to do is:

  1. Have a list of things to pop up and what to display.
  2. Look through the content of the post and wrap thost things with the special tag.

Ok, let's make a list.  Above the line that registers your plugin sink, add this:

$acropops = array ( 'mom'=>'http://www.example.com/images/mom.jpg', );

This creates an associative array (a named list) of images to use when certain text appears in the post.  Whenever the content contains "mom", we're going to make that text pop up her picture.  Optionally change 'mom' to 'lusty babe', but don't forget to change the image to one that actually exists.  So we have the list, now we need to wrap the list items when they appear in the post content.  This is pretty easy to do with one of the built-in PHP replace functions and a little array manipulation.  Inside our array sink, lets start adding some code:

function acropop_the_content($content) { global $acropops; $search_strings = array_keys($acropops); $replace_strings = array_values($acropops); $search_strings = array_map('acropop_search', $search_strings); $replace_strings = array_map('acropop_replace', $replace_strings); $content = preg_replace($search_strings, $replace_strings, $content); return $content; }

Now what the heck does that do?  First, we need to bring the $acropops array into the scope of the function, otherwise it won't be defined when we try to use it.  Then, we set $search_strings to just the key part ('mom') of the $acropops array, and $replace_strings to just the value part ('http://www.example.com/images/mom.jpg') of the $acropops array.  Because we're going to use the PHP function preg_replace() to do our replacing, all of the search strings need to be in regular expression format.  You don't need too firm a grasp on regular expressions to follow along.  Just know that the searching part of the regular expression needs to be delimited at the beginning and end by the same character.  Since our array keys are not delimited, we need to add those delimiters.  That's where the PHP function array_map() comes into play.  array_map() calls a function, passing each element in the array to it.  The function returns a replacement value for each element.  The result of array_map() is a new array with modified values as changed by the specified function.  In the case of $search_strings, we're going to use a function called 'acropop_search', and in the case of $replace_strings, we're going to use a function called 'acropop_replace'.  Check these out and add them to the plugin below the plugin event sink:

function acropop_search($value) { return '#\b' . $value .'\b#i'; } function acropop_replace($value) { return '<a class="acropop" href="#">\0<img src="' . $value . '" /></a>'; }

acropop_replace() returns a pretty wild-looking result.  Basically, it's creating an <a> wrapper for the replaced word (denoted by the regular expression replacement "\0") and adding an <img> tag with the src set from the $acropops array values ($value).  Yeah, it's a little more complicated than the "Simple" in this post title implied, but it gives you a lot of flexibility in what you can accomplish.  One last thing about array_map() and then we'll move on: The second parameter is a string, even though it's talking about a function.  Don't use just the function name in there - be sure you put the function name in quotes!  If you've followed along with the project so far, you should save and try what you have.  When you look at your WordPress output on the home page or a single post, you will notice that there are images everywhere where there used to be only the word "mom".  If you view the source of the page, you'll see that every time you used the word "mom" our plugin wrapped it with an achor tag and an image.  Want to try something fun?  Try having acropop_replace() return something else entirely.  Try return 'dad';.  Do you see the change?  Pretty cool how that works, huh?  Well, now that we've got the anchors in there, how do we get them to pop up the image instead of just showing it?  Ah, that's in our next step... 
In case you were thinking that I had quit talking about WordPress and had moved into a PHP tutorial, keep following.  I promise that I get back to some important stuff.  To make our anchor tags pop up images, we're going to use a CSS technique inspired by one I found on meyerweb, another WordPress-powered site.  Basically, you use CSS to change the display of the specially classed "acropop" anchor tags.  You simply define a few rules in CSS like this:

a.acropop { position:relative; text-decoration: none; border-bottom: 1px dotted #0000FF; } a.acropop img { display: none; } a.acropop:hover img { display: block; position: absolute; padding: 5px; margin: 10px; z-index: 100; color: #AAA; background: black; text-align: center; }

The <img> tags inside of the anchor are styled not to appear by default.  When you move the mouse over the anchor that trips the :hover CSS state, which reveals the image as a floating "tooltip".  Of course this is not the difinitive method for creating tooltip-like popups, but it's easier than describing a ton of javascript when our focus here is WordPress.  Anyway, if you follow through with the rest of the tutorial, you'll have enough knowledge to replace it when you find something better.  A question you might have at this point might be, "How do you get the CSS to be part of the template without editing the site's theme CSS file?" I'm glad you're following along.  We accomplish that using another plugin hook: The wp_head Action.  For more on that, turn the page. 
The wp_head action is a plugin hook that executes inside the <head> tag of the site output.  The <head> tag is where you usually add references to styles and stylesheets.  And that's exactly what we're going to do.  Let's register a hook sink for the wp_head action:

add_action('wp_head', 'acro_wp_head'); function acro_wp_head($unused) { echo '<style type="text/css" media="screen"> <!-- PUT STYLES HERE --> </style>\n'; }

There are a few items of note here.  First off, "PUT STYLES HERE" means just that.  Grab the styles from the previous page, and put them in that spot.  Next, you'll note that this sink function uses the PHP command echo.  You need to be careful using echo in plugin functions.  You will probably not use echo in a Filter, but you might in an Action.  Since wp_head is an Action hook, you're doing fine.  So what will happen is this: When the output page is constructed, WordPress will build the <head> section of the page.  Before it's done, all of the plugin sinks for the the wp_head hook will be called.  WordPress doesn't care what they do or if they return any value.  Ours writes some style information to the browser.  Control then passes back to WordPress, and it finishes construction of the page, including filtering all of the posts for our popup words.  Pretty crafty, eh?  I should mention that this is probably not the best way to do a larger project.  When you add code to the head of the output page like this, you increase the size of the page somewhat.  It's not a lot, but after many hits it starts to pile up.  You might do better using a CSS import command to import style information.  You could even use the plugin file itself as the imported file!  I'll leave this as an exercise for the user, or the topic for my next tutorial.  Someone's going to ask, "But, where's the finished plugin?" Hey, I just wrote several pages of tutorial that not only included all of the code, but explained why and how it all worked.  You write the plugin

Comments

I knew if I said something you'd beat me to it. :P

Thank you, I will try this later tomorrow, when I'm more coherent... *crawls to bed*

For a good list of Mac, Windows, and Unix (Linux) text editors, check out the WordPress Codex's list: http://codex.wordpress.org/Glossary#Text_editor

Nice article. I was thinking about doing something similar one day, but focusing more on good plugin coding habits (naming vars and functions, using classes, checking various things), but I'm waiting to be more 'expert' at it :)

Carthik's Codex page on plugins is good, but it's more of a reference. It doesn't have the conversational tone of a tutorial, which is why I wrote this.

But it does have information that I was thinking on covering in my next (potential) tutorial - why and how to write a plugin with an Options page, including an easy way to handle options maintenance and storage.

Oh crap he's right... I hate IE now... I have finally moved on to FireFox (officially not just part time anymore hehe) and I didn't even notice...

Ah, but that's why this is a "Tutorial on how to write a WordPress plugin" and not a "Tutorial on how to make popup tooltip images in CSS". Thankfully, it seems to degrade gracefully instead of filling IE with images all over the place.

If you've followed the tutorial, it should be academic to find CSS that works on IE and use that in the plugin instead of what I've provided. Admittedly, what I've offered may not work in IE because I'm lazy and by no means a CSS expert.

What I should have done is written a plugin that puts "Download Firefox" at the bottom of every post. ;)

I look forward to th next article. I was hoping this one would focus more on coding php for WP rather than just coding PHP. The intro to the hooks is nice, though. The plugin I have in mind will require some options, though :/

How would you go about having it not respect things found inside <a> tags, because otherwise say an image has alt tag then you get quite the mess.</a>

Hmm... Good point. But there are a number of ways to do this. Maybe the best way would be to craft the regular expression in acropop_search() to do look-behind so that you're only replacing text instances outside of tags:

function acropop_search($value) { return '/(?<!<[^>]*)\b' . $value . '\b/i'; }

I wonder if you can help me with something...I'm trying to either write a plugin or hack WP 1.5 to paginate single posts into multiple pages, very much like this article/post is divided into 5 pages.

If you have source or suggestions on this, I'd very much like to see it.

Why not just use the Page button on the QuickTags toolbar? It inserts <!--nextpage--> into your post, and WordPress automatically breaks it into pages, just like this post. This post is only one post, in case you were confused by that.

This feature and the <!--more--> feature were foreign to me when I started with WordPress, so I'm not shocked that it's common to not know this.

Doh! You're right. I had imagined that might be implemented by now. This just happened to be the first place I saw it, so I had to know how it was done. The last time I used Wordpress it was called b2, so I'm a little rusty. ;)

Thanks all the same...and to think I was going to start hacking away to get something like that going...

When I activate I get these lines in WP 1.5 admin panel. Not on the content pages.

Warning: Cannot modify header information - headers already sent by (output started at /home/wiredump/public_html/wp-content/plugins/acropop.php:20) in /home/wiredump/public_html/wp-admin/admin.php on line 6

What happened? Thanks. Learning.

Nice and simple tutorial, thanks ! I was able to create a simple one for my blog just by running through above.

Wow, ok, now there are page numbers. I hope those appeared after I commented, otherwise I'd feel really blind. Thanks regardless, this tutorial looks to be exactly what I need!

Sorry, commenting on this post is disabled.