Rethinking Our Project Page (and other stuff)

Image from page 211 of “Bulletin” (1961-1962) flickr photo by Internet Archive Book Images shared with no copyright restriction (Flickr Commons)

I’ve been lucky enough to hire two awesome people who have started over the last month or so.1 We’re also going to get a new supervisor on July 3rd. That’s led me to have a bit of breathing room and a reason to start re-thinking some things. One of those things is how we combine documenting our work.

  • Can we document what we do in a way that will create more people interested in doing these things?
  • Can we do a much better job bringing active faculty to the forefront?
  • Can we serve the end of the year report needs regarding various data elements?
  • Can we gather data we might reflect on regarding our own processes?
  • How do we knit all this stuff together from various services without a lot of extra work?

The Old

I’ve done this more than a few times. The latest incarnation at VCU was the examples page (pictured above). It is semi-decent but was done in haste. It tries to affiliate tools and instructional concepts with examples. Conceptually, it’s pretty close to TPACK in that way. It has done a marginal job thus far. It houses examples and people can browse them. It doesn’t really do any of the other stuff well and I’ve been pretty negligent in updating it.

One of the little pieces that has slowed this down is just the stupid screenshots. Slightly different aspect rations led to ugly displays and just general hassle. It’s not huge but it’s been a point of friction and it doesn’t take much friction to slow down something like this.

It doesn’t do anything smart regarding automating reporting and, most importantly, it doesn’t do any magic.


We’ve got some fairly large goals defined and part of that involves mapping out where we currently work and where we’d like to work. For our still very new group I expect some of that to change. That means looking hard at what we’re going to do now but building with flexibility in mind for the fluidity that the future tends to hold.

Our current evaluation was that Google Drive, GitHub, Slack, and email covered a pretty decent spectrum of tools and opportunities both for our internal group and for anyone outside it. No major shifts for anyone in terms of workflow and plenty of opportunities for API integrations.

Stage One – Right Direction, Wrong Path

Initially, I figured I’d do most of this with ACF and make it super-quick and simple. I was just going to set it up so that categories would tie in the custom fields as needed. That’d simplify things etc. etc. Faculty would be tied to projects with their email addresses acting as unique IDs (below).

Things worked well on the initial display with mock data. I played around with it mainly in codepen and was pretty happy with it.

See the Pen alt-proj-layout by Tom (@twwoodward) on CodePen.

Once I pulled the demo structure into WordPress and started hooking up the PHP things got messier. I’d been using the ACF repeater field to pull in the faculty via one or more emails but wasn’t pleased with how it played out in wp_query. You can do it but it felt like the complexity of doing this with ACF was surpassing the complexity of doing it purely in WordPress. Plus, I began to consider the usefulness of being able to use default WordPress URL structures to display data by taxonomies. So . . . time to restructure and do it the way I should have from the start. Once I did that things were easier and I went ahead and added the other elements without ACF.

Then I wanted to make the demo data around the project real and automatic.

For Github, I can use their api and the name of the repository to return the bytes per language in the repository. So this
return this

"PHP": 47598,
"JavaScript": 5899,
"CSS": 1835

For Google Drive, I wrote a small script to run against a folder and write the data to a spreadsheet for later querying.

var img = 0;
var doc = 0;
var ss = 0;

function getAllFolders (){
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getActiveSheet();
  var lastRow = sheet.getLastRow();
  var range = sheet.getRange('A2:F'+ lastRow).clearContent();
 //get project folder 
 var contents = DriveApp.getFolderById('YOURFOLDERIDHERE').getFolders(); 
  //Logger.log('first thing ' + contents);
  while (contents.hasNext()) {
   var data = [];
   var folder =;
   var projName = folder.getName();
   var inception = folder.getDateCreated(); 
    data.push(projName, inception);
   var files = folder.getFiles(); 
    var i = 0;
    while (files.hasNext()){
      var file =;
    img = 0;
    doc = 0;
    ss = 0;

function mimeMatcher (file) {
  var mime = file.getMimeType();
  if ((new RegExp('image')).test(mime)) {
  if ((new RegExp('document')).test(mime)) {
  if ((new RegExp('spreadsheet')).test(mime)) {

For emails per project, I’ll do something similar to what I do to log my support emails with the content being written to a collaborative Google Sheet.

For slack messages per channel it ended up being fairly straight forward as well once I realized which endpoint to use.

function slackCounter ($channel){
	$slack = file_get_contents(''. $channel .'&pretty=1');
	$obj = json_decode($slack);

	return $obj->messages->total;

Which returns

"ok": true,
"query": "in:mother_blog",
"messages": {
"total": 0,
"pagination": {
"total_count": 0,
"page": 1,
"per_page": 20,
"page_count": 0,
"first": 1,
"last": 0
"paging": {
"count": 20,
"total": 0,
"page": 1,
"pages": 0
"matches": []

Other Stuff

So to add emails as a taxonomy, I just need to add the following in functions.php. I opted to do this so they’d work like the structure of tags (no hierarchy) — ‘hierarchical’ => false. I can also assign the taxonomy to multiple custom post types through something like register_taxonomy(’emails’,array(‘project’,’faculty’). Not too hard and all the stuff is pretty much straight from the codex.

add_action( 'init', 'create_tag_taxonomies', 0 );
function create_tag_taxonomies() 
  // Add new taxonomy, NOT hierarchical (like tags)
  $labels = array(
    'name' => _x( 'emails', 'taxonomy general name' ),
    'singular_name' => _x( 'email', 'taxonomy singular name' ),
    'search_items' =>  __( 'Search emails' ),
    'popular_items' => __( 'Popular emails' ),
    'all_items' => __( 'All emails' ),
    'parent_item' => null,
    'parent_item_colon' => null,
    'edit_item' => __( 'Edit email' ), 
    'update_item' => __( 'Update email' ),
    'add_new_item' => __( 'Add New email' ),
    'new_item_name' => __( 'New email Name' ),
    'separate_items_with_commas' => __( 'Separate emails with commas' ),
    'add_or_remove_items' => __( 'Add or remove emails' ),
    'choose_from_most_used' => __( 'Choose from the most used emails' ),
    'menu_name' => __( 'Emails' ),

//registers taxonomy to both project and faculty post types
  register_taxonomy('emails',array('project','faculty'), array(
    'hierarchical' => false,
    'labels' => $labels,
    'show_ui' => true,
    'update_count_callback' => '_update_post_term_count',
    'query_var' => true,
    'rewrite' => array( 'slug' => 'email' ),
    'show_in_rest'          => true,
    'rest_base'             => 'emails',
    'rest_controller_class' => 'WP_REST_Terms_Controller',

1 So very nice to get other in-person perspectives on this stuff again (not that I don’t love you Internet friends).