Force Search API To Re-index affected Commerce Entities/Nodes after "Discount" manipulations

Last updated on 25/10/2016
/**
 * Implements hook_commerce_discount_insert().
 *
 * Re-index related Product-Nodes.
 */
function MY_MODULE_commerce_discount_insert($entity) {
  MY_MODULE_discount_update_search_index($entity);
}
 
/**
 * Implements hook_commerce_discount_update().
 *
 * Re-index related Product-Nodes.
 */
function MY_MODULE_commerce_discount_update($entity) {
  MY_MODULE_discount_update_search_index($entity);
}
 
/**
 * Implements hook_commerce_discount_delete().
 *
 * Re-index related Product-Nodes.
 */
function MY_MODULE_commerce_discount_delete($entity) {
  MY_MODULE_discount_update_search_index($entity);
}
 
/**
 * Get and re-index related Product-Nids of the Discount.
 *
 * @param $entity
 *
 * @see: commerce_product_contains_products_build
 *       hook_inline_conditions_build_alter
 */
function MY_MODULE_discount_update_search_index($entity) {
  $nids = array();
 
  // Get related Nids of the current Discount.
  $wrapper = entity_metadata_wrapper('commerce_discount', $entity);
  $line_items = $wrapper->inline_conditions->value();
  $nids = MY_MODULE_discount_get_related_discount_nids($line_items);
 
  // Check for deleted values.
  if (!empty($entity->original)) {
    $wrapper_old = entity_metadata_wrapper('commerce_discount', $entity->original);
    $line_items = $wrapper_old->inline_conditions->value();
    $old_nids = MY_MODULE_discount_get_related_discount_nids($line_items);
    if (!empty($old_nids)) {
      $nids = array_unique(array_merge($nids, $old_nids));
    }
  }
 
  // Immediately Re-index the Nodes.
  MY_MODULE_reindex_nodes($nids);
}
 
/**
 * Get related Nids by Inline conditions.
 *
 * @param $inline_conditions
 * @return array
 */
function MY_MODULE_discount_get_related_discount_nids($inline_conditions) {
  $nids = array();
 
  // Loop through all the inline condition and get the Node IDs.
  foreach ($inline_conditions as $condition) {
    // Field load is not fired here for some reason.
    if (is_string($condition['condition_settings'])) {
      $condition['condition_settings'] = unserialize($condition['condition_settings']);
    }
 
    // Detect by Discount type.
    switch ($condition['condition_name']) {
      // By direct product reference.
      case 'commerce_product_contains_products':
        $entity_ids = array();
        foreach ($condition['condition_settings']['sku'] as $delta) {
          $entity_ids[] = reset($delta);
        }
 
        // Get the referenced Node of the product.
        $query = db_select('field_data_field_product', 'fp')
          ->fields('fp', array('entity_id'))
          ->condition('fp.deleted', 1, '<>')
          ->condition('fp.field_product_product_id', $entity_ids, 'IN');
        $p_nids = $query->execute()->fetchCol();
        $nids = array_merge($nids, $p_nids);
        break;
 
      // By taxonomy Term.
      case 'commerce_product_has_specified_terms':
        $term_ids = array();
        foreach ($condition['condition_settings']['terms'] as $tid) {
          $term_ids[] = $tid['target_id'];
        }
 
        // Get all the "taxonomy_term_reference" fields.
        $term_reference_fields = field_read_fields(array('type' => 'taxonomy_term_reference'));
        $product_bundles = array('product_type');
 
        foreach ($term_reference_fields as $field) {
          $field_table = 'field_data_' . $field['field_name'];
          $field_value_column = $field['field_name'] . '_tid';
 
          // Get the referenced Node of the product linked to the Term.
          try {
            $query = db_select('field_data_field_product', 'fp');
            $query->innerJoin($field_table, 'ft', 'ft.entity_id=fp.field_product_product_id');
            $query->fields('fp', array('entity_id'))
              ->condition('fp.deleted', 1, '<>')
              ->condition('ft.deleted', 1, '<>')
              ->condition('ft.entity_type', 'commerce_product')
              ->condition('ft.bundle', $product_bundles, 'IN')
              ->condition("ft.$field_value_column", $term_ids, 'IN');
            $t_nids = $query->execute()->fetchCol();
 
            if (!empty($t_nids)) {
              $nids = array_merge($nids, $t_nids);
            }
          } catch (\Exception $e) {
            // Log.
          }
        }
 
        break;
    }
  }
 
  return array_unique($nids);
}
 
/**
 * Helper function.
 *
 * Force node Search API re-indexing.
 *
 * @param array $nids
 */
function MY_MODULE_reindex_nodes($nids = array()) {
 
  if (!is_array($nids)) {
    return;
  }
 
  // Clear the field cache first.
  foreach ($nids as $nid) {
    cache_clear_all('field:node:' . $nid, 'cache_field');
  }
 
  // Reindex the node.
  search_api_track_item_change('node', $nids);
}