David Sword

A decent blog from a Canadian designer, wordpress developer, and beer drinker. Email david@davidsword.ca

Emoji short name’s to HTML HEX Code via PHP

I've been working on a Slack App that shows recent Slack posts and activities. The majority of recent posts include emojis, and problematically Slack's API doesn't store and send emojis as characters, they're down-converted to their respective shortnames, then wrapped in colons (presumably for universal support - it appears to be a standard practice of some sort, as many use it).

Basically I was just looking for converting

:thumbsup: to convert to: \👍 which'd show: 👍

Simple enough task, but I couldn't find any resources to do it (and if you've discovered this blog post, you've probably discovered that out too). So, starting at the top, Slack in their API docs refers to using github.com/iamcal/emoji-data as their emoji shortcode source. This repository does have a PHP script, but it doesn't convert as simply as I wanted it to, and it's huge.

Taking a step back, iamcal/emoji-data has a enormous master .json file, basically a database of each emoji and all variations therein. Taking this file, and running through it with some basic PHP, we can build a simple array of shortcode => hexcode. Doing this was almost too easy:

$table = json_decode(file_get_contents('emoji.json'));
//print_r($table); //take a peak
foreach ($table as $k => $emoji)
foreach ($emoji->short_names as $shortname)
echo "'{$shortname}' => '{$emoji->unified}', \n";

We then take the output of that file, and create our own emoji_unicode.php file, an array housing the values output above. Which looks like:

