[DIY] Create a categorized directory of Marketplace stores with Review pages

Hi all!

I wanted my store owners to be able to submit information about their stores so they could each have a nice dedicated ratings & review page on the main site, with a categorized directory of all stores in the network, and the option to submit premium listings as well. I also wanted all this to be done from the front-end of the main site (don't want them in the dashboard at all!), and it all needed to fit seamlessly with the overall look and feel of my site. Oof!

I did look into WPMUdev's Directory plugin, but it doesn't have a front-end editor, which was a central element of my plan, and as mentioned, I wanted it to fit the current L&F of my site. So I developed my own package using a few plugins and a bit of template customization. (OK, so I just wanted to have some fun making the thing, I'll admit it :slight_smile: )

Here's what it looks like: http://etcemall.com/blog/another-fine-store-here/
...and here's how it all came to be:

Let's first get our plugins (or you can skip straight to the template stuff below and play with plugins later)...

The first plugin required is a front-end post form. My all-around favorite is by far Gravity Forms, but any other will do fine as long as posts can be submitted to predefined categories, and you can define how and what info is to be displayed. http://www.gravityforms.com/

Next are a cool ratings plugin and a sharing plugin, both installed network-wide (again, go ahead and substitute with your own preferences):
http://wordpress.org/extend/plugins/rating-widget/
http://wordpress.org/extend/plugins/share-and-follow/

For all-around convenience in site design, I also use J-Shortcodes and/or TheTheFly plugins for buttons, tabbed content, nifty boxes and such (give them a whirl, you'll love 'em):
http://www.jshortcodes.com/shortcodes/
http://thethefly.com/wp-plugins/thethe-tabs-and-accordions/

Finally, a menu plugin so you can really show off your stuff in style (this is entirely optional, your theme's menu may be perfectly fine for you). I use a magnificent premium menu plugin called UberMenu (I'm hooked!): http://wpmegamenu.com/
... but a very adequate free alternative can be found at Design Chemical:
http://www.designchemical.com/blog/index.php/wordpress-plugins/wordpress-plugin-jquery-drop-down-mega-menu-widget/

Now to the templates we need to customize (and the whole point of this post)...

For my site, I use the Gridmarket child-theme of Framemarket, so all references here will be to templates from that theme... and that's why this post is in the Framemarket forum too :slight_smile:. If you use another theme/child-theme, the customizations can be applied to the corresponding files.

The files from Gridmarket that you'll need are:
content.php
content-single.php
category.php
comments.php
style.css

Note that although comments.php already exists in Gridmarket, you'll need to copy the first 3 files from the Framemarket parent to Gridmarket.

Let's start with the easy one. Open category.php (once you've copied it over to the child-theme of course) and replace this
<h1 class="post-title"><?php printf( __( 'Category Archives: %s', 'framemarket'), '<span>' . single_cat_title( '', false ) . '</span>' ); ?></h1>
...with this

<?php if (is_category(array(17,18,19,20))) : ?>
	<h1 class="post-title"><?php printf( __( 'Here are all our %s stores', 'framemarket'), '<span>' . single_cat_title( '', false ) . '</span>' ); ?></h1>
<?php else : ?>
	<h1 class="post-title"><?php printf( __( 'Category Archives: %s', 'framemarket'), '<span>' . single_cat_title( '', false ) . '</span>' ); ?></h1>
<?php endif; ?>

Replace the category ID's in the array on the first line and the text of the post-title with your own stuff (don't remove the %s 'cuz that's what gets the category name). This will simply ensure that posts made to your selected categories will display on custom archive pages with the heading 'Here are all our (category here) stores'

Now open comments.php and replace the following (around line 25) to customize the display of reviews - formerly known as comments - on the ratings & review pages. Replace this:
<h3><?php printf( _n( '1 response to %2$s', '%1$s responses to %2$s', $num_comments, 'framemarket' ), number_format_i18n( $num_comments ), '<em>' . get_the_title() . '</em>' ) ?></h3>
...with this:
<?php if (in_category(array(17,18,19,20))) : ?>

<h1 class="post-title">Rave reviews for <?php the_title(); ?></h1>
	<h3><?php printf( _n( '%2$s has 1 review', '%2$s has %1$s reviews', $num_comments, 'framemarket' ), number_format_i18n( $num_comments ), '<em>' . get_the_title() . '</em>' ) ?></h3>
