Get and display related products in WooCommerce - php

I have included WooCommerce related products in a theme with the following:
<?php wc_get_template( 'single-product/related.php' ); ?>
This has been copied into my template and is executing.
However, even though I have added various upsells with this product the $related_products variable (used in the loop) is NULL. Is there any other variables at play in order to start showing these related products?

You need much more than that (and the post_id need to be a product):
global $product; // If not set…
if( ! is_a( $product, 'WC_Product' ) ){
$product = wc_get_product(get_the_id());
}
$args = array(
'posts_per_page' => 4,
'columns' => 4,
'orderby' => 'rand',
'order' => 'desc',
);
$args['related_products'] = array_filter( array_map( 'wc_get_product', wc_get_related_products( $product->get_id(), $args['posts_per_page'], $product->get_upsell_ids() ) ), 'wc_products_array_filter_visible' );
$args['related_products'] = wc_products_array_orderby( $args['related_products'], $args['orderby'], $args['order'] );
// Set global loop values.
wc_set_loop_prop( 'name', 'related' );
wc_set_loop_prop( 'columns', $args['columns'] );
wc_get_template( 'single-product/related.php', $args );
Or in a shorter way (which will give you the same):
global $product;
if( ! is_a( $product, 'WC_Product' ) ){
$product = wc_get_product(get_the_id());
}
woocommerce_related_products( array(
'posts_per_page' => 4,
'columns' => 4,
'orderby' => 'rand'
) );
Both ways are tested and works…

Related

WP All Import don't importing values from custom fields

I have custom tab for Frequently Bought Together products in my woocommerce site, that shows up on single product page. When i update products via WP All Import, only one product show up in custom tab and should be a two. Here is the settings of custom fields import and actually view of the single product page.
custom-fields-settings
single-product-accessory-tab
I'll provide Single Product Accessories template, just to make it clear
accessorie template function
global $product;
$loop_columns = apply_filters( 'mc_accessories_loop_columns', 4 );
$posts_per_page = 4;
if ( defined( 'WC_VERSION' ) && version_compare( WC_VERSION, '3.3', '<' ) ) {
global $woocommerce_loop;
$woocommerce_loop['columns'] = $loop_columns;
} else {
wc_set_loop_prop( 'columns', $loop_columns );
}
$product_id = mc_wc_get_product_id( $product );
$accessories = MediaCenter_WC_Helper::get_accessories( $product );
array_unshift( $accessories, $product_id );
if ( sizeof( $accessories ) === 0 && !array_filter( $accessories ) ) {
return;
}
$meta_query = WC()->query->get_meta_query();
$args = apply_filters( 'mc_accessories_query_args', array(
'post_type' => 'product',
'ignore_sticky_posts' => 1,
'no_found_rows' => 1,
'posts_per_page' => $posts_per_page,
'orderby' => 'post__in',
'post__in' => $accessories,
'meta_query' => $meta_query
) );
unset( $args['meta_query'] );
$products = new WP_Query( $args );
$add_to_cart_checkbox = '';
$total_price = 0;
$count = 0;
Any help will be appreciated
Solution is so easy, just need to import post Id's, i lost two weeks on that problem.

Extend WooCommerce product search to custom taxonomies and custom fields

