How to separate every other comment within a wp_list_comments callback function

Just upgraded one of my themes (the only one I’m still using that I can truly say I’ve created myself) to finally utilize WordPress 2.7’s new comment listing function. This made separating actual comments from pings a breeze compared to what it used to be.

The only slight problem was with porting the old separation of every other comment with a different class; since I needed to use a custom callback to retain the old look, I couldn’t utilize the automated classification done by wp_list_comments(). In the end all it took was these three lines added to my callback function:

global $comment_alt;
$oddcomment = $comment_alt % 2 ? 'alt' : '';
$comment_alt++;

With these in place I could now bring in the <li> tag from the old template without any further tweaking:

<li id="comment-<?php comment_ID() ?>"
class="<?php echo $oddcomment?>">

Victims of Akismet's false positives shouldn't be left in the cold

Every now and then Akismet falsely identifies an innocent comment as spam. From the commenter’s perspective this results in their comment vanishing into thin air. In reality that’s not the case, as the comment can be recovered from Akismet’s queue, but there’s no way for the commenter to know this. I’m a little uneasy with the idea of my commenters left thinking their contribution has gone to waste, so I’d like to give them a hint of what has happened. Additionally, I could provide them with an email link, prompting them to contact me about the misidentification so I can fix it.

The trouble is, once a comment is marked spam by Akismet, there’s apparently no way to react to it in the comments template, as there is to comments ending up in the traditional moderation system. The code fetching the comments for the comments template is in the comments_template() function at comment-template.php. There’s a comment marked ‘@todo’ to use API instead of SELECTs, followed by three queries. I suspect the todo refers to the fact that as it is, there’s no way to tap into those queries short from editing them directly by hacking the file. Some people, myself included, would rather not do that because of the way it inconveniences upgrades.

Until a clean way to tap into the way comments are fetched, or better yet, the functionality I’m after being integrated directly into Akismet, I guess I’ll have to do with a big sign saying if your comment seems to have vanished, read this. Then I’ll link it to a page explaining how to contact me about the misidentification, and show it to every commenter beside the comment form. It’s ugly, but still better than giving them the impression my comment box is just a big black hole.

The Pain of WordPress: "You do not have sufficient permissions to access this page" when trying to upgrade

I searched far and wide for a working solution for this, and in the end had to cook one up myself. For a short description of the issue, every time I tried to use the new (and otherwise higly cool) one-click upgrade feature in one of my blogs, I was greeted with the blunt response of “You do not have sufficient permissions to access this page.” This was made all the more curious by the fact that simultaneously upgrades of plugins did work in very the same blog.

Now, I know how to google and this issue seems alarmingly widespread. Luckily there are also quite a few solutions, but unfortunately, as I said, none of them worked for me. Anyway, here’s a list of the solutions othes have found useful, just in case:

In addition, I tried changing the permissions of wp-content and subfolders, clearing my cookies and cache, logging in and out, reloading and so on — all to no avail. When all of these failed, I began to compare the database tables between my other blogs, in which the upgrade worked smoothly, and the one in which it didn’t.

I first discovered that prefix_options had two options called fileupload_realpath and fileupload_url. In my other, working blog they referred to the correct upload path on my webserver. In the broken one they were at default, example values which of course were flawed. So I fixed the paths thinking I’d found the culprit, but not so: the issue remained. However, this fix probably didn’t hurt either, as the upgrades probably use the ‘upgrade’ subdirectory inside the upload path.

The solution

Then I found that the values of prefix_user_roles in prefix_options differed between the working blogs and the one that didn’t, but didn’t differ among the working ones. So, without any idea of the values’ syntax I simply copied the value from one of the working blogs’ tables and pasted it onto the broken one’s. And that did it: the upgrade now works as intended. Yay!

Just in case someone with only a single blog has this issue, I’ll paste the actual contents of my working prefix_user_roles below. It shouldn’t have anything too unportable, as the value is probably a default set by the installation of one of my more recent blogs.

Note that the newlines in weird-looking places are apparently either part of the syntax, or ignored completely, so copying and pasting the value below should work. Unless WordPress — the installation I’m publishing this post in — somehow screws it up. The browser will break the lines when viewed on this page, but it shouldn’t affect selecting and copying, as it’s only part of the visible rendering.

