How to display product.variation_price without currency in Drupal Commerce? - drupal

I need to display product price in the template commerce-product.html.twig
The variable {{ product.variation_price }} is rendered as currency and number e.g. USD700
And I can't understand how to display only number without currency?

There are two ways to achieve this:
Use the Commerce Currency Settings module.
Implement hook_commerce_currency_info_alter() in your custom module.
Since the task is very simple and will most likely never need to be updated after initial setup, there is no need to install another module. This means less components to think about and update in the long run, and less pages in the admin.
By implementing this in your custom module you will also get complete freedom to change the format in which the values are displayed. You can replace the dollar sign with USD, move it before / after the value or add custom labels.
Here's the code you need to use:
/**
* Implements hook_commerce_currency_info_alter().
*/
function YOUR_MODULE_commerce_currency_info_alter(&$currencies) {
// Get the abbreviation of the default currency. This will return "USD" for
// US Dollars, "EUR" for Euros, etc.
// If your site is using multiple currencies, you can skip this and just use
// the abbreviation of the currency you want to change the format for.
$default_currency = commerce_default_currency();
$currencies[$default_currency]['format_callback'] = 'YOUR_MODULE_commerce_currency_format';
}
/**
* Commerce currency format callback.
*/
function YOUR_MODULE_commerce_currency_format($amount, $currency, $currency_code, $object = NULL, $convert = TRUE) {
// Format the price as a number.
$price = number_format($amount, 2, $currency['decimal_separator'], $currency['thousands_separator']);
// Establish the replacement values to format this price for its currency.
$replacements = array(
'#code_before' => $currency['code_placement'] == 'before' ? '' : '', //Here you can set empty or put $currency['code']
'#symbol_before' => $currency['symbol_placement'] == 'before' ? '' : '', // set empty or $currency['symbol']
'#price' => $price,
'#symbol_after' => $currency['symbol_placement'] == 'after' ? '' : '', // set empty or $currency['symbol']
'#code_after' => $currency['code_placement'] == 'after' ? '' : '', //set empty or $currency['code']
'#negative' => $amount < 0 ? '-' : '',
'#symbol_spacer' => $currency['symbol_spacer'],
'#code_spacer' => $currency['code_spacer'],
);
return trim(t('#code_before#code_spacer#negative#symbol_before#price#symbol_spacer#symbol_after#code_spacer#code_after', $replacements));
}
NOTE: if you place the hook_commerce_currency_info_alter()
implementation in YOUR_MODULE.commerce.inc file, the callback will
still need to be placed in the .module file, because the .commerce.inc
file will not be automatically loaded everywhere.
That's it - all prices will be displayed without currency code.

Well, I've just found the answer by myself.
If a product has only one variation, we can get its price as number in Twig like:
{% set price_number = product.variation_price['#items'].0.number %}
Now, according to Displaying prices we can print it without fraction part like:
{{ price_number|number_format(0) }}

Related

Updating an ACF field after creating a Woocommerce attribute

I have a set of products (courses) that are dependent on a calendar.
The calendar is generated by a post type date which has an ACF field date_start and an associated_product
The logic is; the user creates a post-type Date which adds an attribute term to the associated product's attribute pa_dates.
I have hooked save_post and so far so good, the attribute is written to the product.
I then need to copy the date field to the term created $term_set this section doesn't produce anything. (I need this date to order the terms in my product)
Part of the problem is I have no way of interrogating the variables as this is all happening in a hook that has no way of printing output. (I have tried fwrite but with no result)
// Add terms on Date save.
function add_terms_to_date($post_ID) {
if ('date' !== get_post_type() ) {
return;
} else {
$product_id = get_field('associated_product',$post_ID);
$term_name = get_the_title($post_ID);
$taxonomy = 'pa_dates';
$term_set = wp_set_post_terms( $product_id, $term_name, $taxonomy, true );
// up to here, works fine.
// now need to identify that term ($term_set)
// Then I need to write copy the date field to its ACF field in my Date attribute
$selector = "term_date_start"; // the ACF field in the term
$date_start = get_field('date_start', $post_ID); // the date field to be copied
$value = $date_start;
// This next line caused the issue leading to the question so is commented out
// update_field($selector, $value, $term_set);
// and this line is correct
update_field($selector, $value, $taxonomy."_".$term_set);
}
}
add_action('save_post', 'add_terms_to_date');
So, complicated question, simple answer.
The last line should read;
update_field($selector, $value, $taxonomy."_".$term_set);
to avoid confusion with post IDs (RTFM) ACF has a different system for identifying terms. ($taxonomy comes from the earlier line and is pa_dates)
I have edited the post above, just in case it can provide help to someone.

