While the simple example of how to use the Genesis grid loop might be enough to get you up and running, there are far more advanced ways you can use the grid loop to really get the best out of it.

This tutorial will go through the steps to adding a variable column balanced grid for any archive page on your site. If you just want the code, skip to the final section. All of the code snippets go at the end of your child theme functions.php file, just before any closing ?> there might be, except for the CSS which will go at the end of your child theme style.css (or css/custom.css for Prose) file.

This tutorial requires Genesis 1.5 or later to work. Adding it to a child theme while running an earlier version of Genesis will kill your site, so go ahead and update Genesis first!

Using A Grid Loop

The first thing we need to decide, is on which pages we want the grid loop to run. The simple example tells you to put the loop helper function straight into home.php, which means it won’t run on category, tag, monthly, or other archive pages.

add_action( 'genesis_before_loop', 'child_maybe_do_grid_loop' );
/**
 * Before we get to the loop, see if we're anywhere but a single page. If so,
 * swap out the standard loop for our grid loop.
 *
 * @author Gary Jones
 * @link http://genesis.mywsiportal.com/genesis-grid-loop-advanced.htm
 */
function child_maybe_do_grid_loop() {
    // Amend this conditional to pick where this grid looping occurs
    if ( ! is_single() && ! is_page() ) {
        // Remove the standard loop
        remove_action( 'genesis_loop', 'genesis_do_loop' );
        // Use the prepared grid loop
        add_action( 'genesis_loop', 'child_do_grid_loop' );
        // Add some extra post classes to the grid loop so we can style the columns
        add_filter( 'genesis_grid_loop_post_class', 'child_grid_loop_post_class' );
    }
}

This function uses the conditional tag of is_single(), preceded by the negation operator (!) to ensure the grid loop is not used on single posts, custom post types or attachments, and is_page()preceded by the negation operator to ensure it is not used on Pages either. That leaves it free to be used everywhere else.

The next three lines of code are quite logical – we remove our normal loop and add in our grid loop, which we’ll define in a moment. We also make reference to a filter that will add a few CSS classes which we use to style the columns.

Preparing The Grid Loop

Now we need to set up our grid loop. The genesis_grid_loop() functions takes an array of values, which we can configure.

/**
 * Prepare the grid loop.
 *
 * Takes care of existing query arguments for the page e.g. if it's a category
 * archive page, then the "cat" argument is carried into the grid loop, unless
 * it's overwritten in the $grid_args.
 *
 * @author Gary Jones
 * @link http://genesis.mywsiportal.com/genesis-grid-loop-advanced.htm
 * @uses genesis_grid_loop() Requires Genesis 1.5
 */
function child_do_grid_loop() {
    global $query_string, $paged;
    // Ensure the arguments for the normal query for the page are carried forwards
    // If you're using a Page to query the posts (e.g. with the Blog template), comment out the next line.
    wp_parse_str( $query_string, $query_args );
    // Create an array of arguments for the loop - can be grid-specific, or
    // normal query_posts() arguments to alter the loop
    $grid_args = array(
        'features' => 1,
        'feature_image_size' => 0,
        'feature_image_class' => 'alignleft post-image',
        'feature_content_limit' => 0,
        'grid_image_size' => 'grid-thumbnail',
        'grid_image_class' => 'alignleft post-image',
        'grid_content_limit' => 0,
        'more' => __( 'Continue reading →', 'genesis' ),
        'posts_per_page' => 6,
    );
    // Make sure the first page has a balanced grid
    if ( 0 == $paged )
        // If first page, add number of features to grid posts, so balance is maintained
        $grid_args['posts_per_page'] += $grid_args['features'];
    else
        // Keep the offset maintained from our page 1 adjustment
        $grid_args['offset'] = ( $paged - 1 ) * $grid_args['posts_per_page'] + $grid_args['features'];
    // Merge the standard query for this page, and our preferred loop arguments
    genesis_grid_loop( array_merge( (array) $query_args, $grid_args ) );
}

There’s a lot there, so lets go through it. Firstly, we pull in a couple of global values that WordPress has created and populated for us. We need these later in the function, so we need to be able to access the values of them.

Next we take the normal query arguments for that page (like the category ID, tag ID, custom post type name or something else that defines what set of posts we want) and put them into an array. The simple example didn’t need to include this, as the home page was just showing all posts, in the default date order. Now we’ve enabled the grid loop on other archive pages, this is needed.

The amendment to that is when you’re using the Blog page template magic from within Genesis to show posts on a Page. In this case, the query according to WordPress is for the Page, so passing these through to the grid loop functions means the blog page template magic gets bypassed and no posts would should show. To solve this, we can just comment out the wp_parse_str() line as indicated.

