Ask your WordPress questions! Pay money and get answers fast! Comodo Trusted Site Seal
Official PayPal Seal

$wpdb and $woocommerce dont work inside woocommerce action WordPress

  • SOLVED

On my woocommerce store, once a customer makes a payment I need to update a database field.

I do so using the "woocommerce_payment_complete" action called from function.php in my theme. This works perfectly when the customer pays using a credit card on our website, but when a customer chooses to pay via PayPal, $wpdb and $woocommerce are for some reason empty. Because of this the rest of my code does not execute! It gives me no errors, but when I write var_dump($wpdb) and var_dump($woocommerce) the result is empty. I tried requiring wp-load.php but that still doesn't work.

The strange thing is that it works perfectly when a customer pays with a credit card (not with PayPal). When a Paypal payment is made on the other hand, the customer gets redirected to the PayPal website, makes the payment and then an 'IPN payment completed' notification is sent back to the site to mark the payment as complete. Something happens during this PayPal process that I just don't understand which causes $wpdb, and $woocommerce to be empty.

P.S. something like $order = new WC_Order( $order_id ); does work, so the action obviously has access to some Wordpress functions and objects.

Thanks in advance!

<code>

add_action( 'woocommerce_payment_complete', 'link_customization_data_to_order_id',10,2);

//$order_id is passed by woocommerce_payment_complete action
function link_customization_data_to_order_id( $order_id ) {

global $wpdb,$woocommerce;

//loop through items in cart
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $cart_item ) {

$wpdb->query( $wpdb->prepare("UPDATE wp_products SET order_id = '$order_id', status = 'order-placed' WHERE cart_item_key = '$cart_item_key'",null));

} //end foreach

}

<code>

Answers (3)

2014-11-05

John Cotton answers:

I don't understand your code.

Why are you trying to access the woocommerce cart? You should be looking at the order, not the cart (with WC_Order as you note).

Also, you should be using WC() not $woocommerce......


WC()->session->order_awaiting_payment (as an example) is called prior to that hook triggering so it will definitely be available.




dmitrip comments:

Hi John,

My store offers heavily customizable products and so when a customer places an order I need to link that with the data for the customizable product located in my own custom table "wp_products".

So what I am essentially doing here is that once the customer pays, I loop through every cart item and get that item's $cart_item_key which the entry in "wp_products" already has and with that I set the order ID for the item in wp_products to the order id of the order.

Hope that makes sense.

So in order to use WC() I will need to be able to access the cart items, and then I will need to update the database record in my custom table "wp_products". So for that unfortunately I will need access to $wpdb. What's strange though is that as you said WC() does work but $woocommerce does not...


John Cotton comments:

<blockquote>So in order to use WC() I will need to be able to access the cart items,</blockquote>

...but there's no guarantee that when PayPal calls back (which might happen instantly or might take several minutes), the cart still exists.

You need to access the items through WC_Order using get_items().

Are you absolutely sure $wpdb is not set?

I've never come across that since WP doesn't do anything without setting that as even the basic stuff needs to read from the database.


dmitrip comments:

This is starting to make sense, $wpdb might actually be working, I am going to double check it right now.

But here is the problem that arises with the new approach. When a customer arrives on the website they customize their product and then click a custom "add to cart button". The button calls for an ajax request that adds the cart item manually and also creates a new entry in "wp_products" with the data for the customizable product..

Then in the action 'woocommerce_add_to_cart' in my functions.php file I record the $cart_item_key in the wp_products entry of the product just added to cart. That way, when it comes to time to place the order. I can take the order number and link it with the customizable product's entry in "wp_products" using the cart_item_key, like so:


add_action('woocommerce_add_to_cart', 'link_cart_item_key_with_customizable_product_entry',10,2);

function link_cart_item_key_with_customizable_product_entry($cart_item_key) {

global $wpdb;

// $wpdb->insert_id comes from customizedproduct_backend.php when the tag is done being customized, the entry is saved to the database, $wpdb->insert_id is a global object therefore it is available here, and the item is added to cart (so here we can receive the $cart_item_key )
$entry_id = $wpdb->insert_id;

$wpdb->query($wpdb->prepare("UPDATE wp_products SET cart_item_key = '$cart_item_key' WHERE id = $entry_id",null));

}



The problem is that with the new approach, using only WC() how will I be able to link the customizable data located in "wp_products" with the order id?


