This example assumes you only have one order type and one order item type, if you have more than one of these then you will need to check for the product you are dealing with to determine whether an upload field is required or not during the checkout.
Step 1. Create a file field on the order item type
Go to -> Commerce > Configuration > Orders > Order item types and then manage fields on your order item type and add a File field, this example I will call this field 'field_file_upload'.
Step 2. Create a custom module
For this example the module name is "commerce_custom_pane". There are only 2 files in the module -
1. commerce_custom_pane/commerce_custom_pane.info.yml
2. commerce_custom_pane/src/Commerce/CheckoutPane/CustomPaneWithUploadField.php
commerce_custom_pane
commerce_custom_pane.info.yml
/ src
/ Commerce
/ CheckoutPane
CustomPaneWithUploadField.php
Step 2a. First we create the info.yml module file to tell Drupal about our module and its dependencies.
# commerce_custom_pane.info.yml
name: Commerce custom pane
description: A custom pane with an upload field
package: Custom
type: module
core: '8.x'
dependencies: - drupal:commerce
Step 2b. Now we create the CustomPaneWithUploadField.php file.
Commerce checkout panes are annotation-based plugins, so we start by placing a @CommerceCheckoutPane
annotation right before our class definition. Also, the buildPaneForm()
method is required, so we'll add that in as well. The submitPaneForm() is called when the user submits the pane.
You should include an id and a label also. It is usually best practice to prefix your id with the name of your module, in this instance I have used 'commerce_custom_pane_file_upload', as I may later add more custom panes which I would name something like 'commerce_custom_pane_custom_message'.
<?php
namespace Drupal\commerce_custom_pane\Plugin\Commerce\CheckoutPane;
use Drupal\commerce_checkout\Plugin\Commerce\CheckoutPane\CheckoutPaneBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\file\Entity\File;
/**
* Provides a pane to upload images for projects.
*
* @CommerceCheckoutPane(
* id = "commerce_custom_pane_file_upload",
* label = @Translation("File Upload Pane"),
* )
*/
class CustomPaneWithUploadField extends CheckoutPaneBase {
/**
* {@inheritdoc}
*/
public function buildPaneForm(array $pane_form, FormStateInterface $form_state, array &$complete_form) {
// Get all items in the order and loop through them adding an upload field for eacg item
foreach ($this->order->getItems() as $item) {
$form['file_upload_'. $item->id()] = [
'#type' => 'managed_file',
'#title' => $this->t('Upload file'),
'#upload_location' => 'private://client_uploads', // Can also use 'public://'
'#required' => TRUE,
'#upload_validators' => [
'file_validate_extensions' => ['zip'], // Limit to any file extension(s) here
],
];
}
return $form;
}
/**
* {@inheritdoc}
*/
public function submitPaneForm(array &$pane_form, FormStateInterface $form_state, array &$complete_form) {
// Get the pane values
$pane = $form_state->getValue('commerce_custom_pane_file_upload'); // The id we annotated earlier
// Loop through each item on the order
foreach ($this->order->getItems() as $item) {
// Get the uploaded file
$fid = $pane['file_upload_'.$item->id()][0];
// Make the file managed
$file = File::load($fid);
$file->setPermanent();
$file->save();
// Add the file id to the file reference field on the order item
$item->set('field_file_upload', $file->id());
$item->save();
}
}
}
Step 3. Install your module and enable your custom pane
Go to Extend in the menu and install your custom module.
Next go to Commerce > Configuration > Orders > Checkout flow and edit your checkout flow, your new pane should be in the disabled section, simply drag into the checkout stage which is appropriate and click save.
Great, your pane should now appear during checkout.
You can check that your file has been added to the order item after your have completed a order by going to your order Commerce > Order then clicking edit on your order item and then looking at the order items.
Now click edit on one of your order items and your file should be present in a reference field.