Skip to content

Instantly share code, notes, and snippets.

@satishgumudavelli
Last active December 23, 2021 08:45
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save satishgumudavelli/f82d5c7b5bd58b4d70d76f75898ec6d1 to your computer and use it in GitHub Desktop.
Save satishgumudavelli/f82d5c7b5bd58b4d70d76f75898ec6d1 to your computer and use it in GitHub Desktop.
magento 2 add video to product programmatically
<?php
namespace Yourcompany\Yourmodule\Controller\Test;
use Magento\Framework\Api\Data\VideoContentInterface;
use Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface;
use Magento\Framework\App\Action\Context;
use Magento\ProductVideo\Model\Product\Attribute\Media\ExternalVideoEntryConverter;
use Magento\Store\Model\Store;
use Magento\Framework\Exception\InputException;
use Magento\Framework\Exception\StateException;
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Api\Data\ProductInterfaceFactory;
class Test extends \Magento\Framework\App\Action\Action
{
private $mimeTypes = [
'png' => 'image/png',
'jpe' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'jpg' => 'image/jpeg',
'gif' => 'image/gif',
'bmp' => 'image/bmp',
'ico' => 'image/vnd.microsoft.icon',
'tiff' => 'image/tiff',
'tif' => 'image/tiff',
'svg' => 'image/svg+xml',
'svgz' => 'image/svg+xml',
];
private $defaultMimeType = 'application/octet-stream';
private $productFactory;
private $externalVideoEntryConverter;
private $productRepository;
private $contentValidator;
private $curl;
private $imageContentFactory;
/**
* @param Context $context
* @param ProductInterfaceFactory $productFactory
* @param ExternalVideoEntryConverter $externalVideoEntryConverter
* @param \Magento\Catalog\Api\ProductRepositoryInterface $productRepository
* @param \Magento\Framework\Api\ImageContentValidatorInterface $contentValidator
* @param \Magento\Framework\HTTP\Adapter\Curl $curl
* @param \Magento\Framework\Api\Data\ImageContentInterfaceFactory $imageContentFactory
*/
public function __construct(
Context $context,
ProductInterfaceFactory $productFactory,
ExternalVideoEntryConverter $externalVideoEntryConverter,
\Magento\Catalog\Api\ProductRepositoryInterface $productRepository,
\Magento\Framework\Api\ImageContentValidatorInterface $contentValidator,
\Magento\Framework\HTTP\Adapter\Curl $curl,
\Magento\Framework\Api\Data\ImageContentInterfaceFactory $imageContentFactory
) {
parent::__construct($context);
$this->productFactory = $productFactory;
$this->productRepository = $productRepository;
$this->externalVideoEntryConverter = $externalVideoEntryConverter;
$this->contentValidator = $contentValidator;
$this->curl = $curl;
$this->imageContentFactory = $imageContentFactory;
}
public function execute()
{
$sampleProductId = 1;
/** @var ProductInterface $product */
$sampleProduct = $this->productFactory->create()->load($sampleProductId);
// NB! Unless you have a multi store setup and need the video only for specific store,
// this has to be done or the video entry might get wrong store id (will only be visible on one store).
// See \Magento\ProductVideo\Model\Plugin\Catalog\Product\Gallery\CreateHandler function afterExecute().
// However this is a hack and better way should be implemented to make sure video will get store id before save is called.
$sampleProduct->setStoreId(Store::DEFAULT_STORE_ID);
// Sample youtube video
$videoUrl = "https://www.youtube.com/watch?v=sGF6bOi1NfA";
$videoId = "sGF6bOi1NfA";
$videoLabel = "Cute pandas playing on the slide";
$videoDescription = "What's more entertaining than watching a panda playing on a slide?";
$videoProvider = "youtube";
$thumbnailUrl = "https://i.ytimg.com/vi/sGF6bOi1NfA/hqdefault.jpg";
// Check if video already exists, and if not, create a new one
if(!$this->isExistingVideo($sampleProduct, $videoUrl)){
$videoEntry = $this->buildVideoEntry($sampleProduct, $videoUrl, $videoId, $videoLabel, $videoDescription, $videoProvider, $thumbnailUrl);
$this->addVideoForProduct($sampleProduct, $videoEntry);
}else{
die('Video already exists!');
}
}
/**
* @param ProductInterface $sampleProduct
* @param string $videoUrl
* @param string $videoId
* @param string $videoLabel
* @param string $videoDescription
* @param string $videoProvider
* @param string $thumbnailUrl
*
* @return ProductAttributeMediaGalleryEntryInterface
* @throws \Magento\Framework\Exception\LocalizedException
*/
private function buildVideoEntry($sampleProduct, $videoUrl, $videoId, $videoLabel, $videoDescription, $videoProvider, $thumbnailUrl)
{
// Build thumbnail image data for sample video
$parts = explode('/', $thumbnailUrl);
$thumbnailImageName = end($parts);
$thumbnailImage = $this->getRemoteImage($thumbnailUrl); // Fetch image from server
/** @var \Magento\Framework\Api\Data\ImageContentInterface $imageContent */
$imageContent = $this->imageContentFactory->create();
$imageContent->setName($videoProvider . '_' . $videoId)
->setType($this->getMimeContentType($thumbnailImageName))
->setBase64EncodedData(base64_encode($thumbnailImage));
// Build video data array for video entry converter
$generalMediaEntryData = [
ProductAttributeMediaGalleryEntryInterface::LABEL => $videoLabel,
ProductAttributeMediaGalleryEntryInterface::TYPES => ['thumbnail', 'image', 'small_image'], // Optional, depends on what is wanted
ProductAttributeMediaGalleryEntryInterface::CONTENT => $imageContent,
ProductAttributeMediaGalleryEntryInterface::DISABLED => false
];
$videoData = array_merge($generalMediaEntryData, [
VideoContentInterface::TITLE => $videoLabel,
VideoContentInterface::DESCRIPTION => $videoDescription,
VideoContentInterface::PROVIDER => $videoProvider,
VideoContentInterface::METADATA => null,
VideoContentInterface::URL => $videoUrl,
VideoContentInterface::TYPE => ExternalVideoEntryConverter::MEDIA_TYPE_CODE,
]);
// Convert video data array to video entry
return $this->externalVideoEntryConverter->convertTo($sampleProduct, $videoData);
}
/**
* Copy of \Magento\Catalog\Api\ProductAttributeMediaGalleryManagementInterface create() function.
* Only difference is that we don't reload product with sku, and thus we don't lose store id 0
* that we set earlier for sample product.
*
* @param ProductInterface $sampleProduct
* @param ProductAttributeMediaGalleryEntryInterface $videoEntry
*
* @return int|null
* @throws InputException
* @throws StateException
*/
private function addVideoForProduct($sampleProduct, $videoEntry)
{
/** @var $entry ProductAttributeMediaGalleryEntryInterface */
$entryContent = $videoEntry->getContent();
if (!$this->contentValidator->isValid($entryContent)) {
throw new InputException(__('The image content is not valid.'));
}
$existingMediaGalleryEntries = $sampleProduct->getMediaGalleryEntries();
$existingEntryIds = [];
if ($existingMediaGalleryEntries == null) {
$existingMediaGalleryEntries = [$videoEntry];
} else {
foreach ($existingMediaGalleryEntries as $existingEntries) {
$existingEntryIds[$existingEntries->getId()] = $existingEntries->getId();
}
$existingMediaGalleryEntries[] = $videoEntry;
}
$sampleProduct->setMediaGalleryEntries($existingMediaGalleryEntries);
try {
$product = $this->productRepository->save($sampleProduct);
} catch (InputException $inputException) {
throw $inputException;
} catch (\Exception $e) {
throw new StateException(__('Cannot save product.'));
}
foreach ($product->getMediaGalleryEntries() as $entry) {
if (!isset($existingEntryIds[$entry->getId()])) {
return $entry->getId();
}
}
throw new StateException(__('Failed to save new media gallery entry.'));
}
/**
* @param ProductInterface $sampleProduct
* @param string $url
*
* @return bool
*/
private function isExistingVideo($sampleProduct, $url)
{
if ($mediaEntries = $sampleProduct->getMediaGalleryEntries()) {
foreach($mediaEntries as $entryKey => $mediaEntry) {
if($mediaEntry->getMediaType() == ExternalVideoEntryConverter::MEDIA_TYPE_CODE) {
$videoUrl = $mediaEntry->getExtensionAttributes()->getVideoContent()->getVideoUrl();
if($videoUrl == $url){
return true;
}
}
}
}
return false;
}
/**
* @param string $fileUrl
*
* @return string
* @throws \Magento\Framework\Exception\LocalizedException
*/
private function getRemoteImage($fileUrl)
{
$this->curl->setConfig(['header' => false]);
$this->curl->write('GET', $fileUrl);
$image = $this->curl->read();
if (empty($image)) {
throw new \Magento\Framework\Exception\LocalizedException(
__('Could not get preview image information. Please check your connection and try again.')
);
}
return $image;
}
/**
* @param string $filename
*
* @return string
*/
private function getMimeContentType($filename)
{
$parts = explode('.',$filename);
$ext = strtolower(array_pop($parts));
if (array_key_exists($ext, $this->mimeTypes)) {
return $this->mimeTypes[$ext];
} else {
return $this->defaultMimeType;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment