commerce-8.x-2.8/modules/product/commerce_product.module
modules/product/commerce_product.module
<?php /** * @file * Defines the Product entity and associated features. */ use Drupal\entity\BundleFieldDefinition; use Drupal\commerce_product\Entity\ProductTypeInterface; use Drupal\Core\Cache\Cache; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\Display\EntityFormDisplayInterface; use Drupal\Core\Render\Element; /** * Implements hook_config_translation_info_alter(). */ function commerce_product_config_translation_info_alter(&$info) { $info['commerce_product_attribute']['class'] = '\Drupal\commerce_product\ConfigTranslation\ProductAttributeMapper'; } /** * Implements hook_ENTITY_TYPE_update(). */ function commerce_product_entity_form_display_update(EntityFormDisplayInterface $form_display) { // Reset the cached attribute field map when the 'default' product variation // form mode is updated, since the map ordering is based on it. if ($form_display->getTargetEntityTypeId() == 'commerce_product_variation' && $form_display->getMode() == 'default') { $attribute_field_manager = \Drupal::service('commerce_product.attribute_field_manager'); $attribute_field_manager->clearCaches(); } } /** * Implements hook_ENTITY_TYPE_update(). */ function commerce_product_entity_view_display_update(EntityInterface $entity) { // The product view uses the variation view and needs to be cleared, which doesn't // happen automatically because we're editing the variation, not the product. if (substr($entity->getConfigTarget(), 0, 27) === 'commerce_product_variation.') { Cache::invalidateTags(['commerce_product_view']); } } /** * Implements hook_theme_registry_alter(). */ function commerce_product_theme_registry_alter(&$theme_registry) { // The preprocess function must run after quickedit_preprocess_field(). $theme_registry['field']['preprocess functions'][] = 'commerce_product_remove_quickedit'; } /** * Turn off Quick Edit for injected variation fields, to avoid warnings. */ function commerce_product_remove_quickedit(&$variables) { $entity_type_id = $variables['element']['#entity_type']; if ($entity_type_id != 'commerce_product_variation' || empty($variables['element']['#ajax_replace_class'])) { return; } if (isset($variables['attributes']['data-quickedit-field-id'])) { unset($variables['attributes']['data-quickedit-field-id']); $context_key = array_search('user.permissions', $variables['#cache']['contexts']); unset($variables['#cache']['contexts'][$context_key]); } } /** * Implements hook_theme(). */ function commerce_product_theme() { return [ 'commerce_product_form' => [ 'render element' => 'form', ], 'commerce_product' => [ 'render element' => 'elements', ], 'commerce_product_variation' => [ 'render element' => 'elements', ], 'commerce_product_attribute_value' => [ 'render element' => 'elements', ], ]; } /** * Implements hook_theme_suggestions_commerce_product(). */ function commerce_product_theme_suggestions_commerce_product(array $variables) { return _commerce_entity_theme_suggestions('commerce_product', $variables); } /** * Implements hook_theme_suggestions_commerce_product_variation(). */ function commerce_product_theme_suggestions_commerce_product_variation(array $variables) { return _commerce_entity_theme_suggestions('commerce_product_variation', $variables); } /** * Implements hook_theme_suggestions_commerce_product_commerce_product_attribute_value(). */ function commerce_product_theme_suggestions_commerce_product_attribute_value(array $variables) { return _commerce_entity_theme_suggestions('commerce_product_attribute_value', $variables); } /** * Prepares variables for product templates. * * Default template: commerce-product.html.twig. * * @param array $variables * An associative array containing: * - elements: An associative array containing rendered fields. * - attributes: HTML attributes for the containing element. */ function template_preprocess_commerce_product(array &$variables) { /** @var Drupal\commerce_product\Entity\ProductInterface $product */ $product = $variables['elements']['#commerce_product']; $variables['product_entity'] = $product; $variables['product_url'] = $product->isNew() ? '' : $product->toUrl(); $variables['product'] = []; foreach (Element::children($variables['elements']) as $key) { $variables['product'][$key] = $variables['elements'][$key]; } } /** * Prepares variables for product variation templates. * * Default template: commerce-product-variation.html.twig. * * @param array $variables * An associative array containing: * - elements: An associative array containing rendered fields. * - attributes: HTML attributes for the containing element. */ function template_preprocess_commerce_product_variation(array &$variables) { /** @var Drupal\commerce_product\Entity\ProductVariationInterface $product_variation */ $product_variation = $variables['elements']['#commerce_product_variation']; $product = $product_variation->getProduct(); $variables['product_variation_entity'] = $product_variation; $variables['product_url'] = ''; if ($product && !$product->isNew()) { $variables['product_url'] = $product->toUrl(); } $variables['product_variation'] = []; foreach (Element::children($variables['elements']) as $key) { $variables['product_variation'][$key] = $variables['elements'][$key]; } } /** * Prepares variables for product attribute value templates. * * Default template: commerce-product-attribute-value.html.twig. * * @param array $variables * An associative array containing: * - elements: An associative array containing rendered fields. * - attributes: HTML attributes for the containing element. */ function template_preprocess_commerce_product_attribute_value(array &$variables) { /** @var Drupal\commerce_product\Entity\ProductAttributeValueInterface $product */ $attribute_value = $variables['elements']['#commerce_product_attribute_value']; $variables['product_attribute_value_entity'] = $attribute_value; $variables['product_attribute_value'] = []; foreach (Element::children($variables['elements']) as $key) { $variables['product_attribute_value'][$key] = $variables['elements'][$key]; } } /** * Adds the default stores field to a product. * * A product can belong to multiple stores. * Store id can't be a base field because the Views integration is broken. * Instead, it is created as a configurable field for each order type. * * @param \Drupal\commerce_product\Entity\ProductTypeInterface $product_type * The product type. */ function commerce_product_add_stores_field(ProductTypeInterface $product_type) { $field_definition = BundleFieldDefinition::create('entity_reference') ->setTargetEntityTypeId('commerce_product') ->setTargetBundle($product_type->id()) ->setName('stores') ->setLabel('Stores') ->setCardinality(BundleFieldDefinition::CARDINALITY_UNLIMITED) ->setRequired(TRUE) ->setSetting('target_type', 'commerce_store') ->setSetting('handler', 'default') ->setDisplayOptions('form', [ 'type' => 'commerce_entity_select', 'weight' => -10, ]); $configurable_field_manager = \Drupal::service('commerce.configurable_field_manager'); $configurable_field_manager->createField($field_definition); } /** * Adds the default body field to a product type. * * @param \Drupal\commerce_product\Entity\ProductTypeInterface $product_type * The product type. * @param string $label * (optional) The label for the body instance. Defaults to 'Body'. */ function commerce_product_add_body_field(ProductTypeInterface $product_type, $label = 'Body') { $field_definition = BundleFieldDefinition::create('text_with_summary') ->setTargetEntityTypeId('commerce_product') ->setTargetBundle($product_type->id()) ->setName('body') ->setLabel($label) ->setTranslatable(TRUE) ->setSetting('display_summary', FALSE) ->setDisplayOptions('form', [ 'type' => 'text_textarea_with_summary', 'weight' => 1, ]) ->setDisplayOptions('view', [ 'label' => 'hidden', 'type' => 'text_default', ]); $configurable_field_manager = \Drupal::service('commerce.configurable_field_manager'); $configurable_field_manager->createField($field_definition, FALSE); } /** * Adds the default variations field to a product type. * * Variations can't be a base field because the Views integration is broken. * Instead, it is created as a configurable field for each product type. * * @param \Drupal\commerce_product\Entity\ProductTypeInterface $product_type * The product type. */ function commerce_product_add_variations_field(ProductTypeInterface $product_type) { $field_definition = BundleFieldDefinition::create('entity_reference') ->setTargetEntityTypeId('commerce_product') ->setTargetBundle($product_type->id()) ->setName('variations') ->setLabel('Variations') ->setCardinality(BundleFieldDefinition::CARDINALITY_UNLIMITED) ->setRequired(TRUE) ->setSetting('target_type', 'commerce_product_variation') ->setSetting('handler', 'default') ->setSetting('handler_settings', [ 'target_bundles' => [ $product_type->getVariationTypeId(), ], ]) ->setDisplayOptions('form', [ 'type' => 'inline_entity_form_complex', 'weight' => 10, 'settings' => [ 'allow_duplicate' => TRUE, 'override_labels' => TRUE, 'label_singular' => 'variation', 'label_plural' => 'variations', ], ]) ->setDisplayOptions('view', [ 'type' => 'commerce_add_to_cart', 'weight' => 10, ]); $configurable_field_manager = \Drupal::service('commerce.configurable_field_manager'); $configurable_field_manager->createField($field_definition); } /** * Implements hook_field_widget_form_alter(). */ function commerce_product_field_widget_form_alter(&$element, FormStateInterface $form_state, $context) { /** @var \Drupal\Core\Field\FieldDefinitionInterface $field_definition */ $field_definition = $context['items']->getFieldDefinition(); $field_name = $field_definition->getName(); $entity_type = $field_definition->getTargetEntityTypeId(); $widget_name = $context['widget']->getPluginId(); $required = $field_definition->isRequired(); if ($field_name == 'path' && $entity_type == 'commerce_product' && $widget_name == 'path') { $element['alias']['#description'] = t('The alternative URL for this product. Use a relative path. For example, "/my-product".'); } elseif ($field_name == 'title' && $entity_type == 'commerce_product_variation' && !$required) { // The title field is optional only when its value is automatically // generated, in which case the widget needs to be hidden. $element['#access'] = FALSE; } } /** * Implements hook_form_FORM_ID_alter() for 'entity_form_display_edit_form'. * * Don't allow referencing existing variations, since a variation must * always belong to a single product only. */ function commerce_product_form_entity_form_display_edit_form_alter(array &$form, FormStateInterface $form_state) { if ($form['#entity_type'] != 'commerce_product') { return; } if (isset($form['fields']['variations']['plugin']['settings_edit_form']['settings'])) { $settings = &$form['fields']['variations']['plugin']['settings_edit_form']['settings']; if (isset($settings['allow_existing'])) { $settings['allow_existing']['#access'] = FALSE; $settings['match_operator']['#access'] = FALSE; } } }