Get it All
Together

I just thought I’d write a note about the new Favorite Actions bar in the new version of WordPress. This seems to have been designed as a way to mollify the concerns of the people who used to like the old layout of the administration areas better. But it’s a handy little shortcut to important things and of course, there’s a natural tendency as a plugin developer to want to utilize this space for your own plugin.

In fact, I was looking up how to do this very thing when I happened upon this page. The author cautions, quite rightly, that using this shortcut bar too much will end up clogging the thing and making it useless.

So, it seems to me that the responsible solution for plugin developers who want to make use of this new space would be to make it an option of your plugin which is always disabled by default. Doing so would allow your plugin users to make their own choices about which options to include in the favourites and which to leave as standard options. It is, after all, called a “favorite” actions bar.

In fact, I am hoping that future iterations of the WordPress core will include options to make this bar genuinely customizable according to your own preferences. The combination of a customizable favorites list and optional inclusion of plugin functions would represent the best of all possible worlds for this easily abused space.

This plugin is deprecated and no longer maintained by the developer.

The new 2.7 version of WordPress MU is pretty awesome and I’m glad to have it running on both of my sites right now. There’s a lot 2.7 has to offer in terms of usability boosts, and while I balked at the redesign when it first started, I have to confess that there is much to love about the new layout.

However, one thing that’s been nagging me is the new Admin Bar functionality. It suffers from two things, in my opinion:

  1. It’s a blog by blog setting, not sitewide. This is fine for sites where you want savvy people to start blogging on your network. It’s less so for community based sites like mine, where the idea is a sort of news magazine site where consistency is key.
  2. Because plugins can add their own top-level menus, the Admin Bar can get a bit crowded and I’d like the option to add or subtract items from the list as I see fit. Again, it would be nice to have these settings happen globally rather than by site.

While I have not worked out the second problem just yet, I thought I’d go ahead and post my modified code to this site which allows site-wide settings rather than by-site. It also tucks the Admin Bar settings under the Admin section rather than Options.

There’s nothing magical here: all I did was change every occurrence of “get_option” and “update_option” to “get_site_option” and “update_site_option.” Then, I just modified the menu statement to look like the following:
// Register the settings page
function AddAdminMenu() {
add_submenu_page('wpmu-admin.php', __('WordPress Admin Bar', 'wordpress-admin-bar'), __('Admin Bar', 'wordpress-admin-bar'), 'read', 'wordpress-admin-bar', array(&$this, 'SettingsPage') );
}

Download the file here and replace the one currently sitting in /wp-includes/wordpress-admin-bar/

Meanwhile, I’m going to work on tweaking the plugin to make it more flexible for MU as I go.

OK, so I realize that the official stable version of WPMU is not out just yet.  But still and all, I’m running the latest beta on this site and it’s quite stable so far.  I’ve not seen so much as a single error yet.  Then again, the day is still young, so to speak.

Of course, this marks WPMU’s foray into the new admin layout and while it’s markedly different than the previous two itterations, its slowly revealing itself to be a real improvement to the system.  The last revamping was really just a reimagining of the same basic WP layout and maybe not quite bold enough to be a real usability improvement.  They rearranged some things and changed some font sizes, but ultimately it was the same top nav design.

Now that we’re into the left hand navigation style, I think it’s going to work.  My one complaint is that it would be better if we were able to move stuff around, either within the submenus or moving top-level stuff where we want it in the list.  I can’t tell you, for example, when the last time was that I used the “Links” for anything at all on this or any other site.

There’s a bunch of new features as well, including a quick post area on the Dashboard and the ability to reply to comments on the comment moderation screen.  Both of these things will be welcome additions to the site, especially my political site.  Having to constantly go to the front page, click the article and then reply has been a source of endless irritation in the old version of WP.  Jotting down quick notes to the world is more easily accomplished from the Dashboard while you’re working on other things.  That’s handy.

