Creando un theme de WordPress (III): mostrando distintos contenidos con el loop y los templates

Respuesta rápida

Para mostrar el contenido de las  entradas y las páginas se utiliza el loop, a su vez, para personalizar el contenido se añaden templates extras como content.php o content-page.php, entre otros. Además, se actualizan los templates generales para diferenciar mejor el contenido.

Respuesta completa

Requisitos:

El loop de WordPress -a partir de ahora WP-, es la esencia más importante de WP, ya que una página no recibe miles de visitas por su diseño ni por su autor, si no por su contenido.

El loop se encargará de mostrar el contenido, por lo tanto irá en la parte central de nuestros templates.

De este modo, nuestro index.php quedará tal que así.

<?php
// File Security Check
if( !function_exists('wp') && !empty($_SERVER['SCRIPT_FILENAME']) && basename(__FILE__) == basename($_SERVER['SCRIPT_FILENAME']) ) {
    die ( 'You do not have sufficient permissions to access this page!' );
}
?>

<?php get_header(); ?>

<section id="primary" role="main">

    <?php if( have_posts() ) : ?>

        <?php get_template_part( 'loop' ); ?>

    <?php else : ?>

        <?php get_template_part( 'loop', 'empty' ); ?>

    <?php endif; ?>

</section>

<?php get_footer(); ?>

Voy a comentar la parte nueva -obviando la primera línea de seguridad-

<?php
// File Security Check
if( !function_exists('wp') && !empty($_SERVER['SCRIPT_FILENAME']) && basename(__FILE__) == basename($_SERVER['SCRIPT_FILENAME']) ) {
    die ( 'You do not have sufficient permissions to access this page!' );
}
?>

<?php get_header(); ?>

<section id="primary" role="main">
<!-- parte principal del contenido, con el role para la accesibilidad ARIA -->

    <?php if( have_posts() ) : ?>
    <!-- si la página tiene algún post que mostrar, llama a loop.php -->

        <?php get_template_part( 'loop' ); ?>
	<!-- esta función hace un require_once('loop.php') -->
	<!-- es MUY recomendable usar las funciones internas de WP -->

    <?php else : ?>
    <!-- si la página no tiene posts que mostrar, llama a loop-empty.php -->

        <?php get_template_part( 'loop', 'empty' ); ?>
	<!-- esta función hace un require_once('loop-empty.php') -->

    <?php endif; ?>

</section>

<?php get_footer(); ?>

Ahora hay que crear los archivos loop.php y loop-empty.php.

Cuando tengamos la página sin ningún post publicado, o tengamos una categoría o un tag sin ningún post vinculado, se mostrará el loop vacío.

Por lo tanto, el loop vacío tiene el siguiente contenido:

<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>

<div id="content" class="post-wrap">

    <article id="post-0" class="post no-results not-found">

        <header class="entry-header">

            <h1 class="entry-title">No se ha encontrado nada</h1>

        </header><!-- .entry-header -->

        <section class="article-content">

            <p>Lo sentimos, pero todavía no hay ninguna entrada relativa a lo que busca.</p>

        </section><!-- .entry-content -->

    </article><!-- #post-0 -->

</div><!--/.post-wrap-->

No voy a comentarlo porque el código en sí es fácil de entender. Usando etiquetas HTML5, tenemos un article que tiene un header con el título -diciendo que no hay nadená– y un section con el contenido -siendo educado al decir que no hay nadená.

Nuestro loop.php deberá generar el mismo formato, pero con contenido dinámico. Además, un loop puede tener varios o un post.

<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>

<div id="content" class="post-wrap">

    <?php while ( have_posts() ) : the_post(); ?>

        <article id="post-<?php the_ID(); ?>" >

            <?php if ( is_page() ) : ?>
                <?php get_template_part( 'content', 'page' ); ?>
            <?php else : ?>
                <?php get_template_part( 'content', get_post_format() ); ?>
            <?php endif; ?>

        </article><!-- #post-<?php the_ID(); ?> -->

    <?php endwhile; ?>

</div><!--/.post-wrap-->

Como se ve en el código, tenemos el bucle while -mientras haya un post, publicamos el post-.

A su vez, como en el loop-empty, creamos el article y le damos un id único con la función the_ID().

Además, diferenciamos entre una página estática o no. La única diferencia es que llamará a un template u otro.

Para el resto del formato llamamos al archivo content.php.

get_post_format devuelve falso, es decir, no lo usamos para nada, pero considero que es importante conocerlo porque con él se puede recrear el modo en el que Tumblr publica su contenido, teniendo distintos formatos si es un texto, un audio, una imagen, …

Seguimos, ahora con content.php, que solo contendrá el header y el section.

<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>

<header class="post-header">

	<?php if ( is_single() ) : ?>
		<h1 class="post-title entry-title" data-text="<?php the_title(); ?>"><?php the_title(); ?></h1>
	<?php else : ?>
		<h1 class="post-title entry-title" data-text="<?php the_title(); ?>"><a href="<?php the_permalink(); ?>" title="<?php the_title_attribute(); ?>" rel="bookmark"><?php the_title(); ?></a></h1>
	<?php endif; ?>

</header><!-- /.post-header -->

<section class="article-content">

	<?php the_content(); ?>

</section><!-- /.article-content -->

Aquí si voy a comentar:

<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>

