WooCommerce reviews + tutorials

I plan to put together a mini series covering the basics of properly planning, engineering, launching and maintaining a WooCommerce shop. In the future as I write additional articles I will link them together, for now this first article will cover the basics of creating a custom plugin for your WooCommerce site, and provide you with a plugin skeleton to download and use as a starting point. This article assumes a familiarity with basic WordPress plugin development, and expands upon the WooCommerce doc article on creating a plugin. So, lets get going!

Why a Custom Plugin?

WooCommerce is a fabulous ecommerce solution, but creating a website or shop is a very personal endeavor, and you are likely to want to change some functionality or behavior of the stock WooCommerce plugin. Our natural tendency is to look for the simple solutions, and therefore we can be drawn to editing the core files. Resist this base urge! Repeat after me: “I will not modify the core files.” Fortunately, though not as flexible as Magento, WooCommerce provides a lot of action hooks, filters, template files and “template functions” to allow for customizations. Writing a plugin allows us to cleanly separate and keep track of our custom code, and renders WooCommerce upgrades a relatively painless process.

What is an action?
An action in WordPress allows you to execute code triggered at a specific point in the page response process, for instance upon displaying a comment.
What is a filter?
Similar conceptually to an action, filters allow you to modify data at specific points in the WordPress page response process, for instance removing profanity from a comment.
What is a template?
A template is a file that contains a mix of HTML and PHP code, and renders a page, a part of a page, or an email. Templates can be overriden by creating a file of the same name in a special location within your theme or child theme.
What is a template function?
A “template function” is a function that begins with if ( ! function_exists( 'function_name' ) {… If your plugin defines this function first it will be called in place of the default function and allow you to override its behavior with your own.

Writing a custom plugin largely allows you to alter the functionality and behavior of WooCommerce; to customize the look and feel the preferred method is to create a custom child theme. I won’t cover that process in this article series as it is already described well in the WordPress codex and there isn’t much WooCommerce-specific to add. The exception is perhaps the way that you override WooCommerce template files, which I wrote about in another article.

The Plugin Skeleton

I prefer to name my WooCommerce custom plugin woocommerce-company-name, so if your company is Acme, inc, you might use woocommerce-acme. Although not strictly necessary with a self-authored plugin, it’s good practice to check if WooCommerce is active, and also perform a check to ensure a class with the same name as your plugin doesn’t already exist:

if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
  if ( ! class_exists( 'WC_Acme' ) ) {

Next, it’s again good practice though not necessary, to load any translated strings for the plugin. Doing so allows you to use the various translate functions such as __( 'Some text', 'wc_acme' ) and easily provide translation files at some future date.

    load_plugin_textdomain( 'wc_acme', false, dirname( plugin_basename( __FILE__ ) ) . '/' );

I prefer to define the bulk of my plugin functions within a class, which effectively scopes the functions you write and keeps you from having to worry about function name clashes with all the other WordPress core and plugin functions. There are a few commonly used lifecycle action hooks which will be included in our skeleton plugin class. Finally, the plugin class will be instantiated, assuming that WooCommerce is active, and the class name isn’t already taken.

    class WC_Acme {

      public function __construct() {
        // called just before the woocommerce template functions are included
        add_action( 'init', array( $this, 'include_template_functions' ), 20 );

        // called only after woocommerce has finished loading
        add_action( 'woocommerce_init', array( $this, 'woocommerce_loaded' ) );

        // called after all plugins have loaded
        add_action( 'plugins_loaded', array( $this, 'plugins_loaded' ) );

        // indicates we are running the admin
        if ( is_admin() ) {
          // ...
        }

        // indicates we are being served over ssl
        if ( is_ssl() ) {
          // ...
        }

        // take care of anything else that needs to be done immediately upon plugin instantiation, here in the constructor
      }

      /**
       * Override any of the template functions from woocommerce/woocommerce-template.php
       * with our own template functions file
       */
      public function include_template_functions() {
        include( 'woocommerce-template.php' );
      }

      /**
       * Take care of anything that needs woocommerce to be loaded.
       * For instance, if you need access to the $woocommerce global
       */
      public function woocommerce_loaded() {
        // ...
      }

      /**
       * Take care of anything that needs all plugins to be loaded
       */
      public function plugins_loaded() {
        // ...
      }
    }

    // finally instantiate our plugin class and add it to the set of globals

    $GLOBALS['wc_acme'] = new WC_Acme();

Wrapping Up

If you were already familiar with WordPress/WooCommerce development there probably wasn’t much new for you here, but hopefully if you’re new to the game then the above explanations and techniques will prove helpful in getting you started. Either way, the best way to learn the multitude of WooCommerce actions and filters available for customization is to browse the source code. Also remember that in addition to hooking into actions/filters and adding functionality, you can just as easily unhook existing actions/filters to remove plugin behavior, or change it wholesale. The trick is to perform the remove_action()/remove_filter() calls after the target action is hooked to (for instance within our woocommerce_loaded() function above), and to always remember to provide all the arguments to the remove functions that were passed in the add functions, optional parameters and all.

Download the example plugin from the article: WooCommerce Acme Demo Plugin

Published by Justin Stern

Justin is one of our co-founders, and is our resident overengineer. He likes to write developer tutorials and make black magic happen in our plugins. He thinks that writing code is a lot easier than writing words.

27 Comments

  1. Hi Justin, what are the pros and cons of using a plugin vs inserting the code in functions.php?

    Simply put — I have accumulated a bunch of code snippets here and there (over the past 2 x months!!! lol), they are all inside my functions.php (most are commented out for now — although I tested them…), and I am not sure whether it’s a good thing or not to have a “big” functions.php file?

    When my site is finally up and running, I will probably be using most of the codes which are commented out ATM.

    Thanks,

    Louis

    • Great question. I don’t think there’s really any huge advantage one way or the other to putting your custom code in functions.php vs. a custom site plugin, in my opinion it comes down to more a matter of preference and style. Nor is there any real danger of having too “big” of a functions.php file. Personally I like the custom site plugin approach because as a developer it makes it easier for me to package up code for clients. I also just prefer it from a code organizational standpoint. I guess another advantage to having the code in a custom site plugin would be for changes which are not theme-specific, that way if you ever changed themes you don’t have to remember to copy over your functions.php modifications. Of course if your changes are theme-specific, then that’s an argument to keeping them in that theme’s functions.php. So there you have it, no real right or wrong answer in my opinion, just however you prefer working.

  2. Thanks justin. I understand, in short plugins are useful as they allow you switch themes without re-tweaking the functions file, and you can re-use them on different projects/websites etc… unless they are themes specific of course.

    I have another question if you don’t mind; say I have got various working codes in my functions file, is it as easy as copying the codes over to new files and sticking it to the plugins folder, or is it a bit more involved? And if so, is it possible to have a single plugin with various/completely different functions inside, again — straight forward or more involved? Thanks again.

    • Well, it’s a little more involved to put together a plugin, as you can tell from my article above, though I do provide that example plugin to use as a skeleton or starting point. Still it is a bit more complicated than adding a bunch of lines to your functions.php. You can certainly have a plugin that does all manner of things with various/completely different functions. The one thing that they all have in common is that they modify your site, hence I refer to it as a Custom Site Plugin. Hope this helps

      • Hi Justin, thanks for the clarification. I agree, seeing your example — I can tell it’s a bit more involved. Well, for now I guess I’ll use the functions.php it makes life easier 😛

  3. Thanks justin for your article. I can write normal wordpress plugins and working with woocommerce since last year. But didn’t need any plugin. Because i did some minor change by Templating. But i need custom extension now for some complicated issue. And i can’t figure it out, from where i will start. Can you help me providing some guideline. The problem is -> There will be two option to select a product to add to cart 1)without company name 2)with company name. And when anyone select with company name, a text field will come and have to put the ‘company name’ in that box. The main problem is i can’t figure, how can i make an extra field at shop page for my text. Waiting for your reply. Thanks in advanced 😉

  4. Hello Justin I’m new to WordPress and WooCommerce.

    I have read other tutorials and yours is very helpful, but there are some things which I’m still confused about:

    1. Is it necessary to create a post type for a custom plugin?

    2. The WooCommerce site has a tutorial for creating a custom shipping method. The sample code for using the WooCommerce settings API doesn’t state if all of the code snippets go in a single file or if each snippet should go to a specific file.

    My goal is to create a custom shipping method that if selected in the shopping cart editing page, makes a descriptive text display right below the shipping method drop-down box. I sort of get the custom shipping part but what is the standard practice for making specific html display depending on what the user selects as the shipping method? Does it involve modifying the theme?

    Any help would be greatly appreciated.

    Thanks in advance.

    • Hey Rahi, 1. It is not necessary to create a post type with a custom plugin, a post type would only be required if you have some data that you want to store that lends itself to being stored in the post datastructure. A classic example is creating a “product” post type to create an ecommerce platform. 2. This is largely a matter of personal preference. You can put all the code into one file or break it up into multiple, just depending on how you want to organize your project. If you break it up into multiples you must of course include all the other files within the main plugin file.

      To display something based upon the shipping method you’d have to look into the available actions/filters in that area, and if none exist that will do the job, you’d have to inject a bit of javascript into the page to do so. That sort of thing starts to get a bit tricky, depending on how much experience you have with PHP and WordPress. best of luck!

  5. This is a great beginner article. Is there any way you could do a post using the same skeleton, but have it do something to the site?

    I am doing my best right now to hook into these filters and actions for woocommerce, and I’ve done something in my functions.php to modify the shipping options based on what products are in the cart, but it would be awesome to move this to a plugin. I just don’t know where in the skeleton above I would put the code.

    Right now I am hooking into the woocommerce_available_shipping_methods filter, and creating a function off of it to modify the flat_rate and free_shipping variables. Where would I put that in the skeleton above?

    Thanks! and great article!

    • Hey Aaron, this should be pretty easy for you, you just want to put your add_filter('woocommerce_available_shipping_methods', array( $this, 'available_shipping_methods' ) ); right into the __construct() method of the plugin, and then make sure you have another function within the class named in this case available_shipping_methods(), or whatever you prefer to call it.

      • Sounds good. I will give that a try. I try to study other plugin code for woocommerce, and there’s just so much stuff in there, and included files, I really can’t tell what functions (if any) I really need to drag into a custom plugin. Do I need to extend woocommerce classes, etc…

  6. Hi justin,

    I have a question, i want to create a new type of product that show only a couple fields from woocommerce and other custom that i will create.

    Is it possible to create a custom dashboat view in a custom post type? I saw this in wootickets where you can insert a event(CPT) ticket from the events page.

    I plan on doing this for a travel agency where you can insert custom variations and extra information.

    Thanks..

  7. Hi Justin,

    Great article! Just wondering if everything still holds true for creating a custom plugin/extension for WooCommerce 2.0?

  8. Hello
    i am working on woocommerce plugin i wants to use function which is get_available_variations() in my custom plugin.
    please guide me
    Thankyou

    • That function returns an array of available variations data; it’s not really possible to discuss using it in a general sense, it all depends on what you’re trying to do, and will definitely require a level of programming ability

  9. I want to customize my woo-commerce plugin at add-to-cart functionality.

  10. Hello Justin,

    If I want to do something everytime an order is paid by customer. What do i do?
    Looking forward to hear from you.

    Best regards,
    Phillip Stemann

    • Hey Phillip, this requires some PHP/WordPress programming knowledge, but basically your best bet would be to hook into the woocommerce_payment_complete action, which sends the id of the order which was just paid. Hope this gets you started in the right direction!

  11. Hi Justin,

    Great post. I was wondering how difficult it would be to customize Woocommerce so that the products are appointments? I’ll also like multiple vendors to be able to post their own available times. This plugin http://shop.mgates.me/shop/wc-marketing/wc-product-vendor/ seems like what I want for multiple vendors and payment, but it doesn’t have an appointment functionality. Can you point me to any resources to add that capability?

    Thanks!

  12. Hi Justin, I was wondering how I’d go about modifying the payment method, to simply display some text with payment instructions rather than using paypal by default

  13. Hi, Justin

    The woocommerce_init action: is this the right one to use?

    I ask because many WC functions like is_shop() aren’t available until the WordPress wp action fires.

    • `woocommerce_init` is a good general-purpose action for code that needs to have access to most WC functions. For any template-related functions (like `is_shop()` or `is_product()`) you’ll want to hook into the `wp` action like you mentioned 🙂

  14. Hi, what is the action hook to use if i need some custom functionality after the product is added or deleted by the admin.

    Many thanks.

Comments are closed.