Good morning, I'm trying to change the header depending on the category of the single product. i am using Wordpress & WooCommerce
My product categories look like this
- the-lawn-store
- - turf
- - grass-seed
- - wildflower-turf
- the-oak-store
- - railway-sleepers
- - pergolas
Basically when viewing an item which falls under the parent category of the-lawn-store I need the header to be <?php get_header('lawn'); ?> and when the parent category is the-oak-store I need the header to be <?php get_header('oak'); ?>, the difference between headers is the styling of the over all page! what is the best way to go about this?
Well, what you need is the category parent. In order to do that, first of all you can get the parent ID with this:
global $wp_query;
$cat_obj = $wp_query->get_queried_object();
if($cat_obj) {
//print_r($cat_obj);
$category_ID = $cat_obj->term_id;
$category_parent = $cat_obj->parent;
$category_taxonomy = $cat_obj->taxonomy;
$category_parent_term = get_term_by( 'id', absint( $category_ID ), $category_taxonomy );
$category_parent_slug = $category_parent_term->slug;
get_header( $category_parent_slug );
}else{
get_header();
}
Uncomment the print_r to see the rest of available vars. Tested on my local woo and works.
You can't filter the get_header() function so you will have to override WooCommerce's single-product.php template. From there you can modify the beginning of the file:
get_header( 'shop' ); ?>
I created the following function to get the top-level product category for any product:
function kia_get_the_top_level_product_category( $post_id = null ){
$product_cat_parent = null;
if( ! $post_id ){
global $post;
$post_id = $post->ID;
}
// get the product's categories
$product_categories = get_the_terms( $product_id, 'product_cat' );
if( is_array( $product_categories ) ) {
// gets complicated if multiple categories, so limit to one
// on the backend you can restrict to a single category with my Radio Buttons for Taxonomies plugin
$product_cat = array_shift( $product_categories);
$product_cat_id = $product_cat->term_id;
while ($product_cat_id) {
$cat = get_term($product_cat_id, 'product_cat'); // get the object for the product_cat_id
$product_cat_id = $cat->parent; // assign parent ID (if exists) to $product_cat_id
// the while loop will continue whilst there is a $product_cat_id
// when there is no longer a parent $product_cat_id will be NULL so we can assign our $product_cat_parent
$product_cat_parent = $cat->slug;
}
}
return $product_cat_parent;
}
Then in your theme's single-product.php you could do:
$parent = kia_get_the_top_level_product_category();
if( $parent == 'oak' ){
get_header('oak');
} elseif( $parent == 'lawn' ){
get_header('lawn');
} else {
get_header('shop');
}
If you don't have a specific header-shop.php then you could technically also do:
$parent = kia_get_the_top_level_product_category();
get_header( $parent );
Overriding this template might put you at risk when WooCommerce upgrades. As an alternative I would suggest filtering the body class.
function wpa_22066003_body_class($c){
if( function_exists('is_product') && is_product() && $parent = kia_get_the_top_level_product_category() ){
$c[] = $parent . '-product-category';
}
return $c;
}
add_filter( 'body_class', 'wpa_22066003_body_class' );
Related
In woocommerce I am using Hide “remove item” from cart for WooCommerce product category answer code and I would like to disable the cart quantity field too, avoiding customer to change the item quantity to zero.
Is that possible? Any track on this will be appreciated.
The following code will remove the "quantity field" from cart for items from a specific product category (that you will define in the 2nd function):
// Custom conditional function that handle parent product categories too
function has_product_categories( $categories, $product_id = 0 ) {
$parent_term_ids = $categories_ids = array(); // Initializing
$taxonomy = 'product_cat';
$product_id = $product_id == 0 ? get_the_id() : $product_id;
if( is_string( $categories ) ) {
$categories = (array) $categories; // Convert string to array
}
// Convert categories term names and slugs to categories term ids
foreach ( $categories as $category ){
$result = (array) term_exists( $category, $taxonomy );
if ( ! empty( $result ) ) {
$categories_ids[] = reset($result);
}
}
// Loop through the current product category terms to get only parent main category term
foreach( get_the_terms( $product_id, $taxonomy ) as $term ){
if( $term->parent > 0 ){
$parent_term_ids[] = $term->parent; // Set the parent product category
$parent_term_ids[] = $term->term_id; // (and the child)
} else {
$parent_term_ids[] = $term->term_id; // It is the Main category term and we set it.
}
}
return array_intersect( $categories_ids, array_unique($parent_term_ids) ) ? true : false;
}
add_filter( 'woocommerce_quantity_input_args', 'hide_cart_quantity_input_field', 20, 2 );
function hide_cart_quantity_input_field( $args, $product ) {
// HERE your specific products categories
$categories = array( 'clothing' );
// Handling product variation
$product_id = $product->is_type('variation') ? $product->get_parent_id() : $product->get_id();
// Only on cart page for a specific product category
if( is_cart() && has_product_categories( $product_id, $categories ) ){
$input_value = $args['input_value'];
$args['min_value'] = $args['max_value'] = $input_value;
}
return $args;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Note: If you are using also your other answer code, the first function is already defined and doesn"t have to be twice on your function php file…
I want to show two attributes on the category pages, with the attribute name and value only on specific categories.
This code that I found displays the labels of the attributes, but is duplicating the value and I am really struggling with a show if categories variable. Any help is greatly appreciated.
The code:
add_action('woocommerce_after_shop_loop_item','add_attribute');
function add_attribute() {
global $product;
$product_attributes = array( 'pa_set', 'pa_team');
$attr_output = array();
// Loop through the array of product attributes
foreach( $product_attributes as $taxonomy ){
if( taxonomy_exists($taxonomy) ){
$label_name = get_taxonomy( $taxonomy )->labels->singular_name;
$value = $product->get_attribute('pa_set');
if( ! empty($value) ){
// Storing attributes for output
$attr_output[] = '<span class="'.$taxonomy.'">'.$label_name.':
'.$value.'</span>';
}
}
}
// Output attribute name / value pairs separate by a "<br>"
echo '<div class="product-attributes">'.implode( '<br>', $attr_output
).'</div>';
}
Updated - The problem comes from the following line, where the product attribute attribute value is always for the same product attribute:
$value = $product->get_attribute( 'pa_set' );
and it should be this instead:
$value = $product->get_attribute( $taxonomy );
The complete revisited code will be:
add_action('woocommerce_after_shop_loop_item','display_loop_product_attribute' );
function display_loop_product_attribute() {
global $product;
$product_attributes = array('pa_set', 'pa_team'); // Defined product attribute taxonomies.
$attr_output = array(); // Initializing
// Loop through the array of product attributes
foreach( $product_attributes as $taxonomy ){
if( taxonomy_exists($taxonomy) ){
if( $value = $product->get_attribute($taxonomy) ){
// The product attribute label name
$label_name = wc_attribute_label($taxonomy);
// Storing attributes for output
$attr_output[] = '<span class="'.$taxonomy.'">'.$label_name.': '.$value.'</span>';
}
}
}
// Output attribute name / value pairs separate by a "<br>"
echo '<div class="product-attributes">'.implode('<br>', $attr_output).'</div>';
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Targeting Product category archive pages:
You will use the conditional tag is_product_category() inside the function on an IF statement…
For specific product category archive pages, you can set them as explained here inside the function in an array, like:
if( is_product_category( array('chairs', 'beds') ) {
// Here go the code to be displayed
}
You will just need to set the right product categories slugs in the array…
Related: Show WooCommerce product attributes in custom home and product category archives
I have set up a custom user role with a slug of performance_customer. I am checking to see if the current user is a "performance customer" and apply certain price discounts to products in specific categories.
Here is my code:
function return_custom_performance_dealer_price($price, $product) {
global $woocommerce;
global $post;
$terms = wp_get_post_terms( $post->ID, 'product_cat' );
foreach ( $terms as $term ) $categories[] = $term->slug;
$origPrice = get_post_meta( get_the_ID(), '_regular_price', true);
$price = $origPrice;
//check if user role is performance dealer
$current_user = wp_get_current_user();
if( in_array('performance_customer', $current_user->roles)){
//if is category performance hard parts
if(in_array( 'new-hard-parts-150', $categories )){
$price = $origPrice * .85;
}
//if is category performance clutches
elseif(in_array( 'performance-clutches-and-clutch-packs-150', $categories )){
$price = $origPrice * .75;
}
//if is any other category
else{
$price = $origPrice * .9;
}
}
return $price;
}
add_filter('woocommerce_get_price', 'return_custom_performance_dealer_price', 10, 2);
The function works perfectly in the product loop, but when I added a product to the cart it blew up and gave me this error for each line containing if(in_array( 'CATEGORY_NAME_HERE', $categories )){.
Error: Warning: in_array() expects parameter 2 to be array, null given in…
I'm guessing this has to do with the 5th line of the code above where I use wp_get_post_terms() to form an array of the categories that each product belongs to. I'm not sure how to make this work.
First, the filter hook woocommerce_product_get_price is now replacing deprecated hook woocommerce_get_price…
To avoid the error you got you should use Wordpress conditional dedicated function has_term()
I have revisited your code a bit, so please try this instead:
add_filter('woocommerce_product_get_price', 'return_custom_performance_dealer_price', 10, 2);
function return_custom_performance_dealer_price( $price, $product ) {
$price = $product->get_regular_price();
//check if user role is performance dealer
$current_user = wp_get_current_user();
if( in_array('performance_customer', $current_user->roles) ){
//if is category performance hard parts
if( has_term( 'new-hard-parts-150', 'product_cat', $product->get_id() ) ){
$price *= .85;
}
//if is category performance clutches
elseif( has_term( 'performance-clutches-and-clutch-packs-150', 'product_cat', $product->get_id() ) ){
$price *= .75;
}
//if is any other category
else{
$price *= .9;
}
}
return $price;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Tested for WooCommerce 3+… It should work now…
I wan't to restrict certain product pages from logged-out users or users with a specific role. The easiest way would probably be to check the category ID of the product page and if current_user_can('') than redirect to the main shop page.
However I don't really know where to start.. Should I add an action on init? And how do I check for the current page product ID?
I thought I could get some data with a var_dump() But that resulted in nothing.
I did this:
add_action('init', 'get_all_post_meta');
function get_all_post_meta() {
//$meta = get_post_meta( get_the_ID() );
global $post;
var_dump('$post');
$metavar = get_the_terms($post->ID);
var_dump('$metavar');
}
But no results in my console.
Edit: I found my var_dump() was incorrect as it should be like var_dump($post); Continuing my quest now.
This is my solution so far, now I need to figure out how to remove a single product instead of them all.
add_action('wp_head', 'get_all_post_meta', 1 );
function get_all_post_meta() {
global $post;
$banned_cid = array(8);
$current_cid = array();
$metavar = get_the_terms($post->ID, 'product_cat');
global $woocommerce;
$redirect_url = 'http://www.example.nl/';
if(current_user_can('subscriber') || current_user_can('manage_options')){}else if( is_product()){
foreach ( $metavar as $term ) {
$cat_id .= $term->term_id.',';
array_push($current_cid, $term->term_id);
}
var_dump($current_cid);
$c = array_intersect($banned_cid, $current_cid);
if (count($c) > 0) {
$woocommerce->cart->empty_cart();
wp_redirect( $redirect_url, 302 );
exit;
}
}
}
Currently my function only checks if the product is type 'external' before execution, how can I change the function to check if the product is part of a 'grouped' woocommerce product. Then echo the button which contains the parent product permalink which has already been configured.
This is how I would like the code to run (if product is child of grouped product - show permalink button)
I no longer wish to check if the product is type external.
function parent_permalink_button() {
global $post;
if( function_exists('get_product') ){
$product = get_product( $post->ID );
if( $product->is_type( 'external' ) ){
$permalink = get_permalink($post->post_parent);
echo '<a class="button" href="'.$permalink.'">Compare Deals</a>';
}
}
}
I think this might work but will have to test it.
function parent_permalink_button() {
global $post;
if( $post->post_parent != 0 ){
$permalink = get_permalink($post->post_parent);
echo '<a class="button" href="'.$permalink.'">Compare Deals</a>';
}
}