Customizing and adding woocommerce template data - php

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;

Related

Listing WooCommerce best selling products without a shortcode

So, I have been trying to do exactly the same thing as the [products limit="10" columns="4" best_selling="true" ] shortcode does.
I need to implement it to a php page template, but I have read that do_shortcode is bad practice, and I would like to do it the right way.
This is what I have so far, but where do I go from here?
$args = array(
'limit' => '10',
'columns' => '4',
'orderby' => 'total_sales',
'order' => 'DESC',
);
$products = wc_get_products( $args );
If I understand it correctly this will save the 10 best selling products, descending by the number of total sales into $products. Is this not correct?
How do I show the actual product listings from $products correctly (just like the shortcode would do)?
total_sales can be set in the query using meta_key.
Once you return the results from the query, you just need to loop through them and output whatever attributes you need.
$args = array(
'limit' => '10',
'orderby' => array( 'meta_value_num' => 'DESC', 'title' => 'ASC' ),
'meta_key' => 'total_sales',
);
$query = new WC_Product_Query( $args );
$products = $query->get_products();
if ( $products ) {
foreach ( $products as $product ) {
echo $product->get_name(); // Here, we're just listing each product's name
}
} else {
echo __( 'No products found' );
}
Update
With this update, we're now using the results from wc_get_products() on a custom page template adapted from archive-product.php. The goal here was to avoid using WP_Query/get_posts(), as they are not recommended for product querying.
wc_get_products and WC_Product_Query provide a standard way of retrieving products that is safe to use and will not break due to database changes in future WooCommerce versions. Building custom WP_Queries or database queries is likely to break your code in future versions of WooCommerce as data moves towards custom tables for better performance. This is the best-practices way for plugin and theme developers to retrieve multiple products. wc_get_products and WC_Product_Query are similar to WordPress get_posts and WP_Query. Just like those, you pass in an array of arguments defining the criteria for the search.
We're now able to get the same layout/styles that normal product category/archive pages have, but with our top-sellers query. We have the product title, image, price, and add-to-cart button and all of the WooCommerce/theme styles applied without having to build everything from scratch as with the previous method (above).
Tested and working in WooCommerce 3.5.6
defined( 'ABSPATH' ) || exit;
get_header( 'shop' );
do_action( 'woocommerce_before_main_content' );
?>
<header class="woocommerce-products-header">
<?php if ( apply_filters( 'woocommerce_show_page_title', true ) ) : ?>
<h1 class="woocommerce-products-header__title page-title"><?php echo get_the_title(); ?></h1>
<?php endif; ?>
</header>
<?php
if ( ! function_exists( 'wc_get_products' ) ) {
return;
}
echo '<div class="woocommerce">'; // needed for default styles
$top_selling_products = wc_get_products( array(
'meta_key' => 'total_sales', // our custom query meta_key
'return' => 'ids', // needed to pass to $post_object
'orderby' => array( 'meta_value_num' => 'DESC', 'title' => 'ASC' ), // order from highest to lowest of top sellers
) );
if ( $top_selling_products ) {
do_action( 'woocommerce_before_shop_loop' );
woocommerce_product_loop_start();
foreach ( $top_selling_products as $top_selling_product ) {
$post_object = get_post( $top_selling_product );
setup_postdata( $GLOBALS['post'] =& $post_object );
do_action( 'woocommerce_shop_loop' );
wc_get_template_part( 'content', 'product' );
}
wp_reset_postdata();
woocommerce_product_loop_end();
do_action( 'woocommerce_after_shop_loop' );
} else {
do_action( 'woocommerce_no_products_found' );
}
echo '</div><!-- .woocommerce -->';
do_action( 'woocommerce_after_main_content' );
do_action( 'woocommerce_sidebar' );
get_footer( 'shop' );

wc_get_template for orders.php page not working

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);

Create shortcode for displaying woocommers users order history

