I've been creating a modified My Accounts UI and am unable to get past order history to populate with the wc_get_template command for the /myaccounts/orders.php page. I have customized this page so its in the same directory as my-account.php hence why my wc_get_template() does not have /myaccounts/orders.php instead.
Here is my code:
$user_id = get_current_user_id();
$path = plugin_dir_path( __FILE__ );
wc_get_template( 'orders.php', array('user_id' => $user_id , 'has_orders' => true ),'', $path); ?>
I feel like I might be missing something in the array... but not sure what. I have set has_orders to true for testing purposes
For anyone who was looking for an answer you must pass 2 more arguments in the wc_get_template for orders.php:
$current_page = empty( $current_page ) ? 1 : absint( $current_page );
$customer_orders = wc_get_orders( apply_filters( 'woocommerce_my_account_my_orders_query', array( 'customer' => get_current_user_id(), 'page' => $current_page, 'paginate' => true ) ) );
wc_get_template(
'orders.php', array('current_page' => absint( $current_page ),'customer_orders' => $customer_orders,'has_orders' => 0 < $customer_orders->total, ),'', $path);
Related
I am working on a new plugin. I am dealing with a problem that I have outlined in the title. My intention is to redirect the user to the My Pages page after the user clicks the "Delete page" button.
Here is my code:
function custom_admin_bar_delete_link( $wp_admin_bar ) {
global $post;
if( is_admin() || ! is_object( $post ) )
return;
if ( ! current_user_can( 'delete_pages' ) )
return;
if ( $post->post_type != 'page' )
return;
$args = array(
'id' => 'delete_link',
'title' => 'Delete this page',
'href' => get_delete_post_link( $post->ID ),
'meta' => array( 'class' => 'delete-link' )
);
$wp_admin_bar->add_node( $args );
}
add_action( 'admin_bar_menu', 'custom_admin_bar_delete_link', 999 );
function custom_page_delete_redirect( $location, $post_id ) {
$post = get_post( $post_id );
if ( 'page' === $post->post_type && 'trash' === get_post_status( $post_id ) ) {
return admin_url( 'edit.php?post_type=page' );
}
return $location;
}
add_filter( 'wp_redirect', 'custom_page_delete_redirect', 10, 2 );
Thank you.
Without thinking too hard about it, I would add an ID to your button and just write some jQuery to do the redirect.
(The PHP: NOT tested)
EDIT:
Per the Wordpress documentation, you should be able to add an ID:
https://developer.wordpress.org/reference/classes/wp_admin_bar/add_node/
$args = array(
'id' => 'delete_link',
'title' => 'Delete this page',
'href' => get_delete_post_link( $post->ID ),
'id' => "someid",
'meta' => array( 'class' => 'delete-link' )
);
The jQuery:
EDIT:
How are you adding the jQuery? You should probably save it in a separate file in your plugin folder (maybe in a subfolder named "js") and enqueue it in your plugin. The 2nd answer to this question would be a good place to start:
https://wordpress.stackexchange.com/questions/42641/how-to-include-a-simple-jquery-file-into-a-wordpress-plugin
jQuery(document).ready(function($){
$('body').on('click','#someid',function(event){
// window.alert('jquery executing');
setTimeout(function(){window.location.href = "http://example.com/page/";}, 500);
});
});
Thoughts: I added a timeout, because Wordpress loads slowly sometimes, and I've had to do this for other applications in Wordpress, but try without and see if it performs without the timeout.
Have a look at this answer:
https://wordpress.stackexchange.com/questions/132196/get-delete-post-link-redirect
The question is similar, and this may get you where you need to go.
I am using this code to add admin action to change bulk order statuses.
I have custom build status with name "wc-to-order".
Unfortunatelly, I got error when use code from Woo bulk action.
Can anyone help me to resolve it?
This is code:
add_action( 'admin_action_wc-to-order', 'add_new_order_status_wc_on_hold' ); // admin_action_{action name}
function add_new_order_status_wc_on_hold() {
// if an array with order IDs is not presented, exit the function
if( !isset( $_REQUEST['post'] ) && !is_array( $_REQUEST['post'] ) )
return;
foreach( $_REQUEST['post'] as $order_id ) {
$order = new WC_Order( $order_id );
$order_note = 'That\'s what happened by bulk edit:';
$order->update_status( 'wc-to-order', $order_note, true );
}
$location = add_query_arg( array(
'post_type' => 'shop_order',
'wc-to-order' => 1, // markED_awaiting_shipment=1 is just the $_GET variable for notices
'changed' => count( $_REQUEST['post'] ), // number of changed orders
'ids' => join( $_REQUEST['post'], ',' ),
'post_status' => 'all'
), 'edit.php' );
wp_redirect( admin_url( $location ) );
exit;
}
I got this in debug log
PHP Fatal error: Uncaught TypeError: join(): Argument #2 ($array) must be of type ?array, string given in /public_html/sitename/wp-content/themes/themename/functions.php:648
From the log, it appears that $_REQUEST['post'] may not be an array. In the below code we first check if it is an array. If it is not, then we cast it as array.
add_action( 'admin_action_wc-to-order', 'add_new_order_status_wc_on_hold' ); // admin_action_{action name}
function add_new_order_status_wc_on_hold() {
// if an array with order IDs is not presented, exit the function
if( !isset( $_REQUEST['post'] ) ) {
return;
}
//check if it is an array. If not, cast it as array
$orders_array = is_array($_REQUEST['post']) ? $_REQUEST['post'] : array($_REQUEST['post']);
foreach( $orders_array as $order_id ) {
$order = new WC_Order( $order_id );
$order_note = 'That\'s what happened by bulk edit:';
$order->update_status( 'wc-to-order', $order_note, true );
}
$location = add_query_arg( array(
'post_type' => 'shop_order',
'wc-to-order' => 1, // markED_awaiting_shipment=1 is just the $_GET variable for notices
'changed' => count( $orders_array ), // number of changed orders
'ids' => join( $orders_array, ',' ),
'post_status' => 'all'
), 'edit.php' );
wp_redirect( admin_url( $location ) );
exit;
}
This way we ensure that array is always provided to join function.
I'm trying to run the following function daily, to auto-complete all processing order older than 10 days and who have a specific custom meta value.
I'm using the following snippet, however this will simply not work. Any idea as to why?
function autoComplete(){
$orders = wc_get_orders( array(
'status' => 'wc-processing',
'date_created' => '<' . ( time() - 10 * DAY_IN_SECONDS ),
'meta_key' => 'status_us',
'meta_compare' => '=',
'meta_value' => 'Sent to USA',
) );
foreach ($orders as $order){
$order->update_status( 'completed' );
}
}
if ( ! wp_next_scheduled( 'autoComplete' ) ) {
wp_schedule_event( time(), 'daily', 'autoComplete' );
}
Is there any error I've missed? Thanks for your help!
You did a good attempt but you made a few mistakes.
The following code goes inside your functions.php.
add_action( 'wp_loaded','start_custom_code' );
// Once everything theme and plugins are loaded we register our cron job.
function start_custom_code() {
if ( ! wp_next_scheduled( 'bks_mark_processing_order_complete_if_sent_to_usa' ) ) {
wp_schedule_event( time(), 'daily', 'bks_mark_processing_order_complete_if_sent_to_usa' );
}
}
add_action( 'bks_mark_processing_order_complete_if_sent_to_usa', 'bks_mark_processing_order_complete_if_sent_to_usa' );
Your function has minor errors bks_mark_processing_order_complete_if_sent_to_usa()
function bks_mark_processing_order_complete_if_sent_to_usa(){
$args = array(
'status' => array( 'wc-processing'),
'limit' => -1,
'date_created' => '>' . ( time() - 864000 ), // your mistake 1
'status_us' => 'Sent to USA', // your mistake 2
);
$orders = wc_get_orders( $args );
foreach ($orders as $order){
$order->update_status( 'completed' );
$order->save(); // your mistake 3
}
};
Mistake Explanations
While your attempt was in right direction but 'date_created' => '<' . ( time() - 10 * DAY_IN_SECONDS ), you had to use > instead of < also you didn't acutally set DAY_IN_SECONDS You had to replace it with 86400. So the correct value would be '>' . ( time() - 864000 ). For 10 days 10 * 86400 = 864000. You can read about this explanation here in the WooCommerce documentation.
Here I have created new custom variable for you which is set using woocommerce_order_data_store_cpt_get_orders_query and then queried. Code that needs to be added.
function handle_custom_query_var( $query, $query_vars ) {
if ( ! empty( $query_vars['status_us'] ) ) {
$query['meta_query'][] = array(
'key' => 'status_us',
'value' => esc_attr( $query_vars['status_us'] ),
);
}
return $query;
}
add_filter( 'woocommerce_order_data_store_cpt_get_orders_query', 'handle_custom_query_var', 10, 2 );
You updated the status but you forgot to save it. $order->save();
So to summarise you have to add the following code in your functions.php
add_action( 'wp_loaded','start_custom_code' );
add_action( 'bks_mark_processing_order_complete_if_sent_to_usa', 'bks_mark_processing_order_complete_if_sent_to_usa' );
function start_custom_code() {
if ( ! wp_next_scheduled( 'bks_mark_processing_order_complete_if_sent_to_usa' ) ) {
wp_schedule_event( time(), 'daily', 'bks_mark_processing_order_complete_if_sent_to_usa' );
}
}
function bks_mark_processing_order_complete_if_sent_to_usa(){
$args = array(
'status' => array( 'wc-processing'),
'limit' => -1,
'date_created' => '>' . ( time() - 864000 ),
'status_us' => 'Sent to USA',
);
$orders = wc_get_orders( $args );
foreach ($orders as $order){
$order->update_status( 'completed' );
$order->save();
}
};
function handle_custom_query_var( $query, $query_vars ) {
if ( ! empty( $query_vars['status_us'] ) ) {
$query['meta_query'][] = array(
'key' => 'status_us',
'value' => esc_attr( $query_vars['status_us'] ),
);
}
return $query;
}
add_filter( 'woocommerce_order_data_store_cpt_get_orders_query', 'handle_custom_query_var', 10, 2 );
The above code is TESTED and WORKS.
Proof:
Install WP CRON plugin to check your cron. See above screenshot. You can test by hitting Run Now.
Caveat :
WP Cron runs, when somebody visits your website. Thus if nobody visits, ?>the cron never runs.
Read this : https://wordpress.stackexchange.com/a/179774/204925
Here is what I do to validate orders based on a CRON task.
$order->payment_complete('transaction ID string'); //validate payment
wc_reduce_stock_levels($order->get_id()); //reduce stock
$woocommerce->cart->empty_cart(); //empty cart
$order->update_status('completed', 'A order note string'); //change order statyus
I believe that you don't need the "wc-" prefix.
Are you sure that your scheduled event is working? and that $orders is filled? Please test your method without the schedule first.
a week ago I've started to build a WooCommerce store which should have the option to share orders between two customers. Here is a little diagram I've made for you so you can understand how it should be (Please take a look at it):
So here is what I did step for step
User B clicks a button -> (Save second user id to the order):
$related_order = $_POST['related_order'];
$current_user = wp_get_current_user();
$userID = $current_user->ID;
update_post_meta($related_order, 'second_user_id', $userID);
User B clicks another button -> (Remove second user id from the order)
$related_order = $_POST['related_order'];
$current_user = wp_get_current_user();
$user_id = $current_user->ID;
delete_post_meta($related_order , 'second_user_id');
These two steps (show and hide the order for user B) are working fine - I've tested it. The field gets set and unset.
Now it's getting worse:
I've searched a lot and asked some people to find the function in WooCommerce which gets all orders for a customer. After I found it I've tried to change it so that the second_user_id field gets checked to. I simply thought that I can show the order from customer A to B this way:
function woocommerce_account_orders( $current_page ) {
$current_page = empty( $current_page ) ? 1 : absint( $current_page );
$customer_orders = wc_get_orders( apply_filters( 'woocommerce_my_account_my_orders_query', array(
'customer' => get_current_user_id(),
'second_user_id' => get_current_user_id(),
'page' => $current_page,
'paginate' => true,
) ) );
wc_get_template(
'myaccount/orders.php',
array(
'current_page' => absint( $current_page ),
'customer_orders' => $customer_orders,
'has_orders' => 0 < $customer_orders->total,
)
);
}
The method is located in: https://docs.woocommerce.com/wc-apidocs/source-function-woocommerce_account_orders.html#2465-2486
As you can see I've tried to add the second_user_id to the query which returns the orders for a customer. This is my custom field saved in each order:
[5] => WC_Meta_Data Object (
[current_data:protected] => Array (
[id] => 3477
[key] => second_user_id
[value] => 2
)
After that did not worked I've got help from a friendly guy which told me, that this can't work the way I did it. There are permission which must be given to the user B to view the order from A and a lot of other stuff... So is there someone who can help me with this part? What is wrong with my implementation and how can I change the functionality the way I need it?
if we take look at the responsbile function which WooCommerce use to query the customer you will WooCommerceselect all orders which related to the user based on the user id.
Functions source code:
function woocommerce_account_orders( $current_page ) {
$current_page = empty( $current_page ) ? 1 : absint( $current_page );
$customer_orders = wc_get_orders( apply_filters( 'woocommerce_my_account_my_orders_query', array(
'customer' => get_current_user_id(),
'page' => $current_page,
'paginate' => true,
) ) );
wc_get_template(
'myaccount/orders.php',
array(
'current_page' => absint( $current_page ),
'customer_orders' => $customer_orders,
'has_orders' => 0 < $customer_orders->total,
)
);
}
}
If you want to alter this query and add specific order id's which is not belong to this user beside the default orders we need to do some sort of hack to this query and the possible option i can think of now is by using post__in instead of getting the orders by customer id.
we are going to use the woocommerce_my_account_my_orders_query filter to alter the query.
i will assume the additional orders for that user is stored in wp_usermeta table
The Solution will be:
add_filter( 'woocommerce_my_account_my_orders_query', 'modify_my_order_query' , 20, 1 );
function modify_my_order_query( $q ) {
global $wpdb;
$current_user_id = get_current_user_id();
//Check if the user have addtional orders
$secondary_post_ids = get_user_meta( $current_user_id, 'additional_orders', false );
if ( ! empty( $secondary_post_ids ) ) {
// Get All Orders ID for the main customers
$prepare_query = $wpdb->prepare(
" SELECT post_id FROM {$wpdb->postmeta}
WHERE meta_key LIKE %s and meta_value LIKE %d ",
'_customer_user',
$current_user_id
);
$results = $wpdb->get_results( $prepare_query, ARRAY_A );
$main_post_ids = wp_list_pluck( $results, 'post_id' );
// Merge All Orders IDs
$all_posts_ids = ( isset( $secondary_post_ids[0] ) ) ? array_merge( $main_post_ids, $secondary_post_ids[0] ) : $main_post_ids;
//Modify the my Order Query to include all orders ID including the additional ones
unset( $q['customer'] );
$q['post__in'] = $all_posts_ids;
}
return $q;
}
you will see in the above solution first we check if the current user have additional order if yes then we select all his default orders id and merge the array with his additional order is and then we modified the query so we can get all those orders.
Now the only things left is to allow the user to see his additional orders and to do so we need to use user_has_cap hook.
add_filter( 'user_has_cap', 'give_permissions' , 10, 3 );
function give_permissions( $allcaps, $cap, $args ) {
if ( isset( $cap[0] ) && $cap[0] == 'view_order' ) {
$get_additional_ids = get_user_meta( get_current_user_id(), 'additional_orders', false );
if ( isset( $get_additional_ids[0] ) && in_array( $args[2], $get_additional_ids[0] ) ) {
$allcaps[ $cap[0] ] = true;
}
}
return ( $allcaps );
}
i believe this solution will achieve your target goal.
I am having some trouble customizing the woocommerce templates in my wordpress theme. I would like to add additional data as variables in my templates.
I want to show active orders on the dashboard/my-account page. I want to do this by passing in order data variables to the template to be able to call, like how it is done in the orders.php template.
I know I can override the wc-template-functions.php in my theme and then add the data in the wc_get_templates function for the dashboard or my account. However, I don't want to do this.
What I've tried is creating a hook such as:
functions.php
function wc_fr_add_orders_to_account( $fr_account_orders, $current_page ) {
global $fr_account_orders;
$current_page = empty( $current_page ) ? 1 : absint( $current_page );
$customer_orders = wc_get_orders( apply_filters( 'woocommerce_my_account_my_orders_query',
array(
'customer' => get_current_user_id(),
'page' => $current_page,
'paginate' => true,
'status' => array( 'wc-pending' )
) ) );
$fr_account_orders = array(
'current_page' => absint( $current_page ),
'customer_orders' => $customer_orders,
'has_orders' => 0 < $customer_orders->total
);
return $fr_account_orders;
}
add_action( 'woocommerce_account_content', 'wc_fr_add_orders_to_account' );
/theme-directory/woocommerce/templates/myaccount/dashboard.php (also tried in my-account.php)
do_action( 'woocommerce_account_dashboard', $fr_account_orders);
var_dump($fr_account_orders);
$fr_account_orders comes back null. However if I var_dump the array in the hook function, it comes back with data. Any help is appreciated.
Eaasy there. If you want to return the variable, that's just not the way to do it. You should use the apply_filters like so:
function wc_fr_add_orders_to_account() {
/* your function */
return $fr_account_orders;
}
add_filter( 'woocommerce_account_dashboard', 'wc_fr_add_orders_to_account' );
and in your template..
$my_var = apply_filters( 'woocommerce_account_dashboard', $fr_account_orders );
var_dump( $my_var );
now if you want to send some variables do it like so:
function wc_fr_add_orders_to_account( $var1, $var2 ) {
/* your function */
return $fr_account_orders;
}
add_filter( 'woocommerce_account_dashboard', 'wc_fr_add_orders_to_account', 10, 3 );
and in your template again..
$my_var = apply_filters( 'woocommerce_account_dashboard', $fr_account_orders, $var1, $var2 );
var_dump( $my_var );
read more about apply_filters here https://developer.wordpress.org/reference/functions/apply_filters/ one more thing, try not to change templates, but use add_action on the do_action hooks from template for better compatibility. thanks!
I tried several ways and couldn't figure out how to keep the pagination correct. This way lists all of the orders on my dashboard.
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$args = array(
'posts_per_page' => 3,
'paged' => $paged,
'meta_key' => '_customer_user',
'meta_value' => get_current_user_id(),
'post_type' => wc_get_order_types(),
'post_status' => array ('wc-pending'),
);
$customer_waiting_orders = new WP_Query( $args );
if ( $customer_available_orders->have_posts() ) :
while ( $customer_available_orders->have_posts() ) : $customer_available_orders->the_post();
//code here
wp_reset_postdata();
endwhile;
endif;