Building a classified ads directory with WordPress

When talking about what else WordPress could be used for except blogs, classified ads directories come up high on the list.  It’s one of those examples which illustrate the scenario nicely and doesn’t require a lot of work.

So, how can WordPress be used to build a classified ads directory?  Here is a list of a few ways you might go:

  1. Buy and install ClassiPress – a theme and plugin to do just that – build a classified ads directory.  This is probably the fastest, cheapest, and simplest option.  If you want one of those directories up and running within a few minutes, that’s the way to go.
  2. Install wp-classified plugin and tweak it until you are happy.  You’ll pay with your time, not your money.  And you won’t have to start from scratch.
  3. Build your own, from scratch.  This is suitable for those who want to have 100% understanding of how their directory works, and for those who want learn how WordPress can be customized beyond blogging.

In this post, I’ll focus only on the third option.

So, before we start building something, it’s good to get a better idea of what is that we are actually about to build.  Here are the things that I think a reasonable classified ads directory should have:

  1. Multiple categories for ads (cars, electronics, books, etc.).  Ideally, each ad should be in one category only, but we are not going to force that limitation for now.
  2. Search.  Categories are good, but we should be able to just type whatever is that we are looking for and find it.
  3. User submitted ads, with some moderation.  SPAM bots will probably be all over this, so we need some protection, without making it too hard for legitimate users.
  4. Notification system for new ads – RSS feeds, email notifications, Twitter updates, or any combination of these.
  5. Content rich, template ads.  So that we can have pictures associated with ads, as well as custom data.  For example, for cars we could ask about manual or automatic gearbox, etc.

There are of course a gadzillion of other things that we can add, but the point is to demonstrate WordPress-based problem solving within realistic scenarios, not to build a perfect classified ads directory.

Now that we know what we want (not to be confused with what women want), how can we build it?  From the top of my head, I can suggest three possible directions:

  1. Completely customized solution within WordPress.  That would probably be packaged as a plugin, which creates and populates its own database tables, has its own administration interface, and such.
  2. Re-use WordPress comments.
  3. Re-use WordPress posts and post by email functionality.

Option 1 will require us to build a lot of stuff from scratch.  The good things about this approach is that we can have a high degree of fine-tuning. For example, in such a system, we’d have custom tables to hold our ads, with very specific fields that we want.  And we can have really specific administration interface.  On the WordPress side, we’d probably reuse user permissions, friendly URLs, and plugin architecture (installation, upgrade, initialization, options, etc).  The downside of this approach is the same – a lot of development.  It will take some time to write all that code and fit it into WordPress.  Then debug and maintain it.  And then solve all the problems that will arise, like SPAM control and moderation of ads.  While it can work, it’s not what I’d go for.

Option 2 is based around WordPress comments.  We can create an empty post for each ad category that we want (cars, books, electronics, etc).  Then a customized comment form could be used to submit ads to the specific category.  The pros of this approach are: very little coding to be done (most of it is already there), moderation system is built-in and SPAM control can be handled by plugins like Akismet.  Additional benefits include Gravatar support, and threads, which could be used as comments to ads (first level / parent comments).  Also the RSS feeds are there.  And even search problem could be solved with one of those enhanced search plugins.  Rich content is also not a big problem with advanced editor plugins.  In the cons, I’d specify flexibility.  Since there are only so many things that you can do with comments.

Option 3 is based on WordPress posts.  We’ll have regular categories like in the blog, and each ad would be a separate post.  We can extend the post_type field in wp_posts table with pretty much anything we want, which would give us the control of custom fields for different ad types (fields for cars are different from fields for electronics).  Search is ready.  As are RSS feeds.  And integration with notification emails, Twitter updates, etc. is trivial.  Just install any of the plugins that broadcasts your posts and you are done.  Figuring out the user submission and moderation processes might take some time, but with posts being more flexible (IMHO) than comments, it seems There Is More Than One Way To Do It.  That’s a Perl motto if you didn’t know.

One of the ways to submit user content with SPAM filtering and pre-moderation might be via post by email functionality available in WordPress.  The idea is the following.  We create a new POP3 mailbox for those incoming ads.  Ideally, we should probably open Gmail account, as it both supports POP3 and has excellent SPAM filtering.  Once the POP3 account is working, we can configure WordPress post by email options.  We’d want a separate category for these incoming messages (“new”, “incoming”, “to-moderate”) or something like that. Not one of the categories that we feature on the front page (“cars”, “books”, “electronics”, etc).   Once this is done, we can install one of those Contact Form plugins which helps to configure a form for site visitors and sends submitted results by email.  In the destination mailbox we need to put the POP3 mailbox.  Additional bonus: most of the Contact Form plugins have some sort of SPAM filtering capabilities as well.  So we’d be protected both by the form plugin and POP3 SPAM filtering system.

As you might have guessed, Option 3 is my favourite direction.  It seems more natural to handle ads as posts than anything else.  And if I were to build a classifieds ads directory, that would probably be the approach that I’d take.