There is also a more intelligent “Publish” window to the right of the writing window on the Add New Post screen.  Now the buttons in this section more closely reflect the status of the article you’re working on, displaying “schedule,” if you’ve set it up as a post-dated post, or “update” instead of “save draft” if the article is already published.

What I’ve not yet had a chance to do is actually crawl through the changed code and figure out neat new stuff to do.  For example, it appears as though most of the menus are considerably more configurable than they’ve been in the past.  Adding new menu items to the Add Post screen should be much easier going forward. There are more options for site administrators in WPMU 2.7 as well, allowing you to set parameters like new blog defaults and such.

I’ll definitely report back as I discover things.

I’ve been struggling to understand exactly how the cron functions of WordPress work.

I’ve been working on a plugin for some friends of mine that need a mailing list manager, this plugin in turn requires the ability to schedule tasks. So, I spent a long time puzzling over the various bits of documentation and posts on other blogs about WP-Cron, pouring over code and experimenting with my own, until I finally got a working plugin.

And while I’m sure that the information that is out there now about Cron functions is adequate for some, it’s clear to me that others may need a different set of explanations, which is where this blog post comes in. I’m going to attempt to lay out the WP-Cron world in a different way in hopes of improving slightly on what’s out there.

Let me start by saying that the best article I’ve read on the subject of crons is definitely “Timing is everything: scheduling in WordPress,” by Glenn Slaven. I highly recommend that, even before reading this article, you take a gander at that one. There are really just a few things on which I would like to expand and revise slightly, because they threw me off. I’m also slightly reorganizing the order of discussion into something more akin to a step-by-step set of instructions.

Editor Update: Ack! Looks like this other article is no longer available. Sorry, everybody!

The Scenario

The example we’re going to work with is the mailing list manager plugin I’m developing. We’re not going to get into too much of the actual code of that plugin, but the scenario is doubtless a common need. We’ll be assuming that we’re working with a blog which has many, many users. (real world example: 400+) We want to keep our users up to date with periodic email blasts. Rather than those blasts being separated from the regular content, we want to specify that certain posts will become both posts on the site and email messages.

But of course, sending emails out to 400+ recipients at once is going to make the SMTP server very, very suspicious. In order to avoid problems with the mail server, we need to throttle the messages by sending blasts every twenty minutes ((or at least, approximately twenty minutes, remember that WordPress cannot be exact about timing)) until the last user group has been emailed. To do this, we will be using the wp_schedule_single_event() function within the WP-Cron suite of tools.

Scheduling: What You’ll Need

In order to schedule an event of any kind, you’re going to need a few basic components. We’ll get into more detail further down the line, but it’s important to be able to identify the landmarks as we proceed:

  • Your Cron Function ~ This is the actual function that does the stuff you want when the scheduled event is fired
  • A Custom Action Hook ~ Here’s where we get into the nitty-gritty of how WordPress operates. It’s very simple, actually, but understanding how to create custom action hooks is key to understanding WordPress cron functions. And a great deal more about WordPress!!
  • Your Scheduling Function ~ This is the function that initially assigns the scheduled task.

Your Cron Function

[php]my_scheduled_function([$arg1, [$arg2, [$arg3. . . ]]])[/php]

This function lies at the heart of your scheduling world! It is here that you put all the stuff you want to get done at a specified time. In our example, this is where you actually send the email to your latest batch of users. Note that this function can include an arbitrary number of arguments. We’ll get into how you pass those arguments on to the function later. For now, just notice that this is a standard function like pretty much any other. In fact, in the case of the mailing list manager I created, it’s as simple a function as you could ask for:

[php]function bhd_cron_send($sender_email, $subject, $mail_text, $send_headers) {
wp_mail($sender_email, $subject, $mail_text, $send_headers);
}[/php]

It’s probably advisable to create your function and make sure it works without adding in the cron functionality first. This is because a) there’s no need adding extra complexity to the system until you’re sure the function works and b) you’ll need to know how many arguments will need to be passed to the function and in what order.

Your Custom Action Hook

