Simple age shortcode for WordPress

As I was updating the about page on this blog today, I decided that I wanted to make my age in the following string dynamic: “I am a 31-year-old Texan”. After considering options, creating a shortcode seemed like a simple enough route. Here’s the code that I came up with:

/**
 * A simple shortcode for displaying a person's age within WordPress content. This was
 * created with an "about" in mind, so that I wouldn't have to keep updating my age. :)
 * 
 * Usage: [simple_age birthday="January 1 2020"]
 */
function simple_age_shortcode( $atts ) {
	if ( empty( $atts['birthday'] ) ) {
		return '';
	}
	
	// If the birthday couldn't be parsed, then show some numeric output at least ¯\_(ツ)_/¯
	$birthday = strtotime( $atts['birthday'] );
	if ( ! $birthday ) {
		return 0;
	}
	
	$time_diff  = time() - $birthday;
	$years_diff = floor( $time_diff / YEAR_IN_SECONDS );
	
	return intval( $years_diff );
}
add_shortcode( 'simple_age', 'simple_age_shortcode');

Then, in my about page, I modified the content to look like this:

I am a [simple_age birthday="January 1 2020"]-year-old Texan...

To add this code to your site, you can add it as a plugin, in the functions.php file of your theme, or you could use a plugin like Code Snippets (which is my favorite option for small bits of code like this).

If you land here, then hopefully you find this simple age shortcode for WordPress handy. 😄 If there’s some interest, I may consider adding the plugin to the core repo to make it easier for people to use the shortcode. Feel free to leave a comment below if you’d prefer that.

NWTFS September Rifle Match

Last month, Destiny and I attended the high power rifle match at Northwest Texas Field and Stream Association. This was the first match that Destiny and I had competed in at the club, and it was only the second time that we had ever competed. The first time that we competed being at the Rifle SAFS competition at Camp Perry in 2019.

Below are some pictures and video from the match. 😄

Camp Perry Pistol Week– 2019

I spent last week, July 8th-14th, at Camp Perry in Port Clinton, Ohio for the National Precision Pistol Championship.

The Trip

The trip was about a 17 hour drive to get from Wichita Falls, Tx to Port Clinton, Ohio.

And with 4 people and all of our gear, you can imagine that the van we took was pretty packed! The picture below is with the two back seats folded down. 😄

We left on Saturday the 6th, directly following the Don James Memorial match at Northwest Texas Field and Streams, stayed in St. Louis for the night, and then finished the trip on the 7th. On the way back, we left Port Clinton at about 7:15am and drove through until we got to Wichita Falls.

The Hut

While at Camp Perry for pistol week, the group of folks from Wichita Falls stayed in a hut. Huts cost $52 per night, have four beds, power outlets, and an air conditioner. Here’s a panorama picture of what our hut looked like from the front door.

And here’s a picture of what our hut looked like from the outside. Notice all of the mayflies on the building. 😄

Results

The match results for pistol week at Camp Perry can be found at the following links:

To summarize, I took third marksman for the NRA championship but did not receive any points or win for the CMP matches. All the same, it was a great week.

Photos

Install Unison 2.48.4 on Mac OS X with Homebrew

I use Unison to sync code between my local machine and my dev servers. To sync between two servers, it requires that the same version of Unison be installed on both servers.

Now, this isn’t usually a big deal, because once you get Unison set up, it’s set up. But, I usually get a bit frustrated when setting up a new development machine and ensuring that it has the same Unison version as my remote server.

Most recently, I needed to get Unison 2.48.4 on my local Mac so that it matched my remote server. BUT, homebrew didn’t support Unison 2.48.4.

So, after getting some feedback from one of my coworkers, we came up with the following. Maybe you’ll find it helpful.

# Get rid of existing Unison
brew uninstall --force unison

# Checkout version of homebrew with Unison 2.48.4
cd /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core
git checkout 05460e0bf3ae5f1a15ae40315940b2d39dd6ac52 Formula/unison.rb

# Install
brew install --force-bottle unison

# Set homebrew-core back to normal
git checkout master
git reset HEAD .
git checkout -- .

