I've a site based on wordpress. I'm using wc vendor plugin, woocommerce bookings and wc vendors for woocommerce bookings. I need the status of each order to automatically change to "complete" (wc-completed) 24 hours after the end of each rental (indicated with _booking_end as meta value in the database). I need the function to run once a day at 1pm. I wrote this code in my theme's functions.php file, but it doesn't work. Can you tell me if there are any errors and how can I correct them? Thank you
// Funzione per impostare gli ordini come completati se sono passate 24 ore dal booking_end
function imposta_ordine_completo() {
global $wpdb;
$orders = $wpdb->get_results(
"SELECT * FROM {$wpdb->prefix}posts WHERE post_type = 'shop_order' AND post_status = 'wc-processing'"
);
$count = 0;
// Loop through each order
foreach ( $orders as $order ) {
$order_id = $order->ID;
$booking_end = get_post_meta( $order_id, '_booking_end', true );
if ( $booking_end ) {
$current_time = current_time( 'timestamp' );
$booking_end_timestamp = strtotime( $booking_end );
$time_difference = $current_time - $booking_end_timestamp;
if ( $time_difference >= 86400 ) { // 24 hours in seconds
$order = wc_get_order( $order_id );
if ( $order && $order->get_status() === 'wc-processing' ) {
$order->update_status( 'completed' );
$count++;
}
}
}
}
error_log( "La funzione imposta_ordine_completo è stata eseguita. Sono stati completati $count ordini." );
}
// Registro il cron job che avvia la funzione ogni 24 ore
add_action( 'init', 'register_imposta_ordine_completo_event' );
function register_imposta_ordine_completo_event() {
if ( ! wp_next_scheduled( 'imposta_ordine_completo_event' ) ) {
wp_schedule_event( strtotime( '13:00:00' ), 'daily', 'imposta_ordine_completo_event' );
}
}
// Aggiungo l'hook che chiama la funzione
add_action( 'imposta_ordine_completo_event', 'imposta_ordine_completo' );
I had no results with this code
I want to display shipping notice based on free shipping settings for min amount order. I have more then one shipping zone based on different country and currency. Tried to use the following code, it works when you add product to cart, the shipping notice is display but as if you update quantity the shipping notice is removed, maybe duo to Ajax load? Can I add something to this code to make it work with qty update on product?
add_action( 'woocommerce_before_mini_cart_contents', 'display_free_shipping_cart_notice_zones' );
function display_free_shipping_cart_notice_zones() {
// Get Shipping Methods for Current Zone
global $woocommerce;
$shipping_methods = $woocommerce->shipping->get_shipping_methods();
// Loop through the array to find min_amount value/s
foreach($shipping_methods as $key => $value) {
if ( $shipping_methods[$key]->min_amount > 0 ) {
$min_amounts[$key] = $shipping_methods[$key]->min_amount;
}
}
if ( is_array($min_amounts) ) {
// Find lowest min_amount
$min_amount = min($min_amounts);
// Get Cart Subtotal inc. Tax excl. Shipping
$current = WC()->cart->subtotal;
// If Subtotal < Min Amount Echo Notice
// and add "Continue Shopping" button
if ( $current < $min_amounts ) {
$added_text = 'Get free shipping if you order ' . wc_price( $min_amount - $current ) . ' more!';
$return_to = wc_get_page_permalink( 'shop' );
$notice = sprintf( '%s %s', esc_url( $return_to ), 'Continue Shopping', $added_text );
wc_print_notice( $notice, 'notice' );
}
else if ( $current = $min_amounts ) {
$added_text = 'Congratulations - Your shipping is now on us and absolutely free :)';
$return_to = wc_get_page_permalink( 'shop' );
//$notice = sprintf( '%s %s', esc_url( $return_to ), 'Continue Shopping', $added_text );
$notice = sprintf( '%s', $added_text );
wc_print_notice( $notice, 'notice' );
}
}
}
I am using WooCommerce Subscriptions to manage recurring payments on my WordPress site, which sells baby diapers.
I want to add additional detail to my subscriptions, so that my customers can differentiate between their subscriptions in other ways than by subscription id.
I capture leads about the customers baby, including their name, in a form at the beginning of the customers journey.
To add my extra detail field to the subscriptions data, I modified the wcs_create_subscription function located here:
wp-content/plugins/woocommerce-subscriptions/vendor/woocommerce/subscriptions-core/wcs-functions.php
by first adding a 'baby_name' argument to the $default_args array, that I have set to store the current users id with get_current_user_id(), just to test the functionality:
$default_args = array(
'status' => '',
'baby_name' => get_current_user_id(),
'order_id' => 0,
'customer_note' => null,
'customer_id' => ( ! empty( $order ) ) ? $order->get_user_id() : null,
'start_date' => $default_start_date,
'date_created' => $now,
'created_via' => ( ! empty( $order ) ) ? wcs_get_objects_property( $order, 'created_via' ) : '',
'order_version' => ( ! empty( $order ) ) ? wcs_get_objects_property( $order, 'version' ) : WC_VERSION,
'currency' => ( ! empty( $order ) ) ? wcs_get_objects_property( $order, 'currency' ) : get_woocommerce_currency(),
'prices_include_tax' => ( ! empty( $order ) ) ? ( ( wcs_get_objects_property( $order, 'prices_include_tax' ) ) ? 'yes' : 'no' ) : get_option( 'woocommerce_prices_include_tax' ), // we don't use wc_prices_include_tax() here because WC doesn't use it in wc_create_order(), not 100% sure why it doesn't also check the taxes are enabled, but there could forseeably be a reason
);
Then I run a update_post_meta() function to save my argument in the subscriptions database:
update_post_meta( $subscription_id, '_baby_name', $args['baby_name'] );
Here is my full wcs_create_subscription function:
/**
* Create a new subscription
*
* Returns a new WC_Subscription object on success which can then be used to add additional data.
*
* #return WC_Subscription | WP_Error A WC_Subscription on success or WP_Error object on failure
* #since 2.0
*/
function wcs_create_subscription( $args = array() ) {
$now = gmdate( 'Y-m-d H:i:s' );
$order = ( isset( $args['order_id'] ) ) ? wc_get_order( $args['order_id'] ) : null;
if ( ! empty( $order ) ) {
$default_start_date = wcs_get_datetime_utc_string( wcs_get_objects_property( $order, 'date_created' ) );
} else {
$default_start_date = ( isset( $args['date_created'] ) ) ? $args['date_created'] : $now;
}
$default_args = array(
'status' => '',
'baby_name' => get_current_user_id(),
'order_id' => 0,
'customer_note' => null,
'customer_id' => ( ! empty( $order ) ) ? $order->get_user_id() : null,
'start_date' => $default_start_date,
'date_created' => $now,
'created_via' => ( ! empty( $order ) ) ? wcs_get_objects_property( $order, 'created_via' ) : '',
'order_version' => ( ! empty( $order ) ) ? wcs_get_objects_property( $order, 'version' ) : WC_VERSION,
'currency' => ( ! empty( $order ) ) ? wcs_get_objects_property( $order, 'currency' ) : get_woocommerce_currency(),
'prices_include_tax' => ( ! empty( $order ) ) ? ( ( wcs_get_objects_property( $order, 'prices_include_tax' ) ) ? 'yes' : 'no' ) : get_option( 'woocommerce_prices_include_tax' ), // we don't use wc_prices_include_tax() here because WC doesn't use it in wc_create_order(), not 100% sure why it doesn't also check the taxes are enabled, but there could forseeably be a reason
);
$args = wp_parse_args( $args, $default_args );
$subscription_data = array();
// Validate the date_created arg.
if ( ! is_string( $args['date_created'] ) || false === wcs_is_datetime_mysql_format( $args['date_created'] ) ) {
return new WP_Error( 'woocommerce_subscription_invalid_date_created_format', _x( 'Invalid created date. The date must be a string and of the format: "Y-m-d H:i:s".', 'Error message while creating a subscription', 'woocommerce-subscriptions' ) );
} elseif ( wcs_date_to_time( $args['date_created'] ) > current_time( 'timestamp', true ) ) {
return new WP_Error( 'woocommerce_subscription_invalid_date_created', _x( 'Subscription created date must be before current day.', 'Error message while creating a subscription', 'woocommerce-subscriptions' ) );
}
// Validate the start_date arg.
if ( ! is_string( $args['start_date'] ) || false === wcs_is_datetime_mysql_format( $args['start_date'] ) ) {
return new WP_Error( 'woocommerce_subscription_invalid_start_date_format', _x( 'Invalid date. The date must be a string and of the format: "Y-m-d H:i:s".', 'Error message while creating a subscription', 'woocommerce-subscriptions' ) );
}
// check customer id is set
if ( empty( $args['customer_id'] ) || ! is_numeric( $args['customer_id'] ) || $args['customer_id'] <= 0 ) {
return new WP_Error( 'woocommerce_subscription_invalid_customer_id', _x( 'Invalid subscription customer_id.', 'Error message while creating a subscription', 'woocommerce-subscriptions' ) );
}
// check the billing period
if ( empty( $args['billing_period'] ) || ! in_array( strtolower( $args['billing_period'] ), array_keys( wcs_get_subscription_period_strings() ) ) ) {
return new WP_Error( 'woocommerce_subscription_invalid_billing_period', __( 'Invalid subscription billing period given.', 'woocommerce-subscriptions' ) );
}
// check the billing interval
if ( empty( $args['billing_interval'] ) || ! is_numeric( $args['billing_interval'] ) || absint( $args['billing_interval'] ) <= 0 ) {
return new WP_Error( 'woocommerce_subscription_invalid_billing_interval', __( 'Invalid subscription billing interval given. Must be an integer greater than 0.', 'woocommerce-subscriptions' ) );
}
$subscription_data['post_type'] = 'shop_subscription';
$subscription_data['post_status'] = 'wc-' . apply_filters( 'woocommerce_default_subscription_status', 'pending' );
$subscription_data['ping_status'] = 'closed';
$subscription_data['post_author'] = 1;
$subscription_data['post_password'] = uniqid( 'order_' );
// translators: Order date parsed by strftime
$post_title_date = strftime( _x( '%b %d, %Y # %I:%M %p', 'Used in subscription post title. "Subscription renewal order - <this>"', 'woocommerce-subscriptions' ) ); // phpcs:ignore WordPress.WP.I18n.UnorderedPlaceholdersText
// translators: placeholder is order date parsed by strftime
$subscription_data['post_title'] = sprintf( _x( 'Subscription – %s', 'The post title for the new subscription', 'woocommerce-subscriptions' ), $post_title_date );
$subscription_data['post_date_gmt'] = $args['date_created'];
$subscription_data['post_date'] = get_date_from_gmt( $args['date_created'] );
if ( $args['order_id'] > 0 ) {
$subscription_data['post_parent'] = absint( $args['order_id'] );
}
if ( ! is_null( $args['customer_note'] ) && ! empty( $args['customer_note'] ) ) {
$subscription_data['post_excerpt'] = $args['customer_note'];
}
// Only set the status if creating a new subscription, use wcs_update_subscription to update the status
if ( $args['status'] ) {
if ( ! in_array( 'wc-' . $args['status'], array_keys( wcs_get_subscription_statuses() ) ) ) {
return new WP_Error( 'woocommerce_invalid_subscription_status', __( 'Invalid subscription status given.', 'woocommerce-subscriptions' ) );
}
$subscription_data['post_status'] = 'wc-' . $args['status'];
}
$subscription_id = wp_insert_post( apply_filters( 'woocommerce_new_subscription_data', $subscription_data, $args ), true );
if ( is_wp_error( $subscription_id ) ) {
return $subscription_id;
}
// Default order meta data.
update_post_meta( $subscription_id, '_order_key', wcs_generate_order_key() );
update_post_meta( $subscription_id, '_order_currency', $args['currency'] );
update_post_meta( $subscription_id, '_prices_include_tax', $args['prices_include_tax'] );
update_post_meta( $subscription_id, '_created_via', sanitize_text_field( $args['created_via'] ) );
// add/update the billing
update_post_meta( $subscription_id, '_billing_period', $args['billing_period'] );
update_post_meta( $subscription_id, '_billing_interval', absint( $args['billing_interval'] ) );
update_post_meta( $subscription_id, '_customer_user', $args['customer_id'] );
update_post_meta( $subscription_id, '_order_version', $args['order_version'] );
update_post_meta( $subscription_id, '_schedule_start', $args['start_date'] );
update_post_meta( $subscription_id, '_baby_name', $args['baby_name'] );
/**
* Filter the newly created subscription object.
*
* #since 2.2.22
* #param WC_Subscription $subscription
*/
$subscription = apply_filters( 'wcs_created_subscription', wcs_get_subscription( $subscription_id ) );
/**
* Triggered after a new subscription is created.
*
* #since 2.2.22
* #param WC_Subscription $subscription
*/
do_action( 'wcs_create_subscription', $subscription );
return $subscription;
}
I can confirm that this works, as I can see a row with _baby_name in the meta_key field and my user id in the meta_value field for a subscription with id 2898 that I placed recently in my sites _postmeta database table:
As I know that I should never modify the core plugin files, I am looking to make my modifications in a snippet or similar that I can place in my child themes function.php file. Any advice?
From the code you have posted it can be deduced that use can be made of the wcs_create_subscription action hook:
/**
* Triggered after a new subscription is created.
*
* #since 2.2.22
* #param WC_Subscription $subscription
*/
function action_wcs_create_subscription( $subscription ) {
// Get ID
$subscription_id = $subscription->get_id();
update_post_meta( $subscription_id, '_baby_name', 'my_value' );
}
add_action( 'wcs_create_subscription', 'action_wcs_create_subscription', 10, 1 );
There is no need to add this as an argument first. Via $subscription you can obtain multiple data, if desired
i have something i cant get working and i dont understand why.
I want to add some custom fields below a grouped product in woocommerce on the frontend.
So i have the following function (which works fine):
function add_data_opbouw_front(){
global $woocommerce; global $post;
$id = $post->ID;
if ($id === 1411){
$optiestijd = array();
$optiesdag = array();
$id = get_the_ID();
$html = '<table><tbody>';
$i=0;
if( !empty(get_post_meta($id,'tijdslot',true) ) ){
$html .= '<tr><td>Kies een tijd:</td><td><select name="tijdslot" required><option value="">Kies:</option>';
$optiestijden = get_post_meta(get_the_ID(),'tijdslot',true);
foreach ($optiestijden as $key=>$optie){
$optiestijd[$optie] = 'Kies een tijdslot:';
}
foreach ($optiestijd as $optie => $label){
if(!empty($optie)){
$i++;
$html .= '<option value="'.$optie.'"><span class="choiceoption">'. $optie.'</span></option>';
}
}
$html .= '</select></td></tr>';
}
if( !empty(get_post_meta($id,'dag',true) ) ){
$optiesdagen = get_post_meta(get_the_ID(),'dag',true);
$optiesdagen = explode('|',$optiesdagen);
$html.= '<tr><td>Kies een dag:</td><td><select name="dag" required><option value="">Kies:</option>';
foreach ($optiesdagen as $optie){
$i++;
$html .= '<option value="'.$optie.'"><span class="choiceoption">'. $optie.'</span></option>';
}
}
$html .= '</select></td></tr></tbody></table>';
$html .= '<input type="hidden" name="voorraad_afname" value="1">';
echo $html;
}
}
add_action('woocommerce_before_add_to_cart_button','add_data_opbouw_front', 35);
because i want to obligate user to pick a day and time, i want to validate before the add to cart and i do it like this:
function so_validate_add_cart_item( $passed, $product_id, $quantity, $variation_id = '', $variations= '' ) {
global $woocommerce; global $post;
$id = $post->ID;
if ($id === 1411){
// do your validation, if not met switch $passed to false
if ( empty($_POST['tijdslot']) || empty($_POST['dag']) ){
$passed = false;
wc_add_notice( __( 'De velden "Kies een dag" en "Kies een tijdslot" zijn beiden verplicht', 'textdomain' ), 'error' );
}
}
return $passed;
}
add_filter( 'woocommerce_add_to_cart_validation', 'so_validate_add_cart_item', 10, 5 );
But when I leave one of the select boxes empty, the product is being added to the cart anyway. So the validate doesnt throw in the error. I dont really understand why this is not working.
Any ideas?
After a long puzzle, i found out that approaching global $post is not working. Better is to approach the product_id. Because it is a grouped product, i checked wether one of the grouped products ID are in the add-to-cart like so:
$check = array('1398','1399','1400');
if (in_array($product_id,$check)){
And that does work.
So updated code is:
function so_validate_add_cart_item( $passed, $product_id, $quantity, $variation_id = '', $variations= '' ) {
$check = array('1398','1399','1400');
if (in_array($product_id,$check)){
// check if both selectboxes are used
if ( empty($_POST['tijdslot']) || empty($_POST['dag']) ){
$passed = false;
wc_add_notice( __( 'De velden "Kies een dag" en "Kies een tijdslot" zijn beiden verplicht', 'textdomain' ), 'error' );
}
}
return $passed;
}
add_filter( 'woocommerce_add_to_cart_validation', 'so_validate_add_cart_item', 10, 5 );
I created a custom field for the ecommerce admin order item meta. Everything is fine.
I would like to display the Custom Fields MetaValue on My Account's Order Details page. But nothing is being displayed. Based on Save Order item custom field in Woocommerce Admin order pages answer code, this is my attempt
function add_order_item_custom_field( $item_id, $item ) {
woocommerce_wp_text_input( array(
'id' => 'v_number'.$item_id,
'label' => __( 'V Number : ', 'ctxt' ),
'description' => __( 'Enter the title of your custom text field.', 'ctxt' ),
'desc_tip' => true,
'class' => 'v_number_class',
'value' => wc_get_order_item_meta( $item_id, '_v_number' ),
) );
}
add_action( 'woocommerce_before_order_itemmeta', 'add_order_item_custom_field', 10, 2 );
// Save the custom field value
function save_order_item_custom_field_value( $post_id, $post ){
$order = wc_get_order( $post_id );
foreach ( $order->get_items() as $item_id => $item ) {
if( isset( $_POST['v_number'.$item_id] ) ) {
$item->update_meta_data( '_v_number', sanitize_text_field( $_POST['v_number'.$item_id] ) );
$item->save();
}
}
$order->save();
}
add_action('save_post', 'save_order_item_custom_field_value' );
// Display meta my account view order page
printf (
'<p><a>V Number : <strong>' . $order->get_meta('_v_number') . '</strong></a></p>'
);
it should print your custom order meta value.
add_action( 'woocommerce_view_order', 'print_custom_order_meta' );
function print_custom_order_meta( $order_id ){
$order = wc_get_order($order_id);
foreach( $order->get_items() as $item ) {
echo 'V Number for '. $item->get_name() .' - ' . $item->get_meta( '_v_number', true ) . '<br>';
}
}
edit
for need to show metavalue after each product item you need to hook with a different action like this.
add_action('woocommerce_order_item_meta_end', 'show_order_meta', 11, 3);
function show_order_meta( $item_id, $item, $order ) {
echo '<br>V Number for '. $item->get_name() .' - ' . $item->get_meta( '_v_number', true ) . '<br>';
}