Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Here is some code for adding the rules based on number of products of specific product-type:
/**
* Implements hook_rules_condition_info().
*/
function foo_webstore_rules_condition_info() {
return array(
'foo_webstore_rules_condition_ordered_num_line_items' => array(
'group' => t('Commerce'),
'callbacks' => array(
'execute' => 'foo_webstore_rules_condition_ordered_num_line_items',
),
'label' => t('User ordered number of line items'),
'parameter' => array(
'count_type' => array(
'type' => 'text',
'label' => t('Products to compare'),
'description' => t('Select which products should be taken into consideration.'),
'optional' => TRUE,
'default value' => '=',
'options list' => 'foo_webstore_rules_condition_ordered_num_line_items_count_types',
'restriction' => 'input',
),
'commerce_line_item' => array(
'type' => 'commerce_line_item',
'label' => t('Product')
),
'operator' => array(
'type' => 'text',
'label' => t('Operator'),
'description' => t('The comparison operator.'),
'optional' => TRUE,
'default value' => '=',
'options list' => 'commerce_numeric_comparison_operator_options_list',
'restriction' => 'input',
),
'value' => array(
'type' => 'text',
'label' => t('Value'),
'description' => t('Integer representing a value.'),
'default value' => '0',
),
),
'module' => 'foo_webstore',
),
);
}
/**
* Rules condition's select box items for "Products to compare".
*/
function foo_webstore_rules_condition_ordered_num_line_items_count_types() {
return array(
'any' => t('Count products of any type'),
'any|free' => t('Count free products of any type'),
'exact' => t('Count products of the same type'),
'exact|free' => t('Count free products of the same type'),
);
}
/**
* Rules action callback for "User ordered number of line items".
*/
function foo_webstore_rules_condition_ordered_num_line_items($count_type, $line_item, $operator, $value) {
$count_types = explode('|', $count_type);
$num_in_cart = 0;
$product_id = $line_item->data['context']['entity']['entity_id'];
$line_item_id = $line_item->line_item_id;
$product_id = reset($line_item->data['context']['product_ids']);
// Checking total number of products in the cart.
$cart_order = commerce_cart_order_load($GLOBALS['user']->uid);
foreach ($cart_order->commerce_line_items[LANGUAGE_NONE] as $item) {
$cart_line_item = commerce_line_item_load($item['line_item_id']);
$cart_product_id = reset($cart_line_item->data['context']['product_ids']);
$cart_product_price_free = $cart_line_item->commerce_total[LANGUAGE_NONE][0]['amount'] == 0;
if (in_array('any', $count_types) || (in_array('exact', $count_types) && $cart_product_id === $product_id)) {
if (!in_array('free', $count_types) || $cart_product_price_free) {
++$num_in_cart;
}
}
}
$num_bought = 0;
// Checking how many products of this is user already bought.
$data = db_query("
SELECT LI.line_item_id AS lid, LI.quantity, LI.data
FROM commerce_order O
LEFT JOIN commerce_line_item LI ON LI.order_id = O.order_id
WHERE O.`status` NOT IN ('selected', 'cart', 'canceled') AND O.uid = :uid
", array(
':uid' => $GLOBALS['user']->uid
))->fetchAll();
foreach ($data as $row) {
$commerce_data = unserialize ($row->data);
$bought_product_id = reset($commerce_data['context']['product_ids']);
// @TODO: Would be a good idea to check price in another way if we want code to be shareable.
$bought_product = commerce_product_load($bought_product_id);
$bought_product_price_free = $bought_product->commerce_price_eur[LANGUAGE_NONE][0]['amount'] == 0;
if (in_array('any', $count_types) || (in_array('exact', $count_types) && $bought_product_id === $product_id)) {
if (!in_array('free', $count_types) || $bought_product_price_free) {
++$num_bought;
}
}
}
// "1" is for current line item.
$num_total = $num_in_cart + $num_bought + 1;
switch ($operator) {
case '<': return $num_total < $value;
case '<=': return $num_total <= $value;
case '=': return $num_total == $value;
case '>=': return $num_total >= $value;
case '>': return $num_total > $value;
}
}
This could be combined with: #1267156-20: Create a "Remove single item from cart" action
Comments
Comment #1
kenorb CreditAttribution: kenorb commentedComment #2
kenorb CreditAttribution: kenorb commentedComment #3
brylie CreditAttribution: brylie commentedI am trying to build a cart rule based on counting the number of items in the cart. Has this functionality been merged into Commerce core?
Comment #4
nvahalik CreditAttribution: nvahalik at Centarro commented@brylie, go check out https://www.drupal.org/node/2514330.
Comment #5
kentr CreditAttribution: kentr as a volunteer commentedHere's another solution for this: http://www.bonify.io/blog/2014/09/limit-quantity-when-adding-product-cart
@brylie, if you still need a cart rule based on counting the number of items in the cart, that link might work for you.
Comment #6
emircanerkul CreditAttribution: emircanerkul at Vardot commentedThe link is no longer valid. Here it is: https://web.archive.org/web/20160925091846/http://www.bonify.io:80/blog/...
Comment #7
emircanerkul CreditAttribution: emircanerkul at Vardot commentedBTW, I hate whole d7 answers (All should be destroyed). It is just a waste of time and probably misleads the AI-generated answers too.
https://www.drupal.org/forum/support/module-development-and-code-questio... Here more a clearer and fresh answer.