Author Archives: Tom Woodward

Weekly Web Harvest for 2017-09-10

  • I Can’t Get Google – YouTube

    think about this sometime you assume people have some shared understanding of the Internet

  • Is there any value in people who cannot write JavaScript?

    The worst part about pushing the “know everything” mentality is that we end up creating an industry full of professionals suffering from burnout and mental illness. We have people speaking at conferences about wellbeing, imposter syndrome and full stack anxiety, yet despite that, we perpetuate this idea that people have to know everything and be amazing at it.

  • Corrupted Blood incident – Wikipedia

    The spell, intended to last only seconds and function only within the new area of Zul’Gurub, soon spread across the virtual world by way of an oversight that allowed pets and minions to take the affliction out of its intended confines. By both accidental and purposeful intent, a pandemic ensued that quickly killed lower-level characters and drastically changed normal gameplay, as players did what they could do to avoid infection. Despite measures such as programmer-imposed quarantines, and the players’ abandoning of densely populated cities (or even just not playing the game), it lasted until a combination of patches and resets of the virtual world finally controlled the epidemic.


  • idyll-lang.github

    Idyll is a tool that makes it easier to author interactive narratives for the web. The goal of the project is to provide a friendly markup language — and an associated toolchain — that can be used to create dynamic, text-driven web pages.

  • The Online Photographer: Photography Isn’t Getting Any Easier

    Photography isn’t getting any easier mainly because the hard parts are still hard. Seeing and recognizing photographs (both while shooting and while editing) and understanding their meaning and their appeal have never been common skills, and still aren’t.

    Some things are much easier c. 2017—for instance, getting a sharp, clear, well-exposed, in-focus shot with accurate color in low light with a minimum of labor. But for everything that’s easier there are other things that are harder—for example, cutting through the noise and getting attention for your work in a field that’s global, overcrowded, atomized, and Balkanized. Much harder now.

  • BinderHub Documentation — BinderHub 0.0.1 documentation

    BinderHub allows you to BUILD and REGISTER a Docker image using a GitHub repository, then CONNECT with JupyterHub, allowing you to create a public IP address that allows users to interact with the code / environment you specify in the repository within a live JupyterHub instance. You can also specify a specific branch name / commit / tag to serve.

    h/t Stephen Downes

  • Can Techie Parents Reinvent School For Everyone–Or Just Their Rich Kids?

    Six-year-old Tiana had just gotten her ice cream machine working for the first time …..

    Eyes wide, Tiana turned to her teacher, Shira Leibowitz.

    “Shira, this is the most important day of my career,” she declared.

Working on Accessibility

Working on Accessibility

Bean with Tools on the Ocean of Storms flickr photo by NASA on The Commons shared with no copyright restriction (Flickr Commons)

We’re taking a much deeper dive into accessibility lately. It is a fruitful and good thing to do but also one of those deceptively deep topics with lots of complications. As a result I’m learning a good bit so I better write it down before it’s all forgotten.

Two Handy Tools

Thanks to both Matt and Jeff, I ended up using a few different tools.1

Google’s Vox Plugin helps you get a better idea what the experience was going to be like for someone with issues seeing the website. Using this will enable you to understand exactly how some of your decisions play out. I found it very handy. As a minor warning, there appears to be no way to turn it off/on short of disabling the extension. Despite that, I really think it’s a good idea to spend some time using this tool. It really helps.

The other useful tool so far has been the Siteimprove Chrome extension. It’s pretty handy to see what warnings/failures are in play in each page. It’s led me to realize that there are so many problems.

Bits of Useful Code

One of VCU’s requirements is a text only view for the page. I figured that would be an existing WordPress plugin but it didn’t seem to be.2 So I have this mostly working plugin which I’ll be tweaking as we learn more. The javascript that does most of the work is below. It’s a bit ES6-y but you can see how this removes styles, images3, svgs, and any in-line css styles.

