uc_product.admin.inc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. <?php
  2. /**
  3. * @file
  4. * Product administration menu items.
  5. */
  6. /**
  7. * Displays a list of product classes.
  8. */
  9. function uc_product_class_default() {
  10. $classes = uc_product_class_load();
  11. $header = array(t('Class ID'), t('Name'), t('Description'), t('Operations'));
  12. $rows = array();
  13. foreach ($classes as $class) {
  14. $ops = array(l(t('edit'), 'admin/store/products/classes/' . $class->pcid . '/edit'));
  15. if (empty($class->locked)) {
  16. $ops[] = l(t('delete'), 'admin/store/products/classes/' . $class->pcid . '/delete');
  17. }
  18. $rows[] = array(
  19. check_plain($class->pcid),
  20. check_plain($class->name),
  21. filter_xss_admin($class->description),
  22. implode(' ', $ops),
  23. );
  24. }
  25. $build = array();
  26. $build['product_classes'] = array(
  27. '#theme' => 'table',
  28. '#header' => $header,
  29. '#rows' => $rows,
  30. '#empty' => t('No product classes have been defined yet.'),
  31. );
  32. $build['header'] = array(
  33. '#markup' => '<h2>' . t('Add a class') . '</h2>',
  34. );
  35. $build['form'] = drupal_get_form('uc_product_class_form');
  36. return $build;
  37. }
  38. /**
  39. * Form to change product settings.
  40. *
  41. * @ingroup forms
  42. */
  43. function uc_product_settings_form($form, &$form_state) {
  44. // Put fieldsets into vertical tabs
  45. $form['product-settings'] = array('#type' => 'vertical_tabs');
  46. $form['product'] = array(
  47. '#type' => 'fieldset',
  48. '#title' => t('Product settings'),
  49. '#group' => 'product-settings',
  50. '#weight' => -10,
  51. );
  52. // Loop through all the integrated image widgets and build an options array.
  53. $options = array();
  54. foreach (module_invoke_all('uc_image_widget') as $key => $widget) {
  55. $options[$key] = check_plain($widget['name']);
  56. }
  57. if (empty($options)) {
  58. $options[NULL] = t('No image widgets installed.');
  59. }
  60. else {
  61. // If we have widgets installed, add option to not use any of them
  62. $options['none'] = t("Don't use any image widgets.");
  63. }
  64. $form['product']['uc_product_image_widget'] = array(
  65. '#type' => 'radios',
  66. '#title' => t('Product image widget'),
  67. '#description' => t('The selected widget will be used to display a zoomed version of product images when they are clicked.'),
  68. '#options' => $options,
  69. '#default_value' => variable_get('uc_product_image_widget', NULL),
  70. );
  71. if (module_exists('uc_cart')) {
  72. $form['product']['uc_product_add_to_cart_qty'] = array(
  73. '#type' => 'checkbox',
  74. '#title' => t('Display an optional quantity field in the <em>Add to Cart</em> form.'),
  75. '#default_value' => variable_get('uc_product_add_to_cart_qty', FALSE),
  76. );
  77. $form['product']['uc_product_update_node_view'] = array(
  78. '#type' => 'checkbox',
  79. '#title' => t('Update product display based on customer selections'),
  80. '#default_value' => variable_get('uc_product_update_node_view', FALSE),
  81. '#description' => t('Check this box to dynamically update the display of product information such as display-price or weight based on customer input on the add-to-cart form (e.g. selecting a particular attribute option).'),
  82. );
  83. }
  84. foreach (module_invoke_all('uc_product_feature') as $feature) {
  85. if (isset($feature['settings']) &&
  86. function_exists($feature['settings'])) {
  87. $form[$feature['id']] = array(
  88. '#type' => 'fieldset',
  89. '#title' => t('@feature settings', array('@feature' => $feature['title'])),
  90. '#group' => 'product-settings',
  91. );
  92. $form[$feature['id']] += $feature['settings'](array(), $form_state);
  93. if (function_exists($feature['settings'] . '_validate')) {
  94. $form['#validate'][] = $feature['settings'] . '_validate';
  95. }
  96. if (function_exists($feature['settings'] . '_submit')) {
  97. $form['#submit'][] = $feature['settings'] . '_submit';
  98. }
  99. }
  100. }
  101. return system_settings_form($form);
  102. }
  103. /**
  104. * Displays the product features tab on a product node edit form.
  105. */
  106. function uc_product_features($node, $fid = NULL, $pfid = NULL) {
  107. drupal_set_title($node->title);
  108. $header = array(t('Type'), t('Description'), t('Operations'));
  109. $rows = array();
  110. $features = uc_product_feature_load_multiple($node->nid);
  111. foreach ($features as $feature) {
  112. $operations = array(
  113. 'edit' => array('title' => t('edit'), 'href' => 'node/' . $node->nid . '/edit/features/' . $feature->fid . '/' . $feature->pfid),
  114. 'delete' => array('title' => t('delete'), 'href' => 'node/' . $node->nid . '/edit/features/' . $feature->fid . '/' . $feature->pfid . '/delete'),
  115. );
  116. $rows[] = array(
  117. array('data' => uc_product_feature_data($feature->fid, 'title')),
  118. array('data' => $feature->description),
  119. theme('links', array(
  120. 'links' => $operations,
  121. 'attributes' => array('class' => array('links', 'inline')),
  122. )),
  123. );
  124. }
  125. $build['features'] = array(
  126. '#theme' => 'table',
  127. '#header' => $header,
  128. '#rows' => $rows,
  129. '#attributes' => array('class' => array('uc-product-features')),
  130. '#empty' => t('No features found for this product.'),
  131. );
  132. $build['add_form'] = drupal_get_form('uc_product_feature_add_form', $node);
  133. return $build;
  134. }
  135. /**
  136. * Handles adding or editing product features.
  137. */
  138. function uc_product_feature_edit($node, $fid, $pfid) {
  139. $func = uc_product_feature_data($fid, 'callback');
  140. if (function_exists($func)) {
  141. $form_state = array(
  142. 'build_info' => array(
  143. 'args' => array(
  144. $node,
  145. ),
  146. ),
  147. 'wrapper_callback' => 'uc_product_feature_form',
  148. );
  149. if ($pfid == 'add') {
  150. $form_state['build_info']['args'][] = array();
  151. $build = drupal_build_form($func, $form_state);
  152. }
  153. elseif (intval($pfid) > 0) {
  154. $feature = uc_product_feature_load($pfid);
  155. if (isset($feature)) {
  156. $form_state['build_info']['args'][] = $feature;
  157. $build = drupal_build_form($func, $form_state);
  158. }
  159. }
  160. else {
  161. drupal_goto('node/' . $node->nid . '/edit/features');
  162. }
  163. }
  164. else {
  165. drupal_set_message(t('Error: Attempted to add a non-existent product feature type.'), 'error');
  166. drupal_goto('node/' . $node->nid . '/edit/features');
  167. }
  168. if (empty($build)) {
  169. drupal_set_message(t('Error: No form data was returned for that operation.'), 'error');
  170. drupal_goto('node/' . $node->nid . '/edit/features');
  171. }
  172. return $build;
  173. }
  174. /**
  175. * Adds the form for adding a product feature to the features tab.
  176. *
  177. * @see uc_product_feature_add_form_submit()
  178. * @see theme_uc_product_feature_add_form()
  179. * @ingroup forms
  180. */
  181. function uc_product_feature_add_form($form, &$form_state, $node) {
  182. foreach (module_invoke_all('uc_product_feature') as $feature) {
  183. $options[$feature['id']] = $feature['title'];
  184. }
  185. ksort($options);
  186. $form['feature'] = array(
  187. '#type' => 'select',
  188. '#title' => t('Add a new feature'),
  189. '#options' => $options,
  190. );
  191. $form['actions'] = array('#type' => 'actions');
  192. $form['actions']['submit'] = array(
  193. '#type' => 'submit',
  194. '#value' => t('Add'),
  195. );
  196. return $form;
  197. }
  198. /**
  199. * Theme function for uc_product_feature_add_form().
  200. *
  201. * @param $variables
  202. * An associative array containing:
  203. * - form: A render element representing the form.
  204. *
  205. * @see uc_product_feature_add_form()
  206. * @ingroup themeable
  207. */
  208. function theme_uc_product_feature_add_form($variables) {
  209. return '<table class="add-feature"><tr><td>' . drupal_render_children($variables['form']) . '</td></tr></table>';
  210. }
  211. /**
  212. * Form submission handler for uc_product_feature_add_form().
  213. *
  214. * @see uc_product_feature_add_form()
  215. */
  216. function uc_product_feature_add_form_submit($form, &$form_state) {
  217. $node = $form_state['build_info']['args'][0];
  218. $form_state['redirect'] = 'node/' . $node->nid . '/edit/features/' . $form_state['values']['feature'] . '/add';
  219. }
  220. /**
  221. * Confirmation form to delete a product feature.
  222. *
  223. * @see uc_product_feature_confirm_delete_submit()
  224. * @ingroup forms
  225. */
  226. function uc_product_feature_confirm_delete($form, &$form_state, $node, $fid, $feature) {
  227. $description = t('Are you sure you wish to delete this %feature?', array('%feature' => uc_product_feature_data($fid, 'title')))
  228. . '<div><b>' . t('Description') . ':</b><br />' . $feature['description'] . '</div><br />';
  229. return confirm_form($form, check_plain($node->title), 'node/' . $node->nid . '/edit/features', $description, t('Delete'), t('Cancel'), 'pf_delete');
  230. }
  231. /**
  232. * Form submission handler for uc_product_feature_confirm_delete().
  233. *
  234. * @see uc_product_feature_confirm_delete()
  235. */
  236. function uc_product_feature_confirm_delete_submit($form, &$form_state) {
  237. $node = $form_state['build_info']['args'][0];
  238. $feature = $form_state['build_info']['args'][2];
  239. if ($form_state['values']['pf_delete']) {
  240. uc_product_feature_delete($feature['pfid']);
  241. drupal_set_message(t('The product feature has been deleted.'));
  242. }
  243. $form_state['redirect'] = 'node/' . $node->nid . '/edit/features';
  244. }
  245. /**
  246. * Sets up image field for products.
  247. *
  248. * @see uc_product_uc_store_status()
  249. */
  250. function uc_product_image_defaults() {
  251. uc_product_add_default_image_field();
  252. drupal_set_message(t('Default image support configured for Ubercart products.'));
  253. drupal_goto('admin/store');
  254. }
  255. /**
  256. * Form builder for product classes.
  257. *
  258. * @see uc_product_class_form_validate()
  259. * @see uc_product_class_form_submit()
  260. * @ingroup forms
  261. */
  262. function uc_product_class_form($form, &$form_state, $class = NULL) {
  263. if (!is_null($class)) {
  264. $classname = $class->name;
  265. $classdesc = $class->description;
  266. drupal_set_title($classname);
  267. $form['pcid'] = array(
  268. '#type' => 'hidden',
  269. '#value' => $class->pcid
  270. );
  271. }
  272. else {
  273. $classname = '';
  274. $classdesc = '';
  275. $form['pcid'] = array(
  276. '#type' => 'textfield',
  277. '#title' => t('Class ID'),
  278. '#required' => TRUE,
  279. '#maxlength' => 32,
  280. '#description' => t('The machine-readable name of this content type. This text will be used for constructing the URL of the <em>create content</em> page for this content type. This name may consist only of lowercase letters, numbers, and underscores. Dashes are not allowed. Underscores will be converted into dashes when constructing the URL of the <em>create content</em> page. This name must be unique to this content type.'),
  281. );
  282. }
  283. $form['name'] = array(
  284. '#type' => 'textfield',
  285. '#title' => t('Class name'),
  286. '#description' => t('The human-readable name of this content type as it should appear on the !create_content page. There are no character restrictions on this name.', array('!create_content' => l(t('Create content'), 'node/add'))),
  287. '#default_value' => $classname,
  288. '#required' => TRUE,
  289. );
  290. $form['description'] = array(
  291. '#type' => 'textarea',
  292. '#title' => t('Description'),
  293. '#description' => t('This text describes the content type to administrators.'),
  294. '#default_value' => $classdesc,
  295. );
  296. $form['actions'] = array('#type' => 'actions');
  297. $form['actions']['submit'] = array(
  298. '#type' => 'submit',
  299. '#value' => t('Save'),
  300. );
  301. return $form;
  302. }
  303. /**
  304. * Ensures the new product class is unique.
  305. *
  306. * @see uc_product_class_form()
  307. * @see uc_product_class_form_submit()
  308. */
  309. function uc_product_class_form_validate($form, &$form_state) {
  310. if ($form['pcid']['#type'] == 'textfield') {
  311. $type = node_type_get_type($form_state['values']['pcid']);
  312. if ($type) {
  313. if ($type->base == 'uc_product') {
  314. form_set_error('pcid', t('This product class already exists.'));
  315. }
  316. elseif ($type->custom == 0) {
  317. form_set_error('pcid', t('This is a node type provided by another module. Only custom node types may become product classes.'));
  318. }
  319. }
  320. }
  321. }
  322. /**
  323. * Form submission handler for uc_product_class_form().
  324. *
  325. * @see uc_product_class_form()
  326. * @see uc_product_class_form_validate()
  327. */
  328. function uc_product_class_form_submit($form, &$form_state) {
  329. $is_new = $form['pcid']['#type'] == 'textfield';
  330. $pcid = $form_state['values']['pcid'];
  331. // Convert whitespace to underscores, and remove other non-alphanumeric characters.
  332. $pcid = preg_replace(array('/\s+/', '/\W/'), array('_', ''), strtolower($pcid));
  333. $result = db_merge('uc_product_classes')
  334. ->key(array('pcid' => $pcid))
  335. ->fields(array(
  336. 'name' => $form_state['values']['name'],
  337. 'description' => $form_state['values']['description'],
  338. ))
  339. ->execute();
  340. db_update('node_type')
  341. ->fields(array(
  342. 'name' => $form_state['values']['name'],
  343. 'description' => $form_state['values']['description'],
  344. ))
  345. ->condition('type', $pcid)
  346. ->execute();
  347. uc_product_node_info(TRUE);
  348. if ($result == MergeQuery::STATUS_INSERT) {
  349. variable_set('node_options_' . $pcid, variable_get('node_options_product', array('status', 'promote')));
  350. if (module_exists('comment')) {
  351. variable_set('comment_' . $pcid, variable_get('comment_product', COMMENT_NODE_OPEN));
  352. }
  353. module_invoke_all('uc_product_class', $pcid, 'insert');
  354. }
  355. else {
  356. module_invoke_all('uc_product_class', $pcid, 'update');
  357. }
  358. node_types_rebuild();
  359. if ($is_new) {
  360. $type = node_type_get_type($pcid);
  361. node_add_body_field($type, t('Description'));
  362. uc_product_add_default_image_field($pcid);
  363. }
  364. menu_rebuild();
  365. drupal_set_message(t('Product class saved.'));
  366. }
  367. /**
  368. * Confirms the deletion of a product class.
  369. *
  370. * @see uc_product_class_delete_confirm_submit()
  371. */
  372. function uc_product_class_delete_confirm($form, &$form_state, $class) {
  373. $form['pcid'] = array(
  374. '#type' => 'value',
  375. '#value' => $class->pcid,
  376. );
  377. $question = t('Are you sure you want to delete the %type product class?', array('%type' => $class->pcid));
  378. $description = t('The node type associated with this product class will revert to a standard node type.');
  379. // Find out how many nodes of this class exist and add to the description.
  380. $count = db_query("SELECT COUNT(*) FROM {node} WHERE type = :pcid", array(':pcid' => $class->pcid))->fetchField();
  381. if ($count > 0) {
  382. $description .= '<br />' . format_plural($count, 'There is 1 node of this type.', 'There are @count nodes of this type.');
  383. }
  384. return confirm_form($form, $question, 'admin/store/products/classes', $description, t('Delete'), t('Cancel'));
  385. }
  386. /**
  387. * Form submission handler for uc_product_class_delete_confirm().
  388. *
  389. * @see uc_product_class_delete_confirm()
  390. */
  391. function uc_product_class_delete_confirm_submit($form, &$form_state) {
  392. $type = node_type_get_type($form_state['values']['pcid']);
  393. $type->base = 'node_content';
  394. $type->custom = 1;
  395. node_type_save($type);
  396. db_delete('uc_product_classes')
  397. ->condition('pcid', $form_state['values']['pcid'])
  398. ->execute();
  399. module_invoke_all('uc_product_class', $form_state['values']['pcid'], 'delete');
  400. uc_product_node_info(TRUE);
  401. node_types_rebuild();
  402. menu_rebuild();
  403. drupal_set_message(t('Product class %type deleted.', array('%type' => $form_state['values']['pcid'])));
  404. $form_state['redirect'] = 'admin/store/products/classes';
  405. }