Can I do something like this to add a capability after someone purchases a product in my child's function file? Please note, I'm using s2member and woocommerce, and I am a newbie.

add_action( 'cap_added', 'change_user_cap_with_purchase', 1 ); 
function change_user_cap_with_purchase ( $order_id ){
            $order = wc_get_order( $order_id );

            foreach( $order->get_items() as $item ) {
                // Product ID
                if ( $item['product_id'] == 999 ) {
                function add_cap_to_role() {
    $customer = get_role('customer');

1 Answer 1


First, you indicated you want to add a capability to a user of your WordPress site. (This is in contrast to adding a capability to a role, as well as being different from adding a role to a user. More about all that is here.) As you're new to this, I wanted to point that out.

Second, to the code. I don't know what your ordering process looks like so I can't advise as to what hook to use. WooCommerce offers a huge number of entry points into its processes. For the sake of argument, let's say that you want to add the capability when a user of your site completes payment for the order. In such a case, you may want to enter the WooCommerce process when the WC_Order->payment_complete() method is called. You could use the woocommerce_payment_complete action hook (and you already know how to use hooks).

add_action('woocommerce_payment_complete', 'bucktastic_adds_cap');
function bucktastic_adds_cap($order_id) { ... }

This hook passes the order number of a WC_Order that is used in the hook's callback function. We then have to use this order number to manipulate the order in question. So, let's grab the order object so we can manipulate the order (and you know how to do that as well).

$order = wc_get_order($order_id);

This could return FALSE, so we'll have to check that before continuing on in our script. But, let's say we get the order object. The next thing to do is to try to get the WordPress user of the customer. According to the docs, our WC_Order has a nice little function that will return the user of our site, the WP_User, who is associated with the order:

$user = $order->get_user();

Again, this function could return FALSE, so we'll have to check for that. Now that we have our user object, we can add a capability to that use. (You already know how to use the WP_User->add_cap() method, and you are suggesting that you want to add the cst11 capability to your website user.) Putting it all together ...

add_action('woocommerce_payment_complete', 'bucktastic_adds_cap');

function bucktastic_adds_cap($order_id) {
    // Grab the order, but do not continue if the order number is invalid
    $order = wc_get_order($order_id);
    if($order === FALSE) return;

    // Grab the user, but do not continue if no user could be found
    $user = $order->get_user();
    if($user === FALSE) return;

    // Add the capability to bucktastic's website user.

I do have some questions for you, because your code represents that you are asking for more help than what you state in your question.

1.) Why are you iterating over all the list items and checking the item number before adding the capability? Are you trying to only add the capability to the user if they purchase a specific item?

2.) Why are you redefining the function add_cap_to_role() to add the capability every time you iterate over an item of the order? (This will definitely throw an error. But it you are coding PHP, so you have a basic understanding of how to code and you already knew this.)

3.) Why are you requiring yourself to call a function to add the capability? (That is the purpose of the callback function, which you can use elsewhere aside from the hook, so to make another function to do the exact same thing is bad coding practice.)

4.) If you are adding a capability to an individual user account, why are you trying to manipulate the role on every purchase? (Please refer to my opening statement for some clarity as to why I'm asking this question.)

EDIT: Here's a link to some more possible help for you.

  • Hi, thank you so much for such a detailed answer. To answer most of your question(s), I didn't know, I was searching how to solve it and was guessing for most of it. I cannot thank you enough for providing documentation to show how to complete it properly and the solution. 1) Yes, I was trying to add the capability to the user after they purchased a specific item
    – bucktastic
    May 28, 2020 at 23:12
  • OK. Well, thank you for the response. I'm glad to be of aid. If you would be kind enough, @bucktastic, to mark this answer as the correct one, it would be appreciated.
    – Mort 1305
    May 29, 2020 at 2:50
  • Hi @Mort thanks again, just want to make sure I'm clear, because I am adding the cap after purchase, how can I include the product id to confirm that it was purchased?
    – bucktastic
    May 29, 2020 at 16:21
  • Your foreach statement checking the ['product_id'] of each item is how you do that. When you find the item in the iteration, then do something ... return without taking any further action, fire off a trigger, save a value, whatever your heart desires.
    – Mort 1305
    May 29, 2020 at 17:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.