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
Related
I've been struggling applying filters to my woocommerce shop. I have a website with multiple store pages and I've found a filter to only shop products published within the last 30 days. I want this filter to only apply to the 'new releases' shoppage, not to the whole website. Currently it's filtering everything, so even pages created before last month won't appear for example.
How do I make sure this filter is only applied to 1 store? Can I apply an IF statement and check current URL before the filter works or something?
Any help is appreciated.
Filter: (from https://www.sitepoint.com/community/t/show-latest-30-days-products-in-woocommerce/258276)
function baba_recent_products() {
//return 'This is where the recent products should show up if I get the shortcode working. ';
global $woocommerce_loop;
extract( shortcode_atts( array(
'per_page' => '48',
'columns' => '2',
'orderby' => 'date',
'order' => 'desc'
), $atts ) );
$meta_query = WC()->query->get_meta_query();
$args = array(
'post_type' => 'product',
'post_status' => 'publish',
'ignore_sticky_posts' => 1,
'posts_per_page' => $per_page,
'orderby' => $orderby,
'order' => $order,
'meta_query' => $meta_query
);
ob_start();
$products = new WP_Query( apply_filters( 'woocommerce_shortcode_products_query', $args, $atts ) );
$woocommerce_loop['columns'] = $columns;
if ( $products->have_posts() ) : ?>
<?php woocommerce_product_loop_start(); ?>
<?php while ( $products->have_posts() ) : $products->the_post(); ?>
<?php wc_get_template_part( 'content', 'product' ); ?>
<?php endwhile; // end of the loop. ?>
<?php woocommerce_product_loop_end(); ?>
<?php endif;
wp_reset_postdata();
return '<div class="woocommerce columns-' . $columns . '">' . ob_get_clean() . '</div>';
}
add_shortcode( 'baba_recent_products', 'baba_recent_products' );
function filter_where($where = '') {
//posts in the last 30 days
$where .= " AND post_date > '" . date('Y-m-d', strtotime('-30 days')) . "'";
return $where;
}
add_filter('posts_where', 'filter_where');
function baba_recent_products() {
//return 'This is where the recent products should show up if I get the shortcode working. ';
global $woocommerce_loop;
extract( shortcode_atts( array(
'per_page' => '48',
'columns' => '2',
'orderby' => 'date',
'order' => 'desc'
), $atts ) );
$meta_query = WC()->query->get_meta_query();
$args = array(
'post_type' => 'product',
'post_status' => 'publish',
'ignore_sticky_posts' => 1,
'posts_per_page' => $per_page,
'orderby' => $orderby,
'order' => $order,
'meta_query' => $meta_query
);
ob_start();
$products = new WP_Query( apply_filters( 'woocommerce_shortcode_products_query', $args, $atts ) );
$woocommerce_loop['columns'] = $columns;
if ( $products->have_posts() ) : ?>
<?php woocommerce_product_loop_start(); ?>
<?php while ( $products->have_posts() ) : $products->the_post(); ?>
<?php wc_get_template_part( 'content', 'product' ); ?>
<?php endwhile; // end of the loop. ?>
<?php woocommerce_product_loop_end(); ?>
<?php endif;
wp_reset_postdata();
return '<div class="woocommerce columns-' . $columns . '">' . ob_get_clean() . '</div>';
}
add_shortcode( 'baba_recent_products', 'baba_recent_products' );
function filter_where($where = '') {
global $post;
if($post->ID === /*Page ID as int here*/){
//posts in the last 30 days
$where .= " AND post_date > '" . date('Y-m-d', strtotime('-30 days')) . "'";
}
return $where;
}
add_filter('posts_where', 'filter_where');
I trying to get products by post author id using a WC_Query in WooCommerce, so I tried to include a new custom meta_key "_author", with the following:
add_filter( 'woocommerce_product_data_store_cpt_get_products_query', 'handling_custom_meta_query_keys', 10, 3 );
function handling_custom_meta_query_keys( $wp_query_args, $query_vars ) {
$meta_key = '_author';
if ( ! empty( $query_vars[$meta_key] ) ) {
$wp_query_args['meta_query'][] = array(
'key' => $meta_key,
'value' => esc_attr( $query_vars[$meta_key] ),
'operator' => '==',
);
}
return $wp_query_args;
}
Then I tried to use it with wc_get_products():
$product_list = wc_get_products( array('_author' => get_current_user_id()) );
but it return null array. Any idea?
You can simply get products by author Id in a WC_Query using the undocumented parameter "author'" as follow:
$products = wc_get_products( array(
'status' => 'publish',
'limit' => -1,
'author' => get_current_user_id()
) );
You will get an array of WC_Product Objects
You can use custom query like this
<?php
$authorID = get_the_author_meta('ID');
$args = array(
'post_type' => 'product',
'post_status' => 'publish'
'posts_per_page' => 12,
'product_cat' => 'pants'
'author' => $authorID
);
$loop = new WP_Query( $args );
?>
<div class="author_products">
<?php if ( $loop->have_posts() ) { ?>
<ul class="author_pubproducts">
<?php while ( $loop->have_posts() ) : $loop->the_post();
woocommerce_get_template_part( 'content', 'product' );
endwhile; ?>
</ul>
<?php
} else {
echo __( 'No products found', 'textdomain' );
}
wp_reset_postdata();
?>
Hope it's work
I want to add Featured products for upsell (or Recent Products OR Best Selling Products) in New order Email template. It works like Upsell with email marketing. How do I add it to woocommerce email template so that there is a section in the end of the email which shows my featured/Recent/best selling products. I tried using this code in my New order Email template but nothing works. I use all latest version of wordpress n woocommerce.
$args = array(
'post_type' => 'product',
'meta_key' => '_featured',
'meta_value' => 'yes',
'posts_per_page' => 1
);
$featured_query = new WP_Query( $args );
if ($featured_query->have_posts()) :
while ($featured_query->have_posts()) :
$featured_query->the_post();
$product = get_product( $featured_query->post->ID );
// Output product information here
endwhile;
endif;
wp_reset_query(); // Remember to reset
Since Woocommerce 3, the products following properties:
"featured",
"stock status",
"catalog visibility"
"rating system"
are now stored like a post term under 'product_visibility' taxonomy, for better performances. So old postmeta data doesn't work anymore.
To make your code working you need instead to make a tax_query this way:
function custom_featured_products(){
$query = new WP_Query( array(
'post_type' => 'product',
'post_status' => 'publish',
'posts_per_page' => -1 ,
'tax_query' => array( array(
'taxonomy' => 'product_visibility',
'field' => 'term_id',
'terms' => 'featured',
'operator' => 'IN',
) )
) );
$featured_product_names = array();
if ( $query->have_posts() ): while ( $query->have_posts() ): $query->the_post();
$product = wc_get_product( $query->post->ID );
$featured_product_names[] = $product->get_title();
endwhile; wp_reset_query();endif;
// Testing output
echo '<p>Featured products: ' . implode(', ', $featured_product_names) . '</p>';
}
// Displaying the featured products names in new order email notification
add_action ('woocommerce_email_customer_details', 'new_order_featured_products_display', 30, 4 );
function new_order_featured_products_display( $order, $sent_to_admin, $plain_text, $email ){
// Only for "New Order" email notification
if( 'new_order' != $email->id ) return;
custom_featured_products(); // calling the featured products function output
}
This code goes on function.php file of your active child theme (or theme).
Tested and works.
Updated related to your comments…
Added the code in a function that is called via a hooked function in "New order" email notification.
To get the product image use: $product->get_image( 'shop_thumbnail' );
To get the product link use : $product->get_permalink();
<ul class="products">
<?php
$args = array(
'post_type' => 'product',
'posts_per_page' => 12,
'tax_query' => array(
array(
'taxonomy' => 'product_visibility',
'field' => 'name',
'terms' => 'featured',
),
),
);
$loop = new WP_Query( $args );
if ( $loop->have_posts() ) {
while ( $loop->have_posts() ) : $loop->the_post();
echo '<p>'.get_the_title().'</p>';
endwhile;
} else {
echo __( 'No products found' );
}
wp_reset_postdata();
?>
</ul><!--/.products-->
I want to create a stock level field in WooCommerce Products for every Store custom post type.
I've already created the Store custom post type and added 3 stores to it. I want to automatically add a "stock level at store" field every time someone adds a Store so that I could check the stocks at store level.
I'm trying to put the custom field at the Products->Inventory-> right under the Stock Quantity.
I've tried this:
$post_type = 'store';
$tax = 'show-topic';
$inv_arg_terms = get_terms(array('orderby' => 'id', 'order' => 'ASC'));
if ($inv_arg_terms) {
$args = array(
'post_type' => $post_type,
'post_status' => 'publish',
'posts_per_page' => - 1,
'orderby' => 'title',
'order' => 'ASC'
); // END $args
$my_query = null;
$my_query = new WP_Query($args);
if ($my_query->have_posts()) {
while ($my_query->have_posts()) : $my_query->the_post();
add_action( 'woocommerce_product_options_inventory_product_data', 'wc_inventory_stock_product_field' );
function wc_inventory_stock_product_field() {
woocommerce_wp_text_input( array( 'id' => 'stock_level_' . the_title(), 'class' => 'short wc_input_stock', 'label' => __( 'Stock Level at ' . the_title(), 'woocommerce' ) . ' (' . get_woocommerce_currency_symbol() . ')' ) );
}
add_action( 'save_post', 'wc_cost_save_product' );
function wc_cost_save_product( $product_id ) {
// stop the quick edit interferring as this will stop it saving properly, when a user uses quick edit feature
if (wp_verify_nonce($_POST['_inline_edit'], 'inlineeditnonce'))
return;
// If this is a auto save do nothing, we only save when update button is clicked
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return;
if ( isset( $_POST['stock_level_' . the_title()] ) ) {
if ( is_numeric( $_POST['stock_level_' . the_title()] ) )
update_post_meta( $product_id, 'stock_level_' . the_title(), $_POST['cost_price'] );
} else delete_post_meta( $product_id, 'stock_level_' . the_title() );
}
endwhile;
} // END if have_posts loop
wp_reset_query();
} // END if $inv_arg_terms
and I got this:
Fatal error: Call to undefined function get_userdata() in
.../wp-includes/query.php on line 4758
Is what I'm thinking possible? How do I go about it?
Thanks, appreciate every help I could get.
Finally got it to work. Here's the code:
add_action( 'woocommerce_product_options_inventory_product_data', 'wc_stock_product_field' );
add_action( 'woocommerce_process_product_meta', 'wc_stock_save_product' );
function wc_stock_product_field() {
global $woocommerce, $post;
$post_type = 'store';
$args = array(
'post_type' => $post_type,
'post_status' => 'publish',
'posts_per_page' => - 1,
'orderby' => 'id',
'order' => 'ASC',
'caller_get_posts' => 1
); // END $args
$store_query = null;
$store_query = new WP_Query($args);
if ($store_query->have_posts()) {
while ($store_query->have_posts()) : $store_query->the_post();
woocommerce_wp_text_input(
array(
'id' => get_the_id() ,
'class' => 'short wc_input_stock',
'label' => __( 'Stock Level # ' . get_the_title(), 'woocommerce' ) ) );
endwhile;
} // END if have_posts loop
wp_reset_query();
}
function wc_stock_save_product( $product_id ) {
// stop the quick edit interferring as this will stop it saving properly, when a user uses quick edit feature
if (wp_verify_nonce($_POST['_inline_edit'], 'inlineeditnonce'))
return;
// If this is a auto save do nothing, we only save when update button is clicked
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return;
$post_type = 'store';
$args = array(
'post_type' => $post_type,
'post_status' => 'publish',
'posts_per_page' => - 1,
'orderby' => 'id',
'order' => 'ASC',
'caller_get_posts' => 1
); // END $args
$store_query = null;
$store_query = new WP_Query($args);
if ($store_query->have_posts()) {
while ($store_query->have_posts()) : $store_query->the_post();
if ( isset( $_POST[get_the_id()] ) ) {
if ( is_numeric( $_POST[get_the_id()] ) )
update_post_meta( $product_id, get_the_id(), $_POST[get_the_id()] );
} else delete_post_meta( $product_id, get_the_id() );
endwhile;
} // END if have_posts loop
wp_reset_query();
}
I've recently had a lot of help creating an upcoming events list (see here Showing upcoming events (including todays event)?), as a result my pagination using WP Pagenavi is broken.
At the moment, when you click on page 2 it just shows the same posts as page one. Although the URL does actually change to page/2 page/3 etc.
I have this in my functions.php file:
function filter_where( $where = '' ) {
$where .= " AND post_date >= '" . date("Y-m-d") . "'";
return $where;
}
add_filter( 'posts_where', 'filter_where' );
$query = new WP_Query(
array(
'post__not_in' => array(4269),
'paged' => get_query_var('paged'),
'post_type' => 'whatson',
'exclude' => '4269',
'post_status' => 'future,publish',
'posts_per_page' => 20,
'order' => 'ASC'
)
);
remove_filter( 'posts_where', 'filter_where' );
My loop is then as follows:
<?php while ( $query->have_posts() ) : $query->the_post(); ?>
// content
<?php endwhile; // end of the loop. ?>
<?php if (function_exists('wp_pagenavi')) { wp_pagenavi( array( 'query' => $query ) ); } ?>
Finally solved this with:
function my_filter_where( $where = '' ) {
global $wp_query;
if (is_array($wp_query->query_vars['post_status'])) {
if (in_array('future',$wp_query->query_vars['post_status'])) {
// posts today into the future
$where .= " AND post_date > '" . date('Y-m-d', strtotime('now')) . "'";
}
}
return $where;
}
add_filter( 'posts_where', 'my_filter_where' );
And:
<?php
$wp_query = array(
'post__not_in' => array(4269),
'paged' => get_query_var('paged'),
'post_type' => 'whatson',
'exclude' => '4269',
'posts_per_page' => 20,
'order' => 'ASC',
'orderby' => 'date',
'post_status' =>array('future','published'));
query_posts($wp_query);
?>
<?php
if ($wp_query->have_posts()) {
while ( $wp_query->have_posts() ) : $wp_query->the_post(); ?>
Content
<?php endwhile; // end of the loop.
} ?>
<?php if (function_exists('wp_pagenavi')) { wp_pagenavi( array( 'query' => $wp_query ) ); } ?>
Do you want it for specific post or for all of them ? If you want general pagination you can make pagination links without plugins with this piece of code :
<?php
global $wp_query;
$big = 999999999; // need an unlikely integer
echo paginate_links( array(
'base' => str_replace( $big, '%#%', get_pagenum_link( $big ) ),
'format' => '?paged=%#%',
'current' => max( 1, get_query_var('paged') ),
'total' => $wp_query->max_num_pages
) );
?>
Just add it to your index.php or archives.php and see the magic happens :)
I am not sure what is going on with the rest of your code, but one thing to try that would be a simple test would be to use wp_reset_query() before your new WP_Query just to make sure that the query variables have not been modified.