Categories
WordPress WordPress Templates

WordPress Theme Exercise Solution: Metonymic Content Generation

This page presents a solution for WordPress Theme Exercise: Metonymic.

If you want to try building the site without following step-by-step directions, consult that document.

If going through these instructions, please first review the original instructions at that link.

Content Generation

Let’s start with the biggest task: the generation of content for the front page.

A Quick Edit to a Template Part

First, duplicate the content.php file that is inside the template-parts folder. Call the duplicate content-BACKUP.php. Then open up the file content.php. (We’re keeping a copy of the original in case anything goes wrong).

Here we will make a small change to the file in order to output excerpts if we’re not on a single view of a post. Specifically, change this section:

the_content( sprintf(
        wp_kses(
                /* translators: %s: Name of current post. Only visible to screen readers */
                __( 'Continue reading<span class="screen-reader-text"> "%s"</span>', 'metonymic' ),
                array(
                        'span' => array(
                                'class' => array(),
                        ),
                )
        ),
        get_the_title()
) );

to the following. We’re adding a condition: if we’re not on a single template page, use the excerpt(). If we are, use the_content();

if ( !is_single() ) :
 the_excerpt( sprintf(
        wp_kses(
                /* translators: %s: Name of current post. Only visible to screen readers */
                __( 'Continue reading<span class="screen-reader-text"> "%s"</span>', 'metonymic' ),
                array(
                        'span' => array(
                                'class' => array(),
                        ),
                )
        ),
        get_the_title()
 ) );


else : 
 the_content( sprintf(
        wp_kses(
                /* translators: %s: Name of current post. Only visible to screen readers */
                __( 'Continue reading<span class="screen-reader-text"> "%s"</span>', 'metonymic' ),
                array(
                        'span' => array(
                                'class' => array(),
                        ),
                )
        ),
        get_the_title()
 ) );

endif

In short, we have duplicated the loop and changed one word in the duplicate, then added the three lines that make up our condition (IF, ELSE, ENDIF).

Test the front page of your site. You should now be seeing the articles get content summaries rather than the full text of the post.

Conversely, if you click on a post title, you will see the post with the full content rather than the summary.

We will make additional changes to the content.php later, but for now, that will be enough to get started with our main looping tasks.

The Front Page Loops

In your theme, duplicate the index.php file and call it front-page.php (note: that’s a hyphen, not an underscore).

Here’s the loop we start with:


<?php
if ( have_posts() ) :

        if ( is_home() && ! is_front_page() ) :
                ?>
                <header>
                        <h1 class="page-title screen-reader-text"><?php single_post_title(); ?></h1>
                </header>
                <?php
        endif;

        /* Start the Loop */
        while ( have_posts() ) :
                the_post();

                /*
                 * Include the Post-Type-specific template for the content.
                 * If you want to override this in a child theme, then include a file
                 * called content-___.php (where ___ is the Post Type name) and that will be used instead.
                 */
                get_template_part( 'template-parts/content', get_post_type() );

        endwhile;

        the_posts_navigation();

else :

        get_template_part( 'template-parts/content', 'none' );

endif;
?>

Clean Up The Loop

Let’s clean that loop up a bit. Remove the following parts:

  • The is_home() && ! is_front_page() condition
    We don’t need this condition. It is testing to see if we’re on a static home page and outputting the title of the page wrapped in a class that hides the content while making it still accessible. That class uses (screen-reader-text) functions like the famous visually-hidden class.
    We don’t need the title of a post or page output here, so remove the whole if .. endif block. Since it won’t be triggered anyway, it’s just taking up space.
  • The Big Comment Block
    This block (‘include the post-type…’) explains how the get_template_part code works. Remove that.
  • the_posts_navigation() function
    This function outputs links to the next and previous posts at the end a loop. This is of course very useful in a traditional blog format (and definitely in an archive), but we’re going for a different format (a specific number of posts on the front page) for this site. So remove that function call.

Here’s the loop we’re left with:

<?php
if ( have_posts() ) :

        /* Start the Loop */
        while ( have_posts() ) :
                the_post();

                get_template_part( 'template-parts/content', get_post_type() );

        endwhile;

else :
        get_template_part( 'template-parts/content', 'none' );
endif;
?>

The logic is now nice and basic:

  • if we have posts, output using the content template part.
  • If we don’t have posts, output a message using the content-none template part.

Custom Queries

In earlier exercises, we made custom query objects using the new wp_query() constructor function, then copied the resulting loops to make multiple sections of content.

