Skip to content

Instantly share code, notes, and snippets.

@klickreflex
Last active July 27, 2016 11:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save klickreflex/f917479dca40211a7624962cf76efaa8 to your computer and use it in GitHub Desktop.
Save klickreflex/f917479dca40211a7624962cf76efaa8 to your computer and use it in GitHub Desktop.
Drupal Commerce: Add to Cart OR Download Formatter, https://www.drupal.org/node/2660424
<?php
/**
* @file
* adds a formatter for commerce file fields that shows an add to cart button OR
* a file download link, depending on whether the current user has a license for the file
*
*/
/**
* Implements hook_field_formatter_info().
*/
function si_formatters_field_formatter_info() {
return array(
'add_to_cart_or_download_formatter' => array( // machine name of the formatter
'label' => t('Add to Cart or Download'),
'field types' => array('commerce_product_reference'), // this will only be available for product reference fields
'settings' => array (
// custom setting for the Download link
'download_text' => t('Download now'), //ditto
// Settings from the original add to cart form:
'show_quantity' => FALSE,
'default_quantity' => 1,
'combine' => TRUE,
'show_single_product_attributes' => FALSE,
'line_item_type' => 'product',
), // Array of the settings we'll create
),
);
}
/**
* Implements hook_field_formatter_settings_form().
*/
function si_formatters_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
//This gets the view_mode where our settings are stored
$display = $instance['display'][$view_mode];
//This gets the actual settings
$settings = $display['settings'];
//Initialize the element variable
$element = array();
$element['download_text'] = array(
'#type' => 'textfield', // Use a textbox
'#title' => t('Download Now'), // Widget label
'#description' => t('The download link text for users who are allowed to download without checkout.'), // helper text
'#default_value' => $settings['download_text'], // Get the value if it's already been set
);
$element['show_quantity'] = array(
'#type' => 'checkbox',
'#title' => t('Display a textfield quantity widget on the add to cart form.'),
'#default_value' => $settings['show_quantity'],
);
$element['default_quantity'] = array(
'#type' => 'textfield',
'#title' => t('Default quantity'),
'#default_value' => $settings['default_quantity'] <= 0 ? 1 : $settings['default_quantity'],
'#element_validate' => array('commerce_cart_field_formatter_settings_form_quantity_validate'),
'#size' => 16,
);
$element['combine'] = array(
'#type' => 'checkbox',
'#title' => t('Attempt to combine like products on the same line item in the cart.'),
'#description' => t('The line item type, referenced product, and data from fields exposed on the Add to Cart form must all match to combine.'),
'#default_value' => $settings['combine'],
);
$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.'),
'#default_value' => $settings['show_single_product_attributes'],
);
return $element;
}
/**
* Implements hook_field_formatter_settings_summary().
*/
function si_formatters_field_formatter_settings_summary($field, $instance, $view_mode) {
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
$summary = t('Use either Add to Cart button or a Download link (depending on file license)');
return $summary;
}
/**
* Implements hook_field_formatter_view().
*/
function si_formatters_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
if ($display['type'] == 'add_to_cart_or_download_formatter') {
$result = array();
$settings = $display['settings']; // get the settings
$download_text = $settings['download_text']; // The label assigned in settings
// Collect the list of product IDs.
$product_ids = array();
foreach ($items as $delta => $item) {
$product_ids[$item['product_id']] = $item['product_id'];
}
// Exit now if we didn't find any product IDs.
if (empty($product_ids)) {
return;
}
// Load the referenced products.
$products = commerce_product_load_multiple($product_ids, array('status' => 1));
foreach ($products as $delta => $product) {
// Protect ourselves from recursive rendering.
static $depth = 0;
$depth++;
if ($depth > 20) {
throw new CommerceProductReferenceRecursiveRenderingException(t('Recursive rendering detected when rendering product (@product_id). Aborting rendering.', array('@product_id' => $item['product_id'])));
}
$fid = $product->commerce_file['und'][0]['fid'];
$file = file_load($fid);
// the file description is used for the download link,
// so we set/override it here with the display setting
$file->description = $download_text;
$download_link = theme('file_link', array( 'file' => $file ));
$element[0]['#markup'] = $download_link;
}
global $has_license;
$has_license = false;
if(commerce_file_access('download', $file)) {
$has_license = true;
return $element;
}
else {
// show add to cart button if user has no license
$settings = array_merge(field_info_formatter_settings($display['type']), $display['settings']);
// Collect the list of product IDs.
$product_ids = array();
foreach ($items as $delta => $item) {
if (isset($item['product_id'])) {
$product_ids[] = $item['product_id'];
}
elseif (module_exists('entityreference') && isset($item['target_id'])) {
$product_ids[] = $item['target_id'];
}
}
// Load the referenced products.
$products = commerce_product_load_multiple($product_ids);
// Check to ensure products are referenced, before returning results.
if (!empty($products)) {
$type = !empty($settings['line_item_type']) ? $settings['line_item_type'] : 'product';
$line_item = commerce_product_line_item_new(commerce_product_reference_default_product($products), $settings['default_quantity'], 0, array(), $type);
$line_item->data['context']['product_ids'] = array_keys($products);
$line_item->data['context']['add_to_cart_combine'] = !empty($settings['combine']);
$line_item->data['context']['show_single_product_attributes'] = !empty($settings['show_single_product_attributes']);
$result[] = array(
'#arguments' => array(
'form_id' => commerce_cart_add_to_cart_form_id($product_ids),
'line_item' => $line_item,
'show_quantity' => $settings['show_quantity'],
),
);
}
return $result;
}
} // if add_to_cart_formatter
}
/**
* Implements hook_field_attach_view_alter().
*
* When a field is formatted for display, the display formatter does not know
* what view mode it is being displayed for. Unfortunately, the Add to Cart form
* display formatter needs this information when displaying product reference
* fields on nodes to provide adequate context for product field replacement on
* multi-value product reference fields. This hook is used to transform a set of
* arguments into a form using the arguments and the extra context information
* gleaned from the parameters passed into this function.
*/
function si_formatters_field_attach_view_alter(&$output, $context) {
// Loop through the fields passed in looking for any product reference fields
// formatted with the Add to Cart form display formatter.
foreach ($output as $field_name => $element) {
if (!empty($element['#formatter']) && $element['#formatter'] == 'add_to_cart_or_download_formatter') {
global $has_license;
if(!$has_license) {
// Prepare the context information needed by the cart form.
$cart_context = $context;
// Remove the full entity from the context array and put the ID in instead.
list($entity_id, $vid, $bundle) = entity_extract_ids($context['entity_type'], $context['entity']);
$cart_context['entity_id'] = $entity_id;
unset($cart_context['entity']);
// Remove any Views data added to the context by views_handler_field_field.
// It unnecessarily increases the size of rows in the cache_form table for
// Add to Cart form state data.
if (!empty($cart_context['display']) && is_array($cart_context['display'])) {
unset($cart_context['display']['views_view']);
unset($cart_context['display']['views_field']);
unset($cart_context['display']['views_row_id']);
}
// Add the context for displaying product fields in the context of an entity
// that references the product by looking at the entity this product
// reference field is attached to.
$cart_context['class_prefix'] = $context['entity_type'] . '-' . $entity_id;
$cart_context['view_mode'] = $context['entity_type'] . '_' . $element['#view_mode'];
$entity_uri = entity_uri($context['entity_type'], $element['#object']);
foreach (element_children($element) as $key) {
// Extract the drupal_get_form() arguments array from the element.
$arguments = $element[$key]['#arguments'];
// Add the display path and referencing entity data to the line item.
if (!empty($entity_uri['path'])) {
$arguments['line_item']->data['context']['display_path'] = $entity_uri['path'];
}
$arguments['line_item']->data['context']['entity'] = array(
'entity_type' => $context['entity_type'],
'entity_id' => $entity_id,
'product_reference_field_name' => $field_name,
);
// Update the product_ids variable to point to the entity data if we're
// referencing multiple products.
if (count($arguments['line_item']->data['context']['product_ids']) > 1) {
$arguments['line_item']->data['context']['product_ids'] = 'entity';
}
// Replace the array containing the arguments with the return value of
// drupal_get_form(). It will be rendered when the rest of the object is
// rendered for display.
$output[$field_name][$key] = drupal_get_form($arguments['form_id'], $arguments['line_item'], $arguments['show_quantity'], $cart_context);
}
}
}
}
//} // end check
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment