Building a "Recently Bought" Plugin for WooCommerce - Part 2

This is the second part in the Building a “Recently Bought” Plugin for WooCommerce series, make sure you read the first part before diving into this one!

In Part 1, we set up the plugin folder, and added a basic constructor to the plugin. We will be picking up from that point, and adding some methods to our plugin to fetch the data we need for our “Recently Bought” popup.

It’s important to remember that we’re building this plugin using a PHP class, so reading part 1 is recommended to get you up to speed, or check out the GitHub repo to see it in action.

Enabling the Debug Log

It’s important at this stage (perhaps even before this stage, at WordPress installation) that we enable the debug log in WordPress. This will help us in 2 ways. Firstly, we can use to check if any errors are occurring, and rectify them. Secondly, we can use it to print useful information during the build process.

It’s fair to say that debug.log is always open for me while I’m developing. In Coda, it automatically updates when an error is logged.

Let’s turn it on. Open up your wp-config.php file. Have a look for the line define('WP_DEBUG', ****);. If it’s not there, we’ll be adding it in, if it is there, we will replace it.

Anywhere before /* That's all, stop editing! Happy blogging. */, add (or replace the existing declaration with):

This firstly enables the debugging in WordPress. We then tell it to enable the log; this is a file that will be created at wp-content/debug.log when a log message is created. Lastly, we tell it not to display errors on the frontend; this is just a preference for me, you can enable this if you like.

Now that’s enabled, there’s a handy snippet I use to print data to the log in a formatted manner. Whenever you want to print something to the log for debugging, use the following:

Where $some_var is the data you want to print in the log. The true parameter of print_r() means the result will be returned, rather than echoed/printed.

Planning The Required Methods (Functions)

At this stage, it’s useful to have a think about what methods the plugin will use. This will help us to prepare more for the structure of the plugin. As this is a fairly small plugin, I’ll be building it all in a single class. For larger plugins, you may want to consider using sub-classes, autoloaders, and the like; planning out at the beginning will help you to structure this data more effectively.

I believe these are the methods we’ll require:

  • Fetch recent product purchases
  • Fetch recent product purchases via Ajax and return JSON
  • Add styles to the frontend
  • Add scripts to the frontend
  • Add a settings framework

That’s not to say that we can’t deviate from this list, but it puts us in a good position to get started.

Fetch Recent Product Purchases

Let’s get to the nitty-gritty!

For the purpose of this plugin, I believe it would be better to fetch a single product from each order to display to the potential customers visiting the website. This should give us a bit more variance in the results, and if we choose to display the purchaser’s first name, it will show that there are multiple customers on the store.

When looking at the database tables provided by WooCommerce, we can see there is table called <code>wp_woocommerce_order_items</code> (<code>wp_</code> is your table prefix). Within this table, we have a list of every order item for all order. This includes line items and shipping.

Given the above information, I’d say our method needs to fetch line items, where the order ID is unique. This should get us 1 product from each order.

We’re going to add this method just after the initiate_hook() method in the main plugin class. As we’re developing within a class, we have a bit more freedom when it comes to naming our methods. It’s recommended that we use names that clearly describe what will happen when we use it. I also like to maintain some sort of consistency to what WordPress uses for function names, in that a function prefixed with get_ will “return” the data, rather than echo it.

There’s a few things going on here. We know we’re going to interact with the database, as a wp_query won’t cut it in this instance, so we’ve included the $wpdb global. We’ve also created a $products variable, which will store our product information. We then return that. If there are no products found, this method will just return the empty $products array.

Let’s get us some data!

I’ve done a couple of things here. You may notice I added a default of “5” for the $limit parameter. After that, we’ve done our line_item query, and then printed it to the log.

I’m using 2 $wpdb methods here, $wpdb->get_results() and $wpdb->prepare(). The $wpdb->get_results() method simply allows us to fetch multiple rows of data. We’re then using the $wpdb->prepare() method to prepare our query, and prevent SQL injections. $wpdb->prepare() works in a similar way to sprintf(), in terms of syntax, and WordPress will also validate the variables we pass into the function. As of WordPress 3.5, the prepare method requires at least 2 parameters.

