Half-Elf on Tech

Thoughts From a Professional Lesbian

Author: Ipstenu (Mika Epstein)

  • Two Forks In The Road

    Two Forks In The Road

    I believe in healthy competition.

    Rivals, professionally and personally, have the ability to inspire us to reach great heights. They also have the ability to be terrible, but when a true rival, who respects you and your work, arrives, they should be embraced.

    The other day I said that I would love to see a W3TC killer. Killer was the wrong word, as what I mean is that I would love to see something as amazing as W3TC that reaches out and tackles caching in a new and inventive way. I’d also love to see a WordPress killer, an iPhone killer, and a Linux killer. And a Hybrid Car killer.

    I don’t mean I want any of those things to fail, I mean I want to see them have a challenger who does what they do, differently, in a way that inspires them to do more and more and better.

    Growth stagnates without good rivalry. When you have a rival who does what you do, and they succeed, you want to succeed. When you’re both healthy rivals, you can carry it even further. Reaching out to your rivals and telling them “I am impressed with how you did X! Nice job!” is the greatest gift. With WordPress code, taking a leaf from their book and forking some of their code (with credit) is another way to hat-tip them.

    In truth, W3TC and WP Super Cache never really competed. They can’t. They have wildly different approaches to just about everything, and they’re not even ‘after’ the same customer base. WP Super Cache appeals to people with it’s simplicity and directness. It works and you can (mostly) ignore it. W3TC has an insanely deep and complex set of tools that works closer to the base level of a server. W3TC has options, oh my god it has options, and they can overwhelm.

    But the real crux to all this, besides the take away that caching is hella hard, is that there is always more than one way to solve a problem. And there is always room for multiple solutions in any ecosystem. It comes down to needs, wants, and user preferences. Both plugins I’ve named here do a great job at meeting the needs for their audiences. And both plugins grew out of someone’s need. Donnacha and Fredrick both created something to solve their own problems. They shared these solutions with the world and became unintentional rivals and kings of caching.

    Okay so back to what I said.

    Should there be a ‘killer’ caching plugin? Will there be one?

    Maybe.

    There should never be one killer app, no matter what it is. There should never be one perfect solution. Mostly because I don’t believe there’s such a thing. There’s nothing we can create that will suit everyone’s needs and wants. It’s statistically impossible. So when we talk about a ‘killer’ anything we never mean that. We mean “There should be options and the options creators should be healthy competition with each other to create some awesome things.”

    And I really truly thing we should do that. I would love to see someone tackle WordPress with a serious self-hosted alternative. Something easier to install on my own than Ghost, but as easy as Hugo or Jekyll to write a post. Something extendable like Drupal, but with better backwards compatibility. Something next. And I want to see WordPress take what it learns from those other tools to become even more.

    Because healthy rivalry between friends and equals is a good thing.

  • Google Knowledge Blindspot

    Google Knowledge Blindspot

    With the new release of Yoast SEO 3.6, I decided to test out their new walk-through setup.

    As someone who’s been studying SEO to one degree or another since the 1990s, SEO in and of itself is no great mystery to me. The bare bones of how it works, how you make good content, is understandable. But what Yoast SEO does, and what I like it for, is it makes it obvious to people without my experience what is needed. It also takes the generally good SEO of WordPress (and a good theme) and optimizes it for the myriad, constant changes that Google does.

    For that, the walk-through is a wonderful idea. I like it. I think new users will love it. I think it’ll lessen the barrier to those people who are told “You need a website!” but no one is willing to (or able to) sit with them and help them get started.

    Initially I was super impressed. Yoast had clearly studied the aspects of walk-throughs that had worked and that didn’t, lifting pages from other complex plugins that needed to be used by, perhaps, non-technical savvy people.

    Yoast Walk Through: What kind of site is this?

    Being asked what kind of site I was running was brilliant. For the purposes of this test, I decided to use my community/wiki/library – LezWatchTV. And right away I ran into a problem.

    Am I a company or a person?

    The tool wanted me to say if I was a company or a person.

    Well … Neither. I’m a community site. Or maybe a group? Either way, the two designations didn’t really apply properly. Where was “Other”?

    This couldn’t be Yoast making a boneheaded maneuver, I realized. Few people know better than Joost and his crew what WordPress is used for. They’re smart people. They’ve seen more of the Internet than most of the rest of us and they know well how it’s used. So could the screwup be Google or Schema.org?

    I went to Schema.org to look up how they would classify the site, and determined that DataCatalog was the most appropriate. Alright, knowing there was a good classification, I looked back at Google’s Knowledge Graph.

    Google’s Knowledge Graph is a weird thing. It’s Google’s attempt to figure out how to answer your questions. You know how you can type in “How do I do X?” into Google and you get that interesting formatted answer?

    Example: How do I bake a pie?

    That’s from their Knowledge Graph. But more importantly, so is this:

    Example: Knowledge Graph data of Root from Person of Interest

    The more you dig into it, the more you realize that the only boxes like that are for people or companies. So the breakdown is that Google has not yet figured out how to flag non-people non-companies.

    This means my ultimate question of ‘what I am?’ has become a little more existential than I’d wanted, and a little simple. It’s not a person, therefore it must be a company. And while that is entirely, totally, daftly incorrect, it’s also less incorrect that a person.

    Thanks, Google.

  • Per-Site MU Plugins

    Per-Site MU Plugins

    A great many moons ago, I handled my per-site MU plugins in a very straight forward way. I made a halfelf-functions.php file and checked for the blog ID with if ( $blog_id == 2 ) {...} and off I went.

    Now? I do this:

    global $blog_id;
    $helf_site_url = parse_url( get_site_url( $blog_id ) );
    $helf_file = plugin_dir_path( __FILE__ ) .'functions/'. $helf_site_url['host'] .'.php';
    if ( file_exists( $helf_file ) ) {
        include_once( $helf_file );
    }
    

    I have a folder called ‘functions’ and in there I have a file for every site that needs it’s own functions. This also let me clean up some rather old code I wasn’t using anymore, but it also let me add in code to include local CSS. Since I version control my mu-plugins folder, this allowed me to move my custom CSS from Jetpack to a normal CSS file.

    Why did I need to do that? Jetpack CSS doesn’t allow the fill param for CSS. Their current justification is that it’s advanced enough that people should be editing the theme. And mine is “But … why?” SVGs are becoming more and more popular, after all, and a number of plugins are allowing them. That means to style your SVGs, you’ll want to use CSS. And you can’t with Jetpack, which means you’re back to the old hell of editing your theme’s CSS. And that was something I wanted to avoid.

    You’d think I could do this:

    $helf_file_css = plugin_dir_path( __FILE__ ) .'functions/css/'. $helf_site_url['host'] .'.css';
    function helf_scripts() {
    	if ( file_exists( $helf_file_css ) ) {
    		wp_enqueue_style( $helf_site_url['host'], $helf_file_css );
    	}
    }
    add_action( 'wp_enqueue_scripts', 'helf_scripts' );
    

    But that actually didn’t work. No matter what I did, the result of $helf_site_url['host'] was empty. I know, right? What’s up with that.

    What’s up is me not thinking about how functions ‘know’ what they know.

    function helf_scripts() {
    	global $blog_id;
    	$url = parse_url( get_site_url( $blog_id ) );
    	$css_path = plugin_dir_path( __FILE__ ) .'functions/css/'. $url['host'] .'.css';
    	$css_url = plugins_url( 'functions/css/'. $url['host'] .'.css', __FILE__ );
    
    	if ( file_exists( $css_path ) ) {
    		wp_enqueue_style( $url['host'] , $css_url );
    	}
    }
    add_action( 'wp_enqueue_scripts', 'helf_scripts' );
    

    Inside the function, you see, it can’t see non-globals. So it wouldn’t work. If you’re not using Multisite, you don’t need to use $blog_id, but I don’t know why you’d want to use this if you weren’t using Multisite. The other silly moment was remembering that plugin_dir_path() would give me /home/user/public_html/wp-content/mu-plugins which would make the URL a relative URL, and not at all what I wanted. But using plugins_url() would give me an absolute path.

    Perfect.

  • Moving cPanel email to Gmail

    Moving cPanel email to Gmail

    There should be a collective gasp here.

    It’s no big secret I dislike Google. I don’t trust them at all. I think Cory Doctorow’s story Scroogled is pretty much on the ball. But I also have been struggling with handling my server’s email and spam situations and if there’s one thing Google has turned out to be pretty good at, it’s spam. Also having my email separate from my hosting means if the site goes down, I’ll still get emails… Which is sort of important.

    So I bit the bullet, sorted out I needed to pay for three emails (making it $15 a month) and a boat load of secondary domains and filters. Since I’d dropped the cost of my hosting by $20 a month, this worked out alright.

    The Setup

    This part is the easy one. Go to https://apps.google.com and put in your information. If, like me, you have multiple domains, pick one to be your ‘master’ domain. I chose ipstenu.org because that’s my main domain in Multisite and there’s some parity going on here. Since this is geared to businesses, you do need to give your business a name. Sorry.

    Next you’ll pick your users. Like I said, I have three: Me, my wife, and my admin account. Why does admin need it’s own account? It doesn’t. But it might. For now I had them email me at my personal gmail (I can always resend later) since I don’t want them to be alerted to things just yet as I planned to import all their old email.

    Finally it does the “Verify your domain and set up email” step. Which failed. And took 50 minutes. Unfunny. Originally I did the TXT domain setup, and when that failed I did CNAME. Longest ‘about 50 minutes’ ever. And that failed too. Finally I did the damned ‘file verification’ which was ridiculous and stupid but that worked and it still took another 50 minutes to set up my emails.

    Eventually, after talking to Google, my web host, and my domain registrar, it turned out there was a glitch in my domain servers… There was no A record for my nameservers. Thank you Carol, Samuel, and Tatyana for helping that one.

    Migrating Data

    I mentioned I have three accounts. They have around 30 megs of email each. But I also have secondary accounts which are basically the same accounts only not… And to be honest I don’t know why I have so many. This was a chance to combine everything, so I set up those three accounts and then I used the IMAP importer to pull in everything. And it worked. That simple.

    Configuring Accounts

    Now that I have three accounts, I needed to add in my ‘other’ emails. I have a lot of weird aliases. I used to have separate accounts for each email but … well that’s a pain in the ass. So instead of that, I set up folders. I made a folder for each domain alias and then set up redirects. If email was sent to the halfelf.org domain, then it went to a folder called ‘HalfElf.’ Originally I had a whole mess of weird redirects going on, like if it was from WP then it went to a WordPress folder and so on, but unraveling that and going simple seemed like a wise choice.

    I went into the cPanel backups page and downloaded all my forwarder information as well and set up email forwards! Well. Not forwards. Aliases. Same idea really. And it was nice, since I added all my domains as aliases, ipstenu@[anydomain] would now work! I set up a lot of filters to keep things out of my inbox and in their proper, attention needing, spots.

    Blocking Users

    Finally it was time for my soon to be favorite step. Blocking users. Blocking senders for every domain is possible in Gmail and in my opinion, it’s huge. I have a list of 66 emails that I block on all my servers. This is for myriad reasons, but primarily is these are people who don’t know how the shut the hell up and leave me alone. Since I’m under no obligation to talk to these people, I blocked them.

    Exporting that list from cPanel was un-fun. You can either manually copy it out, line by line, or you can find the filter rules. They are, sadly, stored in the /etc/vfilters directory, so you need root access (which I have), but it’s not easy to get at. BUT! As of the latest version of cPanel, if you go into backups you can export your filters. They’re in a YAML format, but that’s easier than copy/pasta.

    Cleaning up cPanel

    So now that everything is on gmail, do I even need to run email on the server? Yes. I have to be able to send email. I did go through and delete all the accounts, though, freeing up a bit of space, and I turned off Greylisting (I know, I just did that!), and I hid the ability to add new accounts.

  • Sortable Custom Columns: Taxonomies

    Sortable Custom Columns: Taxonomies

    You may have noticed that when I was making Sortable Custom Columns I didn’t make it so I could sort some of the fields.

    Showing sorted columns

    That’s because unlike my lovely post meta, those other fields are custom taxonomies. And by their very nature, they’re not sortable. In order to do this however you need some SQL.

    Make the Columns Sortable

    First we have to add our new columns (lez_gender and lez_sexuality) into our sortable function.

    add_filter( 'manage_edit-post_type_characters_sortable_columns', 'sortable_post_type_characters_column' );
    function sortable_post_type_characters_column( $columns ) {
    	unset( $columns['cpt-shows'] ); 			 	// Don't allow sort by shows
    	$columns['postmeta-roletype']		= 'role';	// Allow sort by role
    	$columns['taxonomy-lez_gender']		= 'gender';	// Allow sort by gender identity
    	$columns['taxonomy-lez_sexuality']	= 'sex';	// Allow sort by gender identity
        return $columns;
    }
    

    Last time it only had the unset and the postmeta-roletype columns. Now we’re adding in our taxonomies as taxonomy-{TAXONOMYNAME} to that.

    Actually Sort the Content

    Now here’s the sneaky SQL stuff.

    function lez_gender_clauses( $clauses, $wp_query ) {
    	global $wpdb;
    
    	if ( isset( $wp_query->query['orderby'] ) && 'gender' == $wp_query->query['orderby'] ) {
    
    		$clauses['join'] .= <<<SQL
    LEFT OUTER JOIN {$wpdb->term_relationships} ON {$wpdb->posts}.ID={$wpdb->term_relationships}.object_id
    LEFT OUTER JOIN {$wpdb->term_taxonomy} USING (term_taxonomy_id)
    LEFT OUTER JOIN {$wpdb->terms} USING (term_id)
    SQL;
    
    		$clauses['where'] .= " AND (taxonomy = 'lez_gender' OR taxonomy IS NULL)";
    		$clauses['groupby'] = "object_id";
    		$clauses['orderby']  = "GROUP_CONCAT({$wpdb->terms}.name ORDER BY name ASC) ";
    		$clauses['orderby'] .= ( 'ASC' == strtoupper( $wp_query->get('order') ) ) ? 'ASC' : 'DESC';
    	}
    
    	return $clauses;
    }
    add_filter( 'posts_clauses', 'lez_gender_clauses', 10, 2 );
    

    I repeat this with ‘gender’ changed to ‘sex’ and ‘lez_gender’ changed to ‘lez_sexuality’ for the other taxonomy.

    I tested this on 921 posts in a custom post type and it didn’t make my server cry. Which is a bonus.