Half-Elf on Tech

Thoughts From a Professional Lesbian

Tag: wordpress

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

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

  • Custom Columns Search: Not unique table/alias

    Custom Columns Search: Not unique table/alias

    After making Custom Sortable Columns everything was awesome, right?

    Well… Mostly.

    When I tried to sort a search, I got this:

    WordPress database error: [Not unique table/alias: 'wp_postmeta']
    SELECT SQL_CALC_FOUND_ROWS DISTINCT wp_posts.ID 
    FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) 
    LEFT JOIN wp_postmeta ON wp_posts.ID = wp_postmeta.post_id WHERE 1=1 
    AND (((wp_posts.post_title LIKE '%kate%') OR ( (wp_postmeta.meta_key 
    IN ( 'lezchars_actor', 'lezshows_worthit_details', 'lezshows_plots', 
    'lezshows_episodes', 'lezshows_realness_details', 'lezshows_quality_details', 
    'lezshows_screentime_details' ) ) AND (wp_postmeta.meta_value LIKE '%kate%') ) 
    OR (wp_posts.post_excerpt LIKE '%kate%') OR (wp_posts.post_content LIKE '%kate%'))) 
    AND ( wp_postmeta.meta_key = 'lezchars_type' ) AND wp_posts.post_type = 'post_type_characters' 
    AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'future' OR 
    wp_posts.post_status = 'draft' OR wp_posts.post_status = 'pending' OR 
    wp_posts.post_status = 'private') GROUP BY wp_posts.ID ORDER BY 
    wp_postmeta.meta_value DESC LIMIT 0, 20
    

    Not good.

    And not actually (really) related to the sortability! No no, I did this to myself by adding in optimized post-meta search. You see, that runs on the front and the back end of WordPress.

    I knew it had to be the search tweaks I’d made when I saw this:

    OR ( (wp_postmeta.meta_key IN ( 'lezchars_actor', 'lezshows_worthit_details', 
    'lezshows_plots', 'lezshows_episodes', 'lezshows_realness_details', 
    'lezshows_quality_details', 'lezshows_screentime_details' ) )
    

    Right away I realized it had to be my custom queries both calling from wp_postmeta and, in doing so, stemming all over each other. Not good at all.

    The fix was relatively simple. All I had to do was move the filters to run only if we’re not in wp-admin.

    /**
     * Only run if we're NOT in the admin screen!
     */
    
    if ( ! is_admin() ) {
    	add_filter( 'posts_join', 'lezwatch_search_join' );
    	add_filter( 'posts_where', 'lezwatch_search_where' );
    	add_filter( 'posts_distinct', 'lezwatch_search_distinct' );
    }
    

    This meant that the internal post search wouldn’t query those fields, but in the grand scheme of things, that’s okay. Generally when I’m looking for a post in the search, I’m looking for it by title. If I wanted to be more particular, I could have it not use my custom joins when I’m on a post listing page, but allow it if I’m editing a post (so adding a new link would search all that content too).

    For now, this is what I need.