commerce_apd.module in Auto Product Display 7
Contain main functions for Auto Product Display
File
commerce_apd.moduleView source
<?php
/**
* @file
* Contain main functions for Auto Product Display
*/
/**
* Implements hook_menu().
*/
function commerce_apd_menu() {
// Add menu to open the configuration page.
$items["admin/commerce/config/auto-product-display"] = array(
"title" => "Auto product display",
"description" => "Configure the auto product display behavior.",
"type" => MENU_NORMAL_ITEM,
"access arguments" => array(
"configure auto product display",
),
"page callback" => "drupal_get_form",
"page arguments" => array(
"_commerce_apd_configuration",
),
"file" => "commerce_apd_admin.inc",
);
return $items;
}
/**
* Implements hook_entity_update().
*/
function commerce_apd_entity_update($entity, $type) {
// Check if the updated entity is commerce product.
if ($type == "commerce_product") {
// Get the product ID.
$product_id = $entity->product_id;
// Get the referencing nodes.
$referencing_nodes = _commerce_apd_get_nodes_referencing($product_id);
// Loop through the nodes
foreach ($referencing_nodes as $nid) {
// Update node status based on the product status.
$node = node_load($nid);
$node->status = $entity->status;
node_save($node);
}
}
}
/**
* Implements hook_permission().
* Add permission to configure auto product display.
*/
function commerce_apd_permission() {
return array(
"configure auto product display" => array(
"title" => t("configure auto product display"),
"description" => t("Configure the auto product display behavior."),
),
);
}
/**
* Implements hook_form_alter().
*/
function commerce_apd_form_commerce_product_ui_product_delete_form_alter(&$form, &$form_state, $form_id) {
$content_type = _commerce_apd_get_content_type($form_state['product']->type);
// If we aren't attaching the product to any specific content type, ignore.
if ($content_type == "") {
return;
}
// Add one submit handler to delete product display after product deletion.
$form['#submit'][] = '_commerce_apd_delete_referencing_node';
// Reverse the array so the new function will be executed first.
$form['#submit'] = array_reverse($form['#submit']);
}
/**
* Form submission handler for deleting product display.
*/
function _commerce_apd_delete_referencing_node($form, &$form_state) {
// Get the referencing node.
$referencing_nodes = _commerce_apd_get_nodes_referencing($form_state['product']->product_id);
// Make sure there is only one node referenced to the product and the configuration is set for that.
if (count($referencing_nodes) == 1 && variable_get("commerce_apd_auto_delete_display", 0) == 1) {
node_delete($referencing_nodes[0]);
}
}
/**
* Implements hook_form_alter().
* Alter the product creation form to add a new option to
* automatically create product display.
*/
function commerce_apd_form_commerce_product_ui_product_form_alter(&$form, &$form_state, $form_id) {
// Get the default content type for product display.
$content_type = _commerce_apd_get_content_type($form_state['commerce_product']->type);
// If we aren't attaching the product to any specific content type, ignore.
if ($content_type == "") {
// Notify user that this product has no product display.
drupal_set_message(t("This product is not configured to has product display, so it should be added manually when creating product display."));
return;
}
// Get the referencing node(s).
$existing_references = array();
if (isset($form_state['commerce_product']->product_id)) {
$referenced_from = _commerce_apd_get_nodes_referencing($form_state['commerce_product']->product_id);
if (!empty($referenced_from)) {
foreach ($referenced_from as $reference) {
$existing_references[] = $reference;
}
}
}
// Count the existing references.
$count_existing_references = count($existing_references);
// If new product creation or no referencing node found.
if (isset($form_state['commerce_product']->is_new) || $count_existing_references <= 1) {
// Check if the product display creation form should be displayed automatically.
$show_form = variable_get("commerce_apd_show_product_display_form", 0);
// Show the checkbox if the form for creating product display is not configured
// to be displayed automatically and there is no node referencing to it.
if ($show_form == 0 && $count_existing_references == 0) {
// Display the option for creating product display.
// Use AJAX to displaying or hiding the form.
$form['auto_display'] = array(
'#type' => 'checkbox',
'#title' => t('Create product display'),
'#description' => t('Check this options if you want to create the display for this product.'),
'#weight' => $form['actions']['#weight'] - 2,
'#ajax' => array(
'event' => 'click',
'callback' => '_commerce_apd_product_display_form',
'wrapper' => 'create-display-fieldset',
),
);
}
// If there is only one node referencing this product.
if ($count_existing_references == 1) {
// Load the node.
$node = node_load($existing_references[0]);
// Save node id to a hidden input for deciding to update node or create new node
// when the form is submitted.
$form['commerce_apd_referenced_nid'] = array(
"#type" => "hidden",
"#value" => $existing_references[0],
);
}
else {
// Prepare node object.
$node = new stdClass();
$node->type = $content_type;
}
// Get the field name which type is product reference.
$field_product = _commerce_apd_get_product_field($content_type);
// Create product display fieldset to hold sub-form.
// Initially it will be hidden using inline style.
$form['product_display'] = array(
'#type' => 'fieldset',
'#attributes' => array(
'id' => 'create-display-fieldset',
'style' => 'display:none',
),
'#legend' => $show_form == 0 && $count_existing_references == 0 ? t('Product display') : '',
'#weight' => $form['actions']['#weight'] - 1,
);
// If the form is not shown automatically and the value of the auto display checkbox is checked,
// or there is node referencing to this product, or for is form is set to be shown automatically,
// We will display the form.
$auto_display = isset($form_state['values']['auto_display']) ? $form_state['values']['auto_display'] : FALSE;
if ($show_form == 0 && $auto_display == TRUE || $count_existing_references == 1 || $show_form == 1) {
// Show the fieldset by removing the style.
unset($form['product_display']['#attributes']['style']);
// Attach the product display form to product creation variable.
field_attach_form('node', $node, $form['product_display'], $form_state);
// Check if product display title can be defined manually or just automatically.
if (variable_get("commerce_apd_auto_product_display_title", 1) == 0) {
// The trick to find the minimum weight from each form components.
$min_weight = 0;
foreach ($form['product_display'] as $key => $component) {
if (substr($key, 0, 1) !== "#" && is_array($component)) {
if (isset($component['#weight'])) {
if ($component['#weight'] < $min_weight) {
$min_weight = $component['#weight'];
}
}
}
}
// Display new field to override product display title.
// This field will be displayed first. That's why we need the minimum weight.
$form['product_display']['display_title'] = array(
'#title' => t('Displayed title'),
'#description' => t('The title that will be displayed in front-end. Leave it empty to use the same title as the product.'),
'#type' => 'textfield',
'#weight' => $min_weight - 1,
'#default_value' => isset($node->title) ? $node->title : '',
);
}
// Don't include the product reference field because it will be filled
// automatically after form submission.
unset($form['product_display'][$field_product]);
}
// Add submit handler function.
$form['actions']['submit']['#submit'][] = 'commerce_apd_product_form_reference_submit';
}
else {
// If there are more than one nodes referencing this product,
// they will be displayed is list with the update link.
// We made fieldset for containing the list.
$form['referencing_nodes'] = array(
'#type' => 'fieldset',
'#title' => t('Product display'),
'#weight' => $form['actions']['#weight'],
);
// Get the referencing nodes including the 'update' link
// for updating the product display.
$rows = array();
foreach ($existing_references as $key => $existing_reference) {
$rows[] = _commerce_apd_get_product_reference_detail($existing_reference, $form_state['commerce_product']->product_id);
}
// Finally, display them in a table.
$form['referencing_nodes']['table'] = array(
'#theme' => 'table',
'#header' => array(
'Title',
'Language',
'Action',
),
'#rows' => $rows,
'#empty' => t('No content available.'),
);
}
}
/**
* Handle the form submission process. Product display will be created here.
*/
function commerce_apd_product_form_reference_submit(&$form, &$form_state) {
global $user;
// Check if the form for creating product display is configured to be displayed automatically.
$show_form = variable_get("commerce_apd_show_product_display_form", 0);
// Get the value of "create product display" checkbox if it exists.
$auto_display = isset($form_state['values']['auto_display']) ? $form_state['values']['auto_display'] : FALSE;
// Check if the product display should be created automatically or
// the form for creating product display is configured to be displayed automatically.
if ($auto_display == TRUE || $show_form == 1 || isset($form_state['values']['commerce_apd_referenced_nid'])) {
// Get the default content type for product display.
$content_type = _commerce_apd_get_content_type($form_state['commerce_product']->type);
// Get the field name which type is product reference.
$field_product = _commerce_apd_get_product_field($content_type);
// TO DO: Find a better way to store language for node.
$lang = LANGUAGE_NONE;
// If there is no submitted value storing the referenced node id, create a new node.
if (!isset($form_state['values']['commerce_apd_referenced_nid'])) {
// Set some fields value.
$node = new stdClass();
$node->is_new = TRUE;
$node->type = $content_type;
$node->uid = $user->uid;
// Variable for storing temporary attached form.
$form2 = array();
// Variable for storing product display form which
// fields will be attached to node.
$node_form = array();
// Attached product display form to retreive its field.
field_attach_form('node', $node, $form2, $form_state);
// Unset the product reference field.
unset($form2[$field_product]);
// Loop through attached form
foreach ($form2 as $field => $value) {
// Fill the node form for submission.
if (isset($form[$field])) {
$node_form[$field] = $form[$field];
}
}
// Add other fields (if any) to the node class,
// so they value can also be saved.
entity_form_submit_build_entity('node', $node, $node_form, $form_state);
// Check if product display title can be defined manually or just automatically.
$auto_product_display_title = true;
if (variable_get("commerce_apd_auto_product_display_title", 1) == 0) {
$auto_product_display_title = false;
}
// Check if the product display title will be overriden.
// This code must be placed after running entity_form_submit_build_entity above.
$display_title = isset($form_state['values']['display_title']) ? $form_state['values']['display_title'] : '';
if ($display_title != '' && $auto_product_display_title == false) {
$node->title = $form_state['values']['display_title'];
}
else {
$node->title = $form_state['values']['title'];
}
// Save the product reference field.
$node->{$field_product} = array(
$lang => array(
array(
'product_id' => $form_state['build_info']['args'][0]->product_id,
),
),
);
// Check node publishing option.
$options = variable_get('node_options_' . $node->type, 0);
if ($options == 0) {
$node->status = 1;
}
else {
if (in_array('status', $options)) {
$node->status = 1;
}
else {
$node->status = 0;
}
}
// Check node promotion.
if ($options == 0) {
$node->promote = 1;
}
else {
if (in_array('promote', $options)) {
$node->promote = 1;
}
else {
$node->promote = 0;
}
}
// Check sticky option.
if (is_array($options)) {
if (in_array('sticky', $options)) {
$node->sticky = 1;
}
else {
$node->sticky = 0;
}
}
else {
$node->sticky = 0;
}
// Check node comment option.
$options = variable_get('comment_' . $node->type, array());
if (count($options) == 0) {
// Comment is open by default.
$node->comment = 2;
}
else {
$node->comment = intval($options);
}
// Set language here.
$node->language = $lang;
// Finally save it.
node_save($node);
}
else {
// Update existing node.
$node = node_load($form_state['values']['commerce_apd_referenced_nid']);
// Make sure if node exists.
if (is_object($node)) {
// Variable for storing temporary attached form.
$form2 = array();
// Variable for storing product display form which
// fields will be attached to node.
$node_form = array();
// Attached product display form to retreive its field.
field_attach_form('node', $node, $form2, $form_state);
// Unset the product reference field.
unset($form2[$field_product]);
// Loop through attached form
foreach ($form2 as $field => $value) {
// Fill the node form for submission.
if (isset($form[$field])) {
$node_form[$field] = $form[$field];
}
}
// Add other fields (if any) to the node class,
// so they value can also be saved.
entity_form_submit_build_entity('node', $node, $node_form, $form_state);
// Check if product display title can be defined manually or just automatically.
$auto_product_display_title = true;
if (variable_get("commerce_apd_auto_product_display_title", 1) == 0) {
$auto_product_display_title = false;
}
// Check if the product display title will be overriden.
// This code must be placed after running entity_form_submit_build_entity above.
$display_title = isset($form_state['values']['display_title']) ? $form_state['values']['display_title'] : '';
if ($display_title != '' && $auto_product_display_title == false) {
$node->title = $form_state['values']['display_title'];
}
else {
$node->title = $form_state['values']['title'];
}
// Set language here.
$node->language = $lang;
// Check node revision option.
$options = variable_get('node_options_' . $node->type, array());
$node->revision = in_array('revision', $options);
// Finally update it.
node_save($node);
}
}
}
}
/**
* Get the field name in product display that has reference to product.
*/
function _commerce_apd_get_product_reference_fields() {
$product_reference_fields = array();
$fields = field_info_fields();
foreach ($fields as $field) {
if ($field['type'] == 'commerce_product_reference' && $field['field_name'] != 'commerce_product') {
$product_reference_fields[] = $field['field_name'];
}
}
return $product_reference_fields;
}
/**
* Get the entities that has reference to a product.
*/
function _commerce_apd_get_nodes_referencing($product_id) {
$product_fields = _commerce_apd_get_product_reference_fields();
$entities = array();
foreach ($product_fields as $field) {
$result = db_query('SELECT entity_id FROM {field_data_' . $field . '} df WHERE df.' . $field . '_product_id = :pid AND df.entity_type = :entity_type', array(
':pid' => $product_id,
':entity_type' => 'node',
));
foreach ($result as $reference) {
$entities[] = $reference->entity_id;
}
}
return $entities;
}
/**
* Get the detail information of node that has reference to a product.
*/
function _commerce_apd_get_product_reference_detail($existing_reference, $product_id) {
if ($existing_reference != '') {
$node_obj = db_query('SELECT n.nid, n.title, n.language FROM {node} n WHERE nid = :nid', array(
':nid' => $existing_reference,
))
->fetchObject();
$node_title = $node_obj->title;
$node_id = $node_obj->nid;
$node_language = $node_obj->language;
}
else {
$node_title = '';
$node_id = '';
$node_language = '';
}
return array(
'title' => $node_title,
'language' => $node_language,
'link' => l(t('view'), 'node/' . $node_id) . ' ' . l(t('edit'), 'node/' . $node_id . '/edit', array(
'query' => array(
'destination' => 'admin/commerce/products/' . $product_id . '/edit?destination=admin/commerce/products',
),
)),
);
}
/**
* Get one field from content type which type is product reference.
*/
function _commerce_apd_get_product_field($content_type) {
$field = "";
// Select the product reference field from content type (LIMIT TO 1 PRODUCT DISPLAY ONLY).
$rs = db_query_range("SELECT a.field_name FROM {field_config_instance} a\n INNER JOIN {field_config} b ON a.field_id = b.id\n WHERE a.entity_type = :type AND a.bundle= :bundle AND\n b.type = :reference AND b.module = :reference", 0, 1, array(
':type' => 'node',
':bundle' => $content_type,
':reference' => 'commerce_product_reference',
));
if ($rs
->rowCount() > 0) {
$data = $rs
->fetchObject();
$field = $data->field_name;
}
return $field;
}
/**
* Get default product display content type for product.
*/
function _commerce_apd_get_content_type($product_type) {
$content_type = variable_get("commerce_apd_product_display", array());
if (isset($content_type[$product_type])) {
$content_type = $content_type[$product_type];
}
else {
$content_type = "";
}
return $content_type;
}
/**
* Function for handling AJAX request for showing create product display form.
*/
function _commerce_apd_product_display_form($form, $form_state) {
// Return the product display section only.
return $form['product_display'];
}Functions
|
Name |
Description |
|---|---|
| commerce_apd_entity_update | Implements hook_entity_update(). |
| commerce_apd_form_commerce_product_ui_product_delete_form_alter | Implements hook_form_alter(). |
| commerce_apd_form_commerce_product_ui_product_form_alter | Implements hook_form_alter(). Alter the product creation form to add a new option to automatically create product display. |
| commerce_apd_menu | Implements hook_menu(). |
| commerce_apd_permission | Implements hook_permission(). Add permission to configure auto product display. |
| commerce_apd_product_form_reference_submit | Handle the form submission process. Product display will be created here. |
| _commerce_apd_delete_referencing_node | Form submission handler for deleting product display. |
| _commerce_apd_get_content_type | Get default product display content type for product. |
| _commerce_apd_get_nodes_referencing | Get the entities that has reference to a product. |
| _commerce_apd_get_product_field | Get one field from content type which type is product reference. |
| _commerce_apd_get_product_reference_detail | Get the detail information of node that has reference to a product. |
| _commerce_apd_get_product_reference_fields | Get the field name in product display that has reference to product. |
| _commerce_apd_product_display_form | Function for handling AJAX request for showing create product display form. |