Author: George Stephanis

  • Displaying Custom Post Type Archive on Your WordPress Homepage

    Here’s how to do it!

    add_action( 'pre_get_posts', 'my_query_mods' );
    function my_query_mods( $query ){
        if( is_admin() ) return;
        if( is_main_query() && is_home() )
            $query->set( 'post_type', 'texture' );
    }
    
  • Need a category index page?

    Why not just use a normal page?

    Oh, sure, you want a dynamically loading list of the categories.

    Try this on for size:

    
    add_shortcode( 'taxonomy-list', 'my_taxonomy_list' );
    function my_taxonomy_list( $atts ) {
        $args = shortcode_atts( array(
            'taxonomy' => 'category',
            'title_li' => '',
            'depth' => 1,
            'hide_empty' => 1,
        ), $atts );
    
        ob_start();
        ?>
            <ul class="taxonomy-list taxonomy-<?php echo $args['taxonomy']; ?>-list" data-taxonomy="<?php echo $args['taxonomy']; ?>">
                <?php wp_list_categories( $args ); ?>
            </ul>
        <?php
        return ob_get_clean();
    }
    
    
  • CSS3 Snow!

    So I got a bit irked the other day when looking to sort out what sort of method I’d like to use for putting snow on a website.  All the options just looked bad.  Some were using images (which I’d prefer to avoid) — others were using crazy javascript hijinks.  I figured there’d have to be a simpler way.

    So I wrote one.  It’s not perfect, and it’s not quite a ‘drop-in’ (read: you’ll need to test it before pushing it live.  Tweak the speed, height, etc to your heart’s content).  It was originally written to only put snow in the header of the site — not over the whole page.

    http://dl.dropbox.com/u/5581009/snow.html

    Enjoy!  Any questions about implementation are welcome!

  • I’ll be speaking at WordCamp Philly 2012!

    Looks like I’ve been accepted to speak this year at WordCamp Philly!  I’ll be rambling on about the “Seven Deadly Sins of Theming” — a look at the ghastliest and most horrifying grievances that are made against best practices when making themes — specifically those for commercial consumption.

    My main bullet points (so far) are:

    • Copying Snippets (without understanding what they do)
    • Bundling Plugins (just slapping them in your theme directory)
    • Assuming Plugins (calling plugin functions directly from your theme without checking that they are available first)
    • timthumb.php (using it when the existing WordPress thumbnails functionality is secretly better)
    • CDN-Hosted JS, and using it the wrong way.
    • Hardcoding CSS & JS links (rather than enqueueing them properly)
    • Ignoring Child Themes (or, why your template directory is not the same as your stylesheet directory, and the importance of knowing the difference)
    • Failing to take internationalization into consideration
    • Hacking Core Files.  (I’ll punch you in the throat through the internet if you do it)

    I’ll probably be cutting or merging a few (to keep it at seven) — but please feel free to make any suggestions of egregious violations that you’ve seen in the comments section below!

  • How to change post thumbnail crop position in WordPress WITHOUT HACKING CORE

    DISCLAIMER: This requires WordPress 3.4 to work correctly. The filter was added based on Trac Ticket #15989

    Okay, to start, here is the function that we’re going to be working with, from ~/wp-includes/media.php :

    /**
     * Retrieve calculated resized dimensions for use in imagecopyresampled().
     *
     * Calculate dimensions and coordinates for a resized image that fits within a
     * specified width and height. If $crop is true, the largest matching central
     * portion of the image will be cropped out and resized to the required size.
     *
     * @since 2.5.0
     * @uses apply_filters() Calls 'image_resize_dimensions' on $orig_w, $orig_h, $dest_w, $dest_h and
     *		$crop to provide custom resize dimensions.
     *
     * @param int $orig_w Original width.
     * @param int $orig_h Original height.
     * @param int $dest_w New width.
     * @param int $dest_h New height.
     * @param bool $crop Optional, default is false. Whether to crop image or resize.
     * @return bool|array False on failure. Returned array matches parameters for imagecopyresampled() PHP function.
     */
    function image_resize_dimensions($orig_w, $orig_h, $dest_w, $dest_h, $crop = false) {
    
    	if ($orig_w <= 0 || $orig_h <= 0)
    		return false;
    	// at least one of dest_w or dest_h must be specific
    	if ($dest_w <= 0 && $dest_h = $orig_w && $new_h >= $orig_h )
    		return false;
    
    	// the return array matches the parameters to imagecopyresampled()
    	// int dst_x, int dst_y, int src_x, int src_y, int dst_w, int dst_h, int src_w, int src_h
    	return array( 0, 0, (int) $s_x, (int) $s_y, (int) $new_w, (int) $new_h, (int) $crop_w, (int) $crop_h );
    
    }
    

    Some people have looked at this and felt that there was no way to override the $s_y = floor( ($orig_h - $crop_h) / 2 ); line without hacking core. Well, that’s iffy, but if you scroll up above, you’ll see something that lets you basically ‘short-circuit’ the function in question:

    // plugins can use this to provide custom resize dimensions
    $output = apply_filters( 'image_resize_dimensions', null, $orig_w, $orig_h, $dest_w, $dest_h, $crop );
    if ( null !== $output )
    	return $output;
    

    So here’s our function to make all crops start at (0,0) — customize it as you like:

    function my_awesome_image_resize_dimensions( $payload, $orig_w, $orig_h, $dest_w, $dest_h, $crop ){
    
    	// Change this to a conditional that decides whether you 
    	// want to override the defaults for this image or not.
    	if( false )
    		return $payload;
    
    	if ( $crop ) {
    		// crop the largest possible portion of the original image that we can size to $dest_w x $dest_h
    		$aspect_ratio = $orig_w / $orig_h;
    		$new_w = min($dest_w, $orig_w);
    		$new_h = min($dest_h, $orig_h);
    
    		if ( !$new_w ) {
    			$new_w = intval($new_h * $aspect_ratio);
    		}
    
    		if ( !$new_h ) {
    			$new_h = intval($new_w / $aspect_ratio);
    		}
    
    		$size_ratio = max($new_w / $orig_w, $new_h / $orig_h);
    
    		$crop_w = round($new_w / $size_ratio);
    		$crop_h = round($new_h / $size_ratio);
    
    		$s_x = 0; // [[ formerly ]] ==> floor( ($orig_w - $crop_w) / 2 );
    		$s_y = 0; // [[ formerly ]] ==> floor( ($orig_h - $crop_h) / 2 );
    	} else {
    		// don't crop, just resize using $dest_w x $dest_h as a maximum bounding box
    		$crop_w = $orig_w;
    		$crop_h = $orig_h;
    
    		$s_x = 0;
    		$s_y = 0;
    
    		list( $new_w, $new_h ) = wp_constrain_dimensions( $orig_w, $orig_h, $dest_w, $dest_h );
    	}
    
    	// if the resulting image would be the same size or larger we don't want to resize it
    	if ( $new_w >= $orig_w && $new_h >= $orig_h )
    		return false;
    
    	// the return array matches the parameters to imagecopyresampled()
    	// int dst_x, int dst_y, int src_x, int src_y, int dst_w, int dst_h, int src_w, int src_h
    	return array( 0, 0, (int) $s_x, (int) $s_y, (int) $new_w, (int) $new_h, (int) $crop_w, (int) $crop_h );
    
    }
    add_filter( 'image_resize_dimensions', 'my_awesome_image_resize_dimensions', 10, 6 );
    
  • WordCamp Boston 2012

    I’ll be speaking this year at WordCamp Boston!  Date and time to follow as I learn more, but my talk will be titled “Old, New, Borrowed, and Blue” — we’ll be looking at the classic ‘Kubrick’ theme that shipped with WordPress until 3.0, and bringing it up to date with HTML5 and CSS3!

    The theme has traditionally used images to achieve the rounded borders and gradients it displayed.  Fortunately, these are all achievable with modern CSS technologies, and in this talk, we’ll look at why and how we can implement them!

    Come say hi!

  • Detect mobile devices in WP 3.4

    So there’s a new function in town for detecting mobile browsers — no need to rely on the syntactically incorrect $is_iphone!

    Azaozz added in the new wp_is_mobile(); — no parameters, and it returns a Boolean — true or false.  Its a great way to future-proof your code, and outsource the browser detection to core, rather than having to maintain it as new browsers and devices get released.

    Enjoy!

  • Windows Phone 7 is Obnoxious

    Especially when trying to manage dropdown/flyout menus.

    I’m trying to sort out a way to make the WP core admin UI friendly to Mobile IE, but it doesn’t actually care about the `ontouchstart` event.  At all.

    All it sees are clicks.

  • PVP Redesign has UX Problems

    So PVP, a webcomic that I’ve followed since about 2002 (back when it was still physically published by Dork Storm Press) just launched a site redesign.

    And it looks hideous.

    Not in the way that most people would say hideous, mind you.  But rather from a User Experience (UX) perspective.  The header of the interior pages is 215px tall, and the front page is 415px.  When you add that to the typical browser/OS overhead of 100px or so, that means on the homepage, the content is starting about 550px down the screen.

    Worse yet, Scott Kurtz (creator of PVP) has done that highly obnoxious thing (that I seem to recall him venting a couple years ago about Penny-Arcade doing) — moving the single piece of content that 95% of your visitors are coming to your site to view off of your front-page, thereby making them click through to the new page, doubling your page views, and doubling your Ad Impressions. (And doubling the aggravation of everyone who wants to just see today’s comic) (with doublemint gum)

    Yes, the new site looks more modern and fresh.  However from the perspective of any visitor, with regard to usability, it has gone way down.

    So as I hate criticizing things unless I’m ready to step up to the plate and do something to help, here’s a JS `bookmarklet` that you can drag to your browser bar to see how much nicer pvponline could look without that hideous massive header obscuring the screens of most of his audience.

    Because let’s face it, Scott — most of your audience isn’t viewing the website on a 27″ iMac like you.

    Without further ado (Yes, I do tend to ramble) here’s your bookmarklet:

    PVPretty

    Here’s the code that it executes:

    s=document.createElement('style');
    c=document.createTextNode('#header,#headerSub{background:#000000;}'
    +'#header .content,#headerSub .content{height:auto; padding:0;}'
    +'#header .content > #adLeaderboard,#headerSub .content > #adLeaderboard,'
    +'#header .content > h1,#headerSub .content > h1,'
    +'#header .content > #featured{display:none;}'
    +'#header .content .nav,#headerSub .content .nav{position:relative; top:0;}');
    s.appendChild(c);
    document.head.appendChild(s);

    And the CSS that it puts in the page.

    #header,
    #headerSub {background:#000000;}
    #header .content,
    #headerSub .content {height:auto; padding:0;}
    #header .content > #adLeaderboard,
    #headerSub .content > #adLeaderboard,
    #header .content > h1,
    #headerSub .content > h1,
    #header .content > #featured {display:none;}
    #header .content .nav,
    #headerSub .content .nav {position:relative; top:0;}

    By the way, Scott, if you ever read this, I know you consider yourself a professional. Which makes it all the more aggravating when you are eternally incapable of having your webcomics actually follow a posting schedule. Occasionally, they’ll be up by noon on the day that they’re scheduled for. But those times are rare. Far more common, they may go up around 7pm, if you actually make the date they’re meant to be up for, instead of publishing them late and backdating them.

    If you want to consider yourself a professional, then why are you chronically unreliable in having the fruits of your labor up, when every single one of the other webcomics I follow does manage it, day in, and day out?

    For the record, the other webcomics I read are as follows:

    • XKCD
    • CandiComics
    • QuestionableContent
    • Sinfest
    • Nodwick/FFN
    • OutThere