Wordpress Site : Woocommerce Plugin
I have multiple meta product fields that I need to export.
I have looked up the reference in WooCommerce Product CSV Importer & Exporter Documentation but I am having a little trouble understanding how to expand the example to add more than one custom column.
This part I am fine with
$columns is an array
So all I need to do is add an array item for each custom field.
/**
* Add the custom column to the exporter and the exporter column menu.
*
* #param array $columns
* #return array $columns
*/
function add_export_column( $columns ) {
// column slug => column name
$columns['my_custom_supplier_product_code'] = 'Supplier Product CODE';
$columns['my_custom_supplier_product_desc'] = 'Supplier Product DESC';
return $columns;
}
add_filter( 'woocommerce_product_export_column_names', 'add_export_column' );
add_filter( 'woocommerce_product_export_product_default_columns', 'add_export_column' );
Here I am not quite sure what to do
REFERENCE
/**
* Provide the data to be exported for one item in the column.
*
* #param mixed $value (default: '')
* #param WC_Product $product
* #return mixed $value - Should be in a format that can be output into a text file (string, numeric, etc).
*/
function add_export_data( $value, $product ) {
$value = $product->get_meta( 'custom_column', true, 'edit' );
return $value;
}
// Filter you want to hook into will be: 'woocommerce_product_export_product_column_{$column_slug}'.
add_filter( 'woocommerce_product_export_product_column_custom_column', 'add_export_data', 10, 2 );
My mod for my first custom column
/**
* Provide the data to be exported for one item in the column.
*
* #param mixed $value (default: '')
* #param WC_Product $product
* #return mixed $value - Should be in a format that can be output into a text file (string, numeric, etc).
*/
function add_export_data( $value, $product ) {
$value = $product->get_meta( 'my_custom_supplier_product_code', true, 'edit' );
return $value;
}
// Filter you want to hook into will be: 'woocommerce_product_export_product_column_{$column_slug}'.
add_filter( 'woocommerce_product_export_product_column_my_custom_supplier_product_code', 'add_export_data', 10, 2 );
Now how do I add what is required for my second column ?
Should I have
2 x add_export_data functions
2 x add_filter
/**
* Provide the data to be exported for one item in CUSTOM COLUMN 1
*
* #param mixed $value (default: '')
* #param WC_Product $product
* #return mixed $value - Should be in a format that can be output into a text file (string, numeric, etc).
*/
function add_export_data_my_custom_supplier_product_code( $value, $product ) {
$value = $product->get_meta( 'my_custom_supplier_product_code', true, 'edit' );
return $value;
}
// Filter you want to hook into will be: 'woocommerce_product_export_product_column_{$column_slug}'.
add_filter( 'woocommerce_product_export_product_column_my_custom_supplier_product_code', 'add_export_data_my_custom_supplier_product_code', 10, 2 );
/**
* Provide the data to be exported for one item in CUSTOM COLUMN 2
*
* #param mixed $value (default: '')
* #param WC_Product $product
* #return mixed $value - Should be in a format that can be output into a text file (string, numeric, etc).
*/
function add_export_data_my_custom_supplier_product_desc( $value, $product ) {
$value = $product->get_meta( 'my_custom_supplier_product_desc', true, 'edit' );
return $value;
}
// Filter you want to hook into will be: 'woocommerce_product_export_product_column_{$column_slug}'.
add_filter( 'woocommerce_product_export_product_column_my_custom_supplier_product_desc', 'add_export_data_my_custom_supplier_product_desc', 10, 2 );
Note that I have tried the code as above, but for some reason
ALL of my columns appear in the spreadsheet
SOME are empty and are not pulling the data from the Product Custom Fields
Rather than 'hacking around' trying to fix the issue, I am now stepping back to try to get a better understanding of how this works.
Thanks
Answering my own question here, and a suggestion that may help others.
Yes, I was correct in my code snippet above.
It does work as expected.
#CBroe was correct:
Maybe start by double-checking the spellings everywhere. The name of
the hooks seem to be related directly to the column slugs, so even the
tiniest misspelling there will likely cause it to not call any
function for the field in question.
My issues were essentially finger trouble
I have 11 Custom Fields.
That gets a little unwieldy when the custom_field_slug references get separated by other code.
So I am adding here
a breakdown to explain what steps are needed
and a formatting suggestion that has made life a lot easier for me to scan across a whole group of related items to make sure I haven't got any typos
STEP 1 : Add Custom Columns to Array for Mapping
/* [ mycode ] EXPORT : ADD custom columns to Exporter
------------------------------------------------------------------------------*/
/**
* Add the custom columns to the exporter and the exporter column menu.
*
* #param array $columns
* #return array $columns
*
*/
function add_export_columns( $columns ) {
// ---------------------------------------------------- Company SYSTEM Fields
// column slug > column name
$columns['company_system_item_code'] = 'Company SYSTEM Item Code';
$columns['company_system_item_description'] = 'Company SYSTEM Item Description';
$columns['company_system_item_category'] = 'Company SYSTEM Item Category';
$columns['company_system_item_unit_weight'] = 'Company SYSTEM Item Unit Weight';
$columns['company_system_item_unit_price'] = 'Company SYSTEM Item Unit Price';
// ---------------------------------------------------- Company WEBSITE Fields
// column slug > column name
$columns['company_website_discount_percent'] = 'Company WEBSITE Discount Percent';
$columns['company_website_item_unit_price'] = 'Company WEBSITE Item Unit Price';
$columns['company_website_item_minimum_units'] = 'Company WEBSITE Item Minimum Units';
// ---------------------------------------------------- Company SUPPLIER Fields
// column slug > column name
$columns['company_supplier_item_code'] = 'Company_SUPPLIER Item Code';
$columns['company_supplier_item_description'] = 'Company SUPPLIER Item Description';
$columns['company_supplier_item_unit_price'] = 'Company SUPPLIER Item Unit Price';
return $columns;
}
add_filter( 'woocommerce_product_export_column_names', 'add_export_columns' );
add_filter( 'woocommerce_product_export_product_default_columns', 'add_export_columns' );
STEP 2 : All the Export Data Functions
/* [ mycode ] EXPORT : GET data to be exported
------------------------------------------------------------------------------*/
/**
*
* Functions to provide the data to be exported for one item in EACH column.
*
*/
// ------------------------------------------------------- Company SYSTEM Fields
function add_export_data_company_system_item_code( $value, $product ) {
$value = $product->get_meta( 'company_system_item_code', true, 'edit' );
return $value;
}
function add_export_data_company_system_item_description( $value, $product ) {
$value = $product->get_meta( 'company_system_item_description', true, 'edit' );
return $value;
}
function add_export_data_company_system_item_category( $value, $product ) {
$value = $product->get_meta( 'company_system_item_category', true, 'edit' );
return $value;
}
function add_export_data_company_system_item_unit_weight( $value, $product ) {
$value = $product->get_meta( 'company_system_item_unit_weight', true, 'edit' );
return $value;
}
function add_export_data_company_system_item_unit_price( $value, $product ) {
$value = $product->get_meta( 'company_system_item_unit_price', true, 'edit' );
return $value;
}
// ------------------------------------------------------- Company WEBSITE Fields
function add_export_data_company_website_discount_percent( $value, $product ) {
$value = $product->get_meta( 'company_website_discount_percent', true, 'edit' );
return $value;
}
function add_export_data_company_website_item_unit_price( $value, $product ) {
$value = $product->get_meta( 'company_website_item_unit_price', true, 'edit' );
return $value;
}
function add_export_data_company_website_item_minimum_units( $value, $product ) {
$value = $product->get_meta( 'company_website_item_minimum_units', true, 'edit' );
return $value;
}
// ------------------------------------------------------- Company SUPPLIER Fields
function add_export_data_company_supplier_item_code( $value, $product ) {
$value = $product->get_meta( 'company_supplier_item_code', true, 'edit' );
return $value;
}
function add_export_data_company_supplier_item_description( $value, $product ) {
$value = $product->get_meta( 'company_supplier_item_description', true, 'edit' );
return $value;
}
function add_export_data_company_supplier_item_unit_price( $value, $product ) {
$value = $product->get_meta( 'company_supplier_item_unit_price', true, 'edit' );
return $value;
}
STEP 3 : All the Filters
/**
*
* Add filters to hook in for EACH column
*
*/
// ------------------------------------------------------- Company SYSTEM Fields
add_filter( 'woocommerce_product_export_product_column_company_system_item_code' , 'add_export_data_company_system_item_code', 10, 2 );
add_filter( 'woocommerce_product_export_product_column_company_system_item_description' , 'add_export_data_company_system_item_description', 10, 2 );
add_filter( 'woocommerce_product_export_product_column_company_system_item_category' , 'add_export_data_company_system_item_category', 10, 2 );
add_filter( 'woocommerce_product_export_product_column_company_system_item_unit_weight' , 'add_export_data_company_system_item_unit_weight', 10, 2 );
add_filter( 'woocommerce_product_export_product_column_company_system_item_unit_price' , 'add_export_data_company_system_item_unit_price', 10, 2 );
// ------------------------------------------------------- Company WEBSITE Fields
add_filter( 'woocommerce_product_export_product_column_company_website_discount_percent' , 'add_export_data_company_website_discount_percent', 10, 2 );
add_filter( 'woocommerce_product_export_product_column_company_website_item_unit_price' , 'add_export_data_company_website_item_unit_price', 10, 2 );
add_filter( 'woocommerce_product_export_product_column_company_website_item_minimum_units', 'add_export_data_company_website_item_minimum_units', 10, 2 );
// ------------------------------------------------------- Company SUPPLIER Fields
add_filter( 'woocommerce_product_export_product_column_company_supplier_item_code' , 'add_export_data_company_supplier_item_code', 10, 2 );
add_filter( 'woocommerce_product_export_product_column_company_supplier_item_description' , 'add_export_data_company_supplier_item_description', 10, 2 );
add_filter( 'woocommerce_product_export_product_column_company_supplier_item_unit_price' , 'add_export_data_company_supplier_item_unit_price', 10, 2 );
NOTE also the white space padding I used to align the components.
When you have many column slugs of different length, it's quite awkward to scan for errors.
If you don't have every hook and every function named correctly with the appropriate column slugs, then you won't get the expected results.
Hopefully this worked example may be useful for someone else in future.
I'm selling multiple products, each with 2 variations that will each need to have a custom bit of text (with with URLs embedded) in the Completed email. Lots of custom emails: per product and variation. I've found many options for functions.php but they are all from many years and woo versions ago.
The very popular "Woo Custom Emails Per Product" plugin does not have a per-variation function. I do not want to make each variation its own product (and could therefore use that plugin) since I want a single product page for each, where the patron can select the variation they want.
So I decided the best way to add the info for each variation is in the "Description" field for the variation.
Here's where I would like it go, above what I believe is the woocommerce_email_order_items_table:
screen grab of email showing where text should go
I tried adding this to functions.php but it's from 2015 and is for "processing" not "completed" emails:
add_filter( 'woocommerce_product_variation_title_include_attributes', '__return_false' );
function render_product_description($item_id, $item, $order){
$_product = $order->get_product_from_item( $item );
echo "<br>" . $_product->post->post_content;
}
add_action('woocommerce_order_item_meta_end', 'render_product_description',10,3);
I've tried this, but it's from years ago and did not accomplish what I need:
Add the product description to WooCommerce email notifications
This is close: Add Custom Product Field in WooCommerce 'Order Completed' Emails but not quite what I want, because there is not a custom field specific to each variation; it seems the only thing custom to each variation is "Description."
I'd like to find a way to edit the email template, as I think that would be the ideal way to go here. If it can simply list the Description contents for each item's variation ordered, I can format that text to be self-explanatory for the patron, and then the order summary box (with Product/Quantity/Price) will stay clean and just list the items.
This is a test page I set up: https://www.chambermusicpittsburgh.org/concerts-and-tickets-new-store/. Only the Escher and Dover product has the variables, with a tester phrase and URL in the Description for the weblink (which will pop down if you choose that option, but which I will eventually hide here with CSS but I've left it for testing).
I feel like adding the variation Description to the email should be super straightforward/simple, and maybe I'm not experienced enough or not looking in the right place, but that particular piece of data seems extremely hard to hook into and display in the Order Confirmed email.
Thanks!
To add custom content to the email template at this point:
You can use the woocommerce_email_before_order_table hook. See here for more information.
The following function will get the descriptions of each ordered product (if the description is not empty).
The description is obtained from the product variation NOT the
variable product.
// adds the product description before the order table in the completed order email
add_action( 'woocommerce_email_before_order_table', 'add_content_before_order_table', 99, 4 );
function add_content_before_order_table( $order, $sent_to_admin, $plain_text, $email ) {
// only for the email of the completed order
if ( ! $email->id == 'customer_completed_order' ) {
return;
}
// initializes the array with all product descriptions
$descriptions = array();
// for each product ordered
foreach ( $order->get_items() as $order_item ) {
$product = $order_item->get_product();
// get the product description
if ( $product->get_description() ) {
$descriptions[] = $product->get_description();
}
}
// if the $descriptions is not empty it shows it
if ( ! empty( $descriptions ) ) {
foreach ( $descriptions as $content ) {
echo '<p>' . $content . '</p>';
}
}
}
The code has been tested and works. Add it to your active theme's functions.php.
This works but added the description in both the processing and the completed mail and admin mails. There seems to something wrong with the status check $email->id == 'customer_completed_order'. I added $status = $order->get_status(); and changed it to look for $status == "completed" instead. It works for me, but please add your thoughts or comments if this is a good way.
add_action( 'woocommerce_email_before_order_table', 'add_content_before_order_table', 99, 4 );
function add_content_before_order_table( $order, $sent_to_admin, $plain_text, $email ) {
// checking if it's the order status we want
$status = $order->get_status();
if ( $status == "completed" ) {
// initializes the array with all product descriptions
$descriptions = array();
// for each product ordered
foreach ( $order->get_items() as $order_item ) {
$product = $order_item->get_product();
// get the product description
if ( $product->get_description() ) {
$descriptions[] = $product->get_description();
}
}
// if the $descriptions is not empty it shows it
if ( ! empty( $descriptions ) ) {
foreach ( $descriptions as $content ) {
echo '<p>' . $content . '</p>';
}
}
}
}
Im trying to apply a custom post meta field billing_company_id to orders formatterd billing address, and place it below billing company.
Via the following code I can apply a string but how to get the custom post meta from an order?
add_action( 'woocommerce_order_get_formatted_billing_address', 'company_billing_id', 20, 1 );
function company_billing_id($address){
$address .= 'Custom field string';
return $address;
}
The woocommerce_order_get_formatted_billing_address filter hook contains not 1 but 3 parameters.
Via the 3rd you have access to the $order object, so you could use something like:
/**
* Filter orders formatterd billing address.
*
* #since 3.8.0
* #param string $address Formatted billing address string.
* #param array $raw_address Raw billing address.
* #param WC_Order $order Order data. #since 3.9.0
*/
function filter_woocommerce_order_get_formatted_billing_address( $address, $raw_address, $order ) {
// Get meta
$value = $order->get_meta( 'billing_company_id' );
// NOT empty
if ( ! empty ( $value ) ) {
// Append
$address .= $value;
}
return $address;
}
add_filter( 'woocommerce_order_get_formatted_billing_address', 'filter_woocommerce_order_get_formatted_billing_address', 10, 3 );
This question already has answers here:
How to get WooCommerce order details
(6 answers)
Closed 2 years ago.
How can I get a custom billing field from my WooCommerce order? For example I've WooCommerce Germanized installed which adds a custom billing field named vat_id.
I've found a function get_address_prop() in the WooCommerce orders class but this function is protected so I can't call it with $order->get_address_prop().
Any ideas? Thanks!
This is my function I've created to retrieve any custom billing field I want:
/**
* Returns a custom billing field value
*
* #param object $order
* #param string $custom_field
*
* #return string
*/
function get_custom_billing_field( object $order, string $custom_field ): string {
$order_data = $order->get_data();
$custom_field_val = '';
if ( ! empty( $order_data ) && isset( $order_data['billing'][ $custom_field ] ) ) {
$custom_field_val = $order_data['billing'][ $custom_field ];
}
return apply_filters( 'get_custom_billing_field', $custom_field_val );
}
This is an example call for retrieving the vat_id set in WooCommerce Germanized Pro:
$order = wc_get_order( 22 );
get_custom_billing_field( $order, 'vat_id' );
I hope this helps someone. If you got a better idea, please let me know.
so, I'm stuck with adding second custom checkout field to my store.
That first custom field is radio buttons and it is added straight in to template field. The other one is the same radio buttons but with different id and names.
Shipping part works just fine, but that Private label is not saving and is not displayed in admin area after order is complete.
Here is what I already have, what am i doing wrong?
/**
* Update the user meta with field value
**/
add_action('woocommerce_checkout_update_user_meta', 'my_custom_checkout_field_update_user_meta');
function my_custom_checkout_field_update_user_meta( $user_id ) {
if ($user_id && $_POST['shippinng']) update_user_meta( $user_id, 'shippinng', esc_attr($_POST['shippinng']) );
if ($user_id && $_POST['private']) update_user_meta( $user_id, 'private', esc_attr($_POST['private']) );
}
/**
* Update the order meta with field value
**/
add_action('woocommerce_checkout_update_order_meta', 'my_custom_checkout_field_update_order_meta');
function my_custom_checkout_field_update_order_meta( $order_id ) {
if ($_POST['shippinng']) update_post_meta( $order_id, 'Transport', esc_attr($_POST['shippinng']));
if ($_POST['private']) update_post_meta( $order_id, 'Private label', esc_attr($_POST['private']));
}
/**
* Display field value on the order edit page
*/
add_action( 'woocommerce_admin_order_data_after_billing_address', 'my_custom_checkout_field_display_admin_order_meta', 10, 1 );
function my_custom_checkout_field_display_admin_order_meta($order){
echo '<p><strong>'.__('Transport').':</strong> ' . get_post_meta( $order->id, 'Transport', true ) . '</p>';
echo '<p><strong>'.__('Private label').':</strong> ' . get_post_meta( $order->id, 'Private label', true ) . '</p>';
}
/**
* Add the field to order emails
**/
add_filter('woocommerce_email_order_meta_keys', 'my_custom_checkout_field_order_meta_keys');
function my_custom_checkout_field_order_meta_keys( $keys ) {
$keys[] = 'Transport';
$keys[] = 'Private label';
return $keys;
}
You have to register private label in order to save it. I advise downloading checkout field editor and examining the code for learning purposes. Comparison has always been a good model to follow from my experience :)
This isn't a full answer but I can see one issue with how you are adding the fields to the emails. It's an old question but I thought I'd answer it to help myself out when I inevitably have to Google it in 6 months.
Doing this:
$keys[] = 'Transport';
$keys[] = 'Private label';
The second line overwrites the first, so the $keys array becomes just array( "Private label" );.
Instead, try formatting it like this:
$keys = array("Transport", "Private label");
This is working on my current project:
/* Add custom field to emails */
add_filter('woocommerce_email_order_meta_keys', 'my_custom_order_meta_keys');
function my_custom_order_meta_keys( $keys ) {
$keys = array("Purchase Order Number", "Preferred Delivery Date"); // This will look for both of the specified fields and add them to the emails
return $keys;
}