I am creating advance woocommerce search and I want to add sku and product_tag and product_category in search query. Below I am using Enable custom taxonomies in WooCommerce product search answer code, that enable search for multiple taxonomies:
add_filter( 'posts_search', 'woocommerce_search_product_tag_extended', 999, 2 );
function woocommerce_search_product_tag_extended( $search, $query ) {
global $wpdb, $wp;
$qvars = $wp->query_vars;
if ( is_admin() || empty($search) || ! ( isset($qvars['s'])
&& isset($qvars['post_type']) && ! empty($qvars['s'])
&& $qvars['post_type'] === 'product' ) ) {
return $search;
}
// Here set your custom taxonomies in the array
$taxonomies = array('product_tag', 'product_cat');
$tax_query = array('relation' => 'OR'); // Initializing tax query
// Loop through taxonomies to set the tax query
foreach( $taxonomies as $taxonomy ) {
$tax_query[] = array(
'taxonomy' => $taxonomy,
'field' => 'name',
'terms' => esc_attr($qvars['s']),
);
}
// Get the product Ids
$ids = get_posts( array(
'posts_per_page' => -1,
'post_type' => 'product',
'post_status' => 'publish',
'fields' => 'ids',
'tax_query' => $tax_query,
) );
if ( sizeof( $ids ) > 0 ) {
$search = str_replace( 'AND (((', "AND ((({$wpdb->posts}.ID IN (" . implode( ',', $ids ) . ")) OR (", $search);
}
return $search;
}
I want to add product sku too in search query, how to add it ?
The following will extend Product search to multiple taxonomies (Product Category and Product tag) and multiple custom fields (as SKU here):
add_filter( 'posts_search', 'woocommerce_search_product_mega_extended', 999, 2 );
function woocommerce_search_product_mega_extended( $search, $query ) {
global $wpdb, $wp;
$qvars = $wp->query_vars;
if ( is_admin() || empty($search) || ! ( isset($qvars['s'])
&& isset($qvars['post_type']) && ! empty($qvars['s'])
&& $qvars['post_type'] === 'product' ) ) {
return $search;
}
// SETTINGS:
$taxonomies = array('product_tag', 'product_cat'); // Here set your custom taxonomies in the array
$meta_keys = array('_sku'); // Here set your product meta key(s) in the array
// Initializing tax query
$tax_query = count($taxonomies) > 1 ? array('relation' => 'OR') : array();
// Loop through taxonomies to set the tax query
foreach( $taxonomies as $taxonomy ) {
$tax_query[] = array(
'taxonomy' => $taxonomy,
'field' => 'name',
'terms' => esc_attr($qvars['s']),
);
}
// Get the product Ids from taxonomy(ies)
$tax_query_ids = (array) get_posts( array(
'posts_per_page' => -1,
'post_type' => 'product',
'post_status' => 'publish',
'fields' => 'ids',
'tax_query' => $tax_query,
) );
// Initializing meta query
$meta_query = count($meta_keys) > 1 ? array('relation' => 'OR') : array();
// Loop through taxonomies to set the tax query
foreach( $taxonomies as $taxonomy ) {
$meta_query[] = array(
'key' => '_sku',
'value' => esc_attr($qvars['s']),
);
}
// Get the product Ids from custom field(s)
$meta_query_ids = (array) get_posts( array(
'posts_per_page' => -1,
'post_type' => 'product',
'post_status' => 'publish',
'fields' => 'ids',
'meta_query' => $meta_query,
) );
$product_ids = array_unique( array_merge( $tax_query_ids, $meta_query_ids ) ); // Merge Ids in one array with unique Ids
if ( sizeof( $product_ids ) > 0 ) {
$search = str_replace( 'AND (((', "AND ((({$wpdb->posts}.ID IN (" . implode( ',', $product_ids ) . ")) OR (", $search);
}
return $search;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
Related: Enable custom taxonomies in WooCommerce product search

Display related products based on subcategory - woocommerce

I would like to display related products in my single product page that are related to the subcategory and not the parent category. Now i have about 100 products and about 90 of them belong to the same parent category (they also belong to other parent categories). So in a single product page you can see pretty much any random product because of that big parent category.
Is there a way to limit this? I did a research and i came accross some answers that were about version 1.6 of woocommerce... Now i use 3.2.6, so it didn't work.
you can use this code or adapted to work for you case,, hope its work..
Add it to your function.php
add_filter( 'woocommerce_product_related_posts', 'woocommerce_get_direct_related_products' );
function woocommerce_get_direct_related_products() {
global $woocommerce, $product;
// Related products are found from category
$cats_array = array(0);
// Get categories
$terms = wp_get_post_terms( $product->id, 'product_cat' );
//Select only the category which doesn't have any children
foreach ( $terms as $term ) {
$children = get_term_children( $term->term_id, 'product_cat' );
if ( !sizeof( $children ) )
$cats_array[] = $term->term_id;
}
// Don't bother if none are set
if ( sizeof( $cats_array ) == 1 ) return array();
// Meta query
$meta_query = array();
$meta_query[] = $woocommerce->query->visibility_meta_query();
$meta_query[] = $woocommerce->query->stock_status_meta_query();
$limit = 5;
// Get the posts
return array(
'orderby' => 'rand',
'posts_per_page'=> $limit,
'post_type' => 'product',
'fields' => 'ids',
'meta_query' => $meta_query,
'tax_query' => array(
array(
'taxonomy' => 'product_cat',
'field' => 'id',
'terms' => $cats_array
)
)
);
}
This is a possible duplicate of Woocommerce: Only show related products from same subcategory
Another workaround would be to overwrite the template file [your-theme]/woocommerce/single-product/related.php
The following is updated to work with Woocommerce 3.x
<?php
/**
* Related Products
*
* This template can be overridden by copying it to yourtheme/woocommerce/single-product/related.php.
*
* HOWEVER, on occasion WooCommerce will need to update template files and you
* (the theme developer) will need to copy the new files to your theme to
* maintain compatibility. We try to do this as little as possible, but it does
* happen. When this occurs the version of the template file will be bumped and
* the readme will list any important changes.
*
* #see https://docs.woocommerce.com/document/template-structure/
* #author WooThemes
* #package WooCommerce/Templates
* #version 3.9.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
global $product, $woocommerce_loop;
if ( empty( $product ) || ! $product->exists() ) {
return;
}
if ( ! $related = $product->get_related( $posts_per_page ) ) {
return;
}
// Get ID of current product, to exclude it from the related products query
$current_product_id = $product->get_id();
$cats_array = array(0);
// get categories
$terms = wp_get_post_terms( $product->id, 'product_cat' );
// select only the category which doesn't have any children
foreach ( $terms as $term ) {
$children = get_term_children( $term->term_id, 'product_cat' );
if ( !sizeof( $children ) )
$cats_array[] = $term->term_id;
}
$args = apply_filters( 'woocommerce_related_products_args', array(
'post_type' => 'product',
'post__not_in' => array( $current_product_id ), // exclude current product
'ignore_sticky_posts' => 1,
'no_found_rows' => 1,
'posts_per_page' => $posts_per_page,
'orderby' => $orderby,
'tax_query' => array(
array(
'taxonomy' => 'product_cat',
'field' => 'id',
'terms' => $cats_array
),
)
));
$products = new WP_Query( $args );
$woocommerce_loop['name'] = 'related';
$woocommerce_loop['columns'] = apply_filters( 'woocommerce_related_products_columns', $columns );
if ( $products->have_posts() ) : ?>
<section class="related products">
<?php
$heading = apply_filters( 'woocommerce_product_related_products_heading', __( 'Related products', 'woocommerce' ) );
if ( $heading ) :
?>
<h2><?php echo esc_html( $heading ); ?></h2>
<?php endif; ?>
<?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(); ?>
</section>
<?php endif;
wp_reset_postdata();

Changing custom field value for WooCommerce order based on product variations in order

In WooCommerce with Advanced Custom Fields plugin, I am creating a function to up date a custom field for subscription orders on a WooCommerce store selling a print magazine. This function will update the 'starting_issue' field for subscription orders with the name for a single issue product depending on whether the user has opted to start their subscription from the previous, current or next issue of the magazine (chosen as a product variation for three different types of subscription products).
I have coded the function as follows but on any test orders I am completing, with changed attempted to the code below, it does not work as required - not updating the 'starting_issue' meta field for orders.
I have built similar functions before to auto-complete orders based on set conditions. I am struggling to see why this particular function is not working but I know I may be missing something very crucial.
The code I have written is:
/*** UPDATE 'STARTING ISSUE' FIELD FOR ORDERS ***/
// Club membership ID = '7968'
// Subscription (non-gift) ID = '13962'
// Subscription (gift) ID = '13966'
add_action( 'first_issue_for_subs', 'first_issue_for_subs' );
function first_issue_for_subs( $order_id ) {
if ( ! $order_id ) { return; }
global $woocommerce;
$order = new WC_Order( $order_id );
foreach( $order->get_items() as $item ) {
if ( ( $item['product_id'] == '7968' ) or ( $item['product_id'] == '13962' ) or ( $item['product_id'] == '13966' ) ) {
$product = wc_get_product( $item['product_id'] );
$variations = $product->children;
foreach ( $variations as $variation ) {
$variation_id = $variation->variation_id;
if ( $variation_id == '16171' or $variation_id == '16174' or $variation_id == '16168' ) {
// Current Issue
$current_args = [
'posts_per_page' => 1,
'post_type' => 'product',
'tax_query' => array( array( 'taxonomy' => 'product_cat', 'field' => 'slug', 'terms' => 'single_issues' ) ),
];
$current_query = get_posts( $current_args );
foreach ( $current_query as $queried_issue ) {
$first_issue = the_title();
$order->update_field( 'starting_issue', $first_issue );
}
}
elseif ( $variation_id == '16167' or $variation_id == '16170' or $variation_id == '16173' ) {
// Next Issue
$next_args = [
'posts_per_page' => 1,
'post_status' => 'draft',
'post_type' => 'product',
'tax_query' => array( array(
'taxonomy' => 'product_cat',
'field' => 'slug',
'terms' => 'single_issues'
) ),
'orderby' => 'date',
'order' => 'ASC',
];
$next_query = get_posts( $next_args );
foreach ( $next_query as $queried_issue ) {
$first_issue = the_title();
$order->update_field( 'starting_issue', $first_issue );
}
}
elseif ( $variation_id == '6169' or $variation_id == '16172' or $variation_id == '16166' ) {
// Previous Issue - gift
$previous_args = [
'posts_per_page' => 2,
'offset' => 1,
'post_type' => 'product',
'tax_query' => array( array(
'taxonomy' => 'product_cat',
'field' => 'slug',
'terms' => 'single_issues'
) ),
];
$previous_query = get_posts( $previous_args );
foreach ( $previous_query as $queried_issue ) {
$first_issue = the_title();
$order->update_field( 'starting_issue', $first_issue );
}
}
}
} else {
$first_issue = 'NOT_SUBSCRIPTION';
$order->update_field( 'starting_issue', $first_issue );
}
}
}
Can anybody shed some light on this? Many thanks in advance for any help.

wordpress add field for every custom type

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

Categories