Creating custom pages in woocommerce

what if you want to have a custom page in woocommerce? For example a page called abc under my-account

best way is to use shortcodes. Create a new page under my-account, ie my-account/abc and put in the shortcode [abc_shortcode]

then in functions.php

function abc_function( $atts ){
	wc_get_template( 'myaccount/abc.php' );
add_shortcode( 'abc_shortcode', 'abc_function' );

now you need to create the abc.php file which can contain anything

Allow different order status in woocommerce

sometimes it is necessary to add new order type, for example some of the items i sell requires installer confirmation. Thanks woocommerce, the hooks are easy to use. In your functions file:

// New order status - Waiting for Installer Response
function register_waiting_installer_order_status() {
  register_post_status( 'wc-waiting-installer', array(
    'label' => _x( 'Waiting for installer Response', 'Order status', 'woocommerce' ),
    'public' => false,
    'exclude_from_search' => false,
    'show_in_admin_all_list' => true,
    'show_in_admin_status_list' => true,
    'label_count' => _n_noop( 'Waiting for installer response <span class="count">(%s)</span>', 'Pre Order <span class="count">(%s)</span>', 'textdomain' )
  ) );
add_action( 'init', 'register_waiting_installer_order_status' );

function waiting_for_installer_response_order_status($o) {
	$o['wc-waiting-installer'] = _x( 'Waiting for installer response', 'Order status', 'woocommerce' );
	return $o;

add_filter( 'wc_order_statuses', 'waiting_for_installer_response_order_status' );

Language translation in wordpress (tips)

Its important to think of language translation when creating plugins, hence is important. Use __ or _e whenever possible.

I strongly recommend poedit for text translation. In poedit, open an existing language file and save it again under your locale but named differently eg woocommerce-zh_AU.po – see 2 files will be created, ie .mo and .po in the default plugin directory. The trick though is not to save them in the plugin directory or else it is possible that your files could be gone upon plugin updates. Where do you save it then? save it in /wp-content/languages/{plugin_name}/{translated_file}, in my example, it will be /wp-content/languages/woocommerce/woocommerce-zh_AU.po and

Next, define your new locale in wp-config.php

// how about some australian chinese
define ('WPLANG', 'zh_AU');

All done.

My experience with Magento, Woocommerce and other e-shop options


Magento has been a buzz word in the ecommerce industry for many years now. I worked with magento in my previous life and still get a lot of calls from many job agencies looking for magento developers today. The fact is that good magento developers are hard to find simply because having an in depth understanding of magento requires a bit of time. If you have good object oriented foundation, it  is not as complicated as many claimed. It was smooth sailing for me once I got the concept and the hang of it. The challenge for me was actually teaching the end user how to use it.

Magento was packed with features and was like out of the box. Most people only used probably 10% of what it had to offer. The large code base and number of objects also meant a strong requirement for hardware and server tweaks to get the desired performance. Caching helped but it was not enough. I was puzzled why most people opted for magento as their first choice when they wanted an e-shop. Perhaps this just showed how successful magento’s marketing was – they could brainwash the public into believing that magento was the best solution for everyone. I often warned people that unless they have lots (and I mean LOTS) of budget, magento should be the first thing they should strike from their list. Personally, I was not comfortable with the cost involved to get customisation in magento. You just need to look at the cost of some simple extensions to get a feel of what’s going on.

In conclusion, I was comfortable with the software but not comfortable with money making policy. My gut feeling was that they would face tougher competition from other ecommerce solutions as time went by (and I was right). Relunctantly, I filed a divorce with magento.

So go ahead with magento want a robust ecommerce solution and has too much money to spare.

Hosted solution

Most hosted solution such as shopify requires a monthly fee and is usually very user friendly. This can be a good option for people who requires little customisation and don’t want to host their own shopping cart. I never considered this as a good option for me because I always believed that personalisation and customisation was the key to improve client relationship. Hosted solution means limited customisation. The logic is simple, their software should be generic for everyone and they can’t break their software just to accomodate your requirements.

Woocommerce and Other Ecommerce Software

I have used other software over the years as well but came to like Woocommerce recently. Woocommerce offers the flexibility and robustness that an ecommerce shop should have. As it is open sourced (as with magento community edition), I had full control over the behaviour of the shop. There were enough hooks in the code to do what I want. I could also make it work with other wordpress plugins such as  membership management system, LMS, caching, seo…etc. The only thing I had to be careful was not to make the shop too bloated, ie by adding too much features into it, thereby affecting the performance.

I believe there are other good options out there and time will tell us when one stands out above the rest.

Woocommerce 2.x: Using your own assets js

Instead of hacking the js files under assets/js, its better to create one yourself. Say you want to modify assets/js/frontend/checkout.js for example, in your theme functions.php

 * use our own checkout js in the proper way
 * @return null
function use_custom_js() {
  global $woocommerce;
  // make sure its checkout page
  if (is_checkout()) {
    // create assets/js/frontend/ dir under your theme dir.
    wp_enqueue_script( 'wc-checkout-my', dirname(get_stylesheet_uri()).'/assets/js/frontend/checkout.js', array( 'jquery', 'woocommerce' ), $woocommerce->version, true );
add_action('wp_enqueue_scripts', 'use_custom_js');

Woocommerce 2.x: disable email notification upon order status update

Woocommerce 2.0 was a major upgrade. I had to relook at the email library to figure things out. To disable email notification upon order completion, add the following code to your functions.php

 * Remove order status notification upon completion. Feel free to remove other notification hooks here as well.
 * Good to customise the way you send email. Too many emails to a person in a short time might blacklist your email server.
 * @param  WC_Emails $wc_emails email class
 * @return null
function do_not_send_some_email_notifications(WC_Emails $wc_emails) {
  remove_action('woocommerce_order_status_completed_notification', array($wc_emails->emails['WC_Email_Customer_Completed_Order'], 'trigger'));
add_action('woocommerce_email', 'do_not_send_some_email_notifications');

Note that this code does not work in woocommerce 1.x


woocommerce 2.0: ajax refresh of mini cart

Things are alot harder now if you want to hid the mini cart if there are no items in the cart. If things doesn’t work out of the box in woocommerce 2.0, create your own mini cart widget.

1) duplicate the mini cart from plugins/woocommerce/classes/widgets/class-wc-widget-cart.php to your theme dir.

2) rename the widget class to something-else.php and change the class and function names accordingly.

3) In about line 62 of something-else.php, replace “echo $before_widget” with

echo preg_replace('/sidebar-widget/', 'sidebar-widget widget_shopping_cart', $before_widget);

4) in your theme’s function.php, register your newly created widget, eg

add_action('widgets_init', 'my_register_widgets');
function my_register_widgets() {

5) go into your admin panel and replace your mini cart widget with your newly created widget.

Conclusion: I still don’t like this hack because user still see the widget appearing first and hidden suddenly after the page is loaded. In the woocommerce 1.x, adding widget_shopping_cart class is the trick to get wooocommerce to refresh the cart when items are added to the cart. In woocommece 2.x, they added extra classes and div to get the ajax to work, there are also a lot more ugly javaascript in cart-fragments.js. I don’t think they should offload the job of hiding the widget to javascript.

Woocommerce: Best way to insert Javascript in template files

sometimes it is necessary to insert jquery in template files. Instead of just writing the script tag straight away, use woocommerce built-in capability.

Say I want to modify fancybox behaviour in the product page to not display the title upon popup, I add this snippet in the single-product/product-image.php for example.

jQuery("a.zoom, a.show_review_form").fancybox({
'titleShow' : false,
$code = ob_get_clean(); 

Note that the fancy code example used here is ver 1.3. There are newer version by the time you read this.

Woocommerce: Send Invoice Straight Away When Payment Successful

One good feature I really want is to send an invoice straight away when payment is successful. At the moment, customers receive an order completion notification email which I find it useless. To send an invoice, you have to login to wp-admin and click on the send invoice button.

We can add some custom code in functions.php in your theme folder to achieve this functionality

 * remove order status completed notification
 * @param  WC_Email $this woocommerce email class
 * @return null
function do_not_send_order_complete_notification($this) {
  remove_action('woocommerce_order_status_completed_notification', array($this,'customer_completed_order'));
  // you can add other stuff you want to do here...
add_action('woocommerce_email', 'do_not_send_order_complete_notification');

 * send invoice straight away if payment is successful
 * @param  string $order_id valid payment order id
 * @return null
function send_invoice_upon_payment_successful($order_id) {
  global $woocommerce;
  $order = new WC_Order($order_id);
  $mailer = $woocommerce->mailer();
  $mailer->customer_invoice( $order );
add_action('woocommerce_payment_complete', 'send_invoice_upon_payment_successful');

For woocommerce 2.x, the send_invoice_upon_payment_successful function still works, however do_not_send_order_complete_notification function doesn’t. See my 2.x update here