$emoji_unicode = array(
'copyright' => '00A9',
'registered' => '00AE',
'bangbang' => '203C',

Much smaller and easier to work with. 97% smaller actually coming in at: 35KB instead of 928KB. I've hosted the file on github here.

So with a simple array to call back to, we can just include it, search the string for the colon'ized shortcode emojis and replace with hex code, like so:


$text = "hello :world_map: . it's :hammer: :stopwatch:.";

//alphanumeric, hyphens, plus-signs, and underscores string, wrapped in colons
preg_match_all("/:([a-zA-Z0-9'_+-]+):/", $text, $emojis);

foreach ($emojis[1] as $emojiname)
  if (isset($emoji_unicode[$emojiname]))
    $text = str_replace(":".$emojiname.":", "&#x".$emoji_unicode[$emojiname].";", $text);
    $text = str_replace(":".$emojiname.":", "(".$emojiname.")", $text);

echo $text;

Which'd output

hello 🌎 . it's 🔨 ⏱.

This works with :skin-tone-x which surprised me- I guess the skin-tone is a "invisible" character of it's own, that basically gets compounded with the emoji character before it, and changes the emojis that way. Pretty cool, so no extra work for that. (And no, this method doesn't work on devices that don't support emojis).

Kindle Currently Reading on Panic Status Board or Website

Here's a neat little widget that'll fetch your currently-reading and read books from your Goodreads shelf, and show them as a widget for either Panic Status Board (DIY Panel), or your website. Code is inspired and built upon from a great little 2013 script from flapane.com

First, some styling:

#bookshelf {
    margin: 0 auto;
.book { 
    -webkit-filter: grayscale(1); 
    -webkit-filter: grayscale(100%); 
    filter: grayscale(100%); 
    filter: gray;
    background-position:center center;
    background-repeat: no-repeat;
    width:98px; // original
    height:147px; // original
    width:px; // new
    height:172px; // new
    box-shadow: 0 0 3px 3px rgba(0,0,0,0.09);
.reading {
    float: left;
    margin-right: 5px;
.read {
    float: left;
    width:98px; // original
    height:147px; // original
    width:px; // new
    height:54px; // new
    opacity: 0.8;
    margin: 0 0px 5px 0;

Setup, query and cache:

$curl_options = array(
  CURLOPT_HEADER        =>; false,
  CURLOPT_ENCODING      => "",
  CURLOPT_AUTOREFERER       => true,
  CURLOPT_TIMEOUT       => 8,
  CURLOPT_MAXREDIRS         => 3,
  CURLOPT_USERAGENT     => "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.A.B.C Safari/525.13"

// Is the file older than $refreshbook, or the file is new/empty?
if ($force_refresh || ((time() - filectime($cache)) > ($refreshbook * 3600) || 0 == filesize($cache))) {

    // the query, pretty straight forward
    $reading_books_path = "https://www.goodreads.com/review/list/".$user.".xml?key=".$apikey."&v=2&shelf=currently-reading&sort=date_started&order=d&page=1&per_page=2";

    // make the curl request, basically get_file_contents().
    $ch = curl_init($reading_books_path);
    curl_setopt_array($ch, $curl_options);
    $content = curl_exec( $ch );
    if(curl_error($ch)) output('Curl error:' . curl_error($ch) . "
"); curl_close( $ch ); # again, but for read sleep(2);//1 query per second for goodreads api $reading_books_path = "https://www.goodreads.com/review/list/".$user.".xml?key=".$apikey."&v=2&shelf=read&sort=date_started&order=d&page=1&per_page=5"; $ch = curl_init($reading_books_path); curl_setopt_array($ch, $curl_options); $content_read = curl_exec( $ch ); if(curl_error($ch)) output('Curl error:' . curl_error($ch) . "
"); curl_close( $ch ); // save curl request results to cache, store together, but serperate two $handle = fopen($cache, 'wb'); fwrite($handle, $content.$breaker.$content_read); fclose($handle); } ?>

Read and output:


// cycle through currently reading (@TODO i dont know if cycle works nativily, only developed with 1 book in shelf. sometimes they change the xml structure when >1.  would need to change)
foreach ($reading->reviews->review as $reading)
    echo "
book->title}' class='book reading' style='background-image:url(".str_replace('http:', 'https:', $reading->book->image_url).");'>
"; // cycle through read $c = 1; foreach ($read->reviews->review as $read) { $img = @(isset($image_fix['id_'.$read->book->id])) ? $image_fix['id_'.$read->book->id] : $read->book->image_url; if ($c < 4) echo "
book->title} - #{$read->book->id}' class='book read' style='background-image:url(".str_replace('http:', 'https:', $img).");'>
"; $c++; } echo ""; ?>

You'll need to create empty file goodreads.cache manually, in the dir of the script.

I'm not entirely sure what happens when there's more than 1 currently-reading. I never bothered checking.

$image_fix is nasty, I don't understand why the Goodreads user API would not return a cover when the cover is present on the Goodreads site itself. I had to do a fix for one of my books, manually tracking down the cover's URL on Goodreads.com.

width:px; is my ..interesting.. way of doing proportional scaling on the fly. Old width/height values kept prior to overwrites for reference; makes sizing your widgets books covers to much easier.

filter: grayscale(100%); Keepin' it real with Kindle, grayscale the covers.

404’s Are Server, Not WordPress’s 404

Frustrating problem I've had happen more than once. Your Wordpress site returns a 404 (which you may be relying on), but it shows a HTML (server generated) 404 page, not a Wordpress 404 page.

Solution for apache is simple: let the server know to revert to index.php when the header is 404, set the following in .htaccess

ErrorDocument 404 /index.php


Big Neon

A poster done up for a bar event in Kamloops. Removed all meta, showing just the main graphic.

It’s Pink!

For a week we held onto our ultrasound result containing the answer to if it's a little boy or girl. We gave the sealed envelope to her family, who then gave it to a baker. The baker injected the cupcakes with either blue or pink icing.

We all got together, had a really nice day, and here's the heart warming seconds when Jess and I found out that our little baby is going to be a girl (we were convinced it was a boy, the cupcakes even seemed to have a hue of blue to them). With a mouth full of cupcake, she cries out "It's pink! It's Pink" then begins to turn to mush for 15minutes.