22
33namespace Cloudinary \Cloudinary \Plugin \Catalog \Block \Category ;
44
5- use Magento \Catalog \ViewModel \Category \Image as CategoryImageViewModel ;
65use Cloudinary \Asset \Media ;
76use Cloudinary \Cloudinary \Core \ConfigurationInterface ;
87use Cloudinary \Cloudinary \Core \ConfigurationBuilder ;
98use Cloudinary \Cloudinary \Core \Image \Transformation ;
109use Cloudinary \Configuration \Configuration ;
11- use Magento \Framework \View \Element \Block \ArgumentInterface ;
1210use Magento \Catalog \Model \Category ;
1311use Cloudinary \Cloudinary \Core \Image as CoreImage ;
1412use Cloudinary \Cloudinary \Model \ResourceModel \MediaLibraryMap \CollectionFactory as MediaLibraryMapCollectionFactory ;
13+ use Magento \Catalog \ViewModel \Category \Image as CategoryImageViewModel ;
1514
1615class Image
1716{
17+ /**
18+ * @var ConfigurationInterface
19+ */
1820 protected $ configuration ;
21+
22+ /**
23+ * @var ConfigurationBuilder
24+ */
1925 protected $ configurationBuilder ;
26+
27+ /**
28+ * @var Transformation
29+ */
2030 protected $ transformation ;
31+
32+ /**
33+ * @var MediaLibraryMapCollectionFactory
34+ */
2135 protected $ mediaLibraryMapCollectionFactory ;
2236
37+ /**
38+ * @var bool
39+ */
2340 private $ authorised = false ;
2441
42+ /**
43+ * @param ConfigurationInterface $configuration
44+ * @param ConfigurationBuilder $configurationBuilder
45+ * @param Transformation $transformation
46+ * @param MediaLibraryMapCollectionFactory $mediaLibraryMapCollectionFactory
47+ */
2548 public function __construct (
2649 ConfigurationInterface $ configuration ,
2750 ConfigurationBuilder $ configurationBuilder ,
@@ -34,6 +57,11 @@ public function __construct(
3457 $ this ->mediaLibraryMapCollectionFactory = $ mediaLibraryMapCollectionFactory ;
3558 }
3659
60+ /**
61+ * Authorize Cloudinary configuration
62+ *
63+ * @return void
64+ */
3765 protected function authorise ()
3866 {
3967 if (!$ this ->authorised && $ this ->configuration ->isEnabled ()) {
@@ -44,9 +72,19 @@ protected function authorise()
4472
4573 /**
4674 * Plugin after getUrl to return Cloudinary version
75+ *
76+ * For rendition images (.renditions/*) without local mapping, returns the local image URL.
77+ * For regular uploaded images, returns the Cloudinary URL.
78+ *
79+ * @param CategoryImageViewModel $subject
80+ * @param string $result
81+ * @param Category $category
82+ * @param string $attributeCode
83+ * @return string
84+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
4785 */
4886 public function afterGetUrl (
49- \ Magento \ Catalog \ ViewModel \ Category \ Image $ subject ,
87+ CategoryImageViewModel $ subject ,
5088 string $ result ,
5189 Category $ category ,
5290 string $ attributeCode = 'image '
@@ -59,40 +97,69 @@ public function afterGetUrl(
5997 }
6098
6199 try {
62- $ filename = preg_replace ('/\.[^.]+$/ ' , '' , ltrim ($ imagePath , '/ ' ));
63- $ publicId = null ;
64-
65- // Try to find mapping by searching cld_public_id with the filename pattern
66-
67- $ collection = $ this ->mediaLibraryMapCollectionFactory ->create ();
68- $ collection ->addFieldToFilter ('cld_public_id ' , ['like ' => '% ' . $ filename ]);
69-
70- if ($ collection ->getSize () > 0 ) {
71- $ mapping = $ collection ->getFirstItem ();
72- // Use exact public_id from mapping (already without extension)
73- $ publicId = $ mapping ->getData ('cld_public_id ' );
100+ $ imageId = ltrim ($ imagePath , '/ ' );
101+ $ isRenditionImage = strpos ($ imageId , '.renditions/ ' ) !== false ;
102+
103+ // Check if this is a rendition image (gallery selection or other rendition)
104+ // These images are stored locally and should not use Cloudinary unless there's a mapping
105+ if ($ isRenditionImage && !$ this ->configuration ->isEnabledLocalMapping ()) {
106+ // Local mapping not enabled - return local image URL for rendition images
107+ return $ result ;
74108 }
75109
76- // Fallback: construct public_id from imagePath (without extension)
77- if (!$ publicId ) {
78- if (preg_match ('/cld_[a-zA-Z0-9]+_/ ' , $ filename )) {
79- $ filename = preg_replace ('/cld_[a-zA-Z0-9]+_/ ' , '' , $ filename );
80- }
81- $ publicId = $ filename ;
82- }
110+ // Try to find mapping if local mapping is enabled
111+ if ($ this ->configuration ->isEnabledLocalMapping ()) {
112+ $ mappedPublicId = $ this ->getMappedPublicId ($ imageId );
113+ if ($ mappedPublicId ) {
114+ // If it's a full URL, return it directly
115+ if (preg_match ('/https?:\/\//i ' , $ mappedPublicId )) {
116+ return $ mappedPublicId ;
117+ }
118+ $ imageId = $ mappedPublicId ;
119+ } elseif ($ isRenditionImage ) {
120+ // Rendition image without mapping - return local image URL
121+ return $ result ;
122+ }
123+ }
83124
84- $ asset = Media::fromParams ($ publicId , [
125+ // Generate Cloudinary URL using the imageId
126+ $ imagePath = Media::fromParams ($ imageId , [
85127 'transformation ' => $ this ->transformation ->build (),
86128 'secure ' => true ,
87129 'sign_url ' => $ this ->configuration ->getUseSignedUrls (),
88130 'version ' => 1
89131 ]) . '?_i=AB ' ;
90132
91- $ image = CoreImage::fromPath ($ asset , '' );
133+ $ image = CoreImage::fromPath ($ imagePath , '' );
92134 return (string ) $ image ;
93135
94136 } catch (\Exception $ e ) {
95137 return $ result ; // fallback to original if Cloudinary fails
96138 }
97139 }
140+
141+ /**
142+ * Get mapped public ID from database
143+ *
144+ * @param string $imageId
145+ * @return string|null
146+ */
147+ private function getMappedPublicId ($ imageId )
148+ {
149+ preg_match ('/(cld_[A-Za-z0-9]{13}_).+$/i ' , $ imageId , $ cldUniqid );
150+ if (!$ cldUniqid || !isset ($ cldUniqid [1 ])) {
151+ return null ;
152+ }
153+
154+ $ mapped = $ this ->mediaLibraryMapCollectionFactory ->create ()
155+ ->addFieldToFilter ('cld_uniqid ' , $ cldUniqid [1 ])
156+ ->setPageSize (1 )
157+ ->getFirstItem ();
158+
159+ if ($ mapped && ($ origPublicId = $ mapped ->getCldPublicId ())) {
160+ return $ origPublicId ;
161+ }
162+
163+ return null ;
164+ }
98165}
0 commit comments