Editing Woocommerce category/subcategory loop - wordpress

I'm currently building a custom WP theme with WooCommerce integration. So a little background first. My theme is using Foundation 6. I have disabled the WooCommerce styles and layouts. I am using overriding templates so that I can integrate Foundation.
My shop page is listing product categories, not individual products. Then once a category is selected, you get another list of sub-categories, then finally the products.
I'm able to put the products into 4 column rows just fine with the following code:
loop-start.php
<div class="row">
archive-product.php
<?php woocommerce_product_loop_start(); ?>
<?php woocommerce_product_subcategories(); ?>
<?php $counter = 1; while ( have_posts() ) : the_post(); ?>
<?php wc_get_template_part( 'content', 'product' ); ?>
<?php
if( $counter % 4 == 0 ) : echo '</div><div class="row">'; endif;
$counter++;
endwhile; // end of the loop. ?>
<?php woocommerce_product_loop_end(); ?>
loop-end.php
</div>
content-product.php
<div <?php if($wcp_last_loop) : post_class('medium-3 columns end'); else : post_class('medium-3 columns'); endif; ?>>
<?php
/**
* woocommerce_before_shop_loop_item hook.
*
* #hooked woocommerce_template_loop_product_link_open - 10
*/
do_action( 'woocommerce_before_shop_loop_item' );
/**
* woocommerce_before_shop_loop_item_title hook.
*
* #hooked woocommerce_show_product_loop_sale_flash - 10
* #hooked woocommerce_template_loop_product_thumbnail - 10
*/
do_action( 'woocommerce_before_shop_loop_item_title' );
/**
* woocommerce_shop_loop_item_title hook.
*
* #hooked woocommerce_template_loop_product_title - 10
*/
do_action( 'woocommerce_shop_loop_item_title' );
/**
* woocommerce_after_shop_loop_item_title hook.
*
* #hooked woocommerce_template_loop_rating - 5
* #hooked woocommerce_template_loop_price - 10
*/
do_action( 'woocommerce_after_shop_loop_item_title' );
/**
* woocommerce_after_shop_loop_item hook.
*
* #hooked woocommerce_template_loop_product_link_close - 5
* #hooked woocommerce_template_loop_add_to_cart - 10
*/
do_action( 'woocommerce_after_shop_loop_item' );
?>
</div>
So this works great for products not categories though. I know the categories and subcategories are being pulled in by
<?php woocommerce_product_subcategories(); ?>
I also know I will have to use a hook or filter to put every 4 categories in a row, but I'm not well versed in WP hooks and filters, so are struggling to find a solution. I've been trying to read up on hooks and filters, but are hoping to find some help more specific to what I'm trying to do.
Any advice would be greatly appreciated.

So I did end up finding a solution, not sure if it is the best route to go but it worked.
For others who may run into the same issue, here is what I did.
Located the woocommerce_product_subcategories() in wc-template-functions.php. Copy the entire function, including the check to see if it exists.
Paste into your functions.php file. Rename the function, for example:
function new_name_product_subcategories( $args = array() ) { .... }
Look for the following foreach loop:
foreach ( $product_categories as $category ) {
wc_get_template( 'content-product_cat.php', array(
'category' => $category
) );
}
and change to:
$cat_counter = 1;
foreach ( $product_categories as $category ) {
wc_get_template( 'content-product_cat.php', array(
'category' => $category
) );
if( $cat_counter % 4 == 0 ) : echo '</div><div class="row">'; endif;
$cat_counter++;
}
Then in your archive-product.php file, change:
<?php woocommerce_product_subcategories(); ?>
To
<?php new_name_product_subcategories(); ?>
If I find a way to do via WP hooks, I will post a reply, but this was the only way I could think to do it as of now.
Also, I didn't go over how I added the .columns classes the individual categories. I added those in the content-product_cat.php file.

Related

Where I can get the location of wc_get_template_part( 'content', 'product' )