Then comes the main configurable section for how we want the grid loop to run. See the Understanding the Parameters section on the simple example to know what they all mean. The only changes made here, are the number of features, number of posts_per_page, and the more link text.

The bit after that about balancing needs a little bit of explaining. In the simple example, the number of features was equal to the number of columns, meaning that on page 2 and later of the archives, the grid was always complete (except maybe for the final page). However, we want something more flexible that allows, say, 3 columns, and 1 feature post. If we set our posts_per_page to be an exact multiple of the number of columns, then on page 2 and later, the grid is balanced, but page 1, where one of the posts is a feature, means we’ll have an unsightly gap at the end of the grid. If we increased the posts_per_page so the page 1 looked right, then there would be one extra grid post on it’s own on all later pages!

What we do, therefore, is adjust the total number of posts to also include the number of feature posts we want, just for page 1 (props to Jen for identifying this issue and coming up with a simple fix). Unfortunately, this causes an overlap where the last post(s) (equal to the number of feature posts) on page 1 are repeated at the start of page 2, so we add an offset in, and WordPress starts pulling posts from the database at the right spot. Phew!

Finally, we take the first array of query values (cast to an array, in case the wp_parse_str() line is commented out; $query_args would be a scalar value if so, which means our grid array would be unable to merge with it and would be dropped), merge it with our provided grid loop values, and send it all off to Genesis to create the grid loop itself. One alternative you might want here is to only show the features and grids on the first page of the archive, and go back to normal posts on page 2 and later. If so, switch the final line:

// Merge the standard query for this page, and our preferred loop arguments
genesis_grid_loop( array_merge( $query_args, $grid_args ) );

for:

// Only use the grid on the first page
if ( 0 == $paged) {
    // Merge the standard query for this page, and our preferred loop arguments
    genesis_grid_loop( array_merge( $query_args, $grid_args ) );
} else {
    query_posts( array_merge( $query_args, $grid_args ) );
    genesis_standard_loop();
}

Styling The Grid Loop

In terms of styling, the simple example focused on the case when you have two columns – float one left, float one right, give them both a width of just under half, with some padding in between. However, if we want more than two columns in our grid, we can’t make use of the even and odd class names, so we’ll add our own, using the function we defined earlier on.

/**
 * Add some extra body classes to grid posts.
 *
 * Change the $columns value to alter how many columns wide the grid uses.
 *
 * @author Gary Jones
 * @link http://genesis.mywsiportal.com/genesis-grid-loop-advanced.htm
 *
 * @global array $_genesis_loop_args
 * @global integer $loop_counter
 * @param array $classes
 */
function child_grid_loop_post_class( $grid_classes ) {
    global $_genesis_loop_args, $loop_counter;
    // Alter this number to change the number of columns - used to add class names
    $columns = 3;
    // Only want extra classes on grid posts, not feature posts
    if ( $loop_counter >= $_genesis_loop_args['features'] ) {
        // Add genesis-grid-column-? class to know how many columns across we are
        $grid_classes[] = sprintf( 'genesis-grid-column-%s', ( ( $loop_counter - $_genesis_loop_args['features'] ) % $columns ) + 1 );
        // Add size1of? class to make it correct width
        $grid_classes[] = sprintf( 'size1of%s', $columns );
    }
    return $grid_classes;
}

By the time this function is run, we’re inside the grid loop, about to start showing individual posts. Specifically, this is run when it comes to adding classes to each post.

We start by pulling in another couple of global variables – one created by Genesis when it was creating the loop, and another from WordPress that identifies how far through the loop we’ve got; for each post that is displayed, $loop_counter gets increased by one.

The next line is so simple, yet is probably my favourite – once the CSS is set up (we’ll get to that shortly), it’s just this value you need to change to alter between two, three, four or more columns on the grid. Beautiful :)

We then come to adding our extra classes. As we only want them on our grid posts, we skip over this section if we’re outputting a feature post. For grid posts, there are two classes being added. The first adds a numbered class, indicating which column we’re in; this allows you to style all of the third column posts, say, via .genesis-grid-column-3 { color: red; }. The second class adds asize1of3 class (when $columns = 3), and this is used to specify the width of the column.

Suggested CSS

Taking our lead from some of the Genesis 1.5 style sheet styles, we come up with the following:

#content .genesis-grid {
    float: left;
    margin: 0;
    padding: 15px 0 10px 3%;
}
#content .genesis-grid-column-1 {
    clear:left;
    padding-left: 0;
}
.size1of2 {
    width: 48%;
}
.size1of3 {
    width: 31%;
}
.size1of4 {
    width: 22.5%;
}
.size1of5 {
    width: 17.4%;
}
.size1of6 {
    width: 14%;
}
/* Above widths assume 0 left padding on the first column, 3% left padding on all
subsequent columns, and a total sum of 99% to avoid browser rounding errors */