Let’s see if I can pull it off.  So, the implementation plan so far is:

  1. Create a new POP3 mailbox with some SPAM filtering (Gmail to the rescue).
  2. Install fresh WordPress (not required, but since I don’t have anything else to play with I’ll go for that).
  3. Configure posting by email in WordPress via the POP3 account created in step 1.
  4. Install some Contact Form plugin that can send submitted results to email. Set it to use the POP3 account from step 1.
  5. Create a page with the contact form.
  6. Create categories for ads (cars, books, electronics).
  7. Create a custom theme (very basic, for the sake of the example) to display ads from difference categories, and show the search form as well.
  8. Submit some ads via contact form in page created by step 5.
  9. Moderate the incoming ads from step 8 to approve some and decline the others.
  10. Summarize the experience, provide useful links, ???, PROFIT.

Let’s go!

Step 1.

Creating a new Gmail mailbox is as easy as installing WordPress these days.  Make sure that you follow WordPress recommendation (from the Post via e-mail section of the Writing administration screen):

To post to WordPress by e-mail you must set up a secret e-mail account with POP3 access. Any mail received at this address will be posted, so it’s a good idea to keep this address very secret.

to Once registered, you need to go to Settings, Fowarding and POP/IMAP, and in POP Downloads section Enable POP for all mail.

Step 2.

Installing a new WordPress is trivial.  Download the archive, unzip into the folder where web server can see it, create a new MySQL database, copy wp-config-sample.php file to wp-config.php and update it with the location and credentials of that database.  Now visit the the URL of your new WordPress site and finish the installation by specifying the blog title and admin email, and changing random password of administrator account to something that you can actually remember.  Done.

Step 3. Configuration of POP3 access in WordPress turned out to be a bit trickier than I expected, but I managed to get through anyway.  By default, WordPress suggests the plain-text POP3 connection (port 110).  However, Gmail insists on encrypted connection (port 995), which is better, because it is more secure. Just changing the port in configuration didn’t help.  But once I stumbled upon this thread in WordPress Ideas, everything started to fall into place.  My problem was that in Mail Server field I had pop.gmail.com .  When I changed that to ssl://pop.gmail.com (with port still set to 995), it worked liked a charm.

One thing that you would probably be confused about after setting up the above is how to actually tell WordPress to import messages from the POP3 account.  It doesn’t do it automatically.  To force it, you’ll need to visit yourdomain.com/path/to/your/wordpress/wp-mail.php .  And since we are all about automation, I suggest that you tell your scheduler to fetch this page automatically every few minutes (“/usr/bin/wget -O /dev/null -q URL“, or something like that).

I also recommend to create a separate category, like “Moderatorial”, where all posts from email will go.  When doing approvals, we’ll remove them from this category and place in the appropriate ad category.

If you did everything right and all stars aligned properly, your WordPress will now import emails from that POP3 account into your blog.  Try sending a few emails to that secret account of yours and see.  Also, try sending emails from several different emails there.  You might notice that something cool is happening.  Looking through wp-mail.php source code, I noticed that WordPress does the following check:

  • get email sender’s email address from From: or Reply-To: field
  • clean-up that email address
  • check if there is a registered WordPress user with such email (in your database, not in WordPress.com)
  • if found, check if this user has permission to publish posts

If user was not found or if user was found but he doesn’t have permission to publish posts, then the post status will be “pending“.  If the user was found and he can publish posts, then the status will be “publish“.  That means that for approved users, posts will get get published automatically, while for everyone else you’ll need to manually approve posts.  And also, if the user was found by the email address, then the post author will be set to this user.  I think this is just awesome!

Step 4.

Now for the contact form plugin.  There are a few to choose from.  Keeping in mind that we are building a classified ads directory, which should have at least some flexibility, I went for the Contact Form 7 plugin.  It has supports multiple contact forms, and has a nice interface for building those forms (field types, captions, required / not required, email templates, destination email addresses, etc).  It even supports file uploads and limits of file sizes on those fields.  That’s pretty cool too.  For every form you build, it gives your a short tag to put into the page or post to have the form rendered.  Make sure you specify the destination email to be the one WordPress checks via POP3, because by default the destination email is of the site administrator.  Or currently logged in user.

Step 5.

Creating pages is a routine task.  For every ad category that we will have, we can create a separate contact form.  For each contact form we can create a separate page, where the short tag for that specific form is pasted.  Takes about 4 seconds per page.  Done.

Step 6.

Create categories for ads.  That’s so simple that the only reason I put it here is just not to forget.  If you don’t know how to do it for some reason, go to your WordPress administration and look under Posts, Categories.

Step 7.

Create a custom theme.  That’s where things start to get interesting.  Most of the themes that you’ll find in the wild are for blogs.  And we need a classified ads directory.   Those look different.  If you don’t know how, just imagine a page with a large search box in the top-middle of the page, and then a few vertical blocks aligned horizontally (yeah, I know it sounds confusing), with each block featuring a few ads from a specific category.  Here is for example, a partial screenshot of a popular Craigslist directory:

