uc_varprice.module in UC Variable Price 6
Same filename and directory in other branches
Defines a product feature to turn any product into a variable priced product.
File
uc_varprice.moduleView source
<?php
/**
* @file
* Defines a product feature to turn any product into a variable priced product.
*/
/**
* Implementation of hook_init()
*/
function uc_varprice_init() {
drupal_add_js(drupal_get_path('module', 'uc_varprice') . '/uc_varprice_show_arb.js');
}
/**
* Implementation of hook_theme()
*/
function uc_varprice_theme() {
return array(
'varprice_qty' => array(
'arguments' => array(
'form' => NULL,
),
),
);
}
/**
* Implementation of hook_form_alter().
*
* Summary of alterations:
* 1) Alters the product feature add form to restrict multiple Variable Price
* features from being added to a single product.
* 2) Alters the add to cart form for variable priced products.
* 3) Disable the appropriate Qty. fields on the cart view form.
* 4) Alter the product class form to set default donations.
*/
function uc_varprice_form_alter(&$form, &$form_state, $form_id) {
// 1) Alter the product feature add form.
if ($form_id == 'uc_product_feature_add_form') {
// If a Variable Price feature has already been added to this product...
if (db_result(db_query("SELECT COUNT(*) FROM {uc_product_features} WHERE nid = %d AND fid = '%s'", arg(1), 'varprice'))) {
// Remove Variable Price from the available list of features to add.
unset($form['feature']['#options']['varprice']);
}
}
// 2) Alter the add to cart form.
if (strpos($form_id, 'uc_product_add_to_cart_form_') === 0) {
$data = uc_varprice_product_load($form['nid']['#value']);
if ($data) {
// Determine the default value
$default_val = !empty($data->price_default) ? $data->price_default : variable_get('uc_varprice_global_default', '0');
// Are we going to add a selectable widget?
if ($data->selectable) {
$options = $data->sel_options;
// Add "other" option if users can also enter arbitrary values
if ($data->arbitrary) {
$options['other'] = t('Other...');
}
if (isset($options[$default_val])) {
// If the default value is in the options…
$sel_default = $default_val;
$default_val = FALSE;
}
elseif ($data->arbitrary) {
// If "other" is an option, select that by default and have the
// default value appear in the arbitrary value field.
$sel_default = 'other';
}
elseif (count($options)) {
// If all else fails, just select the first item.
$sel_default = array_shift(array_keys($options));
}
else {
// If we get here, then there aren't any options in the list anyway.
// What the heck?
$sel_default = '';
}
$form['varprice_sel'] = array(
'#type' => $data->sel_widget,
'#title' => !empty($data->amount_title) ? $data->amount_title : t('Amount'),
'#options' => $options,
'#default_value' => $sel_default,
'#weight' => -5.2,
);
}
if ($data->arbitrary) {
$description = array();
if ($data->selectable) {
$description[] = t('If you’ve selected “Other…” above, enter the precise amount here.');
}
if (!empty($data->price_minimum)) {
$description[] = t('Minimum: @price', array(
'@price' => uc_currency_format($data->price_minimum),
));
}
if (!empty($data->price_maximum)) {
$description[] = t('Maximum: @price', array(
'@price' => uc_currency_format($data->price_maximum),
));
}
// Add the amount textfield to the add to cart form.
$form['varprice'] = array(
'#type' => 'textfield',
'#title' => $data->selectable ? '' : (!empty($data->amount_title) ? $data->amount_title : t('Amount')),
'#description' => implode('<br />', $description),
'#default_value' => !empty($default_val) ? $default_val : ($data->selectable ? '' : variable_get('uc_varprice_global_default', '0')),
'#size' => 8,
'#weight' => -5,
'#field_prefix' => variable_get('uc_sign_after_amount', FALSE) ? '' : variable_get('uc_currency_sign', '$'),
'#field_suffix' => variable_get('uc_sign_after_amount', FALSE) ? variable_get('uc_currency_sign', '$') : '',
'#attributes' => array(
'class' => 'uc_varprice_arb',
),
);
// Relabel the "Add to cart" button
if (!empty($data->add_to_cart_title)) {
$form['submit']['#value'] = $data->add_to_cart_title;
}
}
$form['#validate'][] = 'uc_varprice_add_to_cart_form_validate';
}
}
// 3) Disable the appropriate Qty. fields on the cart view form.
if ($form_id == 'uc_cart_view_form') {
for ($i = 0, $j = count(uc_cart_get_contents()); $i < $j; $i++) {
$data = unserialize($form['items'][$i]['data']['#value']);
// If this item has a quantity restriction on it...
if ($data['varprice'] > 0) {
$form['items'][$i]['qty']['#type'] = 'value';
$form['items'][$i]['qty']['#theme'] = 'varprice_qty';
}
}
}
// 4) Alter the product class form to set default donations.
if ($form_id == 'uc_product_class_form') {
// Add some helper JS to the form.
drupal_add_js(drupal_get_path('module', 'uc_varprice') . '/uc_varprice.js');
$data = variable_get('ucvp_class_def_' . $form['pcid']['#value'], array());
if (!empty($data)) {
$data = (object) unserialize($data);
}
else {
$data = FALSE;
}
$form['varprice'] = array(
'#type' => 'fieldset',
'#title' => t('Default Variable Price product feature'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#weight' => 5,
);
$form['varprice']['default_varprice'] = array(
'#type' => 'checkbox',
'#title' => t('Check this box to add a default product feature to every product of this class using these settings.'),
'#default_value' => $data === FALSE ? FALSE : TRUE,
);
$form['varprice'] += _uc_varprice_feature_form($data);
$form['#validate'][] = 'uc_varprice_feature_form_validate';
$form['#submit'][] = 'uc_varprice_product_class_submit';
$form['submit']['#weight'] = 10;
}
}
// Validation handler to ensure that the submitted price is valid.
function uc_varprice_add_to_cart_form_validate($form, &$form_state) {
$vp_data = uc_varprice_product_load($form_state['values']['nid']);
if (!isset($form_state['values']['varprice_sel']) || $form_state['values']['varprice_sel'] === 'other') {
if (empty($form_state['values']['varprice']) || $form_state['values']['varprice'] == 0) {
form_set_error('varprice', t('You must specify a price.'));
}
elseif (!empty($vp_data->price_minimum) && $form_state['values']['varprice'] < $vp_data->price_minimum) {
form_set_error('varprice', t('You must specify an amount greater than or equal to @price.', array(
'@price' => uc_currency_format($vp_data->price_minimum),
)));
}
elseif (!empty($vp_data->price_maximum) && $form_state['values']['varprice'] > $vp_data->price_maximum) {
form_set_error('varprice', t('You must specify an amount less than or equal to @price.', array(
'@price' => uc_currency_format($vp_data->price_maximum),
)));
}
}
}
// Submit handler for the product class form for default Variable Price features.
function uc_varprice_product_class_submit($form, &$form_state) {
if ($form_state['values']['default_varprice']) {
// @TODO:
// The $data array building below is pretty much identical to what appears
// in uc_varprice_feature_form_submit() - maybe it should be in a helper
// function?
$data = array(
'price_default' => $form_state['values']['price_default'],
'price_minimum' => $form_state['values']['price_minimum'],
'price_maximum' => $form_state['values']['price_maximum'],
'override_add_to_cart_title' => $form_state['values']['override_add_to_cart_title'],
'add_to_cart_title' => $form_state['values']['override_add_to_cart_title'] ? $form_state['values']['add_to_cart_title'] : '',
'override_amount_title' => $form_state['values']['override_amount_title'],
'amount_title' => $form_state['values']['override_amount_title'] ? $form_state['values']['amount_title'] : '',
'arbitrary' => $form_state['values']['arbitrary'],
'selectable' => $form_state['values']['selectable'],
'sel_widget' => $form_state['values']['sel_widget'],
'sel_options' => $form_state['values']['sel_options_arr'],
);
variable_set('ucvp_class_def_' . $form_state['values']['pcid'], serialize($data));
}
else {
variable_del('ucvp_class_def_' . $form_state['values']['pcid']);
}
}
/**
* Implementation of hook_nodeapi().
*
* Summary of alterations:
* 1) Removes price displays from variable priced product nodes.
* 2) Inserts Variable Price product feature on product node creation.
*/
function uc_varprice_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
// When the node is being prepped for display...
if ($op === 'view') {
// If this node has a variable price product feature...
if (db_result(db_query("SELECT pfid FROM {uc_product_features} WHERE fid = 'varprice' AND nid = %d", $node->nid))) {
// Hide all the prices from display.
$node->content['cost']['#access'] = FALSE;
$node->content['list_price']['#access'] = FALSE;
$node->content['sell_price']['#access'] = FALSE;
$node->content['display_price']['#access'] = FALSE;
}
}
elseif (uc_product_is_product($node)) {
// When a product node is created...
if ($op === 'insert') {
$data = variable_get('ucvp_class_def_' . $node->type, array());
// If the product class has a default Variable Price product feature...
if ($data) {
// Prepare the data as if it were from a form submission.
$data = unserialize($data);
$data['nid'] = $node->nid;
$data['pfid'] = '';
$form_state = array(
'values' => $data,
);
// Add the feature to the product by spoofing the normal form submission.
$form_state['values']['sel_options_arr'] = $form_state['values']['sel_options'];
uc_varprice_feature_form_submit(array(), $form_state);
}
}
elseif ($op === 'delete') {
$data = uc_varprice_product_load($node->nid);
if ($data) {
db_query('DELETE FROM {uc_varprice_products} WHERE vpid = %d', $data->vpid);
}
}
}
}
/**
* Implementation of hook_add_to_cart_data().
*/
function uc_varprice_add_to_cart_data($form_values) {
// Store the customer entered price in the product's data array.
if (isset($form_values['varprice']) && (!isset($form_values['varprice_sel']) || $form_values['varprice_sel'] === 'other')) {
return array(
'varprice' => $form_values['varprice'],
'uniqid' => uniqid(),
);
}
elseif (isset($form_values['varprice_sel'])) {
return array(
'varprice' => $form_values['varprice_sel'],
'uniqid' => uniqid(),
);
}
}
/**
* Implementation of hook_cart_item().
*/
function uc_varprice_cart_item($op, &$item) {
// When the cart product is being loaded...
if ($op == 'load') {
// If the product has a variable price set...
if (!empty($item->data['varprice'])) {
// Update the cart item's price to the entered price value.
list($price, $uniqueness) = explode(':', $item->data['varprice']);
$price = trim($price);
$item->price = trim($price);
// If a uniqueness string has been attached to the price, append it to the item's title.
if ($uniqueness) {
$item->title .= ": " . trim($uniqueness);
}
}
}
}
/**
* Implementation of hook_product_feature().
*/
function uc_varprice_product_feature() {
$features = array();
$features[] = array(
'id' => 'varprice',
'title' => t('Variable price'),
'callback' => 'uc_varprice_feature_form',
'delete' => 'uc_varprice_feature_delete',
'settings' => 'uc_varprice_settings',
'multiple' => FALSE,
);
return $features;
}
// Adds settings to the product features form for UC Variable Price.
function uc_varprice_settings() {
$form = array();
$form['uc_varprice_global_default'] = array(
'#title' => t('Global default price'),
'#type' => 'textfield',
'#size' => 8,
'#description' => t('The global default price for variable priced products; may be overridden at the product class or product level.'),
'#default_value' => variable_get('uc_varprice_global_default', '0'),
'#field_prefix' => variable_get('uc_sign_after_amount', FALSE) ? '' : variable_get('uc_currency_sign', '$'),
'#field_suffix' => variable_get('uc_sign_after_amount', FALSE) ? variable_get('uc_currency_sign', '$') : '',
);
return $form;
}
// Settings form for individual Variable Price product features.
function uc_varprice_feature_form($form_state, $node, $feature) {
$form = array();
// Add some helper JS to the form.
drupal_add_js(drupal_get_path('module', 'uc_varprice') . '/uc_varprice.js');
// Load the Variable Price data specific to this product.
if ($data = db_fetch_object(db_query("SELECT * FROM {uc_varprice_products} WHERE pfid = %d", $feature['pfid']))) {
$data->sel_options = unserialize($data->sel_options);
}
$form['nid'] = array(
'#type' => 'value',
'#value' => $node->nid,
);
$form['pfid'] = array(
'#type' => 'value',
'#value' => $data ? $data->pfid : '',
);
$form += _uc_varprice_feature_form($data);
return uc_product_feature_form($form);
}
function _uc_varprice_feature_form($data = FALSE) {
$form = array();
$form['#validate'] = array(
'uc_varprice_feature_form_validate',
);
$form['prices'] = array(
'#type' => 'fieldset',
'#title' => t('Price settings'),
);
$form['prices']['price_default'] = array(
'#type' => 'textfield',
'#title' => t('Default price'),
'#size' => 8,
'#description' => t('The default price for this variable priced product.'),
'#default_value' => $data ? $data->price_default : variable_get('uc_varprice_global_default', '0'),
'#field_prefix' => variable_get('uc_sign_after_amount', FALSE) ? '' : variable_get('uc_currency_sign', '$'),
'#field_suffix' => variable_get('uc_sign_after_amount', FALSE) ? variable_get('uc_currency_sign', '$') : '',
);
$form['prices']['sel_fs'] = array(
'#type' => 'fieldset',
'#title' => t('Selectable price'),
);
$form['prices']['sel_fs']['selectable'] = array(
'#type' => 'checkbox',
'#title' => t('Enable selectable variable prices'),
'#description' => t('When enabled, visitors may select one of several pre-set values defined by you.'),
'#default_value' => $data ? $data->selectable : FALSE,
);
$form['prices']['sel_fs']['sel_widget'] = array(
'#type' => 'radios',
'#title' => t('Selection widget type'),
'#options' => array(
'radios' => t('Radio buttons'),
'select' => t('Drop-down menu'),
),
'#default_value' => $data ? $data->sel_widget : 'radios',
);
$sel_options_array = array();
if ($data && $data->sel_options) {
foreach ($data->sel_options as $key => $val) {
$sel_options_array[] = "{$key}|{$val}";
}
}
$form['prices']['sel_fs']['sel_options'] = array(
'#type' => 'textarea',
'#title' => t('Selectable prices'),
'#description' => t('Enter one price per line, without currency symbols. If both selectable and arbitrary prices are enabled, an “Other” option will be automatically added to the end; when selected, the field to enter an arbitrary price will become available. If the value entered in the “Default price” field above matches one of these values, that option will be the default value of the price selection widget. You can also enter a price on each line in the format key|label, where the key is the price, and the label is is what you want displayed to end users. Example: "100|Sustainer ($100)". If you want to have more than one option at the same price but with different display text, you can add a colon and an optional unique identifier string after the price. Example:<br />100:School A|Sustainer from School A ($100)<br />100:School B|Sustainer from School B ($100)'),
'#default_value' => implode("\n", $sel_options_array),
'#field_prefix' => variable_get('uc_sign_after_amount', FALSE) ? '' : variable_get('uc_currency_sign', '$'),
'#field_suffix' => variable_get('uc_sign_after_amount', FALSE) ? variable_get('uc_currency_sign', '$') : '',
);
$form['prices']['arb_fs'] = array(
'#type' => 'fieldset',
'#title' => t('Arbitrary price'),
);
$form['prices']['arb_fs']['arbitrary'] = array(
'#type' => 'checkbox',
'#title' => t('Enable arbitrary variable prices'),
'#description' => t('When enabled, visitors will be able to enter any arbitrary price for this product, within the limits specified below.'),
'#default_value' => $data ? $data->arbitrary : TRUE,
);
$form['prices']['arb_fs']['price_minimum'] = array(
'#type' => 'textfield',
'#title' => t('Minimum price'),
'#size' => 8,
'#description' => t('The minimum price required for this product to be added to the cart.<br />Leave blank for no minimum.'),
'#default_value' => $data ? $data->price_minimum : '',
'#field_prefix' => variable_get('uc_sign_after_amount', FALSE) ? '' : variable_get('uc_currency_sign', '$'),
'#field_suffix' => variable_get('uc_sign_after_amount', FALSE) ? variable_get('uc_currency_sign', '$') : '',
);
$form['prices']['arb_fs']['price_maximum'] = array(
'#type' => 'textfield',
'#title' => t('Maximum price'),
'#size' => 8,
'#description' => t('The maximum price allowed for this product to be added to the cart.<br />Leave blank for no maximum.'),
'#default_value' => $data ? $data->price_maximum : '',
'#field_prefix' => variable_get('uc_sign_after_amount', FALSE) ? '' : variable_get('uc_currency_sign', '$'),
'#field_suffix' => variable_get('uc_sign_after_amount', FALSE) ? variable_get('uc_currency_sign', '$') : '',
);
$form['titles'] = array(
'#type' => 'fieldset',
'#title' => t('Add to cart form element titles'),
'#description' => t('Use these settings to adjust the normal titles of add to cart form elements for variable priced products.'),
);
$form['titles']['override_add_to_cart_title'] = array(
'#type' => 'checkbox',
'#title' => t('Override the title of the add to cart button.'),
'#description' => t('Defaults to <em>Add to cart</em>. For multilingual sites, use <a href="!url">String Overrides</a> instead.', array(
'!url' => url('http://drupal.org/project/stringoverrides', array(
'absolute' => TRUE,
)),
)),
'#default_value' => $data ? !empty($data->add_to_cart_title) : FALSE,
'#attributes' => array(
'class' => 'override-checkbox',
),
);
$form['titles']['add_to_cart_title'] = array(
'#type' => 'textfield',
'#title' => t('Add to cart button title'),
'#default_value' => $data && !empty($data->add_to_cart_title) ? $data->add_to_cart_title : t('Add to cart'),
);
$form['titles']['override_amount_title'] = array(
'#type' => 'checkbox',
'#title' => t('Override the title of the amount field for the price on the add to cart form.'),
'#description' => t('Defaults to <em>Amount</em>. For multilingual sites, use <a href="!url">String Overrides</a> instead.', array(
'!url' => url('http://drupal.org/project/stringoverrides', array(
'absolute' => TRUE,
)),
)),
'#default_value' => $data ? !empty($data->amount_title) : FALSE,
'#attributes' => array(
'class' => 'override-checkbox',
),
);
$form['titles']['amount_title'] = array(
'#type' => 'textfield',
'#title' => t('Amount field title'),
'#default_value' => $data && !empty($data->amount_title) ? $data->amount_title : t('Amount'),
);
return $form;
}
function uc_varprice_feature_form_validate($form, &$form_state) {
// Check for invalid text in the "Selectable prices" field
$form_state['values']['sel_options_arr'] = array();
foreach (array_unique(explode("\n", $form_state['values']['sel_options'])) as $value) {
list($value, $display) = explode('|', $value);
$display = trim($display);
// Be forgiving of spaces and blank lines
$value = trim($value);
list($value, $uniqueness) = explode(':', $value);
if ($value !== '') {
if (!is_numeric($value)) {
form_set_error('sel_options', t('The value %val does not appear to be a number. Please enter only one number per line, without currency symbols.', array(
'%val' => $value,
)));
}
else {
// We want the keys of this array to be in the same format as the
// price_default field in the database (2 decimal points) so that we can
// properly select the default on the select widget.
// But we also want to be able to have multiple display options for the same value, so
// you can have an optional unique identifier after the value, preceded by a colon.
$value_key = $uniqueness ? sprintf('%.2f', $value) . ":{$uniqueness}" : sprintf('%.2f', $value);
$form_state['values']['sel_options_arr'][$value_key] = $display ? $display : uc_currency_format($value);
}
}
}
}
function uc_varprice_feature_form_submit($form, &$form_state) {
// Build an array of Variable Price data from the form submission.
$vp_data = array(
'pfid' => $form_state['values']['pfid'],
'price_default' => $form_state['values']['price_default'],
'price_minimum' => $form_state['values']['price_minimum'],
'price_maximum' => $form_state['values']['price_maximum'],
'add_to_cart_title' => $form_state['values']['override_add_to_cart_title'] ? $form_state['values']['add_to_cart_title'] : '',
'amount_title' => $form_state['values']['override_amount_title'] ? $form_state['values']['amount_title'] : '',
'arbitrary' => intval($form_state['values']['arbitrary']),
'selectable' => intval($form_state['values']['selectable']),
'sel_widget' => $form_state['values']['sel_widget'],
'sel_options' => serialize($form_state['values']['sel_options_arr']),
);
// Build the product feature description.
$description = array(
t('Customers can specify a price for this product.'),
t('<strong>Default price:</strong> @price', array(
'@price' => uc_currency_format($vp_data['price_default']),
)),
);
if (!empty($vp_data['amount_title'])) {
$description[] = t('<strong>Amount field title:</strong> @title', array(
'@title' => $vp_data['amount_title'],
));
}
if ($vp_data['selectable']) {
$description[] = t('Customers may select a price from a list.');
$description[] = t('<strong>Selectable prices:</strong> @prices', array(
'@prices' => implode(', ', $form_state['values']['sel_options_arr']),
));
if ($form_state['values']['sel_widget'] === 'radios') {
$description[] = t('Prices are selected with <strong>radio buttons</strong>.');
}
elseif ($form_state['values']['sel_widget'] === 'select') {
$description[] = t('Prices are selected with a <strong>drop-down menu</strong>.');
}
}
if ($vp_data['arbitrary']) {
$description[] = t('Customers may enter an arbitrary price.');
if (!empty($vp_data['price_minimum'])) {
$description[] = t('<strong>Minimum price:</strong> @price', array(
'@price' => uc_currency_format($vp_data['price_minimum']),
));
}
if (!empty($vp_data['price_maximum'])) {
$description[] = t('<strong>Maximum price:</strong> @price', array(
'@price' => uc_currency_format($vp_data['price_maximum']),
));
}
if (!empty($vp_data['add_to_cart_title'])) {
$description[] = t('<strong>Add to cart title:</strong> @title', array(
'@title' => $vp_data['add_to_cart_title'],
));
}
}
// Save the basic product feature data.
$data = array(
'pfid' => $vp_data['pfid'],
'nid' => $form_state['values']['nid'],
'fid' => 'varprice',
'description' => implode('<br />', $description),
);
$form_state['redirect'] = uc_product_feature_save($data);
// Insert or update the data in the Variable Price products table.
if (empty($data['pfid'])) {
$vp_data['pfid'] = db_last_insert_id('uc_product_features', 'pfid');
$key = NULL;
}
else {
$vp_data['vpid'] = db_result(db_query("SELECT vpid FROM {uc_varprice_products} WHERE pfid = %d", $data['pfid']));
$key = 'vpid';
}
drupal_write_record('uc_varprice_products', $vp_data, $key);
}
// Variable Price product feature delete function.
function uc_varprice_feature_delete($feature) {
db_query("DELETE FROM {uc_varprice_products} WHERE pfid = %d", $feature['pfid']);
}
// Load the product feature data for a given node.
function uc_varprice_product_load($nid) {
$return = db_fetch_object(db_query("SELECT vp.* FROM {uc_product_features} AS pf LEFT JOIN {uc_varprice_products} AS vp ON pf.pfid = vp.pfid WHERE pf.fid = 'varprice' AND pf.nid = %d", $nid));
if ($return) {
$return->sel_options = unserialize($return->sel_options);
}
return $return;
}
// Theme the Qty. field for products in the shopping cart with variable prices.
function theme_varprice_qty($element) {
return $element['#default_value'];
}Functions
|
Name |
Description |
|---|---|
| theme_varprice_qty | |
| uc_varprice_add_to_cart_data | Implementation of hook_add_to_cart_data(). |
| uc_varprice_add_to_cart_form_validate | |
| uc_varprice_cart_item | Implementation of hook_cart_item(). |
| uc_varprice_feature_delete | |
| uc_varprice_feature_form | |
| uc_varprice_feature_form_submit | |
| uc_varprice_feature_form_validate | |
| uc_varprice_form_alter | Implementation of hook_form_alter(). |
| uc_varprice_init | Implementation of hook_init() |
| uc_varprice_nodeapi | Implementation of hook_nodeapi(). |
| uc_varprice_product_class_submit | |
| uc_varprice_product_feature | Implementation of hook_product_feature(). |
| uc_varprice_product_load | |
| uc_varprice_settings | |
| uc_varprice_theme | Implementation of hook_theme() |
| _uc_varprice_feature_form |