Half-Elf on Tech

Thoughts From a Professional Lesbian

Category: How To

  • When You Need Blocks

    When You Need Blocks

    There are a lot of cases where you don’t need a custom block. My spoiler block (from last week) is a great example of that:

    But. What about when you want to have that spoiler have choices? Now you’re outside the shared content block territory and into the confusing land of Gutenberg plugins.

    Blocks Are Not Simple

    I’m the sort of person who abhors boilerplate plugins. I just do. I feel that they divorce you from understanding what the code is and does, and how it all plays together. The more you rely on them, the less you can debug when it goes sideways. Oh, and it will. It always does.

    But. Gutenberg requires a lot more Javascript than I happen to be good at. Or rather, it requires new Javascript. Which is why I did exactly what I did the first time I ever made any plugin. I went and found one that did mostly what I wanted, and I edited it.

    Whaaaaat? 

    It’s true. And I want everyone to take a moment and realize this is a perfectly normal, okay, thing! In fact, I would like to see Hello Dolly converted to include a Gutenblock because learning by example is a valid, tried and true, way to teach someone how things come together.

    What Examples Are Good?

    Okay so where is a good place to start?

    That’s enough to get you started, I think. I went with WP-CLI since I like it and I’m used to it. Of course, it came with a small problem. In order to make a block via wp-cli, you have to put the code in a plugin (or a theme). Well fine. I did that to scaffold it and then I moved it to where I was developing. Most people aren’t so particular.

    Is It Hard?

    Not really. Once you get used to editing the js file instead of PHP, it’s just like hacking any other plugin. Start with the simple thing. Make a block that just does one thing and isn’t editable. My one tip is that when you call your blocks, make sure to wrap it in a check if the function exists:

    if ( function_exists( 'register_block_type' ) ) {
    	include_once( dirname( __FILE__ ) . '/spoilers.php' );
    }

    Otherwise there’s a chance that a non-Gutensite will die on you.

    Good luck and happy Gutenberging!

  • 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();
        }
    }
    
  • 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.