Half-Elf on Tech

Thoughts From a Professional Lesbian

Category: How To

  • Chart.js Category Statistics

    Chart.js Category Statistics

    One of the sites I work on is using the Metro Theme by StudioPress Themes for WordPress. And on that site, I have a page dedicated to some odd stats based on the categories and tags and custom taxonomies.

    What I have is a post type ‘shows’ and a custom taxonomy called ‘clichés’ and from that I was easily able to generate a percentage of how many shows use the cliché of queers in law enforcement (38%) or how many have the death of a queer (also 38% right now). But that wasn’t enough. We wanted ‘pretty graphs’ and for that I needed a tool like Chart.js and a little PHP magic.

    How to Chart.js?

    Chart.js is a super cool and super responsive and super flexible way to include a chart. And using it is incredibly easy once I figured out that I could just use inline script tags. A very basic chart that would show you how many days each month has looks like this:

    <script src="Chart.js"></script>
    <canvas id="barDays" width="600" height="400"></canvas>
    
    <script>
    var barDaysData = {
    	labels : ["January", "February", "March", "April", "May", "June", "July", "August", "September", "November", "December"],
    	datasets : [
    		{
    			fillColor : "#7d3255",
    			strokeColor : "#532138",
    			data : ["31","28","31","30","31","30","31","31","30","31","31"]
    		}
    	]
    }
    
    var barDays = document.getElementById("barDays").getContext("2d");
    new Chart(barDays).Bar(barDaysData);
    </script>
    

    If you’re using WordPress, you’ll want to use wp_enqueue_script to call it. Here’s what I did for my theme:

    wp_enqueue_script( 'chart.js', get_bloginfo('stylesheet_directory').'/inc/js/Chart.min.js' , array( 'jquery' ), CHILD_THEME_VERSION );

    But that’s the basics of it. Once I understood that, I was good to go.

    The Code

    Before I can do anything, I need to make sure I have the data I needed. What I wanted was a list of all the shows that were published and a list of all the cliches, ordered in the way I need them. The order is simply comma separated values, enclosed in quotes, enclosed in brackets:

    labels : ["January", "February", "March", "April", "May", "June", "July", "August", "September", "November", "December"],
    

    And the data is similar:

    data : ["31","28","31","30","31","30","31","31","30","31","31"]
    

    Since I’m lazy, I checked that the array worked if it ended in a , and it did! That means my PHP looks like this:

    $count_shows = wp_count_posts( 'post_type_shows' )->publish;
    $cliches = get_terms('cliches');
    
    $barshow_labels = '';
    foreach ( $cliches as $cliche ) {
    		$barshow_labels .= '"'.$cliche->name.'",';
    }
    
    $barshow_data = '';
    foreach ( $cliches as $cliche ) {
    		$barshow_data .= $cliche->count.',';
    }
    

    And my js looks like this:

    <script>
    var barShowsData = {
    	labels : [<?php echo $barshow_labels; ?>],
    	datasets : [
    		{
    			fillColor : "#7d3255",
    			strokeColor : "#532138",
    			data : [<?php echo $barshow_data; ?>]
    		}
    	]
    }
    
    var barShows = document.getElementById("barShows").getContext("2d");
    new Chart(barShows).Bar(barShowsData);
    </script>
    

    You may notice the simple call of <?php echo $barshow_data; ?> in there? That’s where it outputs the data I sorted out in the PHP section. Done. I’m could put it more inline, but I liked to separate them as much as I could.

    Putting it in the theme

    This is a Genesis theme so while I am making use of the Genesis loop, the call to get_template_part can be used by anyone. I’ll explain in a moment. First, here’s the page template:

    <?php
    /**
    * Template Name: Lezbian Stats Template
    * Description: Used as a page template to show page contents, followed by a loop
    * to show the stats of lezbians and what not.
    */
    
    // Show Dead count below the content:
    add_action( 'genesis_entry_footer', 'lez_stats_footer', 9 );
    
    function lez_stats_footer() {
    	get_template_part( 'stats' );
    }
    
    genesis();
    

    This works like any other page template. You make a page, you select the template, and it loads this custom design.

    The magic sauce is in get_template_part( 'stats' ); which calls the file stats.php and that file has all the code you saw above. This means I can edit my post with all the explanations I want, and then it always outputs the stats on the bottom. By calling the Genesis code in the bottom, I retain all of it’s magic while pulling in what I want.

    The Result

    The graph of cliches about queer women on TV

    Looks nice, doesn’t it? I’m quite fond of it.

  • Composer and WordPress’ Plugin Preflight Check

    Composer and WordPress’ Plugin Preflight Check

    When you upload a plugin to WordPress.org’s repository, it does some pre-flight checks to make sure the code is okay. More than once it’s caught a missing ; for me. But one day it caught this:

    PHP error in: myplugin/tags/0.6/aws/Doctrine/Common/Proxy/ProxyGenerator.php:
    Errors parsing myplugin/tags/0.6/aws/Doctrine/Common/Proxy/ProxyGenerator.php
    

    I stared for a moment, Googled to be sure, and sighed when I figured out that what was happening was my library was a PHP 5.6+ version and that didn’t pass the 5.4 checks.

    Regardless of how annoying this is, it’s not too hard to fix. No, I’m not going to tell you how to avoid the scan, nor am I going to talk about the stupidity of the scan. Instead I’d like to tell you how to get around this problem.

    It’s so easy, too.

    You see, my issue is that I use Composer to build my resource libraries and in my composer.json file, I have this:

    "require": {
    	"aws/aws-sdk-php": "2.7.*",
    	"doctrine/orm": "*",
    	"monolog/monolog": "*"
    },
    

    And for what it’s worth, this is great. I have it download all my libraries. Then I have it run a script to copy over just what I need to my aws folder and I have Git and SVN ignore the vendor folder. Everyone wins! The problem is that Composer sees that my laptop is running PHP 5.6 and so it installed version

    Fix PHP on Your Computer

    Since I use Homebrew on my Mac, this is super easy for me.

    $ brew unlink php56
    $ brew install php54
    

    Then when I re-run composer update it will install what I need.

    The problem here, though, is that this is tied to a specific computer, and if a coworker downloads my stuff and plans to fork it, they’re SOL and merges fail and it’s sad times all around. So with that in mind, uninstall 5.4 and go back to 5.6.

    If you have a problem with installing 5.6, run it this way:

    $ xcode-select --install
    $ brew unlink php54
    $ brew install php56
    

    Fix PHP in Composer

    I like this fix better. Put this above your require statement and you’ll force Composer to build based on PHP 5.4:

    "config": {
    		"platform": {
    		"php": "5.4"
    	 }
    },
    

    Now we’re cooking with fire. This works for everyone, it forces Composer to download 5.4 compatible libraries, and my very long transmission worked.

    Is This Perfect?

    Obviously not. There are going to be cases where your code absolutely has to be the code for PHP 5.5 and up. The latest version of the AWS SDK is v3, for example. But it’s for 5.5 only. I personally don’t feel there’s enough of a buy-in for PHP 5.5 and up yet to make an issue of it. And having no check at all won’t fly.

  • Making Plugins Filterable

    Making Plugins Filterable

    I’m really bad at thsi since, generally, I don’t know why people would want to with the plugins I make. Which means I don’t do it. Which means I didn’t know how.

    I have a plugin that records the IP address of users as they register and outputs it on the ‘show users’ page. It’s simple and it works.

    Someone asked me if I could make it link to a place where he could see where the IP was from. Now my intent with the plugin was to list the IPs so I could spot serial sock puppets. But this use-case, I agreed, was valid. I just didn’t want to tie my plugin into one service or another. So I made it filterable.

    As it happens, it was incredibly simple. This is filed under “Stuff I should have known years ago…”

    Make The Output Filterable

    Originally I had the code outputting $theip and, in order to make it filterable, I wrapped that with this:

    if ( has_filter('ripm_show_ip') ) {
        $theip = apply_filters('ripm_show_ip', $theip);
    }
    

    The whole function looks like this:

    	public function columns($value, $column_name, $user_id) {
            if ( $column_name == 'signup_ip' ) {
                $ip = get_user_meta($user_id, 'signup_ip', true);
                if ($ip != ""){
                    $theip = $ip;
    				if ( has_filter('ripm_show_ip') ) {
    					$theip = apply_filters('ripm_show_ip', $theip);
    				}
                    return $theip;
                } else {
                    $theip = '<em>'.__('None Recorded', 'register-ip-multisite').'</em>';
                    return $theip;
                }
            }
    	    return $value;
    	}
    

    You’ll notice the has_filter() check is only on one possible output? That’s because I’m translating the output on the other one, which says “None Recorded” I could filter that, so people could change it to anything they want, but right now I think that’s a bit odd.

    Filter The Output

    To test this, I made a file /mu-plugins/register-ip-multisite.php and put the following inside:

    function filter_ripm_show_ip($theip) {
        $theip = '<a href="https://duckduckgo.com/?q='.$theip.'" target="new">'.$theip.'</a>';
        return $theip;
    }
    add_filter('ripm_show_ip', 'filter_ripm_show_ip');
    

    That made it a link. Simple.

    Does It Work?

    Of course!

    Example of users screen with the IP showing as a link

    I did not apply the filter to the output on the edit-users page, but if that turns out to be needed, I can.

  • Unique vs Common

    Unique vs Common

    Someone asked me if I could explain why sometimes I tell people to name their functions uniquely and sometimes I don’t.

    I get how this is confusing, even though it makes perfect sense to me. Here’s how to remember:

    • What’s yours is unique to your plugin
    • What’s common is unique to what’s common

    Okay, maybe that didn’t help. Let’s try a practical example!

    I have a plugin called ‘Genericon’d’ which includes the Genericons library inside. In that plugin, I have the following enqueues:

            wp_enqueue_style( &#039;genericons&#039;, plugins_url( &#039;genericons/genericons/genericons.css&#039;, __FILE__ , &#039;&#039;, self::$gen_ver ) );
            wp_enqueue_style( &#039;genericond&#039;, plugins_url( &#039;css/genericond.css&#039;, __FILE__ , &#039;&#039;, self::$gen_ver ) );
    

    The first one is for Genericons, the library. There I use the common name of genericons which means if anyone else also enqueues Genericons with this name, one of ours will win depending on load order. For my personal plugin CSS, I use the name genericond (notice that D?) as it matches the name of my plugin and, therefore, is less likely to conflict with someone else’s plugin.

    Conflict is the name of the game here. I actually want genericons to conflict. Well, not conflict. I want it to be recognized as a shared library, so WordPress only loads it once. If I had named it genericond-genericons then, in the event someone has Jetpack or a theme like TwentyFifteen which both include Genericons, they would load the entire library twice! And I would suck. On the other hand, if we all share the library name, WordPress will check, see it’s loaded, and carry on.

    Name what’s yours in a way unique to your plugin or theme.

    Name what’s shared in a way that’s unique, but also stupid obvious and easy to share.

    Font-Awesome? Use font-awesome for your enqueues.

    As for functions and class names, even if you put in a check for ‘if this doesn’t exist…’ the logic works the same. If it’s yours and yours alone and only exists in this code, name it unique to your plugin/theme. If it’s a shared library, like the aws-sdk, name the class in the standard way and wrap it in an ‘if this doesn’t already exist…’ so that if it does exist, it only gets called once.

    Standard names for shared libraries.

    Unique names for your personal codes.

    And bonus! If you keep your names to a standard, while being unique, someone may call your functions too.

    By the way, anything global like DEFINE( 'FOO', true ); should always be unique. Those are globals. Everyone uses them. I’ve made that mistake too.

  • Packaging and Shipping Resource Folders

    Packaging and Shipping Resource Folders

    No, I don’t mean resources to get help.

    Have you ever opened a plugin or theme and seen a folder that says bower_components or node_modules? Yeah, I hate those. I don’t hate Bower or Node, I use them quite a lot. I hate how people use them in their plugins.

    What Are Those Folders?

    In order to make life easier, Bower is a package manager that lets you install libraries that your plugin needs. Making a plugin that needs AWS SDK?

    bower install aws-sdk-js

    Boom. And you can easily upgrade it too with bower update – which I love. This is a great idea.

    $ bower install aws-sdk --save
    bower aws-sdk#*                 cached git://github.com/aws/aws-sdk-js.git#2.2.28
    bower aws-sdk#*               validate 2.2.28 against git://github.com/aws/aws-sdk-js.git#*
    bower aws-sdk#~2.2.28          install aws-sdk#2.2.28
    
    aws-sdk#2.2.28 bower_components/aws-sdk
    

    But notice that last line? bower_components/aws-sdk is where it saved my files. And if I go in there, the JS file I need is bower_components/aws-sdk/dist/aws-sdk.min.js and that is surrounded by other files:

    Deep down the bower rabbit hole

    Now as a developer you have a couple choices here. You can leave the file where it is and just call it from there or you can move it. If you move it, you want to make a simple way of updating it. After all, the whole point of using Bower here is to make life easier. Personally I use Grunt for these things. I talked about it last year but my basic idea is to use Bower to download the latest and greatest versions, and then Grunt takes care of (a) updating the Bower packages and (b) copying the files to where I need them.

    Okay, but what if I have something a little more complex?

    What Resources Do I Need?

    This seemingly innocuous question is surprisingly deep. It’s not just ‘what package/library am I trying to manage’, but how do I manage it and with what? What if, instead of the javascript, I wanted to use the PHP AWS SDK instead? Well, the AWS SDK for PHP is not available in Bower! Instead it uses Composer.

    Here’s where things get weird. Composer is a package manger. Grunt is a package manager. Node and Bower are too. This means I have to stop and think hard. Which one do I need? Why do I need it? What am I going to be managing?

    It’s time to ask this:

    What Are My Packages For?

    Within Node there are two kinds of packages:

    • “dependencies”: these packages are required by your application in production
    • “devDependencies”: these packages are only needed for development and testing

    Take a moment to think what you need to dev and what you need to run. Your test code doesn’t need to be in your release, does it? No, of course not. It would make perfect sense to have in your Git or personal repository, but the WordPress SVN repository is not actually for your own code management. It’s a release management tool. That’s another post for another time. Just keep in mind that you should really only be pushing your code to SVN when it’s a version ready for use (be that beta testing or releases).

    Back to what things are for. When talking about the AWS SDK javascript, I’m talking about front end packages. So that’s a dependancy. But Bower? It’s a devDependency. The users don’t need to know (or care) that I’m using Grunt and Bower to package things up. That means they shouldn’t be installed in my plugin!

    In the case of my AWS SDK a ‘devDependency’ is Composer. I only need it to build my packages.

    My dependencies are as follows:

        "require": {
    	    "aws/aws-sdk-php": "2.*",
    	    "doctrine/orm": "*",
    	    "monolog/monolog": "*"
    	}
    

    Adding that to my composer.json file is a simple thing and now I can just run composer update to get everything I need!

    Where Should My Packages Live?

    This is generally pre-destined. If you use Node they go in node_modules and Bower likes bower_components and Composer uses vendor and so on and so forth. You can, of course, customize these. I often make a folder called ‘assets’ or ‘assets-dev’ so I can easily ignore it in my version control. Frankly I don’t need them and neither do my users and it’ll help save space.

    There’s a cool thing about composer. If you use composer init then it asks, at the end “Would you like the vendor directory added to your .gitignore [yes]?” This is great, because if you looked at the folder vendor you would see a lot of folders and files you don’t really want. I actually only want one folder vendor/aws/aws-sdk-php/src/Aws/ and I want that folder to be located in aws/Aws please and thank you. Composer adds this into .gitignore for you.

    You’ll still have to add that into your SVN ignore file, which is a little more annoying. To ignore all composer.* files it’s this:

    svn propset svn:ignore "composer.*" .

    And if you want to ignore multiple files or folders use the following command to bring up the text editor:

    svn propedit svn:ignore . 

    For SVN I would ignore composer.json, composer.lock, and the vendor folder.

    How Do I Move Folders?

    Remember I want to move things to another folder? I use Composer’s scripts to do this. I admit this is ugly code. I have this in my composer.json:

    	"scripts": {
            "post-update-cmd": [
    	        "rm -rf aws/Aws",
    	        "cp -r vendor/aws/aws-sdk-php/src/Aws aws/",
    	        "rm -rf aws/Doctrine",
    	        "cp -r vendor/doctrine/common/lib/Doctrine aws/",
    	        "rm -rf aws/Guzzle",
    	        "cp -r vendor/guzzle/guzzle/src/Guzzle aws/",
    	        "rm -rf aws/Monolog",
    	        "cp -r vendor/monolog/monolog/src/Monolog aws/",
    	        "rm -rf aws/Psr",
    	        "cp -r vendor/psr/log/Psr aws/",
    	        "rm -rf aws/Symphony",
    	        "mkdir -p aws/Symphony/Component/EventDispatcher",
    	        "cp -r vendor/symfony/event-dispatcher/* aws/Symphony/Component/EventDispatcher/"
            ]
        }
    

    This runs whenever I run composer update in this folder and it copies everything where I need it to be. I did tell you it was ugly, right? But it does work.

    The Result?

    The result is my vendor code is never uploaded to WordPress.org’s SVN, my users never see the stuff they don’t care about, and I have a faster way to update my plugins when I need to make sure all the packages are right.

  • WP JSON API Challenges

    WP JSON API Challenges

    In my frustration of my static process, I ripped everything out by it’s roots and decided to take things in a strict order.

    Decision: All-In-One or Separate?

    The first question was do I want to download everything as one big JSON file and split it out later, or do I want to, from the start, download each post as it’s own file? The time to download shouldn’t change, and if I do it right, I could script it to check if the date stamp on my downloaded file was older than the post date in WP. That means I could have this logic:

    if ( ! post file exists || post file date < post datestamp ) {
        download JSON for this post
    }
    

    That made it an easy win. Let’s split away from the original plan. Now my goal is to extract all the posts from my WP site in JSON format.

    Remember the goal here is to run a static website with WP. There are plugins that convert WP to static HTML, which you can then use to power a site, and this isn’t a bad idea.

    How To: Get all the posts from a WP site via the JSON API?

    This sounded easy. http://local.wordpress.dev//wp-json/wp/v2/posts listed posts, and the v1 comparison chart says that you can list all posts, it stands to reason that I can easily get all my posts.

    In a way, this is a WordPress problem. WP doesn’t want you to show all posts. It would make your site very slow if you had, say, 10,000 posts. Which means that the claim that the JSON API can lists all posts is true, it just doesn’t do them all at once.

    I happen to have 40 published posts on my test site, so when I GET with this URL, it loads all of them: http://local.wordpress.dev//wp-json/wp/v2/posts?per_page=100

    But that isn’t sustainable. And the old trick of making per_page equal to -1 didn’t work.

    I did determine that the JSON API actually knows what the amount of posts is!

    JSON reports X-WP-Total which, in my case is 40

    The header “X-WP-Total: 40” is what I needed. Of course, that is rather weird to get. It means to get all the files, I have to write ‘something’ that does this:

    1. Get http://local.wordpress.dev//wp-json/wp/v2/posts and parse it to get the value of X-WP-Total
    2. Get http://local.wordpress.dev//wp-json/wp/v2/posts?per_page=X-WP-Total

    Okay. So how?

    Well remember how I mentioned a plugin that made a static site already? I was talking about things like Really Static. Save a post, it saves the JSON file! Why not write this plugin?

    Why not use “Really Static”? Well I don’t want to have WP doing more than be my content generator. I want to separate content (the blog) from WP. And that means I will end up writing a plugin…

    Am I In Too Deep? Or Am I Over My Head?

    So far, this has been an incredible amount of work. It’s been a lot of two steps forward and three steps back, over and over and over. And yes, it’s been very frustrating. I’ve given up many times and, if my posts about multiple approaches are any indication, I’ve deleted and restarted many, many times.

    And I have to be honest here… I’m giving up on this overly ambitious plan right now.

    This marks two major failures (three if I could how insane the entire ‘use Jekyll/Hugo to run a gallery’ was). First, I’ve failed to sensibly convert JSON files to MD in a scriptable and reproducible way. Second, I’ve failed to export JSON from WordPress in a simple way. Both those failures can be worked around. I can build a plugin that exports the JSON. It’s not trivial, but having done similar things I’m sure I can do it. The issue is ‘is it worth it’? And right now I think the answer is no.

    I’m back to the drawing board right now, sketching up new plans and ideas. I want to eliminate as many steps as possible. I’d like to leave WordPress alone, let it be WordPress, and similarly let my static generator be static. These failures have taught me more about the interdependencies than I expected, and I’ve learned more from them than I may have if I’d had outright success from the start.

    While I’m starting over, again, I feel hopeful and less ‘I hate you, JSON’ than I thought I would. I now understand things more clearly and I see how I made things far, far more complicated for myself.

    The future of this project is, weirdly, bright.