Half-Elf on Tech

Thoughts From a Professional Lesbian

Tag: wordpress

  • Prefix or Suffix

    Prefix or Suffix

    I’ve been seeing a lot of a new trend in coding, which stems from boilerplate plugin code, and that is the use of suffixes in function names. This has become increasingly popular in WordPress code and I, for one, am not a fan.

    WordPress Function, What’s Your Function?

    Otto likes to say that well named functions don’t need code comments.

    While optimistic in this day and age of complex code, the basic concept remains quite valid. If you name your functions well, the chances are that they will trigger your contextual memory and you’ll remember what they are, what they do, and why they’re there. To this end, the difference between function activate_pluginname() and function pluginname_activate() is miniscule. Both of those are clearly functions that run on ‘activate’ and that makes perfect sense. We can see the purpose of the function by its name, and that is the majority of Otto’s point. They are well named as they indicate their job. The issue then does not like in the name of the function but in the format of the name of the function.

    Function Name Conflicts

    A majority of the time, my argument for having unique function names is that there are over fifty-thousand plugins out there, and the odds of two of them having the same function name is quite high, for cases when the function name is generic. For example, function my_plugin_init() is not unique in the slightest. Yes, people literally use my_plugin_ as a prefix. That’s not a placeholder. That particular error occurs when people use boilerplates and don’t read the directions clearly. Most state “Search and replace my_plugin with your plugin prefix.”

    Preventing conflicts means it’s incumbent of developers to select unique function names. Now this pressure is alleviated by the use of namespaces and classes, but even those have to be unique to their plugin (or theme). After all, class WordPress is not a great classname.

    Again, in this regard there is very little difference between function activate_pluginname() and function pluginname_activate() in the real world. Both are unlikely to cause conflicts.

    Internal Consistency is Good

    Another aspect of names is that good function names are logical and consistent. Few things pain me more than seeing function pluginname_init() and function pn_admin_init() (where pn is an abbreviation for the plugin name). What I see a great deal with the plugin name as suffix is this hodgepodge of names:

    • init_plugin_name()
    • plugin_name_uninstall()
    • pn_wp_class_list()

    My guess at this point is that any time a particular boilerplate doesn’t specify the name of the function needed, people fall back into old habits. Or rather, they fall back into the recommended habits. You know, a prefix. Consistently named functions make it easier for people to recognize what function belongs to what plugin or theme.

    So why Prefix?

    This takes us to an interesting point. Both function activate_pluginname() and function pluginname_activate() meet the requirement of being well named and unique (and can be consistent). So what actually is the problem here?

    The problem is the future.

    Your code does not exist in a vacuum! Code that will only ever be used on your own server still runs with the other plugins and themes you add, and they could cause a conflict. It’s somewhat trivial to change those things, but it’s not fun and usually it means that you broke something in your live environment.

    • Consistently named functions make it easier to know what function relates to what.
    • Uniquely named functions are easier to find.
    • Well named functions remind you what the function is supposed to do.

    But again, why prefix?

    Remember Who Comes Next

    I do a lot of searches on code in myriad plugins. More than most people involved in WordPress I suspect. I have a very peculiar relationship with plugins, after all. When the core developers want to figure out how ‘well used’ a function is before changing it, I help out by running a search on all the code in the plugin directory. This results in me finding a lot of weirdly named functions that require me to track back through the plugin and find out what it’s really doing. When things are prefixed, this search goes a lot faster.

    Besides just my convenience, when you remember that your code is used by thousands of people, they will have an easier time searching for your code when they have an error. If you got an error that a function named halfelf_init was doing something wrong, you could run this to find the file: grep -r "halfelf_init" ./wp-content/

    Some of the more experienced debuggers out there are probably wondering why I grep from wp-content when most errors give the full path of wp-content/plugins/plugin-name/filename.php in the first place. The answer to that is “most” but also because often functionality plugins that are related to a theme (or other plugins) will cross-reference themselves in ways that can cause PHP to give you the wrong file for the problem.

    If you ran my check and found that the function was called in nothing but files in that plugin’s folder, great. But if you found it was called in a theme, you would then want to run this: grep -r "halfelf_" ./wp-content/themes/theme-name/ — That would reveal all the calls for the functions that belonged to a specific other tool.

    And what if you got a warning that the function had already be declared? grep -r "function halfelf_" ./wp-content/plugins/other-plugin/ will list all the functions that start with halfelf_ and save you a headache of solving one warning only to have it be replaced by another. (Of course, if you use namespaces or classes, this gets thrown out the window, oh well).

    Finally there’s the human factor. This is exceptionally subjective, I know, but doesn’t a line of functions all starting with the same term feel cleaner to you? It demonstrates a repeating pattern that a human mind can follow and feel comfortable with.

    Solution: Be Consistent

    There’s only one solution to be had here. While I greatly prefer a prefix, if you chose to use a suffix, be consistent. Make every single function end with _pluginname and don’t skip a single one.

  • Rebranding Featured Image

    Rebranding Featured Image

    WordPress 3.0 introduced featured images, letting everyone designate an image for a post (or page) in a way that themes have taken great advantage of in the intervening years. The concept of a ‘featured’ image was easy enough to understand. An image the content featured. Cool. But it can do so much more.

    The Defaults

    The basic box is one all WordPress users are familiar with:

    The basic featured image box

    A simple box that says “Featured Image” with a link to set the featured image.

    It’s great, but it’s a little boring.

    Changing the Title

    The actual trick to this is to remove the metabox. The three attributes you will need are the name of the meta box, the post type, and the location. The post type is the one most of you are going to change. For example, I wanted to change the title for a specific post type so it was clearer what kind of image I was looking for to use as a featured. For TV shows, I wanted it to indicate that I was looking for a Title Card type image.

    add_action('do_meta_boxes', 'featured_image_title_post_type_shows');
    function featured_image_title_post_type_shows() {
        remove_meta_box( 'postimagediv', 'post_type_shows', 'side' );
        add_meta_box('postimagediv', __('Show Image/Title Card'), 'post_thumbnail_meta_box', 'post_type_shows', 'side');
    }
    

    This little snippet removes the meta box and then adds it back with a new title:

    Customized feature image with new title

    Changing the Main Content

    Once the title is changed, the next step is to change the content. I’ve done this before, putting in the image size to the content. What I wanted to do here was change the content from “Set featured image” to “Set show image” and for that, I want to use a string replacement:

    add_filter( 'admin_post_thumbnail_html', 'set_featured_image_text_post_type_shows' );
    function set_featured_image_text_post_type_shows( $content ) {
        global $current_screen;
    
        if( !is_null($current_screen) && 'post_type_shows' == $current_screen->post_type )
            return $content = str_replace( __( 'Set featured image' ), __( 'Set show image' ), $content);
        else
            return $content;
    }
    

    But that only changed the one. Once you’ve set a featured image, the language changes to “Remove featured image”. I could add in more replacements, or I could be smart. We like being smart.

    return $content = str_replace( __( 'featured' ), __( 'show' ), $content);
    

    And yes, it works.

    Customizing by Type

    What if you have ten custom post types? Well then it’s time to get smart! By using anonymous functions, we can do this quite effectively, getting a list of all the publicly registered post types that aren’t the built-ins, and then for each one, renaming the content:

    // Customize Featyred images for CPTs
    add_action( 'admin_init', 'helf_featured_images' );
    function helf_featured_images() {
    	$post_type_args = array(
    	   'public'   => true,
    	   '_builtin' => false
    	);
    	$post_types = get_post_types( $post_type_args, 'objects' );
    	foreach ( $post_types as $post_type ) {
    
    		$type = $post_type->name;
    		$name = $post_type->labels->singular_name;
    
    		// change the default "Featured Image" metabox title
    		add_action('do_meta_boxes', function() use ( $type, $name ) {
    			remove_meta_box( 'postimagediv', $type, 'side' );
    			add_meta_box('postimagediv', $name.' Image', 'post_thumbnail_meta_box', $type, 'side');
    		});
    
    		// change the default "Set Featured Image" text
    		add_filter( 'admin_post_thumbnail_html', function( $content ) use ( $type, $name ) {
    			global $current_screen;
    			if( !is_null($current_screen) && $type == $current_screen->post_type ) {
    				return $content = str_replace( __( 'featured' ), strtolower( $name ) , $content);
    			} else {
    				return $content;
    			}
    		});
    	}
    }
    

    This trick uses the values of a custom post type which you already set when you built out your custom post types.

    Customizing the Content Further

    Now that we’ve changed ‘featured’ to match our custom post types, it’s time to take it even further. Can we smartly add in the image size? Usually the answer here is no, because it’s impossible to know what you want to have as your featured image size for each custom post type. As it happens I can because I was smart.

    Every single CPT that has a special image has an image size for it:

    add_image_size( 'character-img', 150, 200, true );
    add_image_size( 'show-img', 960, 400, true );
    

    And my post-names for those things are ‘post_type_characters’ and ‘post_type_shows’. This means I can add the following to my filter for admin_post_thumbnail_html:

    		add_filter( 'admin_post_thumbnail_html', function( $content ) use ( $type, $name ) {
    			global $current_screen;
    			if( !is_null($current_screen) && $type == $current_screen->post_type ) {
    			    // Get featured image size
    			    global $_wp_additional_image_sizes;
    			    $genesis_image_size = rtrim( str_replace( 'post_type_', '', $type ), 's' ).'-img';
    
    			    if ( isset( $_wp_additional_image_sizes[ $genesis_image_size ] ) ) {
    			        $content = '<p>Image Size: ' . $_wp_additional_image_sizes[$genesis_image_size]['width'] . 'x' . $_wp_additional_image_sizes[$genesis_image_size]['height'] . 'px</p>' . $content;
    			    }
    				$content = str_replace( __( 'featured' ), strtolower( $name ) , $content);
    			}
    			return $content;
    		});
    

    This could even be extended to only show the image size when it was not set. For now, this does what I want.

    How’s it look?

    Not bad:

    Featured Images renamed and rebranded

    And there you have it. More information for your users to know what kind of and size image to use.

  • Recoding Taxonomies

    Recoding Taxonomies

    It’s hard to know what the future will be. When initially building out a site, it’s a game of guesswork to name things. You want to name them to be long term sustainable, but without a crystal ball, there will be missteps.

    Take, for example, the case of custom taxonomies. When my site was originally built out, it only had one custom set of tags and they were logically called sitename_tags. As the site grew, it became apparent that multiple tags were going to be needed and, in the end, it had five.

    What Are Our Names

    While it’s relatively easy to rename a taxonomy’s display name by editing the data in register_taxonomy, you don’t want to rename the rewrite after the fact. You can do it, of course, but I recommend you be really up to speed on your redirects before you try. Obviously the best choice is to pick good names in the beginning. But what names are we actually talking about?

    1. The Display Name – This is the name your readers (and you) see. Categories and Tags are display names. In my case, Stations, Clichés, and Tropes are display names. You can change these as you need.
    2. The Slug – This is the rewrite I mentioned. It’s in your URL. Don’t change this unless you know redirects.
    3. The Taxonomy Name – This is secret. You’d only know what it was if you hovered over the links and noticed that tags have a taxonomy of post_tag.

    Today we’re talking about that third one.

    Why Bother?

    If you’re the only one who really sees that you named your stations show_tag instead of show_station, why does it matter?

    As it turns out, if you’re working on the theme and plugins for a site, you will end up running into those quirks when you write a loop to perform complex displays on your data. It’s both annoying to have to always comment things like “Yes show_tag means show_station” so that future you knows what the hell you’re doing.

    Like my friend says, the best documentation for a function is a good name, and fixing the name will make you feel better and smarter.

    How To Do It

    This requires two steps:

    1) Run a search/replace on your files to swap the names out
    2) Run a search/replace on your database to swap the names out

    The reason is that those two things have to be in sync. Since my world lives in a git repo and a server with WP-CLI, I ran a search/replace on my files, pushed the changes, and then ran a quick wp search-replace show_tag show_station to clean it up.

    The important thing to note is that what you’re changing in your database is not post content, but meta information and tags tables.

  • Copyright Years for WordPress

    Copyright Years for WordPress

    At the bottom of every page on my site is a little bit of info declaring copyright: “Copyright © 2017 Mika A. Epstein”

    How do I do that and not have to update all my site themes and widgets every year? With code, of course! I have both a function I could use in themes and a shortcode I could use anywhere a shortcode can be used.

    The Code

    There are two functions, the base code and the shortcode. The concept is that if you don’t put in a year (which is the start year for your copyright) it will only show the current year. If you do put in year, it forces it to be an integer and then does a couple checks. The checks were originally as follows:

    1. Is $year ‘auto’? Force this year.
    2. Is $year this year? Force this year.
    3. Is $year equal to 0? Force this year.
    4. Is $year greater than this year? Oh, silly human. Force this year.
    5. Is $year less than this year? Use the ‘start – end’ format

    The reason for this is practical. We’re sanitizing things as early as we can, and then we’re checking for the logical and illogical entries. If someone decides the year is ‘Bob’ then intval() throws a 0 and since 0 isn’t actually a valid year in the Gregorian calendar, then I can do a simple “if 0” check.

    But … I’m not so bold as to assume the only people who will want this are using the Gregorian calendar. To be more universal, I changed the code to make the first check for if the year was set to ‘auto’ (which defaults to this year), or if it was a non-number. If it’s not a number, you get forced this year. Otherwise, the code trusts you.

    function helf_auto_copyright( $year = 'auto' , $text = '' ){ 
    	$year = ( $year == 'auto' || ctype_digit($year) == false )? date('Y') : intval($year);
    	$text = ( $text == '' )? '&copy;' : sanitize_text_field( $text );
    
    	if( $year == date('Y') || $year > date('Y') ) $output = date('Y');
    	elseif( $year < date('Y') )  $output = $year . ' - ' . date('Y');	
    
    	echo $text . ' ' . $output;
    }
    
    function helf_auto_copyright_shortcode( $atts ) {
        $attributes = shortcode_atts( array(
            'year' => 'auto',
            'text' => '&copy;'
        ), $atts );
    
        return helf_auto_copyright( sanitize_text_field($attributes['year']), sanitize_text_field($attributes['text']) );
    }
    add_shortcode( 'copyright', 'helf_auto_copyright_shortcode' );
    

    The one failing here is I only account for the common era (or ‘AD’ for those who didn’t know we all switched to CE a while back). I’m sure this can be extended to BCE if so desired. Spitballing, I’d just use negative numbers, check for them and output ‘year BCE – year CE’ instead. But that’s a little much for this use case.

    Usage

    As a shortcode: Copyright 2016 - 2025

    As a function: helf_auto_copyright_shortcode( '2016', 'Copyright' );

    Both will output the same thing (as of 2017): Copyright 2016 – 2017

    And in 2018? It will magically update for you.

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