Half-Elf on Tech

Thoughts From a Professional Lesbian

Category: How To

  • How To Pick Your Webhost

    How To Pick Your Webhost

    This is not a real conversation, except it totally is.

    User: I want hosting.
    Me: What kind of site do you want to host?
    User: A WordPress site!
    Me: What kind of content do you plan on writing?
    User: Oh you know, blog stuff.
    Me: Okay… A food blog, a photo blog, a tech blog…?
    User: ​Why are you asking me all this!?!?!

    I’ve had so many conversations like this, I’m of the opinion that recommending hosting is a mugs game that simply cannot be ‘won’ so I generally don’t play.

    Then why am I presuming I can tell you how to pick a webhost? Because I’m telling you how to pick a webhost, not who the best webhost is.

    Preface

    Someone will hate every single webhost on the planet. I use Liquidweb and DreamHost. People hate both of those. There’s the bevy of EIG companies whom people will detest and lambast and accuse of shady actions to be listed somewhere. There are the millions of small companies. There are good and bad companies, and there are reasons to use them. Whenever someone asks what host to use, I remind them that someone will hate their choice. That’s okay, just don’t take it personally and I recommend you ignore people who simply jump on bandwagons to tell you “X SUCKS!” They’re not being helpful.

    Needs vs Wants

    I repeat this a lot in myriad situations. Your needs are what your website needs, which should be obvious. If you’re running WordPress you need a webserver than runs a modern version of PHP and a MySQL (or MariaDB) database. That’s it. But that isn’t all of what you need for a website, and to understand your needs you need to be very clear about your own abilities, your capabilities, and the time you’re willing to commit to your project. Running a website is very time consuming and stressful. You can’t just set it and forget it.

    Who Are You?

    We should all know who we are, what our skills are, and what we enjoy doing. I’m like playing with servers and code. My wife prefers practical experimentation (she makes cheese and mead). My father is a mathematician. We’re all writers of a sort, but of the three of us I’m the one who runs the website and puts of articles on the regular. This is not because the others can’t, but because they know who they are. My father sends me his articles to post, my wife posts her own, and I both write my own for me but for my company, and I maintain the servers (and email). If you’re not me, and don’t have a me, you need a me. That may be your host, and it may not.

    How Do You Communicate Best?

    Do you get anxiety with phone calls? Look for a company with live chat and email support. Do you hate live chat? Are you dyslexic? Look for phone support. You know how you like to communicate with strangers, so pick a host that has what you need. I personally prefer ticket based systems, unless my server is actually on fire. That hasn’t happened much.

    How Do You Add People?

    Let’s say you decide to hire someone to work on your website. Do they need access to the server? Do they need access to your billing? How do you do that without giving them your passwords? Find out how the host handles this. Can you simply add a technical contact or will there be more complicated steps?

    What Is Your Site About?

    Why does this matter? Well, think of it this way. “I want to make a community site where people from my city can come and post news, events, crimes, etc.” Did you just think about BuddyPress? You will likely need a bigger server than Shared. “I want a photoblog!” Okay you will need to seriously look at diskspace, which means SSDs may be a little tricky for you since most limit space. Check if the host allows easy upgrades. “I’m going to run a multisite network for my school!” You need a private server. Knowing what your site is about will help you predict upcoming hurdles.

    Do You Know Any Metrics?

    Most people, especially people with a brand new site, are going to say “No!” here and that’s okay. But if you do know things like how much traffic you get or how often you post or how much disk space you use, talk to the host about it. Pre-sales questions like “What’s the best hosting plan for a site that gets 2000 visits a day, and then 12k on one day a week?” are the bread and butter of a host. If they can’t answer it, move on.

    Does The Host Make You Feel Good?

    If you get a bad feeling from the host at any step along the way, you feel like they’re dismissive or maybe not a good fit, walk away. Look, you need to be comfortable with your host, and if the advertising practices of a host upset you, don’t use them. It’s that simple. Even if they’re the best for your needs, if they make you uncomfortable, you will be miserable. And remember, for every single host there will be people who hate them. That’s okay too. If it works for you, and you feel good about doing business with them, then that is really all that matters.

  • A Simplier Hugo Deploy

    A Simplier Hugo Deploy

    I have a Hugo site that I’ve been deploying by running Hugo on the server. But this isn’t the only way about it.

    If you use Git and it’s on the same server as your site, and owned by the same user, it’s remarkably easy to do this.

    First make sure the public folder in your Hugo repository is being tracked. Yes, this can make your repository a little large but that’s not something to worry about too much. Space is cheap, or it should be. Next make a folder in tmp – I called mine library – to store the Git output in.

    The new post-update code then looks like this:

    #!/bin/sh
    
    SRC_DIR=$HOME/tmp/library/public/
    DST_DIR=$HOME/public_html/library/
    
    export GIT_WORK_TREE=$HOME/tmp/library/
    git checkout -f
    
    rsync -a --delete $SRC_DIR $DST_DIR 
    
    exit
    

    What this does is checkout the Git repository and then copy it over. The format of the sync will delete anything not found. Done.

    The benefit of this method is that you don’t need to install GoLang or Hugo on your server, and everything is pure and simple Git and copy. Rsync is a delightful way to copy everything over as well. You can delete the temp folder when you’re done, but the checkout process handles things for you. Another nice trick is you can specify what branch to checkout, so if you have a special one for publishing, just use that.

    But could this be even easier? Yes and no. You see, what I’m going is checking out the whole thing and then copying over folders. What if I could tell Git to just checkout the code in that one folder?

    There’s a think called a ‘sparse checkout’ where in I can tell Git “Only checkout this folder.” Then all I have to do is go into that folder and checkout the content I wanted. The problem there is it literally checked out the folder ‘public’ and what I wanted was the content of the public folder. Which means while it’s ‘easier’ in that I’ve only checked out the code I need, I can’t just checkout it out into where I want. I will always have to have a little extra move.

    To set up my folder, I did this:

    cd ~/tmp/library/
    git init
    git remote add -f origin ~/repositories/library.git
    git config core.sparsecheckout true
    echo public/ >> .git/info/sparse-checkout
    git checkout master
    

    And then my script remains the same. But! This is going to be a faster checkout since it’s only ever going to be exporting and seeing the folders it needs.

  • Aiding Symbol Selection

    Aiding Symbol Selection

    Last week I was talking about the difficulties I was having with Symbol Selection. At it’s crux, the issue is explaining something visual that’s clear to me but may not be to others.

    What I ended up doing was making in-line documentation. When you edit a category, you see the option to change the icon, but now it has some exposition:

    Exposition has a link to help you visualize things

    This is pretty simple, I now, but the point is that if you get that far and go “Wait, what?” your eyes will hit that link and you’ll probably click on it and get the new Appearance page:

    A page to show you all the symbolicons

    The page is generated by an mu-plugin, and quite simply it scans the folder for all the symboicons and shows you each one. Since it’s in an mu-plugin and the images are a part of the theme, I put in an extra check to see if the folder is there and, if so, show an error.

    class SymboliconsSettings {
    
        public function __construct() {
            add_action( 'init', array( &$this, 'init' ) );
        }
    
        public function init() {
            add_action( 'admin_menu', array( $this, 'add_settings_page') );
        }
    
    	// Sets up the settings page
    	public function add_settings_page() {
    		$page = add_theme_page(__('Symbolicons'), __('Symbolicons'), 'edit_posts', 'symbolicons', array($this, 'settings_page'));
    	}
    
    	// Content of the settings page
    	function settings_page() {
    		?>
    		<div class="wrap">
    
    		<style>
    			span.cmb2-icon {
    			    width: 80px;
    			    display: inline-block;
    			    vertical-align: top;
    			    margin: 10px;
    			    word-wrap: break-word;
    			}
    			span.cmb2-icon svg {
    			    width: 75px;
    			    height: 75px;
    			}
    			span.cmb2-icon svg * {
    			    fill: #444!important;
    			}
    		</style>
    
    		<h2>Symbolicons</h2>
    
    		<?php
    
    		$imagepath = get_stylesheet_directory().'/images/symbolicons/';
    
    		if ( !file_exists( $imagepath ) && !is_dir( $imagepath ) ) {
    			echo '<p>Your theme does not appear to have the symbolicons folder included, so you can\'t use them. How sad. It should be installed in <code>'.get_stylesheet_directory().'/images/symbolicons/</code> for this to work.';
    
    		} else {
    
    		    echo '<p>The following are all the symbolicons we have to chose from and their file names. Let this help you be more better.</p>';
    
    			foreach( glob( $imagepath.'*' ) as $filename ){
    				$image = file_get_contents( $filename );
    				$name  = str_replace( $imagepath, '' , $filename );
    				$name  = str_replace( '.svg', '', $name );
    				echo '<span role="img" class="cmb2-icon">' . $image . $name .'</span>';
    			}
    		}
    	}
    
    }
    new SymboliconsSettings();
    

    It’s not perfect, but it helps.

  • A Blog Thought On Documentation

    A Blog Thought On Documentation

    Everyone, everyone, hates doing it. We all do.

    But there’s something that blogging regularly has brought me that is specifically related to documentation. And it’s this.

    I am more likely to write down exactly how I solved a problem if I think about it as a new blog post.

    I know, that sounds so simply it’s stupid, but I’ve realized that the whole reason I’ve figured all these things out is that I want to have something to blog about, and I want the blog posts to be interesting, so I started writing down how I solved problems.

    Of course, the joy of a problem is in the solving, so most of the time I’m talking about happy things. I do also blog about my failures, my missteps, and my totally-wrongs. Nothing wrong with being wrong. You learn a lot more from it, I feel.

    Start Without Code

    When I start ‘figuring out’ a thing, I write it down without any code. I write down “I want to do X.” And then I start brain storming.

    Take Monday’s post about term icons. “I want to assign an icon to a term.”

    That’s how it started. Then I talked through my vague concepts:

    • Show the icon on the back end
    • No uploading icons
    • Show the icon on the term edit and terms list page
    • Make sure it can show on the front end

    It’s really just the broad ideas. I’m not digging in deep.

    Pick Something Easy

    When I start coding, I pick the thing I already know how to do the most of. In this case, it was showing the icon on the front end. That let me start in comfort. I uploaded the images to the development server (VVV in this case) and started messing around with showing the images on the front end.

    I hardcoded in everything at first, using a default icon of ‘bacon’, and went about figuring out how I wanted it to display. I didn’t document this as much since it really was just about the look first. I knew when I got down to brass tacks, I’d be doing this:

    	<ul class="myterms-list"><?php
    		$terms = get_the_terms( $show_id, 'my_terms' );
    		if ( $terms && ! is_wp_error( $terms ) ) {
    			// loop over each returned cliche
    			foreach( $terms as $term ) { ?>
    				<li class="show myterm myterm-<?php echo $term->slug; ?>">
    					<a href="<?php echo get_term_link( $term->slug, 'my_terms'); ?>" rel="show cliche"><?php
    						$icon = get_term_meta( $term->term_id, 'my_termsmeta_icon', true );
    						$iconpath = get_stylesheet_directory().'/images/symbolicons/'.$icon.'.svg';
    						if ( empty( $icon ) || !file_exists( $iconpath ) ) {
    							$iconpath = get_stylesheet_directory().'/images/symbolicons/bacon.svg';
    						}
    						echo file_get_contents( $iconpath );
    						echo ' '.$term->name;
    					?></a>
    				</li><?php
    			}
    		} ?>
    	</ul>
    

    All of that code, except the icon part, was already written. That’s why it was easy.

    Pick Something Obvious

    Once I’ve done something easy and boosted my confidence, I start with the actual work. How do I set a term meta for a custom taxonomy?

    I knew how to make custom meta boxes, but taxonomies were different. I quickly remembered all the work Boone did for WordPress 4.4 and read his post on the Taxonomy Roundup. That way I learned that, as I had assumed, get_term_meta was a thing.

    Then I check to see if CMB2 knew how to use term meta, and happily found that it will work with term meta out of the box. No extra work. Thus the obvious became simple and I made a custom meta box for my term to put in a plain text field which was (originally) the path to my media file.

    I used that process to start the blog post. That was the new thing, so I wrote up the answer, not the process, and explained how to do the thing.

    Write About the Tweaks

    At that point, all that was left was busy work. I added in how to show the images on the back end, but then… then I did something extra. As I wrote the end of the post, I asked myself what the next logical step was? Well that would be not letting someone typo or put in names of images that didn’t exist. Instead of having to document all the images, I could just show a list.

    And that’s what I did.

    Share It

    This is actually universal.

    If you just documented something, you either did it so you can repeat the process over and over, or so you could have someone else do your dirty work for a change.

    If it’s personal, change ‘share it’ to ‘store it in an accessible place.’ Something in the cloud will do in a pinch. I often have my little things in a DropBox folder called “How Do I…” That’s because I usually ask “How do I edit all the images for …”

    But if it’s not personal, if I know a group will have to do it again later, I document it and share it. It may go in the company internal knowledge base or maybe it’ll be on a GoogleDoc shared with the people who need to know. Maybe I’ve put it on this blog.

    Either way, I documented. I released it.

    Now it’s your turn.

  • Making More With Less Work

    Making More With Less Work

    The other day, I added meta data of an icon to a custom taxonomy. When you need to add one or two filters to one or two items, it’s simple.

    add_filter( 'manage_edit-{my_taxonomy}_columns',  'my_terms_column_header' );
    add_action( 'manage_{my_taxonomy}_custom_column', 'my_terms_column_rows', 10, 3  );
    

    Replace {my_taxonomy} with your taxonomies, call it a day. But when you add in two, or three, or four, you don’t want to make four, or six, or eight lines of code. And when you’re calling the same array over and over, it’s time to get smart.

    Make An Array

    I originally only want to do this custom work in one taxonomy, so it was no sweat to repeat a little code. But then I realized I wanted to see it in four. Maybe more. So I picked out my array:

    $icon_taxonomies = array( 'tax_cliches', 'tax_chartags', 'tax_gender', 'tax_sexuality' );
    

    I made this outside the two functions, because I knew I was going to need it in multiple places. It would necessitate me tossing global $icon_taxonomies; into every function that needed it, but that was okay. Better that then trying to make sure every time I updated an array, I did it in all the places. Once is better.

    Make Your Loop

    The easiest thing was to trigger this on admit_init. Grabbing my global, I ran a simple for-loop from that array and added a filter based on the taxonomy named stored in the array:

    add_action( 'admin_init', 'my_add_taxonomy_icon_options' );
    function my_add_taxonomy_icon_options() {
        global $icon_taxonomies;
        foreach ( $icon_taxonomies as $tax_name ) {
    	add_filter( 'manage_edit-'.$tax_name. '_columns',  'my_terms_column_header' );
    	add_action( 'manage_'.$tax_name. '_custom_column', 'my_terms_column_rows', 10, 3 );
        }
    }
    

    Is It Really Less?

    A clever person will count the lines in this code (10 when you add in the variable) and think “Mika, you wrote two extra lines!”

    A more clever person will count the lines and think “At 5 taxonomies begins the break even point.”

    I know. From the outset it looks like I’m taking more time to over-engineer the solution to a very simple problem. And while I am, I’m also making it easier not to make typos and not to forget a step. I can make one change, one word, and update multiple places becuase that array is also used back in the my_register_taxonomy_metabox() function.

    'taxonomies'       => array( 'my_cliches', 'my_chartags' ),
    

    I removed the array and tossed in the new code.

    Yes, that’s adding two lines, but it removes my need to think “Where does this all go?” down to one place. And yes, I documented this in-line. The code header has a nice docblock explaining the whole section, what each variable is, and what each function does.

  • Custom Terms and CMB2

    Custom Terms and CMB2

    Let’s say you have some custom taxonomies in WordPress. And let’s say you want to add a special field to them for an icon. How would you do it?

    There’s a cool plugin by someone I know that can do this, called WP SVG Icons and it works great. But it wasn’t quite what I needed.

    You see, I had 832 really awesome SVG icons I wanted to use. In order to use Evan’s plugin I’d have to convert them into a font using Icomoon. I already had about 300 in a font, which is cool, but I was in the thought to move these from fonts to pure SVG anyway since they’ll show up in better detail if you don’t have retina screens. Also they’re smaller and loaded on demand and … well it is what it is.

    I decided the simplest solution was as follows:

    1. Upload all the SVG to the server
    2. Add a custom term meta field to the taxonomies for ‘icon’
    3. Show the icon on the Terms List Page
    4. Show the icon on the Term Edit page

    And yes, it works.

    Where Do The Icons Go?

    I put them in my theme. They’re pretty specific to the theme itself, but usually things that are related to custom data ends up in mu-plugins since I want them to exist outside of the theme. For the record, I also have CMB2 outside the theme, so the code is all there, but the images are in the theme. You can decide how you want.

    Adding Custom Term Meta

    There are a lot of ways of doing this, but as I’m using CMB2, well, I’m using CMB2 so it looks like this:

    add_action( 'cmb2_admin_init', 'my_register_taxonomy_metabox' );
    function my_register_taxonomy_metabox() {
    	$prefix = 'my_termsmeta_';
    
    	$cmb_term = new_cmb2_box( array(
    		'id'               => $prefix . 'edit',
    		'title'            => 'Category Metabox',
    		'object_types'     => array( 'term' ),
    		'taxonomies'       => array( 'my_cliches', 'my_chartags' ),
    		'new_term_section' => true, 
    	) );
    
    	$cmb_term->add_field( array(
    		'name'		=> 'Icon',
    		'desc'		=> 'Name of the image you want to use, without filetype (i.e. carrot)',
    		'id'		=> $prefix . 'icon',
    		'type'		=> 'text_medium',
    		'before_field'	=> 'cmb2_before_field_icon',
    	) );
    }
    

    You’ll notice before_field there. That’s what will let me do the 4th item on my list. The description tells you how to use the field. Don’t worry, I do sanity checks later on.

    Show The Icon On The Terms List

    I wanted the icon to show after save so that people would be able to know what they’d added and change it if needed.

    add_filter( "manage_edit-{my_taxonomy}_columns", "my_terms_column_header" );
    add_action( "manage_{my_taxonomy}_custom_column",  "my_terms_column_rows", 10, 3  );
    
    function my_terms_column_header($columns){
        $columns['icon'] = 'Icon';
        return $columns;
    }
    
    function my_terms_column_rows($value, $content, $term_id){
    	$icon = get_term_meta( $term_id, 'lez_termsmeta_icon', true );
    	$iconpath = get_stylesheet_directory().'/images/symbolicons/'.$icon.'.svg';
    	if ( empty($icon) || !file_exists( $iconpath ) ) {
    		$content = 'N/A';
    	} else {
    		$content = '<span role="img" class="cmb2-icon">'.file_get_contents($iconpath).'</span>';
    	}
        return $content;
    }
    

    You can see where I’m checking if the icon has been set and if the file exists. What this does is first generate a column for the icon and then populate the content based on the term information.

    Icons shown on the list of terms

    There you can see the icon, looking rather nice.

    See The Icon When You Edit

    This is a little different. I had to check the output the of the field value, which is set by CMB2, and then base the rest of the code off that.

    function cmb2_before_field_icon( $field_args, $field ) {
    	$icon = $field->value;
    	$iconpath = get_stylesheet_directory().'/images/symbolicons/'.$icon.'.svg';
    	if ( !empty($icon) || file_exists( $iconpath ) ) {
    		echo '<span role="img" class="cmb2-icon">'.file_get_contents(get_stylesheet_directory_uri().'/images/symbolicons/'.$icon.'.svg').'</span>';
    	}
    }
    

    Again I double check the file actually exists, just in case you typo.

    The edit term page

    I put it before the field because that looked better to me, but there are other places this could go.

    Results?

    I started this because, originally, it was all done with CSS. That meant if people added in new terms, someone with admin ability had to go in and edit things. This way, people can not only see what they’ve added, but you can get a quick view of what doesn’t have icons set. It’s instructive and has visual feedback.

    The ‘next level up’ would be to only allow selection from a dropdown.

    For the least amount of hustle, add this to your my_register_taxonomy_metabox function:

    	$icon_array = array();
    	foreach (glob( get_stylesheet_directory().'/images/symbolicons/*.svg' ) as $file) {
    		$icon_array[ basename($file, '.svg') ] = basename($file, '.svg');
    	}
    

    And then replace 'type' => 'text_medium', with this:

    	    'type'             => 'select',
    	    'show_option_none' => true,
    	    'default'          => 'custom',
    	    'options'          => $icon_array,
    

    And voila. Done. Now you’re even harder to get wrong.

    names as dropdowns

    It even looks good.