This is what really threw me. I’ve never created my own custom action hooks and never really understood them, but you’ll need to in order to get things done with cron, so this is important. Creating a custom hook is as simple as typing the following:

[php]add_action(‘my_custom_hook’, ‘some_function’ [, $priority, [$num_args]]);[/php]

WordPress assumes that anything added as the first argument exists without any additional registration of that new hook. In other words, ‘my_custom_hook’ actually is the declaration of the action hook in this example. The second argument should be a valid function name and will be the function associated with ‘my_custom_hook’ whenever ‘my_custom_hook’ is invoked anywhere in the system.

Obviously, since you’re writing your custom action, you’ll also need to invoke that custom action somewhere. That’s the last piece of the puzzle, which is explained down the page a bit.

But before we leave this topic, it’s worth pointing out that, just like any other action, it’s entirely possible to hook more than one function into the custom action you’ve created. It’s also possible to invoke the hook somewhere else in your code, separate from your Cron function. This bit of WordPress theory may prove helpful to you down the line, so it’s just an FYI.

The last two arguments of the add_action function are important. Recall the number of arguments you needed for your scheduling function. That’s the number you’re going to want to put in the $num_args add_action parameter. Otherwise, add_action doesn’t look for and doesn’t accept any arguments provided, which will doubtless render your function either inoperable or ineffective.

Late Update: Per jeremyclark in the comments, this is not really the reason to mess with priority! Thanks Jeremy! If you’re function is particularly computationally expensive (if it’s complex and relies on a lot of processing), it might be worth it to back the priority down a bit. You can do this by setting the $priority argument. The default is 10. In our case, the actual function is trivial, so this is what the add_action looks like for our mailing list:

[php]add_action( ‘bhd_cron_send_hook’, ‘bhd_cron_send’, 10, 4 );[/php]

Your Scheduling Function

Finally, there is the function which will do the scheduling. Depending on the complexity of your plugin, this may not be very complex at all. But the one thing that is required of your function is that it bundle up all the arguments to your cron function into an associative array in the proper order. In our example, the parameters for our sending function are $sender_email, $subject, $mail_text, $send_headers. Thus, we create an array like so:

[php]$mail_bundle = array(
‘sender_email’ => $sender_email,
‘subject’ => $subject,
‘mail_text’ => $mailtext,
‘send_headers’ => $send_headers
);[/php]

Next, we need to assign the scheduled task. For this, we use our custom action hook. Now we understand why it was so important to pay close attention to the number of parameters and their order: the hook only allows you to set the number of arguments and the function – which is now removed by one degree of separation from the schedule – needs those arguments sent to it in the proper order. We call the WordPress scheduling function like so:

[php]wp_schedule_single_event(time()+$time, ‘bhd_cron_send_hook’, $mail_bundle);[/php]

The first argument is simply the Unix system time plus an interval of seconds after which we would like the scheduled task to be fired. Since we want the first of our batch email events to happen twenty or so minutes after the post has been published, $time was defined as follows:

[php]$time = rand(1000, 1200);[/php]

“Wait,” you say, “why the random number?”

If you look at the multi-dimensional array of scheduled events created by the WP-Cron system, you will find that the primary key for identifying events is the Unix timestamp. The second-level identifier is an MD5 of the arguments. In our example, it’s possible that someone could inadvertently set up the cron events twice by correcting the post after they’ve published it: both events fire the ‘publish_post’ event, which the mailing list uses to start it’s process.

However it happens, the possibility is that two events could have exactly the same timestamp and arguments, which would mean that one overwrites the other in the array. To avoid this, I included the slight randomization, which only alters the schedule by a maximum of three minutes.

So, now let’s look at the entire process in code (with some pseudo-code) in order to understand how everything fits together:

