Portfolio Work – Interweaving the Personal API


I know. The title is pure click-bait. That’s part of why this blog is so wildly popular.1

I’ve been building a new portfolio site2 and I think some of this is kind of interesting even if it sounds boring. There are a few different goals in play. One challenge is to create a site that stays up to date with minimal work on my end. It’s a parallel of the small-pieces-loosely-joined mentality. I want tiny-actions-over-time (from the aforementioned small pieces) rather than widely-spaced-herculean efforts. I’m also trying to make sure that it fits in well with my current workflow and that I’m capturing the work I do elsewhere in ways that make sense.

Another focus is to keep any work highly portable. I’ve had to re-enter data a number of times as I’ve migrated and I don’t want to do that any more. That’s going to be made possible mainly through some new API options and by working on my API/JSON, JavaScript skills. I’ll probably have to do chunks of it over anyway but I like to pretend I wont.

I’ve got a ways to go but I’ve made some decent progress. The basic template/visuals are handled by Bootstrap. I’ve also got some simple Angular views, Timeline JS, JSON from Google sheets, WordPress WP Rest API v2, and Pinboard’s API. So that’s kind of fun (I think).

The Front Page

portfolio details

The following is the code for the jQuery JSON parser. It displays the JSON created by the WordPress API. I opted to cache the data rather than call it live for two reasons- it seemed much faster performance-wise and I’m also hosting this on GitHub which brings up http/https issues until I turn on https for my personal site. I just use PHP to grab it and stick it in a folder every 24 hrs via a cron task.

          console.log("ready"); //just to check in the firebug console.
          url:'json/blogs.json', //gets json
          success: function(data) {
//builds the html and does a default img if there isn't one
            $.each(data, function(index, item){
                if (item.better_featured_image != null){ var photo ='<div class="pinimg"><img src="'+ item.better_featured_image.media_details.sizes.thumbnail.source_url +'" width="40px" height="40px"></div>' } else {var photo ='<div class="pinimg"><img src="imgs/default.png" width="40px" height="40px"></div>';};              
                $('#blog').append('<a href="' + item.link + '"><div class="pinboard">' + photo + '<div class="pindetails"> ' +item.title.rendered + ' <br/> published on ' + item.date.substring(0,10) +' </div> </div></a>');              
              if (index == 10) return false; //only display 10 items
              }); //each
            } //success
          }); //ajax

For Pinboard, I did something similar.

          url:'https://feeds.pinboard.in/json/u:twwoodward/', //from the pinboard API
          success: function(data) {
            $.each(data, function(index, item){
                $('#pinboard').append('<div class="pinboard"><a href="' + item.u + '">' + item.d
        + '</a>  -  ' + item.dt.substring(0,10) +' </div>');
              if (index == 10) return false; //only display 10 items
              }); //each
            } //success
          }); //ajax

I tried to parallel the visual elements for the blog posts and the Pinboard posts with the Twitter widget visuals since I couldn’t really change the way that looked. I should have called the class something more generic than pinboard since I used it on things that aren’t pinboard as well.

