Add videos to products programatically

I ended up doing it with the risky inserts directly into the tables.

the tables involved are (in this order)

  • catalog_product_entity_media_gallery
  • catalog_product_entity_media_gallery_value
  • catalog_product_entity_media_gallery_value_to_entity
  • catalog_product_entity_media_gallery_value_video

Pre-explanations: This should happen inside one class.
This class has these members that are added via constructor (di will take care of instantiating them)

// \Magento\Framework\App\ResourceConnection
private $resourceConnection;
// \Magento\Catalog\Api\ProductAttributeRepositoryInterface
private $attributeRepository;

Let's take the tables 1 by 1:

catalog_product_entity_media_gallery

$mediaAttributeId = $this->attributeRepository->get('media_gallery')->getAttributeId();
$image = 'someImage.jpg'; //This is the preview image of the video. the image needs to exist in `/media/catalog/product/`. I'm not going to cover how you add it there
$table = $this->resourceConnection->getTableName('catalog_product_entity_media_gallery');
$data = [
    'attribute_id' => $mediaAttributeId,
    'value' => $image,
    'media_type' => \Magento\ProductVideo\Model\Product\Attribute\Media\ExternalVideoEntryConverter::MEDIA_TYPE_CODE,
    'disabled' => 0
];
$this->resourceConnection->getConnection()->insert($table, $data);

Now remember the last added increment id because it is needed in the later inserts.

$valueId = $this->resourceConnection->getConnection()->lastInsertId();

catalog_product_entity_media_gallery_value

$storeId = the store id for witch the video is available. Use 0 for global;
$productId = the id of the product for which you add the video
$table = $this->resourceConnection->getTableName('catalog_product_entity_media_gallery_value');
$data = [
    'value_id' => $valueId, //the increment id from above
    'store_id' => $storeId,
    'entity_id' => $productId,
    'position' => 1, //any number goes here
    'disabled' => 0
];
$this->resourceConnection->getConnection()->insert($table, $data);

catalog_product_entity_media_gallery_value_to_entity

$table = $this->resourceConnection->getTableName('catalog_product_entity_media_gallery_value_to_entity');
$data = [
    'value_id' => $valueId, // increment id from above
    'entity_id' => $productId, // product id from the step above
];
$this->resourceConnection->getConnection()->insert($table, $data);

catalog_product_entity_media_gallery_value_video

$videoUrl = 'url of the video from youtube or vimeo';  
$table = $this->resourceConnection->getTableName('catalog_product_entity_media_gallery_value_video');
$data = [
    'value_id' => $valueId, //saved increment id from above
    'store_id' => $storeId, // Store id from the steps above
    'provider' => '',
    'url' => $videoUrl,
    'title' => "Video title", //this is mandatory
    'description' => 'Video description', //this can be empty
    'metadata' => '' //I have no idea what this does
];
$this->resourceConnection->getConnection()->insert($table, $data);

That's it. Some reindexing may be needed.


I don't like to overrule Marius' opinion because the answer he's given is really excellent & actually works! However, if you or your company isn't so inclined to run direct SQL queries like that I'd suggest something more like this, using Magento 2's API:

$data = [
    'entry' => [
        'id' => null,
        'media_type' => 'external-video',
        'label' => null,
        'position' => $IntToRepresentWhereInGalleryToPlaceIt,
        'types' => ['image', 'small-image', 'thumbnail'],
        'disabled' => false,
        'content' => [
            'base64_encoded_data' => base64_encode(file_get_contents($thumbnailimageUrl)),
            'type' => 'image/jpeg',
            'name' => '0.jpg'
        ],
        'extension_attributes' => [
            'video_content' => [
                'media_type' => 'external-video',
                'video_provider' => 'youtube',
                'video_url' => $videoURL,
                'video_title' => $videoTitle,
                'video_description' => $videoDescription,
                'video_metadata' => null //Don't know what this is for, add a value if you like
            ]
        ]
    ]
];
$ch = curl_init("http://YOURURL.COM/index.php/rest/V1/products/" . $YourProductSku . "/media");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: application/json", "Authorization: Bearer " . $MagentoIntegrationsAccessToken));
$response = curl_exec($ch);