All of the grid elements are floated left and have some padding added. The grid posts in the first column are set to stop floating, and move on to a fresh new row, with the left padding removed. Finally, all the column widths are added (for up to 6 columns) based on work that Brian has done on the new Genesis style sheet.

If you want different amounts of padding, then you’ll need to adjust the width percentages, else you’ll either have noticeable gaps, or the last post in a row wrapping around to below the others in the same row.

Putting it Altogether

Here’s the final PHP code to drop in to your functions.php file (and don’t forget to put the CSS above into your style.css) – remember to change values on the highlighted lines:

add_action( 'genesis_before_loop', 'child_maybe_do_grid_loop' );
/**
 * Before we get to the loop, see if we're anywhere but a single page. If so,
 * swap out the standard loop for our grid loop.
 *
 * @author Gary Jones
 * @link http://genesis.mywsiportal.com/genesis-grid-loop-advanced.htm
 */
function child_maybe_do_grid_loop() {
    // Amend this conditional to pick where this grid looping occurs
    if ( ! is_single() && ! is_page() ) {
        // Remove the standard loop
        remove_action( 'genesis_loop', 'genesis_do_loop' );
        // Use the prepared grid loop
        add_action( 'genesis_loop', 'child_do_grid_loop' );
        // Add some extra post classes to the grid loop so we can style the columns
        add_filter( 'genesis_grid_loop_post_class', 'child_grid_loop_post_class' );
    }
}
/**
 * Prepare the grid loop.
 *
 * Takes care of existing query arguments for the page e.g. if it's a category
 * archive page, then the "cat" argument is carried into the grid loop, unless
 * it's overwritten in the $grid_args.
 *
 * @author Gary Jones
 * @link http://genesis.mywsiportal.com/genesis-grid-loop-advanced.htm
 * @uses genesis_grid_loop() Requires Genesis 1.5
 */
function child_do_grid_loop() {
    global $query_string, $paged;
    // Ensure the arguments for the normal query for the page are carried forwards
    // If you're using a Page to query the posts (e.g. with the Blog template), comment out the next line.
    wp_parse_str( $query_string, $query_args );
    // Create an array of arguments for the loop - can be grid-specific, or
    // normal query_posts() arguments to alter the loop
    $grid_args = array(
        'features' => 1,
        'feature_image_size' => 0,
        'feature_image_class' => 'alignleft post-image',
        'feature_content_limit' => 0,
        'grid_image_size' => 'grid-thumbnail',
        'grid_image_class' => 'alignleft post-image',
        'grid_content_limit' => 0,
        'more' => __( 'Continue reading →', 'genesis' ),
        'posts_per_page' => 6,
    );
    // Make sure the first page has a balanced grid
    if ( 0 == $paged )
        // If first page, add number of features to grid posts, so balance is maintained
        $grid_args['posts_per_page'] += $grid_args['features'];
    else
        // Keep the offset maintained from our page 1 adjustment
        $grid_args['offset'] = ( $paged - 1 ) * $grid_args['posts_per_page'] + $grid_args['features'];
    // Merge the standard query for this page, and our preferred loop arguments
    genesis_grid_loop( array_merge( (array) $query_args, $grid_args ) );
}
/**
 * Add some extra body classes to grid posts.
 *
 * Change the $columns value to alter how many columns wide the grid uses.
 *
 * @author Gary Jones
 * @link http://genesis.mywsiportal.com/genesis-grid-loop-advanced.htm
 *
 * @global array $_genesis_loop_args
 * @global integer $loop_counter
 * @param array $classes
 */
function child_grid_loop_post_class( $grid_classes ) {
    global $_genesis_loop_args, $loop_counter;
    // Alter this number to change the number of columns - used to add class names
    $columns = 3;
    // Only want extra classes on grid posts, not feature posts
    if ( $loop_counter >= $_genesis_loop_args['features'] ) {
        // Add genesis-grid-column-? class to know how many columns across we are
        $grid_classes[] = sprintf( 'genesis-grid-column-%s', ( ( $loop_counter - $_genesis_loop_args['features'] ) % $columns ) + 1 );
        // Add size1of? class to make it correct width
        $grid_classes[] = sprintf( 'size1of%s', $columns );
    }
    return $grid_classes;
}

Summary

Even after all of this, there are still more ways you can go extend grid loops – the code above can be adapted so that you have differently configured grid loops running on different archive pages, or using a grid loop that uses a custom loop to output the posts in some special way (think images + post title caption for a portfolio). Go ahead and experiment!