Half-Elf on Tech

Thoughts From a Professional Lesbian

Author: Ipstenu (Mika Epstein)

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

  • The Monetization of Edge Sites

    The Monetization of Edge Sites

    When you’re starting out, the idea of making some passive income on your website is pretty appealing. So you look at services like Google Adsense or Project Wonderful, and you think that’s it. Sign up, toss some ads up, and you’ll make $.50 a month (yes, that’s fifty cents). For most people, that works quite well. But what happens when you’re not ‘most’ people?

    What Is an “Edge” Site?

    An edge site is a site that has a very niche audience. For example, 10 years ago, WordPress would have been a very niche subject and thus an ‘edge’ site if you were trying to get advertising. But if you said “It’s a technology blog” then you’d have a broader set of possible advertisers.

    Paradoxically, niche sites do better in Google search results, which makes them better traffic but harder to target. However, that’s not what an edge site really is. An edge site is a site that has content on the edge of what the various ad hosts would be comfortable allowing. And if they’re not comfortable, then they’ll close your account even if it’s just one of your domains that they don’t like.

    What Makes It Questionable Content?

    Have you ever read those terms of service? The ones you agree to when you sign up for ad companies? Of course not. But you kind of get the gist of what they’re on about. Basically they don’t want anything offensive on their networks, like promoting racism or bigotry. And there’s always a clause in there about “pornographic or sexually explicit material” — to whit, don’t have it.

    But what you may not realize is that sexually explicit also covers talking about sex. No, I don’t mean the erotica kind of content, I mean if I use Google Ads, I can’t have a website that gives you advice on sexual dysphoria, or even sexual health issues.

    How Do You Know if You’re Edge?

    You don’t.

    I found out because Google AdSense decided that a picture of two women in a bubble bath (which was a promo picture for a TV show) was too much. They cited it as being ‘adult’ and there was no further information as to if it was actually the image or if it was the post content. Yes, you read that correctly. They just said “This page is naughty!” and didn’t give me a chance to figure out what or why or how, except to experiment.

    Oh and if you experiment and get it wrong, you run the risk of losing the whole AdSense account, not just that one domain. Have a nice day.

    Google effectively doesn’t care about you. There’s no way to email someone and say “Hey, is the problem this one image or the subject matter of my site, which you approved 2 years ago?”

    What Are The Options?

    Now that I’ve scared you a bit, your choices boil down to:

    1. Find a lenient service
    2. Host ads yourself
    3. Rely on affiliate links

    They do really suck.

    Services

    The biggest issue with the services is that unless there’s a human-contact available, there’s very little you can do if you ‘break’ guidelines by being on that edge. I mentioned Google as the worst (if you have less than 500k page views a month, you’re outta luck), but Amazon’s not really much better unless you like auto-replies and stock answers. In my experience, the best people behind ads are Project Wonderful, but the quality of ads can be a bit low.

    Self-Host

    Even though I run my own, self-hosted, WordPress site, I loathe the idea of a self-hosted ad service. You can do it via WordPress plugins, but if you’re thinking they all look a bit janky, you’re right. They do. They’re all clunky in my eyes. Revive (formerly OpenX Source) is the nicest, but they’re not very fast and you have to maintain them. Which is an extra burden. And then it’s the damn hustle to get ads and manage them.

    Affiliates

    Lastly you have affiliates. Now they’re a curious mix of the most lenient, whereby I mean some like ShareASale will let you do anything but ‘adult’ and hate sites, and others like Amazon are super super picky. In both cases, though, they let affiliates approve you as an individual, so there’s that.

    Conclusion?

    If you want ‘easy’ money and you’re an edge or niche site that is possibly on that inane ‘family friendly’ bubble, you’re going to need to go with Project Wonderful. At least until you get big enough for BuySellAds to pick you up. Otherwise it’s a hustle to get the attention.

    Or you could try selling things…

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

  • How Mobile is AMP?

    How Mobile is AMP?

    There are pros and cons of using AMP, the biggest being Alex Kras’ discovery that Google is kinda stealing your mobile traffic with AMP. But since WPBeginner lays out the pros and cons really well, I’m going to skip over that and discuss something else.

    Responsive Themes

    The concept of a ‘mobile only’ theme is one I generally deride. After all, if you’re on a website in 2017, it should have been written with the concept of mobile first. Most people design a site for their computer/browser of choice, and then add in resizes for mobile. Contrasting this is the idea that you build out your website for mobile browsers first, and then go back in and add in the larger views. That is Mobile First.

    It’s an ideal, I agree, and while I love it (and Carrie Dils who made the beautiful Utility Pro Theme as a mobile first them), it can’t always be achieved. Some websites are written to be ‘apps’ and they’re intended to be used as a browser app.

    In general, I support the use of a responsive theme, be it mobile first or not. This kind of theme will react based on browser size, or operating system type. But a mobile ‘only’ theme? I dislike them a great deal. They create headaches with caching (ask anyone who’s had their cache catch the mobile page for everyone!) and they can be difficult to jump back from, if someone is perhaps on a tablet that can handle the ‘full’ site. They also double your work.

    AMP

    AMP is a project by Google. The concept is a super light, ultra-fast mobile page for your sites. AMP is fast, it’s simple, and it’s a stripped down version of your normal site. How it works is that When Google searches your site and adds it to their big giant database, they can can see “Aha, this site has AMP! I will use it for mobile!” And then, when someone surfs to your site via a Google search, Google would notice “This user is on mobile! I will show it AMP displays!”

    The downside you might have noticed is that the AMP pages only get called when you’re doing a Google search. That means if you go to a website on your phone, you get the mobile responsive site anyway. Which is what Paul (and I) think you should be doing. And right away, you might think “Hey, I should make all my mobile visitors go to AMP!” and you may come up with code like this:

    function amp_redirect() {
    	if ( wp_is_mobile() ) {
    		$url = trim(  $_SERVER['REQUEST_URI'], '/' );
    		if ( substr( $url, -3) != 'amp' ) {
    			$url = $_SERVER['REQUEST_URI'] . '/?amp';
    			wp_redirect( $url );
    			exit;
    		}
    	}
    }
    

    That looks great, doesn’t it? It’s smart enough to check if the URL ends in ‘amp’ and, if so, not redirect. Plus it uses ?amp which means if the page doesn’t have an AMP URL, it won’t fail an ugly 404 death.

    There is, however, a big problem with AMP. You end up having two sites. Paul Bakaus talks about the pitfalls of a separate mobile site, and how you should keep a responsive theme for your site, and not use AMP for Mobile. This is not a good thing in the long run.

    A RESTful Alternative

    So let’s think about this differently and not in the simple “Mobile vs Non-Mobile” way. Let’s ask ourselves the real questions. “What is this site doing?” and “How will people be using this site?” Because the crux of the matter is really how is the data from the site being consumed!

    Recently, with the advent of the REST API, WordPress has as new way for people to eat your data. Much like I’ve talked about before, using the REST API to power an Alexa app or a plugin, the REST API can be used to power mobile apps! Yes, people are running iOS apps with the REST API. This lets you display the content however you want, even audio only, and yet power it fully with WordPress.

    In a way, you’re still making two sites, the app and the theme, but… You’re not making a generic theme that fits all users. You’re making a real application that fits the specific use case.

    What’s The Answer?

    Let’s break this down.

    1) Your theme should be responsive for mobile. Period.
    2) AMP is great for Google searches.
    3) The REST API can, and should power your apps.

    That’s it. Three steps to amplifying your site.

    Oh, and please don’t use that code I showed you. It’s sad.

  • The Passion of Change, Part 2

    The Passion of Change, Part 2

    This is part 2 of The Passion of Change. Last time I talked about some theory and decision to make about why to do this with WordPress. Now let’s talk about how it’s done.

    Collecting Data

    There’s no way around this. To collect data that’s … well … never been collected in one place before, you have to sit down and do the work. And it’s hard. This is why companies hire interns, but really you need a researcher who is an expert in the field. And you have to guess and what data is going to be important. Do you just want names and shows, or do you want death days, actors, and cliches and tropes? Decide on your datapoints, but collect more than you need. Trust me on that one. Backfilling dates for 1000 posts wasn’t fun.

    The trick with WordPress is understanding how to organize your data. With Hugo, there’s the basic concept of “everything is a post” and really that’s what WordPress does too. Everything is a post TYPE. By making a custom post type for your data, you can have it listed and organized how you want. We opted for a type for shows and characters, with post meta to store the complex and unique data and taxonomies for the common and shared.

    Display The Data

    Part of displaying your data properly is to do so in a way that is conducive to your SEO. Yeah I said a dirty word. CMB2 lets you add in post meta easily. Yoast SEO lets you add that information to your meta data. AMP makes it better to read on mobile, and FacetWP makes it dynamically sortable. And the Rest API? Well that makes it easily consumable. Anywhere.

    To make it easy to enter and maintain the data, we use CMB2. You can also use PODS or ACF to do this, and really it’s its own post. But the point here is you need to go back to that data you collected and figure out how it needs to be presented. While you could code it all by hand, I strongly recommend a plugin that will let you add in these fields more easily. You need to make sure you data can repeat what needs to be repeated.

    SEO

    And the best part here is that if you have good data and you’ve entered it in a smart way, it will lead to good SEO by doing things like this:

    %%title%% is a %%ct_lez_gender%% %%ct_lez_sexuality%% %cf_lezchars_type%% character played by %%actors%% on %%shows%% %%sep%% Clichés: %%ct_lez_cliches%%
    

    With Yoast SEO in conjunction with CMB2 I was able to auto-populate a unique and yet repeated description for my meta desc in all my posts. The goal here is to optimize smartly. You want your research to be found, so you need to make it easily finable for the right search queries.

    Mobile: AMP

    I use Automattic’s AMP plugin combined with Yoast’s AMP Glue plugin for mobile optimizations. By default it only adds posts as AMP data. I built out custom templates for my CPTs to allow those to show up as AMP pages as well. I did this because I wanted the data to be accessible in more ways than just normal WP pages. Democratizing consumability means being flexible about your displays. Get the data out there clearly.

    Don’t Predict Paths

    Putting the data out there in easy to find ways is step one. When you have lists of data, you also need to make them sortable. FacetWP is a tool for advanced filtering. It lets you sort and resort your data, so if you wanted a list of blue eyed, left handed, centipede groomers, and you had all that data stored, you could find it. It’s a little tricky sometimes to build out your facets the way you want, but they let you refine searches and drill down so you can find everything in the way the users want. The goal, and FacetWP meets it, is to make finding the data people want easier.

    But… There’s another path to consider. The REST API.

    This is hands down my favorite part of the whole thing. It’s great we have all this data we collected, and we can show it in myriad ways. We can get stats to show you trendlines and averages and percentages. But… How do we get the data back out there so other people can consume it? What if you wanted to take the data to make stats we didn’t? This is all done via the Rest API.

    JSON: It Gets The Job Done

    The Rest API made it EASY for me to export all this data into a format anyone could take and expand on. I made them simple, with just names and dates, and complex with everything I could think of. And by doing so, other people DID start to grab the data and use it to construct their own narratives and find their own answers.

    It also let me make a plugin!

    The irony of using a Rest API to power a plugin that lists dead female queers is not lost on me, by the way. I built out a JSON powered plugin that calls the data and uses it to output the data in widgets or shortcodes. It’s possibly the most simple and basic way you can do anything with this, but it demonstrates the extendability. It’s fast, it’s low load for my site which is always good, and it’s easy for me to update.

    All that work that went into the plugin, with the JSON API, was transformed into an Amazon Alexa skill, where you can ask it “Hey Alexa, ask Bury Your Queers who died on March 3rd” and your Echo or Dot will reply. At it’s heart, it seems silly and trivial. The more I worked on the code, though, the more I realized how you could extend this to share more data. Trivia and minutia are small beans, but they’re the beans we REMEMBER. And what we remember is what changes the world.

    Open Data – Sharing Passion Enhances Everything

    Hopefully the story you got from all this is that with WordPress you can share your passion for … well. Anything. And you can use it to fuel change. In the last 18 months, I’ve had the opportunity to talk to people world wide about how just seeing the representation and the statistics have helped them. Including TV producers. And yeah, that was weird. But more over, I’ve helped get data out there and used it to change one thing. And that is the passion that causes change.