[php]
//======================================
// Description: Our scheduling function. Sends the email in 50-recipient chunks
function bhd_schedule_message($sender_email, $subject, $list, $headers, $mailtext) {
// Establish our random time interval between the publishing of the post and the first email blast:
$time = rand(1000, 1200);
for($x = 0; $x $sender_email,
‘subject’ => $subject,
‘mail_text’ => $mailtext,
‘send_headers’ => $send_headers
);
// schedule the email blast, increment the $time variable by twenty minutes for the next loop:
wp_schedule_single_event(time()+$time, ‘bhd_cron_send_hook’, $mail_bundle);
$time = $time + 1200;
}
}
}

//======================================
// Description: here is our actual cron job.
function bhd_cron_send($sender_email, $subject, $mail_text, $send_headers) {
wp_mail($sender_email, $subject, $mail_text, $send_headers);
}

//======================================
// Description: Finally, here is our custom action.
add_action( ‘bhd_cron_send_hook’, ‘bhd_cron_send’, 10, 4 );[/php]

Note: we have not included the function that will be called when the post is published, because of course we’re not dealing with adding actions onto that particular hook. But for reference’s sake, such a function would look something like this:

[php]add_action(‘publish_post’, ‘my_mailinglist_function’);[/php]

I’d been holding off on upgrading to WPMU version 1.5.1 because I was worried that the extent of the changes from 1.3 to the new 2.5 codebase might be a bit too much for the system without some serious recoding.  Turns out, I was about half right.  And when I did finally upgrade about a week ago, it was a comedy of errors that forced my hand.

Since I’m on a web host that limits the size of my database, it has ever been a concern that I would hit the cap on my main blog.  The Tan-Tan Noodles Flickr Plugin did just that to me, since it saves all the pictures you display with the plugin as binaries in the database.  Suddenly one day, I could not post to my site and plugins seemed to be magically turning themselves off.  I thought for sure that someone had hacked into my site.

So, I opted to upgrade, hoping any security holes in 1.3 might be closed in 1.5.1.  Crazy, but again, I was panicking with a fairly high-traffic site suddenly being in limbo.  Unfortunately, I didn’t figure out the db problem till long after I’d already overwritten my old 1.3 files.  After I did the upgrade I found that my templates weren’t loading correctly.  Why should that be?

It turns out, after a long time troubleshooting, that a couple mu-plugins I’d written to bring content from other blogs to the main blog had become unusable.  I figured this out because Donncha’s post describing some of the new changes mentioned that plugins using the switch_to_blog() method might have a problem with the new caching system.  That didn’t turn out to be the problem, but since some of my code was still using another method of snagging the info (literally, concatinating “wp_1_posts” and querying the db directly!), it was this method that was causing the problem.

So a warning to you plugin writers out there: stick to the WPMU API to the best of your abilities!  I’m not entirely sure why querying the db would have caused so much grief, but when I switched to the API, I had no problems.

This may be apropos of nothing for a lot of people, but just as a helpful little hint, you can get the theme used by a blog by calling the get_option() method thusly:

get_option('current_theme');

I’m using this on a plugin that changes the colors of certain objects (not CSS directable) by checking the current theme and setting matching colors. Think “custom color YouTube video window.”

MU admins, you could use get_site_option() if you’re planning on doing something global.

Updated to Version 3.0! New Support Page

Titles to Tags is now fully-functional with WordPress 3.0!

I’ve finally found time to wrap by brain around how Tortoise SVN works – which means understanding SVN in the first place, then figuring out how Tortoise’s GUI works – and I’ve updated the plugin after many moons of inactivity. Updates include some revamping of the code based on my experiments with it in another plugin, improved documentation in the plugin itself and bug fixes including the phantom tags commenters have reported.

Download Plugin

Never forget to post your tags again! With the Titles to Tags plugin, WordPress will scan your post’s title for the most keyword-appropriate words and add them to your tags list automatically on save! The plugin comes with a very long list of words which are statistically irrelevant, such as “I” or “among,” which don’t make good keywords. You can also edit this list to include more or less terms by going to Options > Titles 2 Tags. There is also an option to revert to the original list, but watch out! You will lose your edited list forever if you do this!