craigslist.co.uk

craigslist.co.uk

The goal of this post is to illustrate the process, so let’s follow the simplistic path.  We’ll need to build a custom theme with a somewhat non-traditional front page.  The rest of the pages – category, archive, and search result listings – will look as on the usual blog.  The front page however will have a search box and a few posts from each category that we have.

The best way to assess what we will need to change and how much work that will be, is to look at WordPress template hierarchy.  It seems that we can dump everything into two files only: style.css and index.php .  Here is what I got after a few minutes of poking around.

/*
 * Theme Name: WP Classified Ads
 * Author: Leonid Mamchenkov
 */

body { background-color: #ffffff; width: 80%; margin: auto;}

#searchform {
        width: 400px;
        background-color: #eeeeee;
        padding: 20px;
        text-align: center;
        margin: auto;
        border: 3px double #000000;
}

#searchform input {
        border: 1px solid #000000;
}

h1, h3 {
        text-align: center;
}

/* front page box for each category */
.cat-box {
        float: left;
        display: inline;
        padding: 10px;
        margin: 5px;
        border: 1px solid #000000;
        width: 220px;
}
<html>
    <head>
        <?php wp_head(); ?>
        <title><?php wp_title(); ?> <?php bloginfo('name'); ?></title>
        <link rel="stylesheet" href="<?php bloginfo('stylesheet_url'); ?>" type="text/css" media="screen" />
    </head>
    <body>
        <h1><a href="<?php get_option('home'); ?>"><?php bloginfo('name') ?></a></h1>
        <?php
            // Always show the search form
            get_search_form();

            // Display front page
            if (is_home()) {
                $ads_limit = 5; // how many ads from each category to show
                echo "<h3>we are on the front page</h3>";

                $categories = (array) get_categories();
                foreach ($categories as $category) {

                    $cat_url = get_category_link($category->cat_ID);

                    query_posts('category_name=' . $category->slug . '&showposts='. $ads_limit);
                    // only show category box if there are any ads in it
                    if (have_posts()) {
                        ?>
                        <div class="cat-box">
                            <h3><a href="<?php echo $cat_url; ?>"><?php echo $category->name ?></a></h3>
                            <ul>
                            <?php
                                while (have_posts()) {
                                    the_post();
                                    ?><li><a href="<?php echo the_permalink(); ?>"><?php the_title(); ?></a></li><?php
                                }
                            ?>
                            </ul>
                        </div>
                        <?php
                    }
                }
            }
            // Dispay standalones
            elseif (is_single() || is_page()) {
                if (have_posts()) {
                    while (have_posts()) {
                        the_post();
                        ?><h3><a href="<?php echo the_permalink(); ?>"><?php the_title(); ?></a></h3><?php the_content() ?><br /><?php
                    }
                }
                else {
                    echo "<h3>you are in a very weird place</h3>";
                }

            }
            // Display post collections
            else {
                if (is_search()) {
                    echo "<h3>search results</h3>";
                }
                elseif (is_category()) {
                    echo "<h3>category results</h3>";
                }
                else {
                    echo "<h3>we are somewhere else</h3>";
                }
                // show relevant posts
                if (have_posts()) {
                    echo "<ul>";
                    while (have_posts()) {
                        echo "<li>";
                        the_post();

                        ?><a href="<?php echo the_permalink(); ?>"><?php the_title(); ?></a><?php
                        echo "</li>";
                    }
                    echo "</ul>";
                }
                else {
                   echo "<h3>nothing here to display</h3>";
                }
            }
        ?>
        <?php wp_footer(); ?>
    </body>
</html>

And here is the screenshot of how it looks.

classified ads directory

Of course, the styling and content needs some work, but that’s a start.  Now, let’s recap those requirements we had for the classified ads:

  1. Multiple categories for ads.  Check.
  2. Search. Check.
  3. User submitted ads, with some moderation. Check.  If you don’t like the fact that “Moderatorial” category is displayed, you can easily exclude it.  I left purely for demonstration and lack of any real content.
  4. Notification system for new ads. Check.  All built-in WordPress RSS feeds are still working. All posts and category feeds are of the most importance here. Plus you can have any of the usual plugins for post broadcasts via email, Twitter, Facebook, etc.
  5. Content rich template ads. No check.  WordPress email posting mechanism by default cleans HTML out of incoming emails.  There is a workaround, however we won’t go into it at this time.  The workaround involves the custom email posting plugin.  This should work, because WordPress makes raw content of the email available to plugins (via a hook).  And as I said, it should work, but I haven’t tried it myself yet.

So, with just a few minutes of work (OK, close to an hour), we have ourselves a rather flexible and robust classified ads directory.  We can grow it with more customizations in-house and with more WordPress plugins.  And we can control every tiny bit of display via custom themes.  And I think that’s pretty cool.

Now, what do you have to say?