Posts Tagged ‘nerdery’

Upgrade WordPress automatically

Sunday, July 7th, 2013

WordPress has a one-click upgrade feature, but it requires you to give it your FTP/SFTP credentials. If you log into SSH with keys instead of passwords, you can’t use it. I wrote a script that runs on the server (thus it needs no password or special permissions) to back up your current files, then upgrade.

Lines 6 through 10 features variables that you’ll probably want to alter before you run this script.

A few notes:

  • It only backs up the files, not the database, so if WordPress has a database update that breaks your database, hopefully you’ve got some other backup in place.
  • Sometimes after an update, WordPress will prompt you to please update the database. This script will not do that step – you still need to log in and click the button. This script will send you a reminder that an upgrade has been performed and which will allow you to both confirm that nothing was broken, and click the aforementioned button. I don’t trust myself to act on that reminder promptly, so I haven’t set this script to automatically run. Instead, I have a reminder on my phone to go run it manually.
  • A future version might delete all the old backups (both WordPress versions and websites).

# Created Sept 1, 2012
# Last updated July 7, 2013
# Automatically update WordPress.
# Alter these to reflect your environment
website='~/public_html' # website and htdocs might be the same. If unsure, keep them identical.
sitename='My web site'
date=`date +%y-%m-%d`
if [ -f ]; then
echo Removed old >> $log
echo Got latest version of WordPress >> $log
echo Unzipped latest version of WordPress >> $log
# Create old/ if DNE
if [ ! -d old ]; then
mkdir old
echo Created directory for old stuff >> $log
# Create a backup of your website before making changes
htdocs_dir=`basename $htdocs`
cp -Rv $htdocs old/$new_htdocs
echo Copied htdocs to $new_htdocs >> $log
# Put the files for the new WordPress version into your website.
cp wordpress/* $htdocs -Rv
echo Dumped new WordPress into htdocs >> $log
# Archive this version of WordPress. You could probably delete it, but I like to have a clean copy around in case I muck up the code.
mv wordpress/ old/wordpress_${date}
echo Copied pristine WordPress code into old/ >> $log
# Sometimes it has database upgrades and a human needs to visit the site
# to tell it to go ahead, so this e-mail serves as your reminder.
mail $email -s "Wordpress updated on $sitename - go check it out" < $log

Assuming you store this in ~/bin/, you can run this script monthly automatically with the following steps:

  1. At a prompt, type 'crontab -e'
  2. On most systems, this will open vi. Type "i" to insert text.
  3. Paste:
    0 0 1 * * ~/bin/
  4. Push the ESC key to exit insert mode.
  5. Type ":wq" to write changes then quit vi

Eliminating Suse splash screen forever

Saturday, March 2nd, 2013

This trips me up every time I set up a new system. I go into the process remembering that I get tripped up somewhere, but retaining no details about what I should do differently. I am posting this in the hopes that next time I’ll remember to look it up here.

The first step – the one I tend to remember – is to alter menu.lst: for each entry, change splash=silent to splash=verbose and remove the word quiet.

That will remove the splash screen from all the existing boot options, but when an update inevitably adds a new kernel, it will get the default options, including the splash screen. Thus the second step – make a similar change to the default options stored in /etc/sysconfig/bootloader. The line describing the default options starts with DEFAULT_APPEND; remove the word quiet and change splash=silent to splash=verbose.

Text a reminder to the members of your houseshold

Thursday, October 4th, 2012

Every week we forget trash day, so I’ve been meaning to write a script to remind all of us the night before to put the trash cans out.

I only wanted to type the phone numbers once, so I hard-coded them as variables into the script. Turning the command line argument ‘kj’ into the value of $kj was by far the most difficult because I had to look up how to do indirect references in bash, which, as it turns out, is kind of a pain.

In an effort to spare you that same pain, I’m posting the code here.


If you call the file, the usage is as follows: [path to reminder] [recipient(s)]

[path to reminder]

This script can be used to send you several reminders. It looks for a file at the specified path, then uses the text of that file as the body of the e-mail/text. Be sure to create the reminder file before you run this script. For the purposes of example, let us assume it’s in ~/reminders/reminder.txt. Remember to keep it brief – it will be split into 140-character increments, so if you send an 1,000-character reminder, it’s going to arrive as eight annoying, disjointed texts.


I hard-coded shortcuts into the code so I can use aliases instead of relying on myself to having to type a phone number more than once. You can set up as many recipients you want, but note that the code, as it is pasted below, will fail because there are no real recipients set up. You’ll need to add at least one to get any use out of this code.

Setting up a recipient is fairly simple: most (all?) cell phone companies allow you to text message customers via e-mail with an address following the format [10-digit phone number]@[domain]. Finding the value of [domain] is the most time-consuming part, because each company has a different domain, so you need to ask each potential recipient who their cell phone company is, then dig up the corresponding domain. I used this page as a reference, but it may be out of date by the time you read it. If your phone number is (503)555-1234, and you’re a T-Mobile customer, the address at which my phone receives texts is

As always, send several tests before using it for real.


# etc, you can set up as many aliases as you like.
if [ "$#" -lt 2 ]; then

    echo Usage $0 [path to reminder] [recipients]
    echo Recipients defined: kj, eric # CHANGE THIS

    if [ ! -f $reminder ]; then
        echo The reminder you specified, $reminder, does not exist.
    let i=2;
    while [ $i -le $# ]; do
        varname=`eval echo $numvar`
        vartoeval=`eval echo $varname`
        recipient=`eval echo $recipient2`
        if [ "$recipient" == "" ]; then
            echo I do not understand the recipient $recipient
            echo mail "$recipient" -s 'Friendly reminder' -r -a $reminder
            mail "$recipient" -s 'Friendly reminder' -r "" < $reminder
    let i=i+1

Cron job

In order to make this run regularly, you’ll need to create a cron job. You can do that by running “crontab -e”. On most systems, this will default to vi, which can be kind of scary to the uninitiated, so here’s a cheat sheet.

I’m going to assume you’re uninitiated: Copy and paste the following into a text editor you feel comfortable with:
0 21 * * 1 ~/bin/ ~/reminders/reminder.txt kj eric

This will send a text to each recipient listed reminder at 9 PM every Monday night contain. Change the path and recipient(s) to your liking, then copy the whole thing. Switch to the window where you ran “crontab -e” and vi awaits you. Type “i” to enter “insert” mode – this will allow you to use vi like a normal text editor. Paste.

Hit the “esc” key (top left side of your keyboard) to exit “insert” mode. Type “:wq” to save your changes and exit. If you screw up and you don’t want to save your changes, you can exit with “:q!”.

Potential improvements

This was pretty quick and dirty, but a couple glaring improvements stand out:

  • Allow the user to specify a subject. At the very least, make the hard-coded subject a variable so that it remains uniform between the line that sends the mail, and the line below that prints the send command used.
  • I could have put the aliases in some kind of array, which would have allowed for more robust error-checking and prevented the user from having to manually change the usage instructions.
  • Some of the variable names in the while loop are awful.

How to never again see WordPress’ update nag – no plugin necessary

Wednesday, February 8th, 2012

One reason I like WordPress is because they come out with frequent updates. When you run a WordPress site, it checks periodically for new versions. It reminds you with a helpful little yellow bar at the top. It feels great to install a new version, be up to date, and get rid of the nag. However, because of their awesome frequent updates, it also means you’re only ever free of that annoying reminder for a couple days.

A screenshot of the annyoing yellow bar

While it’s important to keep software up to date, I do have a life beyond updating WordPress. I wanted to get rid of that yellow nag once and for all. There are a couple plugins to disable it, but I don’t see any sense in adding more code (and more plugins to update) when I can just add one line to a stylesheet. So, here is how to rid of it at the cost of 13 characters per page load*:

Open wp-admin/css/colors-fresh.css. All newlines and extraneous spaces have been stripped from the file in the interest of speedier loading (this file loads anew every time you load a page in your Dashboard). Search for: #update-nag

In my version of WordPress, it starts on line 11593 of 34572. Expanded, it looks like the following:
#update-nag, .update-nag {
    background-color: #FFFBCC;
    border-color: #E6DB55;
    color: #555555;

Add the following after the opening curly bracket:
    display: none;

When you refresh the admin page, the update nag will be gone forever.

However! With great power moustache CSS comes great responsibility. The WordPress developers made such a prominent prompt because keeping software up to date is important. There are often important security improvements between versions. If you turn off the nag, you still have a responsibility to yourself, your users and The Internet at large to keep WordPress reasonably up to date. Put a recurring item in your calendar to update about once a month.

*You could also eliminate all the other styling applied to the now-invisible element and end up with fewer characters than you started.

Links for this week

Sunday, January 22nd, 2012

Any given day I pick out several stories in my RSS feed reader to follow up on, and so far they’ve just been building up. In an effort to un-flag some of them, I’ll be linking to stories that caught my interest this week:

Upgrading to WordPress 3.3 – the missing “Format” box

Friday, December 16th, 2011

I recently installed WordPress 3.3 for a client, and I was very impressed. Specifically I was excited about tinkering around with the “Format” box, which allows you to post in a variety of formats, including, “Status”, “Gallery” and the regular post format “Standard”.

I wasted no time upgrading this site to WordPress 3.3, but no fun format box. I poked around at options and Googled, to no avail. Most suggestions seemed to revolve around some browser problem, but I could see it on the other site, plain as day, so my browser was obviously capable of displaying it.

For lack of a better idea, I started grepping. I used Firebug to get the id attribute (“formatdiv”), figuring there would be a finite number of instances in the code. Indeed, there was exactly one. It was in wp-admin/edit-form-advanced.php. There were two relevant lines:
if ( current_theme_supports( 'post-formats' ) && post_type_supports( $post_type, 'post-formats' ) )
    add_meta_box( 'formatdiv', _x( 'Format', 'post format' ), 'post_format_meta_box', null, 'side', 'core' );

This alerted me that it was a problem with the theme, which unsurprising considering that I’m still using a customized version of the 2009 default theme. I knew it worked in the latest theme, twentyeleven, so I went to that directory and grepped for ‘format’ and braced myself for the worst. Once I eliminated the CSS files, it was easy to hone in on line 104 of functions.php
add_theme_support( 'post-formats', array( 'aside', 'link', 'gallery', 'status', 'quote', 'image' ) );

This takes place in a function called setup. I went over to my theme and looked for a similar function in the functions.php file. It did not have one. I pasted it in toward the middle of the file and hoped for the best. The format box appeared like magic. I haven’t actually tinkered with it yet, but I wanted to write up my experiences – before I forget them – so that someone else with an old theme can bring some new magic into their WordPress experience.

Privacy is controlling your own data

Sunday, November 27th, 2011

One topic I find myself ruminating on is the ability to own your own data. For example, many of us use Facebook or Google Calendar, and all the information we’ve painstakingly entered there is available for our use, but if we want to move to a different service, we can’t just pick up our data and go, we have to re-enter a lot of information, but some of the information we just lose.

Google and Facebook and Twitter have various APIs to allow some amount of access to our (and other peoples’ data), but it’s still only as much as the provider cares to share. The data is still subject to the providers’ deletion. Also, an API is fantastic if you’re a programmer with spare time, but an end user doesn’t have a lot of options.

There are some tools that aid to this end, but not nearly as many as I’d like. I haven’t investigated any of the following as thoroughly as I’d like, but for any interested party:

Although not a specific tool, there are distributed social networks. These are pieces of software with functionality similar to Facebook or MySpace or Friendster that you can install on your own machine. I believe some support being install across multiple machines, so I could have a copy on my server, my friend who’s a privacy nut could have a copy on their server, but we could interact with eachother like we’re both on the same site. To me, this type of social network has the most advantage, because it allows anyone who wants absolute ownership of their data to have it, while those who don’t care can just sign up and be an end user.

The downfall with a social network that isn’t already established is that since we use it to socialize, it’s not very useful until it reaches a certain critical mass. Most of our friends don’t want to leave their existing social network because it has all their data and all their friends. However, now is a great time to try to break that barrier. The buzz (no pun intended) around Google+ is putting doubt into people’s minds that Facebook is The Only Way. A lot of my friends are signing up without any investment, mostly to just see what it’s about. Now would be a great time for some enterprising nerd to take advantage of that curiosity.

Improved improved GPS removal

Friday, October 22nd, 2010

I updated my jpeg geotag-removal script to recurse subdirectories. With that came the requirement to filter out irelevant files (not jpeg, no EXIF information). Below is the new script. I hope you find it useful:
# Will remove non-essential EXIF from a jpeg while retaining Date/Time value.
# Use it to remove GPS information from pictures I want to put on the internet.
# Created Wed Aug 11 18:43:03 PDT 2010
# For handling spaces. See:
IFS=$(echo -en "\n\b")
for img in $@; do
    file_type=`file -b $img`
    if [ -d "$img" ]; then
        echo "$img" is a directory - recursing
    $0 "$img/*"
    elif [ $file_type == "JPEG image data" ]; then
        # Grab the original date/time
        DT=`jhead "$img"|grep 'Date/Time'`
        # If the date information started out
        # blank, trying to tack it back on
        # will result in an error
        if [ "$DT" == '' ]; then
            # Current format: " Date/Time : yyyy:mm:dd hh:mm:ss"
            # jhead requires: yyyy:mm:dd-hh:mm:ss
            # Strip non-essential information
            jhead -purejpg "$img"
            # Put the date/time back
            jhead -mkexif -ts$DT "$img"
        echo "$img" is not a JPG - ignoring $file_type

Hacking Tracks to accept shorter usernames

Monday, October 18th, 2010

I’m looking at Tracks/Shuffle to manage to-do lists on my phone/computer. I’m scouring the tubes for one that doesn’t involve me handing my data off to someone else. I like Shuffle because it can synch to any Tracks server you specify, and since Tracks is free software, it’s easy to install on any server.

In an effort to be able to use my usual login (kj), I H@X0R-H@X0R-H@X0R-ed the code to lower the minimum login from 3 to 2 characters. It’s not rocket science, but I hope it’ll save somebody else a bit of grepping:

In app/models/user.rb, line 115, change

validates_length_of :login, :within => 3..80


validates_length_of :login, :within => 2..80

In spec./models/user_spec.rb, line 81, change

it_should_validate_length_of :login, :within => 3..80


it_should_validate_length_of :login, :within => 2..80

If you’re feeling really ambitious, you could even change the error messages to be accurate. In test/unit/user_test.rb,. line 87:

assert_error_on u, :login, “is too short (minimum is 3 characters)”


assert_error_on u, :login, “is too short (minimum is 2 characters)”

Again in test/unit/user_test.rb,. this time on line 107:

assert_errors_on u, :login, [“can’t be blank”, “is too short (minimum is 3 characters)”]


assert_errors_on u, :login, [“can’t be blank”, “is too short (minimum is 2 characters)”]

Improved GPS removal

Friday, August 13th, 2010

I recently posted about a way to remove the GPS information from pictures. I wrote a script that will retain the Date/Time information. It requires jhead.
# Will remove non-essential EXIF from a jpeg
# while retaining Date/Time value. I use it to
# remove GPS information from pictures I
# want to put on the internet.
# Created Wed Aug 11 18:43:03 PDT 2010
# For handling spaces. See:
IFS=$(echo -en "\n\b")
for img in $@; do
    echo Working on "$img"
    # Grab the original date/time
    DT=`jhead "$img"|grep 'Date/Time'`
    # Current format: " Date/Time : yyyy:mm:dd hh:mm:ss"
    # jhead requires: yyyy:mm:dd-hh:mm:ss
    # Strip non-essential information
    jhead -purejpg "$img"
    # Put the date/time back
    jhead -mkexif -ts$DT "$img"

It accepts image files as arguments. You can pass as many or as few as you feel like. If you’re interested in keeping other non-essential exif data, you might want to look into the jhead argument “-te”.