Get it All
Together

The WP folks are announcing the latest version of WordPress will be released some time later this month.  Granted, there’s not a lot left in the month and they’re only just beta testing now, but nevertheless they plan on releasing this month.  The new features are exciting to contemplate, but especially helpful to us developers is the new Widget schema:

via Version 2.8 « WordPress Codex.

WP_Widget is a class that abstracts away much of the complexity involved in writing a widget, especially multi-widgets.

They’ve basically created a new class from which all new plugin widgets can be produced.  This is, as noted, especially helpful when you want to have more than one instance of the plugin on the page at any one time.  The process for this has previously been laborious enough that I haven’t bothered to write any such thing into any of my plugins.  Of course, such labor-intensive duplication is silly when you use a language capable of near-OOP programming and apparently the powers that be WordPress now agree.

I’m continuing to work with my CakePHP project and have run across some interesting math problems I thought I’d share that surround ratings and popularity ranking for the site.

The hypothetical new service provides a social network sensibility to local civic participation, allowing users to vote on the importance of issues and comment on them. The ranking system is a simple up-or-down voting system, held in the database as either a 1 or 0, depending on the vote.

So, being a social networking site, it is important to provide some rankings in order for people to know what’s hot and what’s not on the site. These rankings are: newest, highest rated, most popular and most active. Highest rated and most popular differ in that the highest rated issue is purely a function of the ratings system, whereas most popular needs to take into account how many people have commented. Most popular and most active differ in that most active is merely an indication of how many votes and comments a given issue has. Newest is obviously a function of time and therefore a straight-ahead dB query.

So, how to arrive at the other ratings? This seemed more obvious at first, but it got more complex as I went. I determined that the best thing to do was to get out the old spreadsheet and start laying out some numbers. Initially, I thought the highest rated function aught to be purely a count of the “yes” votes on each issue. But such a system does not take into account the power of the “no” votes. The solution was to divide the number of positive ratings by the total number of ratings. This gives you a percentage of the positive ratings, so one positive rating out of five makes an overall negative rating (20% positive), whereas one positive vote out of two is much more strongly weighted (50%).

This is not an entirely satisfactory, since a single positive vote can launch an issue to the top of the ratings board. There is also the issue of two or more pairs of ratings and positives equaling the same average, such as “4 ratings, 2 positives” and “2 ratings, 1 positive.” But since the ratings are not the only criteria, it’s acceptable to over-rate low numbers. The issue of matching averages will have to be dealt with in a sorting correction.

The next step was to determine the most popular issues. In this case, I opted to multiply the rating by the number of comments. This is a more satisfactory result overall, except that no matter how many comments an issue gets, if the rating is 0, the popularity is also 0. The solution to that is to add back in the number of comments, which has the effect of pushing up the lowest numbers without unduly affecting the higher popularity numbers.

I think I’ve gotten a decent handle on how to jiggle the numbers and get out of them what I think is most important. I’d be interested in hearing from any statistics experts or other folks with experience in this type of thing how they would change my metrics system to be more accurate.

For those who are serious about cataloging and displaying news from across the Internet in one blog, I’ve created the DFE News Harvester Plugin. DFENH allows you to register a variety of news feeds, read them within WordPress, select the articles you’d like to publish and publish them as posts in a blog.

DFENH also works with WP meta data to provide a number of bits of data that you might want in a news article, such as a title, a secondary “teaser” title, an image with credit and a brief summary. It’s up to you how you want to actually use this metadata on your site: DFENH does not offer any method of displaying metadata on the site.

Another feature of DFE News Harvester is it’s ability to automatically create tags for each article based on it’s title. When a list of articles is submitted for publication, DFENH automatically breaks the title up by words, eliminates unnecessary words like “by, the, if, etc” and creates tags for each of the remaining keywords.

This is a plugin which will work in either WordPress or WordPress MU. However, this is not a plugin meant to run in the /mu-plugins folder and I have not tested it for that use.

To install, simply download from WordPress.org, drop the entire /dfe_news_harvester folder into your wp-content/plugins folder and activate through the Control Panel of your blog.

Is This a Splog Plugin?

You can use this plugin however you like, but I would submit that there are far more efficient methods of creating a splog than this plugin provides. This plugin is geared towards providing updated news content in a way that is administration-heavy, relative to splogging tools. It does not harvest content off the original website by itself, it does provide a method of renaming links and providing your own summary of articles.

I trust that everyone who uses this plugin does so with the utter-most respect for original content on the web!

Download this plugin

Because someone asked me and because I haven’t seen quite the same solution out there on the nets, I’m posting this really quick for the benefit of those who need a quick submit button confirmation. If, for example, you want to prompt users to confirm whether or not they wish to delete an item out of a form, you can use the below JavaScript function to get it done. The function is designed to serve as confirmation for many different types of events, so it’s quite flexible:
[javascript]
// confirmButton: simple function to test user response
function confirmButton(message) {
var conf = confirm(message);
if(conf) {
return true;
} else {
return false;
}
}
[/javascript]
To us it, I use my trusty Unobtrusive JS action loading function like so:
[js light=”true”]
addEvent(editsubmitbtnz[i], ‘click’, function() { return confirmButton(‘Are you sure you want to edit this feed?’); });
[/js]
You could also add the function directly to the button like so:
[html light=”true”]<input type="submit" value="Delete This" onclick="return confirmbutton(‘Are you sure you want to delete this feed?’);" />[/html]
The result is a JavaScript function that will halt all action on the screen when you hit the submit button that the function is assigned to. It prompts the user to say whether or not they agree with the statement passed as a reference to the function, then pass that value (true or false) back to the page and either submit the form as normal or cancel the operation.

OK, I’m playing around with CakePHP and have been banging my head against a wall trying to figure out the error message which is the title of this post. For the benefit of those who come after me, let me explain what I’ve been doing wrong:

The problem was the models I was using. In my haste to get some drudge work out of the way quickly, I setup one of my models and – assuming I had done it correctly – copied and pasted for all my other models, changing the specifics as needed but basically assuming the same pattern. Well, the pattern was messed up.

If you’re specifying more options for a given relationship than just the name, you need to wrap the entire thing inside of an array(). This is what it should look like when correctly setup:

var $hasMany = array(
'Town' => array(
'className' => 'Town',
'foreignKey' => 'metro_ID',
'dependent' => 'false'
)
);

And this is the wrong way to set it up:

var $hasMany = 'Town' => array(
'className' => 'Town',
'foreignKey' => 'metro_ID',
'dependent' => 'false'
);

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’ =&amp;gt; $sender_email,
‘subject’ =&amp;gt; $subject,
‘mail_text’ =&amp;gt; $mailtext,
‘send_headers’ =&amp;gt; $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’ =&amp;gt; $subject,
‘mail_text’ =&amp;gt; $mailtext,
‘send_headers’ =&amp;gt; $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.