Half-Elf on Tech

Thoughts From a Professional Lesbian

Author: Ipstenu (Mika Epstein)

  • Displaying Taxonomy Count

    Displaying Taxonomy Count

    Monday we displayed post counts. Well, what about taxonomies? That’s a little more complicated, I’m afraid.

    Posts are easy. You pick a post type, you display the number of published posts, you walk away. Taxonomies though are a mixed bag. By default you have categories (category) and tags (post_tag) and inside them, you have terms. For example ‘Uncategorized’ is a category. The problem is that to check if a taxonomy exists (and display a post count), you have two have both the taxonomy name and the term name.

    While you think you could just write a loop ‘If the term name isn’t in categories, it’s in tags!’ the reality is that anyone can add any taxonomy and, worse, term names aren’t unique. It’s ironic here, because I desperately wanted term names and slugs to not be unique. I wanted to have a tag for ‘random’ and a category for ‘random’ and they all have the same slug names. So here I am now, realizing I’ve set myself up for disaster.

    The options are simple:

    1. Force people to use term and taxonomy
    2. Somehow be clever

    I went with option 2. Allow people to use term and taxonomy, but if they don’t, find the first instance and go for it.

    The Code

    // [numtax term="term_slug" taxonomy="tax_slug"]
    function numtax_shortcode( $atts ) {
    	$attr = shortcode_atts( array(
    		'term'     => '',
    		'taxonomy' => '',
    	), $atts );
    
    	// Early Bailout
    	if ( is_null($attr['term']) ) return "n/a";
    
    	$the_term = sanitize_text_field( $attr['term'] );
    	$all_taxonomies = ( empty( $attr['taxonomy'] ) )? get_taxonomies() : array( sanitize_text_field( $attr['taxonomy'] ) );
    
    	//$all_taxonomies = get_taxonomies();
    	foreach ( $all_taxonomies as $taxonomy ) {
    	    $does_term_exist = term_exists( $the_term, $taxonomy );
    
    	    if ( $does_term_exist !== 0 && $does_term_exist !== null ) {
    		    $the_taxonomy = $taxonomy;
    		    break;
    	    } else {
    		    $the_taxonomy = false;
    	    }
    	}
    
    	// If no taxonomy, bail
    	if ( $the_taxonomy == false ) return "n/a";
    
    	$to_count = get_term_by( 'slug', $the_term, $the_taxonomy );
    
    	return $to_count->count;
    
    }
    add_shortcode( 'numtax', 'numtax_shortcode' );
    

    There are two moments where I bail out early. If they forgot to put in a term, display “N/A”. The same if we get all the way to the end and there was no found taxonomy.

    Also if someone puts in a taxonomy, I treat it as an array in order to be lazy and not repeat myself. Good coding doesn’t repeat, so since I have to loop the array of found taxonomies in order to find the matchup, I may as well use it once to find the same data when I know what I have.

    I admit, I was really excited here since I finally got to use ternary operations. I’ve known how they work for ages, but I never had a moment where it was so obvious to use them.

  • Displaying Post Count

    Displaying Post Count

    If you need a count of all your posts in WordPress, there’s a pretty handy function called wp_count_posts() for that.

    For example, if you have a post-type of ‘characters’ and you wanted to show a count of that, you can do this:

    $to_count = wp_count_posts( 'characters' );
    printf( __('Total Characters: %s'), $count->publish );
    

    And that’s all well and good, but I was working on some SEO thoughts. In doing so, I ran into the recommendation that, for a ‘company’ type page, having a list of your posts was a bad idea. This made sense. After all, a site that is about non-traditional blog content shouldn’t start with a blog.

    To correct this, I restructured the front page to show, in order:

    1. An introduction to the site
    2. The 4 newest characters added
    3. The 4 newest shows added
    4. The latest 10 blog posts

    This keeps the blog information visible (which helps show that content is being updated) but also doesn’t drop people into a cold open. They can understand why they’re on the site, what they’re getting, and where to go.

    But part of telling people about the site meant I wanted to indicate the depth of information. When I used to run a MediaWiki site, I used {{NUMBEROFARTICLES}} to list the number of articles. It was a very obvious way to display activity and attentiveness. If a site had 500 articles, it was probably getting up there. If it had 1500, it probably knew what it was doing.

    That meant with WordPress what I wanted was a dynamic way to show the number of posts in a post type, like [numberofposts type="characters"] with the default being posts.

    The Code

    function numberofposts_shortcode( $atts ) {
    	$attr = shortcode_atts( array(
    		'type' => 'post',
    	), $atts );
    
    	$posttype = sanitize_text_field( $attr['type'] );
    	if ( post_type_exists( $posttype ) !== true ) $posttype = 'post';
    
    	$to_count = wp_count_posts( $posttype );
    
    	return $to_count->publish;
    
    }
    add_shortcode( 'numberofposts', 'numberofposts_shortcode' );
    

    What I chose to do here was check if the post type exists and, if not, force it to show posts. That way there will never be an error, though it may not show you what you expected if you put in ‘posts’ as your post type.

  • Prettier Search Queries

    Prettier Search Queries

    By default, when you search on a WordPress site, your search URL has an /?s= parameter. Back in the old days of WordPress, we all had URLs like /?p=123 where 123 was the page ID. With the advent of Pretty Permalinks, we moved to pretty URLs like /2016/prettier-search-queries/ and everyone was happier.

    What about search?

    As it happens, the WP Rewrite API actually has a search base of … search. If you go to your Settings > Permalinks page, you won’t see it there, and yet on every site if you go to https://halfelf.org/search/apache you’ll actually get that nice, pretty path.

    Because of that, you could get away with adding this to your .htaccess file in order to get those pretty URLs.

    RewriteCond %{QUERY_STRING} s=(.*)
    RewriteRule ^$ /search/%1? [R,L]
    

    You can also use a plugin like Mark Jaquith’s Nice Search.

    Those methods work for nearly all sites.

    But you know me. I’m not ‘all’ sites.

    Extra Paramater Headache

    I had a different problem. Because my site had specialized data, it had extra search parameters. I was intentionally limiting my search to specific post type. This meant my URLs looked like this: /?s=rookie+blue&post_type[]=post_type_shows

    When I translated that to use the pretty search, well …/search/rookie+blue&post_type[]=post_type_shows just didn’t work.

    This is for a pretty obvious reason when you study the URLs. The first one has ?s=... and then later an &, while the second only has the & in there. If I changed the URL to this, it worked: /search/rookie+blue/?post_type[]=post_type_shows

    The reason for this was due to how parameters work in URLs. They have to start with ? at the beginning. All additional parameters are added with ?param=value after that.

    Semi Pretty Search Permalinks

    To me, the nicest URLs would be `/search/rookie+blue/section/shows/’. The reality is that people will search shows and characters and I wasn’t quite sure how I wanted to handle that. Did I want them to be sections separated by plus signs, or extra ‘folders’ or what? In the end, I decided that for now it was okay to just make these prettier.

    Taking Mark’s code as my start point, I came up with this:

    function pretty_permalink_search_redirect() {
    	// grab rewrite globals (tag prefixes, etc)
    	// https://codex.wordpress.org/Class_Reference/WP_Rewrite
    	global $wp_rewrite;
    
    	// if we can't get rewrites or permalinks, we're probably not using pretty permalinks
    	if ( !isset( $wp_rewrite ) || !is_object( $wp_rewrite ) || !$wp_rewrite->using_permalinks() )
    		return;
    
    	// Set Search Base - default is 'search'
    	$search_base = $wp_rewrite->search_base;
    
    	if ( is_search() && !is_admin() && strpos( $_SERVER['REQUEST_URI'], "/{$search_base}/" ) === false ) {
    
    		// Get Post Types
    		$query_post_types = get_query_var('post_type');
    		if ( is_null($query_post_types) || empty($query_post_types) || !array($query_post_types) ) {
    			$query_post_types = array( 'post_type_characters', 'post_type_shows' );
    		}
    
    		$query_post_type_url = '/?';
    		foreach ( $query_post_types as $value ) {
    			$query_post_type_url .= '&post_type[]=' . $value ;
    		}
    
    		wp_redirect(
    			home_url( "/{$search_base}/"
    			. urlencode( get_query_var( 's' ) )
    			. urldecode( $query_post_type_url )
    			) );
    		exit();
    	}
    }
    add_action( 'template_redirect', 'pretty_permalink_search_redirect' );
    

    And that actually does work exactly as I want it to.

  • 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.

  • EasyApache 4, PHP, and WP-CLI

    EasyApache 4, PHP, and WP-CLI

    Way back in March, I upgraded my server to use EasyApache 4. I did this because I wanted to have multiple versions of PHP on my server and be able to segregate it by domain. I also wanted to be able to upgrade PHP without having to rebuild Apache.

    For the most part, it’s been great. There were a couple odd snafus, like when it accidentally installed the wrong wp-cli on a minor upgrade for me, but it magically fixed it.

    PHP Breaks WP-CLI

    The problem was when I ran wp-cli commands, I got this error:

    PHP Warning:  array_slice() expects parameter 1 to be array, null given in phar:///usr/local/bin/wp/php/WP_CLI/Runner.php on line 610
    PHP Warning:  Invalid argument supplied for foreach() in phar:///usr/local/bin/wp/php/WP_CLI/Configurator.php on line 132
    PHP Warning:  proc_open(): Descriptor item must be either an array or a File-Handle in phar:///usr/local/bin/wp/php/commands/help.php on line 111
    PHP Warning:  proc_close() expects parameter 1 to be resource, boolean given in phar:///usr/local/bin/wp/php/commands/help.php on line 111
    Content-type: text/html; charset=UTF-8
    

    Scary! I tried reinstalling and that didn’t work

    I took a note of what version of PHP I had running on command line and so something weird:

    PHP 7.0.10 (cgi-fcgi) (built: Aug 22 2016 20:34:53) Copyright (c) 1997-2016 The PHP Group Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies with Zend OPcache v7.0.10, Copyright (c) 1999-2016, by Zend Technologies

    The Wrong PHP

    PHP 7.0.10 (cgi-fcgi) sounds like it should be okay, except I knew two thing:

    1. Fast CGI (fcgi) isn’t supported on EA 4 yet. It’s not even supported today. They’re working on it but it shouldn’t have been a thing installed.
    2. That should be cli not cgi-fcgi!

    I pinged a friend at cPanel who said “Oh no!” and promised to look into it for me. The next day I got an email that there was a minor PHP update to my server last night. I knew that meant PHP had been rebuilt. When I went to look, wp-cli was working again.

    Ergo – Something was wrong in PHP 7.0.10. It pushed the wrong version of PHP for command line somehow.

    Risk vs Reward

    Obviously this is a risk, having a server auto-update itself. It could install a rogue package or someone could typo or worse. At the same time, having PHP apply it’s own security patches for me means I don’t have to worry that I’m in Japan for a week and forget to do something. The risk, knowing that EA will roll out a fix for me, is less than the reward of being secure.

  • Damn You, Autocorrect!

    Damn You, Autocorrect!

    After the seventh time I shouted “stop autocorrecting cmb2 fields!” at my site, I knew I had to do something.

    When you run a website where you enter a lot of people’s names, Autocorrect is a curse more than a blessing. Of course I want it on my post content, but when I get to the field where I enter someone’s name, for crying out loud, some names like Nuñez just don’t meet a spell check. And don’t get me started on my friend’s names or my own. I’ve lost track of the number of times I ended up as “Mike.”

    This issue used to only be on phones and tablets. Then Apple introduced autocorrect to their MacOS, which resulted in a lot of tweets followed up by “Damn you, Autocorrect!”

    HTML Attributes

    If you’ve got a form and you want to tell autocorrect to go away, the code looks like this:

    <input autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />
    

    For the most part, this will work. You don’t need all of them all of the time, but in my case I was adding names and “Debbie van Houten” was one problem and “Dr. el Farad” was another. I wanted it to just shut up and let me type the name as their parents intended, no matter what. I went whole hog.

    But as I mentioned, I use CMB2 and I needed to stop my site from autocorrecting CMB2 fields. It was time for some code.

    CMB2 Custom HTML Attributes

    This one is so straightforward I was delighted. When you create a new field, you can set arbitrary attributes.

    // Field: Actor Name
    $cmb_characters->add_field( array(
    	'name'				=> 'Actor Name',
    	'desc'				=> 'Include years (in parens) for multiple actors',
    	'id'				=> $prefix . 'actor',
    	'type'				=> 'text',
    	'repeatable'		=> 'true',
    	'attributes'		=> array(
    		'autocomplete'		=> 'off',
    		'autocorrect'		=> 'off',
    		'autocapitalize'	=> 'off',
    		'spellcheck'		=> 'false',
    	),
    ) );
    

    That was all I needed to do in order to get autocorrect to duck itself. Now I was free to write however weird a name I needed without worrying that autocorrect wanted to call me Mike. Again.

    Thanks, autocorrect. Thanks a lot.