function removeStyles(){
	Array.from(document.querySelectorAll('link[rel="stylesheet"], style')).forEach((elem) => elem.parentNode.removeChild(elem)); //destroy the styles

function removeImages(){
	Array.from(document.querySelectorAll('img')).forEach((elem) => elem.parentNode.removeChild(elem)); //destroy the images

function removeSVG(){
	Array.from(document.querySelectorAll('svg')).forEach((elem) => elem.parentNode.removeChild(elem)); //destroy the SVG 

function removeInline(){
    Array.from(document.querySelectorAll('*')).forEach((elem) => elem.removeAttribute('style')); //destroy the inline css

Then I decided to deal with iframe embeds in a less ‘kill it with fire’ method as it seemed like they’d hold more valuable information and I didn’t want to destroy that. This will remove the iframe but create a functioning link. I don’t like that screen readers will then read that link letter by letter but I can’t figure out a decent way to get a useful title from totally unknown iframe structures. It seems better than just removing the content in terms of creating a comparable experience.

function removeIframe(){ //destroy iframes and replace with their internal URL as a link
    var frames = document.querySelectorAll('iframe'), i;
    for (i = 0; i < frames.length; ++i) {
      var link = document.createElement('a');
      link.href = frames[i].src;
      frames[i].parentNode.replaceChild(link, frames[i]);

I know this doesn’t solve all problems, for instance I haven’t dealt with pages which load images via javascript after the ‘text only’ button is pushed. There are also a number of other fringe cases which haven’t been seen to be dealt with but I think this is a start.

One other useful bit of CSS has to do with tabbed navigation and onfocus being visible. This example uses the default browser behavior but it does seem to ensure that it occurs. I haven’t tested it widely but it addressed the issue of tabbed navigation working but not being visible on a couple of our sites.

*:focus, *:active{
    outline: 5px auto -webkit-focus-ring-color;
    outline-offset: -2px;

The tabbed navigation itself is a bit odd to me. Chrome navigates between elements in a way that I expect. Vivaldi behaves in a similar manner. Safari requires a modifier key (option – thanks Matt) and Firefox has an advanced setting where you can activate keyboard navigation but I didn’t have much success with it working.


Alternate versions seem acceptable according to the rule makers. What I don’t know is how that plays out in this world of automated assessments. When Siteimprove or the Office of Civil Rights assesses your site, does the machine click the ‘high contrast’ button? There are some nice WordPress plugins that add functionality like that to the site. WP Accessibility is one we have running on several sites. I think that meets the standards but I get a bit more hesitant when I read the reasoning behind permitting alternate versions. I probably worry more about machine scans and then having to argue with people after the fact.

I have lots of questions about what kind of image shouldn’t have alt text. I tend to put fairly obscure images at the top of my blog posts. I don’t think do much more than add something visually amusing4. I’m more than happy to have alt text there but I wonder when it is simply annoying and what level of alt text is needed to actually convey information. The qualitative aspect vs the technical meeting of the standard is something that I want to understand better.

1 It is so very nice to work with people. Even with the Internet, having people around doing the same things is very pleasant and useful.

2 Cue Alan’s comment with a link to one he built in Fortran in 1992.

3 I might need to revisit this one and do something better with any existing alt text.

4 and probably just amusing to me

Correct Names in Comments

We had some trouble with the selected display name not showing up correctly in comments. It worked fine in themes which displayed post and page authors but comments was often incorrect. That wasn’t good from a user experience perspective and also concerned me a bit in terms of what students might expect to be showing vs what actually was showing.

A bit of Google-ing prior to trying to write it from scratch led me to this post which I was able to add to a network activated plugin and be done with the issue.

//make sure comments reflect display name from
add_filter('get_comment_author', 'wpse31694_comment_author_display_name');
function wpse31694_comment_author_display_name($author) {
    global $comment;
    if (!empty($comment->user_id)){

    return $author;

I tend to link in the source of stuff I used to solve the problem1 in the plugin. That gives me an embedded reference/footnote in case I ever need to revisit it and it provides a kind of credit as well. Good for me. Possibly even good for the author of the fix.

Having a plugin network activated for fixes of this type is also handy. It keeps the plugin numbers down and ends up being a single place for adding/removing/troubleshooting random custom functions like this.

1 Harvard may not agree.

Weekly Web Harvest for 2017-09-03

  • Locus Online Perspectives » Cory Doctorow: Demon-Haunted World

    In 2015, HP pushed a fake security update to millions of Officejet owners, which showed up as a routine, ‘‘You must update your soft­ware’’ notification on their printers’ screens. Running that update installed a new, secret feature in your printer, with a long fuse. After six months’ wait, the infected printers all checked to see whether their ink cartridges had been refilled, or manufactured by third parties, and to refuse to print with any ink that HP hadn’t given its corporate blessing to.

  • CS50 Updates Course Policies, Asks Students To Go To Class | News | The Harvard Crimson

    Students are now “encouraged” to physically attend the course’s taped weekly lectures, according to the two-page document. Malan had previously tweaked the course policies in fall 2016 to make lecture attendance optional. Attendance is now also expected at every discussion section until the first mid-semester exam.

    Malan wrote Thursday that previous CS50 students had reported the online presentations lacked the energy of in-person lectures.

  • Meet Me in the Google Doc For, Uh… a Performance? | KQED Arts

    took part in a previous incarnation of the Google Doc as shared canvas. “We had no idea how it would develop,” she says. “Over three hours, the doc took on a life of its own. It grew from 1 page to 80 pages.”

    The archived version of that performance, A Work in Progress, resembles something like a Geocities site crossed with the early days of Facebook, when writing on a friend’s wall meant you could edit all previous messages left on its surface. (See it, in Google Docs, here.)

  • Song of the sausage creature

    some others hear the song of the Sausage Creature.

The Events Calendar Venue Issue

I’m a big fan of Events Calendar Pro. It makes all sorts of date related things in WordPress very pleasant. The free plugin also does a great job.

I did run into a bit of an issue this afternoon as I tried to take events I created in one site and get them into another. Since the events are a custom post type you use the normal WordPress Tools>Export to get them out.

The WordPress export screen showing Events as the designated export option selected.

That worked fine and I was able to import the events into the new site. The issue came with venues. I’d defined some Venues so I wouldn’t have to keep entering the same addresses again and again. I was able to export/import them in the same way I’d exported the events and they showed up fine as content.

Unfortunately, it seems like plugin references the venues via post1 IDs. My imported venues ended up with different IDs and the IDs reference by the events ended up being random WordPress posts (in the traditional sense). This led to venues with names like ‘untitled 4’ or ‘a moment of calm in online teaching.’ Trying to change them on the backend to the venues I’d imported led to weird duplications and the prior information displayed no matter what I did.

I didn’t have a huge number of events, maybe 13. Really just enough that I wasn’t willing to give up without a fight.

I took a quick scan of my export XML and searched for venue. I found two main chunks.


I opted to just remove the first piece and then try to re-import things. That did the trick.

It’s like that I could have set the 621 data in the example above to the ID of my new venue and I’d have gotten that to work rather than just unsetting the venue. I opted not to bother because I needed people to verify the rooms anyway.

Another small example of how you don’t actually need to know exactly what you’re doing to get things to (mostly) work.

1 All custom posts are posts even if you call them events or venues.

Troubleshooting WordPress

a feedwordpress screen that is empty of useful text that should show what feeds I have aggregating but doesn't

This is an attempt to explain a pattern of troubleshooting WordPress through a specific event and perhaps reinforce the need for me to be humble in all interactions with people.

So even if you never have this problem this might be useful.


An admin for one of our sites using FeedWordPress and suddenly can’t see any feeds in her syndicated sites view for that plugin. She sends me an email. I drop into the site and check. All looks good to me.

Sadly. Sadly. Sadly. I respond to her and say it seems to be working on my end . . . has she tried another browser, computer, login/logout/restart etc. It’s easy to end up assuming the person reporting the problem is wrong by default. I get a fair number of emails. Many of them, probably most of them, report problems that are more human than mechanical. It’s easy to fall into a trap of assuming it’s a human issue, especially if a superficial inspection confirms that suspicion. It’s also called a trap for a reason. Avoid it if at all possible and if you fall into it please attempt to climb out.1

A bit later she indicates that she has done these things and the problem persists. I go back to the site. It still works for me.

I now do what I should have done the first time. I assume her account permissions using User Switching. This plugin really lets you assume the role of the human you’re trying to help. You see what they see. Their restrictions are your restrictions. Instant empathy?

Presto. I am now seeing the error. At some point as I switch between my account and her account . . . my own account loses the ability to see the feeds. That is both a good and bad thing. Good in that I can now more easily replicate the issue without changing roles back and forth. Bad. In that the disease is spreading! Worse. The issue travels with me to other sites where I have FeedWordPress running.

In this process, I’m dumping various caches. I’m trying various browsers. I’m doing things in incognito.2

I invite Matt and Jeff to try with their super admin accounts. Matt can see initially but loses that ability. Jeff somehow remains infection free. I even ask Twitter what’s going on. Jeff does some mysql table repair/verifications. No dice.

So now I sort of know some things. The issue is not site specific. The issue travels with the user account to other sites.

That really makes me think something has somehow been set at the user level. That data is stored in the wp_usermeta table. I take a look in there and find that I have a lot of stuff there. My initial impulse it delete everything that isn’t in the default table description in the codex but I take a minute and scan for a bit . . . and find two rows with feedwordpress in them.


Deleting those two lines heals my account. I go to the faculty member’s account and find the same thing. I delete them and she is healed as well. I celebrate in a quiet way as it is nearly 10PM and my kids ought to be asleep.

In further experiments with Matt this AM, it looks like we could have just deleted the metabox hidden row. I’m also still not sure how this setting was set but I’m taking it as a victory for now.

Big Picture

I need to work harder on putting humans first and taking the time to make sure I’m assuming they are right and have good intentions. It’s easy to let that slip when lots is happening. It is easy to get frustrated doing technical support. No self-flagellation here, I think I do a good job of that most of the time but I need to stay on top of it. I don’t want to end up a bitter tech troll at the bottom of a bit cursing the sun and the humanssssssss.

And technically, if issues follows specific users, but not all users, between sites check the wp_usermeta table sooner rather than later.

1 Lying at the bottom while slowly becoming less and less human is an option but one I would not recommend.

2 Very handy for various things. Keyboard shortcut on the Mac is command+option+n)

Weekly Web Harvest for 2017-08-27

echo wp_oembed_get fix

echo wp_oembed_get fix

Pure click-bait gold, baby!1

You know I’m focused on those high-traffic titles.

And now on to the show . . .

I’m doing a site for the esteemed Jon Becker’s school law class. The goal is to take tweets that exemplify really bad legal choices by public school administrators. They even have a hashtag – #schoollawwtf.

Since we’re taking tweets into WordPress for further analysis we end up with some weird constraints. I can’t rely on useful titles if we want to automate this as the tweet content might contain any number of things and the regex to try to purify it wouldn’t be worth the hassle.

New content wouldn’t have any body text either because it’s just a tweet. Granted, I could duplicate that text in the body but I didn’t really see much point in that.

I opted to stick the tweet URL in a custom field. That soon led me to the handy wp_oembed_get function which was new to me.2 That worked very nicely for display on single posts (screenshot and code snippet below).

 if (get_post_meta(get_the_ID(), 'tweet', true)) {
        echo wp_oembed_get(get_post_meta(get_the_ID(), 'tweet', true));

Where it ended up failing me was when we needed to display a bunch of tweets in need of analysis. All I had were the Twitter oEmbed element to show and clicking on them would take you to Twitter-land rather than to thee blog post like I needed. No big deal, I figured I’d throw a div over the top of the tweet, put my a link around that3 and be good to go. That’s not quite what ended up happening.

It’s a bit hard to explain but no matter how many different paths I tried the a link would close with nothing in it. You can see in the screenshot below. I end up with two empty a links with nothing to click on. Strange and really frustrating. I tried many, many other combinations . . . pulled things into functions, tried printf, wrote all the HTML together first, etc. etc. Nothing worked.
echo wp_oembed_get fix

I finally decided to give up on the php route and do it in javascript. This ended up being almost painfully easy.

The div was already over the top so I just needed to turn it into a link that went where I desired. For me, that usually means going the data attribute route.4 Easiest thing I had handy was the post ID.

echo '<div class="wtf-tweet-holder" data-link="' . get_the_ID() . '">';

Now to for the javascript to make them clickable.

function twitterLinks (){
	var url = WPURLS.siteurl + '/?p='; //sets a nice base URL based on localizing the script in the functions.php 
	jQuery(".wtf-tweet-holder").click(function() { //get all the divs with class .wtf-tweet-holder
		window.location = url + jQuery(this).data('link');//create the url using the data-link at the ID

One of the other useful things I found out in this process was that Twitter treats retweets and quote tweets very differently than replies.

This is a quote tweet. On the embed, you essentially lose the quoted tweet entirely which sucks. It’s there on Twitter’s timeline but not on the embed.

While a conversation (replying to a Tweet and using our hashtag) gets a conversation you can embed like so (but which looks much odder on Twitter’s timeline).

1 My wife insisted I add the comma. She claimed it wasn’t possible I really meant a solid gold click-bait baby despite my insistence that I meant exactly that.

2 I really need to sit down and just read the whole codex.

3 Valid in HTML5 and all 50 states and Puerto Rico.

4 Really sad how much I like data attributes.

Web Development Podcasts

strange image using headphones as eyes

My podcast listening ebbs and flows.

I am currently in the flow state.1

Anyway, I like these three podcasts that are all web development related.2

1 That sounds weird but ebb wouldn’t make any sense.

2 I’m also listening to some strange fitness/weight lifting podcasts which make these seem mainstream.

KSES Allow Twitter Widget Embed

$allowedposttags["script"] = array();
$allowedposttags['a']['data-widget-id'] = true;

The two little lines above keep the Twitter tag search widget embed code (below) from getting cleansed in the WordPress Editor.

            <a class="twitter-timeline"  href="" data-widget-id="832281528470216705">Tweets about #vcusocy OR #digisoc OR #digitaldata OR #socydigitaldata</a>
            <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);;js.src=p+"://";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>

Keeping a chunk of these extra-curricular allowed elements in a plugin allows us to activate them on a per trusted user basis.

Contact us

Academic Learning Transformation Lab - ALT Lab
1000 Floyd Ave, Suite 4102 | Richmond, Virginia 23284 | 804-827-5181

Last updated: April 27, 2016

Virginia Commonwealth University

HTML tutorial