I have created the custom shop page in wooommerce and I removed all the code from then archive-product.php and added the below code and it's displaying the products.
defined( 'ABSPATH' ) || exit;
get_header( 'shop' );
/**
* Hook: woocommerce_before_main_content.
*
* #hooked woocommerce_output_content_wrapper - 10 (outputs opening divs for the content)
* #hooked woocommerce_breadcrumb - 20
* #hooked WC_Structured_Data::generate_website_data() - 30
*/
do_action( 'woocommerce_before_main_content' );
?>
<div class="container">
<div class="products">
<div class="row">
<?php
$args = array(
'post_type' => 'product',
'posts_per_page' => 12
);
$loop = new WP_Query( $args );
if ( $loop->have_posts() ) {
while ( $loop->have_posts() ) : $loop->the_post();
wc_get_template_part( 'content', 'product' );
endwhile;
} else {
echo __( 'No products found' );
}
wp_reset_postdata();
?>
</div>
</div>
</div>
<?php
get_footer( 'shop' );
Now Where I will get the code of this wc_get_template_part( 'content', 'product' ); because I have to change the strcture
Below screenshot is the woocommerce template.
As it's used inside the product loop, the template file that is called in:
wc_get_template_part( 'content', 'product' );
is content_product.php located in the woocommerce plugin folder > templates subfolder (Take a look to the code on HERE).
Note: you can override WooCommerce templates via your active child theme (or active theme) or use all available hooks in the template content_product.php.
For the displayed thumbnail:
You can see on content_product.php template this:
/**
* Hook: woocommerce_before_shop_loop_item_title.
*
* #hooked woocommerce_show_product_loop_sale_flash - 10
* #hooked woocommerce_template_loop_product_thumbnail - 10 // <=== HERE
*/
do_action( 'woocommerce_before_shop_loop_item_title' );
So Image is called via the template function woocommerce_template_loop_product_thumbnail() and that function call woocommerce_get_product_thumbnail() function:
/**
* Get the product thumbnail, or the placeholder if not set.
*
* #param string $size (default: 'woocommerce_thumbnail').
* #param int $deprecated1 Deprecated since WooCommerce 2.0 (default: 0).
* #param int $deprecated2 Deprecated since WooCommerce 2.0 (default: 0).
* #return string
*/
function woocommerce_get_product_thumbnail( $size = 'woocommerce_thumbnail', $deprecated1 = 0, $deprecated2 = 0 ) {
global $product;
$image_size = apply_filters( 'single_product_archive_thumbnail_size', $size );
return $product ? $product->get_image( $image_size ) : '';
}
}
Related: WooCommerce action hooks and overriding templates

Add custom message based on product tag in WooCommerce email notification

