Half-Elf on Tech

Thoughts From a Professional Lesbian

Author: Ipstenu (Mika Epstein)

  • You Don’t Need a Block

    You Don’t Need a Block

    Like a great many people, I recognize the need to learn the new world with Gutenberg and adapt my code as well as my writing to the platform. But, like a great many people, I recognized my coding ability might not quite be up to snuff with the javascript required for blocks.

    But then I asked myself something important. And you should ask yourself this, before you lament about how much work you have ahead.

    Do I need a new block?

    What’s a Block Anyway?

    The concept of ‘block’ writing is one people who use Scrivner may be familiar with. Or maybe if you’ve ever been a part of a writer’s room, breaking down a season of a TV show. The idea is that each index card is it’s own entity.’ Or rather, in the case of WordPress, each paragraph is it’s own entity.

    This means you can move the paragraphs around, which for paragraphs makes little sense. But for layout? Oh it makes a great deal more sense. A block is, literally, a block you move around until your page looks the way you want it to. Awesome.

    Why Don’t We Need Them?

    Actually the question should be when don’t we need them? Obviously we need blocks. That won’t change. But by default WordPress has quite a number of blocks out of the … block. And that begs the question of when and why do we need to make new ones?

    This is a question many developers who have shortcode plugins will be asking themselves, and the realization I stumbled across at WordCamp San Diego is that … a lot of developers don’t need to make new blocks! Because a lot of shortcodes aren’t actually going to be all that necessary in the future.

    Let’s use an example of something common…

    Example Shortcode: Spoilers

    Let’s say you have a WordPress site and it sometimes talks about spoilers.

    River Song warning the Doctor about Spoilers

    Today in WordPress an easy way to put a warning at the top of every page would be with a shortcode that looks like [spoilers] or if you’re feeling puckish, [spoilers warning="OMG SPIDERS!!!"] 

    Those would output a simple paragraph that warned people about spoilers.

    Right away, I thought “Oh, that would be a nice, easy sort of thing to turn into a block.” It’s just a direct output of some code:

    <div class="alert alert-danger" role="alert"><strong>' . $warning . '</strong></div>

    But then I thought …. What if I don’t?

    Enter Shared Blocks

    Shared Blocks, formerly called reusable blocks, are blocks of content defined by each site, specific to the site, that are .. well .. reusable. You don’t need to know how to code to make them, either. Which means you don’t need a developer to do this. Start by just making a new block with the content:

    Warning: This post contains spoilers!

    That’s easy. But what we want is to apply color to it. And that can be done in a number of ways. The easiest would be to use the advanced section in the block editor and add an additional CSS Class of, in this case, alerts.

    But that isn’t the only way…. Because I can also make this:

    Whaaat? Total game changer!

    Gutenberg Blocks Are Editable

    In every single Gutenberg block you can change text and color to suit your needs. I edited that particular block and said I wanted the background to be one color, the next another, and I wanted the size to be Large. I’m aware the large size doesn’t show properly… I also told it how I wanted the block alightment to look:

    Example of a block being edited

    Okay, But Reusing?

    Don’t worry, I didn’t forget. When you hover over a block there are three vertical icons on the right indicating a menu. Click on the menu and you get options and one is to convert it to a shared block. Click on that, give it the name you want, and you’ve created a block!

    Shared Block
    The share icon in the lower right is how you know.

    And now, when you go to enter a new block, you click on the plus button on the left, click on ‘Shared,’ and you have this:

    Example of searching for a spoilers block

    What’s Missing?

    Right away you’ll notice you can’t edit the shared block without editing it for everyone. So if you made it “Aaaaaahhh! Spiders!!!!!” everything would change. And that’s not great for everyone. But for a lot of people who just want a simple, repeatable, notice or signature, this is just fine. 

    It won’t spare you having to convert some of your shortcodes to blocks, but it may make life easier for people who don’t want to have to use them in the first place. And that, I think, is a win.

  • AutoDeploy: Github to DreamObjects

    AutoDeploy: Github to DreamObjects

    There are a lot of things that Github makes easy. One of them is a great way to keep versions of data publicly accessible, trackable, and deployable.

    Well. Not so much that last one.

    Automated deployment with Github can be incredibly convoluted, twisted, and perplexing. If you don’t speak high geek, it’s worse. Thankfully there are services like Codeship that let you ship code, run tests, and more importantly, run some hefty commands.

    When the day came that I wanted to keep some JSON files on Github for version control, but deploy them to the cloud, I knew what to do. I was already doing a version of the process, in reverse, for my Remoteless SVG images, after all.

    Create Your Repository

    Now I’m using Github, but Codeship supports Bitbucket or Gitlab, so that’s also an option. Once you’ve made your repository, commit your code but don’t push anything yet! We have to make a couple decisions first.

    First: Branches.

    I have two philosophies of this. If I’m working on something like a plugin or a theme or an app that needs versioned releases, I’m going to name my branches REL_1.2.3 and so on. If, instead, I’m maintaining a theme or plugin for personal use, I have a development branch that I use for all normal dev work. I may spin up a special branch for some new feature, but it always goes into that dev branch first.

    Second: Deployments.

    The reason I use that branch system is that when I push to the dev branch, it pushes code to the dev server.

    Schnieder from One Day at a Time (2017) going 'Mind blown'
    Mind? Blown.

    Once you decide how you want your set up to deploy, and when, you’re ready to Ship That Code.

    Gettit? Right…

    Setup Codeship

    If you’ve never setup Codeship before, I explain how you do that in my post about Deploying from Github with Codeship. The special sauce here is your Custom Script.

    Before you write the script, add in Environment Variables for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY with those names specifically. This way you won’t have to write a mess of custom code.

    pip install 
    awscli aws s3 --endpoint-url https://objects-us-east-1.dream.io sync ~/clone/ s3://bucket-name/

    The important bits:

    • Endpoint URL is my S3-esque host
    • bucket-name is my bucket name…

    Push Your Code

    Once that’s saved, you can push code and it’ll automatically kick the code to the cloud.

    A lot of this is obviously a backwards implementation of code I already described, but sometimes we need something explained in the straightforward way to help us move forward.

    Enjoy your deploys!

  • Posts by Day, Every Year

    Posts by Day, Every Year

    In my previous post I mentioned a site that has a tag for a date. That is, it uses 25-march (or march-25) to tag it’s posts so someone could conceivably find all the posts made on March 25th in every single year.

    WordPress makes it easy to list all the posts on a specific date. Just visit example.com/2018/04/19/ and you’ll see all the posts made on April 19th of this year. Remove the 19 and you get everything from April and so on and so forth.

    But you can’t, out of the box, list everything on April 19th from every single year the site’s been up.

    WP_Query has Dates

    As of 3.7, WordPress has a date_query aspect to WP_Query which lets you do this:

    $all_posts_on_this_date = new WP_Query( array(
        'posts_per_page' => -1, // this will show all the posts
        'date_query' => array(
            array(
                'month' => date( 'n', current_time( 'timestamp' ) ),
                'day'   => date( 'j', current_time( 'timestamp' ) )
            ),
        ),
    ) );
    

    That generates an array of every single post that has the same month and day of today, but does not check the year. If you don’t want all the posts, just the last ten, use 'posts_per_page' => 10, instead.

    Once you have your list of posts, you can use a normal loop to display the content:

    if ( $all_posts_on_this_date->have_posts() ){
        while( $all_posts_on_this_date->have_posts() ) {
            $all_posts_on_this_date->the_post();
            the_title();
        }
    }
    
  • Organization

    Organization

    In September 2005, Lorelle wrote what I consider to be the definitive piece on tags vs categories. In 12 years, my opinions have not changed and I still feel her explanation is correct. That said, there is room for improvement at scale.

    The Gist

    Her advice boils down to this:

    • Categories are a table of contents
    • Tags are index words

    By this we mean that categories are the high-level, big ticket items, and tags are the smaller, more precise terms. This is, I feel, the heart of understanding the two.

    Further down, Lorelle states that at around 25 posts, a tag is ‘big enough’ to be a category, and that if a category dominates a blog, it should perhaps be a separate blog. And that’s where I disagree.

    On Beyond Zebra

    When she wrote her post, the concept of custom taxonomies was barely a gleam in someone’s eyes. Multisite was still WPMU, and a separate installation. Today we have the ability to add our own taxonomies (either in category or tag styles) and we can create a network of related sites on our own. All we need is a little more technical know-how.

    When we add on custom taxonomies, we afford ourselves a new way to classify posts, so to the above I would add this:

    • Custom Taxonomies are critical but exceptionally unique index words that must be grouped together

    Okay that was long, I know, but a Custom Taxonomy is in essence a new subdivision of your site. You can either make it a new table of contents or a new index … or a combination of the two. It’s a little wild, especially when you factor in custom post types.

    Overwhelming Category? Custom Post Type!

    Instead of making a new blog when your category gets too large and unwieldy, I would recommend making a new custom post type. If I use my helpful example of LezWatchTV, we currently have three custom post types: Shows, Actors, and Characters.

    While we could have made them into posts, and used categories to index them, having them be their own post type means instead of a table of contents, I’ve made an appendix. This gives me access to all the cool WordPress features, like archives and sorting and organization, but it does so outside the realm of posts which restricts crossovers. Unless you’re really clever with cross-related content.

    A custom post type keeps it all on one blog, but separates them like your laundry.

    Too Many Tags? Custom Taxonomy!

    If you find yourself having too many tags, it’s time to consider a custom taxonomy. Again, pointing to LezWatchTV, actors have two custom taxonomies: gender identity and sexuality. While those are the same as we use for characters, by having them separate and only applicable to the actor post type, we are able to give a list of all trans female actors with a click. In other words, we’re using WordPress’s native features.

    But if we look at the custom post type for TV shows, we have a lot more taxonomies, including two that are constantly being added on to: nations and stations. Every time a new station airs a show, we have to add it in. And there, as of April 1, we end up having 29 nations and 168 TV stations.

    Which brings up the next problem, and one that Lorelle does indeed address, but not the way I would.

    When Tags Go Rogue

    Can tags still go too large? Yes. Oh my lordy, yes.

    Recently I saw a site that used unique tags on every single post. I physically flinched when I realized that.

    You see, they had around 30,000 posts and 48,000 tags, and for the life of me I couldn’t understand why until I read the site and looked. For every single post there was a commensurate tag for the post title and the date. After 365 dates they thankfully started to repeat, so you might have 10 posts for the march-25 tag. Except they weren’t consistent and someone else used 25-march and now you can see the rabbit hole fall into infinity and beyond.

    Now that said, I have 168 tags for TV stations, each TV show has one, maybe two if they’re lucky or weird, and some tags only have 1 show listed. Others, like ABC, NBC, and CBS, have around 60. Do I think any of those are ‘too large’?

    I don’t. Because the number of 25 posts to a tag only holds up at a smaller scale. With 100 to 200 posts, yes, that starts to make sense. At 600 to 3000 posts, suddenly having 198 posts tagged with “Bury Your Queers” doesn’t sound so out of place. It’s about the percentages, somewhat, and also the use-case.

    If I know people are looking for a smaller tag (say they really want to see the 10 shows that have the ‘Fake Relationship’ tag), then for the purpose of this site, it’s important. On the other hand, if only one character was tagged cougar, I might not keep the tag as it’s too small to make the data useful.

    Optimal Organization

    There is no magic number of tags to categories to custom post types to taxonomies. It all comes down to understanding the goal of your site, the way users look for data, and what is maintainable to you.

    In the case of the site with 48k tags, I would have them delete all the date ones, as well as the ones with the same names as posts, and stick to using topical tags. After all, if a tag is only used once, or duplicates some feature already found in WordPress, it’s perhaps not the best idea.

  • WP-CLI Tables

    WP-CLI Tables

    I was working on an update to the Varnish plugin I’ve adopted, and one of the requested features was for more debugging tool. I’d added in a status page, but this plugin is also used by web hosts, and sometimes asking a customer “Can you go to this bad and send me the results?” is a time sink.

    So why not add in a command line tool?

    WP-CLI?

    I love WP-CLI. It’s a command line interface (CLI) for WordPress (WP) that lets you do most anything via the command line. You can install and activate plugins, update themes, even write posts and add users. But if you’re tech savvy, it’s also a great tool to automate and manage the minutia of WordPress maintenance drudgery.

    I’d already built out a basic varnish flush command (wp varnish purge) so adding on to it isn’t terribly difficult. But what was difficult was making the output what I wanted.

    Start With an Array

    No matter what you need an array of the correct format for this to work. I was already storing everything in an array I save in a variable called $results that looks like this:

    Array ( 
        [varnish] => Array ( 
            [icon] => awesome 
            [message] => Varnish is running properly and caching is happening. 
        ) 
        [remote_ip] => Array ( 
            [icon] => awesome 
            [message] => Your server IP setup looks good. 
        ) 
        [age] => Array ( 
            [icon] => good 
            [message] => Your site is returning proper "Age" headers. 
        )
    )
    

    I was initially doing this so I could loop and output all results with an icon and message on the status page, but translating this to wp-cli was a matter of taking the array and repurposing it.

    WP-CLI Tables

    In order to add in a table output to WP-CLI, you use the format_items function:

    WP_CLI\Utils\format_items( $format, $items, $headers );
    

    The $format value is taken from $assoc_args['format'] (I set mine to default to table if it’s not defined). The $items are your array, and the $headers are another array of what your headers are.

    This is the tricky part. You have to make sure your array of headers matches your array of items, and fulfills the output you desire. In order to do this, start with figuring out what you need to output.

    In my case, I wanted a name, a status (aka the icon), and the message. This means my array looks like this: $headers = array( 'name', 'status', 'message' )

    Rebuild The Array

    Once I sorted out what the format was like, based on the headers, I built the items array as follows:

    // Generate array
    foreach ( $results as $type => $content ) { 
    	$items[] = array(
    		'name'    => $type,
    		'status'  => ucwords( $content['icon'] ),
    		'message' => $content['message'],
    	);
    }
    

    Remember, my $results were already an array. I’m just making it look right here.

    Final Results

    How does it look? Like this:

    +-----------+---------+-------------------------------------------------------+
    | name      | status  | message                                               |
    +-----------+---------+-------------------------------------------------------+
    | varnish   | Awesome | Varnish is running properly and caching is happening. |
    | remote_ip | Awesome | Your server IP setup looks good.                      |
    | age       | Good    | Your site is returning proper "Age" headers.          |
    +-----------+---------+-------------------------------------------------------+
    

    And that is a nice tool for people to debug.

  • Shortcode Example: Reviews

    Shortcode Example: Reviews

    Sometimes people want to have reviews mean ‘people leave reviews on my work.’ But the other kind of reviews are the ones where I review other peoples’ works. And for that, I found it helps to have some kind of standard.

    Let’s say I’m reviewing a TV show for overall quality but also overall gayness. That is, I want to be able to write up a post and then, at the bottom, put up a shortcode to say “This show is really good but has no gay characters.” To do that, I made a list of the important factors to distill:

    • Name: The name of the TV show
    • Summary: A short, 140 character summary of the overall show.
    • Queer: A 1-5 rating of how queer the show is
    • Rating: A 1-3 scale (yes, meh, no) for how good the show is overall
    • Warning: Is there a trigger warning (or CW) to be aware of

    The intent is to make it easy for someone to scroll down and find what they want to watch. Right?

    The Code

    A bit of warning. There are two specific to my site bits of design in here. First are the icons. While I’ve generalized them for you as Emoji, keep in mind you probably want to have your own style here. Second, I’m using Bootstrap, so I’ve leveraged some of their default code. You’ll want to tweak the CSS.

    class TV_Shortcodes {
    
    	/**
    	 * Constructor
    	 */
    	public function __construct() {
    		add_action( 'init', array( $this, 'init' ) );
    		add_filter( 'widget_text', 'do_shortcode' );
    	}
    
    	/**
    	 * Init
    	 */
    	public function init() {
    		add_shortcode( 'review', array( $this, 'review' ) );
    	}
    
    	/**
    	 * Reviews.
    	 */
    	public function review( $atts ) {
    
    		$attributes = shortcode_atts( array(
    			'title'   => 'Coming Soon',
    			'summary' => 'Coming soon ...',
    			'queer'   => '3',
    			'rating'  => 'meh',
    			'warning' => 'none',
    		), $atts );
    
    		$queer = (float) $attributes['queer'];
    		$queer = ( $queer < 0 )? 0 : $queer;
    		$queer = ( $queer > 5 )? 5 : $queer;
    
    		$worth = ( in_array( $attributes['worth'], array( 'yes', 'no', 'meh' ) ) )? $attributes['worth'] : 'meh';
    		switch ( $worth ) {
    			case 'yes':
    				$worth_icon = '??';
    				$worth_color = 'success';
    				break;
    			case 'no':
    				$worth_icon  = '??';
    				$worth_color = 'danger';
    				break;
    			case 'meh':
    				$worth_icon  = '?';
    				$worth_color = 'warning';
    				break;
    		}
    
    		// Get proper triger warning data
    		$warning = '';
    		$trigger = ( in_array( $attributes['trigger'], array( 'high', 'medium', 'low' ) ) )? $attributes['trigger'] : 'none';
    
    		if ( $trigger != 'none' ) {
    			$warn_image    = '⚠️';
    			switch ( $trigger ) {
    				case 'high':
    					$warn_color = 'danger';
    					break;
    				case 'medium':
    					$warn_color = 'warning';
    					break;
    				case 'low':
    					$warn_color = 'info';
    					break;
    			}
    
    			$warning = '<span data-toggle="tooltip" aria-label="Warning - This show contains triggers" title="Warning - This show contains triggers"><button type="button" class="btn btn-' . $warn_color . '"><span class="screener screener-warn ' . $warn_color . '" role="img">' . $warn_image . '</span></button></span>';
    		}
    
    		$output = '<div class="bd-callout"><h5 id="' . esc_attr( $attributes['title'] ) . '">Screener Review on <em>' . esc_html( $attributes['title'] ) . '</em></h5>
    		<p>' . esc_html( $attributes['summary'] ) . '</p>
    		<p><span data-toggle="tooltip" aria-label="How good is this show for queers?" title="How good is this show for queers?"><button type="button" class="btn btn-dark">Queer Score: ' . $queer . '</button></span> <span data-toggle="tooltip" aria-label="Is this show worth watching? ' . ucfirst( $worth ) . '" title="Is this show worth watching? ' . ucfirst( $worth ) . '"><button type="button" class="btn btn-' . $worth_color . '">Worth It? <span role="img" class="screener screener-worthit ' . lcfirst( $worth ) . '">' . $worth_icon . '</span></button></span> ' . $warning . '</p>
    		</div>';
    
    		return $output;
    
    	}
    }
    new TV_Shortcodes();
    

    The Future

    I’m thinking about changing the scores from numbers to stars, and adding in a link if the show has been added to the site. But it being a shortcode, it’s reasonably extensible.

    Enjoy, and export to your own review sites.