<header class="post-header">

    <?php if ( is_single() ) : ?>
    <!-- si la página a mostrar es la página específica del post mostrará el título tal cual -->
        <h1 class="post-title entry-title" data-text="<?php the_title(); ?>"><?php the_title(); ?></h1>
        <!-- the_title() muestra el titulo del post -->
	<!-- data-text con the_title() ayuda a la conexión con terceros (aka Twitter) -->

    <?php else : ?>
	<!-- si la página a mostrar es una serie de post habrá que poner el enlace a cada post en sí -->
        <h1 class="post-title entry-title" data-text="<?php the_title(); ?>"><a href="<?php the_permalink(); ?>" title="<?php the_title_attribute(); ?>" rel="bookmark"><?php the_title(); ?></a></h1>
	<!-- the_title() muestra el titulo del post -->
	<!-- the_permalink() muestra el enlace al post -->
	<!-- the_title_attribute() muestra el titulo del post "desinfectado" por seguridad -->
    <?php endif; ?>

</header><!-- /.post-header -->

<section class="article-content">

    <?php the_content(); ?>
    <!-- muestra el contenido del post -->

</section><!-- /.article-content -->

El content-page.php tiene la misma lógica y es más simple:

<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>

<header class="page-title entry-header">

    <h1 class="page-title entry-title"><?php the_title(); ?></h1>

</header><!-- /.post-header -->

<section class="page-content article-content">

	<?php the_content(); ?>

</section><!-- /.article-content -->

¡Ya tenemos el loop terminado! Ahora hay que llamarlo en cada template genérico, cada uno con sus diferencias.

Como he decidido preguntar dentro del loop.php si es una página o no, nuestro single.php y page.php son idénticos:

<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>

<?php get_header(); ?>

    <section id="primary" role="main">

        <?php if( have_posts() ) : ?>

            <?php get_template_part( 'loop' ); ?>

        <?php endif; ?>

    </section>

<?php get_footer(); ?>

En este momento no preguntamos por el loop-empty porque si no se encuentra nos dará un error 404, cuya plantilla es:

<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>

<?php get_header(); ?>

    <section id="primary" role="main">

        <article id="page-404" class="page not-found">

            <header class="entry-header">

                <h1 class="entry-title">Error 404. No encontrado</h1>

            </header><!-- .entry-header -->

            <section class="article-content">

                <p>En serio, En este lugar no hay nada y lo que usted busca ya no existe (o incluso, nunca ha existido).</p>
                <p>Sin embargo, aquí hay cosas interesantes. ¡Echa un vistazo!</p>

            </section><!-- .entry-content -->

        </article><!-- #page-404 -->

    </section>

<?php get_footer(); ?>

Por último, nuestro archive.php es el más «dinámico», ya que tiene que diferenciar cuando tiene que mostrar según qué categoría, que etiqueta, que autor o que fecha.

<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>

<?php get_header(); ?>

    <section id="primary" role="main">

        <header class="page-header">

            <h1 class="archive-title">
                <?php
                if ( is_category() ) :
                    echo 'Archivos de categor&iacute;a: ' . '<span>' . single_cat_title( '', false ) . '</span>';

                elseif ( is_tag() ) :
                    echo 'Archivos de etiqueta: ' . '<span>' . single_tag_title( '', false ) . '</span>';

                elseif ( is_author() ) :
                    /* Queue the first post, that way we know
                     * what author we're dealing with (if that is the case).
                    */
                    the_post();
                    echo 'Archivos del autor: ' . '<span class="vcard"><a class="url fn n" href="' . esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ) . '" title="' . esc_attr( get_the_author() ) . '" rel="me">' . get_the_author() . '</a></span>';
                    /* Since we called the_post() above, we need to
                     * rewind the loop back to the beginning that way
                     * we can run the loop properly, in full.
                     */
                    rewind_posts();

                elseif ( is_day() ) :
                    echo 'Archivos del d&iacute;a: ' . '<span>' . get_the_date() . '</span>';

                elseif ( is_month() ) :
                    echo 'Archivos del mes: ' . '<span>' . get_the_date( 'F Y' ) . '</span>';

                elseif ( is_year() ) :
                    echo 'Archivos del a&ntilde;: ' . '<span>' . get_the_date( 'Y' ) . '</span>';

                else :
                    echo 'Archivos';

                endif;
                ?>
            </h1>

            <?php
            if ( is_category() ) :
                // show an optional category description
                $category_description = category_description();
                if ( ! empty( $category_description ) ) :
                    echo apply_filters( 'category_archive_meta', '<div class="taxonomy-description">' . $category_description . '</div>' );
                endif;

            elseif ( is_tag() ) :
                // show an optional tag description
                $tag_description = tag_description();
                if ( ! empty( $tag_description ) ) :
                    echo apply_filters( 'tag_archive_meta', '<div class="taxonomy-description">' . $tag_description . '</div>' );
                endif;

            endif;
            ?>

        </header><!-- /.page-header -->

        <?php if( have_posts() ) : ?>

            <?php get_template_part( 'loop' ); ?>

        <?php else : ?>

            <?php get_template_part( 'loop', 'empty' ); ?>

        <?php endif; ?>

    </section>

<?php get_footer(); ?>

Al principio puede parecer extraño tener tantos archivos divididos, pero a la larga ayuda mucho a la escalabilidad.

Por ahora ha sido bastante información.

Mucho código nuevo, pero si se analiza, siempre se está respetando el mismo formato.

Puedes descargarte el contenido aquí: Alisios v0.1.3