I have Woocommerce and Woocommerce Bookings. I want to add some more info on the cart, after a user added it there.
At the moment, I have the starting date of the booking and the duration, with a label.
<dl class="variation">
<dt class="variation-Booking"><font><font class="">Booking Date:</font></font></dt>
<dd class="variation-Booking"><p><font><font class="">August 11, 2015</font></font></p></dd>
<dt class="variation-Duration"><font><font>Duration:</font></font></dt>
<dd class="variation-Duration"><p><font><font>4 days</font></font></p></dd>
</dl>
I try to find where this code is created on the PHP files of Woocommerce, so I can either add more attributes that are available on the database (like ending date and SKU for example) and also change the HTML output.
In the cart.php file, there is this part of the code:
// Meta data
echo WC()->cart->get_item_data( $cart_item );
Then on class-wc-cart.php the above function:
public function get_item_data( $cart_item, $flat = false ) {
$item_data = array();
// Variation data
if ( ! empty( $cart_item['data']->variation_id ) && is_array( $cart_item['variation'] ) ) {
foreach ( $cart_item['variation'] as $name => $value ) {
if ( '' === $value )
continue;
$taxonomy = wc_attribute_taxonomy_name( str_replace( 'attribute_pa_', '', urldecode( $name ) ) );
// If this is a term slug, get the term's nice name
if ( taxonomy_exists( $taxonomy ) ) {
$term = get_term_by( 'slug', $value, $taxonomy );
if ( ! is_wp_error( $term ) && $term && $term->name ) {
$value = $term->name;
}
$label = wc_attribute_label( $taxonomy );
// If this is a custom option slug, get the options name
} else {
$value = apply_filters( 'woocommerce_variation_option_name', $value );
$product_attributes = $cart_item['data']->get_attributes();
if ( isset( $product_attributes[ str_replace( 'attribute_', '', $name ) ] ) ) {
$label = wc_attribute_label( $product_attributes[ str_replace( 'attribute_', '', $name ) ]['name'] );
} else {
$label = $name;
}
}
$item_data[] = array(
'key' => $label,
'value' => $value
);
}
}
// Other data - returned as array with name/value values
$other_data = apply_filters( 'woocommerce_get_item_data', array(), $cart_item );
if ( $other_data && is_array( $other_data ) && sizeof( $other_data ) > 0 ) {
foreach ( $other_data as $data ) {
// Set hidden to true to not display meta on cart.
if ( empty( $data['hidden'] ) ) {
$display_value = ! empty( $data['display'] ) ? $data['display'] : $data['value'];
$item_data[] = array(
'key' => $data['name'],
'value' => $display_value
);
}
}
}
// Output flat or in list format
if ( sizeof( $item_data ) > 0 ) {
ob_start();
if ( $flat ) {
foreach ( $item_data as $data ) {
echo esc_html( $data['key'] ) . ': ' . wp_kses_post( $data['value'] ) . "\n";
}
} else {
wc_get_template( 'cart/cart-item-data.php', array( 'item_data' => $item_data ) );
}
return ob_get_clean();
}
return '';
}
And the cart-item-data.php that is called above:
<dl class="variation">
<?php
foreach ( $item_data as $data ) :
$key = sanitize_text_field( $data['key'] );
?>
<dt class="variation-<?php echo sanitize_html_class( $key ); ?>"><?php echo wp_kses_post( $data['key'] ); ?>:</dt>
<dd class="variation-<?php echo sanitize_html_class( $key ); ?>"><?php echo wp_kses_post( wpautop( $data['value'] ) ); ?></dd>
<?php endforeach; ?>
</dl>
However, I am still unaware of how I can change the layout and add specific attributes from the database.
add_filter( 'woocommerce_get_item_data', 'wc_add_address_to_cart', 10, 2 );
function wc_add_address_to_cart( $other_data, $cart_item ) {
$post_data = get_post( $cart_item['product_id'] );
$post_data->post_author;
$vendor_id = $post_data->post_author;
echo '<br>';
$Add = 'Address: ';
$city = 'City: ';
$tel = 'Phone: ';
echo $test;
$user_id = $vendor_id;
// Get all user meta data for $user_id
$meta = get_user_meta( $user_id );
// Filter out empty meta data
$meta = array_filter( array_map( function( $a ) {
return $a[0];
}, $meta ) );
echo $Add;
print_r( $meta ['_vendor_address_1'] );
echo '<br>';
echo $city;
print_r( $meta['_vendor_city'] );
echo '<br>';
echo $tel;
print_r( $meta['_vendor_phone'] );
return $other_data;
}
Add this to the functions.php file in your theme. it will display the Address of each vendor on the products. you can customize it to what ever you want.
Related
If I am using the following code to track recently viewed products...
/**
* Track user woocommerce viewed products.
*/
function dorzki_wc_track_product_views() {
if( ! is_singular( 'product' ) || is_active_widget( false, false, 'woocommerce_recently_viewed_products', true ) ) {
return;
}
global $post;
if ( empty( $_COOKIE['woocommerce_recently_viewed'] ) ) {
$viewed_products = array();
} else {
$viewed_products = wp_parse_id_list( (array) explode( '|', wp_unslash( $_COOKIE['woocommerce_recently_viewed'] ) ) );
}
$keys = array_flip( $viewed_products );
if ( isset( $keys[ $post->ID ] ) ) {
unset( $viewed_products[ $keys[ $post->ID ] ] );
}
$viewed_products[] = $post->ID;
if ( count( $viewed_products ) > 15 ) {
array_shift( $viewed_products );
}
wc_setcookie( 'woocommerce_recently_viewed', implode( '|', $viewed_products ) );
}
add_action( 'template_redirect', 'dorzki_wc_track_product_views', 20 );
and this code to display recently view products...
/**
* Display recently viewed products.
*/
function dorzki_wc_display_products_viewed() {
if ( empty( $_COOKIE['woocommerce_recently_viewed'] ) ) {
return;
}
$total_products = apply_filters( 'loop_shop_columns', get_option( 'woocommerce_catalog_columns', 4 ) );
$viewed_products = wp_parse_id_list( (array) explode( '|', wp_unslash( $_COOKIE['woocommerce_recently_viewed'] ) ) );
$products = array_slice( $viewed_products, 0, $total_products );
$ids = implode( ',', $products );
echo "<h2>" . esc_html__( 'Recently Viewed Products', 'dorzki' ) . "</h2>";
echo do_shortcode( "[products ids='{$ids}']" );
}
add_action( 'woocommerce_after_cart', 'dorzki_wc_display_products_viewed' );
How can I obtain the 'count'? Ideally I would like to create a shortcode that will output how many products the user has viewed recently.
I've tried this and I 'think' it works??
function recently_count() {
$total_products = apply_filters( 'loop_shop_columns', get_option( 'woocommerce_catalog_columns', 4 ) );
$viewed_products = wp_parse_id_list( (array) explode( '|', wp_unslash( $_COOKIE['woocommerce_recently_viewed'] ) ) );
$products = array_slice( $viewed_products, 0, $total_products );
$ids = implode( ',', $products );
if ($ids == 0) {
echo '0';
}
else {
echo count($ids);
}
}
add_shortcode( 'recently_count', 'recently_count' );
To just count the number of recently viewed products and return that in a shortcode, then you just have to count the exploded array of the cookie value.
Also, remember that you never echo a shortcode output, it must be returned.
function recently_count() {
return isset( $_COOKIE['woocommerce_recently_viewed'] ) ? count( (array) explode( '|', wp_unslash( $_COOKIE['woocommerce_recently_viewed'] ) ) ) : 0;
}
add_shortcode( 'recently_count', 'recently_count' );
This will return an integer.
I have this code to display product attributes
add_action('woocommerce_single_product_summary', 'attributes', 30 );
function attributes() {
global $product;
$attributes_names = array('Size', 'Color', 'Material', 'Pieces');
$attributes_data = array();
foreach ( $attributes_names as $attribute_name ) {
if ( $value = $product->get_attribute($attribute_name) ) {
$attributes_data[] = $attribute_name . ': ' . $value;
}
}
if ( ! empty($attributes_data) ) {
echo '<div><p>' . implode( '</p>', $attributes_data ) . '</div>';
}
}
Instead of displaying the attribute's value, I want to display their description, so something like
$attributes_data[] = $attribute_name . ': ' . $term_description;
How can this be done?
You can use wc_get_product_terms to retrieve the terms for a product (including its attributes). The parameters of the function are the product ID, the taxonomy and the query args.
For example, you could do something like this:
function attributes() {
global $product;
$attributes_names = array( 'Size', 'Color', 'Material', 'Pieces' );
$attributes_data = array();
foreach ( $product->get_attributes() as $attribute => $value ) {
$attribute_name = wc_get_attribute( $value->get_id() )->name;
if ( ! in_array( $attribute_name, $attributes_names, true ) ) {
continue;
}
$values = wc_get_product_terms( $product->get_id(), $attribute, array( 'fields' => 'all' ) );
if ( $values ) {
$attribute_descriptions = array();
foreach ( $values as $term ) {
$attribute_descriptions[] = term_description( $term->term_id, $term->taxonomy );
}
$attributes_data[] = $attribute_name . ': ' . implode( ',', $attribute_descriptions );
}
}
if ( ! empty( $attributes_data ) ) {
echo '<div><p>' . implode( '</p>', $attributes_data ) . '</div>';
}
}
To note that the attribute description includes any HTML tags, line breaks, etc. That's why in my example above I stripped those, but of course it might not be necessary.
On a single product, inside the admin panel, on the Linked Products tab (on woocommerce), i can set up Up-Sells and Cross-Sells Products. I can add the product i wish to link to by searching for it.
At the moment search gives all products, even the ones that are out of stock. I would like if i write down an id of a product that is out of stock, it won't appear on the list.
The function that is responsible for json result is
public static function json_search_products_and_variations() {
self::json_search_products( '', true );
}
public static function json_search_products( $term = '', $include_variations = false ) {
check_ajax_referer( 'search-products', 'security' );
if ( empty( $term ) && isset( $_GET['term'] ) ) {
$term = (string) wc_clean( wp_unslash( $_GET['term'] ) );
}
if ( empty( $term ) ) {
wp_die();
}
if ( ! empty( $_GET['limit'] ) ) {
$limit = absint( $_GET['limit'] );
} else {
$limit = absint( apply_filters( 'woocommerce_json_search_limit', 30 ) );
}
$include_ids = ! empty( $_GET['include'] ) ? array_map( 'absint', (array) wp_unslash( $_GET['include'] ) ) : array();
$exclude_ids = ! empty( $_GET['exclude'] ) ? array_map( 'absint', (array) wp_unslash( $_GET['exclude'] ) ) : array();
$exclude_types = array();
if ( ! empty( $_GET['exclude_type'] ) ) {
// Support both comma-delimited and array format inputs.
$exclude_types = wp_unslash( $_GET['exclude_type'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
if ( ! is_array( $exclude_types ) ) {
$exclude_types = explode( ',', $exclude_types );
}
// Sanitize the excluded types against valid product types.
foreach ( $exclude_types as &$exclude_type ) {
$exclude_type = strtolower( trim( $exclude_type ) );
}
$exclude_types = array_intersect(
array_merge( array( 'variation' ), array_keys( wc_get_product_types() ) ),
$exclude_types
);
}
$data_store = WC_Data_Store::load( 'product' );
$ids = $data_store->search_products( $term, '', (bool) $include_variations, false, $limit, $include_ids, $exclude_ids );
$products = array();
foreach ( $ids as $id ) {
$product_object = wc_get_product( $id );
if ( ! wc_products_array_filter_readable( $product_object ) ) {
continue;
}
$formatted_name = $product_object->get_formatted_name();
$managing_stock = $product_object->managing_stock();
if ( in_array( $product_object->get_type(), $exclude_types, true ) ) {
continue;
}
if ( $managing_stock && ! empty( $_GET['display_stock'] ) ) {
$stock_amount = $product_object->get_stock_quantity();
/* Translators: %d stock amount */
$formatted_name .= ' – ' . sprintf( __( 'Stock: %d', 'woocommerce' ), wc_format_stock_quantity_for_display( $stock_amount, $product_object ) );
}
$products[ $product_object->get_id() ] = rawurldecode( $formatted_name );
}
wp_send_json( apply_filters( 'woocommerce_json_search_found_products', $products ) );
}
Before wp_send_json(...) how can i exclude from $products array the outofstock products?
Before
$products[ $product_object->get_id() ] = rawurldecode( $formatted_name );
the code
if ('outofstock' === $product_object->get_stock_status()){
continue;
}
worked for me.
I want to show attibutes from a simple product, in cart and checkout. Just like variable products does, but there is only one attibute. See image below:
Is this possible to achive with PHP?
I was thinking about something like using echo $product->get_attributes()
Add the follows code snippets to achieve your above task -
function modify_woocommerce_get_item_data( $item_data, $cart_item ) {
if( $item_data || $cart_item['data']->is_type( 'variation' ) ) return $item_data;
if ( $cart_item['data']->is_type( 'simple' ) ) {
$attributes = array_filter( $cart_item['data']->get_attributes(), 'wc_attributes_array_filter_visible' );
foreach ( $attributes as $attribute ) {
$values = array();
if ( $attribute->is_taxonomy() ) {
$attribute_taxonomy = $attribute->get_taxonomy_object();
$attribute_values = wc_get_product_terms( $cart_item['data']->get_id(), $attribute->get_name(), array( 'fields' => 'all' ) );
foreach ( $attribute_values as $attribute_value ) {
$value_name = esc_html( $attribute_value->name );
if ( $attribute_taxonomy->attribute_public ) {
$values[] = '' . $value_name . '';
} else {
$values[] = $value_name;
}
}
} else {
$values = $attribute->get_options();
foreach ( $values as &$value ) {
$value = make_clickable( esc_html( $value ) );
}
}
$item_data[] = array(
'key' => wc_attribute_label( $attribute->get_name() ),
'value' => apply_filters( 'woocommerce_attribute', wpautop( wptexturize( implode( ', ', $values ) ) ), $attribute, $values ),
);
}
}
return $item_data;
}
add_filter( 'woocommerce_get_item_data', 'modify_woocommerce_get_item_data', 99, 2 );
Codes goes to your active theme's functions.php
Yes you can. Please try adding a filter as bellow,
add_filter('woocommerce_cart_item_name', function($name, $cart_item) {
//has attributes
if ($cart_item['data']->is_type( 'simple' ) && $attributes = $cart_item['data']->get_attributes()) {
$name .= " - ";
foreach ($attributes as $att)
$name .= $att->get_name() . " : " . implode(',', $att->get_options());
}
return $name;
}, 10, 2);
In Woocommerce, there is a block of code in variable.php that displays the variation options. I am needing to display the SKU of each individual variation in the list next to the title. Is there a way I can do this that is similar to $product->get_sku;?
This is the full block:
global $product;
$attribute_keys = array_keys( $attributes );
<?php foreach ( $attributes as $name => $options ) : ?>
<tr class="attribute-<?php echo sanitize_title($name); ?>">
<?php
$sanitized_name = sanitize_title( $name );
if ( isset( $_REQUEST[ 'attribute_' . $sanitized_name ] ) ) {
$checked_value = $_REQUEST[ 'attribute_' . $sanitized_name ];
} elseif ( isset( $selected_attributes[ $sanitized_name ] ) ) {
$checked_value = $selected_attributes[ $sanitized_name ];
} else {
$checked_value = '';
}
?>
<td class="value">
<?php
if ( ! empty( $options ) ) {
if ( taxonomy_exists( $name ) ) {
// Get terms if this is a taxonomy - ordered. We need the names too.
$terms = wc_get_product_terms( $product->get_id(), $name, array( 'fields' => 'all' ) );
foreach ( $terms as $term ) {
if ( ! in_array( $term->slug, $options ) ) {
continue;
}
print_attribute_radio( $checked_value, $term->slug, $term->name, $sanitized_name );
}
} else {
foreach ( $options as $option ) {
echo $product->get_sku; // This is where the variation SKU would go
print_attribute_radio( $checked_value, $option, $option, $sanitized_name );
}
}
}
echo end( $attribute_keys ) === $name ? apply_filters( 'woocommerce_reset_variations_link', '<a class="reset_variations" href="#">' . __( 'Clear', 'woocommerce' ) . '</a>' ) : '';
?>
</td>
</tr>
<?php endforeach; ?>
This is where the Variation SKU would go within this section:
foreach ( $options as $option ) {
echo $product->get_sku; // This is where the variation SKU would go
print_attribute_radio( $checked_value, $option, $option,
$sanitized_name );
}
Thanks.
Replace your foreach with:
$product = new WC_Product_Variable( $post->ID );
$variations = $product->get_available_variations();
foreach ($variations as $key => $variation) {
$sku = $variation['sku'];
$options = $variation['attributes'];
.
.
.