├── Model
├── Logger.php
├── ProductVideo.php
├── MediaLibraryMap.php
├── ProductSpinsetMap.php
├── ProductGalleryApiQueue.php
├── ResourceModel
│ ├── ProductVideo.php
│ ├── Synchronisation.php
│ ├── Transformation.php
│ ├── MediaLibraryMap.php
│ ├── ProductSpinsetMap.php
│ ├── ProductGalleryApiQueue.php
│ ├── ProductVideo
│ │ └── Collection.php
│ ├── MediaLibraryMap
│ │ └── Collection.php
│ ├── ProductSpinsetMap
│ │ └── Collection.php
│ ├── ProductGalleryApiQueue
│ │ └── Collection.php
│ ├── Transformation
│ │ └── Collection.php
│ └── Synchronisation
│ │ └── Collection.php
├── ProductImageFinder
│ ├── ImageFilter.php
│ ├── DeletedImageFilter.php
│ ├── NewImageFilter.php
│ └── ImageCreator.php
├── Logger
│ └── CloudinaryHandler.php
├── Template
│ └── Filter.php
├── Config
│ ├── Source
│ │ └── Dropdown
│ │ │ ├── Dpr.php
│ │ │ ├── Video
│ │ │ ├── VideoFormat.php
│ │ │ ├── SourceTypes.php
│ │ │ ├── Type.php
│ │ │ ├── StreamMode.php
│ │ │ ├── ABR
│ │ │ │ └── Comment.php
│ │ │ ├── Controls.php
│ │ │ ├── Autoplay.php
│ │ │ ├── StreamProtocol.php
│ │ │ ├── Autoplay
│ │ │ │ └── Comment.php
│ │ │ └── VideoQuality.php
│ │ │ ├── Lazyload
│ │ │ ├── Effect.php
│ │ │ └── Placeholder.php
│ │ │ ├── FreeTransformBehavior.php
│ │ │ ├── ProductGallery
│ │ │ ├── ZoomTrigger.php
│ │ │ ├── Transition.php
│ │ │ ├── ZoomType.php
│ │ │ ├── Navigation.php
│ │ │ ├── IndicatorsShape.php
│ │ │ ├── CarouselStyle.php
│ │ │ ├── ThumbnailsSelectedStyle.php
│ │ │ ├── CarouselLocation.php
│ │ │ ├── ZoomViewerPosition.php
│ │ │ ├── ThumbnailsMediaSymbolShape.php
│ │ │ ├── ThumbnailsNavigationShape.php
│ │ │ ├── ThumbnailsSelectedBorderPosition.php
│ │ │ └── AspectRatio.php
│ │ │ ├── CmsBlocks.php
│ │ │ ├── Gravity.php
│ │ │ └── Quality.php
│ └── Backend
│ │ └── ProductGalleryCustomFreeParams.php
├── Synchronisation.php
├── MigrationTask.php
├── Observer
│ ├── ProductGalleryChangeTemplate.php
│ ├── DeleteProductImage.php
│ ├── UploadProductImage.php
│ └── SaveProductTransform.php
├── Framework
│ └── File
│ │ └── Uploader.php
├── ProductImageFinder.php
└── AutoUploadMapping
│ └── AutoUploadConfiguration.php
├── view
├── base
│ └── web
│ │ ├── images
│ │ ├── colorpicker_indic.gif
│ │ ├── cloudinary_placeholder.jpg
│ │ ├── cloudinary_cloud_glyph_blue.png
│ │ ├── spinset_indic.svg
│ │ ├── cloudinary_cloud_glyph_white.svg
│ │ └── cloudinary_cloud_glyph_regular.svg
│ │ ├── js
│ │ ├── form
│ │ │ └── element
│ │ │ │ ├── file-uploader.js
│ │ │ │ └── image-uploader.js
│ │ ├── cloudinary-lazyload.js
│ │ └── jquery.lazyload.min.js
│ │ └── template
│ │ └── form
│ │ └── element
│ │ └── uploader
│ │ └── uploader.html
├── frontend
│ ├── templates
│ │ ├── product
│ │ │ ├── video
│ │ │ │ ├── script.phtml
│ │ │ │ └── settings.phtml
│ │ │ ├── old_image.phtml
│ │ │ ├── image.phtml
│ │ │ ├── old_image_with_borders.phtml
│ │ │ └── image_with_borders.phtml
│ │ ├── javascript.phtml
│ │ └── lazyload.phtml
│ ├── layout
│ │ ├── catalog_product_view.xml
│ │ └── default.xml
│ ├── requirejs-config.js
│ └── web
│ │ └── js
│ │ ├── cloudinary-product-gallery.js
│ │ └── swatch-renderer-mixin.js
└── adminhtml
│ ├── templates
│ ├── javascript.phtml
│ ├── cms
│ │ └── images.phtml
│ ├── lazyload.phtml
│ ├── config
│ │ ├── free.phtml
│ │ └── auto-upload-mapping-btn.phtml
│ └── browser
│ │ └── content.phtml
│ ├── layout
│ ├── adminhtml_system_config_edit.xml
│ ├── cms_block_edit.xml
│ ├── cms_page_edit.xml
│ ├── default.xml
│ └── cms_wysiwyg_images_index.xml
│ ├── ui_component
│ ├── pagebuilder_base_form_with_background_video.xml
│ ├── pagebuilder_video_form.xml
│ └── media_gallery_listing.xml
│ ├── web
│ ├── template
│ │ └── product
│ │ │ ├── free_transform_row.html
│ │ │ └── free_transform.html
│ └── js
│ │ ├── form
│ │ └── element
│ │ │ └── validator-rules-mixin.js
│ │ └── cloudinary-spinset-dialog.js
│ └── requirejs-config.js
├── Core
├── Exception
│ ├── InvalidCredentials.php
│ ├── ApiError.php
│ ├── FileExists.php
│ └── MigrationError.php
├── ImageInterface.php
├── Security
│ ├── EnvironmentVariable.php
│ ├── Key.php
│ ├── Secret.php
│ ├── ConsoleUrl.php
│ ├── ApiSignature.php
│ ├── SignedConsoleUrl.php
│ └── CloudinaryEnvironmentVariable.php
├── Image
│ ├── SynchronizationCheck.php
│ ├── Synchronizable.php
│ ├── Transformation
│ │ ├── Dpr.php
│ │ ├── Quality.php
│ │ ├── Gravity.php
│ │ ├── DefaultImage.php
│ │ ├── FetchFormat.php
│ │ ├── Freeform.php
│ │ ├── Crop.php
│ │ └── Dimensions.php
│ ├── LocalImage.php
│ └── ImageFactory.php
├── Migration
│ ├── SynchronizedMediaRepository.php
│ ├── Task.php
│ ├── Logger.php
│ └── Queue.php
├── FolderTranslator.php
├── UploadResponseValidator.php
├── ImageProvider.php
├── SynchroniseAssetsRepositoryInterface.php
├── Cloud.php
├── CredentialValidator.php
├── AutoUploadMapping
│ ├── AutoUploadConfigurationInterface.php
│ └── RequestProcessor.php
├── Credentials.php
├── ConfigurationInterface.php
├── ConfigurationBuilder.php
├── ValidateRemoteUrlRequest.php
├── UploadConfig.php
├── Image.php
└── UrlGenerator.php
├── registration.php
├── .gitignore
├── etc
├── adminhtml
│ ├── routes.xml
│ ├── events.xml
│ └── di.xml
├── module.xml
├── crontab.xml
├── cron_groups.xml
├── acl.xml
├── schema.graphqls
└── csp_whitelist.xml
├── marketplace.composer.json
├── Api
├── ResourcesManagementInterface.php
├── SynchronisationRepositoryInterface.php
└── ProductGalleryManagementInterface.php
├── Plugin
├── ExcludeFilesFromMinification.php
├── Cms
│ └── Block
│ │ ├── Block.php
│ │ └── Widget
│ │ └── Block.php
├── Catalog
│ └── Block
│ │ └── Category
│ │ └── View.php
├── Ui
│ └── Component
│ │ └── Form
│ │ └── Element
│ │ └── DataType
│ │ └── Media
│ │ └── Image.php
├── MediaConfig.php
├── FileRemover.php
└── Config
│ └── Block
│ └── System
│ └── Config
│ └── Form
│ └── Field
│ └── Image.php
├── composer.json
├── LICENSE.txt
├── Block
├── Scripts.php
├── Adminhtml
│ ├── System
│ │ └── Config
│ │ │ ├── ModuleVersion.php
│ │ │ ├── Form
│ │ │ └── Field
│ │ │ │ └── ColorPicker.php
│ │ │ └── AutoUploadMapping.php
│ ├── Form
│ │ └── Field
│ │ │ └── Free.php
│ └── Cms
│ │ └── Wysiwyg
│ │ └── Images
│ │ └── Content.php
└── Lazyload.php
├── README.md
├── Controller
└── Adminhtml
│ ├── PageBuilder
│ └── MediaGallery
│ │ └── Upload.php
│ └── Ajax
│ └── Free
│ └── Sample.php
├── Command
├── StopMigration.php
└── ProductGalleryApiQueueProcess.php
├── Ui
└── Component
│ └── Control
│ └── AddFromCloudinary.php
├── Helper
├── Reset.php
└── Product
│ └── Free.php
└── Cron
└── VideoDataImport.php
/Model/Logger.php:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/view/base/web/images/cloudinary_placeholder.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudinary/cloudinary_magento2/HEAD/view/base/web/images/cloudinary_placeholder.jpg
--------------------------------------------------------------------------------
/view/base/web/images/cloudinary_cloud_glyph_blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudinary/cloudinary_magento2/HEAD/view/base/web/images/cloudinary_cloud_glyph_blue.png
--------------------------------------------------------------------------------
/Core/Exception/InvalidCredentials.php:
--------------------------------------------------------------------------------
1 |
2 | isEnabled() && $cname = $block->getCname()): ?>
3 |
4 |
5 |
--------------------------------------------------------------------------------
/view/frontend/templates/javascript.phtml:
--------------------------------------------------------------------------------
1 |
2 | isEnabled() && $cname = $block->getCname()): ?>
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Core/Migration/SynchronizedMediaRepository.php:
--------------------------------------------------------------------------------
1 | _init(\Cloudinary\Cloudinary\Model\ResourceModel\ProductVideo::class);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Model/MediaLibraryMap.php:
--------------------------------------------------------------------------------
1 | _init(\Cloudinary\Cloudinary\Model\ResourceModel\MediaLibraryMap::class);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/view/adminhtml/templates/cms/images.phtml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
13 |
--------------------------------------------------------------------------------
/view/adminhtml/templates/lazyload.phtml:
--------------------------------------------------------------------------------
1 |
6 | isEnabledLazyload()) {
7 | return;
8 | } ?>
9 |
10 |
--------------------------------------------------------------------------------
/view/frontend/templates/lazyload.phtml:
--------------------------------------------------------------------------------
1 |
6 | isEnabledLazyload()) {
7 | return;
8 | } ?>
9 |
10 |
--------------------------------------------------------------------------------
/Model/ProductSpinsetMap.php:
--------------------------------------------------------------------------------
1 | _init(\Cloudinary\Cloudinary\Model\ResourceModel\ProductSpinsetMap::class);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Model/ProductGalleryApiQueue.php:
--------------------------------------------------------------------------------
1 | _init(\Cloudinary\Cloudinary\Model\ResourceModel\ProductGalleryApiQueue::class);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Core/Migration/Logger.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Model/ResourceModel/ProductVideo.php:
--------------------------------------------------------------------------------
1 | _init('cloudinary_synchronisation', 'cloudinary_synchronisation_id');
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/etc/adminhtml/routes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Model/ProductImageFinder/ImageFilter.php:
--------------------------------------------------------------------------------
1 | _init('cloudinary_transformation', 'image_name');
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Core/FolderTranslator.php:
--------------------------------------------------------------------------------
1 | _init('cloudinary_media_library_map', 'id');
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Model/ResourceModel/ProductSpinsetMap.php:
--------------------------------------------------------------------------------
1 | _init('cloudinary_product_spinset_map', 'id');
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Core/UploadResponseValidator.php:
--------------------------------------------------------------------------------
1 | key = (string)$key;
12 | }
13 |
14 | public static function fromString($aKey)
15 | {
16 | return new Key($aKey);
17 | }
18 |
19 | public function __toString()
20 | {
21 | return $this->key;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/marketplace.composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cloudinary/cloudinary",
3 | "description": "Cloudinary Magento 2 Integration.",
4 | "type": "magento2-module",
5 | "version": "1.18.0",
6 | "license": "MIT",
7 | "require": {
8 | "cloudinary/cloudinary_php": "^1.20.52"
9 | },
10 | "autoload": {
11 | "files": [
12 | "registration.php"
13 | ],
14 | "psr-4": {
15 | "Cloudinary\\Cloudinary\\": ""
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Model/ResourceModel/ProductGalleryApiQueue.php:
--------------------------------------------------------------------------------
1 | _init('cloudinary_product_gallery_api_queue', 'id');
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Core/ImageProvider.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Core/Cloud.php:
--------------------------------------------------------------------------------
1 | cloudName = (string)$cloudName;
12 | }
13 |
14 | public static function fromName($aCloudName)
15 | {
16 | return new Cloud($aCloudName);
17 | }
18 |
19 | public function __toString()
20 | {
21 | return $this->cloudName;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Core/Image/Transformation/Dpr.php:
--------------------------------------------------------------------------------
1 | value = $value;
12 | }
13 |
14 | public static function fromString($value)
15 | {
16 | return new Dpr($value);
17 | }
18 |
19 | public function __toString()
20 | {
21 | return $this->value;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Core/Security/Secret.php:
--------------------------------------------------------------------------------
1 | secret = (string)$secret;
12 | }
13 |
14 | public static function fromString($aSecret)
15 | {
16 | return new Secret($aSecret);
17 | }
18 |
19 | public function __toString()
20 | {
21 | return $this->secret;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Model/ProductImageFinder/NewImageFilter.php:
--------------------------------------------------------------------------------
1 | value = $value;
12 | }
13 |
14 | public static function fromString($value)
15 | {
16 | return new Quality($value);
17 | }
18 |
19 | public function __toString()
20 | {
21 | return $this->value;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Model/Template/Filter.php:
--------------------------------------------------------------------------------
1 | getParameters().
11 | *
12 | * @param string $value raw parameters
13 | * @return array
14 | */
15 | public function getParams($value)
16 | {
17 | return $this->getParameters($value);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Core/CredentialValidator.php:
--------------------------------------------------------------------------------
1 | validate();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Model/ResourceModel/ProductVideo/Collection.php:
--------------------------------------------------------------------------------
1 | _init(
13 | \Cloudinary\Cloudinary\Model\ProductVideo::class,
14 | \Cloudinary\Cloudinary\Model\ResourceModel\ProductVideo::class
15 | );
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/Dpr.php:
--------------------------------------------------------------------------------
1 | '1.0',
14 | 'label' => '1.0',
15 | ],
16 | [
17 | 'value' => '2.0',
18 | 'label' => '2.0',
19 | ],
20 | ];
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Model/ResourceModel/MediaLibraryMap/Collection.php:
--------------------------------------------------------------------------------
1 | _init(
13 | \Cloudinary\Cloudinary\Model\MediaLibraryMap::class,
14 | \Cloudinary\Cloudinary\Model\ResourceModel\MediaLibraryMap::class
15 | );
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Model/ResourceModel/ProductSpinsetMap/Collection.php:
--------------------------------------------------------------------------------
1 | _init(
13 | \Cloudinary\Cloudinary\Model\ProductSpinsetMap::class,
14 | \Cloudinary\Cloudinary\Model\ResourceModel\ProductSpinsetMap::class
15 | );
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Api/ResourcesManagementInterface.php:
--------------------------------------------------------------------------------
1 | 'none',
13 | 'label' => 'None',
14 | ],
15 | [
16 | 'value' => 'auto',
17 | 'label' => 'Auto',
18 | ],
19 | ];
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/Lazyload/Effect.php:
--------------------------------------------------------------------------------
1 | 'show',
14 | 'label' => 'Show',
15 | ],
16 | [
17 | 'value' => 'fadeIn',
18 | 'label' => 'Fade In',
19 | ],
20 | ];
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Core/Image/Transformation/Gravity.php:
--------------------------------------------------------------------------------
1 | value = $value;
12 | }
13 |
14 | public function __toString()
15 | {
16 | return $this->value;
17 | }
18 |
19 | public static function fromString($value)
20 | {
21 | return new Gravity($value);
22 | }
23 |
24 | public static function null()
25 | {
26 | return new Gravity(null);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Model/ResourceModel/ProductGalleryApiQueue/Collection.php:
--------------------------------------------------------------------------------
1 | _init(
13 | \Cloudinary\Cloudinary\Model\ProductGalleryApiQueue::class,
14 | \Cloudinary\Cloudinary\Model\ResourceModel\ProductGalleryApiQueue::class
15 | );
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Model/ResourceModel/Transformation/Collection.php:
--------------------------------------------------------------------------------
1 | _init(TransformationModel::class, TransformationResourceModel::class);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Core/Security/ConsoleUrl.php:
--------------------------------------------------------------------------------
1 | consoleUrl = self::CLOUDINARY_CONSOLE_BASE_URL . $path;
14 | }
15 |
16 | public static function fromPath($path)
17 | {
18 | return new ConsoleUrl($path);
19 | }
20 |
21 | public function __toString()
22 | {
23 | return $this->consoleUrl;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/FreeTransformBehavior.php:
--------------------------------------------------------------------------------
1 | 'add',
14 | 'label' => 'Add',
15 | ],
16 | [
17 | 'value' => 'override',
18 | 'label' => 'Override',
19 | ],
20 | ];
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Model/ResourceModel/Synchronisation/Collection.php:
--------------------------------------------------------------------------------
1 | _init(SynchronisationModel::class, SynchronisationResourceModel::class);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Core/Image/LocalImage.php:
--------------------------------------------------------------------------------
1 | localPathGenerator = $localPathGenerator;
19 | }
20 |
21 | public function __toString()
22 | {
23 | return call_user_func($this->localPathGenerator);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Core/Image/Transformation/DefaultImage.php:
--------------------------------------------------------------------------------
1 | value = $value;
12 | }
13 |
14 | public function __toString()
15 | {
16 | return $this->value;
17 | }
18 |
19 | public static function fromString($value)
20 | {
21 | return new DefaultImage($value);
22 | }
23 |
24 | public static function null()
25 | {
26 | return new DefaultImage(null);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/ProductGallery/ZoomTrigger.php:
--------------------------------------------------------------------------------
1 | 'click',
14 | 'label' => 'Click',
15 | ],
16 | [
17 | 'value' => 'hover',
18 | 'label' => 'Hover',
19 | ],
20 | ];
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Plugin/ExcludeFilesFromMinification.php:
--------------------------------------------------------------------------------
1 | process($subject, $html);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/view/adminhtml/layout/cms_block_edit.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Plugin/Cms/Block/Widget/Block.php:
--------------------------------------------------------------------------------
1 | process($subject, $html);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Api/SynchronisationRepositoryInterface.php:
--------------------------------------------------------------------------------
1 | apiSignature = Cloudinary::api_sign_request($params, (string) $secret);
14 | }
15 |
16 | public static function fromSecretAndParams(Secret $secret, array $params = [])
17 | {
18 | return new ApiSignature($secret, $params);
19 | }
20 |
21 | public function __toString()
22 | {
23 | return $this->apiSignature;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/etc/crontab.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | * * * * *
6 |
7 |
8 | * * * * *
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cloudinary/cloudinary-magento2",
3 | "description": "Cloudinary Magento 2 Integration.",
4 | "type": "magento2-module",
5 | "version": "2.1.3",
6 | "license": "MIT",
7 | "require": {
8 | "php": ">=7.3",
9 | "cloudinary/cloudinary_php": "^3.0 || >=2.7 <=2.11.0"
10 | },
11 | "autoload": {
12 | "files": [
13 | "registration.php"
14 | ],
15 | "psr-4": {
16 | "Cloudinary\\Cloudinary\\": ""
17 | }
18 | },
19 | "repositories": [{
20 | "type": "git",
21 | "url": "https://github.com/cloudinary/cloudinary_magento2"
22 | }]
23 | }
24 |
--------------------------------------------------------------------------------
/view/adminhtml/layout/cms_page_edit.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Core/Image/Transformation/FetchFormat.php:
--------------------------------------------------------------------------------
1 | value = $value;
14 | }
15 |
16 | public static function auto()
17 | {
18 | return self::fromString(self::FETCH_FORMAT_AUTO);
19 | }
20 |
21 | public static function fromString($value)
22 | {
23 | return new FetchFormat($value);
24 | }
25 |
26 | public function __toString()
27 | {
28 | return $this->value;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/etc/cron_groups.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1
5 | 4
6 | 2
7 | 10
8 | 60
9 | 600
10 | 1
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Plugin/Catalog/Block/Category/View.php:
--------------------------------------------------------------------------------
1 | process($subject, $html);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/view/frontend/layout/catalog_product_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/ProductGallery/Transition.php:
--------------------------------------------------------------------------------
1 | 'none',
14 | 'label' => 'None',
15 | ],
16 | [
17 | 'value' => 'fade',
18 | 'label' => 'Fade',
19 | ],
20 | [
21 | 'value' => 'slide',
22 | 'label' => 'Slide',
23 | ],
24 | ];
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/ProductGallery/ZoomType.php:
--------------------------------------------------------------------------------
1 | 'inline',
14 | 'label' => 'Inline',
15 | ],
16 | [
17 | 'value' => 'flyout',
18 | 'label' => 'Flyout',
19 | ],
20 | [
21 | 'value' => 'popup',
22 | 'label' => 'Popup',
23 | ],
24 | ];
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/Video/SourceTypes.php:
--------------------------------------------------------------------------------
1 | 'webm/vp9',
13 | 'label' => 'WebM/VP9',
14 | ],
15 | [
16 | 'value' => 'mp4/h265',
17 | 'label' => 'MP4/H.265',
18 | ],
19 | [
20 | 'value' => 'mp4/h264',
21 | 'label' => 'MP4/H.264',
22 | ]
23 | ];
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/Video/Type.php:
--------------------------------------------------------------------------------
1 |
8 | * Date: 14/01/2024
9 | * Time: 14:22
10 | */
11 | class Type implements OptionSourceInterface
12 | {
13 | public function toOptionArray()
14 | {
15 | return [
16 | [
17 | 'value' => 'native',
18 | 'label' => 'Default player',
19 | ],
20 | [
21 | 'value' => 'cloudinary',
22 | 'label' => 'Cloudinary player',
23 | ],
24 | ];
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/etc/acl.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/ProductGallery/Navigation.php:
--------------------------------------------------------------------------------
1 | 'none',
14 | 'label' => 'None',
15 | ],
16 | [
17 | 'value' => 'always',
18 | 'label' => 'Always',
19 | ],
20 | [
21 | 'value' => 'mouseover',
22 | 'label' => 'Mouseover',
23 | ],
24 | ];
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/ProductGallery/IndicatorsShape.php:
--------------------------------------------------------------------------------
1 | 'round',
14 | 'label' => 'Round',
15 | ],
16 | [
17 | 'value' => 'square',
18 | 'label' => 'Square',
19 | ],
20 | [
21 | 'value' => 'radius',
22 | 'label' => 'Radius',
23 | ],
24 | ];
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/Video/StreamMode.php:
--------------------------------------------------------------------------------
1 |
8 | * Date: 14/01/2024
9 | * Time: 14:22
10 | */
11 | class StreamMode implements OptionSourceInterface
12 | {
13 | public function toOptionArray()
14 | {
15 | return [
16 | [
17 | 'value' => 'optimization',
18 | 'label' => 'Progressive mode (i.e MP4/Webm)',
19 | ],
20 | [
21 | 'value' => 'abr',
22 | 'label' => 'ABR',
23 | ]
24 | ];
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/view/frontend/layout/default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/ProductGallery/CarouselStyle.php:
--------------------------------------------------------------------------------
1 | 'none',
14 | 'label' => 'None',
15 | ],
16 | [
17 | 'value' => 'thumbnails',
18 | 'label' => 'Thumbnails',
19 | ],
20 | [
21 | 'value' => 'indicators',
22 | 'label' => 'Indicators',
23 | ],
24 | ];
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/view/adminhtml/layout/default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/ProductGallery/ThumbnailsSelectedStyle.php:
--------------------------------------------------------------------------------
1 | 'border',
14 | 'label' => 'Border',
15 | ],
16 | [
17 | 'value' => 'gradient',
18 | 'label' => 'Gradient',
19 | ],
20 | [
21 | 'value' => 'all',
22 | 'label' => 'All',
23 | ],
24 | ];
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Core/Credentials.php:
--------------------------------------------------------------------------------
1 | key = $key;
16 | $this->secret = $secret;
17 | }
18 |
19 | public static function fromKeyAndSecret(Key $key, Secret $secret)
20 | {
21 | return new Credentials($key, $secret);
22 | }
23 |
24 | public function getKey()
25 | {
26 | return $this->key;
27 | }
28 |
29 | public function getSecret()
30 | {
31 | return $this->secret;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/view/base/web/js/form/element/file-uploader.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @api
3 | */
4 | /* global Base64 */
5 | define([
6 | 'jquery',
7 | 'Magento_Ui/js/form/element/file-uploader'
8 | ], function($, Element) {
9 | 'use strict';
10 |
11 | return Element.extend({
12 |
13 | /**
14 | * {@inheritDoc}
15 | */
16 | initialize: function() {
17 | this._super();
18 | this.cloudinaryMLoptions.imageParamName = this.paramName || this.inputName;
19 | this.cloudinaryMLoptions.cldMLid = this.cloudinaryMLoptions.imageParamName + '_' + this.uid;
20 | this.cloudinaryMLoptions.callbackHandler = this;
21 | this.cloudinaryMLoptions.callbackHandlerMethod = 'addFile';
22 | },
23 |
24 | });
25 | });
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/Video/ABR/Comment.php:
--------------------------------------------------------------------------------
1 | urlInterface = $urlInterface;
23 | }
24 |
25 | public function getCommentText($elementValue)
26 | {
27 |
28 | if ($elementValue == 'optimization') {
29 | $comment = '';
30 | }
31 | return $comment;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Core/Image/Transformation/Freeform.php:
--------------------------------------------------------------------------------
1 | urlParameters = $urlParameters;
20 | }
21 |
22 | /**
23 | * @param string $value
24 | * @return Freeform
25 | */
26 | public static function fromString($value)
27 | {
28 | return new Freeform($value);
29 | }
30 |
31 | /**
32 | * @return string
33 | */
34 | public function __toString()
35 | {
36 | return $this->urlParameters;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/Video/Controls.php:
--------------------------------------------------------------------------------
1 |
8 | * Date: 14/01/2024
9 | * Time: 14:22
10 | */
11 | class Controls implements OptionSourceInterface
12 | {
13 | public function toOptionArray()
14 | {
15 | return [
16 | [
17 | 'value' => 'all',
18 | 'label' => 'All',
19 | ],
20 | [
21 | 'value' => 'play',
22 | 'label' => 'Play buttons',
23 | ],
24 | [
25 | 'value' => 'none',
26 | 'label' => 'None',
27 | ],
28 | ];
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/Video/Autoplay.php:
--------------------------------------------------------------------------------
1 |
8 | * Date: 14/01/2024
9 | * Time: 14:22
10 | */
11 | class Autoplay implements OptionSourceInterface
12 | {
13 | public function toOptionArray()
14 | {
15 | return [
16 | [
17 | 'value' => 'never',
18 | 'label' => 'Off',
19 | ],
20 | [
21 | 'value' => 'always',
22 | 'label' => 'Always',
23 | ],
24 | [
25 | 'value' => 'on-scroll',
26 | 'label' => 'On-scroll',
27 | ]
28 | ];
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/view/frontend/templates/product/old_image.phtml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
12 | escapeHtml($block->getCustomAttributes()) ?>
14 | src="= /* @noEscape */ $block->getLazyloadPlaceholder() ?>"
15 | data-original="= $escaper->escapeUrl($block->getImageUrl()) ?>"
16 | width="= $escaper->escapeHtmlAttr($block->getWidth()) ?>"
17 | height="= $escaper->escapeHtmlAttr($block->getHeight()) ?>"
18 | alt="= /* @noEscape */ $block->stripTags($block->getLabel(), null, true) ?>" />
19 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/ProductGallery/CarouselLocation.php:
--------------------------------------------------------------------------------
1 | 'top',
14 | 'label' => 'Top',
15 | ],
16 | [
17 | 'value' => 'right',
18 | 'label' => 'Right',
19 | ],
20 | [
21 | 'value' => 'left',
22 | 'label' => 'Left',
23 | ],
24 | [
25 | 'value' => 'bottom',
26 | 'label' => 'Bottom',
27 | ],
28 | ];
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/ProductGallery/ZoomViewerPosition.php:
--------------------------------------------------------------------------------
1 | 'top',
14 | 'label' => 'Top',
15 | ],
16 | [
17 | 'value' => 'right',
18 | 'label' => 'Right',
19 | ],
20 | [
21 | 'value' => 'left',
22 | 'label' => 'Left',
23 | ],
24 | [
25 | 'value' => 'bottom',
26 | 'label' => 'Bottom',
27 | ],
28 | ];
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/Video/StreamProtocol.php:
--------------------------------------------------------------------------------
1 |
9 | * Date: 10/03/2024
10 | * Time: 17:54
11 | */
12 | class StreamProtocol implements OptionSourceInterface
13 | {
14 | public function toOptionArray()
15 | {
16 | return [
17 | [
18 | 'value' => 'dash',
19 | 'label' => 'Dynamic adaptive streaming over HTTP (MPEG-DASH)',
20 | ],
21 | [
22 | 'value' => 'hls',
23 | 'label' => 'HTTP live streaming (HLS)',
24 | ],
25 | ];
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/ProductGallery/ThumbnailsMediaSymbolShape.php:
--------------------------------------------------------------------------------
1 | 'none',
14 | 'label' => 'None',
15 | ],
16 | [
17 | 'value' => 'round',
18 | 'label' => 'Round',
19 | ],
20 | [
21 | 'value' => 'square',
22 | 'label' => 'Square',
23 | ],
24 | [
25 | 'value' => 'radius',
26 | 'label' => 'Radius',
27 | ],
28 | ];
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/view/adminhtml/ui_component/pagebuilder_base_form_with_background_video.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
19 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/CmsBlocks.php:
--------------------------------------------------------------------------------
1 | blockFactory = $blockFactory;
19 | }
20 |
21 | public function toOptionArray()
22 | {
23 | $options = [];
24 | foreach ($this->blockFactory->create()->getCollection()->setOrder('title', 'asc') as $block) {
25 | $options[] = [
26 | 'value' => $block->getIdentifier(),
27 | 'label' => $block->getTitle(),
28 | ];
29 | }
30 | return $options;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/etc/schema.graphqls:
--------------------------------------------------------------------------------
1 | type CustomMediaAttribute {
2 | attribute_code: String
3 | url: String
4 | }
5 |
6 | type CloudinaryData {
7 | image: String
8 | small_image: String
9 | thumbnail: String
10 | media_gallery: [String]
11 | gallery_widget_parameters: String @doc(description: "Cloudinary gallery widget parameters (json)")
12 | custom_media_attributes(attribute_codes: [String]!): [CustomMediaAttribute]
13 | @resolver(class: "\\Cloudinary\\Cloudinary\\Model\\GraphQLResolver\\ProductAttributeCldResolver")
14 | @doc(description: "Fetch a custom media attributes for the product based on the provided attribute code.")
15 | }
16 |
17 | interface ProductInterface {
18 | cld_data: CloudinaryData
19 | @resolver(class: "\\Cloudinary\\Cloudinary\\Model\\GraphQLResolver\\ProductAttributeCldResolver")
20 | @doc(description: "Cloudinary urls generated for product images and gallery widget parameters.")
21 | }
22 |
--------------------------------------------------------------------------------
/view/frontend/templates/product/video/settings.phtml:
--------------------------------------------------------------------------------
1 |
8 |
18 |
21 | helper('Cloudinary\Cloudinary\Helper\ProductGalleryHelper');
23 | ?>
24 | isHyvaThemeEnabled()): ?>
25 |
26 |
27 |
--------------------------------------------------------------------------------
/view/base/web/js/form/element/image-uploader.js:
--------------------------------------------------------------------------------
1 | /* global Base64 */
2 | define([
3 | 'jquery',
4 | 'Magento_Ui/js/form/element/image-uploader'
5 | ], function($, Element) {
6 | 'use strict';
7 |
8 | return Element.extend({
9 | /**
10 | * {@inheritDoc}
11 | */
12 | initialize: function() {
13 | this._super();
14 | this.cloudinaryMLoptions.imageParamName = this.paramName || this.inputName;
15 | this.cloudinaryMLoptions.cldMLid = this.cloudinaryMLoptions.imageParamName + '_' + this.uid;
16 | this.cloudinaryMLoptions.callbackHandler = this;
17 | this.cloudinaryMLoptions.callbackHandlerMethod = 'addFile';
18 | },
19 | /**
20 | * hides the 'Upload from Gallery' button at category page.
21 | * */
22 | showGalleryUploader: function() {
23 | return (this.cloudinaryMLoptions.isGallerySupported)
24 | }
25 | });
26 | });
27 |
--------------------------------------------------------------------------------
/etc/adminhtml/events.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Core/Security/SignedConsoleUrl.php:
--------------------------------------------------------------------------------
1 | time(), "mode" => "check"];
14 | $params["signature"] = (string)ApiSignature::fromSecretAndParams($credentials->getSecret(), $params);
15 | $params["api_key"] = (string)$credentials->getKey();
16 | $query = http_build_query($params);
17 |
18 | $this->signedConsoleUrl = (string)$url . '?' . $query;
19 | }
20 |
21 | public static function fromConsoleUrlAndCredentials(ConsoleUrl $url, Credentials $credentials)
22 | {
23 | return new SignedConsoleUrl($url, $credentials);
24 | }
25 |
26 | public function __toString()
27 | {
28 | return $this->signedConsoleUrl;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/view/frontend/requirejs-config.js:
--------------------------------------------------------------------------------
1 | var config = {
2 | map: {
3 | '*': {
4 | loadPlayer: 'Cloudinary_Cloudinary/js/load-player',
5 | 'Magento_ProductVideo/js/fotorama-add-video-events': 'Cloudinary_Cloudinary/js/fotorama-add-video-events',
6 | cloudinaryProductGallery: 'Cloudinary_Cloudinary/js/cloudinary-product-gallery',
7 | cloudinaryLazyload: 'Cloudinary_Cloudinary/js/cloudinary-lazyload'
8 | }
9 | },
10 | paths: {
11 | 'jquery.lazyload': "Cloudinary_Cloudinary/js/jquery.lazyload.min",
12 | cloudinaryProductGalleryAll: "//product-gallery.cloudinary.com/latest/all"
13 | },
14 | shim: {
15 | 'jquery.lazyload': {
16 | deps: ['jquery']
17 | },
18 | },
19 | config: {
20 | mixins: {
21 | 'Magento_Swatches/js/swatch-renderer': {
22 | 'Cloudinary_Cloudinary/js/swatch-renderer-mixin': true
23 | }
24 | }
25 | }
26 | };
27 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/ProductGallery/ThumbnailsNavigationShape.php:
--------------------------------------------------------------------------------
1 | 'none',
14 | 'label' => 'None',
15 | ],
16 | [
17 | 'value' => 'round',
18 | 'label' => 'Round',
19 | ],
20 | [
21 | 'value' => 'square',
22 | 'label' => 'Square',
23 | ],
24 | [
25 | 'value' => 'radius',
26 | 'label' => 'Radius',
27 | ],
28 | [
29 | 'value' => 'rectangle',
30 | 'label' => 'Rectangle',
31 | ],
32 | ];
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/view/frontend/templates/product/image.phtml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
12 | getCustomAttributes() as $name => $value): ?>
14 | = $escaper->escapeHtmlAttr($name) ?>="= $escaper->escapeHtmlAttr($value) ?>"
15 |
16 | src="= $escaper->escapeHtmlAttr($block->getLazyloadPlaceholder()) ?>"
17 | data-original="= $escaper->escapeUrl($block->getImageUrl()) ?>"
18 | width="= $escaper->escapeHtmlAttr($block->getWidth()) ?>"
19 | height="= $escaper->escapeHtmlAttr($block->getHeight()) ?>"
20 | alt="= $escaper->escapeHtmlAttr($block->getLabel()) ?>" />
21 |
--------------------------------------------------------------------------------
/Core/Image/Transformation/Crop.php:
--------------------------------------------------------------------------------
1 | value = $value;
17 | }
18 |
19 | public static function fromString($value)
20 | {
21 | return new Crop($value);
22 | }
23 |
24 | public static function pad()
25 | {
26 | return new Crop(self::PAD);
27 | }
28 |
29 | public static function lpad()
30 | {
31 | return new Crop(self::LPAD);
32 | }
33 |
34 | public static function fit()
35 | {
36 | return new Crop(self::FIT);
37 | }
38 |
39 | public static function limit()
40 | {
41 | return new Crop(self::LIMIT);
42 | }
43 |
44 | public function __toString()
45 | {
46 | return $this->value;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/view/adminhtml/ui_component/pagebuilder_video_form.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
20 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/Video/Autoplay/Comment.php:
--------------------------------------------------------------------------------
1 |
12 | * Date: 07/03/2024
13 | * Time: 14:04
14 | */
15 | class Comment implements CommentInterface
16 | {
17 | /**
18 | * @var UrlInterface
19 | */
20 | protected $urlInterface;
21 |
22 | /**
23 | * @param UrlInterface $urlInterface
24 | */
25 | public function __construct(
26 | UrlInterface $urlInterface
27 | ) {
28 | $this->urlInterface = $urlInterface;
29 | }
30 |
31 | public function getCommentText($elementValue)
32 | {
33 | $url = 'https://cloudinary.com/glossary/video-autoplay';
34 |
35 | $comment = '';
36 |
37 | return $comment;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright 2018 Cloudinary
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/view/adminhtml/layout/cms_wysiwyg_images_index.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Magento\Backend\Block\DataProviders\ImageUploadConfig
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Model/Synchronisation.php:
--------------------------------------------------------------------------------
1 | _init(SynchronisationResourceModel::class);
14 | }
15 |
16 | public function setImagePath($imagePath)
17 | {
18 | return $this->setData('image_path', $imagePath);
19 | }
20 |
21 | public function getImagePath()
22 | {
23 | return $this->getData('image_path');
24 | }
25 |
26 | public function getFilename()
27 | {
28 | return basename($this->getImagePath());
29 | }
30 |
31 | public function getRelativePath()
32 | {
33 | return $this->getImagePath();
34 | }
35 |
36 | public function tagAsSynchronized()
37 | {
38 | $this->save();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/Video/VideoQuality.php:
--------------------------------------------------------------------------------
1 | 'none',
13 | 'label' => 'Not set',
14 | ],
15 | [
16 | 'value' => 'q_auto',
17 | 'label' => 'Auto',
18 | ],
19 | [
20 | 'value' => 'q_auto:best',
21 | 'label' => 'Auto best',
22 | ],
23 | [
24 | 'value' => 'q_auto:good',
25 | 'label' => 'Auto good',
26 | ],
27 | [
28 | 'value' => 'q_auto:eco',
29 | 'label' => 'Auto eco',
30 | ],
31 | [
32 | 'value' => 'q_auto:low',
33 | 'label' => 'Auto low',
34 | ]
35 | ];
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/view/base/web/images/spinset_indic.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 | spinset-indication
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Plugin/Ui/Component/Form/Element/DataType/Media/Image.php:
--------------------------------------------------------------------------------
1 | getData('config/cloudinaryMLoptions')) {
20 | $component->setData(array_replace_recursive(
21 | $component->getData(),
22 | [
23 | 'config' => [
24 | 'template' => 'Cloudinary_Cloudinary/form/element/uploader/image',
25 | 'component' => 'Cloudinary_Cloudinary/js/form/element/image-uploader',
26 | ]
27 | ]
28 | ));
29 | }
30 | return $result;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Core/Exception/MigrationError.php:
--------------------------------------------------------------------------------
1 | message = sprintf('%s%s', $this->message, $suffix);
28 | }
29 |
30 | /**
31 | * @return Image
32 | */
33 | public function getImage()
34 | {
35 | return $this->image;
36 | }
37 |
38 | /**
39 | * @param Image $image
40 | * @param string $message
41 | * @throws MigrationError
42 | */
43 | public static function throwWith(Image $image, $message = '')
44 | {
45 | $exception = new static($message ?: static::DEFAULT_MESSAGE);
46 | $exception->image = $image;
47 | throw $exception;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/view/frontend/web/js/cloudinary-product-gallery.js:
--------------------------------------------------------------------------------
1 | define([
2 | 'jquery',
3 | 'cloudinaryProductGalleryAll'
4 | ], function($) {
5 | 'use strict';
6 |
7 | $.widget('mage.cloudinaryProductGallery', {
8 |
9 | options: {
10 | cloudinaryPGoptions: {}, // Options for Cloudinary-PG galleryWidget()
11 | cldPGid: 0,
12 | },
13 |
14 | /**
15 | * @private
16 | */
17 | _create: function() {
18 | this._super();
19 |
20 | var widget = this;
21 | window.cloudinary_pg = window.cloudinary_pg || [];
22 | this.options.cldPGid = this.options.cldPGid || 0;
23 | if (typeof window.cloudinary_pg[this.options.cldPGid] === "undefined") {
24 | this.cloudinary_pg = window.cloudinary_pg[this.options.cldPGid] = cloudinary.galleryWidget(this.options.cloudinaryPGoptions);
25 | this.cloudinary_pg.render();
26 | } else {
27 | this.cloudinary_pg = window.cloudinary_pg[this.options.cldPGid];
28 | }
29 |
30 |
31 | },
32 |
33 | });
34 |
35 | return $.mage.cloudinaryProductGallery;
36 | });
37 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/ProductGallery/ThumbnailsSelectedBorderPosition.php:
--------------------------------------------------------------------------------
1 | 'top',
14 | 'label' => 'Top',
15 | ],
16 | [
17 | 'value' => 'bottom',
18 | 'label' => 'Bottom',
19 | ],
20 | [
21 | 'value' => 'left',
22 | 'label' => 'Left',
23 | ],
24 | [
25 | 'value' => 'right',
26 | 'label' => 'Right',
27 | ],
28 | [
29 | 'value' => 'top-bottom',
30 | 'label' => 'Top-Bottom',
31 | ],
32 | [
33 | 'value' => 'left-right',
34 | 'label' => 'Left-Right',
35 | ],
36 | [
37 | 'value' => 'all',
38 | 'label' => 'All',
39 | ],
40 | ];
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/Lazyload/Placeholder.php:
--------------------------------------------------------------------------------
1 | 'blur',
14 | 'label' => 'Blur',
15 | ],
16 | [
17 | 'value' => 'pixelate',
18 | 'label' => 'Pixelate',
19 | ],
20 | [
21 | 'value' => 'predominant-color',
22 | 'label' => 'Predominant color',
23 | ],
24 | [
25 | 'value' => 'vectorize',
26 | 'label' => 'Vectorize',
27 | ],
28 | ];
29 |
30 | /*
31 | export const placeholderImageOptions = {
32 | 'vectorize': {effect: 'vectorize', quality: 1},
33 | 'pixelate': {effect: 'pixelate', quality: 1, fetch_format: 'auto'},
34 | 'blur': {effect: 'blur:2000', quality: 1, fetch_format: 'auto'},
35 | 'predominant-color': predominantColorTransform
36 | };
37 | */
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Model/MigrationTask.php:
--------------------------------------------------------------------------------
1 | flagDir = $filesystem->getDirectoryWrite(DirectoryList::VAR_DIR);
26 | }
27 |
28 | public function hasStarted()
29 | {
30 | return $this->flagDir->isExist(self::MIGRATION_RUNNING_FLAG_FILENAME);
31 | }
32 |
33 | public function hasBeenStopped()
34 | {
35 | return !$this->hasStarted();
36 | }
37 |
38 | public function stop()
39 | {
40 | $this->flagDir->delete(self::MIGRATION_RUNNING_FLAG_FILENAME);
41 | }
42 |
43 | public function start()
44 | {
45 | $this->flagDir->touch(self::MIGRATION_RUNNING_FLAG_FILENAME);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Model/Observer/ProductGalleryChangeTemplate.php:
--------------------------------------------------------------------------------
1 | configuration = $configuration;
28 | }
29 |
30 | /**
31 | * @param mixed $observer
32 | * @SuppressWarnings(PHPMD.UnusedFormalParameter)
33 | * @return void
34 | */
35 | public function execute(\Magento\Framework\Event\Observer $observer)
36 | {
37 | if (!$this->configuration->isEnabled()) {
38 | return $this;
39 | }
40 | $observer->getBlock()->setTemplate('Cloudinary_Cloudinary::catalog/product/helper/gallery.phtml');
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/view/frontend/templates/product/old_image_with_borders.phtml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
12 |
14 |
16 | escapeHtmlAttr($block->getCustomAttributes()) ?>
18 | src="= /* @noEscape */ $block->getLazyloadPlaceholder() ?>"
19 | data-original="= $escaper->escapeUrl($block->getImageUrl()) ?>"
20 | width="= $escaper->escapeHtmlAttr($block->getWidth()) ?>"
21 | height="= $escaper->escapeHtmlAttr($block->getHeight()) ?>"
22 | max-width="= $escaper->escapeHtmlAttr($block->getWidth()) ?>"
23 | max-height="= $escaper->escapeHtmlAttr($block->getHeight()) ?>"
24 | alt="= /* @noEscape */ $block->stripTags($block->getLabel(), null, true) ?>"/>
25 |
26 |
--------------------------------------------------------------------------------
/Core/ConfigurationInterface.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | Preview
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Core/Image/Transformation/Dimensions.php:
--------------------------------------------------------------------------------
1 | width = is_null($width) ? null : (int) round($width);
14 | $this->height = is_null($height) ? null : (int) round($height);
15 | }
16 |
17 | public function getWidth()
18 | {
19 | return $this->width;
20 | }
21 |
22 | public function getHeight()
23 | {
24 | return $this->height;
25 | }
26 |
27 | public static function square($length)
28 | {
29 | return new Dimensions($length, $length);
30 | }
31 |
32 | public static function squareMissingDimension(Dimensions $dimensions)
33 | {
34 | if (!$dimensions->getWidth()) {
35 | return Dimensions::square($dimensions->getHeight());
36 | } elseif (!$dimensions->getHeight()) {
37 | return Dimensions::square($dimensions->getWidth());
38 | }
39 |
40 | return $dimensions;
41 | }
42 |
43 | public static function fromWidthAndHeight($width, $height)
44 | {
45 | return new Dimensions($width, $height);
46 | }
47 |
48 | public static function null()
49 | {
50 | return new Dimensions(null, null);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/view/base/web/images/cloudinary_cloud_glyph_white.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/view/base/web/images/cloudinary_cloud_glyph_regular.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Core/ConfigurationBuilder.php:
--------------------------------------------------------------------------------
1 | configuration = $configuration;
16 | }
17 |
18 | /**
19 | * @return Configuration instance
20 | */
21 | public function build()
22 | {
23 |
24 | $reg = $this->configuration->getCoreRegistry();
25 | $credentials = $this->configuration->getCredentials();
26 | if ($credentials) {
27 | $cloud = [
28 | 'cloud_name' => $credentials['cloud_name'],
29 | 'api_key' => $credentials['api_key'],
30 | 'api_secret' => $credentials['api_secret']
31 | ];
32 |
33 | $url = array_diff($credentials, $cloud);
34 |
35 | $config = array('cloud' => $cloud);
36 |
37 | if ($url && is_array($url)) {
38 | $config['url'] = $url;
39 | }
40 |
41 | if ($this->configuration->getCdnSubdomainStatus()) {
42 | $config['cloud']['cdn_subdomain'] = true;
43 | }
44 |
45 | return $config;
46 | }
47 | return $this;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Core/Migration/Queue.php:
--------------------------------------------------------------------------------
1 | migrationTask = $migrationTask;
26 | $this->synchronizedMediaRepository = $synchronizedMediaRepository;
27 | $this->logger = $logger;
28 | $this->batchUploader = $batchUploader;
29 | }
30 |
31 | public function process()
32 | {
33 | if ($this->migrationTask->hasBeenStopped()) {
34 | return;
35 | }
36 |
37 | $images = $this->synchronizedMediaRepository->findUnsynchronisedImages();
38 |
39 | if (!$images) {
40 | $this->logger->notice(self::MESSAGE_COMPLETE);
41 | $this->migrationTask->stop();
42 | } else {
43 | $this->logger->notice(self::MESSAGE_PROCESSING);
44 | $this->batchUploader->uploadImages($images);
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Core/Image/ImageFactory.php:
--------------------------------------------------------------------------------
1 | configuration = $configuration;
29 | $this->synchronizationChecker = $synchronizationChecker;
30 | }
31 |
32 | /**
33 | * @param $imagePath
34 | * @return Image
35 | */
36 | public function build($imagePath, callable $localPathGenerator)
37 | {
38 | $migratedPath = $this->configuration->getMigratedPath($imagePath);
39 |
40 | if ($this->configuration->isEnabled() && $this->synchronizationChecker->isSynchronized($migratedPath)) {
41 | return Image::fromPath($imagePath, $migratedPath);
42 | } else {
43 | return new LocalImage($localPathGenerator);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Model/Observer/DeleteProductImage.php:
--------------------------------------------------------------------------------
1 | productImageFinder = $productImageFinder;
31 | $this->cloudinaryImageManager = $cloudinaryImageManager;
32 | }
33 |
34 | /**
35 | * @param Observer $observer
36 | */
37 | public function execute(Observer $observer)
38 | {
39 | $product = $observer->getEvent()->getProduct();
40 |
41 | foreach ($this->productImageFinder->findDeletedImages($product) as $image) {
42 | $this->cloudinaryImageManager->removeAndUnSynchronise($image);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/etc/adminhtml/di.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | -
8 |
- Cloudinary\Cloudinary\Ui\DataProvider\Product\Form\Modifier\Product
9 | - 55
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Plugin/MediaConfig.php:
--------------------------------------------------------------------------------
1 | imageFactory = $imageFactory;
28 | $this->urlGenerator = $urlGenerator;
29 | }
30 |
31 | /**
32 | * @param CatalogMediaConfig $mediaConfig
33 | * @param \Closure $originalMethod
34 | * @param string $file
35 | *
36 | * @return string
37 | */
38 | public function aroundGetMediaUrl(CatalogMediaConfig $mediaConfig, \Closure $originalMethod, $file)
39 | {
40 | $image = $this->imageFactory->build(
41 | $mediaConfig->getBaseMediaPath() . $file,
42 | function () use ($originalMethod, $file) {
43 | return $originalMethod($file);
44 | }
45 | );
46 |
47 | return $this->urlGenerator->generateFor($image);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Block/Scripts.php:
--------------------------------------------------------------------------------
1 | configuration = $configuration;
37 | $this->_helper = $mediaHelper;
38 | }
39 |
40 | /**
41 | * @method isEnabledLazyload
42 | * @return boolean
43 | */
44 | public function isEnabled()
45 | {
46 | return $this->configuration->isEnabled();
47 | }
48 |
49 | /**
50 | * @return string|null
51 | */
52 | public function getCname()
53 | {
54 | return $this->_helper->getCname();
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/Core/ValidateRemoteUrlRequest.php:
--------------------------------------------------------------------------------
1 | curlHandler = curl_init($url);
12 | $this->setCurlOptions();
13 | }
14 |
15 | public function validate()
16 | {
17 | $result = $this->execute();
18 |
19 | if ($result->responseCode == 200 && is_null($result->error)) {
20 | return true;
21 | }
22 |
23 | return false;
24 | }
25 |
26 | private function execute()
27 | {
28 | curl_exec($this->curlHandler);
29 |
30 | $result = new \stdClass();
31 | $result->responseCode = $this->getResponseCode();
32 | $result->error = $this->getErrorMessage();
33 |
34 | curl_close($this->curlHandler);
35 |
36 | return $result;
37 | }
38 |
39 | private function getResponseCode()
40 | {
41 | return curl_getinfo($this->curlHandler, CURLINFO_HTTP_CODE);
42 | }
43 |
44 | private function getErrorMessage()
45 | {
46 | return curl_errno($this->curlHandler) ? curl_error($this->curlHandler) : null;
47 | }
48 |
49 | private function setCurlOptions()
50 | {
51 | curl_setopt($this->curlHandler, CURLOPT_HEADER, 1);
52 | curl_setopt($this->curlHandler, CURLOPT_FAILONERROR, 1);
53 | curl_setopt($this->curlHandler, CURLOPT_RETURNTRANSFER, 1);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/Gravity.php:
--------------------------------------------------------------------------------
1 | '',
14 | 'label' => 'Magento\'s Default',
15 | ],
16 | [
17 | 'value' => 'north_west',
18 | 'label' => 'North West',
19 | ],
20 | [
21 | 'value' => 'north',
22 | 'label' => 'North',
23 | ],
24 | [
25 | 'value' => 'north_east',
26 | 'label' => 'North East',
27 | ],
28 | [
29 | 'value' => 'east',
30 | 'label' => 'East',
31 | ],
32 | [
33 | 'value' => 'center',
34 | 'label' => 'Center',
35 | ],
36 | [
37 | 'value' => 'west',
38 | 'label' => 'West',
39 | ],
40 | [
41 | 'value' => 'south_west',
42 | 'label' => 'South West',
43 | ],
44 | [
45 | 'value' => 'south',
46 | 'label' => 'South',
47 | ],
48 | [
49 | 'value' => 'south_east',
50 | 'label' => 'South East',
51 | ],
52 | ];
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/Quality.php:
--------------------------------------------------------------------------------
1 | '',
14 | 'label' => 'Magento\'s Default',
15 | ],
16 | [
17 | 'value' => '20',
18 | 'label' => '20%',
19 | ],
20 | [
21 | 'value' => '30',
22 | 'label' => '30%',
23 | ],
24 | [
25 | 'value' => '40',
26 | 'label' => '40%',
27 | ],
28 | [
29 | 'value' => '50',
30 | 'label' => '50%',
31 | ],
32 | [
33 | 'value' => '60',
34 | 'label' => '60%',
35 | ],
36 | [
37 | 'value' => '70',
38 | 'label' => '70%',
39 | ],
40 | [
41 | 'value' => '80',
42 | 'label' => '80%',
43 | ],
44 | [
45 | 'value' => '90',
46 | 'label' => '90%',
47 | ],
48 | [
49 | 'value' => '100',
50 | 'label' => '100%',
51 | ],
52 | [
53 | 'value' => 'auto',
54 | 'label' => 'Auto',
55 | ]
56 | ];
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/view/adminhtml/templates/config/free.phtml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Custom transformations will be added to the default image transformations settings chosen above.
4 | For information about the full range of transforms available see the
5 | Cloudinary documentation .
6 |
7 | You may need to clear or rebuild the Magento block and full page caches to see the changes in the front end.
8 |
9 |
10 |
11 | isCanPreviewTransformations()) ? ' disabled' : '' ?>
17 | >
18 | Preview custom transformation
19 |
20 |
21 | ", "ajaxKey": "= /* @noEscape */ $this->getFormKey() ?>"}}'>
24 |
25 |
--------------------------------------------------------------------------------
/Model/ProductImageFinder/ImageCreator.php:
--------------------------------------------------------------------------------
1 | mediaDirectory = $filesystem->getDirectoryRead(DirectoryList::MEDIA);
37 | $this->baseMediaPath = $mediaConfig->getBaseMediaPath();
38 | }
39 |
40 | /**
41 | * @param array $imageData
42 | *
43 | * @return Image
44 | */
45 | public function __invoke(array $imageData)
46 | {
47 | $fullPath = $this->baseMediaPath . $imageData['file'];
48 | $relativePath = 'media' . DIRECTORY_SEPARATOR . $fullPath;
49 |
50 | return Image::fromPath(
51 | $this->mediaDirectory->getAbsolutePath($fullPath),
52 | $relativePath
53 | );
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Cloudinary Magento 2 Extension
2 |
3 | The Cloudinary Magento extension links your Magento website to your Cloudinary account, allowing you to serve all your product, category, and content management system (CMS) images directly from Cloudinary.
4 |
5 | Before you install the extension, make sure you have a Cloudinary account. You can start by [signing up](https://cloudinary.com/users/register_free?utm_source=magento-2-git-page&utm_medium=affiliate&utm_content=sign-up&utm_campaign=1975) for a free plan. When your requirements grow, you can upgrade to a [plan](https://cloudinary.com/pricing) that best fits your needs.
6 |
7 | For more information on using the Cloudinary Magento 2 extension, take a look at our [documentation](https://cloudinary.com/documentation/magento_integration).
8 |
9 | ## Installation
10 |
11 | You can download and install the extension from the [Magento Marketplace](https://marketplace.magento.com/cloudinary-cloudinary.html) or install it via composer by running the following commands under your Magento 2 root dir:
12 |
13 | ```
14 | composer require cloudinary/cloudinary-magento2
15 | php bin/magento maintenance:enable
16 | php bin/magento setup:upgrade
17 | php bin/magento setup:di:compile
18 | php bin/magento setup:static-content:deploy
19 | php bin/magento maintenance:disable
20 | php bin/magento cache:flush
21 | ```
22 |
23 | https://www.cloudinary.com/
24 |
25 | Copyright © 2020 Cloudinary. All rights reserved.
26 |
27 | 
28 |
--------------------------------------------------------------------------------
/Block/Adminhtml/System/Config/ModuleVersion.php:
--------------------------------------------------------------------------------
1 | configuration = $configuration;
29 | parent::__construct($context, $data);
30 | }
31 |
32 | /**
33 | * Remove scope label
34 | *
35 | * @param AbstractElement $element
36 | * @return string
37 | */
38 | public function render(AbstractElement $element)
39 | {
40 | $element->unsScope()->unsCanUseWebsiteValue()->unsCanUseDefaultValue();
41 | return parent::render($element);
42 | }
43 |
44 | /**
45 | * Return element html
46 | *
47 | * @param AbstractElement $element
48 | * @return string
49 | */
50 | protected function _getElementHtml(AbstractElement $element)
51 | {
52 | return "{$this->configuration->getModuleVersion()}
";
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Core/UploadConfig.php:
--------------------------------------------------------------------------------
1 | useFilename = $useFilename;
31 | $this->uniqueFilename = $uniqueFilename;
32 | $this->overwrite = $overwrite;
33 | }
34 |
35 | public static function fromBooleanValues($useFilename, $uniqueFilename, $overwrite)
36 | {
37 | return new UploadConfig($useFilename, $uniqueFilename, $overwrite);
38 | }
39 |
40 | /**
41 | * @return boolean
42 | */
43 | public function useFilename()
44 | {
45 | return $this->useFilename;
46 | }
47 |
48 | /**
49 | * @return boolean
50 | */
51 | public function uniqueFilename()
52 | {
53 | return $this->uniqueFilename;
54 | }
55 |
56 | /**
57 | * @return boolean
58 | */
59 | public function overwrite()
60 | {
61 | return $this->overwrite;
62 | }
63 |
64 | public function toArray()
65 | {
66 | return [
67 | "use_filename" => $this->useFilename,
68 | "unique_filename" => $this->uniqueFilename,
69 | "overwrite" => $this->overwrite,
70 | ];
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Core/Image.php:
--------------------------------------------------------------------------------
1 | imagePath = $imagePath;
16 | $this->relativePath = $relativePath;
17 | $this->pathInfo = pathinfo($this->imagePath);
18 | }
19 |
20 | public static function fromPath($imagePath, $relativePath = '')
21 | {
22 | return new Image($imagePath, $relativePath);
23 | }
24 |
25 | public function __toString()
26 | {
27 | return $this->imagePath;
28 | }
29 |
30 | public function getRelativePath()
31 | {
32 | return $this->relativePath;
33 | }
34 |
35 | public function getRelativeFolder()
36 | {
37 | $result = dirname($this->getRelativePath());
38 | return $result == '.' ? '' : $result;
39 | }
40 |
41 | public function getId()
42 | {
43 | return sprintf(
44 | '%s%s',
45 | $this->relativePath ? ($this->getRelativeFolder() . DIRECTORY_SEPARATOR) : '',
46 | $this->pathInfo['basename']
47 | );
48 | }
49 |
50 | public function getIdWithoutExtension()
51 | {
52 | return sprintf(
53 | '%s%s',
54 | $this->relativePath ? ($this->getRelativeFolder() . DIRECTORY_SEPARATOR) : '',
55 | $this->pathInfo['filename']
56 | );
57 | }
58 |
59 | public function getExtension()
60 | {
61 | return $this->pathInfo['extension'];
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Model/Framework/File/Uploader.php:
--------------------------------------------------------------------------------
1 | 180) {
38 | throw new \InvalidArgumentException('Filename is too long; must be 180 characters or less');
39 | }
40 |
41 | if (preg_match('/^_+$/', $fileInfo['filename'])) {
42 | $fileName = 'file.' . $fileInfo['extension'];
43 | }
44 |
45 | return $fileName;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Model/Config/Source/Dropdown/ProductGallery/AspectRatio.php:
--------------------------------------------------------------------------------
1 | 'square',
14 | 'label' => 'Square',
15 | ],
16 | [
17 | 'value' => '1:1',
18 | 'label' => '1:1',
19 | ],
20 | [
21 | 'value' => '3:4',
22 | 'label' => '3:4',
23 | ],
24 | [
25 | 'value' => '4:3',
26 | 'label' => '4:3',
27 | ],
28 | [
29 | 'value' => '4:6',
30 | 'label' => '4:6',
31 | ],
32 | [
33 | 'value' => '6:4',
34 | 'label' => '6:4',
35 | ],
36 | [
37 | 'value' => '5:7',
38 | 'label' => '5:7',
39 | ],
40 | [
41 | 'value' => '7:5',
42 | 'label' => '7:5',
43 | ],
44 | [
45 | 'value' => '5:8',
46 | 'label' => '5:8',
47 | ],
48 | [
49 | 'value' => '8:5',
50 | 'label' => '8:5',
51 | ],
52 | [
53 | 'value' => '9:16',
54 | 'label' => '9:16',
55 | ],
56 | [
57 | 'value' => '16:9',
58 | 'label' => '16:9',
59 | ],
60 | ];
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Core/UrlGenerator.php:
--------------------------------------------------------------------------------
1 | configuration = $configuration;
28 | $this->imageProvider = $imageProvider;
29 | }
30 |
31 | /**
32 | * @param ImageInterface $image
33 | * @param Transformation $transformation
34 | *
35 | * @return string
36 | */
37 | public function generateFor(ImageInterface $image, ?Transformation $transformation = null)
38 | {
39 | if ($image instanceof LocalImage) {
40 | return (string)$image;
41 | }
42 |
43 | return (string)$this->imageProvider->retrieveTransformed(
44 | $image,
45 | $transformation ?: $this->configuration->getDefaultTransformation()
46 | );
47 | }
48 |
49 | /**
50 | * @param Image $image
51 | * @param Dimensions $dimensions
52 | *
53 | * @return string
54 | */
55 | public function generateWithDimensions(ImageInterface $image, Dimensions $dimensions)
56 | {
57 | $transformation = $this->configuration->getDefaultTransformation();
58 |
59 | return $this->generateFor($image, $transformation->withDimensions($dimensions));
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Block/Adminhtml/System/Config/Form/Field/ColorPicker.php:
--------------------------------------------------------------------------------
1 | getElementHtml();
18 | $value = $element->getData('value');
19 |
20 | $html .= '';
40 |
41 | return $html;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Model/ProductImageFinder.php:
--------------------------------------------------------------------------------
1 | imageCreator = $imageCreator;
29 | }
30 |
31 | /**
32 | * @param Product $product
33 | *
34 | * @return \Cloudinary\Cloudinary\Core\Image[]
35 | */
36 | public function findNewImages(Product $product)
37 | {
38 | return $this->find($product, new NewImageFilter());
39 | }
40 |
41 | /**
42 | * @param Product $product
43 | *
44 | * @return \Cloudinary\Cloudinary\Core\Image[]
45 | */
46 | public function findDeletedImages(Product $product)
47 | {
48 | return $this->find($product, new DeletedImageFilter());
49 | }
50 |
51 | /**
52 | * @param Product $product
53 | * @param ImageFilter $filter
54 | *
55 | * @return \Cloudinary\Cloudinary\Core\Image[]
56 | */
57 | private function find(Product $product, ImageFilter $filter)
58 | {
59 | return array_map(
60 | $this->imageCreator,
61 | array_filter(
62 | $product->getMediaGallery('images') ?: [],
63 | $filter
64 | )
65 | );
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/view/adminhtml/requirejs-config.js:
--------------------------------------------------------------------------------
1 | var config = {
2 | map: {
3 | '*': {
4 | cloudinaryFreeTransform: 'Cloudinary_Cloudinary/js/cloudinary-free',
5 | newVideoDialog: 'Cloudinary_Cloudinary/js/new-video-dialog',
6 | 'Magento_ProductVideo/js/get-video-information': 'Cloudinary_Cloudinary/js/get-video-information',
7 | cloudinaryMediaLibraryModal: 'Cloudinary_Cloudinary/js/cloudinary-media-library-modal',
8 | cloudinarySpinsetModal: 'Cloudinary_Cloudinary/js/cloudinary-spinset-modal',
9 | cldspinsetDialog: 'Cloudinary_Cloudinary/js/cloudinary-spinset-dialog',
10 | productGallery: 'Cloudinary_Cloudinary/js/product-gallery',
11 | cloudinaryLazyload: 'Cloudinary_Cloudinary/js/cloudinary-lazyload',
12 | updateCmsImages: 'Cloudinary_Cloudinary/js/cms/preview-update',
13 | 'Magento_PageBuilder/js/content-type/image/preview': 'Cloudinary_Cloudinary/js/content-type/image/preview',
14 | }
15 | },
16 | paths: {
17 | 'jquery.lazyload': "Cloudinary_Cloudinary/js/jquery.lazyload.min",
18 | cloudinaryMediaLibraryAll: "//media-library.cloudinary.com/global/all",
19 | es6Promise: "//cdnjs.cloudflare.com/ajax/libs/es6-promise/4.1.1/es6-promise.auto.min",
20 | 'uiComponent': 'Magento_Ui/js/core/app',
21 | },
22 | shim: {
23 | 'jquery.lazyload': {
24 | deps: ['jquery']
25 | },
26 | 'uiComponent': {
27 | deps: ['jquery']
28 | },
29 | 'Cloudinary_Cloudinary/js/cms/preview-update': {
30 | deps: ['jquery']
31 | }
32 | },
33 | config: {
34 | mixins: {
35 | 'Magento_Ui/js/lib/validation/validator': {
36 | 'Cloudinary_Cloudinary/js/form/element/validator-rules-mixin': true
37 | },
38 | }
39 | }
40 | };
41 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/PageBuilder/MediaGallery/Upload.php:
--------------------------------------------------------------------------------
1 | logger = $logger;
33 | }
34 |
35 | public function execute()
36 | {
37 | $resultJson = $this->resultFactory->create(ResultFactory::TYPE_JSON);
38 | try{
39 | $params = $this->getRequest()->getParams();
40 |
41 | } catch (NoSuchEntityException $e) {
42 | $responseCode = self::HTTP_OK;
43 | $responseContent = [];
44 | } catch (\Exception $e) {
45 | $responseCode = self::HTTP_INTERNAL_ERROR;
46 | $this->logger->critical($e);
47 | $responseContent = [
48 | 'success' => false,
49 | 'message' => __('An error occurred on attempt to retrieve asset information.'),
50 | ];
51 | }
52 |
53 | $resultJson->setHttpResponseCode($responseCode);
54 | $resultJson->setData($responseContent);
55 |
56 | return $resultJson;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Command/StopMigration.php:
--------------------------------------------------------------------------------
1 | objectManager = $objectManager;
34 | }
35 |
36 | /**
37 | * Configure the command
38 | *
39 | * @return void
40 | */
41 | protected function configure()
42 | {
43 | $this->setDescription('Stops any currently running upload/download.');
44 | }
45 |
46 | /**
47 | * @param InputInterface $input
48 | * @param OutputInterface $output
49 | *
50 | * @return int
51 | */
52 | protected function execute(InputInterface $input, OutputInterface $output)
53 | {
54 | $this->migrationTask = $this->objectManager
55 | ->get(\Cloudinary\Cloudinary\Model\MigrationTask::class);
56 |
57 | if ($this->migrationTask->hasStarted()) {
58 | $this->migrationTask->stop();
59 | $output->writeln(self::STOPPED_MESSAGE);
60 | } else {
61 | $output->writeln(self::NOP_MESSAGE);
62 | }
63 | return 1;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/view/adminhtml/web/template/product/free_transform.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Image
7 |
8 |
9 | Label
10 |
11 |
12 | File
13 |
14 |
15 | Cloudinary Transformation
16 |
17 |
18 | Action
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Product image transformations will be added to the the site-wide default image transformation options
30 | chosen from dropdowns on the Cloudinary config page. Product image transformations will override any
31 | free form transformation options that have been specified in the 'Global custom transform' field
32 | of the Cloudinary config page.
33 |
34 |
35 | For information about the full range of transforms available see the
36 | Cloudinary documentation .
37 |
38 |
39 | You may need to clear or rebuild the Magento block and full page caches to see the changes in the front end.
40 |
41 |
42 | Only images are listed - transforms to videos are not yet possible using the Magento module.
43 |
44 |
--------------------------------------------------------------------------------
/Block/Lazyload.php:
--------------------------------------------------------------------------------
1 | configuration = $configuration;
34 | $this->jsonEncoder = $jsonEncoder;
35 | parent::__construct($context, $data);
36 | }
37 |
38 | /**
39 | * @method isEnabledLazyload
40 | * @return boolean
41 | */
42 | public function isEnabledLazyload()
43 | {
44 | return $this->configuration->isEnabled() && $this->configuration->isEnabledLazyload();
45 | }
46 |
47 | /**
48 | * @method getLazyloadOptions
49 | * @param boolean $json
50 | * @return string|array
51 | */
52 | public function getLazyloadOptions($json = true)
53 | {
54 | $options = [
55 | 'threshold' => $this->configuration->getLazyloadThreshold(),
56 | 'effect' => $this->configuration->getLazyloadEffect(),
57 | 'placeholder' => $this->configuration->getLazyloadPlaceholder(),
58 | ];
59 | return $json ? $this->jsonEncoder->encode($options) : $options;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Core/AutoUploadMapping/RequestProcessor.php:
--------------------------------------------------------------------------------
1 | configuration = $configuration;
26 | $this->apiClient = $apiClient;
27 | }
28 |
29 | /**
30 | * @param string $folder
31 | * @param string $url
32 | * @param bool $force
33 | * @return bool
34 | */
35 | public function handle($folder, $url, $force = false)
36 | {
37 | if ($this->configuration->isActive() == $this->configuration->getRequestState() && !$force) {
38 | return true;
39 | }
40 |
41 | if ($this->configuration->getRequestState() == AutoUploadConfigurationInterface::ACTIVE) {
42 | return $this->handleActiveRequest($folder, $url);
43 | }
44 |
45 | $this->configuration->setState(AutoUploadConfigurationInterface::INACTIVE);
46 |
47 | return true;
48 | }
49 |
50 | /**
51 | * @param string $folder
52 | * @param string $url
53 | * @return bool
54 | */
55 | private function handleActiveRequest($folder, $url)
56 | {
57 | $result = $this->apiClient->prepareMapping($folder, $url);
58 |
59 | if ($result) {
60 | $this->configuration->setState(AutoUploadConfigurationInterface::ACTIVE);
61 | } else {
62 | $this->configuration->setRequestState(AutoUploadConfigurationInterface::INACTIVE);
63 | }
64 |
65 | return $result;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Model/Observer/UploadProductImage.php:
--------------------------------------------------------------------------------
1 | productImageFinder = $productImageFinder;
31 | $this->cloudinaryImageManager = $cloudinaryImageManager;
32 | }
33 |
34 | /**
35 | * @param Observer $observer
36 | */
37 | public function execute(Observer $observer)
38 | {
39 | $product = $observer->getEvent()->getProduct();
40 |
41 | foreach ($this->productImageFinder->findNewImages($product) as $image) {
42 | if (!$this->isCloudinaryImage($image)) {
43 | $this->cloudinaryImageManager->uploadAndSynchronise($image);
44 | }
45 | }
46 | }
47 | /**
48 | * Check if image sourced from Cloudinary media
49 | * @param $image
50 | * return bool
51 | */
52 | protected function isCloudinaryImage($image)
53 | {
54 | $file = $image->getRelativePath();
55 |
56 | // Skip if it's our known placeholder
57 | if (strpos($file, 'cloudinary_placeholder.jpg') !== false) {
58 | return true;
59 | }
60 |
61 | return strpos($file, 'c/l/cld_') !== false;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/view/adminhtml/templates/browser/content.phtml:
--------------------------------------------------------------------------------
1 |
12 | getCloudinaryMediaLibraryWidgetOptions();
14 | ?>
15 |
16 |
45 |
--------------------------------------------------------------------------------
/Api/ProductGalleryManagementInterface.php:
--------------------------------------------------------------------------------
1 | cloudinaryImageManager = $cloudinaryImageManager;
42 | $this->mediaDirectory = $filesystem->getDirectoryRead(DirectoryList::MEDIA);
43 | $this->configuration = $configuration;
44 | }
45 |
46 | /**
47 | * Delete file (and its thumbnail if exists) from storage
48 | *
49 | * @param string $target File path to be deleted
50 | * @return $this
51 | */
52 | public function beforeDeleteFile(Storage $storage, $target)
53 | {
54 | if (!$this->configuration->isEnabled() || !$this->configuration->hasEnvironmentVariable()) {
55 | return [$target];
56 | }
57 |
58 | $this->cloudinaryImageManager->removeAndUnSynchronise(
59 | Image::fromPath($target, $this->mediaDirectory->getRelativePath($target))
60 | );
61 |
62 | return [$target];
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Command/ProductGalleryApiQueueProcess.php:
--------------------------------------------------------------------------------
1 | objectManager = $objectManager;
40 | $this->appState = $appState;
41 | }
42 |
43 | /**
44 | * Configure the command
45 | *
46 | * @return void
47 | */
48 | protected function configure()
49 | {
50 | $this->setName('cloudinary:product-gallery-api-queue:process');
51 | $this->setDescription('Process queued items for product gallery API');
52 | }
53 |
54 | /**
55 | * @param InputInterface $input
56 | * @param OutputInterface $output
57 | *
58 | * @return void
59 | */
60 | protected function execute(InputInterface $input, OutputInterface $output)
61 | {
62 | $this->job = $this->objectManager
63 | ->get(\Cloudinary\Cloudinary\Cron\ProductGalleryApiQueue::class);
64 |
65 | $this->appState->setAreaCode(\Magento\Framework\App\Area::AREA_CRONTAB);
66 | return $this->job
67 | ->setOutput($output)
68 | ->execute();
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/Block/Adminhtml/Form/Field/Free.php:
--------------------------------------------------------------------------------
1 | configuration = $configuration;
37 | $this->model = $model;
38 |
39 | parent::__construct($context, $data);
40 | }
41 |
42 | /**
43 | * @return $this
44 | */
45 | protected function _beforeToHtml()
46 | {
47 | $this->setTemplate('Cloudinary_Cloudinary::config/free.phtml');
48 | return $this;
49 | }
50 |
51 | public function isCanPreviewTransformations() {
52 | return $this->_scopeConfig->getValue(self::XML_PATH_GLOBAL_TRANSFORMATION);
53 | }
54 |
55 | /**
56 | * @param AbstractElement $element
57 | * @return string
58 | */
59 | protected function _getElementHtml(AbstractElement $element)
60 | {
61 | return sprintf(
62 | '%s%s',
63 | $element->getElementHtml(),
64 | $this->model->hasAccountConfigured() ? $this->toHtml() : ''
65 | );
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/view/adminhtml/ui_component/media_gallery_listing.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
10 |
11 | -
12 |
-
13 | media_gallery_listing.media_gallery_listing_data_source
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | media_gallery_columns
22 |
23 | media_gallery_listing.media_gallery_listing_data_source
24 |
25 |
26 |
27 |
28 |
29 | Overlay
30 | true
31 | false
32 |
33 |
34 |
35 |
36 | -
37 |
38 | - adobe_stock_images_listing.adobe_stock_images_listing.adobe_stock_images_columns.preview
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/Model/AutoUploadMapping/AutoUploadConfiguration.php:
--------------------------------------------------------------------------------
1 | configReader = $configReader;
35 | $this->configWriter = $configWriter;
36 | }
37 |
38 | /**
39 | * @return bool
40 | */
41 | public function isActive()
42 | {
43 | return $this->configReader->isSetFlag(self::STATE_PATH);
44 | }
45 |
46 | /**
47 | * @param bool $state
48 | */
49 | public function setState($state)
50 | {
51 | $this->setFlag(self::STATE_PATH, $state);
52 | }
53 |
54 | /**
55 | * @return bool
56 | */
57 | public function getRequestState()
58 | {
59 | return $this->configReader->isSetFlag(self::REQUEST_PATH);
60 | }
61 |
62 | /**
63 | * @param bool $state
64 | */
65 | public function setRequestState($state)
66 | {
67 | $this->setFlag(self::REQUEST_PATH, $state);
68 | }
69 |
70 | /**
71 | * @param string $key
72 | * @param bool $state
73 | */
74 | private function setFlag($key, $state)
75 | {
76 | $this->configWriter->save($key, $state ? self::CONFIG_TRUE : self::CONFIG_FALSE);
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/view/adminhtml/templates/config/auto-upload-mapping-btn.phtml:
--------------------------------------------------------------------------------
1 |
7 | = /* @noEscape */ $block->getButtonHtml() ?>
8 |
9 |
10 | isEnabled()): ?>
11 |
42 |
43 | = $escaper->escapeHtmlAttr( __('This button would be available after enabling the module with a valid environment variable.')) ?>
44 |
45 |
--------------------------------------------------------------------------------
/Ui/Component/Control/AddFromCloudinary.php:
--------------------------------------------------------------------------------
1 | images = $images;
38 | $this->authorization = $authorization;
39 | $this->cmsWysiwygImages = $cmsWysiwygImages;
40 | }
41 | /**
42 | * @inheritdoc
43 | */
44 | public function getButtonData(): array
45 | {
46 | $cloudinaryMLwidgetOprions = ($this->images->getCloudinaryMediaLibraryWidgetOptions())
47 | ? json_decode($this->images->getCloudinaryMediaLibraryWidgetOptions(),true)
48 | : null;
49 |
50 | $buttonData = [
51 | 'label' => __('Add From Cloudinary'),
52 | 'class' => 'action-secondary add-from-cloudinary-button cloudinary-button-with-logo lg-margin-bottom',
53 | 'on_click' => 'return false;',
54 | 'data_attribute' => [
55 | 'mage-init' => ['cloudinaryMediaLibraryModal' => $cloudinaryMLwidgetOprions],
56 | 'role' => 'add-from-cloudinary-button',
57 |
58 | ],
59 | 'sort_order' => 200,
60 | ];
61 |
62 | if (!$this->authorization->isAllowed(self::ACL_UPLOAD_ASSETS)) {
63 | $buttonData['disabled'] = 'disabled';
64 | }
65 |
66 | return $buttonData;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/Helper/Reset.php:
--------------------------------------------------------------------------------
1 | connection = $connection;
37 | $this->synchronisation = $synchronisation;
38 | $this->transformation = $transformation;
39 | }
40 |
41 | public function resetModule()
42 | {
43 | $this->truncate($this->synchronisationTableName());
44 | $this->truncate($this->transformationTableName());
45 | $this->removeConfig();
46 | }
47 |
48 | /**
49 | * @return string
50 | */
51 | private function synchronisationTableName()
52 | {
53 | return $this->connection->getTableName($this->synchronisation->getMainTable());
54 | }
55 |
56 | /**
57 | * @return string
58 | */
59 | private function transformationTableName()
60 | {
61 | return $this->connection->getTableName($this->transformation->getMainTable());
62 | }
63 |
64 | /**
65 | * @param string $tableName
66 | */
67 | private function truncate($tableName)
68 | {
69 | $this->connection->getConnection()->query(sprintf('TRUNCATE %s', $tableName));
70 | }
71 |
72 | /**
73 | * @return string
74 | */
75 | private function configTableName()
76 | {
77 | return $this->connection->getTableName('core_config_data');
78 | }
79 |
80 | private function removeConfig()
81 | {
82 | $this->connection->getConnection()->delete(
83 | $this->configTableName(),
84 | "path LIKE 'cloudinary/%'"
85 | );
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/view/base/web/js/cloudinary-lazyload.js:
--------------------------------------------------------------------------------
1 | define([
2 | 'jquery',
3 | 'jquery.lazyload'
4 | ], function($) {
5 | 'use strict';
6 |
7 | $.widget('mage.cloudinaryLazyload', {
8 |
9 | options: {
10 | threshold: 500,
11 | failure_limit: 0,
12 | event: "scroll",
13 | effect: "fadeIn",
14 | data_attribute: "original",
15 | skip_invisible: true,
16 | appear: null,
17 | load: null,
18 | placeholder: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC"
19 | },
20 |
21 | /**
22 | * @private
23 | */
24 | _create: function() {
25 | this._super();
26 | this.initialize();
27 | },
28 |
29 | initialize: function(options) {
30 | var widget = this;
31 | options = $.extend({}, widget.options, options || {});
32 | this.cldLazyloadInit(options);
33 | setInterval(function() {
34 | widget.cldLazyloadInit(options);
35 | }, 4000);
36 | },
37 |
38 | cldLazyloadInit: function(options) {
39 | if ($(".cloudinary-lazyload").length) {
40 | var widget = this;
41 | try {
42 | $(".cloudinary-lazyload").lazyload(options || widget.options);
43 | $(".cloudinary-lazyload").addClass("cloudinary-lazyload-processed").removeClass("cloudinary-lazyload");
44 | } catch (err) {
45 | console.warn("Notice: An error occured while initializing Lazyload (" + err + "). Trying to fix automatically...");
46 | $(".cloudinary-lazyload").each(function() {
47 | if ($(this).is("img") || $(this).is("iframe")) {
48 | $(this).attr("src", $(this).attr("data-original"));
49 | } else {
50 | $(this).css("background-image", "url('" + $(this).attr("data-original") + "')");
51 | }
52 | $(this).addClass("cloudinary-lazyload-processed").removeClass("cloudinary-lazyload");
53 | });
54 | }
55 | }
56 |
57 | }
58 |
59 | });
60 |
61 | return $.mage.cloudinaryLazyload;
62 | });
--------------------------------------------------------------------------------
/view/adminhtml/web/js/form/element/validator-rules-mixin.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright © Magento, Inc. All rights reserved.
3 | * See COPYING.txt for license details.
4 | */
5 |
6 | define([
7 | 'jquery',
8 | 'underscore',
9 | 'Magento_Ui/js/lib/validation/utils'
10 | ], function($, _, utils) {
11 | 'use strict';
12 |
13 | /**
14 | * Validate that string is url
15 | * @param {String} href
16 | * @return {Boolean}
17 | */
18 | function validateIsUrl(href) {
19 | return (/^(http|https|ftp):\/\/(([A-Z0-9]([A-Z0-9_-]*[A-Z0-9]|))(\.[A-Z0-9]([A-Z0-9_-]*[A-Z0-9]|))*)(:(\d+))?(\/[A-Z0-9~](([A-Z0-9_~-]|\.)*[A-Z0-9~]|))*\/?(.*)?$/i).test(href); //eslint-disable-line max-len
20 | }
21 |
22 | return function(validator) {
23 |
24 | validator.addRule(
25 | 'validate-video-url',
26 | function(href) {
27 | if (utils.isEmptyNoTrim(href)) {
28 | return true;
29 | }
30 |
31 | href = (href || '').replace(/^\s+/, '').replace(/\s+$/, '');
32 |
33 | return validateIsUrl(href) && (
34 | href.match(/youtube\.com|youtu\.be/) ||
35 | href.match(/vimeo\.com/) ||
36 | href.match(/cloudinary/) ||
37 | href.match(/\.(mp4|ogv|webm)(?!\w)/)
38 | );
39 | },
40 | $.mage.__('Please enter a valid video URL. Valid URLs have a video file extension (.mp4, .webm, .ogv) or links to videos on YouTube, Vimeo or Cloudinary.')//eslint-disable-line max-len
41 | );
42 |
43 | validator.addRule(
44 | 'validate-video-source',
45 | function (href) {
46 | if (utils.isEmptyNoTrim(href)) {
47 | return true;
48 | }
49 |
50 | href = (href || '').replace(/^\s+/, '').replace(/\s+$/, '');
51 |
52 | return validateIsUrl(href) && (
53 | href.match(/youtube\.com|youtu\.be/) ||
54 | href.match(/vimeo\.com/) ||
55 | href.match(/cloudinary/) ||
56 | href.match(/\.(mp4|ogv|webm)(?!\w)/)
57 | );
58 | },
59 | $.mage.__('Please enter a valid video URL. Valid URLs have a video file extension (.mp4, .webm, .ogv) or links to videos on YouTube, Vimeo or Cloudinary.')//eslint-disable-line max-len
60 | );
61 |
62 | return validator;
63 | };
64 | });
65 |
--------------------------------------------------------------------------------
/Helper/Product/Free.php:
--------------------------------------------------------------------------------
1 | freeModel = $freeModel;
29 | $this->configuration = $configuration;
30 | }
31 |
32 | /**
33 | * @param string $imageName
34 | * @param string $transform
35 | */
36 | public function validate($imageName, $transform)
37 | {
38 | $transformation = $this->configuration
39 | ->getDefaultTransformation()
40 | ->withFreeform(Freeform::fromString($transform));
41 |
42 | $this->freeModel->validate($this->freeModel->namedImageUrl($imageName, $transformation));
43 | }
44 |
45 | /**
46 | * @param string $id
47 | * @param array $images
48 | * @return string
49 | */
50 | public function getImageNameForId($id, array $images)
51 | {
52 | return array_key_exists($id, $images) ? $images[$id]['file'] : '';
53 | }
54 |
55 | /**
56 | * @param Product $product
57 | * @return array
58 | */
59 | public function getMediaGalleryImages(Product $product)
60 | {
61 | $mediaGallery = $product->getMediaGallery();
62 |
63 | if (!$mediaGallery || !array_key_exists('images', $mediaGallery)) {
64 | return [];
65 | }
66 |
67 | return $mediaGallery['images'];
68 | }
69 |
70 | /**
71 | * @param array|null $data
72 | * @param array|null $isUpdated
73 | * @return array
74 | */
75 | public function filterUpdated($data, $isUpdated)
76 | {
77 | if (!is_array($data) || !is_array($isUpdated)) {
78 | return [];
79 | }
80 |
81 | return array_filter(
82 | $data,
83 | function ($id) use ($isUpdated) {
84 | return $isUpdated[$id] === '1';
85 | },
86 | ARRAY_FILTER_USE_KEY
87 | );
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/Core/Security/CloudinaryEnvironmentVariable.php:
--------------------------------------------------------------------------------
1 | environmentVariable = (string)$environmentVariable;
28 | try {
29 | //Cloudinary::config_from_url(str_replace('CLOUDINARY_URL=', '', $environmentVariable));
30 | $this->environmentVariable = str_replace('CLOUDINARY_URL=', '', $environmentVariable);
31 | } catch (\Exception $e) {
32 | throw new \Cloudinary\Cloudinary\Core\Exception\InvalidCredentials('Cloudinary config creation from environment variable failed');
33 | }
34 | }
35 |
36 | /**
37 | * @param $environmentVariable
38 | * @return CloudinaryEnvironmentVariable
39 | * @throws Cloudinary\Core\Exception\InvalidCredentials
40 | */
41 | public static function fromString($environmentVariable)
42 | {
43 | return new CloudinaryEnvironmentVariable($environmentVariable);
44 | }
45 |
46 | /**
47 | * @return string
48 | */
49 | public function getCloud()
50 | {
51 | if (!$this->configuration) {
52 | if (!$this->environmentVariable) {
53 | return false;
54 | }
55 | $this->configuration = new Configuration($this->environmentVariable);
56 | }
57 | return $this->configuration->cloud->cloudName;
58 | }
59 |
60 | /**
61 | * @return Credentials
62 | */
63 | public function getCredentials()
64 | {
65 | if (!$this->configuration) {
66 | $this->configuration = new Configuration($this->environmentVariable);
67 | }
68 |
69 | return Credentials::fromKeyAndSecret(
70 | Key::fromString($this->configuration->cloud->apiKey),
71 | Secret::fromString($this->configuration->cloud->apiSecret)
72 | );
73 | }
74 |
75 | /**
76 | * @return array|string|string[]
77 | */
78 | public function __toString()
79 | {
80 | return $this->environmentVariable;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/view/adminhtml/web/js/cloudinary-spinset-dialog.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright © Magento, Inc. All rights reserved.
3 | * See COPYING.txt for license details.
4 | */
5 | define(
6 | [
7 | 'jquery',
8 | 'underscore',
9 | 'jquery/ui',
10 | 'Magento_Ui/js/modal/modal',
11 | 'mage/translate',
12 | 'mage/backend/tree-suggest',
13 | 'mage/backend/validation'
14 | ],
15 | function($, _) {
16 | 'use strict';
17 |
18 | $.widget('mage.newCldSpinsetDialog', {
19 | /**
20 | * Build widget
21 | *
22 | * @private
23 | */
24 | _create: function() {
25 | var widget = this;
26 |
27 | this.element.modal({
28 | type: 'slide',
29 | //appendTo: this._gallery,
30 | modalClass: 'cldspinset-dialog form-inline',
31 | title: $.mage.__('Add Spinset from Cloudinary'),
32 | buttons: [{
33 | text: $.mage.__('Save'),
34 | class: 'action-primary video-create-button',
35 | click: $.proxy(widget._onCreate, widget)
36 | },
37 | {
38 | text: $.mage.__('Cancel'),
39 | class: 'video-cancel-button',
40 | click: $.proxy(widget._onCancel, widget)
41 | }
42 | ],
43 |
44 | /**
45 | * @returns {null}
46 | */
47 | opened: function() {
48 | console.log('cldspinset opened');
49 | },
50 |
51 | /**
52 | * Closed
53 | */
54 | closed: function() {
55 | console.log('cldspinset closed');
56 | }
57 | });
58 | },
59 |
60 | /**
61 | * Fired when click on create video
62 | *
63 | * @private
64 | */
65 | _onCreate: function() {
66 | console.log('_onCreate');
67 | },
68 |
69 | /**
70 | * Fired when click on create video
71 | *
72 | * @private
73 | */
74 | _onCancel: function() {
75 | console.log('_onCancel');
76 | }
77 | });
78 |
79 | return $.mage.newCldSpinsetDialog;
80 | }
81 | );
--------------------------------------------------------------------------------
/Block/Adminhtml/System/Config/AutoUploadMapping.php:
--------------------------------------------------------------------------------
1 | configuration = $configuration;
34 | parent::__construct($context, $data);
35 | }
36 |
37 | /**
38 | * Remove scope label
39 | *
40 | * @param AbstractElement $element
41 | * @return string
42 | */
43 | public function render(AbstractElement $element)
44 | {
45 | $element->unsScope()->unsCanUseWebsiteValue()->unsCanUseDefaultValue();
46 | return parent::render($element);
47 | }
48 |
49 | /**
50 | * Return element html
51 | *
52 | * @param AbstractElement $element
53 | * @return string
54 | */
55 | protected function _getElementHtml(AbstractElement $element)
56 | {
57 | return $this->_toHtml();
58 | }
59 |
60 | /**
61 | * Return ajax url for collect button
62 | *
63 | * @return string
64 | */
65 | public function getAjaxUrl()
66 | {
67 | return $this->getUrl('cloudinary/ajax_system_config/autoUploadMapping');
68 | }
69 |
70 | /**
71 | * @return bool
72 | */
73 | public function isEnabled()
74 | {
75 | return $this->configuration->isEnabled();
76 | }
77 |
78 | /**
79 | * Generate collect button html
80 | *
81 | * @return string
82 | */
83 | public function getButtonHtml()
84 | {
85 | $button = $this->getLayout()->createBlock(
86 | 'Magento\Backend\Block\Widget\Button'
87 | )->setData(
88 | [
89 | 'id' => 'auto-upload-mapping-btn',
90 | 'label' => __('Map media directory'),
91 | 'disabled' => !$this->configuration->isEnabled(),
92 | ]
93 | );
94 |
95 | return $button->toHtml();
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/Plugin/Config/Block/System/Config/Form/Field/Image.php:
--------------------------------------------------------------------------------
1 | escaper = $escaper;
47 | $this->jsonEncoder = $jsonEncoder;
48 | $this->mediaLibraryHelper = $mediaLibraryHelper;
49 | }
50 |
51 | /**
52 | * Get the Html for the element.
53 | *
54 | * @param \Magento\Config\Block\System\Config\Form\Field\Image $block
55 | * @param string $html
56 | * @return string
57 | */
58 | public function afterGetElementHtml(\Magento\Config\Block\System\Config\Form\Field\Image $block, $html)
59 | {
60 | // TODO: Add JS logics & handlers for after image insert
61 | if (($cloudinaryMLoptions = $this->mediaLibraryHelper->getCloudinaryMLOptions(false))) {
62 | $html .= 'jsonEncoder->encode(['cloudinaryMLoptions' => $cloudinaryMLoptions, 'cloudinaryMLshowOptions' => $this->mediaLibraryHelper->getCloudinaryMLshowOptions("image")]) . '}\'
67 | class="action-secondary add-from-cloudinary-button cloudinary-button-with-logo small-ver sm-top-bottom-margin">
68 | ' . $this->escaper->escapeHtml(__('Add from Cloudinary')) . '
69 | ';
70 | }
71 | return $html;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/view/base/web/template/form/element/uploader/uploader.html:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/Model/Observer/SaveProductTransform.php:
--------------------------------------------------------------------------------
1 | helper = $helper;
40 | $this->transformationFactory = $transformationFactory;
41 | $this->resourceConnection = $resourceConnection;
42 | }
43 |
44 | /**
45 | * @param Observer $observer
46 | */
47 | public function execute(Observer $observer)
48 | {
49 | $product = $observer->getProduct();
50 | $mediaGalleryImages = $this->helper->getMediaGalleryImages($product);
51 |
52 | $changedTransforms = $this->helper->filterUpdated(
53 | $product->getCloudinaryFreeTransform(),
54 | $product->getCloudinaryFreeTransformChanges()
55 | );
56 |
57 | foreach ($mediaGalleryImages as $gallItemId => $gallItem) {
58 | if (isset($gallItem['cldspinset']) && $gallItem['media_type'] === 'image') {
59 | $this->resourceConnection->getConnection()
60 | ->insertOnDuplicate($this->resourceConnection->getTableName('cloudinary_product_spinset_map'), [
61 | 'image_name' => $gallItem['file'],
62 | 'cldspinset' => $gallItem['cldspinset']
63 | ], ['image_name', 'cldspinset']);
64 | }
65 | }
66 | foreach ($changedTransforms as $id => $transform) {
67 | $this->storeFreeTransformation($this->helper->getImageNameForId($id, $mediaGalleryImages), $transform);
68 | }
69 |
70 | foreach ($changedTransforms as $id => $transform) {
71 | $this->helper->validate($this->helper->getImageNameForId($id, $mediaGalleryImages), $transform);
72 | }
73 | }
74 |
75 | /**
76 | * @param string $imageName
77 | * @param string $transform
78 | */
79 | private function storeFreeTransformation($imageName, $transform)
80 | {
81 | $this->transformationFactory->create()
82 | ->setImageName($imageName)
83 | ->setFreeTransformation($transform)
84 | ->save();
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/Model/Config/Backend/ProductGalleryCustomFreeParams.php:
--------------------------------------------------------------------------------
1 | 'No error',
20 | JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
21 | JSON_ERROR_STATE_MISMATCH => 'State mismatch (invalid or malformed JSON)',
22 | JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded',
23 | JSON_ERROR_SYNTAX => 'Syntax error',
24 | JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded'
25 | ];
26 |
27 | /**
28 | * @var ManagerInterface
29 | */
30 | private $messageManager;
31 |
32 | /**
33 | * Application config
34 | *
35 | * @var ScopeConfigInterface
36 | */
37 | protected $appConfig;
38 |
39 | public function __construct(
40 | Context $context,
41 | Registry $registry,
42 | ScopeConfigInterface $config,
43 | TypeListInterface $cacheTypeList,
44 | ManagerInterface $messageManager,
45 | ReinitableConfigInterface $appConfig,
46 | ?AbstractResource $resource = null,
47 | ?AbstractDb $resourceCollection = null,
48 | array $data = []
49 | ) {
50 | $this->messageManager = $messageManager;
51 | $this->appConfig = $appConfig;
52 |
53 | parent::__construct($context, $registry, $config, $cacheTypeList, $resource, $resourceCollection, $data);
54 | }
55 |
56 | public function beforeSave()
57 | {
58 | $rawValue = $this->getValue();
59 |
60 | parent::beforeSave();
61 |
62 | $this->cacheTypeList->cleanType(\Magento\Framework\App\Cache\Type\Config::TYPE_IDENTIFIER);
63 | $this->appConfig->reinit();
64 |
65 | if ($rawValue) {
66 | $data = json_decode($rawValue);
67 | if ($data === null || $data === false) {
68 | $this->setValue('{}');
69 | try {
70 | if (json_last_error() !== JSON_ERROR_NONE) {
71 | $this->messageManager->addError(self::BAD_JSON_ERROR_MESSAGE . ' (' . self::JSON_ERRORS[json_last_error()] . ')');
72 | }
73 | } catch (\Exception $e) {
74 | $this->messageManager->addError(self::BAD_JSON_ERROR_MESSAGE);
75 | }
76 | } else {
77 | $this->setValue(json_encode((array)$data));
78 | }
79 | } else {
80 | $this->setValue('{}');
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/etc/csp_whitelist.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | cloudinary.com
7 | *.cloudinary.com
8 | cdnjs.cloudflare.com
9 | *.youtube.com
10 | *.vimeo.com
11 | unpkg.com
12 |
13 |
14 |
15 |
16 | cloudinary.com
17 | *.cloudinary.com
18 | cdnjs.cloudflare.com
19 |
20 |
21 |
22 |
23 | cloudinary.com
24 | *.cloudinary.com
25 |
26 |
27 |
28 |
29 | cloudinary.com
30 | *.cloudinary.com
31 |
32 |
33 |
34 |
35 | cloudinary.com
36 | *.cloudinary.com
37 | data:
38 | blob:
39 |
40 |
41 |
42 |
43 | cloudinary.com
44 | *.cloudinary.com
45 | *.googleapis.com
46 | unpkg.com
47 |
48 |
49 |
50 |
51 | cloudinary.com
52 | *.cloudinary.com
53 |
54 |
55 |
56 |
57 | *.gstatic.com
58 | *.cloudinary.com
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Ajax/Free/Sample.php:
--------------------------------------------------------------------------------
1 | resultJsonFactory = $resultJsonFactory;
46 | $this->model = $model;
47 | $this->configuration = $configuration;
48 |
49 | parent::__construct($context);
50 | }
51 |
52 | public function execute()
53 | {
54 | $result = $this->resultJsonFactory->create();
55 |
56 | try {
57 | $this->validateAjaxRequest();
58 | $this->validateAccountConfigured();
59 |
60 | $url = $this->model->sampleImageUrl(
61 | $this->defaultTransformWithFreeTransform($this->getRequest()->getParam('free'))
62 | );
63 |
64 | $this->model->validate($url);
65 |
66 | return $result->setData(['url' => $url]);
67 | } catch (\Exception $e) {
68 | return $result->setHttpResponseCode(400)->setData(['error' => $e->getMessage()]);
69 | }
70 | }
71 |
72 | /**
73 | * @param string $freeTransform
74 | * @return Transformation
75 | */
76 | private function defaultTransformWithFreeTransform($freeTransform)
77 | {
78 | return $this->configuration->getDefaultTransformation()
79 | ->withFreeform(Freeform::fromString($freeTransform), false);
80 | }
81 |
82 | /**
83 | * @throws \Exception
84 | */
85 | private function validateAjaxRequest()
86 | {
87 | if (!$this->getRequest()->isAjax()) {
88 | throw new \Exception(self::NON_AJAX_REQUEST);
89 | }
90 | }
91 |
92 | /**
93 | * @throws \Exception
94 | */
95 | private function validateAccountConfigured()
96 | {
97 | if (!$this->model->hasAccountConfigured()) {
98 | throw new \Exception(self::MISSING_ACCOUNT_DETAILS);
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/view/frontend/templates/product/image_with_borders.phtml:
--------------------------------------------------------------------------------
1 |
7 | getVar('product_image_white_borders', 'Magento_Catalog');
17 | $enableLazyLoadingWithoutBorders = (bool)$block->getVar(
18 | 'enable_lazy_loading_for_images_without_borders',
19 | 'Magento_Catalog'
20 | );
21 | $width = (int)$block->getWidth();
22 | $paddingBottom = $block->getRatio() * 100;
23 | ?>
24 |
25 |
26 | getCustomAttributes() as $name => $value): ?>
28 | = $escaper->escapeHtmlAttr($name) ?>="= $escaper->escapeHtmlAttr($value) ?>"
29 |
30 | src="= /* @noEscape */ $block->getLazyloadPlaceholder() ?>"
31 | data-original="= $escaper->escapeUrl($block->getImageUrl()) ?>"
32 |
33 | width="= $escaper->escapeHtmlAttr($block->getWidth()) ?>"
34 | height="= $escaper->escapeHtmlAttr($block->getHeight()) ?>"
35 |
36 | max-width="= $escaper->escapeHtmlAttr($block->getWidth()) ?>"
37 | max-height="= $escaper->escapeHtmlAttr($block->getHeight()) ?>"
38 |
39 | alt="= $escaper->escapeHtmlAttr($block->getLabel()) ?>"/>
40 |
41 | getProductId()} {
44 | width: {$width}px;
45 | }
46 | .product-image-container-{$block->getProductId()} span.product-image-wrapper {
47 | padding-bottom: {$paddingBottom}%;
48 | }
49 | STYLE;
50 | //In case a script was using "style" attributes of these elements
51 | $script = <<