please help me. What am I missing here?
I created a plugin that creates a coupon with an order. And with the following, I want to attach the coupon's code to an email. The coupon is stored in an array in a custom postmeta field _associated_coupons
.
Right now, when I do vardump on $associated_coupons
(at #ref2), it gives me string(0)
.
But when I place the code outside of the hook or plugin (which is very simple, no OOP) and use a manual order_id (which works inside the hook as well), this perfectly returns an array of the associated coupon IDs.
add_action( 'woocommerce_email_before_order_table', 'add_coupons_to_email', 10, 4 );
function add_coupons_to_email( $order, $sent_to_admin, $plain_text, $email ) {
if ( $email->id == 'customer_completed_order' ) {
//#ref1
// get order ID
$order_id = $order->get_id();
// Check order for associated Coupons
if ( metadata_exists( 'post', $order_id, '_associated_coupons' ) ) {
$associated_coupons = get_post_meta( $order_id, '_associated_coupons', true );
// #ref2
// Check if
if ( count( $associated_coupons ) > 0 ) {
// #ref3
// get coupon data etc.
// echo stuff;
}
}
}
}
The hook itself works and I can put stuff in the email (e. g. at #ref1. Just the postmeta does not get through and I do not get to #ref3.
I probably missed something very basic.
Please help!
Update
As requested, here is the rest of the plugin, a hook that creates the coupon with an order:
add_action ( 'woocommerce_order_status_completed', 'create_coupon', 31, 1 );
function create_coupon( $order_id ) {
if ( ! $order_id ) return;
// Allow code execution only once
if ( ! get_post_meta( $order_id, '_created_coupon_on_completion', true ) ) {
// Get an instance of the WC_Order object
$order = wc_get_order( $order_id );
$code = random_bytes(8);
$coupon_ids = array();
// Create a coupon with the properties you need
$data = array(
'discount_type' => 'percent_product', // Type: fixed_cart, percent, fixed_product, percent_product
'coupon_amount' => 100, // value
'individual_use' => 'no',
'product_ids' => array(999),
'exclude_product_ids' => array(),
'usage_limit' => '1',
'usage_limit_per_user' => '',
'limit_usage_to_x_items' => '1',
'usage_count' => '',
'expiry_date' => date( 'Y-m-d', strtotime( '+3 years' ) ), // YYYY-MM-DD
'free_shipping' => 'no',
'product_categories' => array(),
'exclude_product_categories' => array(),
'exclude_sale_items' => 'no',
'minimum_amount' => '',
'maximum_amount' => '',
'customer_email' => array(),
'order_id' => $order_id
);
// Save the coupon in the database
$coupon = array(
'post_title' => $code,
'post_content' => '',
'post_status' => 'publish',
'post_author' => 1,
'post_type' => 'shop_coupon'
);
$new_coupon_id = wp_insert_post( $coupon );
// Write the $data values into postmeta table
foreach ($data as $key => $value) {
update_post_meta( $new_coupon_id, $key, $value );
}
$coupon_ids[] = $new_coupon_id;
// Coupon IDs to order
$order->update_meta_data( '_associated_coupons', $coupon_ids );
// Flag the action as done (to avoid repetitions on reload for example)
$order->update_meta_data( '_created_coupon_on_completion', true );
$order->save();
}
}
The raw value in the db is for example this: a:1:{i:0;i:12345;}
Can the problem relate to the priority or the order in which the hooks are called?
Update 2
As suggested, I tried hardcoding the $order_id
which was successful.
Then I tried another way to get dynamically to the ID:
if ( $email->id == 'customer_completed_order' ) {
$order = $email->object;
$order_id = $order->get_id();
var_dump($order_id);
$associated_coupons = get_post_meta( $order_id, '_associated_coupons', true );
var_dump($associated_coupons);
This leads to int(12345) string(0) ""
(12345 is the correct order_id)
Might the sending of the email happen BEFORE there is anything in the table? Looking at the documentation of get_post_meta
(respectively get_postmeta
):
If the meta field does not exist, the result depends on get_metadata_default(). By default, an empty string is returned if $single is true, or an empty array if it’s false.
Okay, it was the priority. Put both at 10, now it works.