Half-Elf on Tech

Thoughts From a Professional Lesbian

Category: How To

  • Deploying from GitHub with Codeship

    Deploying from GitHub with Codeship

    For the longest time I self-hosted all my git repositories not so much because I enjoyed doing so but because there were limited options for easily pushing code from git to my servers. Invariably you will end up using an intermediary because GitHub and their peers have no real reason nor inclination to make those things easy for you. After all, if they can keep you in their systems, more money to ’em.

    And while that’s perfectly understandable and logical, it’s annoying. And if you’re on a budget and not a Git Expert, it’s extremely frustrating. The deployment API was written in High Level Geek, and I found it a headache to decipher and test.

    Thankfully there are tools for that, and one of them in Codeship. Codeship is free for 100 builds a month, and unlike DeployHQ, it uses rsync, which meshes with my preferred way of moving data.

    The Plan

    My plan is simple. I want to push code to a Github Repository and, when it’s a push to master, it would rsync the files over to my server. This will allow multiple people to work on code, among other things.

    The Setup

    First make an account with Codeship. You can log in as Github which is useful since you’ll want to connect your Github account with Codeship anyway. When you create a project, you’ll be prompted which SCM you want to use:

    Create a Project in Codeship

    I’m using Github, but it’s nice to see GitLab in there as well. Once you pick your SCM, paste in the clone URL.

    Examples:

    • git@github.com:<username>/<repository_name>.git
    • https://github.com/<username>/<repository_name>.git
    • https://github.com/codeship/<repository_name>

    Finally you can pick Codeship Pro or Basic – I picked Basic because it required the least amount of know-how. Not that it’s easy, but I don’t have to configure the server or anything annoying. In fact, Basic is so basic, than you can just accept the default setup commands and go. Which is what I did.

    The Settings

    Once you’ve done all that, you’re on a new screen that tells you to push code. Of course, you can’t do that until you set up a couple more things. Like tell it where to push the code.

    Click on “Project Settings” and go to the General tab. You’ll need to get that SSH key and add it to your server’s ~/.ssh/authorized_keys to allow passwordless deployment. I strongly recommend that.

    Now you can click Deploy and add a Deployment Pipeline. Pick ‘master’ unless you’re using something else.

    Now you have to add a deployment to your pipeline. There are a lot of options here, but for my plan of an rsync, the choice is “Custom Script”. Since I’m pushing code to my DreamPress server, the rsync looks like this:

    # DreamPress
    rsync -aCz -e "ssh" ~/clone/ wp_e413xh@mysite.dream.press:/home/wp_e414xh/mysite.dream.press/wp-content/themes/my-theme-name/ --delete
    

    You can customize your rsync commands however you want. I like mine to delete files I’ve removed.

    Deploy the Ships

    Everything is set up so go back to your project page and push some code to Github

    Magic happens.

    The code deploys.

    Huzzah.

    On the free version you only get 100 private builds and five private projects. Mine are public (so’s the Github repo for that matter) so it doesn’t matter. The only downside is only getting one push at a time, but since they take less than five minutes, it’s perfectly acceptable for a free solution.

  • Demi Related Post Types

    Demi Related Post Types

    In my last post, I talked about relating posts to a custom post type. That is, how I listed the blog posts tagged with a show on the show page. Let’s do the reverse!

    Continuing the Click Hole

    While we’re very good about remembering to tag the posts we write with the shows they’re about, we’re not always as good with remembering to link the first instance of the show name to the show. That is, when we write about Supergirl we sometimes forget to link that to the page for her.

    That said, we still want to make it ‘easy’ for people to figure out where they can read more about the show. The ‘simplest’ way to do that would be to have a block at the bottom of each blog post. “Want to know more about the shows in this post?” or something along those lines.

    Relations Back Across Post Types

    The difficulty here is that if you want to get post data based on a post name, it’s easy. There’s a handy little function get_page_by_title() where you can put in this: get_page_by_title( 'Supergirl', OBJECT, 'post_type_shows' ); where Supergirl is the name of the show and post_type_shows is the post type.

    That’s well and good, but I knew there would be cases where the tag wasn’t going to match the name. People name shows pretty weird stuff (#hastag for example is the name of a show). Instead, I knew that I needed the tag slug and for that, I needed a different function: get_page_by_path()

    The Code

    Here’s the magic sauce:

    function related_shows( $content ) {
        if ( is_singular( 'post' ) ) {
    		$posttags = get_the_tags( get_the_ID() );
    		$shows = '';
    		if ( $posttags ) {
    			foreach ( $posttags as $tag ) {
    				if ( $post = get_page_by_path( $tag->name, OBJECT, 'post_type_shows' ) ) {
    					$shows .= '<li><a href="/show/' . $post->name . '">'. $tag->name . '</a></li>';
    				}
    			}
    		}
    		if ( $shows !== '' ) {
    			$content .= '<section class="related-shows"><div><h4 class="related-shows-title">Read more about shows mentioned in this post:</h4><ul>' . $shows . '</ul></div></section>';
    		}
    	}
    	return $content;
    }
    

    This has a few failsafes in there, like it only runs on single posts, it has to have at least one tag, and it has to have at least one tag that’s a show. Whew.

    After that, it’s just the CSS.

  • Semi Related Posts

    Semi Related Posts

    Once in a while you write some code that you’re pretty sure will never be useful to anyone else on the planet, but the idea is cool, so you want to share it.

    Hence this post.

    The Power Of Relations

    I was making coffee one Sunday morning, thinking about how I could keep turning a site into a wiki-level click hole, where a person could get lost for hours and days reading article after article. The reason WikiPedia works so well is that the content is all interlinked. Now, if you’ve never been a wiki editor, and you’ve just noticed that there are a billion links on every page, taking you around the universe, I’ll let you in on a secret. Those links are all human-made. A person goes in and makes those links, giving you ‘related’ posts.

    But WikiPedia really only works well due to the massive amounts of people who know weird shit and are willing to help and share. When it’s just you and your crazy friend running a site, that’s a lot of work. And you have wives and pets and kids to take care of. No, you want– you need to automate the heck out of this stuff.

    Related Posts are Hard

    Making related posts is a hard thing. There are myriad algorithms out there to calculate ‘relatedness’ and they’re all crazy complex. Worse, they all require a lot of processing power. There’s a reason Jetpack’s related posts feature runs on their servers. They’ve got more power than you do, and it stops people on shared from being nasty neighbors.

    This code is not a replacement for that code. This code is very specific and very targeted. It relies on people being clever (but not too clever). But when it works, it makes the interwoven data sets of a site work well. Because you see, we’re not talking about ‘If you like this article, read this other one…’ No. No we’re talking about crossing custom post types.

    Relations Across Post Types

    Hold on. I know what you’re thinking.

    The point of separate post types is not to cross the streams. Yes, I know. But that’s actually not true. Menus, for example, are a post type, and you a great many people want to have specific menus to their post types. That sounds logical, doesn’t it? Well, in this case, I have a post type for TV Shows, and I have regular old blog posts.

    My lightbulb moment was three-fold:

    1. When we write articles about the TV Shows, we logically use tags of the show name.
    2. Those show name tags match the slugs of the TV shows.
    3. If we link back to the articles from the TV Show page, then we’re getting people down the click hole.

    This meant my logic was simple: On the TV show page, check if there are any blog posts tagged with the show name and, if so, that post was ‘related’ to the show and therefore we should link back to it.

    The Code

    I put all this into a function so I could re-use it in a couple places. I like not repeating myself with code. I also have the function call another function, because I actually re-use this to connect different post types that all use the same tags. If you don’t need that, you can tighten it up.

    The Display

    This is in the theme:

    $slug = get_post_field( 'post_name', get_post() );
    $term = term_exists( $slug , 'post_tag' );
    if ( $term !== 0 && $term !== null ) { ?>
    	<section name="related-posts" id="related-posts" class="shows-extras">
    		<h2>Related Posts</h2>
    		<?php echo related_posts( $slug, 'post' ); ?>
    	</section> <?php
    }
    

    The Functions

    And here’s the function it calls:

    function related_posts( $slug ) {
    	$related_post_loop  = related_posts_by_tag( 'post', $slug );
    	$related_post_query = wp_list_pluck( $related_post_loop->posts, 'ID' );
    
    	if ( $related_post_loop->have_posts() ) {
    		$the_related_posts = '<ul>';
    		foreach( $related_post_query as $related_post ) {
    			$the_related_posts .= '<li><a href="' . get_the_permalink( $related_post ) . '">' . get_the_title( $related_post ) . '</a> &mdash; ' . get_the_date( get_option( 'date_format' ), $related_post ) . '</li>';
    		}
    
    		$the_related_posts .= '</ul>';
    	}
    
    	return $the_related_posts;
    }
    

    And here’s the function that calls:

    function related_posts_by_tag( $post_type, $slug ) {
    	$term = term_exists( $slug, 'post_tag' );
    	if ( $term == 0 || $term == null ) return;
    
    	$count = '5';
    	$query = new WP_Query( array(
    		'post_type'       => $post_type,
    		'posts_per_page'  => $count,
    		'no_found_rows'   => true,
    		'post_status'     => array( 'publish' ),
    		'tag'             => $slug,
    		'orderby'         => 'date',
    		'order'           => 'DESC',
        ) );
    
    	wp_reset_query();
    	return $query;
    }
    

    The Result?

    An unordered list of the last five related posts. You could add a link to ‘show more’ if you were so included.

  • Stopwords and Sort Queries

    Stopwords and Sort Queries

    The code I use is part and parcel from a comment Pascal Birchler made in 2015 and Birgir E. riffed on in 2016. I made one small change.

    The Problem

    People like to name TV shows with ‘The’ or ‘A’ or ‘An’ as the first word. “The Fall” and “The Good Wife” for example. However, when we order such things in a human sensible way, “A Touch of Cloth” should be listed behind both of those.

    • Frankenstein
    • The Fall
    • Grey’s Anatomy
    • The Good Wife
    • A Touch of Cloth

    WordPress, though, sees them as absolutes and you get this:

    • A Touch of Cloth
    • Frankenstein
    • Grey’s Anatomy
    • The Fall
    • The Good Wife

    Not quite right, is it?

    The Fix

    This code does two things.

    The first part is the filter on the posts_orderby function. That checks if the post type is the one I want to filter (in my case, only shows), and if so, use regex to filter out my stop words of ‘the ‘, ‘an ‘, and ‘a ‘. The extra space in each word is important. I want to reorder “The Fall” and not “Then They Fall” after all!

    The second part is the actual filter on the title, to mess with it only for the ordering of posts.

    add_filter( 'posts_orderby', function( $orderby, \WP_Query $q ) {
        if( 'post_type_shows' !== $q->get( 'post_type' ) )
            return $orderby;
    
        global $wpdb;
    
        // Adjust this to your needs:
        $matches = [ 'the ', 'an ', 'a ' ];
    
        return sprintf(
            " %s %s ",
            MYSITE_shows_posts_orderby_sql( $matches, " LOWER( {$wpdb->posts}.post_title) " ),
            'ASC' === strtoupper( $q->get( 'order' ) ) ? 'ASC' : 'DESC'
        );
    
    }, 10, 2 );
    
    function MYSITE_shows_posts_orderby_sql( &$matches, $sql )
    {
        if( empty( $matches ) || ! is_array( $matches ) )
            return $sql;
    
        $sql = sprintf( " TRIM( LEADING '%s' FROM ( %s ) ) ", $matches[0], $sql );
        array_shift( $matches );
        return MYSITE_shows_posts_orderby_sql( $matches, $sql );
    }
    

    If you’re using MariaDB, this can be even easier, but I have to test on my dev site, which uses MySQL.

  • Date, Time, and PHP

    Date, Time, and PHP

    I had a case where I needed to convert time from the format of the US centric dd/MM/YYYY to something a little more sane.

    A Very Bad (and Stupid) Way

    Since I was starting from a set position of 18/07/2017 (for example), the first idea I had was to use explode to do this:

    $date = "18/07/2017";
    $datearray = explode("/", $date);
    $newdate = $date[1].'-'.$date[0].'-'.$date[2]
    

    I did say this was stupid, right? The reason I’d want to do that, though, is that gets it into a DD-MM-YYYY format, which can be parsed a little more easily. Unless you’re an American. Which means this idea is useless.

    A Less Bad, But Still Bad, Way

    What about making it unix timestamp?

    $date = "18/07/2017";
    $date_parse = date_parse_from_format( 'm/d/Y' , $date);
    $date_echo = mktime( $date_parse['hour'], $date_parse['minute'], $date_parse['second'], $date_parse['month'], $date_parse['day'], $date_parse['year'] );
    

    Now I have a unix timestamp, which I can output any which way I want! At this point, if I’m not sure what version of PHP people are using, as long as it’s above 5.2, my code will work. Awesome.

    But we can do better.

    A Clever Way

    Instead of all that, I could use date_parse_from_format:

    $date = "18/07/2017";
    $date_parse = date_create_from_format('m/j/Y', $date );
    $date_echo[] = date_format($date_parse, 'F d, Y');
    

    And this will convert “18/07/2017” into “18 July, 2017”

    Which is far, far more understandable.

    So Which Is Best?

    If it’s your own code on your own server, I’d use date_create_from_format to control the output as you want.

    If this is code you want to run on any server, like in a WordPress plugin, use the unix timestamp, and then use date_i18n to localize:

    date_i18n( get_option( 'date_format' ), $date_echo );
    
  • Yes, You Can Use Enqueues

    Yes, You Can Use Enqueues

    One of the battles I face with plugins is explaining to people that they really do need to use wp_enqueue_scripts() for their code. And often I get an argument back that they can’t because they need to include parameters.

    Hold on to your hats. You totally can.

    The Misconception

    It’s easy to get confused with code. There are so many different ways to solve the same problem, we get twisted around. Let’s say that you wanted to include the following script in your website:

    <script src="https://mycoolsite.com/widget.js" async></script>
    

    That’s pretty straightforward in WordPress:

    wp_enqueue_script( 'my-widget', 'https://mycoolsite.com/widget.js', array( 'jquery' ), 1.0.0 );<
    

    But. What if you wanted to add this as well:

    <script type="text/javascript">
        var _widget_options = {
            theme: 'slow' // Choose from 'fast', 'stop', and 'slow'. Remove this property to get the default theme.
    };
    </script>
    

    Now you clearly have to hand-code this into WordPress. Right?

    Wrong!

    Use Inline Scripts!

    You may have heard about wp_add_inline_script before. If not, don’t feel bad. What this does is add extra, inline, code to an already enqueued script.

    Which means that to add the extra code, you do this:

    wp_add_inline_script( 'my-widget', 'var _widget_options = { theme: "slow" }', 'before' );
    

    Which will echo out exactly what you need.

    The cool thing about this, is what if you want your plugin to have a lot of options? Like you want to use the value for an option to determine what your script should do?

    $my-widget-inline = 'var _widget_options = { theme: "' . get_option( 'my-widget-theme' ) . '" }';
    wp_add_inline_script( 'my-widget', $my-widget-inline, 'before' );
    

    And now you’ve got flexibility.

    Keep In Mind…

    First, the name of the script matters. If you enqueue it as ‘my-widget’ then you call it as ‘my-widget’ as the first parameter in your inline script.

    Second, you can change ‘before’ to ‘after’ if you need it to be after the script.

    Third, as with all things, make sure you only load your javascript when you must. No one likes a slow site because you’re loading your javascript on every page when it only needs to be on a specific custom post type.