<?php else : ?>
	<h3><?php printf( _n( '1 response to %2$s', '%1$s responses to %2$s', $num_comments, 'framemarket' ), number_format_i18n( $num_comments ), '<em>' . get_the_title() . '</em>' ) ?></h3>
<?php endif; ?>

Again, replace the category ID's with your own. If you don't like the extra <h1> title I added, simply delete it or edit it. Now, to show customized labels on the comment form before any comments have actually been submitted, on line 62, replace this:
<?php comment_form() ?>
...with this:

<?php if (in_category(array(17,18,19,20))) : ?>
	<?php comment_form(array('title_reply' => "Review this store", 'label_submit' => "Submit your review", 'comment_field' => '<p class="comment-form-comment"><label for="comment">' . _x( 'Review', 'noun' ) . '</label><textarea id="comment" name="comment" cols="45" rows="8" aria-required="true"></textarea></p>')); ?>
<?php else : ?>
	<?php comment_form() ;?>
<?php endif; ?>

Remember to replace the category ID's with your own here too. Now let's get content.php open. Here we're going to customize the content for archive entries and the archive page navigation. On line 91, replace this:
<?php the_excerpt(); ?>
...with this:

<?php the_content(); ?>
	<?php if (is_category(array(17,18,19,20))) : ?>
		<span><a class="jbutton green" href="<?php the_permalink(); ?>" title="<?php printf( esc_attr__( 'Permalink to %s', 'framemarket'), the_title_attribute( 'echo=0' ) ); ?>" rel="bookmark"><?php _e( 'Read reviews', 'framemarket'); ?></a></span>
	<?php endif; ?>

Replace the category ID's with your own. This ensures that we get the whole post including a thumbnail of the primary image rather than just an excerpt of text. If you prefer just the excerpt, simply change the_content to the_excerpt. Also, notice the 'jbutton' in the link? This is one place the J-Shortcodes plugin comes in handy as it automagically adds a nicely-styled button with a permalink to the review page (we'll get to that soon, promise). Now let's have fun with the page navigation. Down at the bottom around line 130, replace this:

<div id="navigation-bottom" class="navigation">
	<div class="nav-previous"><?php next_posts_link( __( '<span class="meta-nav">?</span> Older posts', 'framemarket') ); ?></div>
	<div class="nav-next"><?php previous_posts_link( __( 'Newer posts <span class="meta-nav">?</span>', 'framemarket' ) ); ?></div>
</div>

...with this:

<?php if (is_category(array(17,18,19,20))) : ?>
	<div id="navigation-bottom" class="navigation">
		<div class="nav-next"><?php next_posts_link( __( 'Continue window shopping this way <span class="meta-nav">?</span>', 'framemarket') ); ?></div>
		<div class="nav-previous"><?php previous_posts_link( __( '<span class="meta-nav">?</span> Go back the way you came', 'framemarket' ) ); ?></div>
	</div>
<?php else : ?>
	<div id="navigation-bottom" class="navigation">
	<div class="nav-next"><?php next_posts_link( __( '<span class="meta-nav">?</span> Older posts', 'framemarket') ); ?></div>
	<div class="nav-previous"><?php previous_posts_link( __( 'Newer posts <span class="meta-nav">?</span>', 'framemarket' ) ); ?></div>
	</div>
<?php endif; ?>

Don't forget the category ID's :slight_smile: Did you notice that the direction of the 'Older' and 'Newer' posts arrows in the original code is screwed up? We just fixed that and added custom messages to display on those links when viewing store category archives. Edit them to suit the particular flavor of your site. I also like to have the navigation at the top; so if you want that too, simply add the replacement code just above line 29 where you see:
<?php while ( have_posts() ) : the_post(); ?>
Finally, and this is an optional template customization, let's open content-single.php and create a simple post-meta box to only display the store category on the review pages. We'll be hiding the actual post-meta in a moment when we get to the CSS. Just above line 7 where you see this:
<div class="post-meta">
...add this:

<div class="mycat">
	<?php if (in_category(array(17,18,19,20))) : ?>
		<?php printf( __( '<span class="%1$s">Store category: </span> %2$s', 'framemarket'), 'post-info-prep post-info-prep-cat-links', get_the_category_list( ', ' )) ; ?>
	<?php endif; ?>
</div>

