Twitter, Movable Type and blog tweeting

| 4 Comments

For years now, I've been using a really great blogging tool called Movable Type Pro. This advanced utility does pretty much everything you'd ever want. Well, most everything that is.

Wouldn't it be great if you could also somehow automatically send out a twitter update (tweet) every time that you've created a new blog entry? Something like this:

Well, as of this very moment you can! All you have to do is keep reading, and if you are patient enough and read carefully what I have to say, then I will reveal to how it's done. Actually it's really quite easy.

Let's call it "blog tweeting".

This is the approach. Whenever a new entry is created, we want to tweet something interesting to the big bad world, grab everyone's attention that something really important has happened. Some kind of catchy phrase would be nice. I use the text "Yet another blog entry" followed by the entry title followed by a url you can click on if interested.

Nowadays, since tweets are deemed short and to the point, rather than use the complete url, which can get quite long, we want to include a shortened version of the url which fits nicely into the short message. The tinyurl service is the popular choice nowadays, so I will use that.

First of all, you need to have a couple CPAN modules installed, namely Net::Twitter and WWW::Shorten::TinyURL. These are installed in the usual way:

# cpan -i Net::Twitter WWW::Shorten::TinyURL

Net::Twitter is based on Moose meaning that the installation will pull in tons of extra dependencies. If you do not want this and only need to tweet an update, then you probably only want to install the lite version:

# cpan -i Net::Twitter::Lite

Alright, let's get started. At the top of your Perl script blog-tweet.pl include the following CPAN modules:

use DBI;
use WWW::Shorten::TinyURL;
use Net::Twitter::Lite;

Now you want to setup the usual database stuff using your movable type username and password like this:

my $dsn = 'DBI:mysql:<database>:<hostname>';
my $db_user_name = '<user_name>';
my $db_password = '<passwd>';
my $dbh = DBI->connect($dsn, $db_user_name, $db_password);
my $url = 'http://www.<domain_name>.com/';

The database query needs to grab the latest blog record from the mt_entry database where it is a blog entry (entry_class = 'entry') and the entry is published for view (entry_status = 2). This is what it should look like:

my $sth = $dbh->prepare(qq{
    select
        entry_title as 'title',
        entry_basename as 'basename',
        entry_created_on as 'created_on'
    from
        mt_entry 
    where
        entry_status = 2
            and
        entry_class = 'entry'
    order by
        entry_created_on desc
    limit 1
});
$sth->execute();
my $rec = $sth->fetchrow_hashref();

The field formats are:

  • created_on - "yyyy-mm-dd hh:mm:ss"
  • basename - "word_word_word"
  • permalink - "blog_root/yyyy/mm/word-word-word.html"
my $basename = $rec->{basename};
$basename =~ s/_/-/g;
my ($year, $month) =
    $rec->{created_on} =~ /(\d\d\d\d)-(\d\d)-.*/;
my $title = $rec->{title};
$url .= "$year/$month/$basename.html";
my $prev_url = '';

Get the previous url, if possible.

if (open(FH, '<blog-tweet.txt')) {
    # File exists.
    $prev_url = <FH>;
    close FH;
}

If new blog entry created, tweet update.

if ($prev_url ne $url) {
    open(FH, '>tweet-my-blog.txt')
        or die "Can't open 'blog-tweet.txt' file: $!";
    print FH $url;
    close FH;

    my $nt = Net::Twitter::Lite->new(
        username => '<username>',
        password => '<passwd>');

    # Convert longurl to shorter tinyurl.
    my $short_url = makeashorterlink($url);
    my $tweet_message =
        "Yet another blog entry '$title' $short_url";

    # Tweet you Update!
    my $result = eval{ $nt->update($tweet_message) };
    
    if ($@) {
        print "Tweet update: $tweet_message, failed ($@)\n";
    }
    else {
        print "Tweet update: $tweet_message, succeeded\n";
    }
}
else {
    print "No new blog entries yet.\n";
}

Finally, don't forget to cleanup.

$sth->finish();
$dbh->disconnect();

The final step is to create a simple cronjob which will run this script every once in awhile. Since I usually write at most one or two entries a day, I've added a cronjob to run once a day at 16.30 in the afternoon:

# crontab -e
30 16 * * * cd /path/to/cgi/scripts && ./blog-tweet.pl

That's pretty much it, have fun blog tweeting!

4 Comments

I'm curious, did you look at Ian Fenn's MT-Twitter plugin? It seems to do exactly what you are doing. I use it and it works great.

Actually I did and it does look pretty good. However, I was unable to get it installed successfully for some reason. Also, I needed a bit more functionality, like being able to define my own message text and retrying if the twitter update failed.

I guess the most important thing was that this was a good exercise for me to learn more about Net::Twitter, taking my ideas from scratch and creating a more tailor-made solution that others might be interested in using.

As always, all suggestions are welcome, so thanks alot.

Alternatively, you could do what most people do and use TwitterFeed. TwitterFeed will monitor any RSS/Atom feed (like the ones created by MT) and publish a (configurable) message to Twitter when it finds a new entry.

Once again a nice tool, but I prefer more freedom and flexibility to roll my own, tweak it as I like.

Leave a comment

Recent Entries

Clojure one-liner
I am convinced that the new programming language called Clojure has alot of potential and if successful will fundamentally ... »
Trusting yourself
An excellent book that I've been reading is called Management 3.0 by Jurgen Appelo. The book has all kinds ... »
Remembering and then forgetting
There is that last fleeting moment right before you fall asleep when your mind empties of all thought and ... »
Zuma
Being stuck in the middle of a huge traffic jam just south of Amsterdam is no fun, especially when ... »
Running in the cold
Most people of sound mind would find it extremely difficult to understand that inner urge of mine which keeps ... »