Dokan action to update order status - woocommerce

I need help with dokan actions on Orders page. Currently here i have two actions, to mark order complete or processing. What I want is to create action to mark order cancelled and on-hold.
I have accessed file that contains these two actions and they are in file Ajax.php:
add_action( 'wp_ajax_dokan-mark-order-complete', array( $this, 'complete_order' ) );
add_action( 'wp_ajax_dokan-mark-order-processing', array( $this, 'process_order' ) );
Is there a way to define similar action:
add_action( 'wp_ajax_dokan-mark-order-cancelled', array( $this, 'cancel_order' ) );
?

I already made a custom action that mark the order as shipped(custom status):
first you can add the below to include/Ajax.php > in the __construct function.
add_action( 'wp_ajax_dokan-mark-order-shipped', array( $this, 'ship_order' ) );
Then you have to include the custom function (in the same file):
public function ship_order() {
if ( ! is_admin() ) {
die();
}
if ( ! current_user_can( 'dokandar' ) || 'on' != dokan_get_option( 'order_status_change', 'dokan_selling', 'on' ) ) {
wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'dokan-lite' ) );
}
if ( ! check_admin_referer( 'dokan-mark-order-shipped' ) ) {
wp_die( esc_html__( 'You have taken too long. Please go back and retry.', 'dokan-lite' ) );
}
$order_id = ! empty( $_GET['order_id'] ) ? intval( $_GET['order_id'] ) : 0;
if ( ! $order_id ) {
die();
}
if ( ! dokan_is_seller_has_order( dokan_get_current_user_id(), $order_id ) ) {
wp_die( esc_html__( 'You do not have permission to change this order', 'dokan-lite' ) );
}
$order = dokan()->order->get( $order_id );
$order->update_status( 'wc-completed' );
wp_safe_redirect( wp_get_referer() );
die();
}
then make sure that you modify the URL :
'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=dokan-mark-order-shipped&order_id=' . dokan_get_prop( $order, 'id' ) ), 'dokan-mark-order-shipped' ),
Please let me know if you need any help

Related

How do I add a custom field for subscriptions in the WooCommerce Subscriptions plugin without touching the core files?

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

WooCommerce custom order itemmeta display my account view order page

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>';
}

WooCommerce Looping on My Account Form Submission

I am trying to override the account_display_name field within the my-account (logged in user) section which I am undertaking through two hooks. The first removes the required attribute, and the second updates the display_name field based on the input of first and last name.
This filter allows me to remove the required="required" attribute from the display_name field and works as intended:
add_filter('woocommerce_save_account_details_required_fields', 'audp_myaccount_required_fields');
function audp_myaccount_required_fields( $required_fields ) {
unset( $required_fields['account_display_name'] );
return $required_fields;
}
This next action is intended to allow me to save the submitted account_first_name and account_last_name as the display_name:
add_action( 'profile_update', 'audp_myaccount_display_name', 20, 2 );
function audp_myaccount_display_name( $display_name ) {
global $current_user;
if ( isset( $_POST['account_first_name'] ) && isset( $_POST['account_last_name'] ) ) {
if ( ! empty( $_POST['account_first_name'] ) && ! empty( $_POST['account_last_name'] ) ) {
wp_update_user(
array (
'ID' => $current_user->ID,
'display_name' => sanitize_text_field( $_POST['account_first_name'] ) . ' ' . sanitize_text_field( $_POST['account_last_name'] ),
)
);
}
}
}
The problem I'm having with this code is the looping after submitting the data. The page 'eventually' returns an Internal 500 Error. If I stop the process (escape) and reload the page, the data has updated. I just don't know how to get out of this loop?
I have researched some options including remove_action( 'profile_update', 'audp_myaccount_display_name', 20, 2 ) before the wp_update_user() and then add_action( 'profile_update', 'audp_myaccount_display_name', 20, 2 ) after wp_update_user() but that has not seemed to work either.
Any assistance would be appreciated!
You should be able to stop endless loops by adding an additional filter, with a default false value, that you check at the top of your function. Stopping your code from being executed when this filter returns true.
Then call that filter before you update the user meta and make it return true. And remove it after updating the user meta. This way the check at the top will return true the second time the functions gets called and stops the endless loop, resulting in your function only running once.
add_action( 'profile_update', 'audp_myaccount_display_name', 20, 2 );
function audp_myaccount_display_name( $display_name ) {
if ( apply_filters( 'prevent_endless_loop_updating_user_meta', false ) ) return; // prevent endless loops
global $current_user;
if ( isset( $_POST['account_first_name'] ) && isset( $_POST['account_last_name'] ) ) {
if ( ! empty( $_POST['account_first_name'] ) && ! empty( $_POST['account_last_name'] ) ) {
add_filter( 'prevent_endless_loop_updating_user_meta', '__return_true' );
wp_update_user(
array (
'ID' => $current_user->ID,
'display_name' => sanitize_text_field( $_POST['account_first_name'] ) . ' ' . sanitize_text_field( $_POST['account_last_name'] ),
)
);
remove_filter( 'prevent_endless_loop_updating_user_meta', '__return_true' );
}
}
}

Mandatory custom radio button choice on Woocommerce checkout

