WooCommerce reviews + tutorials

Today’s post continues our series on building a WooCommerce extension. We started the series by discussing how to use filters to change your site content, and today’s post will be about actions.

Actions and filters make up the basic building blogs of extending WordPress plugins and themes, as they allow you to change or add code to WordPress, themes, or plugins. WooCommerce is no exception, and includes tons of hooks that you can use within your own plugins.

WooCommerce actions will let us add or remove code to the core plugin, and they’re a foundational piece in extending what WooCommerce can do on your site. You can add actions to add conversion scripts to your checkout, add information to your shop or product pages, add fields to orders, or use them to as triggers for events.

What is an action in WordPress?

The WordPress codex gives us a definition that may or may not be helpful:

In WordPress; an Action is a PHP function that is executed at specific points throughout the WordPress Core.

In basic English: If you think of your page loading like a stretch of open highway, an action is like an on-ramp. While your page is moving from point A (nothing loaded) to point B (page fully loaded) on this highway, there are certain places in the page that you can “merge in” and add your own code. An action provides the place for this to happen.

So how’s this different from a filter? Technically, it’s not. But we don’t want to blow your mind just yet 🙂 .

Filters are used to allow you to change a particular value (be it a variable, text, or something else). Think of filters as a way to replace data or content on the page. Actions don’t pass in a value to change or replace; they simply provide the opportunity to “hook” code in or add it at this particular moment in the page load. This lets you add or remove things on the page.

Identifying actions

Actions are created using the do_action function. If you see a do_action call in a plugin or theme, this provides an “on-ramp” for you to bring your code into the page at this point, which can add something of its own or influence any of the code that follows.

The most basic actions have this structure:

do_action( 'tag' );

The “tag” is the action name. This will allow you to use the action to add your own function into the page. However, actions can also pass in “arguments”. The argument works in a similar way to a variable for a filter: arguments provide information you can access in your code. For example, an action that gives me the WooCommerce product would allow me to access any information on that product within my own function (allowing me to, for example, only execute the code for particular products).

do_action( 'tag', $arg_1, $arg_2 );

Actions can have as many arguments as needed, which can be used by any code hooking into this action.

Using an action

To add your code into the page using one of these actions, you’ll use the add_action function. This will always have the following structure:

add_action( 'action_tag', 'my_function', priority);

This will not change, even if the action has arguments that have been / can be passed to your code.

You’ll add your code in via an action similar to this:

function my_function_does_stuff() {
    here is the code that does the magic;
}
add_action( 'the_woocommerce_action', 'my_function_does_stuff' );

If the action contained arguments that I need to use, I’d pass them into my function in the same way I do with a filter:

function my_order_changing_function( $order ) {
    some code to change the $order or add stuff to it;
}
add_action( 'woocommerce_order_special_action', 'my_order_changing_function' );

Example 1: Changing the Storefront Blog Layout

Let’s take a look at the core Storefront theme blog layout:

WooCommerce Storefront theme blog layout

I’m going to move the post meta to the bottom of the post instead of left-aligned, and display both full width instead. While this is a slightly long example, it’s a pretty easy one to understand because it uses simple actions.

Fortunately, Storefront is very easy to change, and all of the post structure is hooked in via the hooks.php file. This shows us that we can remove the action that adds post meta to the page.

It’s added via this code:

add_action( 'storefront_single_post', 'storefront_post_meta', 20 );

In order to remove (and then re-add it ourselves), we’ll need to remove this action in our custom plugin / code snippet:

remove_action( 'storefront_single_post', 'storefront_post_meta', 20 );

Note: You must keep the same priority when removing an action.

Now let’s talk about re-adding this, as we’ll use an action to do so. I was cued into the storefront_single_post_after action by viewing the hooks.php file above. We could re-add the post meta much later in the single post, but I’d like to use this action to re-add the post meta after the post and above the post navigation (next post / previous post links).

I see this code in the single.php template:

do_action( 'storefront_single_post_after' );

This tells me that I can add my post meta back using this action. I’ll structure my add_action call with this action name, and I’ll set a slightly higher than normal priority to ensure my post meta is added before the post navigation links:

add_action( 'storefront_single_post_after', 'storefront_post_meta', 9 );

I don’t need to write my own function here, as I’m using the existing storefront_post_meta function.

This moves my post meta to the bottom of the post instead of left-aligned (though we’ll need to tweak our CSS to finish up):

Storefront theme blog meta moved

Now here’s the reason I chose this theme 🙂 . We’ll need a final action to wrap this up.

You can try adding some CSS to adjust the widths here to finish our blog layout, but adding them into your child theme won’t work too well. The classes used on a single post are the same as those used in the blog archive, so we need to target them more specifically. They’re also nested the same way, so we can’t go a pure-CSS route. We’ll need to only add this CSS to single posts, but not to blog archives.

We can do that with some PHP, and there’s a very useful action that will let us add CSS and javascript to the site footer (allowing our CSS to be added last and overriding the default CSS): wp_print_footer_scripts.

We’ll use this action with our function to add our new blog post styles:

function sv_modify_storefront_blog_styles() {
    if ( is_singular( 'post' ) ) {
    
        ?><style>
            .hentry.type-post .entry-content { width: 100%; }
            .hentry { padding-bottom: 2em; margin-bottom: 2em; }
            .cat-links, .tags-links, .comments-link, .edit-link { display: inline-block; margin: 0 2em 1em 0; }
        </style><?php
        
    }
}
add_action( 'wp_print_footer_scripts', 'sv_modify_storefront_blog_styles' );

