I tried searching online and contacting the plugin author, and he said that it can be retrieved using the WordPress get post meta.
I'm using a plugin called woo-gst to add a product attribute called 'prod_hsn_id' which add a filed called HSN code at product edit page, I'm also using a pdf invoice plugin called woocommerce pdf invoice to generate pdf invoice. Now I want to display the HSN code on the invoice.
<?php foreach ( $this->order->get_items( 'line_item' ) as $item_id => $item ) {
$product = $this->order->get_product_from_item( $item ); ?>
<tr class="product-row">
<td>
<?php echo esc_html( $item['name'] );
global $wpdb;
$hidden_order_itemmeta = apply_filters( 'woocommerce_hidden_order_itemmeta', array(
'_qty',
'_tax_class',
'_product_id',
'_variation_id',
'_line_subtotal',
'_line_subtotal_tax',
'_line_total',
'_line_tax',
'_wc_cog_item_cost',
'_wc_cog_item_total_cost',
'_reduced_stock',
) );
$hidden_order_itemmeta = apply_filters( 'bewpi_hidden_order_itemmeta', $hidden_order_itemmeta );
foreach ( $this->order->has_meta( $item_id ) as $meta ) {
// Skip hidden core fields.
if ( in_array( $meta['meta_key'], $hidden_order_itemmeta, true ) ) {
continue;
}
// Skip serialised meta.
if ( is_serialized( $meta['meta_value'] ) ) {
continue;
}
// Get attribute data.
if ( taxonomy_exists( wc_sanitize_taxonomy_name( $meta['meta_key'] ) ) ) {
$term = get_term_by( 'slug', $meta['meta_value'], wc_sanitize_taxonomy_name( $meta['meta_key'] ) );
$meta['meta_key'] = wc_attribute_label( wc_sanitize_taxonomy_name( $meta['meta_key'] ) );
$meta['meta_value'] = isset( $term->name ) ? $term->name : $meta['meta_value'];
} else {
$meta['meta_key'] = apply_filters( 'woocommerce_attribute_label', wc_attribute_label( $meta['meta_key'], $product ), $meta['meta_key'] );
}
echo '<div class="item-attribute"><span style="font-weight: bold;">' . wp_kses_post( rawurldecode( $meta['meta_key'] ) ) . ': </span>' . wp_kses_post( rawurldecode( $meta['meta_value'] ) ) . '</div>';
}
$field_name = 'hsn_prod_id';
// then loop through items in order and print each custom field
foreach ( $this->order->get_items() as $item_id => $item ) {
if ( $product = $this->order->get_product_from_item( $item ) ) {
$location = $product->get_meta( $field_name );
if ( !empty($hsn_prod_id) ) {
echo '<div class="product-location">HSN Code: '.$hsn_prod_id.'</div>';
}
}
}
?>
</td>```
above is the code In the Invoice Template file I'm trying to display the HSN Code.
I was working on the same today, did not find a solution, and finally here is what I did and it worked well.
We need to pull the data from postmeta table, and to get that you need to have the post id for the product.
If you do $product_id = $product->get_id() this will return the id (they call it Variation ID). The post id and product id are not same.
To get the post id for the product you need to subtract -1 form the $product_id.
This is the line you can use to get the HSN code :
$hsn_prod_id = get_post_meta( $product->get_id()-1, 'hsn_prod_id', true );
UPDATE:
The logic for subtract -1 depends on the Wordpress,WooCommerce version may be. I have tried the same in a fresh setup where it didn't work. In there, I just used this $product_id = $product->get_id() value and it worked.
You can figure it by looking at the id for the product. The id it shows in the UI and the ID you see in the URL when you edit an order. If both are not the same you need to see the sequence difference and take a call.
Related
I am using ACF to store some information on each product that i then want reflected in the admin area. I have got it working on the edit order page for both simple and variable products with the following:
add_action( 'woocommerce_before_order_itemmeta', 'downloadable_items', 100, 3 );
function downloadable_items( $item_id, $item, $product ){
// Only on backend order edit pages
if( ! ( is_admin() && $item->is_type('line_item') ) ) return;
// Get your ACF product value (replace the slug by yours below)
if ( $product->is_type( 'simple' ) ) {
if ( $acf_value = get_field( 'downloadable_image', $product->get_id() ) ) {
$acf_label = __('Download Link: ');
// Outputing the value of the "downloadable item" for this product item
echo '<div class="wc-order-item-custom">' . $acf_label .'<a href="'. $acf_value
.'">'. $acf_value . '</a></div>';
}} else {
if ( $acf_value = get_field( 'downloadable_image', $product->get_parent_id() ) ) {
$acf_label = __('Download Link: ');
// Outputing the value of the "downloadable item" for this product item
echo '<div class="wc-order-item-custom">' . $acf_label .'<a href="'. $acf_value
.'">'. $acf_value . '</a></div>';
}}
}
I would like this to also reflect in the order preview so as not to have to load into each order. Hopefully that makes sense. Any help would be much appreciated
I keep searching for a way to do this, but I can't find anything unfortunately.
I an trying to display all the product's attributes and values, separated by a pipe, in a custom place on the single-product (so for that I was thinking to create a shortcode, so I can place it anywhere I want). the output would be something like this:
BRAND: RENAULT | MODEL: 12 | YEAR: 1973
The code on the Woocommerce template product-attributes.php lists the attributes of the current product on single-product page, but it will list it with some styles I don't want in a place I don't want.
I want to create a shortcode with that code, which is:
<?php foreach ( $product_attributes as $product_attribute_key => $product_attribute ) : ?>
<?php echo wp_kses_post( $product_attribute['label'] ); ?>: <?php echo wp_kses_post( $product_attribute['value'] ); ?> |
<?php endforeach; ?>
How can I create a shortcode with it? I know the general code for a shortcode, but I don't know how to actually integrate the above one in it:
function custom_attributes_product_page() {
// integrate the required code
// Output needs to be return
return
}
// register shortcode
add_shortcode('custom-attributes', 'custom_attributes_product_page');
Would be great if this shortcode would list the attributes and their values separated by a column, like I said above (how to do that?)
Any help is highly appreciated.
Try the following shortcode that will display all product attribute(s) set for a product and their value(s), handling custom attributes too:
function get_product_attributes_shortcode($atts ) {
// Extract shortcode attributes
extract( shortcode_atts( array(
'id' => get_the_ID(),
), $atts, 'display-attributes' ) );
global $product;
if ( ! is_a($product, 'WC_Product') ) {
$product = wc_get_product( $id );
}
if ( is_a($product, 'WC_Product') ) {
$html = []; // Initializing
foreach ( $product->get_attributes() as $attribute => $values ) {
$attribute_name = wc_attribute_label($values->get_name());
$attribute_data = $values->get_data();
$is_taxonomy = $attribute_data['is_taxonomy'];
$option_values = array(); // Initializing
// For taxonomy product attribute values
if( $is_taxonomy ) {
$terms = $values->get_terms(); // Get attribute WP_Terms
// Loop through attribute WP_Term(s)
foreach ( $terms as $term ) {
$term_link = get_term_link( $term, $attribute );
$option_values[] = ''.$term->name.'';
}
}
// For "custom" product attributes values
else {
// Loop through attribute option values
foreach ( $values->get_options() as $term_name ) {
$option_values[] = $term_name;
}
}
$html[] = '<strong>' . $attribute_name . '</strong>: ' . implode(', ', $option_values);
}
return '<div class="product-attributes">' . implode(' | ', $html) . '<div>';
}
}
add_shortcode( 'display-attributes', 'get_product_attributes_shortcode' );
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
USAGE: [display-attributes] or with a defined product Id [display-attributes id="254"]
You will get a display like: BRAND: RENAULT | MODEL: 12 | YEAR: 1973
If you don't want the linked terms, replace:
$term_link = get_term_link( $term, $attribute );
$option_values[] = ''.$term->name.'';
by this:
$option_values[] = $term->name;
I'm trying to show estimated delivery times on the Packing slips. (WP overnight WooCommerce PDF Invoices & Packing Slips).
I'm using a snippet that displays either the category field or, if its there, the product category field. It works fine elsewhere on my site.
I'm fiddling around with this snippet: https://docs.wpovernight.com/woocommerce-pdf-invoices-packing-slips/displaying-product-custom-fields/
This is what I've got so far.
<?php
add_action( 'wpo_wcpdf_after_item_meta', 'wpo_wcpdf_product_custom_field', 10, 3 );
function wpo_wcpdf_product_custom_field( $template_type, $item, $order ) {
if ( $template_type == 'packing-slip' ) {
// check if product exists first
if ( empty( $item[ 'product' ] ) ) return;
// Check en display delivery time
if ( $plevertijd = get_field( 'plevertijd', $item->get_product_id() ) ) {
echo '
<p style="font-size: small; margin-top: 10px;">Verwachte levertijd: ' . $plevertijd . ' (vanaf besteldatum)</p>
';
} else {
$terms = get_the_terms( $item->get_product_id(), 'product_cat' );
if ( !empty( $terms ) ) {
$term = array_pop( $terms );
if ( $levertijd = get_field( 'levertijd', $term ) ) {
echo '
<p style="font-size: small; margin-top: 10px;">Verwachte levertijd: ' . $levertijd . ' (vanaf besteldatum)</p>
';
}
}
}
}
}
?>
But that gives me an error:
Fatal error: Call to a member function get_product_id() on array
Does anyone know how to resolve this?
I can't manage to add a product attribute to a WooCommerce new order email. I have added the snippet below to email-order-items.php (after // SKU.. part), but nothing happens. Even the titel 'Location:' isn't visible. Any thoughts on this?
// Attribute
if ( $item_meta->meta ) {echo '<br/><small>Location: ' . nl2br( $product->get_attribute( 'location' ) ) . '</small>';}
Updated - Instead of overriding Woocommerce templates, always try first to use available hooks like:
add_action( 'woocommerce_order_item_meta_start', 'add_download_links_to_thank_you_page', 10, 3 );
function add_download_links_to_thank_you_page( $item_id, $item, $order ) {
// Set below your product attribute taxonomy (always starts with "pa_")
$taxonomy = 'pa_location';
// On email notifications
if ( ! is_wc_endpoint_url() && $item->is_type('line_item') ) {
$product = $item->get_product();
$label_name = get_taxonomy( $taxonomy )->labels->singular_name;
if ( $term_names = $product->get_attribute( $taxonomy ) ) {
echo '<br/><small>' . $label_name . ': ' . nl2br( $term_names ) . '</small>';
}
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
You can also use woocommerce_order_item_meta_end hook instead.
I have implemented a custom HTML Form and asking for some data which my customers will pass to place order successfully. Without these details my order has no importance.
For HTML form, I am referencing some custom PHP script which is below and which processes POST data from the Form and creates Cart with these data programmatically. Thanks #LoicTheAztec to help me achieve this.
The script.php file code:
<?php
require_once("../wp-load.php");
$customer_name = $_POST["customer_name"];
$customer_email = $_POST["customer_email"];
$customer_sex = $_POST["customer_sex"];
$customer_age = $_POST["customer_age"];
$product_id = $_POST["product_id"];
$custom_data = array(); // Initializing
if( isset($_POST['customer_name']) && ! empty($_POST['customer_name']) )
$custom_data['custom_data']['name'] = $_POST['customer_name'];
if( isset($_POST['customer_email']) && ! empty($_POST['customer_email']) )
$custom_data['custom_data']['email'] = $_POST['customer_email'];
if( isset($_POST['customer_sex']) && ! empty($_POST['customer_sex']) )
$custom_data['custom_data']['sex'] = $_POST['customer_sex'];
if( isset($_POST['customer_age']) && ! empty($_POST['customer_age']) )
$custom_data['custom_data']['age'] = $_POST['customer_age'];
global $woocommerce;
if (WC()->cart->add_to_cart( $product_id, '1', '0', array(), $custom_data )) {
var_dump($product_id);
} else {
var_dump($customer_name);
}
header("Location: ./checkout");
?>
As you see we have programmatically created a cart item using WC_Cart add_to_cart() method. So, all custom data is being saved to Cart as custom cart item data.
And now, we have also placed a code block into functions.php to print these data on Checkout page.
add_action( 'woocommerce_after_order_notes', 'my_custom_checkout_field' );
function my_custom_checkout_field( $checkout ) {
//var_dump($checkout);
global $woocommerce;
echo '<div id="my_custom_checkout_field"><h2>' . __('Child Info') . '</h2>';
foreach ( $woocommerce->cart->get_cart() as $cart_item ) {
if( isset($cart_item['custom_data']) ) {
$custom_data = $cart_item['custom_data'];
echo("<div>Name: <strong>" . $custom_data['name'] . "</strong></div>");
echo("<div>Email: <strong>" . $custom_data['email'] . "</strong></div>");
echo("<div>Gender: <strong>" . $custom_data['sex'] . "</strong></div>");
echo("<div>Age: <strong>" . $custom_data['age'] . "</strong></div>");
}
}
echo '</div>';
}
Now, I am trying to add these data printed on Checkout page to the Order page as well. As my order can't be completed without these data, user need to fill up these data and when he creates order, these data needs to be passed to the Order Summary page as well. And admin also needs to be able to see these data so he can process the order.
I hope this description clears everything and thanks again #LoicTheAztec to make me able to do this. Thank you very much.
Update 2 - Two steps
1) Saving data:
We will save this custom customer data as "Hidden" order "item" meta data and then as order meta data too as this is related to subscriptions with a unique order item:
// Utility function: array of custom customer key/label pairs
function custom_data_keys_labels(){
return array(
'name' => __('Customer name'), 'email' => __('Customer email'),
'sex' => __('Customer gender'), 'age' => __('Customer age'),
);
}
// Add/save custom field value as custom HIDDEN order item meta data
add_action( 'woocommerce_checkout_create_order_line_item', 'custom_field_update_order_item_meta', 20, 4 );
function custom_field_update_order_item_meta( $item, $cart_item_key, $values, $order ) {
if ( ! isset( $values['custom_data'] ) )
return;
$custom_data = $values['custom_data'];
$meta_data = array();
$labels_keys = custom_data_keys_labels();
foreach( $labels_keys as $key => $label ){
if ( isset( $custom_data[$key] ) )
$meta_data[$key] = $custom_data[$key];
}
if ( sizeof( $meta_data ) > 0 )
$item->update_meta_data( __('_customer_data'), $meta_data );
return $cart_item_data;
}
// Add/save custom fields values as custom order meta data
add_action( 'woocommerce_checkout_create_order', 'my_custom_checkout_field_update_order_meta', 20, 2 );
function my_custom_checkout_field_update_order_meta( $order, $data ) {
$order_items = $order->get_items(); // Order itesm
$item = reset($order_items); // Keep only the first order item
$item_data = $item->get_meta( '_customer_data' ); // Get custom customer data
if( is_array($item_data) && sizeof($item_data) > 0 ){
foreach( $item_data as $key => $value ) {
if ( isset( $item_data[$key] ) )
$order->update_meta_data( '_customer_' . $key, $value );
}
// Mark as data saved
$order->update_meta_data( '_customer_data_set', true );
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
2) Displaying saved custom data:
The code below also use our utility function custom_data_keys_labels()…
// Order pages (frontend and admin) display
add_filter( 'woocommerce_order_details_after_order_table' , 'display_admin_order_meta_cutom_data', 20, 1 ); // Front
add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_admin_order_meta_cutom_data', 20, 1 ); // Admin
function display_admin_order_meta_cutom_data( $order ){
$labels_keys = custom_data_keys_labels();
if( $order->get_meta( '_customer_data_set' ) ){
if( is_admin() ){ // Admin
echo '<p>';
foreach( $labels_keys as $key => $label ){
if ( $order->get_meta( '_customer_' . $key ) )
echo '<strong>' . $label . ':</strong> ' . $order->get_meta( '_customer_' . $key ) . '<br>';
}
echo '</p>';
}
else { // Front end: order view and Order received (thankyou)
echo '<table class="woocommerce-table"><tbody>';
foreach( $labels_keys as $key => $label ){
if ( $order->get_meta( '_customer_' . $key ) )
echo '<tr><th>' . $label . ':</th><td>' . $order->get_meta( '_customer_' . $key ) . '</td></tr>';
}
echo '</tbody></table>';
}
}
}
// Email notifications display
add_filter( 'woocommerce_email_order_meta_fields' , 'display_email_cutom_data', 20, 3 );
function display_email_cutom_data ( $fields, $sent_to_admin, $order ) {
$labels_keys = custom_data_keys_labels();
if( $order->get_meta( '_customer_data_set' ) ){
foreach( $labels_keys as $key => $label ){
$fields['customer_' . $key] = array(
'label' => $label,
'value' => $order->get_meta( '_customer_' . $key ),
);
}
}
return $fields;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.