So we want to run this now, and then check the debug log to see what data we get. Currently, of course, we haven’t told this function to run anywhere. For now, let’s add it to the initiate_hook() method.

This will now run on every page in the frontend. Let’s load the homepage and see what our debug log is saying.

Nice! It has gathered the last 5 purchased items, and the data that goes along with them.

One thing we didn’t do, was to make sure that it only gets one product per order ID. Also, I’ve decided that we should make a new method for this, to keep things tidy. Once we have our line items, we’ll also pass them into a method that formats the data and returns exactly the data we need for each product. Let’s add that now.

We’ve created a get_line_items() method, and moved the database query into that; see how much neater it looks now?

Within the get_line_items() method, we’ve added a GROUP BY order_id condition. This means any rows with the same order_id will be grouped, so only one product for each order will appear in our final results.

It’s possible to also say SELECT DISTINCT order_id, however, this will only return the order_id column data, which isn’t what we need.

Check it out! That’s exactly the result we were looking for.

Let’s think about this, then. We’ve got the last 5 items that were purchased from our store, but do we have all the information we require to show it on the frontend of the website? I don’t think we do. What do we need?

  • Product Name
  • Product Permalink
  • Product Image
  • Customer First Name
  • Customer Location

Our pop up will say something like this, alongside an image:

James Kemp from Rugby, UK, just purchased Woo Album #3

So the information we’ve listed above is the minimum information we require. Based on that assessment, it looks like we still need to get everything but the product name.

We have two useful IDs in our data above, order_item_id and order_id. We can use the order_item_id to get our product ID from the wp_woocommerce_order_itemmeta table. The product ID will then get us the permalink and image for the product. We can use the order_id to fetch our customer name and location.

It looks like we need more methods in our plugin. Let’s start with a method to get our product ID from an order item ID.

In case you hadn’t noticed, I like my method names to be very descriptive. Straight away it’s clear what get_product_id_by_order_item_id will do.

We’re using the $wpdb->get_var() method to get a single cell of data from the wp_woocommerce_order_itemmeta table, the product ID.

Let’s update get_recent_product_purchases to make it loop through the line items we gathered earlier, and print the product IDs to the error log.

We run it on the frontend, and the log days:

Perfect! A list of product IDs for our 5 recent orders. It just so happens that in my test data, four of those products are the same. What can I say, Woo Album #3 is a great album.

Let’s use this data to start building up a recent product to add to our $products array.

At this point, I decided to change the get_product_id_by_order_item_id method a bit. Instead of getting just the product ID, I want to get the actual product object. I changed the method name to get_product_by_order_item_id, and the method itself now looks like this:

We basically just use the product ID to create a product object. Now we can easily access the data we want for our $products array.

You can see we use our new order item ID method, get the product object, then use the object to pluck out only the information we require about the product, using the standard WooCommerce product methods.

You may notice that I use what’s called a “stopper”.

It’s much better to do this, than to wrap the whole results in an if statement. It keeps things much cleaner. I once read that the aim of a method or function is to get out of it as soon as possible; working in this way achieves that goal.

Now we just some information about the order. To keep things tidy, I’m going to do two things; move the code to get info about the product into its own method, and create another method to get info we need about the order.

The get_product_info() method looks like this:

And our new get_order_info() method looks like this:

The information we needed from the order is stored as post meta, which means we didn’t need to get the order object using the wc_get_order() function.

Now we have those two methods, let’s see how they look inside the get_recent_product_purchases() method.

You can see that if we didn’t get the product or order information we required, I have chosen to skip the product altogether; no point showing it with half the information.

We then use array_merge() to combine the product and order information into a single array, which we assign to the $products variable.

Once we’ve gathered all that data, we print it to the debug log. What do we get?

Ideal, we can work with this!

Wrap Up

We’ve done quite a lot in this post. We’re almost ready to start displaying this information on the frontend of our store. Keep an eye out for the next post, where we’ll start to do just that.

Don’t forget to check all of the code from today in the GitHub repo, where we’ll have a fully-functioning, open-source plugin by the end of the series.

I’ll look forward to your comments below.

1 Comment

  1. Natalie Latimer says:

    Is this ‘recently bought’ pop up plugin available for purchase yet?

Leave a Reply

Your email address will not be published. Required fields are marked *