Half-Elf on Tech

Thoughts From a Professional Lesbian

Category: How To

  • 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!

  • WordPress Plugin Script

    WordPress Plugin Script

    I don’t like the automated plugin installer. I don’t know why, I just don’t. I have this stupid simple script I use instead. I cleaned it up before posting here. It’s a lot more complicated than my WordPress Upgrade Script because it has to check for the latest release of the plugin via the subversion repository and clean up weird characters (because people write code on Windows, Linux and Mac and everything else!). This is one of the few times I assume that if you don’t specify a version, you probably want the latest and greatest.

    #!/bin/bash
    
    ####################################################################
    # WORDPRESS-PLUGIN.SH - WordPress Plugin Script for BASH SHELL     #
    #                                                                  #
    # This script will download and copy up the specified WordPress    #
    # plugin to the account. By default it gets the latest version,    #
    # but you CAN specify trunk or whatever version you want.          #
    #                                                                  #
    # Author: Mika Epstein                                             #
    # URL: https://halfelf.org/scripts/wordpress-plugin-script/    #
    #                                                                  #
    # Usage: ./wordpress-plugin.sh plugin [version]                    #
    #                                                                  #
    # plugin  == the 'ugly' name of the plugin (i.e. wp-super-cache)   #
    # version == the FULL version number (i.e. 0.1.2)                  #
    #                                                                  #
    # This program is free software; you can redistribute it and/or    #
    # modify it under the terms of the GNU General Public License as   #
    # published by the Free Software Foundation; either version 2 of   #
    # the License, or (at your option) any later version.              #
    #                                                                  #
    # This program is distributed in the hope that it will be useful,  #
    # but WITHOUT ANY WARRANTY; without even the implied warranty of   #
    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    #
    # GNU General Public License for more details.                     #
    #                                                                  #
    ####################################################################
    
    if [ "$1" = "" ]
    then
      echo "EXIT: FAILURE! You didn't specify a plugin name.  Kinda need that."
      echo "Syntax is ./wordpress-plugin.sh plugin [version] "
      exit
    fi
    
    if [ "$2" = "" ]
    then
      # We're getting the readme from the repo and using that to calculate the latest stable release.
      wget -qO $1-readme.txt http://plugins.svn.wordpress.org/$1/trunk/readme.txt
    
      if ! [ -f $1-readme.txt ]
      then
        echo "FAILURE: The plugin is goobered in the WordPress repository, so we can't determine the latest stable release."
    	exit 1
      else
        tr -cd '$2' < $1-readme.txt > $1-readme-tr.txt
        VERSION=.`awk '/Stable/ {print $3}' $1-readme-tr.txt`
        rm $1-readme.txt $1-readme-tr.txt
      fi
    
    else
      # Quick check if someone wants the trunk build with a 'You sure?' 
      # double check.
      if [ "$2" = "trunk" ] # start trunk check
      then
        read -p "Are you sure you want to install the TRUNK version? (y/n) " -n 1
        if [[ ! $REPLY =~ ^[Yy]$ ]]
        then
          echo
    	  echo "You have opted NOT to install the trunk build of $1."
          exit 1
        else
          echo
          VERSION=
        fi
      else
        VERSION=.$2
      fi # end trunk check
    fi
    
    # Download the plugin
    wget http://downloads.wordpress.org/plugin/$1$VERSION.zip
    
    # If the file didn't download, then you probably got the URL wrong. Fail.
    if ! [ -f $1$VERSION.zip ]
    then
      echo "EXIT: FAILURE! Could not download $1$VERSION.zip - Did you get the version and plugin name right?"
      exit
    else
      echo
      unzip -q $1$VERSION.zip
    fi
    
    # This is ONE LAST CHANCE. If you say anything other than yes, then it cleans up.
    read -p "Last chance.  You sure you want to install the plugin $1 v$VERSION for $USER? (y/n) " -n 1
      if [[ ! $REPLY =~ ^[Yy]$ ]]
      then
        rm -rf $1/
        rm $1$VERSION.zip
    	echo
    	echo "EXIT: You have chosen NOT to install WordPress $1 at this time."
    	exit 1
      else
        echo
      fi
    
    # This is a quick check to make the directory if it's not there.
    # Change this if you want to install to a subfolder or whatever.
    if ! [ -d public_html/wp-content/plugins/$1 ]
    then
      mkdir public_html/wp-content/plugins/$1
    fi
    
    # Copy the files up to root public_html
    # Again! Change this if you want to install to a subfolder or whatever.
    cp -r $1/* public_html/wp-content/plugins/$1/
    
    # Post install clean up with a 'I don't know what you did!' error.
    if [ -f $1$VERSION.zip ]
    then
      rm -rf $1/
      rm $1$VERSION.zip
      echo "SUCCESS! You've downloaded the plugin $1 (version $VERSION). Now go activate it!"
    else
      echo "POSSIBLE FAILURE. Could not clean up the files, so there's a chance everything went pear shaped."
      echo "Please review your WordPress plugins and remember: Blame Nacin."
    fi
    
    exit
    
  • WordPress Upgrade Script

    WordPress Upgrade Script

    I don’t like the automated updater. I don’t know why, I just don’t. I have this stupid simple script I use instead. I cleaned it up before posting here. But this is what I use when I want to upgrade my various installs to the latest version, or the nightly build. I didn’t bother to put the svn stuff in here, since the script I use for that is fairly weird and particular to me.

    #!/bin/bash
    
    ####################################################################
    # WORDPRESS.SH - WordPress Upgrade Script for BASH SHELL           #
    #                                                                  #
    # This script will download and copy up WordPress to the account.  #
    # It's pretty simple, with the bare minimum of error checking. So  #
    # be careful.                                                      #
    #                                                                  #
    # Author: Mika Epstein                                             #
    # URL: https://halfelf.org/hacks/wordpress-upgrade-script/     #
    #                                                                  #
    # Usage: ./wordpress.sh version                                    #
    #                                                                  #
    #                                                                  #
    # This program is free software; you can redistribute it and/or    #
    # modify it under the terms of the GNU General Public License as   #
    # published by the Free Software Foundation; either version 2 of   #
    # the License, or (at your option) any later version.              #
    #                                                                  #
    # This program is distributed in the hope that it will be useful,  #
    # but WITHOUT ANY WARRANTY; without even the implied warranty of   #
    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    #
    # GNU General Public License for more details.                     #
    #                                                                  #
    ####################################################################
    
    if [ "$1" = "" ]
    then
      echo "EXIT: FAILURE! Call this as './wordpress.sh VERSION', you nut!"
      exit
    fi
    
    # Quick check if someone wants the nightly build with a 'You sure?' 
    # double check.
    # This sets the URL, as it's different for the nightly builds.
    if [ "$1" = "nightly" ]
    then
      DOMAIN=wordpress.org/nightly-builds
      VERSION=wordpress-latest
     
      read -p "Are you sure you want to install the NIGHTLY build? (y/n) " -n 1
        if [[ ! $REPLY =~ ^[Yy]$ ]]
        then
          echo
    	  echo "You have opted NOT to install the nightly build of WordPress."
          exit 1
        else
    	  echo
        fi
    
    else
      DOMAIN=wordpress.org
      if [ "$1" = "latest" ]
      then
        VERSION=latest
      else
        VERSION=wordpress-$1
      fi
    fi
    
    # Download WordPress
    wget -q http://$DOMAIN/$VERSION.zip
    
    # If the file didn't download, then you probably got the URL wrong. Fail.
    if ! [ -f $VERSION.zip ]
    then
      echo "EXIT: FAILURE! Could not download $VERSION.zip - Did you get the version right?"
      exit
    else
      echo
      unzip -q $VERSION.zip
    fi
    
    # This is ONE LAST CHANCE. If you say anything other than yes, then it cleans up.
    read -p "Last chance.  You sure you want to install WordPress $1 for $USER? (y/n) " -n 1
      if [[ ! $REPLY =~ ^[Yy]$ ]]
      then
        rm -rf wordpress/
        rm $VERSION.zip
    	echo
    	echo "EXIT: You have chosen NOT to install WordPress $1 at this time."
    	exit 1
      else
        echo
      fi
    
    # Get rid of hello dolly and akismet 
    rm -rf wordpress/wp-content/plugins/akismet
    rm wordpress/wp-content/plugins/hello.php
    
    # Copy the files up to root public_html
    # Change this if you want to install to a subfolder or whatever.
    cp -r wordpress/* public_html/
    
    # Post install clean up with a 'I don't know what you did!' error.
    if [ -f $VERSION.zip ]
    then
      rm -rf wordpress/
      rm $VERSION.zip
      echo "SUCCESS! You're on WordPress $1."
    else
      echo "POSSIBLE FAILURE. Could not clean up the files, so there's a chance everything went pear shaped."
      echo "Please review your WordPress install and remember: Blame Nacin."
    fi
    
    exit
    

    The fix to ‘Oh shit, I installed WordPress 2.1 instead of 3.1!’ is to re-run it correctly, by the way. So long as you haven’t logged in to your site, you won’t update the database, so a backout is always a re-run, even in the real world.

  • Unix One Liner – Writing to a file

    Unix One Liner – Writing to a file

    In 2010, I had to log into 100 odd accounts and edit the .profile file so that the line ‘cd ~’ was included. Sounds time consuming, doesn’t it? I couldn’t use a for-loop to log into the accounts, but since they were named ‘test001’ through ‘test100’ and they all had my sudo password saved, it was pretty easy to sort out what I needed. And by easy I mean I pled to Twitter and got stumped on ‘cat’ for a long time until, finally, I wondered if echo worked the way I thought it did.

    It does perplex me that ‘write’ doesn’t. I mean… it should, right? ‘write filename content’ but no. Not so much. And even echo doesn’t format the way I’d expected! It’s

    echo CONTENT >> FILENAME

    Oh Unix, I love you so.

    sudo su - test001
    echo "cd ~" >> .profile
    exit
    

    The trick was remembering that echo … echos. So if I’d use echo cd ~ >> .profile I would have ended up with cd /usr/home/account/ in my .profile, which I didn’t want. The other trick was remembering that the >> part means ‘Add to’ so if the file DID exist (it never did) it would add this to the end on a new line.

    So it only took me 5 minutes instead of the far longer way!

    sudo su - test001
    vi .profile
    a
    cd ~
    [esc]
    ZZ
    exit

    And yes, I did make a for-loop ‘for test001 through test100…’ though this ended up not working as well as I wanted it to, when I found some of the older accounts were named tst099 and test_100 for some reason. Ahh, scripting. You work so well when everyone else is consistent.

  • Filtering Emails via cPanel

    Filtering Emails via cPanel

    Sometimes you get emails that you just don’t want to read. Maybe it’s a person you like who’s driving you batshit. Maybe it’s someone who’s actually harassing you. If you use Gmail, you can filter emails and they go into a folder or your trash-bin, and you don’t have to read them ever again! If you self-host, though, the steps are a little different.

    The first thing I do is make a new folder to hold these emails. I have some filters set up to auto-turf spam and viruses. But for people who harass me, I like to save their emails for review and reporting. Yes, I report them to the authorities when needed, and I save them so I can have their IP and routing info. Because of that, I have a built in folder on my email accounts for ‘Harassment.’

    Obviously you can teach your email client how to do this, and there are tutorials galore about how to get Mail.app, Thunderbird and Outlook to filter emails. But me, I like to have the filter happen before I open my email box, so I don’t have to even consider it.

    Once you’ve made the folder, go into cPanel and click on User Level Filtering. This allows you to make a filter per-email on your server. If you want to filter all emails for all emails on your account, there’s Account Level Filtering, which I use for the aforementioned spammers and virus senders. Also for all mail in non-English encoding. I’m hopelessly mono-lingual.

    Next, select the account you want to add the filter for. This one is pretty obvious, no?

    This screen will show you all your filters. I happen to have an existing one to filter someone’s constant requests for information. Since we want to create a new filter, click the Create a new Filter button.

    Now we’re getting started! Give the filter a useful name. I used ‘Harassment’ since I’m going to be adding in all the emails who harass me, and just dump them into one folder. The email I’ve added is one someone made up. It’s not real so don’t bother spamming it. There are a lot more options under the Rules section, but this one is pretty straightforward for me. I want all emails from jorjafox@gmail.com to be dumped into Harassment.

    Actions, which is just below the rules, is where you decide what happens. You can have multiple actions, the default of which is to discard the email. This means it gets deleted. You never see it. I don’t want this, I want to Deliver to Folder

    Once I’ve picked the action, I have to actually tell it which folder. This is where I pick Harassment.

    Put together, the whole thing looks like this:

    There are a lot more actions you can perform. One of them is NOT ‘Mark as Read’, which annoys me sometimes since my mail app will show my unread count, and I like to keep that low. I have no more than 10 emails, total, in my many inboxes at any one point in time, and the only ones unread are ones I have yet to answer or action (i.e. I have to do something before the email’s ‘done’). You can, however, add as many emails as you want. Just make sure you use OR and not AND for the emails.

    Once you’re happy with your settings, click activate and you’re done! Now that annoying person will be chump-dumped into a folder and stop cluttering your inbox!