a:5:{s:13:"administrator";a:2:{s:4:"name";s:13:"Administrator";s:12:"capabilities";a:53:{s:13:"switch_themes";b:1;s:11:"edit_themes";b:1;s:16:"activate_plugins";b:1;s:12:"edit_plugins";b:1;s:10:"edit_users";b:1;s:10:"edit_files";b:1;s:14:"manage_options";b:1;s:17:"moderate_comments";b:1;s:17:"manage_categories";b:1;s:12:"manage_links";b:1;s:12:"upload_files";b:1;s:6:"import";b:1;s:15:"unfiltered_html";b:1;s:10:"edit_posts";b:1;s:17:"edit_others_posts";b:1;s:20:"edit_published_posts";b:1;s:13:"publish_posts";b:1;s:10:"edit_pages";b:1;s:4:"read";b:1;s:8:"level_10";b:1;s:7:"level_9";b:1;s:7:"level_8";b:1;s:7:"level_7";b:1;s:7:"level_6";b:1;s:7:"level_5";b:1;s:7:"level_4";b:1;s:7:"level_3";b:1;s:7:"level_2";b:1;s:7:"level_1";b:1;s:7:"level_0";b:1;s:17:"edit_others_pages";b:1;s:20:"edit_published_pages";b:1;s:13:"publish_pages";b:1;s:12:"delete_pages";b:1;s:19:"delete_others_pages";b:1;s:22:"delete_published_pages";b:1;s:12:"delete_posts";b:1;s:19:"delete_others_posts";b:1;s:22:"delete_published_posts";b:1;s:20:"delete_private_posts";b:1;s:18:"edit_private_posts";b:1;s:18:"read_private_posts";b:1;s:20:"delete_private_pages";b:1;s:18:"edit_private_pages";b:1;s:18:"read_private_pages";b:1;s:12:"delete_users";b:1;s:12:"create_users";b:1;s:17:"unfiltered_upload";b:1;s:14:"edit_dashboard";b:1;s:14:"update_plugins";b:1;s:14:"delete_plugins";b:1;s:15:"install_plugins";b:1;s:13:"update_themes";b:1;}}s:6:"editor";a:2:{s:4:"name";s:6:"Editor";s:12:"capabilities";a:34:{s:17:"moderate_comments";b:1;s:17:"manage_categories";b:1;s:12:"manage_links";b:1;s:12:"upload_files";b:1;s:15:"unfiltered_html";b:1;s:10:"edit_posts";b:1;s:17:"edit_others_posts";b:1;s:20:"edit_published_posts";b:1;s:13:"publish_posts";b:1;s:10:"edit_pages";b:1;s:4:"read";b:1;s:7:"level_7";b:1;s:7:"level_6";b:1;s:7:"level_5";b:1;s:7:"level_4";b:1;s:7:"level_3";b:1;s:7:"level_2";b:1;s:7:"level_1";b:1;s:7:"level_0";b:1;s:17:"edit_others_pages";b:1;s:20:"edit_published_pages";b:1;s:13:"publish_pages";b:1;s:12:"delete_pages";b:1;s:19:"delete_others_pages";b:1;s:22:"delete_published_pages";b:1;s:12:"delete_posts";b:1;s:19:"delete_others_posts";b:1;s:22:"delete_published_posts";b:1;s:20:"delete_private_posts";b:1;s:18:"edit_private_posts";b:1;s:18:"read_private_posts";b:1;s:20:"delete_private_pages";b:1;s:18:"edit_private_pages";b:1;s:18:"read_private_pages";b:1;}}s:6:"author";a:2:{s:4:"name";s:6:"Author";s:12:"capabilities";a:10:{s:12:"upload_files";b:1;s:10:"edit_posts";b:1;s:20:"edit_published_posts";b:1;s:13:"publish_posts";b:1;s:4:"read";b:1;s:7:"level_2";b:1;s:7:"level_1";b:1;s:7:"level_0";b:1;s:12:"delete_posts";b:1;s:22:"delete_published_posts";b:1;}}s:11:"contributor";a:2:{s:4:"name";s:11:"Contributor";s:12:"capabilities";a:5:{s:10:"edit_posts";b:1;s:4:"read";b:1;s:7:"level_1";b:1;s:7:"level_0";b:1;s:12:"delete_posts";b:1;}}s:10:"subscriber";a:2:{s:4:"name";s:10:"Subscriber";s:12:"capabilities";a:2:{s:4:"read";b:1;s:7:"level_0";b:1;}}}

WordPress and wrong $numposts?

After a fresh WordPress installation, I was dumbfounded for a while when a simple “global $numposts; echo $numposts;” would always print N+1 despite the total number of posts actually being N. Turns out I had forgot to delete the initial “About” page, which obviously isn’t listed among the posts, but among pages, yet gets included when $numposts is calculated.

Old news, but news to me: WordPress security key definitions in wp-config.php

While investigating an entirely separate issue with one of my WordPress installations, I came across this:

“Beginning with WordPress Version 2.6, three (3) security keys, AUTH_KEY, SECURE_AUTH_KEY, and LOGGED_IN_KEY, are used to insure better encryption of information stored in the user’s cookies. Beginning with Version 2.7 a fourth key, NONCE_KEY, was added to this group.

If you don’t find the keys in your wp-config.php file, add the keys definitions with reference to Editing wp-config.php – Security Keys, and upload to your server.”

Step 13: Add security key definitions to the wp-config.php file
WP Codex

