Exchange FAQs: How Do I Create a Custom Product Category Page

From IThemes Codex
Jump to: navigation, search

By default, a theme's category page will be used to display Products per Category. In most, if not all cases, the layout intended for blog posts won't do for products. In this article, I'll describe how you can make a custom category page.

As you will be creating new template files, you need access to your server in order to create and update such files.

All modifications and additions need to be done in your child theme folder. Editing your core theme files is a bad idea, since such modifications will be overwritten when you update your (parent) theme. So make sure that you are using a child theme.

Contents

Step 1: Duplicate the Existing Archive Page

As a starting point for the Product Category pages, we will use the standard archive or category page used in your theme. If your child theme folder currently doesn't have a file named archive.php, copy the one from the parent theme folder into your child theme folder.

In some cases, themes will have a file named category.php and a file archive.php. In that case, first use the category.php file as the basis file.

Rename the copied file to taxonomy-it_exchange_category.php. Do not use any other name, as that won't work.

Step 2: Edit your Product Archive page template (taxonomy-it_exchange_category.php)

The contents of your Product Archive page depends on which theme you are using. For this example, I will use the archive page from the WordPress default theme 2014, but your Product Category page template may look different.

archive.php from the WordPress 2014 theme

<?php
/**
 * The template for displaying Archive pages
 *
 * Used to display archive-type pages if nothing more specific matches a query.
 * For example, puts together date-based pages if no date.php file exists.
 *
 * If you'd like to further customize these archive views, you may create a
 * new template file for each specific one. For example, Twenty Fourteen
 * already has tag.php for Tag archives, category.php for Category archives,
 * and author.php for Author archives.
 *
 * @link http://codex.wordpress.org/Template_Hierarchy
 *
 * @package WordPress
 * @subpackage Twenty_Fourteen
 * @since Twenty Fourteen 1.0
 */

get_header(); ?>

	<section id="primary" class="content-area">
		<div id="content" class="site-content" role="main">

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

			<header class="page-header">
				<h1 class="page-title">
					<?php
						if ( is_day() ) :
							printf( __( 'Daily Archives: %s', 'twentyfourteen' ), get_the_date() );

						elseif ( is_month() ) :
							printf( __( 'Monthly Archives: %s', 'twentyfourteen' ), get_the_date( _x( 'F Y', 'monthly archives date format', 'twentyfourteen' ) ) );

						elseif ( is_year() ) :
							printf( __( 'Yearly Archives: %s', 'twentyfourteen' ), get_the_date( _x( 'Y', 'yearly archives date format', 'twentyfourteen' ) ) );

						else :
							_e( 'Archives', 'twentyfourteen' );

						endif;
					?>
				</h1>
			</header><!-- .page-header -->

			<?php
					// Start the Loop.
					while ( have_posts() ) : the_post();

						/*
						 * Include the post format-specific template for the content. If you want to
						 * use this in a child theme, then include a file called called content-___.php
						 * (where ___ is the post format) and that will be used instead.
						 */
						get_template_part( 'content', get_post_format() );

					endwhile;
					// Previous/next page navigation.
					twentyfourteen_paging_nav();

				else :
					// If no content, include the "No posts found" template.
					get_template_part( 'content', 'none' );

				endif;
			?>
		</div><!-- #content -->
	</section><!-- #primary -->

<?php
get_sidebar( 'content' );
get_sidebar();
get_footer();


There is quite a lot going on in here, but the only relevant part is where the Blog Post content is being displayed (which is eventually the code we want to replace with the Exchange Product). This is generally "inside the loop". "The WordPress Loop" is where the template will go through all posts, and display each one of them. In the 2014 template file, this code can be found from lines 49 through 58. As the theme uses post formats, the code that will actually output the Post (read: Product) is:


get_template_part( 'content', get_post_format() );


Replace this code with:


get_template_part( 'content', 'exchange-category' );


In some Builder themes, the post format files are located in a sub folder post-formats. In that case, the code reads:


get_template_part('post-formats/content', get_post_format());


and you should replace that with:


get_template_part('post-formats/content', 'exchange-category' );


Step 3: Create the exchange-category template part (content-exchange-category.php)

Duplicate the content.php template file and rename it content-exchange-category.php. Again, create the file in your child theme folder.