NOTE: If you get error: fatal: reference is not a tree: 05460e0bf3ae5f1a15ae40315940b2d39dd6ac52 after running git checkout 05460e0bf3ae5f1a15ae40315940b2d39dd6ac52 Formula/unison.rb, we’ve been able to fix the issue by recloning homebrew-core. If you get the same error, you’ll want to add these steps before retrying starting at the git checkout 05460e0bf3ae5f1a15ae40315940b2d39dd6ac52 Formula/unison.rb command above.

cd /usr/local/Homebrew/Library/Taps/homebrew
rm -rf homebrew-core
git clone https://github.com/Homebrew/homebrew-core.git
cd homebrew-core

How to download a gif from Giphy

Recently, when I was trying to download a gif file from Giphy, I noticed that when I went directly to the file, https://media.giphy.com/media/14kdiJUblbWBXy/giphy.gif for example, that it was actually loading a web page instead of the gif file. 😞

Now, on this page, you could choose to alternative/right click on the image and then click “Save Image”. But, this will download the image with a .webp extension. From there, you can choose to change the extension to .gif if you’d like. But, I’ll be honest and tell you that I didn’t consider switching the extension at first. So, I dug further.

I figured that Giphy was probably detecting that based on who/where the request was coming from, so I tried downloading the gif file by running a cURL command. This worked, but it’s not convenient to have to open up a terminal window to run a cURL command.

Luckily, a kind person left a very helpful comment below with an even simpler approach, which I think is the simplest approach overall.

Simple approach

When we go to a standard Giphy source URL, like https://media.giphy.com/media/14kdiJUblbWBXy/giphy.gif, a web page is loaded instead of the gif that we want. Now, the only thing we have to change for the actual gif to load is to change media.giphy.com to i.giphy.com.

So, if we take the above example, we could load the actual gif by going to https://i.giphy.com/media/14kdiJUblbWBXy/giphy.gif

From here, we can alternate/right click to download the gif with the correct extension and go on about our day.

Downloading via cURL

curl https://media.giphy.com/media/KXgJsSeOfvSgg/giphy.gif --output ~/Desktop/download.gif

This resulted in the actual gif file that I wanted being placed on my Desktop as download.gif. 💪

Recursively cast to array in PHP

I recently ran into an issue where JSON encoding some objects in my code wasn’t working properly. After experimenting, I realized that casting everything to an array before JSON encoding magically fixed things. 

Casting an object to an array is simple enough:

$variable_to_array = (array) $object_var;

But, what happens when an object or array contains references to other objects or arrays? The answer is that we then need to recursively cast a given input to an array. But, we don’t necessarily want to recursively cast everything to an array. For example, this is what happens when we cast 1 to an array:

return (array) 1;
=> array(1) {
  [0]=>
  int(1)
}

A simple fix is to recursively cast non-scalar values to an array. Here’s an example of how we would do that:

/**
 * Given mixed input, will recursively cast to an array if the input is an array or object.
 *
 * @param mixed $input Any input to possibly cast to array.
 * @return mixed
 */ 
function recursive_cast_to_array( $input ) {
	if ( is_scalar( $input ) ) {
		return $input;
	}

	return array_map( 'recursive_cast_to_array', (array) $input );
}

How to remove files not tracked in SVN

At Automattic, we use SVN and Phabricator for much of our source control needs. One issue that I often run into is a warning about untracked files when creating a Phabricator differential:

You have untracked files in this working copy.

  Working copy: ~/public_html

  Untracked changes in working copy:
  (To ignore this change, add it to "svn:ignore".)
    test.txt

    Ignore this untracked file and continue? [y/N]

This warning’s purpose is to make sure that the differential being created has ALL of the changes so that a file isn’t forgotten when a commit is made. 

But, what if the untracked file(s) are from previously checking out and testing a patch? In that case, this warning is actually a bit annoying. 😄

The simple fix is to clear out the file(s) that aren’t tracked by SVN, which is as simple as deleting the file(s) since they’re not tracked in SVN. For a single file, that might look like:

rm test.txt