Since most of my WordPress installations are pretty ancient, and upgrading them has long since become a routine job, this was the first time I heard about this feature. So my blogs have been lacking in this security feature, until now (I set up the aforementioned keys in each of my wp-config.php files).

Debian (Lenny): How to change MAC address while installing

It’s easy enough to change your network adapter’s MAC address once you have a Debian/Ubuntu system installed, but I needed to do this from within the Debian installer (Lenny beta 2), and it took me a while to figure out how. So I’m making a note of it for my own future reference, and maybe someone googling for the phrases I initially did will find this helpful.

So here’s the problem: my NIC’s default MAC address is (say) 01:02:03:04:05:06, and for one reason or another, I need it to be 06:05:04:03:02:01 instead. Furthermore, I need this change to be in effect while I’m inside Lenny’s installer, so ifconfig is not available. Here’s how I did it:

  1. From the installer’s boot menu, select Advanced options, and Expert install.
  2. Work your way down the steps as needed, starting from the top, until you’ve gone through Detect network hardware. Instead of the next one (Configure the network), pick Execute a shell from further down the menu.
  3. In the shell you can check your network interface status with
    # ip link show eth0

    You might use eth1 or some other port instead of eth0, but I haven’t done this with anything other than the one NIC I had in the setup, and so haven’t used anything besides eth0.
    In my case, entering the command gives the following output:

    2: eth0:  mtu 1500 qdisc noop qlen 1000
        link/ether 01:02:03:04:05:06 brd ff:ff:ff:ff:ff:ff
  4. Next, the spell you’ve been waiting for. Let’s change that MAC address!
    # ip link set eth0 addr 06:05:04:03:02:01

    If all goes well, ip won’t say anything. Re-run the ‘show‘ command listed in the previous point to see that it actually worked.

  5. Type exit to return to the installer.
  6. Now you pick up from Configure the network, and proceed installing from there.

One last point: the changed MAC address won’t survive the reboot finalizing the installation, so if you want to make it permanent, you’ll want to set it after the first boot into your new system, by using the method I linked to in the beginning (editing /etc/network/interfaces). Or you could to do it from the installer, using nano (in busybox).

Anticipating Google Chrome

On paper, Google’s Chrome seems to have some nice features going for it. Design ideas I like about it, featured either in the comic or the blog post:

  • It’s open source.
  • The importance of stability. Although I’ve had no serious problems with Firefox either (after I ditched Adobe’s flash), making stability one of the selling points instead of just something implied, is definitely something I welcome.
  • Speed. This was one of the biggest reasons I initially switched from IE to Firefox, but since then Firefox has taken on so much extra baggage that it has become unbearable for me, and caused me to switch to Epiphany.
  • The sweet spot between too many features and too few sounds golden. Like I said, I’ve switched to Epiphany, and I made the choice mainly because the design philosophy behind it reflects this marriage of simplicity with the most important features.
  • Linux and Mac versions underway in addition to the Windows version. Definitely a plus, although we’ve perhaps even come to expect this from Google.

Things I’m on the fence about:

  • It’s said to be designed from the perspective of modern web applications. Whether this is good or not depends on how it’s engineered. If it has resulted in less bloat than traditional browsers’ evolutional codebase, even with the advertised increased performance, I’m all for it. Then again, maybe they’ve just re-invented the wheel. Which, of course, isn’t necessarily bad for the user, just a waste of time.
  • Security. Apart perhaps from IE, I think modern browsers are pretty secure, and the overwhelmingly worst threat lies not with them, but between the keyboard and the chair. Of course, not all users are equal, and perhaps a paranoidly secure browser is helpful for users too innocent for their own good on the web, but I like to be in control myself and am easily angered by software attempting to out-smart people using it. Which is what a browser with a wrong idea about the user’s abilities inevitably does.
  • The multi-process design. It seems like a radical solution, which may be revolutionary, or just a dead end. Either way, I’m very happy to see them experiment this way.
  • The privacy mode. In itself, it’s a good thing, but if it has resulted in lack of privacy for the normal mode, it’s a mistake. But privacy-wise I think the bar has been set so low by the current generation of browsers that they should be easily beat at this.

Things I dislike about it:

  • It’s from Google. They’re not necessarily evil, but I dislike any player who’s gotten too big, and when it comes to the web, Google definitely qualify. However, the power of open source is strong enough to counter this point: because they’re not locking users in with Chrome, it doesn’t matter what I think about them. What matters is the product and how good or bad is it in other respects, so I could scratch this point entirely.
  • Only a Windows version available so far. I’ll have to use virtualization to get my hands on it!
  • The Omnibox. I cannot put into words how much I despise Firefox’s AwesomeBar; it was the tipping point for me, finally causing the switch to Epiphany. They’re saying this is nothing like it, but I’ll have to see it to believe it. Until then I’m marking it as a minus.