(*) If the post format files are located in a sub folder, make sure that you maintain that hierarchy, so create the sub folder (with the same name, e.g. post-formats in your child theme folder, and create the content-exchange-category.php in that sub folder.

content.php from the WordPress 2014 theme

<?php
/**
 * The default template for displaying content
 *
 * Used for both single and index/archive/search.
 *
 * @package WordPress
 * @subpackage Twenty_Fourteen
 * @since Twenty Fourteen 1.0
 */
?>

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

	<header class="entry-header">
		<?php if ( in_array( 'category', get_object_taxonomies( get_post_type() ) ) && twentyfourteen_categorized_blog() ) : ?>
		<div class="entry-meta">
			<span class="cat-links"><?php echo get_the_category_list( _x( ', ', 'Used between list items, there is a space after the comma.', 'twentyfourteen' ) ); ?></span>
		</div>
		<?php
			endif;

			if ( is_single() ) :
				the_title( '<h1 class="entry-title">', '</h1>' );
			else :
				the_title( '<h1 class="entry-title"><a href="' . esc_url( get_permalink() ) . '" rel="bookmark">', '</a></h1>' );
			endif;
		?>

		<div class="entry-meta">
			<?php
				if ( 'post' == get_post_type() )
					twentyfourteen_posted_on();

				if ( ! post_password_required() && ( comments_open() || get_comments_number() ) ) :
			?>
			<span class="comments-link"><?php comments_popup_link( __( 'Leave a comment', 'twentyfourteen' ), __( '1 Comment', 'twentyfourteen' ), __( '% Comments', 'twentyfourteen' ) ); ?></span>
			<?php
				endif;

				edit_post_link( __( 'Edit', 'twentyfourteen' ), '<span class="edit-link">', '</span>' );
			?>
		</div><!-- .entry-meta -->
	</header><!-- .entry-header -->

	<?php if ( is_search() ) : ?>
	<div class="entry-summary">
		<?php the_excerpt(); ?>
	</div><!-- .entry-summary -->
	<?php else : ?>
	<div class="entry-content">
		<?php
			the_content( __( 'Continue reading <span class="meta-nav">→</span>', 'twentyfourteen' ) );
			wp_link_pages( array(
				'before'      => '<div class="page-links"><span class="page-links-title">' . __( 'Pages:', 'twentyfourteen' ) . '</span>',
				'after'       => '</div>',
				'link_before' => '<span>',
				'link_after'  => '</span>',
			) );
		?>
	</div><!-- .entry-content -->
	<?php endif; ?>

	<?php the_tags( '<footer class="entry-meta"><span class="tag-links">', '', '</span></footer>' ); ?>
</article><!-- #post-## -->

Depending on your needs, you can remove most of the code, as it is related to displaying the post title, post meta info (written by, published on, # of comments etc.). Then, the actual post content will be displayed through either:


the_excerpt()


or


the_content()


This may differ per theme.

That is the code that you will replace with the code to display a product:


it_exchange_set_product( $post->ID );
it_exchange_get_template_part( 'content-store/elements/product' );


Based on the above template, stripping all unrelated content would result in the following template (for the WordPress 2014 theme):


<?php
/**
 * The default template for displaying content
 *
 * Used for both single and index/archive/search.
 *
 * @package WordPress
 * @subpackage Twenty_Fourteen
 * @since Twenty Fourteen 1.0
 */
?>

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

	<div class="entry-content">
		<?php
			it_exchange_set_product( $post->ID );
			it_exchange_get_template_part( 'content-store/elements/product' );

			wp_link_pages( array(
				'before'      => '<div class="page-links"><span class="page-links-title">' . __( 'Pages:', 'twentyfourteen' ) . '</span>',
				'after'       => '</div>',
				'link_before' => '<span>',
				'link_after'  => '</span>',
			) );
		?>
	</div><!-- .entry-content -->

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

For a Builder theme, e.g. Builder Cohen, the stripped template file to display the product would look like this:

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

	<div class="entry-wrapper">
		<!-- post content -->
		<div class="entry-content clearfix">
                        <?php it_exchange_set_product( $post->ID ); ?>
                        <?php it_exchange_get_template_part( 'content-store/elements/product' ); ?>
		</div>
	</div>

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

Customize the layout of the Product page

To change the layout of how each product is displayed, you can follow these instructions in the Codex: http://ithemes.com/codex/page/Exchange_FAQs:_How_Do_I_Edit_My_Template_Files

More template examples

Not all Themes use Post formats. In that case, it is not necessary to create a content-exchange-category.php template file. For instance, in some Builder themes, the archive.php files looks like this:

archive.php from the Builder-Avail theme

<?php

function render_content() {
	
?>
	<?php if ( have_posts() ) : ?>
		<div class="loop">
			<div class="loop-header">
				<h4 class="loop-title">
					<?php
						the_post();
						
						if ( is_category() ) { // Category Archive
							$title = sprintf( __( 'Archive for %s', 'it-l10n-Builder-Avail' ), single_cat_title( '', false ) );
						}
						else if ( is_tag() ) { // Tag Archive
							$title = sprintf( __( 'Archive for %s', 'it-l10n-Builder-Avail' ), single_tag_title( '', false ) );
						}
						else if ( is_tax() ) { // Tag Archive
							$title = sprintf( __( 'Archive for %s', 'it-l10n-Builder-Avail' ), builder_get_tax_term_title() );
						}
						else if ( function_exists( 'is_post_type_archive' ) && is_post_type_archive() && function_exists( 'post_type_archive_title' ) ) { // Post Type Archive
							$title = post_type_archive_title( '', false );
						}
						else if ( is_author() ) { // Author Archive
							$title = sprintf( __( 'Author Archive for %s', 'it-l10n-Builder-Avail' ), get_the_author() );
						}
						else if ( is_year() ) { // Year-Specific Archive
							$title = sprintf( __( 'Archive for %s', 'it-l10n-Builder-Avail' ), get_the_time( 'Y' ) );
						}
						else if ( is_month() ) { // Month-Specific Archive
							$title = sprintf( __( 'Archive for %s', 'it-l10n-Builder-Avail' ), get_the_time( 'F Y' ) );
						}
						else if ( is_day() ) { // Day-Specific Archive
							$title = sprintf( __( 'Archive for %s', 'it-l10n-Builder-Avail' ), get_the_date() );
						}
						else if ( is_time() ) { // Time-Specific Archive
							$title = __( 'Time Archive', 'it-l10n-Builder-Avail' );
						}
						else { // Default catchall just in case
							$title = __( 'Archive', 'it-l10n-Builder-Avail' );
						}
						
						if ( is_paged() )
							printf( '%s – Page %d', $title, get_query_var( 'paged' ) );
						else
							echo $title;
						
						rewind_posts();
					?>
				</h4>
			</div>
			
			<div class="loop-content">
				<?php while ( have_posts() ) : // The Loop ?>
					<?php the_post(); ?>
					
					<div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
						<!-- title, meta, and date info -->
						<div class="entry-header clearfix">
							<h3 class="entry-title">
								<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
							</h3>
							<div class="entry-meta-wrapper">
							
							<span class="entry-meta date">
								<?php the_time( 'm/d/y' ); ?>
							</span>							
							
							<span class="entry-meta">
								<?php printf( __( '%s', 'it-l10n-Builder-Avail' ), '<span class="author">' . builder_get_author_link() . '</span>' ); ?>
							</span>
							
							<span class="entry-meta">
								<?php do_action( 'builder_comments_popup_link', '<span class="comments">', '</span>', __( '%s', 'it-l10n-Builder-Avail' ), __( 'Comments (0)', 'it-l10n-Builder-Avail' ), __( 'Comments (1)', 'it-l10n-Builder-Avail' ), __( 'Comments (%)', 'it-l10n-Builder-Avail' ) ); ?>
							</span>
							
							</div>
							
						</div>
						
						<!-- post content -->
						<div class="entry-content clearfix">
							<?php the_content( __( 'Read More→', 'it-l10n-Builder-Avail' ) ); ?>
						</div>
						
						<!-- categories, tags and comments -->
						<div class="entry-footer clearfix">
							<?php do_action( 'builder_comments_popup_link', '<div class="entry-meta alignright"><span class="comments">', '</span></div>', __( 'Comments %s', 'it-l10n-Builder-Avail' ), __( '(0)', 'it-l10n-Builder-Avail' ), __( '(1)', 'it-l10n-Builder-Avail' ), __( '(%)', 'it-l10n-Builder-Avail' ) ); ?>
							<div class="entry-meta alignleft">
								<div class="categories"><?php printf( __( 'Categories : %s', 'it-l10n-Builder-Avail' ), get_the_category_list( ', ' ) ); ?></div>
								<?php the_tags( '<div class="tags">' . __( 'Tags : ', 'it-l10n-Builder-Avail' ), ', ', '</div>' ); ?>
							</div>
						</div>
					</div>
					<!-- end .post -->
					
					<?php comments_template(); // include comments template ?>
				<?php endwhile; // end of one post ?>
			</div>
			
			<div class="loop-footer">
				<!-- Previous/Next page navigation -->
				<div class="loop-utility clearfix">
					<div class="alignleft"><?php previous_posts_link( __( '« Previous Page', 'it-l10n-Builder-Avail' ) ); ?></div>
					<div class="alignright"><?php next_posts_link( __( 'Next Page »', 'it-l10n-Builder-Avail' ) ); ?></div>
				</div>
			</div>
		</div>
	<?php else : // do not delete ?>
		<?php do_action( 'builder_template_show_not_found' ); ?>
	<?php endif; // do not delete ?>
<?php
	
}

add_action( 'builder_layout_engine_render_content', 'render_content' );

do_action( 'builder_layout_engine_render', basename( __FILE__ ) );

In this case, all you need to do is strip out the post specific content (such as the post title, post meta information etc.) and would leave something along these lines:

<?php

function render_content() {
	
?>
	<?php if ( have_posts() ) : ?>
		<div class="loop">
			<div class="loop-header">
				<h4 class="loop-title">
					<?php
						the_post();
						
						if ( is_category() ) { // Category Archive
							$title = sprintf( __( 'Archive for %s', 'it-l10n-Builder-Avail' ), single_cat_title( '', false ) );
						}
						else if ( is_tag() ) { // Tag Archive
							$title = sprintf( __( 'Archive for %s', 'it-l10n-Builder-Avail' ), single_tag_title( '', false ) );
						}
						else if ( is_tax() ) { // Tag Archive
							$title = sprintf( __( 'Archive for %s', 'it-l10n-Builder-Avail' ), builder_get_tax_term_title() );
						}
						else if ( function_exists( 'is_post_type_archive' ) && is_post_type_archive() && function_exists( 'post_type_archive_title' ) ) { // Post Type Archive
							$title = post_type_archive_title( '', false );
						}
						else if ( is_author() ) { // Author Archive
							$title = sprintf( __( 'Author Archive for %s', 'it-l10n-Builder-Avail' ), get_the_author() );
						}
						else if ( is_year() ) { // Year-Specific Archive
							$title = sprintf( __( 'Archive for %s', 'it-l10n-Builder-Avail' ), get_the_time( 'Y' ) );
						}
						else if ( is_month() ) { // Month-Specific Archive
							$title = sprintf( __( 'Archive for %s', 'it-l10n-Builder-Avail' ), get_the_time( 'F Y' ) );
						}
						else if ( is_day() ) { // Day-Specific Archive
							$title = sprintf( __( 'Archive for %s', 'it-l10n-Builder-Avail' ), get_the_date() );
						}
						else if ( is_time() ) { // Time-Specific Archive
							$title = __( 'Time Archive', 'it-l10n-Builder-Avail' );
						}
						else { // Default catchall just in case
							$title = __( 'Archive', 'it-l10n-Builder-Avail' );
						}
						
						if ( is_paged() )
							printf( '%s – Page %d', $title, get_query_var( 'paged' ) );
						else
							echo $title;
						
						rewind_posts();
					?>
				</h4>
			</div>
			
			<div class="loop-content">
				<?php while ( have_posts() ) : // The Loop ?>
					<?php the_post(); ?>
					
					<div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
						<!-- post content -->
						<div class="entry-content clearfix">
							<?php it_exchange_set_product( $post->ID ); ?>
							<?php it_exchange_get_template_part( 'content-store/elements/product' ); ?>
						</div>
					</div>
					<!-- end .post -->
					
				<?php endwhile; // end of one post ?>
			</div>
			
			<div class="loop-footer">
				<!-- Previous/Next page navigation -->
				<div class="loop-utility clearfix">
					<div class="alignleft"><?php previous_posts_link( __( '« Previous Page', 'it-l10n-Builder-Avail' ) ); ?></div>
					<div class="alignright"><?php next_posts_link( __( 'Next Page »', 'it-l10n-Builder-Avail' ) ); ?></div>
				</div>
			</div>
		</div>
	<?php else : // do not delete ?>
		<?php do_action( 'builder_template_show_not_found' ); ?>
	<?php endif; // do not delete ?>
<?php
	
}

add_action( 'builder_layout_engine_render_content', 'render_content' );

do_action( 'builder_layout_engine_render', basename( __FILE__ ) );
Personal tools
Namespaces
Variants
Actions
iThemes Codex
Codex Navigation
Toolbox