But, what if there are dozens or hundreds of files? I know I certainly wouldn’t want to run the command above dozens or hundreds of times to remove all of the files that aren’t tracked in SVN. Of course, we can automate all of the work by running something like the following ONCE:

svn st | grep '^?' | awk '{print }' | xargs rm -rf

Simply run the above from the root of the project and the untracked files should be removed. The above command is a bit much, so I’d recommend throwing it in an alias, which would look something like this:

alias clearuntracked='svn st | grep '\''^?'\'' | awk '\''{print }'\'' | xargs rm -rf'

Get unique values in file with shell command

Over the past year, there have been a couple of times where I've needed to sort some large list of values, more than 100 million lines in one case. 😱

In each case, I was dealing with a data source where there was surely duplicate entries. For example, duplicate usernames, emails, or URLs. To address this, I decided to get the unique values from the file before I ran a final processing script over them. This would require sorting all of the values in the given file and then deduping in the resulting groups of values.

This sorting and deduping can be a bit challenging. There are various algorithms to consider and if the dataset is large enough, we also need to ensure that we're handling the data in a way that we don't run out of memory. 

Shell commands to the rescue 🙂

Luckily, there are shell commands that make it quite simple to get the unique values in a file. Here's what I ended up using to get the unique values in a file:

cat $file | sort | uniq

In this example, we are:

  • Opening the file at $file
  • Sorting the file so that duplicates end up in a contiguous block
  • Dedupe so that only one value remains from each contiguous block

Here's another example of this command with piped input:

php -r 'for ( $i = 0; $i < 1000000; $i++ ) { echo sprintf( "%d\n", random_int( 0, 100 ) ); }' | sort -n | uniq

In this example, we are

  • Generating 1,000,000 million random numbers, between 0 and 1,000) on their own lines
  • Sorting that output so that like numbers are together
    • Note that we're using -n here to do an integer sort.
  • Deduping that so that we end up with a unique number on each line

If we wanted know how often each number occurred in the file, we could simple add -c to the end of the command above. The resulting command would be php -r 'for ( $i = 0; $i < 1000000; $i++ ) { echo sprintf( "%d\n", random_int( 0, 100 ) ); }' | sort -n | uniq -c and we would get some output that looked like this:

9880 0
10179 1
9725 2
10024 3
9921 4
9893 5
9945 6
9881 7
9707 8
9955 9
9896 10
9845 11
9928 12
10024 13
10005 14
9834 15
9929 16
9764 17
9795 18
9932 19
9735 20
10082 21
9876 22
9835 23
9748 24
9947 25
9975 26
9841 27
9856 28
9751 29
10138 30
10037 31
10026 32
10128 33
9926 34
9821 35
9990 36
9920 37
9696 38
9886 39
9896 40
9815 41
9924 42
9739 43
9854 44
9936 45
9977 46
9873 47
9824 48
10043 49
10054 50
9870 51
9783 52
9901 53
9819 54
9882 55
10022 56
9899 57
9922 58
9922 59
9902 60
10036 61
9830 62
9792 63
9894 64
10008 65
9774 66
9918 67
9986 68
9814 69
9661 70
10117 71
10046 72
9704 73
10016 74
9601 75
9901 76
9923 77
9931 78
9909 79
9895 80
9771 81
10044 82
10059 83
9864 84
9938 85
9799 86
10006 87
9883 88
9880 89
9837 90
9701 91
9870 92
9998 93
9809 94
9883 95
10144 96
9935 97
9979 98
9922 99
9789 100

What is the JavaScript event loop?

I remember the first time I saw a setTimeout( fn, 0 ) call in some React. Luckily there was a comment with the code, so I kind of had an idea of why that code was there. Even with the comment though, it was still confusing. 😉

Since then, I’ve read several articles about the event loop and got to a point where I was fairly comfortable with my understanding. But, after watching this JSConf talk by Philip Roberts, I feel like I’ve got a much better understanding.

In the talk, Philip uses a slowed down demonstration of the event loop to explain what’s going on to his audience. Philip also demonstrates a tool that he built which allows users to type in code and visualize all of the parts that make JavaScript asynchronous actions work.

You can check out the tool at http://latentflip.com/loupe, but I’d recommend doing it after watching the video.