.pinboard {
  font: normal normal 12px/1.2 Helvetica,Roboto,"Segoe UI",Calibri,sans-serif;
  padding-top: 12px;
  padding-bottom: 12px;
  border-bottom: 2px solid #efefef; 
  line-height: 18px;


  background-color: #f1f7fa;

.pinboard a {
  color: #3498db;
  padding: 2px;


Screen Shot 2016-07-10 at 5.14.22 PM

This is kind of amusing. The following chunk of code uses Flickr’s API to get the total number of photos I’ve uploaded. It seems to take more code than I feel like it should but it works.

 $(document).ready(function() {

        url: 'https://api.flickr.com/services/rest/?method=flickr.people.getInfo&api_key=276580779b3354f9d6820e102e5775f0&user_id=29096601%40N00&format=json&jsoncallback=?',
        dataType: 'jsonp',
        success: function(data) {
                console.log(data); //dumps the data to the console to check if the callback is made successfully.
                $.each(data, function(index, item) {
                    $('#flickrcount').prepend('<div class="bignumber">' + numberWithCommas(item.photos.count._content) + '</div>');
                }); //each

function numberWithCommas(x) {
    return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
//from a stackoverflow answer to format the date nicely
function timeConverter(UNIX_timestamp) {
    var a = new Date(UNIX_timestamp * 1000);
    var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
    var year = a.getFullYear();
    var month = months[a.getMonth()];
    var date = a.getDate();
    var hour = a.getHours();
    var min = a.getMinutes();
    var sec = a.getSeconds();
    var time = date + ' ' + month + ' ' + year;
    return time;

The rest of the page is my more typical Angular construction pattern with Bootstrap. It feels much simpler than the jQuery version to me. It’s using the WordPress JSON in a cached manner.

var app = angular.module('myApp', ['ngSanitize']);
app.controller('SuperCtrl', function($scope, $http) {
.success(function(response) {$scope.entries = response;});
<div class="col-md-10 col-md-offset-1 col-xsm-12">
	<a href="{{ entry.link }}">		 
		<div ng-repeat="entry in entries | filter: search| orderBy:'-id' : reverse" class="col-lg-2 col-md-3 col-xs-12 artist" style="background-image: url({{ entry.better_featured_image.media_details.sizes.medium.source_url }}); background-repeat: no-repeat; background-position: center; background-size: cover ">	
		<div class="artist_title"><h4 ng-bind-html="entry.title.rendered"></h4>

Screen Shot 2016-07-10 at 5.14.41 PM
The Presentations page is fairly similar. It uses Angular and Bootstrap for display and the JSON from a Google Sheets. I link to most of the evidence. I may rethink that a bit given some of the new options I have to automate things via Google Scripts and the tendency for things on the Internet to wander off.

var app = angular.module('myApp', ['ngSanitize','angular.filter']);
$gid = "1xG1ClBl5A0kuNca6TYJliKL-5oHSEx6OerAzAJO9f6o"
//$gid = $_GET['id'];
$gURL = "https://spreadsheets.google.com/feeds/list/" + $gid + "/1/public/values?alt=json";
app.controller('SuperCtrl', function($scope, $http) {
    .success(function(response) {$scope.entries = response.feed.entry;});

There’s still a lot of stuff I don’t feel like I’m capturing well or efficiently. I need to think about it more and do some more work. It does bring up some larger issues that I need to think about career-wise. In the last few years, after resisting for quite some time, I have become a person who can program. I still have so very, very much to learn but I’ve learned a huge amount in the last few years- server stuff, php, WordPress, javascript, various APIs, a bit of Angular, lots of Google Script lately . . . I wonder about focusing. I know it’d help in some ways. I also realize that programming isn’t likely to be where I bring real value in terms of jobs that are likely to pay me. There are lots of younger people who can do more than I can technically. I do have a decent ability to think through things with people and to think about doing things from a variety of angles. I like to solve problems and make life better for the humans.

1 My most popular posts involve either scraping Instagram or a mouse drug game that I linked to several years ago.

2 The evisceration of one’s department will encourage a bit of attention there.

Comments on this post

  1. John Johnston said on July 11, 2016 at 6:43 am

    this is really lovely, elegant.

    I guess you using a Wp Api plugin to provide the json?

    I tried the same sort of thing on my ds106 blog, but in a much more horrible way:

    • Tom Woodward said on July 11, 2016 at 7:09 am

      Thanks John. I’ve become something of a JSON fan.

      I am using the v2 plugin.

  2. carpetbomberz said on July 11, 2016 at 7:57 am

    Noting footnote #2 (ie evisceration etc.) I feel your pain. Our EdTech unit (started ’99-ended ’12) at rochester.edu got shutdown due to money and politics. I escaped to a desktop support job for 1 year, then they re-advertised my original job 1 year later. I applied for that position and I’m right back doing what I had been, with slight changes. EdTech will never go away, EdTech Lives.

    • Tom Woodward said on July 11, 2016 at 8:17 am

      I should clarify that no one at my level has been fired but we’ve had two open positions for nearly a year. We have since lost four more people as they’ve left for a variety of reasons. I’m hoping we’ll get it all straightened out but failing to prepare . . . and all that.

  3. aarondavis1 said on July 2, 2017 at 7:58 am

    This post kind of haunts me Tom. I really like the idea of it, a space that captures me. However, i was wondering about the possibility of creating something that was somewhat automated, but also organised? For example, if I create a new video on YouTube it creates a post, if I post a photo to Flickr, it creates a post. Here is my initial beginning (collection.readwriterespond.com).

    I am thinking that maybe I need to hook into IFTTT or something, but wondering if there could be any other way? I am trying to support students with diverse digital offerings and how a blog could act as a hub. Just trying to automate part of the process.

    • Tom Woodward said on July 2, 2017 at 9:51 am

      The initial content creation would be pretty straight forward in all the major systems I can think of (it’s not too different than how my weekly pinboard post is created via the api . . . which I may have written up only in my head) but the details would be important. For instance, do you capture the raw video from YouTube or just reference the external resource? I think you want the former which would be more complicated with video because of size etc.

      You’d get more complexity if you were trying to sync changes long-term. That’s the part that escapes me. Easy to get the content once and push it in but as scale grows, I can’t think of a sustainable pattern for looking back across all that content for changes.

      I want to get back to this more aggressively in the near future. I feel the need to get my stuff out of Flickr which will take some work and be a nice test of scale. I know quite a bit more than I did a year ago so I might be able to do a good bit more.

    • Tom Woodward said on July 5, 2017 at 9:50 am

      I wrote some quick documentation around how I push my weekly links post into WordPress. It might be helpful.

Trackbacks and Pingbacks on this post

  1. Read Write Respond #012 – Read Write Collect said on December 25, 2017 at 5:19 pm

    […] Portfolio Work and Interweaving the Personal APIĀ – Tom Woodward continues his investigation into the power and potential of personal APIs. I am left wonder the place of APIs within the debate around coding and education. […]