Now my blog transformation is complete.

WooCommerce Storefront theme modified blog

Example 2: Adding a Google Analytics conversion script

Now let’s take a look at an action that passes in an argument. We’ll start with the woocommerce_thankyou action. This action passes in the order id as an argument:

do_action( 'woocommerce_thankyou', $order->id );

You can use the order id for any code that hooks into this action (which really means you can get the entire order object from this id). This can be used to display a custom message if a product is present in the order, display a customized message using the customer name, or welcome back certain customers based on role (i.e., if you have subscribers or your own roles).

The most common example of this action in the wild (and the simplest for us to use at this time) is its use with conversion tracking. Let’s add a tracking script for a third-party service using a tracking pixel (this could be used for affiliate programs or Google Analytics).

Assume the tracking pixel looks like this:

<img src="https://tracking.com/sale?amount=<AMOUNT>&ordernum=<ORDER_NUMBER>" height="1" width="1" border="0" />

Let’s insert that into our page, adding the order amount and number as required.

function sv_tracking_script( $order_id ) {

    // Get the order from the id & the info we need
    $order = wc_get_order( $order_id );
    
    $order_number = $order->get_order_number();
    $order_total = $order->get_order_total();
    
    // Output the tracking pixel with our order info
    printf( '<img src="https://tracking.com/sale?amount=%s&ordernum=%s" height="1" width="1" border="0">', esc_url( $order_total ), esc_url( $order_number ) );
   
}
add_action( 'woocommerce_thankyou', 'sv_tracking_script' );

This will now be added on every “thank you” page that’s displayed in my shop, and will include the relevant order information.

More Examples

  • Our tutorial on adding information to product shop listings uses an action to add info about the products when viewed on shop pages. In this example, we add information like the SKU or shipping weight to the shop display.
  • We’ve discussed how to properly edit WooCommerce templates by using actions and filters instead of overriding them, and this has several examples of actions in use.
  • Here’s another example in which we remove actions hooked into a do_action call: Remove the product sorting dropdown.
  • Our SKU Generator Plugin is a fairly simple plugin, but it uses actions in a couple different ways: we use an action as a trigger to update product meta when a product is saved, and we hook into one to conditionally disable the SKU field.

Further Reading

Published by Beka Rice

Beka leads product direction for SkyVerge and technical documentation. She spends a lot of time on research and interviews, but likes to write so she has an excuse to spend more time jamming out to anything from The Clash to Lady Gaga.

7 Comments

  1. Thank you for your post, I was actually trying to move the post-meta when I found your article.
    As I am fairly new to this stuff, I am still wondering wether I can do this by overwriting the functions in my child theme, or if I have to write my own plugin to do this?

  2. Trying to add some text after a product short description, I came up with this but it is replacing the original short description.

    Is there a way to add the function after the short description without replacing?

    function show_shipping_price() {
    echo ‘Order within 3 hours 27 minutes 12 seconds to get it delivered for only £1‘;
    }
    add_filter( ‘woocommerce_short_description’, ‘show_shipping_price’ );

    • Hey Tom, that’s because the filter changes what you’re passing in; if you were to filter the short description, you’d have to add your text, then return the short description + your text. Instead, since you don’t want to modify the short description, an action would be better — you could use the woocommerce_single_product_summary action since the excerpt / short description is hooked in here (just use a priority after the excerpt).

  3. I found this helpful and used many times, but when using with another 3rd party pixel that rendered px as cfm, I ran into an error with the formatting via printf. Workaround for this scenario – sure many other ways.

    function sv_tracking_script( $order_id ) {

    // Get the order from the id & the info we need
    $order = wc_get_order( $order_id );

    $order_number = $order->get_order_number();
    $order_total = $order->get_order_total();

    // Output the tracking pixel with our order info
    ?>
    <img src="https://tracking.com/sale.cfm?amount=” height=”1″ width=”1″ border=”0″>
    <?php
    }
    add_action( 'woocommerce_thankyou', 'sv_tracking_script' );

  4. Thank You very much for this.
    I’ve problems with “Example 1: Changing the Storefront Blog Layout”
    I don’t understand where to add the code. I’m using a child theme. Do I put the codes in the functions.php?
    That may sounds stupit but I’m working with hooks for the first time and I’m not familiar with that.

  5. Hi Beka,

    I have requirement of getting the user input price on the checkout and passing the same price to the product price on checkout only , can you please let me know how can i achieve this.

    Note: I have only one product at a time in the checkout

    Thanks

  6. Hi Beka,

    I tried to move the “Posted On” to the Post Meta.
    I managed this, but am pretty sure there is an simpler way, please have a look:
    I copied the function storefront_post_meta from the storefront-template-function.php and pasted it to my child theme’s function.php.
    I then copied the storefront_posted_on function’s content 9 also take from storefront-template-function.php and pasted it inside the storefront_post_meta function.

    This is my code:
    https://gist.github.com/schalkjoubert/642c1f7ba721886ee9762079b63e762b

    Thank you very much.

Hmm, looks like this article is quite old! Its content may be outdated, so comments are now closed.