diff --git a/modules/cart/commerce_cart.module b/modules/cart/commerce_cart.module
index 1f2dbff..1729fa8 100644
--- a/modules/cart/commerce_cart.module
+++ b/modules/cart/commerce_cart.module
@@ -1599,6 +1599,92 @@ function commerce_cart_field_instance_is_attribute($instance) {
}
/**
+ * Returns an array of attribute fields instances with their settings and options.
+ *
+ * @param $product_type
+ * The info array of the field instance whose attribute settings should be
+ * retrieved.
+ * @param $default_product
+ * A product entity object for getting the attribute fields options.
+ *
+ * @return
+ * An array of attribute fields with their settings including:
+ * - field: field definition data;
+ * - instance: field instance definition data;
+ * - commerce_cart_settings: field instance (attribute) cart settings;
+ * - options: field instance options;
+ * - weight: field instance weight;
+ * - required: field instance required setting.
+ */
+function commerce_cart_product_type_attributes($product_type, $default_product = NULL) {
+ $attributes = array();
+ // Use initialized product object if it is not defined.
+ if (!$default_product) {
+ $default_product = commerce_product_new();
+ }
+ // Loop through all the field instances on that product type.
+ foreach (field_info_instances('commerce_product', $product_type) as $field_name => $instance) {
+ // A field qualifies if it is single value, required and uses a widget
+ // with a definite set of options. For the sake of simplicity, this is
+ // currently restricted to fields defined by the options module.
+ $field = field_info_field($field_name);
+
+ // If the instance is of a field type that is eligible to function as
+ // a product attribute field and if its attribute field settings
+ // specify that this functionality is enabled...
+ if (commerce_cart_field_attribute_eligible($field) && commerce_cart_field_instance_is_attribute($instance)) {
+ // Get the options properties from the options module for the
+ // attribute widget type selected for the field, defaulting to the
+ // select list options properties.
+ $commerce_cart_settings = commerce_cart_field_instance_attribute_settings($instance);
+
+ switch ($commerce_cart_settings['attribute_widget']) {
+ case 'checkbox':
+ $widget_type = 'onoff';
+ break;
+ case 'radios':
+ $widget_type = 'buttons';
+ break;
+ default:
+ $widget_type = 'select';
+ }
+
+ $properties = _options_properties($widget_type, FALSE, TRUE, TRUE);
+
+ // Try to fetch localized names.
+ $allowed_values = NULL;
+
+ // Prepare translated options if using the i18n_field module.
+ if (module_exists('i18n_field')) {
+ if (($translate = i18n_field_type_info($field['type'], 'translate_options'))) {
+ $allowed_values = $translate($field);
+ _options_prepare_options($allowed_values, $properties);
+ }
+ }
+
+ // Otherwise just use the base language values.
+ if (empty($allowed_values) && $default_product) {
+ $allowed_values = _options_get_options($field, $instance, $properties, 'commerce_product', $default_product);
+ }
+
+ // Only consider this field a qualifying attribute field if we could
+ // derive a set of options for it.
+ if (!empty($allowed_values)) {
+ $attributes[$field_name] = array(
+ 'field' => $field,
+ 'instance' => $instance,
+ 'commerce_cart_settings' => $commerce_cart_settings,
+ 'options' => $allowed_values,
+ 'weight' => $instance['widget']['weight'],
+ 'required' => $instance['required'],
+ );
+ }
+ }
+ }
+ return $attributes;
+}
+
+/**
* Returns an array of cart form field access settings for a field instance.
*
* Fields attached to line item types can be included on the Add to Cart form so
@@ -1939,65 +2025,7 @@ function commerce_cart_add_to_cart_form($form, &$form_state, $line_item, $show_q
// If all the products are of the same type...
if ($same_type) {
- // Loop through all the field instances on that product type.
- foreach (field_info_instances('commerce_product', $type) as $field_name => $instance) {
- // A field qualifies if it is single value, required and uses a widget
- // with a definite set of options. For the sake of simplicity, this is
- // currently restricted to fields defined by the options module.
- $field = field_info_field($field_name);
-
- // If the instance is of a field type that is eligible to function as
- // a product attribute field and if its attribute field settings
- // specify that this functionality is enabled...
- if (commerce_cart_field_attribute_eligible($field) && commerce_cart_field_instance_is_attribute($instance)) {
- // Get the options properties from the options module for the
- // attribute widget type selected for the field, defaulting to the
- // select list options properties.
- $commerce_cart_settings = commerce_cart_field_instance_attribute_settings($instance);
-
- switch ($commerce_cart_settings['attribute_widget']) {
- case 'checkbox':
- $widget_type = 'onoff';
- break;
- case 'radios':
- $widget_type = 'buttons';
- break;
- default:
- $widget_type = 'select';
- }
-
- $properties = _options_properties($widget_type, FALSE, TRUE, TRUE);
-
- // Try to fetch localized names.
- $allowed_values = NULL;
-
- // Prepare translated options if using the i18n_field module.
- if (module_exists('i18n_field')) {
- if (($translate = i18n_field_type_info($field['type'], 'translate_options'))) {
- $allowed_values = $translate($field);
- _options_prepare_options($allowed_values, $properties);
- }
- }
-
- // Otherwise just use the base language values.
- if (empty($allowed_values)) {
- $allowed_values = _options_get_options($field, $instance, $properties, 'commerce_product', $default_product);
- }
-
- // Only consider this field a qualifying attribute field if we could
- // derive a set of options for it.
- if (!empty($allowed_values)) {
- $qualifying_fields[$field_name] = array(
- 'field' => $field,
- 'instance' => $instance,
- 'commerce_cart_settings' => $commerce_cart_settings,
- 'options' => $allowed_values,
- 'weight' => $instance['widget']['weight'],
- 'required' => $instance['required'],
- );
- }
- }
- }
+ $qualifying_fields = commerce_cart_product_type_attributes($type, $default_product);
}
// Otherwise for products of varying types, display a simple select list
@@ -2034,19 +2062,35 @@ function commerce_cart_add_to_cart_form($form, &$form_state, $line_item, $show_q
if ($product_wrapper->{$field_name}->raw() != NULL) {
$field_has_options[$field_name] = TRUE;
}
- $used_options[$field_name][] = $product_wrapper->{$field_name}->raw();
+
+ // Build the options.
+ $field_value = $product_wrapper->{$field_name}->raw();
+ // Use tokens if token formatter specified and there is only attribute defined.
+ if ((empty($qualifying_fields) || count($qualifying_fields) == 1) && $line_item->data['context']['product_select_options_use_tokens'] && !empty($line_item->data['context']['product_select_options_tokens_formatter'])) {
+ if (module_exists('token')) {
+ $token_type = token_get_entity_mapping('entity', 'commerce_product');
+ $options[$field_name][$field_value] = token_replace($line_item->data['context']['product_select_options_tokens_formatter'], array($token_type => $product, 'entity' => $product, 'entity_type' => 'commerce_product'), array('clear' => TRUE));
+ }
+ else {
+ $options[$field_name][$field_value] = token_replace($line_item->data['context']['product_select_options_tokens_formatter'], array('commerce-product' => $product), array('clear' => TRUE));
+ }
+ }
+ // Use the default field options.
+ else {
+ $options[$field_name][$field_value] = $data['options'][$field_value];
+ }
}
// If for some reason no options for this field are used, remove it
// from the qualifying fields array.
- if (empty($field_has_options[$field_name]) || empty($used_options[$field_name])) {
+ if (empty($field_has_options[$field_name]) || empty($options[$field_name])) {
unset($qualifying_fields[$field_name]);
}
else {
$form['attributes'][$field_name] = array(
'#type' => $data['commerce_cart_settings']['attribute_widget'],
'#title' => commerce_cart_attribute_widget_title($data['instance']),
- '#options' => array_intersect_key($data['options'], drupal_map_assoc($used_options[$field_name])),
+ '#options' => $options[$field_name],
'#default_value' => $default_product_wrapper->{$field_name}->raw(),
'#weight' => $data['instance']['widget']['weight'],
'#ajax' => array(
@@ -2056,7 +2100,7 @@ function commerce_cart_add_to_cart_form($form, &$form_state, $line_item, $show_q
// Add the empty value if the field is not required and products on
// the form include the empty value.
- if (!$data['required'] && in_array('', $used_options[$field_name])) {
+ if (!$data['required'] && !empty($used_options) && in_array('', $used_options[$field_name])) {
$form['attributes'][$field_name]['#empty_value'] = '';
}
@@ -2104,7 +2148,20 @@ function commerce_cart_add_to_cart_form($form, &$form_state, $line_item, $show_q
$options = array();
foreach ($matching_products as $product_id => $product) {
- $options[$product_id] = $product->title;
+ // Use tokens if token formatter specified and there is only attribute defined.
+ if ($line_item->data['context']['product_select_options_use_tokens'] && !empty($line_item->data['context']['product_select_options_tokens_formatter'])) {
+ if (module_exists('token')) {
+ $token_type = token_get_entity_mapping('entity', 'commerce_product');
+ $options[$product_id] = token_replace($line_item->data['context']['product_select_options_tokens_formatter'], array($token_type => $product, 'entity' => $product, 'entity_type' => 'commerce_product'), array('clear' => TRUE));
+ }
+ else {
+ $options[$product_id] = token_replace($line_item->data['context']['product_select_options_tokens_formatter'], array('commerce-product' => $product), array('clear' => TRUE));
+ }
+ }
+ // Use the default field options.
+ else {
+ $options[$product_id] = $product->title;
+ }
}
// Note that this element by default is a select list, so its
@@ -2136,7 +2193,8 @@ function commerce_cart_add_to_cart_form($form, &$form_state, $line_item, $show_q
// any qualifying attribute fields...
if (!$same_type || empty($qualifying_fields)) {
// For a single product form, just add the hidden product_id field.
- if (count($products) == 1) {
+ // and the "show_single_product_attributes" is not checked.
+ if (count($products) == 1 && empty($line_item->data['context']['show_single_product_attributes'])) {
$form['product_id'] = array(
'#type' => 'hidden',
'#value' => $default_product->product_id,
@@ -2147,7 +2205,20 @@ function commerce_cart_add_to_cart_form($form, &$form_state, $line_item, $show_q
$options = array();
foreach ($products as $product_id => $product) {
- $options[$product_id] = $product->title;
+ // Use tokens if token formatter specified and there is only attribute defined.
+ if ($line_item->data['context']['product_select_options_use_tokens'] && !empty($line_item->data['context']['product_select_options_tokens_formatter'])) {
+ if (module_exists('token')) {
+ $token_type = token_get_entity_mapping('entity', 'commerce_product');
+ $options[$product_id] = token_replace($line_item->data['context']['product_select_options_tokens_formatter'], array($token_type => $product, 'entity' => $product, 'entity_type' => 'commerce_product'), array('clear' => TRUE));
+ }
+ else {
+ $options[$product_id] = token_replace($line_item->data['context']['product_select_options_tokens_formatter'], array('commerce-product' => $product), array('clear' => TRUE));
+ }
+ }
+ // Use the default field options.
+ else {
+ $options[$product_id] = $product->title;
+ }
}
// Note that this element by default is a select list, so its #options
@@ -2447,6 +2518,8 @@ function commerce_cart_field_formatter_info() {
'combine' => TRUE,
'show_single_product_attributes' => FALSE,
'line_item_type' => 'product',
+ 'product_select_options_use_tokens' => FALSE,
+ 'product_select_options_tokens_formatter' => FALSE,
),
),
);
@@ -2485,8 +2558,8 @@ function commerce_cart_field_formatter_settings_form($field, $instance, $view_mo
$element['show_single_product_attributes'] = array(
'#type' => 'checkbox',
- '#title' => t('Show attribute widgets even if the Add to Cart form only represents one product.'),
- '#description' => t('If enabled, attribute widgets will be shown on the form with the only available options selected.'),
+ '#title' => t('Show attribute widgets or product selection even if the Add to Cart form only represents one product.'),
+ '#description' => t('If enabled, attribute widgets or product selection will be shown on the form with the only available options selected.'),
'#default_value' => $settings['show_single_product_attributes'],
);
@@ -2509,6 +2582,90 @@ function commerce_cart_field_formatter_settings_form($field, $instance, $view_mo
}
}
+ // Token formatter, display alternative for the product select options.
+ // Only for multiple product reference, except for single referenced product type
+ // with multiple attributes defined.
+ if ($field['cardinality'] != 1) {
+ $referenceable_product_types = $instance['settings']['referenceable_types'];
+ $product_types = array_filter($referenceable_product_types);
+ // If there is no product type selected, use all product types.
+ if (empty($product_types)) {
+ $product_types = array_keys($referenceable_product_types);
+ }
+
+ $token_formatter = TRUE;
+ // Check for single referenced product type with multiple attributes defined.
+ if (count($product_types) == 1) {
+ $product_type = reset($product_types);
+ // Get product type attributes.
+ $attributes = commerce_cart_product_type_attributes($product_type);
+ if (count($attributes) > 1) {
+ $token_formatter = FALSE;
+ }
+ }
+
+ if ($token_formatter) {
+ $use_tokens_descripton = t('If enabled, togheter with the replacement text, it will change the display values for the product select options.');
+ $use_tokens_descripton .= '
';
+ $use_tokens_descripton .= t('Exception: it will not work for single referenced product type with multiple attributes defined.');
+ $element['product_select_options_use_tokens'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Use tokens for product select options display values.'),
+ '#description' => $use_tokens_descripton,
+ '#default_value' => isset($settings['product_select_options_use_tokens']) ? $settings['product_select_options_use_tokens'] : FALSE,
+ );
+
+ $tokens_formatter_description = t('Use tokens available for customize the display values of the product select options.');
+ $tokens_formatter_description .= '
';
+ $tokens_formatter_description .= t('For multiple referenced product types, be sure you are using the right tokens. A good practice in this case is usage of tokens of the mutual fields.');
+ $element['product_select_options_tokens_formatter'] = array(
+ '#type' => 'textarea',
+ '#title' => t('Replacement text with token support'),
+ '#description' => $tokens_formatter_description,
+ '#default_value' => $settings['product_select_options_tokens_formatter'],
+ '#states' => array(
+ 'visible' => array(
+ ':input[name="fields[' . $field['field_name'] . '][settings_edit_form][settings][product_select_options_use_tokens]"]' => array('checked' => TRUE),
+ ),
+ ),
+ );
+ $element['product_select_options_tokens_help'] = array(
+ '#type' => 'container',
+ '#states' => array(
+ 'visible' => array(
+ ':input[name="fields[' . $field['field_name'] . '][settings_edit_form][settings][product_select_options_use_tokens]"]' => array('checked' => TRUE),
+ ),
+ ),
+ );
+ if (module_exists('token')) {
+ $token_type = token_get_entity_mapping('entity', 'commerce_product');
+ $element['product_select_options_tokens_help']['token_tree'] = array(
+ '#theme' => 'token_tree',
+ '#token_types' => array($token_type, 'entity'),
+ );
+ $element['product_select_options_tokens_formatter']['#element_validate'] = array('token_element_validate');
+ }
+ else {
+ $token_info = array(
+ 'site' => array(
+ 'type' => 'site',
+ 'label' => t('Site information'),
+ 'description' => t('Site-wide settings and other global information.'),
+ ),
+ 'commerce_product' => array(
+ 'label' => t('Product'),
+ 'type' => 'commerce_product',
+ ),
+ );
+
+ $element['product_select_options_tokens_help']['token_tree'] = RulesTokenEvaluator::help($token_info);
+ $element['product_select_options_tokens_help']['token_extra'] = array(
+ '#markup' => '
' . t("Optional: Install Token module to improve tokens.", array('@token-url' => 'http://drupal.org/project/token')) . '
', + ); + } + } + } + return $element; } @@ -2541,6 +2698,27 @@ function commerce_cart_field_formatter_settings_summary($field, $instance, $view if (count(commerce_product_line_item_types()) > 1) { $summary[] = t('Add to Cart line item type: @type', array('@type' => commerce_line_item_type_get_name($settings['line_item_type']))); } + + // Token formatter setting if available. + $referenceable_product_types = $instance['settings']['referenceable_types']; + // If there is only one product type available, use it. + if (count($referenceable_product_types) == 1) { + $product_types = array_keys($referenceable_product_types); + } + // For more then one product type available, check the ones selected. + else { + $product_types = array_filter($referenceable_product_types); + } + // Only for single product type available for the product reference field instance. + if (count($product_types) == 1) { + foreach ($product_types as $product_type) { + // Get product type attributes. + $attributes = commerce_cart_product_type_attributes($product_type); + if (count($attributes) == 1) { + $summary[] = t('Tokens replacement: !token_formatter', array('!token_formatter' => !empty($settings['product_select_options_tokens_formatter']) ? $settings['product_select_options_tokens_formatter'] : t('Empty (not set).'))); + } + } + } } return implode('