I want to add unique text to WooCommerce's "order complete" email but ONLY when the product purchased has a certain product tag.
If the item purchased has the "fundraiser" tag I want the email to include text thanking them for supporting our fundraisers. Long story but we can't use categories for this and we must use tags.
I've tried editing the customer-complete-order.php file and this works, however I'm not good with PHP code and there are no examples of how to call the tags.
I've also tried editing functions.php based upon what someone else did and this is as far as I've gotten.
function woocommerce_custom_email_per_product_depending_on_product_tag( $email_heading, $order ) {
global $woocommerce;
$items = $order->get_items();
foreach ( $items as $item ) {
$product_tag = $item['product_tag'];
if ( $product_tag == fundraiser ) {
$email_body = 'Thanks for buying a fundraiser.';
}
return $email_heading;
} }
or perhaps it would be better to define this custom text in a new email template? Here's the order confirmation template as woocommerce provides it.
<?php
/**
* Customer completed order email
*
* This template can be overridden by copying it to yourtheme/woocommerce/emails/customer-completed-order.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/
* #package WooCommerce/Templates/Emails
* #version 3.5.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/*
* #hooked WC_Emails::email_header() Output the email header
*/
do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
<?php /* translators: %s: Customer first name */ ?>
<p><?php printf( esc_html__( 'Hi %s,', 'woocommerce' ), esc_html( $order->get_billing_first_name() ) ); ?></p>
<?php /* translators: %s: Site title */ ?>
<p><?php esc_html_e( 'We have finished processing your order.', 'woocommerce' ); ?></p>
<?php
/*
* #hooked WC_Emails::order_details() Shows the order details table.
* #hooked WC_Structured_Data::generate_order_data() Generates structured data.
* #hooked WC_Structured_Data::output_structured_data() Outputs structured data.
* #since 2.5.0
*/
do_action( 'woocommerce_email_order_details', $order, $sent_to_admin, $plain_text, $email );
/*
* #hooked WC_Emails::order_meta() Shows order meta data.
*/
do_action( 'woocommerce_email_order_meta', $order, $sent_to_admin, $plain_text, $email );
/*
* #hooked WC_Emails::customer_details() Shows customer details
* #hooked WC_Emails::email_address() Shows email address
*/
do_action( 'woocommerce_email_customer_details', $order, $sent_to_admin, $plain_text, $email );
?>
<p>
<?php esc_html_e( 'Thanks for shopping with us.', 'woocommerce' ); ?>
</p>
<?php
/*
* #hooked WC_Emails::email_footer() Output the email footer
*/
do_action( 'woocommerce_email_footer', $email );
No need to overwrite template files, you can use the woocommerce_email_before_order_table hook
Via $email->id you can target the desired email
So you get:
function woocommerce_custom_email_per_product_depending_on_product_tag( $order, $sent_to_admin, $plain_text, $email ) {
$items = $order->get_items();
foreach ( $items as $item ) {
// get an array of the WP_Term objects for a defined product ID
$terms = wp_get_post_terms( $item['product_id'], 'product_tag' );
foreach($terms as $term){
$term_names[] = $term->name; // Product tag Name
//$term->term_id; Product tag Id
//$term->slug; Product tag slug
}
}
if ( $email->id == 'customer_processing_order' && in_array('Fundraiser', $term_names) ) {
echo 'Thanks for buying a fundraiser.';
}
}
add_action( 'woocommerce_email_before_order_table', 'woocommerce_custom_email_per_product_depending_on_product_tag', 10, 4 );

Wordpress - Woocommerce, remove pagination from before shop loop

With woocommerce on the archive pages, there is a before shop loop that includes pagination.
The pagination is also included after the shop loop so I want to remove it from the top of the page and leave it at the bottom.
This is the archive page code. Removing the before shop loop php code from the top of the page works but breaks the page formatting with the sidebar:
<?php
/** * The Template for displaying product archives, including the main shop page which is a post type archive. * * Override this template by copying it to yourtheme/woocommerce/archive-product.php * * #author WooThemes * #package WooCommerce/Templates * #version 2.0.0 */
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
get_header( 'shop' ); ?>
<?php
/**
* woocommerce_before_main_content hook
*
* #hooked woocommerce_output_content_wrapper - 10 (outputs opening divs for the content)
* #hooked woocommerce_breadcrumb - 20
*/
do_action( 'woocommerce_before_main_content' );
?>
<?php echo mad_title(array(
'title' => woocommerce_page_title(false)
)); ?>
<?php do_action( 'woocommerce_archive_description' ); ?>
<?php if ( have_posts() ) : ?>
<?php
/**
* woocommerce_before_shop_loop hook
*
* #hooked woocommerce_result_count - 20
* #hooked woocommerce_catalog_ordering - 30
*/
do_action( 'woocommerce_before_shop_loop' );
?>
<?php woocommerce_product_loop_start(); ?>
<?php woocommerce_product_subcategories(); ?>
<?php while ( have_posts() ) : the_post(); ?>
<?php wc_get_template_part( 'content', 'product' ); ?>
<?php endwhile; // end of the loop. ?>
<?php woocommerce_product_loop_end(); ?>
<?php
/**
* woocommerce_after_shop_loop hook
*
* #hooked woocommerce_pagination - 10
*/
do_action( 'woocommerce_after_shop_loop' );
?>
<?php elseif ( ! woocommerce_product_subcategories( array( 'before' => woocommerce_product_loop_start( false ), 'after' => woocommerce_product_loop_end( false ) ) ) ) : ?>
<?php wc_get_template( 'loop/no-products-found.php' ); ?>
<?php endif; ?>
<?php
/**
* woocommerce_after_main_content hook
*
* #hooked woocommerce_output_content_wrapper_end - 10 (outputs closing divs for the content)
*/
do_action( 'woocommerce_after_main_content' );
?>
<?php
/**
* woocommerce_sidebar hook
*
* #hooked woocommerce_get_sidebar - 10
*/
do_action( 'woocommerce_sidebar' );
?>
If anyone can help me work out how to do this i would be grateful.
In the woocommerce config.php the theme developer had added
add_action('woocommerce_before_shop_loop', array(&$this, 'woocommerce_pagination'));
commenting this out resolved the issue.