In this exercise, we will do this more efficiently.

To illustrate, here is one common way the creation of new wp_query objects is done:

$my_loop = new WP_Query( array(
         'category_name'    => 'headlines',
         'posts_per_page'    => '6',
        ) );

if ( $my_loop->have_posts() ) :

   while ( $my_loop->have_posts() ) :
       $my_loop->the_post();

      get_template_part( 'template-parts/content', get_post_type() );

etc.

That is the way we’ve done it in earlier exercises. However, you will often see this type of task coded in another way that is slightly wordier, but probably more legible:

$args = array(
         'category_name'    => 'headlines',
         'post_per_page'    => '6',
        ) 

$my_loop = new WP_Query( $args );

if ( $my_loop->have_posts() ) :

   while ( $my_loop->have_posts() ) :
       $my_loop->the_post();

      get_template_part( 'template-parts/content', get_post_type() );

etc.

In this second way, we define the arguments for the WP_Query constructor separately. I’ve called that array $args (short for arguments), but we could name it whatever we want. Once we define the array of properties for the new query, we pass that array to the WP_Query constructor function, instead of defining the array within the brackets of the constructor (as in the first example).

Both examples above are ultimately doing the same thing.

A Loop of Loops

Taking the second approach a step further, we can make an array of “argument” arrays and then use a loop to pass each one in turn to an inner wp_query constructor function and loop.

In other words, rather than having five WordPress loops, we will repeat a single loop five times. Each of the nested “argument” arrays will hold the properties we want for each iteration of the loop.

To find the values we need to use as arguments for the wp_query class, consult the WordPress code reference on wp_query.

Since each loop represents a section of my front page, I’ve called my array of arrays $sections. Put it above your wp_query constructor. The usual reminder applies here: if you type the code rather than just copying and pasting it from this web page, you will develop a better sense of PHP syntax.

$sections = array(

    array(
        'category_name'     => 'headlines',
        'posts_per_page'    => '9',
        'orderby'           => 'rand',
    ),

    array(
        'category_name'     => 'opinions',
        'posts_per_page'    => '4',
        'orderby'           => 'DATE',                      
    ),                    

    array(
        'category_name'     => 'features',
        'posts_per_page'    => '4',
        'orderby'           => 'DATE',
    ),                    

    array(
        'category_name'     => 'culture',
        'posts_per_page'    => '9',
        'orderby'           => 'rand',
    ),

    array(
        'category_name'     => 'lifestyle',
        'posts_per_page'    => '6',
        'orderby'           => 'rand',
    ),

);

Now modify your loop to make a custom query. As a first step to see if we’ve set up our array of arrays correctly, we’ll here pass the first nested array as an argument.


$my_loop = new WP_Query( $sections[0] );
if ( $my_loop->have_posts() ) :

        while ( $my_loop->have_posts() ) :
                $my_loop->the_post();

                get_template_part( 'template-parts/content', get_post_type() );

        endwhile;

else :
        get_template_part( 'template-parts/content', 'none' );

endif;
        wp_reset_postdata();
?>     

Test your site in a browser. You will see that the content is derived from the first of the nested arrays: as in other programming languages, PHP array positions start a zero, not one.

You should see, in other words, 9 random posts from the headlines category.

If you change $sections[0] to $sections[1], you’ll see that the content is now derived from the second of the nested arrays (Opinions).

How We Loop the Loop

All we have to do now is loop through the whole $sections array. To do that, we can use a foreach loop.

Right above the defining of $my_loop, put the following line:

foreach ( $sections as $section ) {

Then put the closing curly brace after the endif at the end of the loop.

Finally in the new WP_Query constructor function, turn $sections[0] to $section.

The code should now look like this:

foreach ( $sections as $section ) {

  $my_loop = new WP_Query( $section );

  if ( $my_loop->have_posts() ) :

        while ( $my_loop->have_posts() ) :
                $my_loop->the_post();

                get_template_part( 'template-parts/content', get_post_type() );

        endwhile;

  else :
        get_template_part( 'template-parts/content', 'none' );

  endif;

  wp_reset_postdata();

} // end foreach

?>

How does this work? If you notice what’s plural and what’s singular in the variable naming, the logic should be clear.

The foreach loop will go through the items in the $sections array (plural). Each time through, the inner array in that place in the outer array will be placed in a variable called $section (singular).

For that reason, make sure that you have changed the value passed to the new wp_query constructor from $sections[0] to $section.

Now test your page. You should see all five sections of content output.

Now let’s work on sectioning our home page with php, html, & css.