Alter views search api solr result

I am using search api and Solr, When I echo the result variable , it gave me the following results
stdClass Object
(
[entity] => 442415
[_entity_properties] => Array
(
[search_api_relevance] => 1
[search_api_excerpt] =>
[search_api_item_id] => 442415
)
)
In views i added ( custom text field, that is global variable), With this nid 442415, i will do certain node load operation and finally,
i will get price for the specific product. This code block will execute inside the foreach.
_views_pre_render
Please guideme,
which hook i should use , _views_post_execute or _views_pre_render ?
How to assign new value in to which variable and how to print that in tpl
Finally, i want to display the price on each item
This link resolved my problem.
Solution approach
function mymodule_views_pre_render(&$view) {
if($view->name == 'my_view') {
foreach($view->result as &$row) {
$row->_entity_properties['nothing'] = 'new value';
}
}
}
views-view-field--view-name--display-name--nothing.tpl.php
print $row->_entity_properties['nothing'];

Create ACF repeater field from front end

I'm trying to create a form users can use to post from the front end of a wordpress site.
I'm having trouble with creating repeater fields though. I've tried a couple of methods, but nothing seems to work:
$periods = $_POST['periods'];
// for each perdiod, save the start/end date and notes
for ($p = 1; $p <= $periods; $p++) {
update_sub_field( array('date', $p, 'start-date'), $_POST['p'.$p.'-start-date'] );
update_sub_field( array('date', $p, 'end-date'), $_POST['p'.$p.'-start-date'] );
update_sub_field( array('date', $p, 'notes'), $_POST['p'.$p.'-start-date'] );
} // end periods loop
and
// for each perdiod, save the start/end date and notes
for ($p = 1; $p <= $periods; $p++) {
add_post_meta($post_id, 'date_'.$p.'_start-date', $_POST['p'.$p.'-start-date']);
add_post_meta($post_id, 'date_'.$p.'_end-date', $_POST['p'.$p.'-end-date']);
add_post_meta($post_id, 'date_'.$p.'_notes', $_POST['p'.$p.'-notes']);
} // end periods loop
But these do nothing to the post itself.
The repeater is set up like this:
Date (repeater) ->
start-date (field)
end-date (field)
notes (field)
There's also another repeater field in there (repeater within a repeater), but I want to get this one working first!
Any ideas?
To create a post, you'll need to use the actual field keys for each field. You can't use the field name, because the db record hasn't yet been created. Check out Elliot's documentation here for that info.
Here's how some code might look to do this:
$event_field_key = 'field_534d3f17f3ca2';
// for each perdiod, save the start/end date and notes
for ($p = 1; $p <= $periods; $p++) {
$events[] = array(
'_start-date' => $_POST['p'.$p.'-start-date'],
'_end-date' => $_POST['p'.$p.'-end-date'],
'date' => $_POST['p'.$p.'-notes']
);
} // end periods loop
update_field($event_field_key, $events, $post_id);
You will have to get the field key for that field in order for this to work correctly. To do that, go to your custom fields screen and look for screen options in the top right corner. Check the box that says show field keys. Your field keys should now show up to the right of the field name in the custom fields list. Use that to add the field.
Here's Elliot's instructions if mine didn't make sense.

Woocommerce Dynamic Pricing - manually inserting pricing rules

I am using the Woocommerce Dynamic Pricing plugin, which is very useful but does not easily allow me to ammend pricing updates via. the database.
Looking at the sample data,
{"set_5339c459a78e7":
{"conditions_type":"all",
"conditions":{"1":{"type":"apply_to","args":{"applies_to":"everyone"}}},
"collector":{"type":"product"},
"mode":"block",
"date_from":"",
"date_to":"",
"rules":{"1":{"from":"","to":"","type":"price_discount","amount":""}},
"blockrules": {"1":{
"from":"2",
"adjust":"1",
"type":"fixed_adjustment",
"amount":"0.26","repeating":"yes"}}}}
it seems that the meta requires set_* to be specific with the product meta, or it will not apply correctly.
Revising the code, I notice this:
$terms = get_terms('product_cat', array('hierarchical' => false, 'hide_empty' => false, 'parent' => 0));
foreach ($terms as $item_id => $item) {
$set_index = $item->term_id;
$name = 'set_' . $set_index;
}
This is bizarre to me, as the term_id appears to be a 13 character alphanumeric string than the expected bigint. Could anyone explain how I can reproduce this string for when I manually update my tables?
I had a look through the code and I found that in /admin/admin-init.php where it specifies the AJAX handlers, this is how it comes up with new set names:
function woocommerce_pricing_product_admin_create_empty_ruleset() {
global $wc_product_pricing_admin;
$wc_product_pricing_admin->create_empty_ruleset( uniqid('set_') );
die();
}
As you can see it just uses PHP's uniqid function prefixed by nothing but "set_" so in the case of product rules it appears to be just a random ID.
Hope that helps.

