Half-Elf on Tech

Thoughts From a Professional Lesbian

Author: Ipstenu (Mika Epstein)

  • Make An RSS Powered Email List

    Make An RSS Powered Email List

    Sometimes the problems we have are insanely more complicated than they should be, because our heads get trapped in a space they shouldn’t be. For years, I used FeedBurner to manage my RSS feeds. Then I realized I didn’t care that much, I didn’t need to know who was accessing my feeds, and really the only benefit was that I could put ads in my feeds (which … no one clicked on anyway) and 12 people could subscribe via email. Well, with some research I found that I could put ads in my feeds with some WordPress functions (I’ve since removed them) and I could use Subscribe2 as a plugin to email when I had new posts. Don’t get me wrong, I really like Subscribe2 except I didn’t like the interface. It’s on the back end of WordPress. My site is a BuddyPress site. Everything is on the front end for my users, and I like it that way. It all looks ‘branded.’ The plugin dev was, fairly, under the idea of ‘Works how I want it.’ I thought about forking, but as I looked at the code, I thought that I really didn’t need WordPress to handle this. I needed a way to email an RSS feed to a mailing list. A proper, opt-in, stable, mailing list, that wouldn’t affect my blog while processing.

    I found an answer that can be applied to any site, WordPress or not.

    What?

    The problem:
    I have an RSS feed I want to be able to email to people who don’t like RSS, and I don’t want to use FeedBurner, MailChimp or any external process.

    The solution:

    • Setup a MailMan list for your emails and configure as needed
    • Install and configure rss2email
    • Setup a cron job

    Why?

    Why not use [this product]? When I presented this to people the first thing they said was ‘Just use FeedBurner!’ or ‘Use MailChimp!’ I get that I can use those third-party vendors, but I don’t want to. I like to self-host because then, if things go wrong, I have the ability to do something about it. This is also how I increase my IT toolkit. I have a need, I find a solution. Sometimes I write the code, and sometimes I just master a new tool.

    Why Mailman? Mailman (or properly GNU Mailman) is installed on my server and while it may be old, the current stable version is 2.1.14, and that came out September 2010. It’s still updated, maintained and supported. And it works. I’m familiar with it, I’m comfortable with it, and there’s no reason not to. I did experiment with phpList, which claims to be able to handle RSS feeds as ‘source’ on it’s own. The problem, as my Twitter buddy @JohnPBloch warned me, is it’s not friendly. He said “I don’t care much for phpList. I always felt like the software was working against me instead of with me.” And he’s right. It took 5 minutes of setup for me to gag and delete it.

    Why rss2email? I don’t think RSS is dead. In fact, I still prefer it to email (or Twitter). My unread RSS list (currently run via Google Reader) sits, quietly, patiently, waiting my attention. I don’t get spam or junk feeds, and if I decided to mark all my Fail Blog feeds as read without reading them, no one knows but me. I don’t have to reply to anything, and I can go back to using my email for communication. That said, I know a lot of people who like to get updates in their email, so I have to take that into consideration when running a site. Sometimes, when you make a site, you cater to yourself. Sometimes you cater to your audience.

    Why cron? I’m on Linux. That’s what you do when you want to schedule things.

    How?

    Bear in mind that my details are going to be specific to my situation.

    Mailman is the easiest. You make a mailing list. I wanted an announcement mailing list, so under Privacy options -> Sender Filters I set up that all users were moderated by default and to discard their emails. Then added my email under “List of non-member addresses whose postings should be automatically accepted.” I knew I was going to have emails sent from a specific address, and I didn’t want that address to GET the emails, so by putting it on that list, I don’t have to worry about approving posts. That’s pretty much all the ‘special’ customization I did. If I’d wanted to put a reject to other people’s emails to the list, instead of a discard, I’d have added this “This is an announcement only list. Your post has been rejected.”

    rss2email was the hardest, but only because it was new. The install process is really straightforward. I made very minor tweaks to the config.py file, based on a first run when I realized that my mailing list would strip HTML. I set HTML_EMAIL and USE_CSS_STYLING to 0 to get it all to plain text. I changed my DEFAULT_FROM and OVERRIDE_FROM to ‘pretty’ versions of my domain information. Then I had to customize my SMTP stuff, since it requires authentication and is on a special port (not 25).

    cron was the most surprising. Since I have to run rss2email out of the same folder it’s in (Python…) I wrote a quick shell script called rss2email.sh that has two steps. It changes directory to my install of rss2email and then it calls the command ./r2e run. Then I called it with a twice-daily (0 and 12) cron job with /home/USERNAME/rss2email.sh and it’s done. I’m not going to give you a blow by detail on how to do cron stuff. It’s way too complicated to try and overview here.

    Satisfied?

    Pretty well. I’m still massaging the output a bit. The HTML output of a full RSS entry was weird. After changing my WordPress feed to excerpts, I ended up with some weird lines in my emails:

    This was caused by some old functions I had in my theme to insert ads into my feeds (mentioned above). I took that out, called ./r2e reset to clean out the database, and then re-ran the script. Worked fine! I admit, I had some moments where I didn’t like putting the excerpt in. I use a custom crafted excerpt in every single post on this site as part of my layout, and while I prefer to avoid ‘read more!’ type things in my feeds, I realized my custom excerpts would be ‘good enough’ for anyone who cared. I do wish WordPress would make two feeds, one excerpt and one none, but that’s a job for another day. At least I’ve managed to semi-customize my Mailman digest header (via manually editing masthead.txt).

    After all my testing, I deleted the mailing list and reset everything, did a clean build, and voila! Works like a champ, without putting extra stress on things!

  • Customizing a Sidebar Profile – BuddyPress

    Customizing a Sidebar Profile – BuddyPress

    I was looking at BP Tricks and thought ‘You know what would rock my site? A sidebar profile controller!’ Turns out this is pretty easy and only ‘requires’ two plugins.

    My final product (see left) isn’t super impressive, but it’s pretty simple and easy to use. The basic idea is that I have two master widgets. One is what the non-logged in user sees (a simple signup window) and one is what the logged in user sees. The logged in user should be able to see their profile info, their notifications and anythign else I want. Before I got started I made a list of what I wanted them to see.

    • Profile – This lists your profile, edit links, settings links, and a logout link
    • Notifications – This lists everything that can email you: notices/messages, comment subscriptions, newsletters, mailing lists
    • Achivements – I use Paul Gibbs’ Achievements for BuddyPress
    • Activity – Links to the various activity screens

    First I decided I wanted an accordian style profile, where you had sections. I grabbed Tabbed Widgets and tossed that in my widget area. Then I used Widget Logic and set the tab to only show if a user was logged in. If the user is NOT logged in, I used the PHP Code Widget to display a login form. Since I’m using BuddyPress, I just grabbed this wholesale from the source.

    <form id="sidebar-login-form" class="standard-form" action="<?php echo site_url( 'wp-login.php', 'login_post' ) ?>" method="post" name="login-form"><label><!--?php _e( 'Username', 'buddypress' ) ?--> <input id="sidebar-user-login" class="input" type="text" name="log" value="<?php echo esc_attr(stripslashes($user_login)); ?>" /></label><label><!--?php _e( 'Password', 'buddypress' ) ?--> <input id="sidebar-user-pass" class="input" type="password" name="pwd" value="" /></label>
    <p class="forgetmenot"><label> <input id="sidebar-rememberme" type="checkbox" name="rememberme" value="forever" /> <!--?php _e( 'Remember Me', 'buddypress' ) ?--></label></p>
    
    <center><!--?php do_action( 'bp_sidebar_login_form' ) ?--> <input id="sidebar-wp-submit" tabindex="100" type="submit" name="wp-submit" value="<?php _e('Log In'); ?>" /> <input type="hidden" name="testcookie" value="1" /></center></form>
    

    I could have probably done this with a widget, but I like being able to customize my PHP as I want to. Next it was time to build my tabs. The Tabbed Widget plugin is pretty easy to use. You make your widgets in the Invisible Widget area and they show up available for the Tabbed Widget. Using the list I made above, I pulled in the obvious widgets. Three are PHP and one is the Achievements widget which came with the plugin. I dislike using plugins just for widgets, so my PHP is how I customized things. The PHP for notifications has extra cruft you probably won’t need, but I wanted you to see how you could easily port in any link.

    My profile

    <div>
    <div style="float: left; padding-left: 5px;"><strong>Hello, <!--?php echo bp_loggedin_user_fullname() ?--></strong>
     • <a href="<?php echo bp_loggedin_user_domain() ?>profile/">Visit My Profile</a>
     • <a href="<?php echo bp_loggedin_user_domain() ?>profile/edit/">Edit My Profile</a> 
     • <a href="<?php echo bp_loggedin_user_domain() ?>settings/">Edit My Settings</a> </div>
    </div>
    

    My Notifications

    • <a href="http://jorjafox.net/comment-subscriptions/">Edit Comment Subscriptions</a>
    • <a href="http://jorjafox.net/wp-admin/users.php?page=s2_users">Edit Daily Update Emails</a>
    • <a href="http://jorjafox.net/csiwatch/">Edit CSI Watch Subscription</a>
    • <?php if ( messages_get_unread_count() > 0 ) {
    	?><a href="<?php echo bp_loggedin_user_domain() ? rel="nofollow"><?php echo BP_MESSAGES_SLUG ?>">Inbox (<?php echo messages_get_unread_count(); ?>)</a><?php 
    } else {
    	?><a href="<?php echo bp_loggedin_user_domain() ? rel="nofollow">/messages/">No new messages</a><?php 
    } ?>
    

    Activity

    <div style="padding-left: 5px;">
    <ul id="user-menu">
    	<li><a href="<?php echo bp_loggedin_user_domain() ?>activity/">Site Activity</a></li>
    	<li><a href="<?php echo bp_loggedin_user_domain() ?>activity/just-me/">My Activity</a></li>
    	<li><a href="<?php echo bp_loggedin_user_domain() ?>activity/favorites/">My Favorites</a></li>
    	<li><a href="<?php echo bp_loggedin_user_domain() ?>activity/groups/">My Groups</a></li>
    	<li><a href="<?php echo bp_loggedin_user_domain() ?>activity/mentions/">@<!--?php echo bp_loggedin_user_fullname() ?--></a></li>
    </ul>
    </div>
    

    Once I was done making those, I just pulled them into my Tabbed Widget in the order I wanted, with the style and defaults I wanted. The rest was all CSS, which you can do yourself.

    Basically, this just goes to show you that you can do pretty much anything you want with WordPress plugins. I really only needed two to do this, though the third (PHP Code Widget) really helped me take it to the next level. If you’re PHP shy, you can use Login with Ajax instead of my ‘Login’ code, BP Notification Widget instead of my Notification code, and I’m sure people can pick out some alternatives to other code bits.

    Hope this gets you started!

  • Common IT Answers

    I actually have this sitting on my desk at work. It’s so old that the fluid has evaporated enough that it doesn’t work right anymore. But I keep it and use it. What is it? A magic 8-ball of tech support! Many moons ago, our CDW Vendor gave my boss a Magic 8-Ball for programmers showing the answer “IT’S NOT A BUG – IT’S A FEATURE”. The top of the ball says “For your most commonly asked IT requests.” Some of the answers are blatant CDW adverts, but the rest are answers I know I’ve used at least once:

    • Did you press the right button?
    • I can’t test everything
    • It worked yesterday
    • It works like I programmed it
    • It works on my machine
    • It’ll be fixed in the next release
    • It’s a Beta – What did you expect?
    • It’s an unlikely coincidence
    • It’s just an isolated incident
    • it’s not a bug, it’s a feature
    • It’s not supposed to do that
    • Please submit a formal request
    • Plug it in
    • Program works. Must be user error
    • Reboot
    • Someone changed my code.

    Sadly, the thing is dying. I may have to learn how to make a new one, since right now it’s stuck showing me a corner instead of a face.

    I’m not the only person who uses these, though. Eric Mack did as of 2004!

  • Failure of Imagination

    Failure of Imagination

    This is not an excuse.

    People make mistakes, and we all accept that. But what I find astounding is that a lot of users look at the software developers and say things like “I find it unacceptable that you let this critical error slip through.” They seem to think that anything less than a perfect piece of software coded by perfect people with no errors is cause to demean the programmers.

    The other day my father (a seasoned risk analyst – see http://woody.com) passed me an article by Herbert Hecht called Rare Conditions – An Important Cause of Failures, where in Hecht explains that “rarely executed code has a much higher failure rate (expressed in execution time) than frequently executed code during the early operational period.” The point, for those of you who felt your eyes glass over at the big words, is that the less often a piece of code is used, the more likely it is to break.

    I read this article and immediately shouted “Yes! Exactly what I’ve been saying!” And it’s not because we don’t try to write the best code we can, either. It’s because most of us use conventional test case preparation. We say ‘This is what we want the code to do, we shall test it and see if it works. Great! Now what if I did this…’ The problem there is you need a skilled person coming up with the ‘what if.’

    Back in my desktop-software support days, I was testing a piece of software I’d never used before, and I crashed the program. Hard. I had to reboot. And I found I could crash it repeatedly doing that. I called the vendor, who sent their best techs out to look at it. I showed him what I did and he started laughing. What I was doing was something no one familiar with the software, and it’s purpose, would do, because it was simply wrong. Like putting in your phone number in the field for your first name. They agreed that they should error trap it, however, and it certainly shouldn’t crash the system.

    Why didn’t that problem ever show up in their tests? To quote Frank Borman on the Apollo 1 fire “Failure of imagination.” They simply couldn’t conceive of a world where in someone could be that ignorant of the right way to do things. They didn’t document it, because it wasn’t a requirement of their software, but of the process being completed, and they didn’t error-trap it because no one in their right mind would do that.

    The world keeps making bigger and bigger fools, doesn’t it? When you test code, you’re always going to have a bias. You’re looking at it from the perspective of someone familiar with both the program and its purpose. When we test WordPress (and I include me on this as I beta test WordPress and file trac reports when I find problems) we test it from the perspective of experienced WordPress users. We’re the people who read the documentation on what changed. We’re familiar. And that’s the problem.

    So we look at Hecht’s second suggestion. “Random testing over a data set that is rich in opportunities for multiple rare conditions.” Basically it’s making a list of everything that could go wrong, the really wild and rare errors you’ve seen (in the case of WordPress, you could probably cull some great ones from the forums, at work I review my trouble tickets and make a list of the most common), and testing that. Testing stuff you KNOW will break. Again, this has the problem of bias, but it allows you to make sure when your code fails, it fails elegantly. This kind of testing has the other problem of finding the right data set. This really is the hardest part, and takes some seriously dedicated people to come up with one that limits bias.

    Hecht’s final suggestion is “Path testing, particularly where semantic analysis is used to eliminate infeasible paths” but he quickly points out the problems:

    [This] technique can be automated and is the only one for which an objective completeness of test criterion can be identified. However, it is costly and will practically be restricted to the most essential portions of a program.

    So what can we do, other than be smarter? We can test better, certainly, but that’s more difficult than it should be. And why does all this happen in the first place? We’re smart people! We should code better! In a related article (also sent by my father) by David Lorge Parnas discusses Software Aging. In that paper, he posits that too often we concentrate on getting the first release done, rather than looking at the long term goals of the software.

    This article I find has particular relevance to the open source community, which is filled with people who become software ‘engineers’ via non-traditional paths. How non-traditional? In Parnas’ article (dated 1994) he mentions that software designers come either from the classic computer science background or they’re home-grown from their business specialty. This means that a person who writes code for a bank either is a programmer who knows their coding languages and the basics of how to think ‘in computer’, or it’s a bank employee who picks up code and learns it on the job. There are, obvious, drawbacks to both backgrounds. A banker understands the desired end functionality of the program, and the CompSci guy understands who to write it, but not how it’s used. They are, both, too specialized.

    I inherited some code that was undocumented and had the problem of inelegant failures on rarely run processes. Over the last five years, I’ve steadfastly cleaned this up to error-trap correctly and output meaningful errors. I don’t have a CompSci degree. Actually, I don’t have a degree at all, in anything, and while I never declared my major, it was Anthropology (by virtue of the courses I’d taken). As luck would have it, I’m also somewhat ignorant of the purpose of most of the code I write. This means every time I’m tasked with a new project, I look at it with fresh eyes, and I can see the flaws people in their little boxes are unable to see. I’m perpetually on the outside, which means my perspective is almost always ignorant, but rarely is it unintelligent. On multiple occasions, my simple question of ‘Why are we doing it this way? Is it to make it easier on the end user or the programmer?’ elicits astounding reactions. I can help pull the programmers out of their heads and look at the long-view.

    Parnas calls that ‘designing for change’ (a familiar ad slogan in the 1970s). Part of the problem, he thinks, is that people don’t have the appropriate education to their job and, thus, are untutored in the basics of programing and the related thought process. I disagree, and not just because I am inappropriately educated to my day job. It’s true my ‘training’ didn’t prepare me to write code, but my education did. I was taught, from a very early age, to think and reason and question. Those basic principals are why I’m able to do my job and follow along with Parnas’ work. Perhaps he would be better put to say people have not made the effort to learn the basic groundings of good software design, independent of your education and ‘purpose.’ The banker can learn software design irregardless of the intent of his code, and the CompSci programmer can master enough of banking to understand the purpose of what he writes. The middle ground that has the view of goal and design is what allows us to design for the future and write code that can grow and age.

    That all depends on if the code is well documented. Parnas’ rightly twigs to the most common problem I’ve seen in programing. No one likes to write documentation, and when we do, it’s clear as mud to someone who is unfamiliar with our goal and design. If you don’t the goal of the programmers when they came up with Drupal (to pick on someone else for a change), then none of the documentation will help you. Software, being based on mathematics, should have documentation that reflects its parentage, says Parnas. This should not be confused with user documentation, which should have none of that. Developer documentation should resemble mathematical documentation if it has any hope of being useful and lasting.

    While Parnas’ paper was written in 1994, I wonder if the problem of crossover between developer and user was as prevalent as it is today. Today there’s no clear line between the developer who writes the code and the end user who wants to use it. This is the case most noticeably in open source projects, like WordPress, Drupal, Joomla, and so on. These projects are championed by the developer/user, a creature that may not have existed as such as widespread phenomenon 17 years ago. While Parnas does mention the possibility in use-cases, he only does it to highlight the problem of isolation among developer groups, and not as a potential root cause to why problems are missed. They are missed in the isolated groups because we cannot see outside our ‘box’, for lack of a better room, and envision that particular ‘what if.’

    This is why we have a great need for reviews. When a doctor tells you that you have cancer and you’re going to die, you seek out a second opinion. The same is done with software. The code works for you, so you let it out into the world for other people to test. We need the outside sources to come and bang on the rocks and tell us what’s wrong. That’s why you see people like @JaneForShort asking more people to join the WordPress beta tests. She knows the core developers can’t possibly test everything, and the more use-cases we can come up with, the more we can make the end result better.

    Would having more professionals solve this problem? Parnas seems to think so. He thinks that having more people trained in engineering and science combined will produce better programmers. After all, what is coding but math applied to engineering? I feel it’s the techniques that are more important. A grounding in basic algebra (and some calculus, certainly) should be enough to be able to program in most languages. And a well-formed understanding of the disciplines of engineering should allow a person to look past ‘This is my problem, how do I solve it?’ You need innovation, understanding, and a respect for how things work in order to write effective programs.

    Why did we miss a critical error? Because we didn’t see it. It’s always going to remain that simple. With better education, will we be able to see it in the future? Perhaps. But all the traditional book education in the world cannot teach a person how to think. Even if we can perfect the creation of the well-thinking human, we will always be loosing a battle against the universe creating bigger fools. But those thinking people can find the problem, once it’s reported, solve it, and learn to make it better the next time.

    And that should be our goal.

    Make the code better, test it smarter, document it clearly, and plan it thoughtfully.

  • Blocking IPs – Don’t

    Blocking IPs – Don’t

    Here’s the thing. I don’t think blocking an IP address is a good idea.

    Will it prevent spammers from registering on your site? Yes. But much like CAPTCHA, I think it does more harm than good.

    See, IP addresses are numerical labels assigned to each device (e.g., computer, printer) participating in a computer network that uses the Internet Protocol for communication. Big words. Shorter version: The IP address is the phone number. DNS is Caller ID. When you dial ‘Home’ on your cell-phone, the phone translates that into a number and dials, right? Well on the internet, you say “I want to go to ipstenu.org” and it’s DNS that says “Okay, my big bad directory says that’s 67.227.208.52 so here you go!” (actually it says “You want extension on 67.227.208.52” if I can stretch that metaphor).

    The IP address for websites is pretty static. Just as most of us don’t want to change our phone numbers and teach all our parents new contact info, we don’t want to have to update all the DNS servers in the world with our new IP address. It’s a pain in the ass, it takes up to 72 hours to propogate to everyone (usually less), but that still means there’s a period of time where people can’t get to your website.

    This is all over-simplified, but you get the gist.

    Here’s where it gets weird. In order for the internet to know who YOU are and send you back the website you asked for, it has to assign you an IP address. And this changes. A lot. Most ISPs (the people who give you access to the net for moneies) have a ‘range’ of IP addresses which numbers less than the number of people they have who pay for internet access. In order to make sure everyone can get on, when you connect to the net, you get a new IP. Back in the day of dial-up, every time you dialed in, you had a new IP. This was normal, and was one of the many reasons no one bothered to block by IP. All the idiot had to do was reconnect. These days, my IP changes about once a week or so, and I have no idea when or why, but it does. That doesn’t bother me.

    Lately, I’ve gotten complaints and requests to make Ban Hammer or Register IP MS block people by IP address. And after playing with that a bit, I’ve decided I won’t. Not because I can’t (it’s really not that hard, and actually, Ban Hammer already does it for Single Site WordPress by accident), but because I don’t think it adds any value. The IP address can change too easily to make this a useful tool, and the odds are I’m going to accidentally block someone who should be able to access the site!

    This is not to say I don’t block IP addresses at all, just that I don’t do it the way people seem to want to go about it. Maintaining my own blacklist of IPs is insane, and stupid. I don’t need to waste my time clicking and banning spammers or auto-register bots. Instead, I block IPs using one of two tools that was designed to look for bad behavior. I detailed all this in Spam / Splog Wars. That’s how I stop spammers and it works.

    So no, I will not be wasting my time telling you how to edit my plugins to block people from the IP level. There are perfectly good ways of doing this that work without you having to field complaints from innocent users.

    Block the bots, not the people.

  • How the WordPress Upgrade Works

    Edited: This post was linked to by the folks at WTC, so I’m getting a lot more traffic! If you asked a question, I will try to answer it promptly, but if you need serious help fixing a problem, please consider posting in the WordPress forums for help.

    I was 90% sure about this before I started writing the post, and Andrew Nacin was nice enough to tweet me the exact file I needed to look at, so when I got home to look, I was ready to go!

    There are two kinds of automated upgrades for WordPress. The main ‘core’ upgrader and then the ‘child’ upgrades used for themes and plugins. They behave differently.

    Most of the time, we all see the plugin and theme installer, where it downloads the plugin to /wp-content/upgrade/, extracts the plugin, deletes the old one, and copies up the new one. Since this is used more often than the core updater (most of the time), it’s the sort of upgrade we’re all used to and familiar with. And we think ‘WordPress deletes before upgrading, sure.’ This makes sense. After all, you want to make sure to clean out the old files, especially the ones that aren’t used anymore.

    This is not how a core update works.

    WordPress core updates, the ones to take you from 3.0.3 to 3.0.4, do not run a blanket delete. They don’t even run a variable delete. They don’t even run a wild-card delete on files in wp-admin (which they could). Instead they have a manually created list of files to delete, files that have been deprecated, and delete only those files. Here’s a snippet of what it deletes:

    $_old_files = array(
    'wp-admin/bookmarklet.php',
    'wp-admin/css/upload.css',
    [...]
    // MU
    'wp-admin/wpmu-admin.php',
    'wp-admin/wpmu-blogs.php',
    [...]
    
    // 3.1
    'wp-includes/js/tinymce/blank.htm',
    'wp-includes/js/tinymce/plugins/safari',
    [...]
    'wp-admin/images/visit-site-button-grad.gif'
    );
    

    As you can see, the files and folders are all very carefully specified. They are not ac-hoc, they are all determined based on what WordPress has removed. If you read the whole thing, the part that would impress you the most is, perhaps, the folder wp-content, where your themes and plugins are installed, is nowhere on that list. Don’t believe me? Go look at wp-admin/includes/update-core.php and search for it. It’s not not there!

    Once the old files are listed, remember that we have not deleted anything, the upgrader runs through 9 steps.

    1. Download the zip file of the new release, unzip it and delete the zip
    2. Make sure the file unzipped!
    3. Make a .maintenance file in WordPress base (this makes your blog ‘down for maintenance’ so no one can do anything and screw you up mid-stream
    4. Copy over the new files. This is a straight copy/replace. Not delete.
    5. Upgrade the database. This may or may not happen.
    6. Delete the unzipped file
    7. Delete the .maintenance file
    8. Remove the OLD files. This is where it goes through the list of deprecated and unused files and deletes them.
    9. Turn off the flag that tells you to upgrade every time you’re in wp-admin

    Nowhere in there is wp-content and your themes mentioned.

    Well, except in this one weird way.

    See, in order for WordPress to work out of the box, a theme must be included, right? WordPress has the default theme of Twenty Ten. Now, I’ve mentioned before that you should never update your themes directly, and instead make child themes. This is why. When the WordPress core files update the copy over everything. Included in everything are two plugins (Akismet, Hello Dolly) and one theme (Twenty Ten).

    Normally this isn’t a problem. Sure, someone always edits those files directly and lives to regret it, but they do live. This last cycle, with 3.0.4, Akismet was accidentally rolled back from 2.5.1 to 2.4. Again, normally? Not a problem. We just upgrade our Akismet installs, remark on the silliness and annoyance, and move on. The problem for one user is she had another plugin or theme edit that hooked into the new Akismet. With the way WordPress updates core, it only deletes the files it knows to delete (and Akismet isn’t any of them) and it copies over the ‘new’ files. Or in this case, the old ones. Which broke her site. Her fix? Just re-update Akismet manually. Not a big deal and an easy fix. (Personally I think NOT updating core, even a security upgrade, with the latest Akismet is a poor choice, but the rational is that they want to keep it small and easy to maintain. So okay, I get why, I just don’t like it. I will support that as their choice, and continue to do my manual upgrades, which include deleting Akismet, Hello Dolly and Twenty Ten before I upgrade.)

    So then, why doesn’t this work 100% of the time? (Yes, I mentioned this before in the 3.0.1 days, but apparently it bears repeating. Read Why doesn’t the WordPress Auto-Upgrade Work? for more thoughts on the subject.) Well, to start with, that’s impossible. Nothing works 100% of the time. Me submitting this post won’t work 100% of the time. You safely walking up the stairs won’t work 100% of the time. This is just how the world works. There are, simply, far too many variables out there to allow this. Even though I make part of my living ensuring that I have an automated process run in a repeatable fashion, I tell people that I only ask for a 75-80% success ratio on the process before I’ll agree to automate it. Why? Because that’s actually phenomenal.

    If you take into consideration all the moving parts, variables, and possibilities that goes into any one individual WordPress install, it’s sort of impressive this stuff works at all. In baseball, if you hit a ball and get on base 33% of the time, you’re considered a fantastic hitter. If you do it 40% of the time, you’re pretty much promised a slot in Cooperstown. Whenever I try and sort out if something is worth the risk, I quote my father “What can go wrong? How likely is it? What are the consequences?” It boils down to an understanding of risk analysis, and what that actually means. The problem is that most of the people using WordPress are users. They’re not generally expected to think about risk. Not that many don’t, but just that Joe Blogger doesn’t tend to look at an upgrade as a ‘risk.’ After all, WordPress tested this, so it should be easy.

    Most of the time, it is. And when it’s not, it was an acceptable risk. All those horrible and terrifying outcomes you read about (from a very vocal minority) are gut-wrenching when they happen to you, don’t get me wrong, but at the end of the day, you have to ask ‘If I use the default WordPress theme and no plugins, do they happen?’ If the answer is no, then WordPress has done all the testing that is required. The onus is not on WordPress to test every upgrade with every theme and plugin. That responsibility is firmly on the shoulders of the person using the themes and plugins. A good developer tests their plugins and themes the moment a release candidate comes out for a new version of WordPress, and sorts out how best to support both the current users and the future ones.

    It’s what we call ‘acceptable’ risks. You take them all the time. You took an acceptable risk brushing your teeth. You take one every time you walk out your door. You know the risks and you accept them. So when you get to arguing that ‘WordPress upgrades always break’ or ‘I hate upgrading because it means my themes/plugins won’t work’ and using these as reasons to show that WordPress is bad software, then I think you’re missing the point. The more you customize, the more things break. This is something I mentioned in When To Code, and it bears repeating. The more you customize, the more things will break when you upgrade.

    But this is an acceptable risk for most of us!

    So when the WordPress auto-upgrade breaks, and I promise you, it will for you at least once in your experience, you have to learn to accept this. It’s not going to work on every server, it’s not going to work on every host. Your server is being constantly upgraded and tweaked. Security patches for PHP, FTP and everything else are applied, most of the time automatically so you don’t have to waste time thinking about it. And when you combine all those things, yeah, it’s going to break.

    This isn’t meant to scare you off of upgrading, but an attempt to raise your awareness of what’s going on, so when things break (and they will), you have a better understanding of why, and what to do. If the automated upgrade of WordPress breaks, upgrade manually. If every single automated install (upgrades, plugins, themes) always breaks, then start to diagnose your server. But if it’s a one off, just do it manually. It is, literally, copying files up to your server. If that’s too hard for you, you may not want to run your own, self-managed, WordPress install.

    As a blanket reminder, in order to prepare yourself for an upgrade, always make backups of your database and your files. A good backup. Never edit core files (even themes) and always remember that the computer is out to get you.