How to add label for Custom fields in WooCommerce - php

I build a webshop with a couple Custom fields, these custom fields are in my order emails now but I cant seem to find out how to add a label for this. Currently it shows my meta key name or my id but I want to change it like the label on my custom fields!
The code I used in Functions.php:
/**
* 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[] = 'additional_wooccm1';
return $keys;
}
Let me know if you can help me!
[My order email](https://i.stack.imgur.com/ko9vQ.png)
My custom fields
I tried multiple ways like with Snippets into the Function.php but also copied the customer-processing-order.php and tried editing this file without any result.

Related

How to properly create a WooCommerce Variation using the helper class WC_Product_Variation

Before anything, I'd like to say that I have thoroughly searched all over internet to find as much help as I could into solving this particular issue.
I have tried many different ways of creating a variation, in particular this one which also didn't seem to bind the label to the field next to the variation ID on my product page. The outcome was the same as the method I've written with the helper class. I still have it commented somewhere so if you happen to know a solution for this specific way of creating a variation, hit me up!
Some context: I have a csv file with a lot of information on my products. I wrote a script to import them into WooCommerce programmatically using the WC_Product_Simple helper class and a stripped down version of the original csv (with only two items), and everything worked perfectly for the two products. Item #2 is flour, so I figured I'd try creating variations for it instead of creating multiple simple products (for instance Flour (100Gr), Flour (500Gr) and Flour (1Kg)).
I was able to create an attribute for my WC_Product_Variable, set its variation field to true, create three variations (100Gr, 500Gr and 1Kg) and save them. When I look at my Products page in WooCommerce, I can see the three variations under my variable product.
The issue I'm having is that I can't bind a particuliar field to one variation, no matter how hard I try. I have no idea how this field is called, tho I've noticed that setting it reads/writes the post_excerpt column in my {$wpdb->prefix}posts table.
Here is what is displayed:
And here is what I want to achieve programmatically:
Here's the code:
/**
* At this point, the product is correctly created and available through $wc_product.
* Its id is stored in $product_id.
* I also have an array with information from my product called $product.
* This is where the information is stored to create said product.
* You don't have to worry about the creation of the product itself.
*/
// I have stored as a boolean whether my product had variations or not.
if ($variable) {
// Weight => Label
$weights = array(
'100' => '100Gr',
'500' => '500Gr',
'1000' => '1Kg'
);
$attribute = new WC_Product_Attribute();
$attribute->set_id(0);
$attribute->set_name('Weight');
$attribute->set_options(
$weights
);
$attribute->set_position(0);
$attribute->set_visible(true);
$attribute->set_variation(true);
$wc_product->set_attributes(array($attribute));
$wc_product->save();
// At this point my attribute is created. There is no save method for WC_Product_Attribute.
// I'm 100% sure that everything up to this point works as expected, I've left it here
// for clarity and for better understanding what the code does.
foreach ($weights as $weight=>$label) {
// Each variation will be named after the product sku followed by its label.
// For instance: sku5436-100Gr where sku5436 is the variable product.
$variation_sku = "{$product["sku"]}-{$label}";
// Will uncomment once this works!
// These two lines make sure that each variation is unique through their sku.
// $var_id = wc_get_product_id_by_sku($variation_sku);
// $variation = $var_id?new WC_Product_Variation($var_id):new WC_Product_Variation();
/**
* I create my variation,
* I set its parent id,
* I set its sku,
* I calculate its price with a simple weight/price formula,
* I set its price
*
* And here's the part I'm not too sure about
* I thought "set_attributes" would select between 100Gr, 500Gr and 1Kg
* but it looks like it doesn't do anything. I could just remove that line
* and nothing would change.
*/
$variation = new WC_Product_Variation();
$variation->set_parent_id($product_id);
$variation->set_sku($variation_sku);
$variation_price = ($weight / 1000) * $product["kg_price"];
$variation->set_regular_price($variation_price);
// This is the line I thought would bind the label to the field, but it doesn't
$variation->set_attributes(array("Weight" => $label));
$id_var = $variation->save();
// I tried manually setting the post excerpt. The update works, but since
// it wasn't set through the helper class, I'm assuming some cache
// thing isn't correctly binding the label to the field which I still don't know the name
// global $wpdb;
// $wpdb->update($wpdb->prefix . "posts", array("post_excerpt" => $label), array("ID" => $id_var));
}
}
In short: I'd like to bind the fields next to the post ID (see screenshots) to the correct variation. My code does almost everything except that.
I would also really appreciate if someone could tell me the name of this field. The closest thing I've found is that it is bound to the post_excerpt.

