How can I add the product name in the subject line of this email. is there a list of the available filters for the email subject lines? I'd like to be able to do this without having to write custom php. I'm looking to do something like this:
Completed Order - [{product_name}] ({order_number}) - {order_date}
Below code tried and added in functions.php but subject is not displaying:
add_filter( 'woocommerce_email_subject_customer_completed_order', 'customer_completed_order_subject', 10, 2 );
function customer_completed_order_subject($string,$order){
$fname = $order->billing_first_name;
$lanme = $order->billing_last_name;
$email = $order->billing_email;
$items = $order->get_items();
foreach($items as $meta_key => $items){
$product_name = $items['name'];
$product_id = $items['product_id'];
}
$subject_line = get_field('email_subject',$product_id);
$subject_line = str_replace('{product}',$product_name,$subject_line);
$subject_line = str_replace('{biller_fname}',$fname,$subject_line);
$subject_line = str_replace('{biller_lastname}',$lanme,$subject_line);
$subject_line = str_replace('{biller_email}',$email,$subject_line);
$subject_line = str_replace('{blog_name}',get_bloginfo('name'),$subject_line);
return $subject_line;
}
You are not using the correct hook and there are mistakes… Instead use the following:
add_filter( 'woocommerce_email_format_string' , 'add_custom_email_format_string', 10, 2 );
function add_custom_email_format_string( $string, $email ) {
$order = $email->object; // Get the instance of the WC_Order OBJECT
$order_items = $order->get_items(); // Get Order items
$order_item = reset($order_items); // Get the irst order item
// Replace placeholders with their respective values
$string = str_replace( '{biller_fname}', $order->billing_first_name(), $string );
$string = str_replace( '{biller_lname}', $order->billing_last_name(), $string );
$string = str_replace( '{biller_email}', $order->billing_email(), $string );
$string = str_replace( '{product_name}', $order_item->get_name(), $string );
$string = str_replace( '{blog_name}', get_bloginfo('name'), $string );
return $string;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Note: An order can have many items, so many product names. In the code above, I only keep the first product name…
If you want to handle multiple product names, you will use:
add_filter( 'woocommerce_email_format_string' , 'add_custom_email_format_string', 10, 2 );
function add_custom_email_format_string( $string, $email ) {
$order = $email->object; // Get the instance of the WC_Order OBJECT
$products_names = array();
// Loop through order items
foreach( $order->get_items() as $item ) {
$products_names[] = $item->get_name();
};
// Replace placeholders with their respective values
$string = str_replace( '{biller_fname}', $order->billing_first_name(), $string );
$string = str_replace( '{biller_lname}', $order->billing_last_name(), $string );
$string = str_replace( '{biller_email}', $order->billing_email(), $string );
$string = str_replace( '{product_name}', implode(' ', $products_names), $string );
$string = str_replace( '{blog_name}', get_bloginfo('name'), $string );
return $string;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Related: Add a custom placeholder to email subject in WooCommerce
Related
I'm combining four individual ACF fields into one text field, but I need to sanitize those entries individually so I can use them all as CSS classes. I've been trying to use sanitize_title() to turn plain english field values into the equivalent of post slugs—lowercase with dashes instead of spaces and no special characters.
A simplified, two-field example would be:
Status One / Status Two and Sector One / Sector Two / Sector Three
into
status-one-status-two sector-one-sector-two-sector-three
Note that I'm trying to sanitize before merging so I can keep my entries separated by spaces (i.e. multiple CSS classes instead of one-incredibly-long-css-class.
I found the original function here and successfully modified it to merge four of my fields into a fifth ACF field.
function my_acf_save_post( $post_id ) {
$value1 = get_field( 'status', $post_id );
$value2 = get_field( 'sector', $post_id );
$value3 = get_field( 'subsector', $post_id );
$value4 = get_field( 'lead', $post_id );
$clean1 = sanitize_title( $value1 );
$clean2 = sanitize_title( $value2 );
$clean3 = sanitize_title( $value3 );
$clean4 = sanitize_title( $value4 );
$merge = implode(" ",$clean1).' '.implode(" ",$clean2).' '.implode(" ",$clean3).' '.implode(" ",$clean4);
update_field( 'css_classes', $merge );
}
add_action('acf/save_post', 'my_acf_save_post', 20);
I've tried a number of sanitize_* functions—most of them at this point—and a kajillion different syntaxes and I still can't get it to work because I'm a designer who writes a bit of code and not a developer (but you know that by now). kthxbai in advance.
Try out this code to create a slug and merge fields into one.
function custom_slug($text, string $divider = '-')
{
// replace non letter or digits by divider
$text = preg_replace('~[^\pL\d]+~u', $divider, $text);
// transliterate
$text = iconv('utf-8', 'us-ascii//TRANSLIT', $text);
// remove unwanted characters
$text = preg_replace('~[^-\w]+~', '', $text);
// trim
$text = trim($text, $divider);
// remove duplicate divider
$text = preg_replace('~-+~', $divider, $text);
// lowercase
$text = strtolower($text);
if (empty($text)) {
return 'n-a';
}
return $text;
}
function my_acf_save_post( $post_id ) {
$value1 = get_field( 'status', $post_id );
$value2 = get_field( 'sector', $post_id );
$value3 = get_field( 'subsector', $post_id );
$value4 = get_field( 'lead', $post_id );
$clean1 = custom_slug( $value1 );
$clean2 = custom_slug( $value2 );
$clean3 = custom_slug( $value3 );
$clean4 = custom_slug( $value4 );
$merge = $clean1.' '.$clean2.' '.$clean3.' '.$clean4;
update_field( 'css_classes', $merge, $post_id );
}
add_action('acf/save_post', 'my_acf_save_post', 20);
I am using Woocommerce + Gravity forms with the WooCommerce Gravity Forms Product Add-Ons. My form contains a Nested Gravity Perks Form. I need to add the Woocommerce Order number to both the parent and the child gravity form. I have accomplished this with the following code:
add_action( 'woocommerce_checkout_order_processed', 'wc_add_order_id' );<br>function wc_add_order_id( $order_id ) {
$order = wc_get_order( $order_id );
foreach ( $order->get_items() as $item ){
$product_id = $item['product_id'];
if ( has_term( 'camp', 'product_cat', $product_id ) ) { //my woocommerce category
$meta_data = $item->get_formatted_meta_data();
$meta_data_items = $item->get_meta_data();
foreach ( $meta_data_items as $meta ) {
$entry_id = $meta->value['_gravity_form_linked_entry_id'];
$entry = GFAPI::get_entry( $entry_id );
$entry['40'] = $order_id ; //40 is the id of a single field reserved for the Order #
$result = GFAPI::update_entry( $entry );
return $result;
}
}
}
};
I then tried the following to add the order number to my child form (this works if I manually update the parent form entry. It does not work automatically from the update_entry trigger above:
add_action( 'gform_after_update_entry_82', function ( $form, $entry_id ) { //82 is the parent form id<br>
$entry = GFAPI::get_entry( $entry_id );
$entry_child_order = rgar( $entry, '2' ); //2 is the field that contains the entry id of the child
$order_id = rgar( $entry, '40' ); //this has the Woocommerce Order #
$entry2 = GFAPI::get_entry( $entry_child_order);
$entry2['147'] = $order_id ; //147 is the single field reserved for the order number
$result = GFAPI::update_entry( $entry2 );
return $result;
}, 10, 2 );
Does anyone know why "GFAPI::update_entry( $entry );" doesn't automatically trigger the second half of this code?
Ok. I figured it out. I was able to put everything into the same function and it is working.
//add order number to gravity forms
add_action( 'woocommerce_checkout_order_processed', 'wc_add_order_id' );
function wc_add_order_id( $order_id ) {
$order = wc_get_order( $order_id );
$cart_reg = $order->get_items();
$entry_id = array();
$entry_id2 = array();
$entry_id[] = $linked_entry;
$entry_id2[] = $linked_nested_value;
foreach( $cart_reg as $key => $value) {
$linked_entry=$value->get_meta( '_gravity_forms_history')["_gravity_form_linked_entry_id"];
$entry_id = $linked_entry;
$entry = GFAPI::get_entry( $entry_id );
$entry['40'] = $order_id; //40 is my field number that will contain orede number
$result = GFAPI::update_entry( $entry );
$linked_nested_value=$value->get_meta( '_gravity_forms_history')["_gravity_form_lead"]['2'];
if(!$linked_nested_value == ''){
$nested_value_array = preg_split ("/\,/", $linked_nested_value); //array of child entries
$child_entry_amt = substr_count($linked_nested_value, ",") + 1;
}//child entries
if ($child_entry_amt > 0){
for ($n = 0; $n < $child_entry_amt; $n++) {
$entry_id2=$nested_value_array[$n];
$entry2 = GFAPI::get_entry( $entry_id2 );
$entry2['147'] = $order_id;//this is my field number on my child form that will contain order number
$result2 = GFAPI::update_entry( $entry2 );
}
}
}
};
I have found the following code from this answer thread, but it only applied under the product title. So how can apply to the detailed description of the product.
add_action( 'woocommerce_after_shop_loop_item_title', 'shorten_product_excerpt', 35 );
function shorten_product_excerpt()
{
global $post;
$limit = 14;
$text = $post->post_excerpt;
if (str_word_count($text, 0) > $limit) {
$arr = str_word_count($text, 2);
$pos = array_keys($arr);
$text = substr($text, 0, $pos[$limit]) . '...';
// $text = force_balance_tags($text); // may be you dont need this…
}
echo '<span class="excerpt"><p>' . $text . '</p></span>';
}
In Woocommerce product single pages, the long description is displayed in the "description tab". If you look at the source code of single-product/tabs/description.php template, it use the_content() wordpress function to display that long description.
So you can use the_content dedicated Wordpress filter hook to reduce the product long description:
add_filter( 'the_content', 'shorten_product_long_descrition', 20 );
function shorten_product_long_descrition( $content ){
// Only for single product pages
if( ! is_product() ) return $content;
// Set the limit of words
$limit = 14;
if (str_word_count($content, 0) > $limit) {
$arr = str_word_count($content, 2);
$pos = array_keys($arr);
$text = '<p>' . substr($content, 0, $pos[$limit]) . '...</p>';
$content = force_balance_tags($text); // needded
}
return $content;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Before:
After:
Similar: Limit product short description length in Woocommerce
I have a similar problem mentioned here and I want that a short description of the variable product was displayed on the catalog page.
I'm using WooCommerce Show Single Variations commercial pluginn, but it doesn't display short description.
Before that I used some code to display description of simple product on shop page that worked and it looks like this:
add_action( 'woocommerce_after_shop_loop_item_title',
'add_short_description', 9 );
function add_short_description() {
global $post;
$text = $post->post_excerpt;
$maxchar = 75; //максимальное кол-во символов
$text = preg_replace ('~\[[^\]]+\]~', '', $text ); //убираем шорткоды
//удаляем все html символы
//$text = strip_tags( $text);
// Обрезаем
if ( mb_strlen( $text ) > $maxchar ){
$text = mb_substr( $text, 0, $maxchar );
$text = preg_replace('#(.*)\s[^\s]*$#s', '\\1 ...', $text );
}
echo "<span class='catalog-short-desc'>$text</span>";
}
I would be grateful if you tell me how to change this code.
Updated: As I dont have and I don't use your commercial plugin and as your question is not so clear… There is 2 possibilities:
1) You would like to add the short description (from the parent variable product) for the product variations that are displayed (with your plugin) on woocommerce archives pages (like shop …), just like the other products.
This should do the trick (untested with no errors):
add_action( 'woocommerce_after_shop_loop_item_title', 'add_short_description', 9 );
function add_short_description() {
global $post;
// 1. Product variation
if ($post->post_type = 'product_variation'){
$post_parent_id = $post->post_parent; // Get the parent variable product ID
$post_parent = get_post( $post_parent_id ); // Get the parent variable WP_Post object
$text = $post_parent->post_excerpt; // Get the short description from the parent variable product
}
// 2. Other cases (simple, variable …)
else {
$text = $post->post_excerpt;
}
$maxchar = 75; // Maximum number of characters
$text = preg_replace ('~\[[^\]]+\]~', '', $text ); // Remove shortcodes
// Remove all html symbols
//$text = strip_tags( $text);
// Crop
if ( mb_strlen( $text ) > $maxchar ){
$text = mb_substr( $text, 0, $maxchar );
$text = preg_replace('#(.*)\s[^\s]*$#s', '\\1 ...', $text );
}
echo "<span class='catalog-short-desc'>$text</span>";
}
2) You would like to add the description of the product variations that are displayed (with your plugin) on woocommerce archives pages (like shop …), just like the other products… For Product variation short description doesn't exist (it's empty)…
This should do the trick (untested with no errors):
// For Woocommerce versions 3+ only
add_action( 'woocommerce_after_shop_loop_item_title', 'add_short_description', 9 );
function add_short_description() {
global $post, $product;
// 1. Product variation
if ( $product->is_type('product_variation') ){
// Get the product variation description
// short description doesn't exist for product variations
$text = $product->get_description();
// If the product variation description is empty, we get the parent short description
if( empty( $text ) ){
$parent_id = $product->get_parent_id(); // The parent variable product ID
$parent_product = wc_get_product( $parent_id ); // The parent WC_Product object
$text = $parent_product->get_short_description();
}
}
// 2. Other cases (simple, variable …)
else {
$text = $product->get_short_description();
}
$maxchar = 75; // Maximum number of characters
$text = preg_replace ('~\[[^\]]+\]~', '', $text ); // Remove shortcodes
// Remove all html symbols
//$text = strip_tags( $text);
// Crop
if ( mb_strlen( $text ) > $maxchar ){
$text = mb_substr( $text, 0, $maxchar );
$text = preg_replace('#(.*)\s[^\s]*$#s', '\\1 ...', $text );
}
echo "<span class='catalog-short-desc'>$text</span>";
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
I would like to change the order received (thanks page) url for a new one, which includes the ordered product's ID.
Here is the code in the class-wc-order.php
/**
* Generates a URL for the thanks page (order received).
*
* #return string
*/
public function get_checkout_order_received_url() {
$order_received_url = wc_get_endpoint_url( 'order-received', $this->get_id(), wc_get_page_permalink( 'checkout' ));
if ( 'yes' === get_option( 'woocommerce_force_ssl_checkout' ) || is_ssl() ) {
$order_received_url = str_replace( 'http:', 'https:', $order_received_url );
}
$order_received_url = add_query_arg( 'key', $this->get_order_key(), $order_received_url );
return apply_filters( 'woocommerce_get_checkout_order_received_url', $order_received_url, $product, $this, $product->id );
}
Any idea?
Thanks!
This answer on wordpress.stackexchange.com would solve the issue
As a brief, just define the following hook:
add_filter('woocommerce_get_checkout_order_received_url','override_return_url',10,2);
function override_return_url($return_url,$order){
//create empty array to store url parameters in
$sku_list = array();
// retrive products in order
foreach($order->get_items() as $key => $item)
{
$product = wc_get_product($item['product_id']);
//get sku of each product and insert it in array
$sku_list['product_'.$item['product_id'] . 'sku'] = $product->get_sku();
}
//build query strings out of the SKU array
$url_extension = http_build_query($sku_list);
//append our strings to original url
$modified_url = $return_url.'&'.$url_extension;
return $modified_url;
}
Then, you can set the analytics goal to point to the destination below as a regular expression
\/checkout\/order-received\/\d+\/\?key=\w+&product_ID_HERE_sku=SKU_HERE
We can make it simpler by including only product ids:
add_filter('woocommerce_get_checkout_order_received_url','override_return_url',0,2);
function override_return_url($return_url,$order){
$ids = array();
foreach($order->get_items() as $key => $item)
{
$ids[] = $item['product_id'];
}
return add_query_arg('product_ids', join(',', $ids) , $return_url);
}
In this case, the regex would be:
\/checkout\/order-received\/\d+\/\?key=\w+&product_ids=ID1,ID2,ID3
Or for a single product id:
\/checkout\/order-received\/\d+\/\?key=\w+&product_ids=[\w,]*ID[\w,]*