I've got this custom code working to add a couple of radio buttons into the checkout:
add_action( 'woocommerce_review_order_before_payment', 'display_extra_fields_after_billing_address' , 10, 1 );
function display_extra_fields_after_billing_address () { ?>
<h3 class="delivery-options-heading">Delivery Options <sup>*</sup></h3>
<div class="delivery-options">
<p><input type="radio" name="delivery_option" value="Have the courier leave a card." required /> Have the courier leave a card.</p>
<p><input type="radio" name="delivery_option" value="Leave the consignment without a signature." required /> Leave the consignment without a signature.</p>
</div>
<?php
}
add_action( 'woocommerce_checkout_update_order_meta', 'add_delivery_option_to_order' , 10, 1);
function add_delivery_option_to_order ( $order_id ) {
if ( isset( $_POST ['delivery_option'] ) && '' != $_POST ['delivery_option'] ) {
add_post_meta( $order_id, '_delivery_option', sanitize_text_field( $_POST ['delivery_option'] ) );
}
}
add_filter( 'woocommerce_email_order_meta_fields', 'add_delivery_option_to_emails' , 10, 3 );
function add_delivery_option_to_emails ( $fields, $sent_to_admin, $order ) {
if( version_compare( get_option( 'woocommerce_version' ), '3.0.0', ">=" ) ) {
$order_id = $order->get_id();
} else {
$order_id = $order->id;
}
$delivery_option = get_post_meta( $order_id, '_delivery_option', true );
if ( '' != $delivery_option ) {
$fields[ 'Delivery Date' ] = array(
'label' => __( 'Delivery Option', 'delivery_option' ),
'value' => $delivery_option,
);
}
return $fields;
}
Every part of this works fine except for the required attributes on the radio buttons, letting the user checkout without making a choice, which is not ideal. For some reason the required attributes are being ignored.
How can I force the user to select one of the radio buttons before checking out?
Please add this validation hook along with your code that will validate your option on checkout
function action_woocommerce_after_checkout_validation( $data, $errors ) {
if( !isset( $data['delivery_option'] ) || empty( $data['delivery_option'] ) ) :
$errors->add( 'required-field', __( 'No delivery option has been selected. Please choose delivery option.', 'woocommerce' ) );
endif; //Endif
}
// add the action
add_action( 'woocommerce_after_checkout_validation', 'action_woocommerce_after_checkout_validation', 10, 2 );
This was the solution, slightly different to what Krunal Prajapati suggested. The only difference is the second line:
function action_woocommerce_after_checkout_validation( $data, $errors ) {
if ( empty( $_POST['delivery_option'] ) ) :
$errors->add( 'required-field', __( 'No delivery option has been selected. Please choose delivery option.', 'woocommerce' ) );
endif; //Endif
}
// add the action
add_action( 'woocommerce_after_checkout_validation', 'action_woocommerce_after_checkout_validation', 10, 2 );

Removing a Wordpress action added from a Plugin and than adding a new action in place of that

I am creating a wordpress theme and i need to remove a wordpress action added from within a plugin class.
Here is the plugin's class and the action added in this class is
add_action( 'woocommerce_after_shop_loop_item', array( $this, 'add_compare_link' ), 20 ); And this is the action i need to remove in my theme.
After removing that action i need to add a new action on the same location.
New action is:
function product_add_compare_link( $product_id = false, $args = array() ) {
extract( $args );
if ( ! $product_id ) {
global $product;
$product_id = isset( $product->id ) && $product->exists() ? $product->id : 0;
}
if ( empty( $product_id ) ) return;
$is_button = !isset( $button_or_link ) || !$button_or_link ? get_option( 'yith_woocompare_is_button' ) : $button_or_link;
$button_text = get_option( 'yith_woocompare_button_text', __( 'Compare', 'yit' ) );
$localized_button_text = function_exists( 'icl_translate' ) ? icl_translate( 'Plugins', 'plugin_yit_compare_button_text', $button_text ) : $button_text;
printf( '<i class="icon-tasks"></i>%s', $this->add_product_url( $product_id ), 'compare' . ( $is_button == 'button' ? ' add-comp' : '' ), $product_id, ( isset( $button_text ) && $button_text != 'default' ? $button_text : $localized_button_text ) );
}
add_action( 'woocommerce_after_shop_loop_item', 'product_add_compare_link', 20 );
Tried this solution and it removed that action perfectly but i cannot add a new one after that.
What i am doing is:
function kill_old_action() {
remove_anonymous_object_filter(
'woocommerce_after_shop_loop_item',
'YITH_Woocompare_Frontend',
'add_compare_link'
);
}
add_action( 'woocommerce_after_shop_loop_item', 'kill_old_action', 0 );
add_action( 'woocommerce_after_shop_loop_item', 'product_add_compare_link', 50 );
Any help will be highly appreciated.
Thank you
I wouldn't remove the action like that. The traditional way to remove an action that was added from a class is:
remove_action('woocommerce_after_shop_loop_item', array( $class_variable, 'add_compare_link' ), 20 );
where the class variable is the instantiation of the class. How you refer to this depends on how the class has been instantiated in the plugin.
You can read about different ways of instantiating a class and the corresponding remove_action at http://jespervanengelen.com/different-ways-of-instantiating-wordpress-plugins/
Also when you use add_action if you want to be able to use more than one input parameter in your function you need to specify the number of parameters. So in your case:
add_action( 'woocommerce_after_shop_loop_item', 'product_add_compare_link', 50, 2 );

Resources