Add field in woocommerce email setting tab in dashboard

I wanted to add a field in WooCommerce > Settings > Emails tab. In this section there is a list of email template and on clicking any template you can see this screen.
I want to add another field to this section for every template.
I manage to achieve it but I'm feeling its not a proper way.
My code is as follow:
add_filter( 'woocommerce_settings_tabs_email', 'emailText' );
function emailText($args) {
?>
<div class="EmailText">
<label for="EmailText">Email Text</label>
<textarea id="EmailText" class="widefat" name="email_text"></textarea>
</div>
<?php
}
It displays the field but I cannot save anything in it.
The WooCommerce Email Settings tab has a table with all of the available email templates such as 'New Order', 'Canceled Order', 'Failed Order', etc. These are usually defined by extending the WC_Email class. Take a look in /plugins/woocommerce/includes/emails for examples.
As WildProgrammers has pointed out, the 'woocommerce_settings_api_form_fields_{email-id}' can be easily used to add a setting to a specific email class. You can see the definition on the WooCommerce Settings API Code Reference page. It provides us with the array of form fields for the email class.
For this example lets add an additional option to the 'New Order' email template. We can look in the WC_Email_New_Order class constructor (found in class-wc-email-new-order.php) to find/verify the id to replace {email-id} in our hook. In this case the WC_Email_New_Order class id is 'new_order' so to add a setting or form field to the New Order options our hook will look like, add_action( 'woocommerce_settings_api_form_fields_new_order', 'add_my_custom_email_setting',10,1);
Now in the 'add_my_custom_email_setting' function all we need to do is add our new setting to the form_fields array and return it:
function add_my_custom_email_setting($form_fields){
$form_fields['my_custom_id']=['title'=>'My Custom Option',
'description'=>'This is a text area we added to the new order email settings page.',
'type'=>'textarea',
'default'=>''
];
return $form_fields;
}
Take a look at the 'init_form_fields' function in WC_Email class for examples of how to build the options array.
You asked how to add an option to all of the available templates. To do this we could simply manually define a hook for every email class,
add_action('woocommerce_settings_api_form_fields_new_order','add_my_custom_email_setting');
add_action('woocommerce_settings_api_form_fields_failed_order','add_my_custom_email_setting');
add_action('woocommerce_settings_api_form_fields_processing_order','add_my_custom_email_setting');
...
but if we can get a list of all of the id's then we can do it programatically instead. Lucky for us WooCommerce provides us with the 'woocommerce_email_classes' filter which is called right after WC instantiates all of the email classes. Now all we need is a function that iterates over the array of email classes provided by the 'woocommerce_email_classes' filter, get the class id's, and add a hook to 'woocommerce_settings_api_form_fields_{email-id}' for each id:
add_action( 'woocommerce_email_classes', 'add_email_custom_setting');
function add_email_custom_setting($email_class_list){
foreach($email_class_list as $email_class){
add_action( 'woocommerce_settings_api_form_fields_' . $email_class->id,'add_my_custom_email_setting',10,1);
}
return $email_class_list;
}`
We can then use this option in our template files with $email->get_option('my_custom_id');.
You might ask why not simply add the option to the form_fields array in add_email_custom_setting?
Instead of using 'woocommerce_settings_tabs_email' filter try using
'woocommerce_email_settings_after' hook for creating your field.

WooCommerce REST API v2 - Show Protected Meta Data

I am integrating a WooCommerce website into an application I've built.
I am attempting to retrieve custom fields for products (meta data) using the API.
The below is an excerpt from the docs regarding changes from v1 to v2
v1 does not include order item meta, v2 includes full order item meta (with an optional filter parameter to include protected order item meta)
https://woocommerce.github.io/woocommerce-rest-api-docs/v2.html#version
I cannot seem to find anywhere what this actual filter is. The filter below is what's used to get meta data initially
filter[meta]=true
But through my searching, I cannot find the additional filter to return protected meta data for products. Note I am not trying to update protected meta, but just view protected meta.
I found a workaround for now. I did not find a filter for protected fields in the API call however I added the following code to my functions.php file
add_filter( 'is_protected_meta', function ( $protected, $key, $type ) {
if ( $key === '_my_protected_meta_field' ) {
// Expose the `_my_protected_meta_field` meta value publicly
return false;
}
return $protected;
}, 10, 3 );
The meta data for _my_protected_meta_field now shows in the API call with filter[meta]=true

Display Prestashop new product field on product-list.tpl and home featured modules

Using this tutorial on this page Adding new tabs and fields to Prestashop products’ back office, I was able to add a new field for author for products in my Prestashop. I was also able to display it on product page by adding Product.php to override/classes/ and inserting this code below:
class Product extends ProductCore
{
/** #var string Custom Product Field */
public $custom_field;
}
I then added {$product->custom_field} to product.tpl to display the new field. My challenge is that the same code does not work when added to product-list.tpl and the homefeatured.tpl module files.
Can any one explain how to achieve this? I am not an expert but I can find my way around tutorials if I have one. Thanks!
Find the function used by the module Homefeatured to get the products and edit the SQL request in this function to add your new field.
You can't display your new propertie because the SQL request don't get it.
Use . instead of ->
In product-list.tpl & homefeatured.tpl $procuct is array not object.
And do not miss the getFields() method in Product class:
public function getFields()
{
$fields = parent::getFields();
$fields['custom_field'] = $this->custom_field;
return $fields;
}

Multi select filter in layered navigation

I have a custom multi select attribute which I'd like to take part in filtering of products. The attribute is set as used in Layered Navigation however doesn't appear in the list of available filters. Could be due to custom model implementation?
Anyone have some tips where to check why it doesn't appear? Attribute is set for several products
Magento version used is EE 1.11
Thanks
For those who will struggle with this in the future: the problem is in Mage_Catalog_Model_Resource_Product_Indexer_Eav_Source file on line 191. By default multi select attribute values are being pulled from eav_attribute_option and if your custom attribute uses custom source model the attribute will not be indexed.
I don't know as of yet if it's intended but I couldn't find a better solution than overriding that model in local pull and adding required values in $options array.
Hope this helps someone, someday
What is the backend_type. i.e. are the values stored in the catalog_product_entity_varchar or catalog_product_entity_text table?
The backend_type has to match the checks in Mage_Catalog_Model_Resource_Eav_Attribute::isIndexable(), so text wouldn't work without rewriting the attribute model.
Is the is_filterable and/or is_filterable_in_search attribute property set?
The Mage_Catalog_Model_Product_Indexer_Eav::_registerCatalogAttributeSaveEvent() checks for those when updating the index for the layered navigation.
Are the methods getFlatColums(), getFlatIndexes() and getFlatUpdateSelect() implemented in the custom source model?
This actually is only required for building and updating the flat catalog product tables (so the used_in_product_listing or is_filterable property needs to be set in order for Magento to pick up the attribute).
Check the class Mage_Eav_Model_Entity_Attribute_Source_Table as a reference on what these there methods are supposed to return.
NOTE: I'm adding this in a new answer to use the code format.
How it was said, the problem is with multiselect attributes using a custom source model.
Solution:
Rewrite the class
Mage_Catalog_Model_Resource_Product_Indexer_Eav_Source
Override the method:
_prepareMultiselectIndex
add this code after the $options array is filled with the default code (check line 200 in original file)
foreach($attrIds as $attId){
if( ! isset($options[$attId])){
$options[$attId] = $this->_getOptionsFromSourceModel($attId);
}
}
add this method too:
protected function _getOptionsFromSourceModel($attId)
{
$options = array();
/** #var Mage_Eav_Model_Entity_Attribute_Abstract $attribute */
$attribute = Mage::getResourceSingleton('catalog/product')->getAttribute($attId);
/** #var Mage_Eav_Model_Entity_Attribute_Source_Abstract $source */
$source = $attribute->getSource();
$sourceOptions = $source->getAllOptions();
if($sourceOptions){
foreach($sourceOptions as $sourceOption){
if(isset($sourceOption['value'])){
$options[$sourceOption['value']] = true;
}
}
}
return $options;
}
I couldn't find a less intrusive way to fix this.

Categories