This plugin will only save tags to your posts if none exist already. The presumption is that if you’ve already saved tags, you must know what you want and anyway, you might have removed some tags Titles to Tags added because you don’t like them. The function runs every time you save a post, either by publishing, saving or editing the post.

To install the plugin, simply download it from the WordPress Plugin Repository, then extract both the hn_titles_to_tags.php file and then hn_t2t and it’s contents into your /plugins folder. Activate the plugin by going to Plugins, and begin posting as normal.

WordPress MU Developers: Note that, if your creating a community-based website built on MU – and your users aren’t being diligent about adding tags – this is a great way to get those tags created painlessly! You can place the file and it’s companion directory in the /mu-plugins file and each blog will get it’s own editable list of ignored words.

And hey! If you like this plugin, I would really appreciate it if you went back to the WordPress.org page and rated it! Thanks!

Download Here

This one’s called a “Plug-n-Hack” because it relies on a lot more than just the basic plugin to work. It requires careful layout of your blog’s theme and editing the plugin in order to work correctly.

But for those of you who are running sites where you’d like to be able to keep the overall structure of individual blogs the same, while allowing your users to make some adjustments to the color scheme, this may be just the solution. With the Theme Styles Plug-n-Hack, you can create new color schemes as the administrator and offer them to your users to select from.

The plugin itself is very basic. All it does is add a new style element to the wp_head when the site loads. The elements within the style must be the same IDs and classes as you use regularly, because the new declarations will override your default settings for color. As such, it is imperative that before working with this plugin, you take stock of your current color scheme and determine how many colors you work with ordinarily and how many of those you’ll want to change. For example, my site uses five basic colors not counting the text, which I decided would always stay the same color.

Once you’ve determined what colors you’re going to change, you need to start creating a second style sheet (which will eventually replace the one in the plugin) that calls each of the affected elements and declares only those attributes which are related to color. By way of example, in my case:
#top_nav_1 {
background:#CD2626 none repeat scroll 0%;
border-bottom:1px solid #FFCC00;
border-top:1px solid #FFCC00;
}

Now that you have this list, you can begin to replace the RGB color codes with PHP substitutions. The plugin is currently setup to recognize five color variables:
$darkest, $dark, $medium, $light, $border
These variable names made sense to me, but feel free to edit the plugin to change them, if you prefer. Go ahead and start putting in your substitutions where they fit. In my case:
#top_nav_1 {
border-bottom: 1px solid <?php echo($borders); ?>;
border-top: 1px solid <?php echo($borders); ?>;
background:<?php echo($dark); ?>;
}

Now you can go ahead and insert that style list in place of the one in the plugin, starting at line 33 of the theme_styles.php file. Note also that at line 23, some default values are set. You’ll want to switch these around to your theme’s default colors! Defaults are also set for the admin area at line 208.

Once all this is done, you can upload the theme_styles.php file to your /plugins folder and test it out. By activating the plugin, you create two new menu items: one is for Site Admins only, which is located under the Site Admin tab and allows you to either create new styles or change the values of existing styles; the second allows users to select from the styles you’ve created and is located under the Presentation menu.

With a little bit of editing, I think you’ll find this a welcome addition to your website.

Summary:  Returns an array of all users who have Administrative roles on a given domain.

Detail:  This function checks the database for all Site Admin users on the specified domain ($sitedomain and $path).  The returned value is an associative array of usernames and passwords.  This function works not only site-wide but across multiple domains, if you’re environment is set up in that way.

Summary: A companion function to the switch_to_blog() function, this function takes the settings stored in the temporary array setup by switch_to_blog() and swaps them back, thus restoring the original blog.

Detail: This very simple function simply undoes what was done in the switch_to_blog() function. It restores the settings to the $wpdb function and user roles that were held in the temp array setup by the switch_to_blog() function.

As previously noted in the switch_to_blog() post on this site, you cannot expect the temp array to hold more than one blog’s settings, thus if you are iterating over several blogs, you’ll need to either continuously use restore_blog() to get back to the original blog in between iterations, or else use switch_to_blog() to go back to the original, ignoring the temp array altogether.