php - Get the user ID on woocommerce_order_status_completed hook ← (PHP)

I write function:

add_action( 'woocommerce_order_status_completed', 'order_completed');

function order_completed($order_id) {

    $user_id = $order->get_user_id(); // or $order->get_customer_id();
    $order = wc_get_order( $order_id );
    $items = $order->get_items();
    
    foreach ( $items as $item ) {
        $product_name = $item->get_name();          
    }  

    switch ($product_name) {
        case 'FREE':        
            update_user_meta($user_id, 'ads-available',  get_user_meta( $user_id, 'ads-available', true ) +1 );
            break;
      
        case 'VIP':
            update_user_meta($user_id, 'ads-available',  get_user_meta( $user_id, 'ads-available', true ) +3 );
            update_user_meta($user_id, 'karusel',  get_user_meta( $user_id, 'karusel', true ) +1 );
            break;  
    }

    
}

And when I change status order from dashboard I have error:

Type error: E_ERROR in row 102 file /var/www/ /data/www/web-design.com/wp-content/plugins/functions.php. Uncaught Error: Call to a member function get_user_id() on null in /var/www/ /data/www/web-design.com/wp-content/plugins/functions.php:102 Stack trace: #0 /var/www/ /data/www/web-design.com/wp-includes/class-wp-hook.php(294): order_completed(862) #1 /var/www/ /data/www/web-design.com/wp-includes/class-wp-hook.php(316): WP_Hook->apply_filters('', Array) #2 /var/www/ /data/www/web-design.com/wp-includes/plugin.php(484): WP_Hook->do_action(Array) #3 /var/www/ /data/www/web-design.com/wp-content/plugins/woocommerce/includes/class-wc-order.php(363): do_action('woocommerce_ord...', 862, Object(Automattic\WooCommerce\Admin\Overrides\Order)) #4 /var/www/ /data/www/web-design.com/wp-content/plugins/woocommerce/includes/class-wc-order.php(221): WC_Order->status_transition() #5 /var/www/ /data/www/web-design.com/wp-content/plugins/woocommerce/includes/class-wc-order.php(333): WC_Order->save() #6 /var/www/ /data/www/web-design.com/wp-content/plugins/woocommerce/includes/admin/list-tables/class-wc-admin-li

row 102 it is - $user_id = $order->get_user_id(); // or $order->get_customer_id();

Answer



Solution:

You can use the _customer_user meta key. to get user id.

add_action( 'woocommerce_order_status_completed', 'order_completed' );
function order_completed( $order_id ) {

    $user_id = get_post_meta($order_id, '_customer_user', true);
    
    $order = wc_get_order( $order_id );
    $items = $order->get_items();
    
    foreach ( $items as $item ) {
        $product_name = $item->get_name();          
    }  

    switch ($product_name) {
        case 'FREE':        
          update_user_meta($user_id, 'ads-available',  get_user_meta( $user_id, 'ads-available', true ) +1 );
          break;
          
        case 'VIP':
          update_user_meta($user_id, 'ads-available',  get_user_meta( $user_id, 'ads-available', true ) +3 );
          update_user_meta($user_id, 'karusel',  get_user_meta( $user_id, 'karusel', true ) +1 );
          break;    
    }

}

OR you need to get order object first then you can use $order->get_user_id()

add_action( 'woocommerce_order_status_completed', 'order_completed' );
function order_completed( $order_id ) {

    $order = wc_get_order( $order_id );
    $user_id = $order->get_user_id(); // or $order->get_customer_id();
            
    $order = wc_get_order( $order_id );
    $items = $order->get_items();
    
    foreach ( $items as $item ) {
        $product_name = $item->get_name();          
    }  

    switch ($product_name) {
        case 'FREE':        
          update_user_meta($user_id, 'ads-available',  get_user_meta( $user_id, 'ads-available', true ) +1 );
          break;
          
        case 'VIP':
          update_user_meta($user_id, 'ads-available',  get_user_meta( $user_id, 'ads-available', true ) +3 );
          update_user_meta($user_id, 'karusel',  get_user_meta( $user_id, 'karusel', true ) +1 );
          break;    
    }

}

Answer



Solution:

You simply missed the 2nd argument in your hooked function which is $order, the WC_Order Object, so $order = wc_get_order( $order_id ); is not needed and your error will be solved.

I have revisited and simplified your code a bit:

add_action( 'woocommerce_order_status_completed', 'order_completed_update_user_meta', 10, 2 );
function order_completed_update_user_meta( $order_id, $order ) {
    // Check that user Id exist (registered users only)
    if( $user_id = $order->get_user_id() ) {
        $items = $order->get_items(); // Get order items
        $item  = reset($items); // Get first order item
        $name  = $item->get_name(); // Get first product name
        $value = get_user_meta( $user_id, 'ads-available', true ); // Get user meta 'ads-available'

        if ( $name === 'FREE' ) {
            update_user_meta($user_id, 'ads-available',  $value + 1 );
        } 
        elseif ( $name === 'VIP' ) {
            update_user_meta($user_id, 'ads-available',  $value + 3 );

            $karusel = get_user_meta( $user_id, 'karusel', true ); // Get user meta 'karusel'
            update_user_meta($user_id, 'karusel', $karusel + 1 ); 
        }
    }
}

Code goes in functions.php file of the active child theme (or active theme). It should better work.

Source