woocommerce on page templates

Ive made a new page template and copied the woocommerce archive-product.php into it but while the shop page works, the custom page does not, is there a way to make it function the same as the shop page? noticed it also does not pull in anything else from visual composer or normal content.
For those who wants custom woocommerce shop template ( archive-product ) here is a sample template, which can be customized to any extent.
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
get_header( 'shop' ); ?>
<?php
/**
* woocommerce_before_main_content hook
*
* #hooked woocommerce_output_content_wrapper - 10 (outputs opening divs for the content)
* #hooked woocommerce_breadcrumb - 20
*/
do_action( 'woocommerce_before_main_content' ); ?>
<?php if ( apply_filters( 'woocommerce_show_page_title', true ) ) : ?>
<h1 class="page-title"><?php woocommerce_page_title(); ?></h1>
<?php endif; ?>
<?php do_action( 'woocommerce_archive_description' ); ?>
<?php
global $post, $product;
$args = array(
'post_type'=>'product',
'posts_per_page'=>-1,
'orderby'=>'date',
'order'=>'ASC'
);
// get all the posts ( here it would be all the wc products )
$posts = get_posts( $args );
/**
* woocommerce_before_shop_loop hook
*
* #hooked woocommerce_result_count - 20
* #hooked woocommerce_catalog_ordering - 30
*/
do_action( 'woocommerce_before_shop_loop' );
if( count( $posts ) > 0 ) {
woocommerce_product_loop_start();
woocommerce_product_subcategories();
foreach( $posts as $post ) {
// this will put the current post into the GLOBAL $post object
setup_postdata( $post );
// this will put the product data into GLOBAL $product object
wc_setup_product_data( $post ); ?>
<!-- Now you have valid WP loop, put the content-product template here -->
<?php wc_get_template_part( 'content', 'product' ); ?>
<?php
}
woocommerce_product_loop_end();
} else {
wc_get_template( 'loop/no-products-found.php' );
}
/**
* woocommerce_after_shop_loop hook
*
* #hooked woocommerce_pagination - 10
*/
do_action( 'woocommerce_after_shop_loop' );
/**
* woocommerce_sidebar hook
*
* #hooked woocommerce_get_sidebar - 10
*/
do_action( 'woocommerce_sidebar' );
get_footer( 'shop' ); ?>

Woocommerce custom content-product.php