John Cotton comments:

<blockquote>The button calls for an ajax request that adds the cart item manually and also creates a new entry in "wp_products" with the data for the customizable product..</blockquote>

Why not wait until they've placed the order? I tend to use the woocommerce_order_status_changed hook for that sort of thing.

Alternatively, if you need to store specific product customisations, the look at woocommerce_order_item_meta and $cart_item['addons'] which is a good place to store values that WC saves in the database for you (ie you don't really need a separate table, you can let Woocommerce store everything in its order_itemmeta table).


dmitrip comments:

Thanks John, You pointed me in the right direction and that's exactly what I needed. I changed the system and it works now. Thanks again.


John Cotton comments:

Glad you got it sorted.


dmitrip comments:

I hope an admin up votes this answer. As it is the one that helped me solve the problem!


John Cotton comments:

You need to mark the question as complete and then you can vote yourself.

2014-11-04

Francisco Javier Carazo Gil answers:

Are you sure your prefix is "wp"? Use better $wpdb->prefix to avoid this problem.


Francisco Javier Carazo Gil comments:

And also, try to do a var_dump() or write into a log this string:

$wpdb->prepare("UPDATE wp_products SET order_id = '$order_id', status = 'order-placed' WHERE cart_item_key = '$cart_item_key'",null);

Then try to execute it in a SQL console (like the phpMyAdmin SQL console for example).


dmitrip comments:

Hi Francisco,

$wpdb->prepare("UPDATE wp_products SET order_id = '$order_id', status = 'order-placed' WHERE cart_item_key = '$cart_item_key'",null);

is a valid line that works, the problem is that it does not get executed (when paying with PayPal) because global $wpdb,$woocommerce; are empty.


Francisco Javier Carazo Gil comments:

Try with another hook: woocommerce_order_status_pending_to_completed


Francisco Javier Carazo Gil comments:

Look at it:

<blockquote>Change hook name from woocommerce_payment_complete to woocommerce_order_status_pending_to_completed and woocommerce_order_status_on-hold_to_completed because woocommerce_payment_complete never is called for child order role , so that fixed the problem that can't update next payment date for original order
</blockquote>

In [[LINK href="https://github.com/deliciousbrains/woocommerce-subscriptions-renew-active/pull/1"]]https://github.com/deliciousbrains/woocommerce-subscriptions-renew-active/pull/1[[/LINK]].


dmitrip comments:

I tried changing the hook name to woocommerce_order_status_pending_to_completed, but unfortunately the action doesn't run at all now.


Francisco Javier Carazo Gil comments:

Use both hooks, also: woocommerce_order_status_on-hold_to_completed


dmitrip comments:

The problem is that when the PayPal payment goes through, the status goes from pending to processing. It only goes to completed once we ship out the product (changed manually).

2014-11-04

Arnav Joy answers:

can you try following in your function to see what it returns ?

print_r($_REQUEST);

I think paypal will return order id in request array.


dmitrip comments:

print_r($_REQUEST) outputs 1

The "woocommerce_payment_complete" action does pass the $order_id variable. I can access $order_id from within the function. The problem is that global $wpdb,$woocommerce; is empty so the rest of the code cant run.


Arnav Joy comments:

try this one

<?php

add_action( 'valid-paypal-standard-ipn-request', 'aj_ipn_response', 10, 1 );

function aj_ipn_response( $formdata )
{
print_r( $formdata);


}

?>


Arnav Joy comments:

if above code works then you can use following to get order id

<?php

add_action( 'valid-paypal-standard-ipn-request', 'aj_ipn_response', 10, 1 );

function aj_ipn_response( $formdata )
{


$custom = maybe_unserialize( $posted['custom'] );

if ( is_numeric( $custom ) ) {
$order_id = (int) $custom;
$order_key = $posted['invoice'];
} elseif( is_string( $custom ) ) {
$order_id = (int) str_replace( 'WC-', '', $custom );
$order_key = $custom;
} else {
list( $order_id, $order_key ) = $custom;
}


}

?>


dmitrip comments:

Unfortunately that didn't work Arnav, $order_id is empty


Arnav Joy comments:

and what is the output of

<?php



add_action( 'valid-paypal-standard-ipn-request', 'aj_ipn_response', 10, 1 );



function aj_ipn_response( $formdata )

{

print_r( $formdata);





}



?>


dmitrip comments:

print_r( $formdata); returns 1