Drupal Commerce Line Items: alter the price?

I have to add to my cart some line items with a custom amount.
The commerce product is saved with price = 0, and my module compute the price and add the line item to the cart/order, but i dont understand how to set programmatically the price.
I've read about using Rules, but I need my module to be able to set/alter the price, without invoking rules.
I've tryed with an entity wrapper, i tryed to alter the line item created with commerce_product_line_item_new(), but nothing, when the line item gets into the cart always has the original product price (in my case, 0).
How to alter a line item price programmatically?
My code so far looks like:
// For debugging, this function is called by hook_menu()
function mymodule_test($product_id)
{
global $user;
$user = user_load($user->uid);
$order = commerce_cart_order_load($user->uid);
$order_wrapper = entity_metadata_wrapper('commerce_order', $order);
$product = commerce_product_load($product_id);
$line_item = commerce_product_line_item_new(
$product,
1,
0,
array(
),
'cover'
);
$line_item_wrapper = entity_metadata_wrapper("commerce_line_item", $line_item);
$line_item_wrapper->commerce_unit_price->data = commerce_price_component_add(
$line_item_wrapper->commerce_unit_price->value(),
'base_price',
array(
'amount' => 1234,
'currency_code' => 'EUR',
'data' => array(),
),
TRUE
);
$insert_line_item = commerce_cart_product_add($user->uid, $line_item_wrapper->value(), FALSE);
return 'done';
}
The strange thing, is that I tryed to adapt the code of commerce_line_item_unit_price_amount() found in commerce/modules/line_item/commerce_line_item.rules.inc, but this test:
<?php
global $user;
$product = commerce_product_load(4); // my commerce product for test
$line_item = commerce_product_line_item_new(
$product,
1,
0,
array(
),
'cover' // I do have this line_items type
);
// manually set amount and component name
$amount = 1234;
$component_name = 'base_price'; // tryed with discount, nothing change
$wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
$unit_price = commerce_price_wrapper_value($wrapper, 'commerce_unit_price', TRUE);
// Calculate the updated amount and create a price array representing the
// difference between it and the current amount.
$current_amount = $unit_price['amount'];
$updated_amount = commerce_round(COMMERCE_ROUND_HALF_UP, $amount);
$difference = array(
'amount' => $updated_amount - $current_amount,
'currency_code' => $unit_price['currency_code'],
'data' => array(),
);
// Set the amount of the unit price and add the difference as a component.
$wrapper->commerce_unit_price->amount = $updated_amount;
$wrapper->commerce_unit_price->data = commerce_price_component_add(
$wrapper->commerce_unit_price->value(),
$component_name,
$difference,
TRUE
);
$insert_line_item = commerce_cart_product_add($user->uid, $line_item, FALSE);
?>
still fail, the line_item get into the cart but with the original price of the referenced product.
Any idea?
For those people who don't want to use rules and hope to alter the price directly. Here is my solution:
// Alter the price in list and single product page.
function my_module_commerce_product_calculate_sell_price_line_item_alter($line_item){
$price = 100; //1 dollar
$line_item->commerce_unit_price[LANGUAGE_NONE]['0']['amount'] = $price;
}
// Alter the price in cart & order.
function my_module_commerce_cart_line_item_refresh($line_item, $order_wrapper){
$price = 100; //1 dollar
$line_item->commerce_unit_price[LANGUAGE_NONE]['0']['amount'] = $price;
// Alter the base_price component.
$line_item->commerce_unit_price[LANGUAGE_NONE]['0']['data']['components']['0']['price']['amount'] = $price;
}
If you're looking to ignore whatever previous values have been saved to a line item and recalculate the total from your new amount the function you're looking for is commerce_line_item_rebase_unit_price.
Set the new amount value and then run your line item through there, save the line item and the order:
$line_item_wrapper->commerce_unit_price->amount = 13;
commerce_line_item_rebase_unit_price($line_item_wrapper->value());
commerce_line_item_save($line_item_wrapper->value());
I struggled through this issue all day today and final figured out the correct path to altering line items prices. The problem is that, even if you successfully change the line item price to a custom value, on the next page refresh the cart will reset the line items to match the original product price. Take a look at the commerce_cart_order_refresh() function for details. This function is executed every time an order/cart is loaded on the page and there is no way around it.
It turns out that the proper way to alter a line item price is to either use Rules or to implement the hook_commerce_cart_line_item_refresh() function. Either way, Drupal Commerce need to be able to apply the alteration logic each time the cart/order is loaded.
I ended up creating a custom field in the Line Item where I stored the custom price value I wanted. I then used a Pricing Rule to copy the custom price value to the product price value whenever the cart is refreshed.
The following blog post was very helpful in figuring this out. It shows you how to add a custom field to a line item type and how to setup a pricing rule to copy the custom amount to the unit price.
http://commerceguys.com/blog/using-custom-line-items-provide-donation-feature-drupal-commerce
Recently I had to implement a donation form in Commerce but the Commerce Express Checkout module doesn't handle custom line items. Since it was a donation and all (who is trying to screw the house?), I felt it appropriate to pass the donation amount as a 3rd parameter in URL the Express Checkout module provides. Here is how I went about hacking the module:
I added a new entry to the router:
$items['commerce-express-checkout/%/%/%'] = array(
'title' => 'Express Checkout w/ extra argument',
// 'page callback' => 'commerce_express_checkout_create_order',
'page callback' => 'commerce_express_checkout_create_order_extra',
'page arguments' => array(1, 2, 3),
'access arguments' => array('access checkout'),
'type' => MENU_CALLBACK,
);
I duplicated and tweaked the default callback and tacked '_extra' to it. Note that the "data" property seems to be a static variable store for occasions just such as this and persists the life of the line item.
function commerce_express_checkout_create_order_extra($product_id, $token, $amount) {
if (drupal_hmac_base64($product_id, drupal_get_private_key().drupal_get_hash_salt()) == $token && is_numeric($amount)) {
global $user;
$product = commerce_product_load($product_id);
$product->commerce_price['und'][0]['amount'] = (int)$amount;
$order = ($user->uid) ? commerce_order_new($user->uid, 'checkout_checkout') : commerce_cart_order_new();
commerce_order_save($order);
$price = array('amount' => commerce_round(COMMERCE_ROUND_HALF_UP, $amount), 'currency_code' => commerce_default_currency());
$line_item = commerce_product_line_item_new($product, 1, $order->order_id);
$line_item->data = array('und' => array('0' => $price));
commerce_line_item_save($line_item);
$order_wrapper = entity_metadata_wrapper('commerce_order', $order);
$order_wrapper->commerce_line_items[] = $line_item;
$order->data['type'] = 'commerce_express_checkout_order';
commerce_order_save($order);
drupal_goto('checkout/' . $order->order_id);
return "";
}
return "";
}
Here is the part that ended up being most tricky simply due to the learning curve and not knowing what the heck function to use:
/**
* Implements hook_commerce_cart_line_item_refresh().
*/
function commerce_express_checkout_commerce_cart_line_item_refresh($line_item, $order_wrapper) {
if ($line_item->commerce_product['und'][0]['line_item_label'] == 'DONATE' || $line_item->commerce_product['und'][0]['product_id'] == '11') {
$price = array('amount' => commerce_round(COMMERCE_ROUND_HALF_UP, $line_item->data['und'][0]['amount']), 'currency_code' => commerce_default_currency());
$line_item->commerce_unit_price = array('und' => array('0' => $price));
$line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
$line_item_wrapper->commerce_unit_price->data = commerce_price_component_add(
$line_item_wrapper->commerce_unit_price->value(), 'base_price', $price, TRUE
);
}
}
Every single time the cart is modified, it refreshes and attempts to set the products in the cart to their in-code prototype. It seems pretty inefficient to me too, but I could be missing something.
This post pointed me in the right direction for programmatically altering a drupal commerce line item by using hook_commerce_cart_line_item_refersh(). However, some of the answers here are either outright wrong, or very inefficient and sloppy.
This would be a correct working solution for altering the line item type in Drupal Commerce:
/*
* implements hook_commerce_cart_line_item_refresh()
*
*/
function MYMODULE_commerce_cart_line_item_refresh($line_item, $order_wrapper){
$line_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
$new_price = 100; //I use a function to calculate the value of $new_price
if(!empty($new_price)){
$line_wrapper->commerce_unit_price->amount->set($new_price);
$line_wrapper->save();
}
}

Resources