This is the basic code for the template content-product.php
<li <?php post_class( $classes ); ?>>
<?php do_action( 'woocommerce_before_shop_loop_item' ); ?>
<a href="<?php the_permalink(); ?>">
<h3><?php the_title(); ?></h3>
<?php
/**
* woocommerce_before_shop_loop_item_title hook
*
* #hooked woocommerce_show_product_loop_sale_flash - 10
* #hooked woocommerce_template_loop_product_thumbnail - 10
*/
do_action( 'woocommerce_before_shop_loop_item_title' );
?>
<?php
/**
* woocommerce_after_shop_loop_item_title hook
*
* #hooked woocommerce_template_loop_price - 10
*/
do_action( 'woocommerce_after_shop_loop_item_title' );
?>
</a>
<?php do_action( 'woocommerce_after_shop_loop_item' ); ?>
The question is that I need to show much more information for every product in the main page. Here it only shows title, image, price and add to cart button. I need to be able to show, short description, attributes, custom fields, etc...
How can i accomplish this?
Regards.
It looks like you'll need to add some hooks.
Here is a reference on how to do that: http://codex.wordpress.org/Function_Reference/add_action
I'd suggest making a separate plugin that adds hooks to either 'woocommerce_after_shop_loop_item_title' or 'woocommerce_before_shop_loop_item_title'.
Then inside your custom functions, add the information you need.
Or better yet, I was looking at the source code for this file, and it says you can simply override the whole file by copying this file and placing it in to your theme at: yourtheme/woocommerce/content-product.php
That way you can just make the adjustments straight to that file.
To add the short description, you will want to use the the_excerpt() function provided by wordpress.
To add a short description I invite you to add this piece of code to the desired location:
?>
<p class="xxx">
<?php echo $post->post_excerpt; ?>
</p>
<?php
For example to add it under the title just put it under
do_action( 'woocommerce_after_shop_loop_item_title' );
And for the style I let you manage in css.
Excuse my bad English.
You can copy php scripts from content-single-product.php and display them on the template content-product.php.It is better this ways as you will be able to control elements using HTML and CSS.
try this code. i customised the order of stuff so image is at the bottom rather then top but all variations will be shown. only thing i cant do is put two classes in a row rather then stacked just to save space but my php is limited. if anyone could add to this to customize into a better table , id love to hear about it.
<?php
/**
* The template for displaying product content within loops.
*
* Override this template by copying it to yourtheme/woocommerce/content-product.php
*
* #author WooThemes
* #package WooCommerce/Templates
* #version 2.4.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
global $product, $woocommerce_loop;
// Store loop count we're currently on
if ( empty( $woocommerce_loop['loop'] ) ) {
$woocommerce_loop['loop'] = 0;
}
// Store column count for displaying the grid
if ( empty( $woocommerce_loop['columns'] ) ) {
$woocommerce_loop['columns'] = apply_filters( 'loop_shop_columns', 4 );
}
// Ensure visibility
if ( ! $product || ! $product->is_visible() ) {
return;
}
// Increase loop count
$woocommerce_loop['loop']++;
// Extra post classes
$classes = array();
if ( 0 == ( $woocommerce_loop['loop'] - 1 ) % $woocommerce_loop['columns'] || 1 == $woocommerce_loop['columns'] ) {
$classes[] = 'first';
}
if ( 0 == $woocommerce_loop['loop'] % $woocommerce_loop['columns'] ) {
$classes[] = 'last';
}
?>
<li <?php post_class( $classes ); ?>>
<?php do_action( 'woocommerce_before_shop_loop_item' ); ?>
<?php
/**
* remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_title', 5 );
* remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_price', 10 );
* remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_excerpt', 20 );
*/
do_action( 'woocommerce_single_product_summary' );
?>
<a href="<?php the_permalink(); ?>">
<?php
/**
* woocommerce_before_shop_loop_item_title hook
*
* #hooked woocommerce_show_product_loop_sale_flash - 10
* #hooked woocommerce_template_loop_product_thumbnail - 10
*/
do_action( 'woocommerce_before_shop_loop_item_title' );
/**
* woocommerce_shop_loop_item_title hook
*
* #hooked woocommerce_template_loop_product_title - 10
*/
do_action( 'woocommerce_shop_loop_item_title' );
/**
* woocommerce_after_shop_loop_item_title hook
*
* #hooked woocommerce_template_loop_rating - 5
* #hooked woocommerce_template_loop_price - 10
*/
do_action( 'woocommerce_after_shop_loop_item_title' );
?>
</a>
</li>

Resources