Half-Elf on Tech

Thoughts From a Professional Lesbian

Tag: design

  • Data Structure

    Data Structure

    At WordCamp US, Tracy turned to me and said “I want to do something about the actors on our site.”

    Her idea was that, based on the traffic on our sites, people wanted to know a little more about the actors. The way I’d built out the site, you could get a list of all of an actor’s characters, but you couldn’t really get at everything. Tracy explained to me what people were searching for (actors who were queer, or not) and I mulled over the possibilities, sketching out three solutions.

    1. Facet and Smart PHP

    We originally added in actors as a plain-text field, saved as an array, for all names associated with a character. In using this, with FacetWP, it was trivial to look for all characters played by Ali Liebert. We also already had in a repeatable field, so we could put the ‘most prominent’ actor on top (see “Sara Lance”).

    However what was not trivial was the idea of identifying if an actor was queer. You see some characters have multiple actors, and while today all are either queer or not, one day they may not be. I pointed this out to Tracy using the Sara Lance conundrum and Tracy cried ‘Whhhyyyyyyyy?’ and lay down on the floor.

    2. Taxonomies

    Characters already have a bunch of custom taxonomies, and I considered extending that to a new taxonomy for actors. That would immediately provide organizations, and adding new actors is easy on the fly. With auto-complete, we could get away from the drama of my inability to spell names (or autocorrect’s inability to believe me that in this case, I is before C).

    But… Taxonomies lack extendability. Even with a mess of custom meta added in for featured images, we wouldn’t have an ‘easy’ way to track all trans actors. And we wouldn’t have enough of a future.

    3. Custom Post Types

    This is what we actually decided to use. A custom page for each actor. We added in two new taxonomies for actor gender identity and sexual orientation, which are then used to determine if the actor is queer or not. It gives us the most control and extendability of the choices, and the nice permalink.

    There are two significant downsides to this. First, you have to add in a page for the actor before you add in the character page. Second, I had to ‘reproduce’ a loop to list all the characters played by an actor. However I was reusing the same logic as I do for shows which made it easier than it might have been.

    What It Means

    Understanding and predicting an unknown future is hard. It’s near impossible. You have to guess what you want things to be, and as I have said many times with the building out of LezWatchTV, you must be alright with being wrong.

  • Data Based Sites

    Data Based Sites

    Designing your website involves understanding the structure of the data within. Designing your data comes down to how you store it. At its base level, everything on your site is a post, but the way you handle the data WITHIN the posts is how you can plan for growth, adaption, adoption, and the future. Building a site today involves making sure the data is easily consumable by multiple formats, like AMP, JSON APIs, and Alexa Echo Skills. And it all starts with understanding the data you’re using. Even if that data is from TV.

    Television is chewing gum for the eyes

    I love television. I love books, I’m always reading and writing, and I love radio. I like movies. But TV is something weird and wonderful. TV is escapism when a story brings you someplace new and amazing.

    One of the reason I love tv is that I see myself reflected in media. I’m a Jewish lesbian. Growing up, I didn’t see a lot of me on TV. Any, really. If I think about it, the first Jewish Lesbian I can remember seeing is Willow Rosenberg from Buffy. Yeah. I was out of college by then.

    Representation Matters

    In the entirety of television, world wide, there are about 2000 queer females. Total. Yeah. 2000. That’s on about 600 shows. There are not a lot of them, and I know the numbers because I run, with Phillys very own Tracy, a site that uses WordPress to record all of them. That’s right, I have the data.

    Data Driven Design

    This isn’t about themes. I can’t design themes. I don’t. I’m bad at it, I know that, sorry Tracy. And when we set about making this site, we had some lofty goals and ideas and we learned some lessons by prejudging the data. Originally we wanted to simply list shows and if you should watch them or not, and list the characters but…

    Somewhere around 100 characters and fifty shows, it became clear that the datasets we’d defined were underestimated and over-complicated and over-simplified. We had to consider what made a show good or bad. We had to consider the situation. And we had to make changes.

    When you build out any site, you have an idea of what you want. Maybe like us you make a massive list of everything you want to track and get dragged down into the weeds fast. Maybe you make a small list and have to go back and edit. In the end, the trick of it all is planning your site based on your data.

    Even after you do all that planning, you’re going to find out you missed things. You’ll overestimate things. You’re going to underestimate others. People are going to use your data in unpredictable ways. This is just how the world works. So you have to design your code to adapt.

    How to Design for Data

    This is about planning code. Designing your site for data comes down to how you store it. At its base level, everything on our site is a post. There are two types, shows and characters, and all posts have a bevy of ‘meta’ data for the various bits of information.

    What information?

    Shows: tropes, airdates, thumb score, why that score, tv stations, nations, genres, formats, gold star, trigger warnings, quality rating, screentime rating, realness rating, timeline, episodes, & ‘ships.

    Characters: clichés, actor, sexuality, gender, date of death, tv show & role on show.

    So all that is what we record. It’s grown and shrunk. We had urls in there and removed them because it was impossible to upkeep when fansites vanish. I removed and restored ‘ships, after figuring out how to store all of it in a searchable way. But with all that data, we started to see the big picture. And then … we realized how the data was stored mattered.

    Understand What Your Data Is (And Isn’t)

    Most of the data is simple. Ratings are a 1-5 option. Trigger warnings were check boxes for a binary on or off … Were. Sexuality and gender are dropdown lists, and so are tropes and cliches. Managing those is easy. Ish. We understand taxonomies, at least, being WordPess developers.

    Most of the time, data is obvious. Again, I have items that are a binary. A yes or a no. And while I personally believe that sexuality and gender are a spectrum, TV hasn’t caught up there, so that can be stored as a one to one dropdown. You are what you are. The same goes for a character being on a TV show. It’s all one or the other.

    Having said all that, let me introduce you to Sara Lance, as played by Caity Lotz. Schrödinger’s bisexual time traveling action hero.

    The Complex Data: Sara Lance

    Schrödinger’s bisexual time traveling action hero assassin pirate captain.

    Sara Lance has two actors. She’s been on three shows in three separate capacities; guest, recurring, and regular. She’s died and came back to life. Sara Lance exists to make me, as a developer, cry. Because for her I have to store all of that data in a searchable manner that plain-text post meta doesn’t make easy. She made me rethink all our data storage.

    Nothing about Sara is simple. Nothing is straightforward. Not even the existing taxonomies and lists stayed the same. Both gender and Sexuality went from a simple dropdown to a taxonomy. We moved from gay, straight, or bi, to include pansexual and asexual and I’m just waiting for Sara to step into pansexuality, y’all.

    Use WordPress First

    As much as possible, use WordPress. Taxonomies are heavily used for ‘lists’ like cliches and tropes and tv stations, because they come with built in sortables. I can easily list all shows on NBC or all characters who are parents, because those are taxonomies. Even short lists like sexuality and gender work well for that. For the rest, it’s all post meta.

    Sara exists beyond taxonomies. Originally, we had death stored as a simple taxonomy item for character cliches. If you were dead, you got the cliche of dead. Sara came along and died. And came back. So suddenly we had to rethink if someone kept the tags if they died and came back. Pro tip? They don’t. That was a quick decision, though. Don’t worry, she made us make harder decisions.

    Use Plugins Second

    I mentioned everything that isn’t a taxonomy is post meta. Adding metadata to posts that aren’t taxonomies sucks. Yes, I said it. It sucks. Plugins like CMB2 or ACF will save your vegan bacon by making it easier to create a check box or a dropdown or a plain text field, like for actors.

    Sara had two actors. While the field for actor is only plain text, and that’s relatively simple, we had to make it repeatable so we could add multiple actors. God help me, date of death had to be repeatable too. What if Sara dies again!? CMB2 has repeatable fields built in.

    Use Third Party Add-Ons Third

    The bigger the data got, the more important admin design became. The more tropes, the worse a dropdown or multi-check section was. By using a select2 addon, and some custom save code, I was able to convert taxonomies into an auto-complete, which is a lot easier to visualize. So are groups. By clumping related data together, the brain makes the right connextions. And when it’s repeatable, your page grows with the data is uses, not with the data total.

    Sara has three TV shows. THREE!

    Sara’s page is much bigger than anyone else’s because she has three shows, and each show section has a dropdown for character role and another for the show name. And I can’t guess if she’s going to show up on another, like Supergirl maybe. CMB2 does have a limit to repeatable fields and groups, though. I hope Sara doesn’t hit it…

    Be Willing to Make Changes Fourth

    You will be wrong. I removed the list of ships, relationships, from shows. Tracy was sad. I added it back. My bad, totally, and my reasoning was that it was not easy to maintain and manage in a searchable way. It wasn’t. But it could be. And I made it. Be willing to be wrong, to make mistakes, and to recover from them.

    Because … Sara is always changing. Alive, dead, new show, new actor… Sara is always changing and always adapting and always being more awesome. She’s anything but static, and that’s a good thing. Sara Lance made me throw my preconceived notions of data storage and organization out the window. And I’m better for it.

  • Remotely Hosting SVGs

    Remotely Hosting SVGs

    I prefer to use SVGs whenever possible instead of pngs or font icons. They can be resized, they can be colored, and they’re relatively small. But I also have a set of 700 icons I use and I don’t want to have to copy them to every single site. Instead, I’d like to have them all on a central repository and call them remotely.

    To The Cloud

    You can use S3 or really anything for this, but I chose DreamObjects since it’s open source and I work for DreamHost.

    For this to work, you create a bucket in DreamObjects with whatever name you want. I tend to name them after the website I’m working on, but in this case I’m making what is essentially a media library so a better bucket name would be the service. Keep in mind, while you can make a DNS alias like media.mydomain.com for this, you cannot use that with https at this time. Sucks. I know.

    On DreamObjects, the accessible URL will be BUCKET.objects-us-east-1.dream.io — hang on to that. We’ll need it in a bit.

    Upload Your Files

    Since I plan to use this as a collective for ‘media’ related to a network of sites, I named the bucket for the network and then made subfolders:

    • backups
    • site1
    • site2
    • svg
    • svgcolor

    Backups is for everything you’re thinking. Site1 and Site2 are special folders for files unique to those domains only. Think large videos or a podcast. Since they’re not updated a lot, and I want them accessible without draining my server resources, the cloud is perfect. I separated my SVG files into two reasonable folders, because I plan to generate a list of these later.

    Calling An Individual File

    This is the much easier part. In general, PHP can use file_get_contents() for this. But we’re on WordPress and there is a more reliable way about this.

    $svg = wp_remote_get( 'https://BUCKET.objects-us-east-1.dream.io/svg/ICON.svg' );
    if ( $svg['response']['code'] !== '404' ) {
    	$icon = $svg['body'];
    }
    

    By using wp_remote_get it’s possible to check if the file exists before displaying the content of the body. Which is, indeed, how one displays the content.

    The reason, by the way, we want to use wp_remote_get and not file_get_contents is that there’s no way to check if the file exists with the latter. You could still use file_get_contents to display the file, but once you’ve done the remote get, you may as well use it.

    Getting a List Of All SVGs

    I’d done this before with local images, getting a list of all the SVGs. You can’t do a foreach of a remote folder like that. So this is a little messier. You’ll need the Amazon AWS SDK for PHP for this. I’ve tested this on the latest of the 2 branch – 2.8.31 – and the 3 branch – 3.32.3 and the code is different but can work.

    In both cases, I downloaded the .phar file and included it in a function that I used to save a file with a list of the image names in them. By doing that, I can have other functions call the file and not have to query DreamObjects every time I want to get a list.

    function get_icons() {
    	include_once( dirname( __FILE__ ) . '/aws.phar' );
    
    	$svgicons = '';
    
    	// AWS SDK Code Goes Here
    
    	$upload_dir = wp_upload_dir();
    	$this_file  = $upload_dir['basedir'] . '/svgicons.txt';
    	$open_file  = fopen( $this_file, 'wa+' );
    	$write_file = fputs( $open_file, $svgicons );
    	fclose( $open_file );
    }
    

    I left out the SDK code. Let’s do that now.

    SDK V2

    The V2 is actually what’s still officially supported by CEPH, but the PHAR file is larger.

    	Version 2
    	$client = Aws\S3\S3Client::factory(array(
    		'base_url' => 'https://objects-us-east-1.dream.io',
    		'key'      => AWS_ACCESS_KEY_ID,
    		'secret'   => AWS_SECRET_ACCESS_KEY,
    		'version' => 'latest',
    		'region'  => 'us-east-1',
    	));
    
    	$files = $client->getIterator( 'ListObjects', array(
    		'Bucket' => 'BUCKET',
    		'Prefix' => 'svg/',
    	));
    
    
    	foreach ( $files as $file ) {
    		if ( strpos( $file['Key'], '.svg' ) !== false ) {
    			$name         = strtolower( substr( $file['Key'] , 0, strrpos( $file['Key'] , ".") ) );
    			$name         = str_replace( 'svg/', '', $name );
    			$symbolicons .= "$name\r\n";
    		}
    	}
    

    SDK V3

    I would recommend using V3 if possible. Since you’re only using it to get data and not write, it’s fine to use, even if it’s not supported.

    	// Version 3
    	$s3 = new Aws\S3\S3Client([
    		'version' => 'latest',
    		'region'  => 'us-east-1',
    		'endpoint' => 'https://objects-us-east-1.dream.io',
    		'credentials' => [
    			'key'    => AWS_ACCESS_KEY_ID,
    			'secret' => AWS_SECRET_ACCESS_KEY,
    		]
    	]);
    
    	$files = $s3->getPaginator( 'ListObjects', [
    		'Bucket' => 'BUCKET',
    		'Prefix' => 'svg/',
    	]);
    
    	foreach ( $files as $file ) {
    		foreach ( $file['Contents'] as $item ) {
    	
    			if ( strpos( $item['Key'], '.svg' ) !== false ) {
    				$name = strtolower( substr( $item['Key'] , 0, strrpos( $item['Key'] , ".") ) );
    				$name = str_replace( 'svg/', '', $name );
    				$symbolicons .= "$name\r\n";
    			}
    		}
    	}
    

    Side Note…

    If you’re on DreamHost, you’ll want to add this to your phprc file:

    extension=phar.so
    detect_unicode = Off
    phar.readonly = Off
    phar.require_hash = Off
    suhosin.executor.include.whitelist = phar
    

    That way it knows to run phar files properly. And by the way, that’s part of why phar files aren’t allowed in your WordPress plugins.

    Which is Better?

    That’s a difficult question. When it comes to loading them on the front end, it makes little difference. And having them on a CDN or a cloud service is generally better. It also means I don’t have to push the same 400 or so files to multiple servers. On the other hand, calling files from yet another domain gets you a down check on most site speed checks… But the joke’s on them. The image is loaded in PHP.

    Of course the massive downside is that if the cloud is down my site can be kinda jacked. But that’s why using a check on the response code is your lifeline.

  • Where Did Underline Go?

    Where Did Underline Go?

    As of WordPress 4.7, the visual editor no longer has a button for underline. There were a lot of reasons for this, but primary are two:

    1. Space is not limitless.
    2. Underlining looks like links.

    Naturally someone complained that we were breaking style guides:

    When referencing a source of information it is correct form to underline the title of the source.

    They happen to be wrong. Let me explain.

    The Web Is Not Print

    We use double spaces to indicate the end of a sentence in printed works. We don’t on the Internet. It took me a long time to get used to that, and if you look back on my older posts, you’d see it all over the place. The point here is that we know you don’t use the same punctuation and style you might use online as you do on paper.

    I look to the grandpappy of web, Jakob Nielsen, for some backup here. Your writing style for the web is different from print. A lot different. In Writing Style for Print vs. Web he says:

    In linear media — such as print and TV — people expect you to construct their experience for them. Readers are willing to follow the author’s lead.

    In non-linear hypertext, the rules reverse. Users want to construct their own experience by piecing together content from multiple sources, emphasizing their desires in the current moment. People arrive at a website with a goal in mind, and they are ruthless in pursuing their own interest and in rejecting whatever the site is trying to push. Banner blindness is only the most extreme manifestation of this selfishness.

    But that talks about the way we write and not the design of what it looks like. Web and print design are wildly different too. For newspapers, you have to consider the width of the columns. If you’ve never taken a journalism course, there’s as much about layouts as there is about writing a solid lede.

    Good Writing Has Rules

    I’m a huge fan of Strunk & White’s The Elements of Style. My wife has a copy and, when we met, she found my grammar to be deplorable and used to wave it at me a lot. Having read it multiple times (yes, I do re-read it) I’ve found my communication skills have been catapulted because of the directions. People ask me why I’m a good speaker and the answer is because I’m a good writer.

    One of the lessons from Strunk & White is to use the active voice, for example, which is something Nielsen points out as well. You need to engage your readers. You need to bring them on a journey and make it theirs as much as yours. To do that, you need to understand the rules of the language in which you’re writing.

    Content Must Not Confuse By Context

    Going back to the heart of the matter, why is it okay that WordPress killed the underline button? It was confusing.

    Originally we underlined links because it was easy and being consistent about a display reduced the chances for misunderstandings. Why were they underlined and blue? I actually have no idea. I looked it up but was unable to find a solid answer. My theory was that blue would stand out against the standard grey background as well as the black words so everyone knew what it was for. Similarly, on a monochrome screen, which was very common in the day, an underline would stand out (as it happens, Sir Tim Berners-Lee picked blue totally by happenstance).

    Why underline and not bold or italics? My guess is that since underlining is not actually standard practice for writers, it was a safe grab. Otto pointed out that old-old systems always had underlines, but not always italics or bold, so that weighed heavily into the decision as well, clearly.

    In a word, it wasn’t confusing. It was consistent.

    It’s Actually Italics

    Did you double take when I said underlining wasn’t standard practice? Surprise! Let me appeal to Misters Strunk & White on a few matters of form:

    Titles. For the titles of literary works, scholarly usage prefers italics with capitalized initials. The usage of editors and publishers varies, some using italics with capitalized initials, others using Roman with capitalized initials and with or without quotation marks. Use italics (indicated in manuscript by underscoring), except in writing for a periodical that follows a different practice. Omit initial A or The from titles when you place the possessive before them.

    The Iliad; the Odyssey; As You Like It; To a Skylark; The Newcomes; A Tale of Two Cities;Dickens’s Tale of Two Cities.

    Notice the direction to use italics? The talk of a manuscript is in reference to the fact that most people wrote manuscripts by hand or on typewriters that didn’t have italics. I remember having to type a line, and then backspace to add in the underline manually. Have you ever tried to write italics manually? It’s not easy!

    The web is not handwritten. Computers in 2016 can handle italics.

    And it’s not just Strunk & White. Harvard’s documentation on citation doesn’t recommend underlining at all. The MLA (Modern Language Association) says, as of this year, to use italics for large works like books and magazines, but quotes for short ones in titles. The Chicago Style Guide reads the same.

    Use Italics, Not Underline

    If you skip the whole post, let me make this simple for you: The title of a source should be italicized.

  • AMP It Up

    AMP It Up

    We’ve all heard about how Google wants to make mobile pages faster. The Accelerated Mobile Pages (AMP) Project is there to deliver and process a pared down version of a webpage, prioritizing speed. Since speed is important to your SEO, and I’m on a bit of an SEO kick, you bet it was next on my to-do list.

    I admit, Joost talked about this at his WordCamp US talk this year, and among my notes was this:

    Add AMP – not set it and forget it

    This is so, so true.

    The AMP Plugin

    First its like all things WordPress, you install the plugin AMP by Automattic and activate it. That does the easy work. Of course then you have to customize the hell out of it to make it look right. Still, out of the box the plugin adds a /amp/ so if you go to https://halfelf.org/2016/amp-it-up/amp/ then you’ll see my AMPlified pages. If you’re using Multisite, you may need to re-save your permalinks for the URL to work.

    There are some big warnings about this though.

    1) No analytics tracking
    2) You don’t get to design your AMP page
    3) It doesn’t work on the front page or pages or cpts

    Don’t worry! We can fix all that!

    Analytics

    If you’re using Monster Insights for Analytics, supposedly they added in some code to make tracking work, but I was unable to find it in the code or documentation. More than likely it’s in their Pro version. I don’t use that plugin simply because I found it easier to use a 28 line mu-plugin for my network and I don’t need to see my stats all the time. I used the AMP WP recommended method and put it in the same mu-plugin as I have my regular analytics.

    Design

    This is a little messy. Design is a very complicated word. If you just want to change the colors, you can do this via Appearance > AMP. Whaaaat!? That’s right, it lets you change the header color and font color right there. Super simple. If, though, you want to make your CSS tweaks directly to change that light blue header to navy, perhaps, you can follow the AMP WP directions for CSS additions and have this:

    add_action( 'amp_post_template_css', 'halfelf_amp_css' );
    function halfelf_amp_css( $amp_template ) { 
    	?>
    	.amp-wp-header {
    		background-color: #013659;
    	}
        <?php
    }
    

    I strongly recommend making few changes. Oh, color of course, but don’t go and make a 1 meg CSS file. The point of AMP is to load faster, after all!

    There’s a whole second level of design that I’ll get into later. It needs its own post.

    AMP your CPTS

    Right now you can only do it via code. The AMP WP directions for CPTs state they may come up with a better way, but for now you do this:

    add_action( 'amp_init', 'my_amp_add_this_cpt' );
    function my_amp_add_chars_cpt() {
        add_post_type_support( 'post_type_this', AMP_QUERY_VAR );
    }
    

    It’s pretty direct, and I added this in the bottom of my existing CPT code.

  • Long Term Vision

    Long Term Vision

    Say what you will about Jetpack, the plugin serves a great purpose in a few major ways.

    1. Once you register for the API, you never have to again.
    2. Everything is easy to find to update and configure (Menu -> Jetpack).
    3. New Features are added and you don’t need to install a new plugin.

    Now look at something else. A company released over a dozen Facebook plugins. All the plugins required you to connect via their API (a separate connection in each). All the plugins required you to use their admin panel to set up a per-plugin configuration. All the plugins deleted those settings on deactivation. Or how about a WooCommerce related set of plugins that all required the use of their API (legitimately) but all the plugin did was connect you and send you to where that specific plugin part was configured?

    Got that in your head? Good. Now what if Jetpack did that? What if to enable aspect of Jetpack you had to install Jetpack Stats, Jetpack Comment Form, Jetpack Subscriptions, etc etc etc.

    You’d hate Jetpack. And worse, the Jetpack developers would too. They’d have to work extra hard to ensure all the suite of plugins conformed to style and protocol. Shared libraries? Gotta update them in all of the plugins. Oh and don’t forget to make sure they’re all backwards compatible in case someone updates one but not another. Figure out which one takes priority, make sure someone else’s changes on Stats doesn’t break Comment Form, and on and on and on.

    There’s a reason Jetpack works as well as it does, and it’s not just because Automattic is behind it. Jetpack has one sign up, one registration, one setup for the connection. Each sub-app is toggled via Jetpack. New additions, when the main plugin is updated, are all easily checked for backcompat and everyone tests together before pushing out.

    So why do I call this the long view?

    Because the long view considers not just adding new users to your system, but keeping them in a way that makes them happy. The long view looks at the reality that your developers will leave. The long view thinks about the easiest way to maintain a lot of code. The long view makes sure that introducing old users to new things is easy.

    And that means, the long view would look at your 15 or 20 plugins that all use the same ‘base library’ and tell you it’s a shitty plan. It’s more hours on more code with more potential conflicts. It’s less cross-code checking. It’s more testing. It’s more unit tests that have to be repeated over and over.

    The biggest reason I see people argue that 18 plugins is better than 1 is ‘SEO.’ The quotes are there on purpose. Because it’s bullshit. Anyone who thinks 18 plugins will net you better SEO than one, well written, well curated document file on the master plugin has failed at SEO school and needs to meet Ted. Ted is a 12 inch lead pipe that the boss keeps in the top drawer of his desk at DreamHost. No, not really. But the point remains, they’re not an SEO Expert.

    Content is king. Remember that? Duplicate content is bad.

    However, in some cases, content is deliberately duplicated across domains in an attempt to manipulate search engine rankings or win more traffic. Deceptive practices like this can result in a poor user experience, when a visitor sees substantially the same content repeated within a set of search results.

    That applies to your code too. Duplicate code, duplicate functionality, is bad.

    Now there is always a time and a place for multiple separate plugins. I only want to use Easy Digital Downloads extension for Stripe, not any other payment gateway. So I don’t need the extra plugins in a ‘payment gateway suite.’ But there, EDD cleverly has all the base code in their plugin and the add-ons just enable more features. Yoast’s Video SEO is similarly an add-on. They didn’t waste time making a dupe of their main SEO plugin just to add in videos.

    I hope the point is made. You can make your code simpler, easier to maintain, and easier for your users to find the new things if you keep it all in one. And that is a win.