Half-Elf on Tech

Thoughts From a Professional Lesbian

Tag: sorting

  • Reordering Facet Displays … For Death

    Reordering Facet Displays … For Death

    Isn’t that a catchy title?

    I’m using FacetWP to help me order and sort archives in ways that are reflective of the content. One of the things I sort are characters (yeah yeah yeah) and some of those characters are dead. It occurred to me that wouldn’t it be nifty if I could sort the characters by when they died?

    There was just one problem. Actually there were two. One was Sara Lance, and she’s my personal demon. The other was my own stupidity and lack of foresight. Neither were insurmountable.

    How FacetWP Changes Sort Order

    Before I get into the weeds, let’s have a moment to talk about sort order. FacetWP has a way to filter the sort orders.

    So for an example, I have post meta value for the number of characters saved as lezshows_char_count for all shows. If I wanted to sort shows by the most characters to least, I can add this in:

    $options['most_queers'] = array(
    	'label' => 'Number of Characters (Descending)',
    	'query_args' => array(
    		'orderby'  => 'meta_value_num', // sort by numerical custom field
    		'meta_key' => 'lezshows_char_count', // required when sorting by custom fields
    		'order'    => 'DESC', // descending order
    	)
    );
    

    It looks very similar to WP_Query and that’s what makes it easy. Except for my two problems…

    Problem One: Formats

    The first problem was not the Sara Lance problem. It was the ‘Mika didn’t think about things 4 years ago’ problem. I was saving the dates of death in the format of MM/DD/YYYY

    If you’re an American, you’re wondering “So what?” and if you’re anyone else, you’re giving me a death glare because “08/05/2010” could be August 05 OR May 08, and damn it, I knew better. For what it’s worth, the output on the front end is always “05 August 2010” but that’s not here nor there.

    You see, the issue isn’t that I was using stupid date/time formats, the issue is sorting.

    In the previous example, I have an order of meta_value_num which is literally a number. What’s the one for dates? You get meta_value_date or meta_value_datetime and neither of them work with the date format I’d chosen.

    So for this to work, I had to go and change everything from MM/DD/YYYY to YYYY/MM/DD – Not fun, but doable. And it led me to my Sara Lance Drama…

    Problem Two: Arrays

    How many times has Sara Lance died? Right now, three.

    When I decided to sort by the date of death, which one did I pick? Long pause.

    I decided to pick the last one. That is the most recent death. If someone’s actually still dead, the most recent death is the one that stuck. If they’re not, then death was pretty arbitrary to begin with and there ya go.

    The question became how and where did I save the death? I went with a post meta of lezchars_last_death and had it auto update on post save, like this:

    add_action( 'save_post_post_type_characters', 'characters_update_meta', 10, 3 );
    function characters_update_meta( $post_id ) {
    
    	// unhook this function so it doesn't loop infinitely
    	remove_action( 'save_post_post_type_characters', 'characters_update_meta' );
    		
    	// get the most recent death and save it as a new meta
    	$character_death = get_post_meta( $post_id, 'lezchars_death_year', true );
    	$newest_death    = 0000-00-00;
    	foreach ( $character_death as $death ) {
    		if ( $death > $newest_death ) $newest_death = $death;
    	}
    
    	if ( $newest_death !== 0000-00-00 ) {
    		update_post_meta( $post_id, 'lezchars_last_death', $newest_death );
    	}
    
    	// re-hook this function
    	add_action( 'save_post_post_type_characters', 'characters_update_meta' );
    }
    

    If there is a latest death, we get to set it as the YYYY-MM-DD value and off we go. But…

    Problem Three: Orderby Hellscape

    Surprise! I ran into a third problem! Remember how I was using the orderby of meta_value_num in my example? And I mentioned that I wanted to use meta_value_date or meta_value_datetime to sort by date?

    Yeah no.

    If I’d converted the date into unix time, sure. But I was reusing this logic in a couple places, and I didn’t want to re-save everything like that. I also use a query to grab all deaths in a year, and basically I do need to keep it with the format I have. That just messed up my sort until I found the magic of orderby' => 'meta_value',

    End Result?

    It works. It’s got yet another post meta, which I’m not super happy about, but sometimes that’s really just the simplest way to solve a problem. The data is always updating itself, and it’s relatively easy for me to tweak it. Also now I can do a lot more searches in different ways.

    Since I don’t have to worry about database size at the moment, nor speed, since I’ve designed it well, this works for me.

  • Reordering Sort Order Redux

    Reordering Sort Order Redux

    Earlier this year I talked about removing stopwords from sort queries.

    Sadly I ran into a problem where the code wasn’t working.

    The Original Code

    Here’s the original code.

    add_filter( 'posts_orderby', function( $orderby, \WP_Query $q ) {
        if( 'SPECIFIC_POST_TYPE' !== $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 );
    }
    

    This worked, mostly, but it somehow broke pagination. Every page restarted the order. This had to do with complications with the Genesis theme but more importantly it messed up the order on the back of WordPress and it didn’t play well with FacetWP. So I rewrote it a little to be more specific:

    The New Code

    if ( !is_admin() ) {
    	
    	add_filter( 'posts_orderby', function( $orderby, \WP_Query $q ) {
    		
    		// If this isn't an archive page, don't change $orderby
    		if ( !is_archive() ) return $orderby;
    		
    		// If the post type isn't a SPECIFIC_POST_TYPE, don't change $orderby
    		if ( 'SPECIFIC_POST_TYPE' !== $q->get( 'post_type' ) ) return $orderby;
    
    		// If the sort isn't based on title, don't change $orderby
    		$fwp_sort  = ( isset( $_GET['fwp_sort'] ) )? sanitize_text_field( $_GET['fwp_sort'] ) : 'empty';
    		$fwp_array = array( 'title_asc', 'title_desc', 'empty');
    		if ( !in_array( $fwp_sort, $fwp_array ) ) return $orderby;
    
    		// Okay! Time to go!
    		global $wpdb;
    
    		// Adjust this to your needs:
    		$matches = [ 'the ', 'an ', 'a ' ];
    
    		// Return our customized $orderby
    		return sprintf(
    			" %s %s ",
    			MY_CUSTOM_posts_orderby_sql( $matches, " LOWER( {$wpdb->posts}.post_title) " ),
    			'ASC' === strtoupper( $q->get( 'order' ) ) ? 'ASC' : 'DESC'
    		);
    
    	}, 10, 2 );
    
    	function MY_CUSTOM_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 lwtv_shows_posts_orderby_sql( $matches, $sql );
    	}
    }
    

    First of all, I got smart about only loading this when it needed to be loaded. Next I told it to only sort on archive pages, because I was also outputting recently added lists in other places. Finally I forced it to understand Facet, and that if I wasn’t sorting by alphabetical, it didn’t matter at all.

  • Tracking Changes On Sites

    Tracking Changes On Sites

    When you make a site dependent on others for your data, it’s important to be able to get updates on those sites promptly. Most of the time, a site has way to see what’s recently updated, be it by a page that lists what’s new, or an RSS feed, or an email list.

    But what happens when they don’t?

    Well. Then you need to look into monitors. And the bad news? Nothing is perfect. I’ve picked the top two services I tried over the month of May

    VisualPing

    If the content of a page is HTML only, then it’s great. But if you’re trying to monitor a highly dynamic javascript site, it can time out. Especially if the site has a lot of data. The interface of the site is nice, having a simple UX that was easy to understand. At the same time, it doesn’t handle abnormal well, and often wouldn’t tell me there were changes because simply it couldn’t tell.

    Overall, it was a disappointment for me and not useful for the javascript heavy page I was trying to monitor. As such, I’m not using it anymore.

    Versonista

    This is much better for a javascript heavy page that has a long load time. It can list out the URLs added that are new, and you can review the changes into the minutiae. But. The emails are incredibly inconsistent and the UX is overly complex. While I can go in and see what’s changed, down to the source-code, I’m supposed to get a daily email about that and I don’t. Also the options are too much. I just want to see what changed. A list of the changes, maybe a list of the new links. Instead I have to click around to figure out how to see the list better.

    Between that and the email situation, I’m unhappily still using it.

    Overall…

    The real issue I have is not with these services, but the fact that the webpage I’m trying to monitor was not intelligently designed. It’s trying to list everything on one page, using javascript, and sadly it’s not well optimized. I can’t even get the page to load properly on my iPad. The content is also not sortable. It’s always alphabetical, no matter what.

    My biggest takeaway from this is that with some content it makes sense to hard define your content. That is, sorting everything by name and not allowing it to be restored may make sense for many people. But you have to allow people an easy way to see what’s new if you want them to keep coming back.