There are those category ID's again! Also, feel free to give the wrapper div any name you like (I just like cats, so...).

OK, we're done with template customization, now let's get stuff looking nice! Unlike most WPMUdev child-themes, Gridmarket doesn't have a _inc/css folder. Simply open gridmarket/style.css to add custom styles. The first thing we're going to do is add some styling to ensure that all buttons that aren't jbuttons will be styled the same way (this includes Search, Buy Now, Submit, etc.). Harmony is a good thing :slight_smile: Add the following to style.css for those buttons (these styles work in dumb ol' IE too):

/*Same button style as J-Buttons*/
body input[type="submit"], .nav-previous a, .nav-next a, .reply a, a.mp_cart_direct_checkout_link, #mp-product-grid a.mp_link_buynow {
    display: inline-block;
    zoom: 1; /* zoom and *display = ie7 hack for display:inline-block */
    *display: inline;
    vertical-align: baseline;
    margin: 2px;
    outline: none;          /* remove dotted border in FF */
    cursor: pointer;
    text-align: center;
    text-decoration: none;
    font: 14px/100% Arial, Helvetica, sans-serif  !important;
    padding: .35em .75em .4em !important;
    text-shadow: 0 1px 1px rgba(0,0,0,.3);
    -webkit-border-radius: .5em;
    -moz-border-radius: .5em;
    border-radius: .5em;
    -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.2);
    -moz-box-shadow: 0 1px 2px rgba(0,0,0,.2);
    box-shadow: 0 1px 2px rgba(0,0,0,.2);
  color: #f2fbff !important;
  border: solid 1px #0076a3 !important;
  background: #0095cd !important;
  background: -webkit-gradient(linear, left top, left bottom, from(#00adee), to(#0078a5)) !important;
  background: -moz-linear-gradient(top,  #00adee,  #0078a5) !important;
  filter:  progid:DXImageTransform.Microsoft.gradient(startColorstr='#00adee', endColorstr='#0078a5') !important;
  }
body input[type="submit"]:hover, .nav-previous a:hover, .nav-next a:hover, .reply a:hover, a.mp_cart_direct_checkout_link:hover, #mp-product-grid a.mp_link_buynow:hover {
    display: inline-block;
    zoom: 1; /* zoom and *display = ie7 hack for display:inline-block */
    *display: inline;
    vertical-align: baseline;
    margin: 2px;
    outline: none;          /* remove dotted border in FF */
    cursor: pointer;
    text-align: center;
    text-decoration: none;
    font: 14px/100% Arial, Helvetica, sans-serif;
    padding: .35em .75em .4em !important;
    text-shadow: 0 1px 1px rgba(0,0,0,.3);
    -webkit-border-radius: .5em !important;
    -moz-border-radius: .5em !important;
    border-radius: .5em !important;
    -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.2);
    -moz-box-shadow: 0 1px 2px rgba(0,0,0,.2);
    box-shadow: 0 1px 2px rgba(0,0,0,.2);
  background: #007ead !important;
  border: solid 1px #0076a3 !important;
  background: -webkit-gradient(linear, left top, left bottom, from(#0095cc), to(#00678e)) !important;
  background: -moz-linear-gradient(top,  #0095cc,  #00678e) !important;
  filter:  progid:DXImageTransform.Microsoft.gradient(startColorstr='#0095cc', endColorstr='#00678e') !important;
  }
body input[type="submit"]:active, .nav-previous a:active, .nav-next a:active, .reply a:active, , a.mp_cart_direct_checkout_link:active, #mp-product-grid a.mp_link_buynow:active {
    position: relative;
    top: 1px;
  color: #80bed6;
  border: solid 1px #0076a3 !important;
  background: -webkit-gradient(linear, left top, left bottom, from(#0078a5), to(#00adee)) !important;
  background: -moz-linear-gradient(top,  #0078a5,  #00adee) !important;
  filter:  progid:DXImageTransform.Microsoft.gradient(startColorstr='#0078a5', endColorstr='#00adee') !important;
  }

Whew, that's a lot of CSS! Wait, there's more... below is the entire set of rules I use for my review and archive pages. Notice the container class names for categories (ex: .category-featured-stores); you'll need to replace those with your own categories wherever you see them like this: .category-YOUR-CAT-SLUG-HERE
Also, some of the selectors shown below don't exist yet, because we haven't created them (we will when we get to the Gravity Forms part, hang on...)

/*Featured Stores*/
body.archive #content img { /* Will affect all archive images for site consistency. Apply category classes to only affect certain categories like stores. */
  float:left;
  max-width:150px;
  max-height:150px;
  margin-right:20px;
  width:auto;
  }
body.archive span.store-desc { /* Comment this out to show the store description in archives. */
  display:none;
  }
#content .category-featured-stores .post-meta, #content .category-featured-stores .post-info, #content .category-collectibles .post-meta, #content .category-collectibles .post-info, #content .category-clothing-and-accessories .post-meta, #content .category-clothing-and-accessories .post-info, #content .category-handcrafted-goods .post-meta, #content .category-handcrafted-goods .post-info { /* Hides the standard WP navigation on store pages */
  display:none !important;
  visibility:hidden !important;
  }
#content .category-featured-stores h2.post-title, #content .category-collectibles h2.post-title, #content .category-clothing-and-accessories h2.post-title, #content .category-handcrafted-goods h2.post-title {
  background:#eee;
  padding:5px;
  }
#content .category-featured-stores .subtitle, #content .category-collectibles .subtitle, #content .category-clothing-and-accessories .subtitle, #content .category-handcrafted-goods .subtitle {
  font-size:16px;
  font-style:italic;
  }
.single-post .category-featured-stores, .single-post .category-collectibles, .single-post .category-clothing-and-accessories, .single-post .category-handcrafted-goods {
  border-bottom:none;
  }
.optimg { /* Container class for additional store images uploaded via Gravity Forms. */
  float:right;
  margin:0 20px 0 0;
  }
.single #content .optimg img {
  max-width:150px;
  }
