Category: Geek Stuff

  • MODS with the boys

    We took our boys to the Fort Lauderdale Museum of Discovery and Science over the weekend. They both had an absolute blast and we highly recommend the museum for kids of all ages 🙂

  • I Open Sourced My Twenty Sixteen Child Theme

    Today, I open sourced my Twenty Sixteen child theme. It includes an empty resume page template and a clean travel shortcode that uses Google Maps. You’ll need to check out the source code for usage, but it’s very simple 🙂

    This child theme is meant to be only very small improvements to the WordPress Twenty Sixteen default theme, but they were improvements that I felt were very valuable.

    View the code: https://github.com/rcoll/twentysixteen-rcollier

    Pull requests are welcome.

  • Tuesdays at WPCOM

    I’ve now worked support for WordPress.com for every day of the week, and Tuesdays seem to be the most difficult.

    Maybe it’s the crushing hangover from Sunday night still bringing me down, or maybe it’s that our users got to work on Monday and started submitting more difficult tickets. I’ll assume the latter.

    I know, I know – I should be a responsible adult and stay away from behavior that could cause such a hangover. But here’s the thing – my wife and I went out and partied, which we have only done a handful of times in our relationship. Between careers, kids, careers, general life tasks, and careers, we don’t get that opportunity often. So when the chance arose, we jumped head first. And we had an amazing time. So was it worth it? Absolutely. Do I regret it? Hell no. Thanks to Automattic for being a part of making that possible.

    As for the Tuesday blues, I’ll make it through. I’ve set a personal record for ticket volume already. Perhaps difficulty, productivity, and chaos really do coexist in perfect harmony.

  • WordPress Multisite on CentOS 7.2, Nginx 1.9.5, PHP7, batcache, and HTTP/2

    It was time for an overhaul of my go-to WordPress stack. For a long while, I’ve been running PHP 5.4 on CentOS 6 with Varnish. Technical times are changing and it was overdue for an upgrade; so I bring you this!

    My first impression of PHP 7 – WOW, Just WOW! The speed increase is phenomenal compared to PHP 5. It seems like the browser is no longer waiting on the server, but the other way around. WordPress is so fast on this setup that it feels like a native app. Perhaps even better/faster than a native app. I almost can’t believe it.

    As for HTTP/2 – supposedly this new protocol is faster, but I don’t really see a huge difference with it on versus off. I’m sure its advantages will become apparent over time when we start to integrate more technology into our websites.

    I decided to go away from varnish since I’m now running Batcache. Previously, I was a fan of W3TC, but have migrated away from that plugin (it’s become a bloated/buymebuyme nightmare now). This means you lose support for gzip, browser caching, and CDN settings from within WordPress, but you don’t really need to worry about those settings after they’re manually set up in Nginx anyways. Anyways, Batcache versus Varnish – I don’t really see a huge difference. If anything, the cache invalidation is much easier with Batcache. It’s a set-it-and-forget-it type of system and it “just works”.

    On one of my production machines running this stack, I show load averages dropping from 3-4 down to less than 1. This is on a 16-core server, so that’s a significant performance gain. Again – I almost can’t believe it, but the numbers speak for themselves. As for memory usage, I don’t see much difference, but everything looks good and clean.

    Specifications

    Prerequisites

    sudo yum update # update the system
    sudo iptables -F # Flush iptables - we'll rebuild later
    sudo yum install epel-release # Install EPEL repo
    sudo yum install https://mirror.webtatic.com/yum/el7/webtatic-release.rpm
    sudo yum install zlib-devel make gcc

    Now, download the latest nginx source to a convenient location and compile it.

    The Nginx Build

    ./configure \
    --user=nginx \
    --group=nginx \
    --prefix=/etc/nginx \
    --sbin-path=/usr/sbin/nginx \
    --conf-path=/etc/nginx/nginx.conf \
    --pid-path=/var/run/nginx.pid \
    --lock-path=/var/run/nginx.lock \
    --error-log-path=/var/log/nginx/error.log \
    --http-log-path=/var/log/nginx/access.log \
    --with-http_gzip_static_module \
    --with-http_stub_status_module \
    --with-http_ssl_module \
    --with-pcre \
    --with-file-aio \
    --with-http_realip_module \
    --with-http_v2_module \
    --without-http_scgi_module \
    --without-http_uwsgi_module

    Then, of course, make and make install and nginx should compile. You can test this with /usr/sbin/nginx -c /etc/nginx/nginx.conf. You’ll want to kill that process after you test it.

    Next, you need to be able to start/stop/reload nginx. Add this script to /etc/init.d/nginx:

    #!/bin/sh
    #
    # nginx - this script starts and stops the nginx daemon
    #
    # chkconfig:   - 85 15
    # description:  NGINX is an HTTP(S) server, HTTP(S) reverse \
    #               proxy and IMAP/POP3 proxy server
    # processname: nginx
    # config:      /etc/nginx/nginx.conf
    # config:      /etc/sysconfig/nginx
    # pidfile:     /var/run/nginx.pid
    
    # Source function library.
    . /etc/rc.d/init.d/functions
    
    # Source networking configuration.
    . /etc/sysconfig/network
    
    # Check that networking is up.
    [ "$NETWORKING" = "no" ] & exit 0
    
    nginx="/usr/sbin/nginx"
    prog=$(basename $nginx)
    
    NGINX_CONF_FILE="/etc/nginx/nginx.conf"
    
    [ -f /etc/sysconfig/nginx ] & . /etc/sysconfig/nginx
    
    lockfile=/var/lock/subsys/nginx
    
    make_dirs() {
       # make required directories
       user=`$nginx -V 2>&1 | grep "configure arguments:" | sed 's/[^*]*--user=\([^ ]*\).*/\1/g' -`
       if [ -z "`grep $user /etc/passwd`" ]; then
           useradd -M -s /bin/nologin $user
       fi
       options=`$nginx -V 2>&1 | grep 'configure arguments:'`
       for opt in $options; do
           if [ `echo $opt | grep '.*-temp-path'` ]; then
               value=`echo $opt | cut -d "=" -f 2`
               if [ ! -d "$value" ]; then
                   # echo "creating" $value
                   mkdir -p $value & chown -R $user $value
               fi
           fi
       done
    }
    
    start() {
        [ -x $nginx ] || exit 5
        [ -f $NGINX_CONF_FILE ] || exit 6
        make_dirs
        echo -n $"Starting $prog: "
        daemon $nginx -c $NGINX_CONF_FILE
        retval=$?
        echo
        [ $retval -eq 0 ] & touch $lockfile
        return $retval
    }
    
    stop() {
        echo -n $"Stopping $prog: "
        killproc $prog -QUIT
        retval=$?
        echo
        [ $retval -eq 0 ] & rm -f $lockfile
        return $retval
    }
    
    restart() {
        configtest || return $?
        stop
        sleep 1
        start
    }
    
    reload() {
        configtest || return $?
        echo -n $"Reloading $prog: "
        killproc $nginx -HUP
        RETVAL=$?
        echo
    }
    
    force_reload() {
        restart
    }
    
    configtest() {
      $nginx -t -c $NGINX_CONF_FILE
    }
    
    rh_status() {
        status $prog
    }
    
    rh_status_q() {
        rh_status > /dev/null 2>&1
    }
    
    case "$1" in
        start)
            rh_status_q & exit 0
            $1
            ;;
        stop)
            rh_status_q || exit 0
            $1
            ;;
        restart|configtest)
            $1
            ;;
        reload)
            rh_status_q || exit 7
            $1
            ;;
        force-reload)
            force_reload
            ;;
        status)
            rh_status
            ;;
        condrestart|try-restart)
            rh_status_q || exit 0
                ;;
        *)
            echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"
            exit 2
    esac

    Okay, the hard part is over with. If you can start and stop nginx with service nginx start and service nginx stop, then you’re good to go. Time to have some fun. Let’s install some more software.

    # Install memcached
    sudo yum install -y memcached
    
    # Install mariadb (mysql)
    sudo yum install -y mariadb-server mariadb-client
    
    # Install PHP 7
    sudo yum install -y php70w php70w-fpm php70w-mysql php70w-opcache php70w-devel php70w-gd php70w-mbstring php70w-xml
    
    # Install ntp, set timezone, set date
    sudo yum install -y ntp ntpdate
    sudo mv /etc/localtime /etc/localtime.bk
    sudo ln -s /usr/share/zoneinfo/America/New_York /etc/localtime
    sudo ntpdate pool.ntp.org
    
    # Install some other tools that you'll want to have ready
    sudo yum install -y vim htop screen

    Configure Nginx

    Now you’ll want to set up your nginx.conf and conf.d/* files how you want them. Some key things to remember:

    • If you want to use HTTP/2, you’ll need SSL. If you want free (and easy) SSL certificates, check out LetsEncrypt.
    • On WordPress Multisite (subdomain installs), you’ll want a certificate for each subdomain and each mapped domain. That means you will need a minimum of two certificates for your root domain, and two certificates for each subsequent mapped domain. Each *.yourdomain.com subdomain requires it’s own certificate, and each domain you map to a subdomain requires yet another.

    The default nginx.conf is probably okay, though nginx may complain about one or more listen directives (if so, just change whatever it says to change). Here a sample default.conf that includes WordPress rewrite support, concatenation, browser caching, and gzip:

    server {
    	listen 80;
    	server_name {{ actual_hostname }};
    
    	root {{ actual_webroot }};
    	index index.php index.html index.htm;
    
    	client_max_body_size 100M;
    
    	gzip on;
    	gzip_disable "msie6";
    	gzip_vary on;
    	gzip_proxied any;
    	gzip_comp_level 6;
    	gzip_buffers 16 8k;
    	gzip_http_version 1.1;
    	gzip_types text/plain application/json application/x-javascript application/xml application/xml+rss text/javascript;
    
    	error_page 404 /404.html;
    	location /404.html {
    		root {{ actual_webroot }};
    	}
    
    	error_page 500 502 503 504 /50x.html;
    	location = /50x.html {
    		root {{ actual_webroot }};
    	}
    
    	location / {
    		try_files $uri $uri/ /index.php?q=$uri&$args;
    	}
    
    	# Allow access to script concatenation engine
    	location /_static/ {
    		fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
    		include /etc/nginx/fastcgi_params;
    		fastcgi_param SCRIPT_FILENAME $document_root/wp-content/mu-plugins/http-concat/ngx-http-concat.php;
    		include fastcgi_params;
    	}
    
    	# Browser cache static assets and do not access log
    	location ~* \.(jpg|jpeg|gif|png|css|js|ico|svg)$ {
    		expires max;
    		access_log off;
    		log_not_found off;
    	}
    
    	# Block access to PHP files in uploads
    	location ~* /(?:uploads|files)/.*\.php$ {
    		deny all;
    	}
    
    	# Whitelist IPs for nginx status
    	location /nginx_status {
    		stub_status on;
    		access_log off;
    		allow 127.0.0.1;
    		deny all;
    	}
    
    	# All PHP files
    	location ~ \.php$ {
    		try_files $uri $uri/ /index.php?q=$uri&$args;
    		fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
    		fastcgi_index index.php;
    		fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    		include fastcgi_params;
    	}
    }

    This file came from my ansible install.yml so you’ll need to make a few obvious string replacements. You’ll also want to duplicate this into ssl.conf and modify accordingly to accommodate your domain(s) and SSL requirements. Activating HTTP/2 is as easy as modifying the listen directive to reflect listen 443 ssl http2;.

    There are a ton of other configuration items to address and tweak, such as php.ini and /etc/php-fpm.d/www.conf, and don’t forget to set up /etc/sysconfig/memcached… but I’ll leave those fine details to you. Remember to build your firewall also.

    As always, if you need pointers, feel free to hit me up in the comments.

  • Create WordPress Test Users From Breaking Bad Characters

    Obviously, you should only use this in development environments. This is used to create an abundance of test authors (named after popular TV show characters) in WordPress for testing.

    Run this from bash terminal:

    wp user create wwhite wwhite@breakingbad.com --role=author --display_name="Walter White" --first_name="Walter" --last_name="White" --send-email=false
    wp user create swhite swhite@breakingbad.com --role=author --display_name="Skyler White" --first_name="Skyler" --last_name="White" --send-email=false
    wp user create fwhite fwhite@breakingbad.com --role=author --display_name="Flynn White" --first_name="Flynn" --last_name="White" --send-email=false
    wp user create hwhite hwhite@breakingbad.com --role=author --display_name="Holly White" --first_name="Holly" --last_name="White" --send-email=false
    wp user create jpinkman jpinkman@breakingbad.com --role=author --display_name="Jesse Pinkman" --first_name="Jesse" --last_name="Pinkman" --send-email=false
    wp user create gfring gfring@breakingbad.com --role=author --display_name="Gustavo Fring" --first_name="Gustavo" --last_name="Fring" --send-email=false
    wp user create hschrader hschrader@breakingbad.com --role=author --display_name="Hank Schrader" --first_name="Hank" --last_name="Schrader" --send-email=false
    wp user create mschrader mschrader@breakingbad.com --role=author --display_name="Marie Schrader" --first_name="Marie" --last_name="Schrader" --send-email=false
    wp user create sgoodman sgoodman@breakingbad.com --role=author --display_name="Saul Goodman" --first_name="Saul" --last_name="Goodman" --send-email=false
    wp user create mehrmantraut mehrmantraut@breakingbad.com --role=author --display_name="Mike Ehrmantraut" --first_name="Mike" --last_name="Ehrmantraut" --send-email=false
    wp user create lrodarte-quayle lrodarte-quayle@breakingbad.com --role=author --display_name="Lydia Rodarte-Quayle" --first_name="Lydia" --last_name="Rodarte-Quayle" --send-email=false
    wp user create talquist talquist@breakingbad.com --role=author --display_name="Todd Alquist" --first_name="Todd" --last_name="Alquist" --send-email=false
    wp user create sgomez sgomez@breakingbad.com --role=author --display_name="Steve Gomez" --first_name="Steve" --last_name="Gomez" --send-email=false
    wp user create tsalamanca tsalamanca@breakingbad.com --role=author --display_name="Tuco Salamanca" --first_name="Tuco" --last_name="Salamanca" --send-email=false
    wp user create tbeneke tbeneke@breakingbad.com --role=author --display_name="Ted Beneke" --first_name="Ted" --last_name="Beneke" --send-email=false
    wp user create bwolynetz bwolynetz@breakingbad.com --role=author --display_name="Bogdan Wolynetz" --first_name="Bogdan" --last_name="Wolynetz" --send-email=false
    wp user create gboetticher gboetticher@breakingbad.com --role=author --display_name="Gale Boetticher" --first_name="Gale" --last_name="Boetticher" --send-email=false
    wp user create tkitt tkitt@breakingbad.com --role=author --display_name="Tyrus Kitt" --first_name="Tyrus" --last_name="Kitt" --send-email=false
    wp user create deladio deladio@breakingbad.com --role=author --display_name="Don Eladio" --first_name="Don" --last_name="Eladio" --send-email=false
    wp user create jbolsa jbolsa@breakingbad.com --role=author --display_name="Juan Bolsa" --first_name="Juan" --last_name="Bolsa" --send-email=false
    wp user create hsalamanca hsalamanca@breakingbad.com --role=author --display_name="Hector Salamanca" --first_name="Hector" --last_name="Salamanca" --send-email=false
    wp user create lsalamanca lsalamanca@breakingbad.com --role=author --display_name="Leonel Salamanca" --first_name="Leonel" --last_name="Salamanca" --send-email=false
    wp user create msalamanca msalamanca@breakingbad.com --role=author --display_name="Marco Salamanca" --first_name="Marco" --last_name="Salamanca" --send-email=false
    wp user create acantillo acantillo@breakingbad.com --role=author --display_name="Andrea Cantillo" --first_name="Andrea" --last_name="Cantillo" --send-email=false
    wp user create bcantillo bcantillo@breakingbad.com --role=author --display_name="Brock Cantillo" --first_name="Brock" --last_name="Cantillo" --send-email=false
    wp user create jmargolis jmargolis@breakingbad.com --role=author --display_name="Jane Margolis" --first_name="Jane" --last_name="Margolis" --send-email=false
    wp user create dmargolis dmargolis@breakingbad.com --role=author --display_name="Donald Margolis" --first_name="Donald" --last_name="Margolis" --send-email=false
    wp user create bmayhew bmayhew@breakingbad.com --role=author --display_name="Brandon Mayhew" --first_name="Brandon" --last_name="Mayhew" --send-email=false
    wp user create cortega cortega@breakingbad.com --role=author --display_name="Christian Ortega" --first_name="Christian" --last_name="Ortega" --send-email=false
    wp user create spete spete@breakingbad.com --role=author --display_name="Skinny Pete" --first_name="Skinny" --last_name="Pete" --send-email=false
    wp user create apinkman apinkman@breakingbad.com --role=author --display_name="Adam Pinkman" --first_name="Adam" --last_name="Pinkman" --send-email=false
    wp user create jpinkman jpinkman@breakingbad.com --role=author --display_name="Jake Pinkman" --first_name="Jake" --last_name="Pinkman" --send-email=false
    wp user create hbabineaux hbabineaux@breakingbad.com --role=author --display_name="Huell Babineaux" --first_name="Huell" --last_name="Babineaux" --send-email=false
    wp user create pkuby pkuby@breakingbad.com --role=author --display_name="Patrick Kuby" --first_name="Patrick" --last_name="Kuby" --send-email=false
    wp user create harchilleya harchilleya@breakingbad.com --role=author --display_name="Hugo Archilleya" --first_name="Hugo" --last_name="Archilleya" --send-email=false
    wp user create lcorbett lcorbett@breakingbad.com --role=author --display_name="Louis Corbett" --first_name="Louis" --last_name="Corbett" --send-email=false
    wp user create cmolina cmolina@breakingbad.com --role=author --display_name="Carmen Molina" --first_name="Carmen" --last_name="Molina" --send-email=false
    wp user create gschwartz gschwartz@breakingbad.com --role=author --display_name="Gretchen Schwartz" --first_name="Gretchen" --last_name="Schwartz" --send-email=false
    wp user create eschwartz eschwartz@breakingbad.com --role=author --display_name="Elliott Schwartz" --first_name="Elliott" --last_name="Schwartz" --send-email=false
    wp user create dsharp dsharp@breakingbad.com --role=author --display_name="Drew Sharp" --first_name="Drew" --last_name="Sharp" --send-email=false
    wp user create jwelker jwelker@breakingbad.com --role=author --display_name="Jack Welker" --first_name="Jack" --last_name="Welker" --send-email=false
    wp user create dmolina dmolina@breakingbad.com --role=author --display_name="Domingo Molina" --first_name="Domingo" --last_name="Molina" --send-email=false
    wp user create ekoyama ekoyama@breakingbad.com --role=author --display_name="Emilio Koyama" --first_name="Emilio" --last_name="Koyama" --send-email=false
    wp user create dwachsberger dwachsberger@breakingbad.com --role=author --display_name="Dan Wachsberger" --first_name="Dan" --last_name="Wachsberger" --send-email=false
    wp user create dmarkowski dmarkowski@breakingbad.com --role=author --display_name="Dennis Markowski" --first_name="Dennis" --last_name="Markowski" --send-email=false
    wp user create bgoodman bgoodman@breakingbad.com --role=author --display_name="Barry Goodman" --first_name="Barry" --last_name="Goodman" --send-email=false
    wp user create rforenall rforenall@breakingbad.com --role=author --display_name="Ron Forenall" --first_name="Ron" --last_name="Forenall" --send-email=false
    wp user create dchow dchow@breakingbad.com --role=author --display_name="Duane Chow" --first_name="Duane" --last_name="Chow" --send-email=false
    wp user create marciniega marciniega@breakingbad.com --role=author --display_name="Maximino Arciniega" --first_name="Maximino" --last_name="Arciniega" --send-email=false
    wp user create troberts troberts@breakingbad.com --role=author --display_name="Tim Roberts" --first_name="Tim" --last_name="Roberts" --send-email=false
    wp user create gmerkert gmerkert@breakingbad.com --role=author --display_name="George Merkert" --first_name="George" --last_name="Merkert" --send-email=false

    This is also available on GitHub.

    For extra credit, here is one for Prison Break characters:

    wp user create mscofield mscofield@prisonbreak.com --role=author --display_name="Michael Scofield" --first_name="Michael" --last_name="Scofield" --send-email=false
    wp user create lburrows lburrows@prisonbreak.com --role=author --display_name="Lincoln Burrows" --first_name="Lincoln" --last_name="Burrows" --send-email=false
    wp user create vdonovan vdonovan@prisonbreak.com --role=author --display_name="Veronica Donovan" --first_name="Veronica" --last_name="Donovan" --send-email=false
    wp user create lburrows lburrows@prisonbreak.com --role=author --display_name="LJ Burrows" --first_name="LJ" --last_name="Burrows" --send-email=false
    wp user create fsucre fsucre@prisonbreak.com --role=author --display_name="Fernando Sucre" --first_name="Fernando" --last_name="Sucre" --send-email=false
    wp user create tbagwell tbagwell@prisonbreak.com --role=author --display_name="Theodore Bagwell" --first_name="Theodore" --last_name="Bagwell" --send-email=false
    wp user create jabruzzi jabruzzi@prisonbreak.com --role=author --display_name="John Abruzzi" --first_name="John" --last_name="Abruzzi" --send-email=false
    wp user create bbellick bbellick@prisonbreak.com --role=author --display_name="Brad Bellick" --first_name="Brad" --last_name="Bellick" --send-email=false
    wp user create stancredi stancredi@prisonbreak.com --role=author --display_name="Sara Tancredi" --first_name="Sara" --last_name="Tancredi" --send-email=false
    wp user create pkellerman pkellerman@prisonbreak.com --role=author --display_name="Paul Kellerman" --first_name="Paul" --last_name="Kellerman" --send-email=false
    wp user create amahone amahone@prisonbreak.com --role=author --display_name="Alexander Mahone" --first_name="Alexander" --last_name="Mahone" --send-email=false
    wp user create jwhistler jwhistler@prisonbreak.com --role=author --display_name="James Whistler" --first_name="James" --last_name="Whistler" --send-email=false
    wp user create nst.john nst.john@prisonbreak.com --role=author --display_name="Norman St.John" --first_name="Norman" --last_name="St.John" --send-email=false
    wp user create slugo slugo@prisonbreak.com --role=author --display_name="Sofia Lugo" --first_name="Sofia" --last_name="Lugo" --send-email=false
    wp user create gmorgan gmorgan@prisonbreak.com --role=author --display_name="Gretchen Morgan" --first_name="Gretchen" --last_name="Morgan" --send-email=false
    wp user create dself dself@prisonbreak.com --role=author --display_name="Donald Self" --first_name="Donald" --last_name="Self" --send-email=false
    wp user create jkrantz jkrantz@prisonbreak.com --role=author --display_name="Jonathan Krantz" --first_name="Jonathan" --last_name="Krantz" --send-email=false
    wp user create bkim bkim@prisonbreak.com --role=author --display_name="Bill Kim" --first_name="Bill" --last_name="Kim" --send-email=false
    wp user create creynolds creynolds@prisonbreak.com --role=author --display_name="Caroline Reynolds" --first_name="Caroline" --last_name="Reynolds" --send-email=false
    wp user create cscofield cscofield@prisonbreak.com --role=author --display_name="Christina Scofield" --first_name="Christina" --last_name="Scofield" --send-email=false
    wp user create dapolskis dapolskis@prisonbreak.com --role=author --display_name="David Apolskis" --first_name="David" --last_name="Apolskis" --send-email=false
    wp user create cwestmoreland cwestmoreland@prisonbreak.com --role=author --display_name="Charles Westmoreland" --first_name="Charles" --last_name="Westmoreland" --send-email=false
    wp user create cpatoshik cpatoshik@prisonbreak.com --role=author --display_name="Charles Patoshik" --first_name="Charles" --last_name="Patoshik" --send-email=false
    wp user create gfiorello gfiorello@prisonbreak.com --role=author --display_name="Gus Fiorello" --first_name="Gus" --last_name="Fiorello" --send-email=false
    wp user create msanchez msanchez@prisonbreak.com --role=author --display_name="Manche Sanchez" --first_name="Manche" --last_name="Sanchez" --send-email=false
    wp user create abalz-johnson abalz-johnson@prisonbreak.com --role=author --display_name="Avocado Balz-Johnson" --first_name="Avocado" --last_name="Balz-Johnson" --send-email=false
    wp user create shoffner shoffner@prisonbreak.com --role=author --display_name="Seth Hoffner" --first_name="Seth" --last_name="Hoffner" --send-email=false
    wp user create ctrokey ctrokey@prisonbreak.com --role=author --display_name="Christopher Trokey" --first_name="Christopher" --last_name="Trokey" --send-email=false
    wp user create jbuchanon jbuchanon@prisonbreak.com --role=author --display_name="Jason Buchanon" --first_name="Jason" --last_name="Buchanon" --send-email=false
    wp user create hpope hpope@prisonbreak.com --role=author --display_name="Henry Pope" --first_name="Henry" --last_name="Pope" --send-email=false
    wp user create epavelka epavelka@prisonbreak.com --role=author --display_name="Ed Pavelka" --first_name="Ed" --last_name="Pavelka" --send-email=false
    wp user create rgeary rgeary@prisonbreak.com --role=author --display_name="Roy Geary" --first_name="Roy" --last_name="Geary" --send-email=false
    wp user create lpatterson lpatterson@prisonbreak.com --role=author --display_name="Louis Patterson" --first_name="Louis" --last_name="Patterson" --send-email=false
    wp user create kstolte kstolte@prisonbreak.com --role=author --display_name="Keith Stolte" --first_name="Keith" --last_name="Stolte" --send-email=false
    wp user create rgreen rgreen@prisonbreak.com --role=author --display_name="Rizzo Green" --first_name="Rizzo" --last_name="Green" --send-email=false
    wp user create mandrews mandrews@prisonbreak.com --role=author --display_name="Mack Andrews" --first_name="Mack" --last_name="Andrews" --send-email=false
    wp user create thudson thudson@prisonbreak.com --role=author --display_name="Tyler Hudson" --first_name="Tyler" --last_name="Hudson" --send-email=false
    wp user create kwelch kwelch@prisonbreak.com --role=author --display_name="Katie Welch" --first_name="Katie" --last_name="Welch" --send-email=false
    wp user create ksklar ksklar@prisonbreak.com --role=author --display_name="Kenny Sklar" --first_name="Kenny" --last_name="Sklar" --send-email=false
    wp user create nsavrinn nsavrinn@prisonbreak.com --role=author --display_name="Nick Savrinn" --first_name="Nick" --last_name="Savrinn" --send-email=false
    wp user create sabruzzi sabruzzi@prisonbreak.com --role=author --display_name="Sylvia Abruzzi" --first_name="Sylvia" --last_name="Abruzzi" --send-email=false
    wp user create havila havila@prisonbreak.com --role=author --display_name="Hector Avila" --first_name="Hector" --last_name="Avila" --send-email=false
    wp user create dbelle dbelle@prisonbreak.com --role=author --display_name="Debra Belle" --first_name="Debra" --last_name="Belle" --send-email=false
    wp user create pcordero pcordero@prisonbreak.com --role=author --display_name="Petey Cordero" --first_name="Petey" --last_name="Cordero" --send-email=false
    wp user create mdelgado mdelgado@prisonbreak.com --role=author --display_name="Maricruz Delgado" --first_name="Maricruz" --last_name="Delgado" --send-email=false
    wp user create tdelgado tdelgado@prisonbreak.com --role=author --display_name="Theresa Delgado" --first_name="Theresa" --last_name="Delgado" --send-email=false
    wp user create pfalzone pfalzone@prisonbreak.com --role=author --display_name="Philly Falzone" --first_name="Philly" --last_name="Falzone" --send-email=false
    wp user create ofibonacci ofibonacci@prisonbreak.com --role=author --display_name="Otto Fibonacci" --first_name="Otto" --last_name="Fibonacci" --send-email=false
    wp user create dfranklin dfranklin@prisonbreak.com --role=author --display_name="Dede Franklin" --first_name="Dede" --last_name="Franklin" --send-email=false
    wp user create kfranklin kfranklin@prisonbreak.com --role=author --display_name="Kacee Franklin" --first_name="Kacee" --last_name="Franklin" --send-email=false
    wp user create shollander shollander@prisonbreak.com --role=author --display_name="Susan Hollander" --first_name="Susan" --last_name="Hollander" --send-email=false
    wp user create dmorgan dmorgan@prisonbreak.com --role=author --display_name="Darius Morgan" --first_name="Darius" --last_name="Morgan" --send-email=false
    wp user create arix arix@prisonbreak.com --role=author --display_name="Adrian Rix" --first_name="Adrian" --last_name="Rix" --send-email=false
    wp user create lrix lrix@prisonbreak.com --role=author --display_name="Lisa Rix" --first_name="Lisa" --last_name="Rix" --send-email=false
    wp user create gsmallhouse gsmallhouse@prisonbreak.com --role=author --display_name="Gavin Smallhouse" --first_name="Gavin" --last_name="Smallhouse" --send-email=false
    wp user create dsweeney dsweeney@prisonbreak.com --role=author --display_name="Derek Sweeney" --first_name="Derek" --last_name="Sweeney" --send-email=false
    wp user create nvolek nvolek@prisonbreak.com --role=author --display_name="Nika Volek" --first_name="Nika" --last_name="Volek" --send-email=false
    wp user create rglenn rglenn@prisonbreak.com --role=author --display_name="Roland Glenn" --first_name="Roland" --last_name="Glenn" --send-email=false
    wp user create flang flang@prisonbreak.com --role=author --display_name="Felicia Lang" --first_name="Felicia" --last_name="Lang" --send-email=false
    wp user create mwheeler mwheeler@prisonbreak.com --role=author --display_name="Mark Wheeler" --first_name="Mark" --last_name="Wheeler" --send-email=false

    Again, available on GitHub.

  • Truncate a WordPress Database To X-Number of Posts

    I regularly work with huge MySQL database files (10G-100G) so making copies and importing them locally for use in VVV is extremely cumbersome (at best). Here are some MySQL statements that allow you to truncate all but the most recent 1000 posts in your WordPress database. These are useful because they allow you to truncate the database to a manageable size before copying to your local environment or development server. Unless you have something unusual, these statements should retain all post-to-postmeta associations, comment-to-post associations, and term-to-post associations.

    WARNING: DO NOT run these on your production database. You must make a copy of the whole database first and then run these statements on the copy. You have been warned!

    Delete all but the most recent 1000 posts:

    DELETE FROM wp_posts WHERE ID NOT IN ( SELECT ID FROM ( SELECT ID FROM wp_posts WHERE post_type="post" AND post_status="publish" ORDER BY ID DESC LIMIT 1000 ) foo );

    Delete all post meta that is not associated with the remaining posts:

    DELETE FROM wp_postmeta WHERE post_id NOT IN ( SELECT ID FROM ( SELECT ID FROM wp_posts ) foo );

    Delete all comments that are not associated with a remaining post:

    DELETE FROM wp_comments WHERE comment_post_ID NOT IN ( SELECT ID FROM ( SELECT ID FROM wp_posts ) foo );

    Delete all comment meta that is not associated with a remaining post:

    DELETE FROM wp_commentmeta WHERE comment_ID NOT IN ( SELECT comment_ID FROM ( SELECT comment_ID FROM wp_comments ) foo );

    Delete term relationships that don’t associate to a remaining post:

    DELETE FROM wp_term_relationships WHERE object_id NOT IN ( SELECT ID FROM ( SELECT ID FROM wp_posts ) foo );

    Delete terms that are no longer related to an existing post:

    DELETE FROM wp_terms WHERE term_id NOT IN ( SELECT term_taxonomy_id FROM ( SELECT term_taxonomy_id FROM wp_term_relationships ) foo );

    As an added bonus, delete transients from the options table:

    DELETE FROM wp_options WHERE option_name like '%_transient_%';

    And here’s the whole thing in one shot – script it in if you wish:

    DELETE FROM wp_posts WHERE ID NOT IN ( SELECT ID FROM ( SELECT ID FROM wp_posts WHERE post_type="post" AND post_status="publish" ORDER BY ID DESC LIMIT 1000 ) foo );
    DELETE FROM wp_postmeta WHERE post_id NOT IN ( SELECT ID FROM ( SELECT ID FROM wp_posts ) foo );
    DELETE FROM wp_comments WHERE comment_post_ID NOT IN ( SELECT ID FROM ( SELECT ID FROM wp_posts ) foo );
    DELETE FROM wp_commentmeta WHERE comment_ID NOT IN ( SELECT comment_ID FROM ( SELECT comment_ID FROM wp_comments ) foo );
    DELETE FROM wp_term_relationships WHERE object_id NOT IN ( SELECT ID FROM ( SELECT ID FROM wp_posts ) foo );
    DELETE FROM wp_terms WHERE term_id NOT IN ( SELECT term_taxonomy_id FROM ( SELECT term_taxonomy_id FROM wp_term_relationships ) foo );
    DELETE FROM wp_options WHERE option_name like '%_transient_%';
  • Easy Automatic Facebook Share Counts (Fully Javascript)

    Drop this little gem in your site’s header:

    <script>
    function numberFormat(x) {
    	return x.toString().replace(/B(?=(d{3})+(?!d))/g, ',');
    }
    
    jQuery(document).ready(function($){
    	$('.trigger_facebook_count').each(function(){
    		var url = $(this).attr('data-url');
    		var that = $(this);
    
    		$.get('http://graph.facebook.com/' + url, function(data) {
    			that.html(numberFormat(data.shares));
    		});	
    	});
    });
    </script>
    

    Then, add elements to your page like so:

    <div class="trigger_facebook_count" data-url="http://bossip.com"></div>

    Remember to change the data-url to whatever URL you are referencing, and viola! You’re done.

  • Web Server iptables Script

    Here is an iptables script to set up a solid firewall on a CentOS web server. Remember to change the ip address on line 26 with your IP address, or you will lock yourself out of your own server!

    #!/bin/bash
    
    # Backup current iptables rules
    iptables-save > /etc/sysconfig/iptables-previous
    
    # Flush tables
    iptables -F
    
    # Block null packets
    iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP
    
    # Reject syn-flood attacks
    iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP
    
    # Reject XMAS packets
    iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP
    
    # Allow specific traffic
    iptables -A INPUT -i lo -j ACCEPT
    
    # HTTP and HTTPS traffic
    iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
    iptables -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
    
    # SSH from specified clients
    iptables -A INPUT -p tcp -s 123.45.67.89 -m tcp --dport 22 -j ACCEPT
    
    # Allow related connections
    iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
    
    # Allow outgoing connections
    iptables -P OUTPUT ACCEPT
    
    # Block all other connections
    iptables -P INPUT DROP
    
    # Save iptables and restart service
    iptables-save | sudo tee /etc/sysconfig/iptables
  • San Francisco and Napa Valley

    San Francisco and Napa Valley

    I was recently fortunate enough to spend some time at Carneros Resort in Napa, California with the WordPress.com VIP team. We did a bit of coding, a bit of lecturing, and a bunch of networking. It was an amazing experience and I can’t wait to attend the event in the future.

  • Add a pageview column with Jetpack data source

    I decided to get with the times and give Jetpack a try. If you’re unfamiliar with Jetpack, it’s essentially a WordPress plugin which ties your self-hosted WordPress blog to WordPress.com’s servers and allows nifty features like an image CDN, Gravatar hovercards, centralized comments, and a multitude of other features. Personally, I love the WordPress.com stats the most.

    I missed my views column on my posts page in admin though (which I used to source from my Better Postviews plugin). So I wrote up this little function to get the data from Jetpack servers and happily place it where it belongs. Here is the code to do so:

    <?php // Add a Views columns to insert jetpack postviews data into function rdc_add_views_column( $cols ) { $cols['pageviews'] = 'Views'; return $cols; } add_filter( 'manage_edit-post_columns', 'rdc_add_views_column' ); // Grab and display the postviews data from Jetpack for each post function rdc_add_views_col_data( $colname ) { global $post; // Make sure we're inserting into the correct column if ( 'pageviews' !== $colname ) return false; // Make sure jetpack and stats are available if ( ! ( class_exists( 'Jetpack' ) &amp;&amp; Jetpack::is_module_active( 'stats' ) ) ) { echo 'Error'; return false; } // Make sure stats_get_csv is available if ( ! function_exists( 'stats_get_csv' ) ) { echo 'Error'; return false; } // Try to get view count from post meta "cache" $view_count = get_post_meta( $post->ID, '_jetpack_post_views_count', true );
    	$view_count_created = absint( get_post_meta( $post->ID, '_jetpack_post_views_count_created', true ) );
    
    	// No "cache" value, hit the API for the value
    	if ( ! $view_count || time() > $view_count_created + 3600 ) {
    		// Get the post data from Jetpack
    		$postviews = stats_get_csv( 'postviews', "post_id={$post->ID}" );
    
    		// We have a problem if there was no data returned
    		if ( ! $postviews ) {
    			echo 'Error';
    			return false;
    		}
    
    		// Get view count from returned results
    		$view_count = absint( $postviews[0]['views'] );
    
    		// Store the value and time as post meta
    		update_post_meta( $post->ID, '_jetpack_post_views_count', absint( $view_count ) );
    		update_post_meta( $post->ID, '_jetpack_post_views_count_created', absint( time() ) );
    	}
    
    	// Print Jetpack post views
    	echo '<strong>' . number_format( absint( $view_count ) ) . '</strong>';
    }
    add_action( 'manage_posts_custom_column', 'rdc_add_views_col_data' );
    

    Drop that code into your functions.php or another theme file. Also, if you’re REALLY scaling up, you’re probably using something like Varnish cache and the Better Postviews Plugin may not register an accurate view count. If that’s the case, Jetpack may be for you since WordPress.com stats are javascript based.

    There are a ton of other metrics which you can pull from Jetpack also – check out George Stephanis’ slides from WordCamp Boston 2013 for some more info.

    Enjoy!