I'm trying to write a shortcode to display users woocommerce order history.
I've found an answer here in woocommerce, is there a shortcode/page to view all orders? , but that does'nt work anymore.
If i follow the current answer it gives me a fatal error.
Fatal error: Call to undefined function wc_get_account_orders_actions() in /wp-content/themes/wrapgate/woocommerce/myaccount/my-orders.php on line 72
Anybody knows updated code to get my shortcode to work?
Here's the shortcode function i've tried
add_shortcode( 'woocommerce_history', 'woo_order_history' );
function woo_order_history() {
ob_start();
wc_get_template( 'myaccount/my-orders.php', array(
'current_user' => get_user_by( 'id', get_current_user_id() ),
'order_count' => -1
));
return ob_get_clean();
}
Same error occurs if i try to use
woocommerce_account_orders( -1 );
Woocommerce as well as wordpress are on the latest version.
I've tried to call the shortcode function from my themes functions.php
Thanks in advance for every help.
my-orders.php is deprecated after version 2.6.0. Woocommerce my-account uses orders.php now. To create a shortcode to display order history
function woo_order_history( $atts ) {
extract( shortcode_atts( array(
'order_count' => -1
), $atts ) );
ob_start();
$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,
)
);
return ob_get_clean();
}
add_shortcode('woocommerce_history', 'woo_order_history');
Add this code to your theme->functions.php or child-theme->functions.php (if you have child theme enabled).
Now where you want to display the order just add the shortcode [woocommerce_history]

Display only completed orders on my Woocommerce accounts page

In the account area of my woocommerce shopping site you can click 'orders' and see your order i.e. completed, cancelled, on hold etc etc.
However when you click 'collection' (a page I have made within the account area) I want it to display only 'completed' items.
I have tried to put the following code into the functions.php but with no luck:
(ref - https://businessbloomer.com/woocommerce-display-products-purchased-user/)
add_shortcode( 'my_products', 'bbloomer_user_products_bought' );
function bbloomer_user_products_bought() {
global $product, $woocommerce, $woocommerce_loop;
$columns = 3;
$current_user = wp_get_current_user();
$args = array(
'post_type' => 'product',
'post_status' => 'publish',
'meta_query' => array(
array(
'key' => '_visibility',
'value' => array('catalog', 'visible'),
'compare' => 'IN'
)
)
);
$loop = new WP_Query($args);
ob_start();
woocommerce_product_loop_start();
Loop part
while ( $loop->have_posts() ) : $loop->the_post();
$theid = get_the_ID();
if ( wc_customer_bought_product( $current_user->user_email, $current_user->ID, $theid ) ) {
wc_get_template_part( 'content', 'product' );
}
endwhile;
woocommerce_product_loop_end();
woocommerce_reset_loop();
wp_reset_postdata();
return '<div class="woocommerce columns-' . $columns . '">' . ob_get_clean() . '</div>';
}
and then adding the shortcode:
[my_products]
when you click the collection link it does not display anything - well generates a div with nothing in it!
Is there a better way of doing this or a alternative?
Replace your $args with bellow code
$args = array(
'post_type' => 'shop_order',
'post_status' => 'wc-completed'
);
Then let me know the result. Thanks

woocommerce custom admin tab breaks variations

I've added the ability to choose from custom post types in the woocommerce product admin tabs with a function as used in this tutorial http://www.remicorson.com/mastering-woocommerce-products-custom-fields/
so I've added a custom field
woocommerce_wp_select(
array(
'id' => '_circuit',
'label' => __( 'choose circuit', 'woocommerce' ),
'options' => get_circuits_as_array()
)
);
now the function looks like this
function get_circuits_as_array(){
$args = array( 'post_type' => 'top', 'posts_per_page' => -1, 'post_status'=>'published' );
$loop = new WP_Query( $args );
$circuits = array('0'=>'--wybierz opcję--');
while ( $loop->have_posts() ) : $loop->the_post();
setup_postdata( $post );
$circuits[get_the_id()] = get_the_title();
endwhile;
wp_reset_query();
return $circuits;
}
The problem is that while uploading the code to the server this function breaks the variations window it shows only the default "add variations message"
The console shows no errors.
I guess this has something to do with ajax requests but cant figure out exactly what, I've tries to move the get function in other files etc. but no luck.
The woocommerce plugin version is 2.2.8
OK so I've figured this out and the workaround is to use a foreach loop with $loop->posts as the array
function get_circuits_as_array(){
$args = array( 'post_type' => 'top', 'posts_per_page' => -1, 'post_status'=>'published' );
$loop = new WP_Query( $args );
$circuits = array('0'=>'--wybierz opcję--');
foreach ($loop->posts as $circuit) {
$circuits[$circuit->ID] = $circuit->post_title;
}
wp_reset_query();
return $circuits;
}

Categories