.archive .optimg, .archive .store-desc {
  display:none; /* Hides additional images in archive pages. */
  }
.single .category-featured-stores #navigation-bottom, .single .category-collectibles #navigation-bottom, .single .category-clothing-and-accessories #navigation-bottom, .single .category-handcrafted-goods #navigation-bottom, {
  display:none; /* Hides previous-next links on store review pages. */
  }
.archive #navigation-bottom {
  margin:20px 0;
  }
.archive #navigation-bottom .nav-previous {
  float:left;
  width:auto;
  }
.archive #navigation-bottom .nav-next {
  float:right;
  width:auto;
  }
.mycat {
  background:#f0f0f0;
  padding:0 10px;
  font-size:14px;
  }

I won't include any styling here for the other plugins I've recommended 'cuz that would likely clash with whatever look you already have going on your site.

Now to the actual submission form. As I mentioned, I use Gravity Forms for this, but you could adapt it to whatever front-end solution you have. Here's how I've set mine up:

Title field = Your store's name
Website field = Your store's URL
Single line text = Descriptive Subtitle or Tagline
Body field = Store description
Category field = Store Category (select the categories you want your users to post to here, and make sure they're the same ones you've identified in the code snippets above!)
Image field = Store Image
Image field = Optional 2nd Image
Image field = Optional 3rd Image

Right, we have our fields set up, now let's set up the form to make the magic happen for your users. First, a nice touch is to make it so that users are redirected to their store review page upon submission (unless, of course, you set the Post Status to "Draft" or "Pending Review" one of the post fields). In the Form Settings field (the first one at the top), go to the "Confirmation" tab and select "Redirect". Enter http://YOUR-SITE.com/blog/stores/ in the field. Then check the "Pass field data" box and enter this in the field that opens: p={post_id} Voilà, instant redirect to the post just created.

In the Body field, check the "Create content template" box and create a template something like this, selecting your own merge tags from the dropdown of course (notice the jbutton again... geez Louise, they're all over the place!):

{Store Image:1:medium:left}
<br /><br />
<span class="subtitle">{Descriptive Subtitle or Tagline:5}</span>
<br /><br />
<span class="optimg">{Optional 2nd Image:7:medium:right}<br />{Optional 3rd Image:8:medium:right}</span><a class="jbutton green" href="{Your store's URL:4}">Visit this store</a>
<br /><br />
<span class="store-desc">{Store description:3}
</span>
<br /><br />

Finally, create a WP page on your site (or use an existing one) and insert the form shortcode. Navigate to that page, fill out your form and watch the magic unfold.

Hope you find use for this tut. If you need help with specifics, give me a shout!