{"id":32763,"date":"2024-02-02T07:00:00","date_gmt":"2024-02-02T15:00:00","guid":{"rendered":"https:\/\/cloudinary.com\/blog\/?p=32763"},"modified":"2025-03-29T15:24:11","modified_gmt":"2025-03-29T22:24:11","slug":"editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms","title":{"rendered":"Editor-Friendly Image Transformation and Optimized Delivery With Cloudinary and Decap CMS"},"content":{"rendered":"\n<p class=\"has-text-align-center\"><strong><em>How and why you should empower editors with a simple interface to upload and transform images.<\/em><\/strong><\/p>\n\n\n\n<p>Content managers and editors need a simple, intuitive way of handling images in a content management system (CMS). They should also be able to upload, adjust, and remove assets without impacting site performance with bad transformations. As a safeguard, developers need to control the quality and size of the images delivered to the site.&nbsp;<\/p>\n\n\n\n<p>In this blog post, we\u2019ll explore how to set up a CMS that will allow editors to upload images and apply transformations, and for developers to control the quality and size of the delivered images.<\/p>\n\n\n\n<p>To achieve this, we\u2019ll use <a href=\"https:\/\/decapcms.org\/\">Decap CMS<\/a>, a git-based CMS that\u2019s easy to set up and configure. We\u2019ll also use <a href=\"https:\/\/cloudinary.com\/\">Cloudinary<\/a>, a digital asset management (DAM) solution to upload images and apply transformations to them. Finally, we\u2019ll use <a href=\"https:\/\/gohugo.io\/\">Hugo<\/a>, a static site generator, to build the site.<\/p>\n\n\n\n<p>In this blog post:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Using Hugo, A Static Site Generator<\/li>\n\n\n\n<li>Adding Decap CMS<\/li>\n\n\n\n<li>Decap Media Libraries<\/li>\n\n\n\n<li>Configuring the Cloudinary Widget<\/li>\n\n\n\n<li>Constructing Cloudinary Transformation URLs<\/li>\n\n\n\n<li>Caveats<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Using Hugo, a Static Site Generator<\/h2>\n\n\n\n<p>We need a front matter-based site generator and something to serve the CMS locally. We could also use Gatsby, Next.js, or any other <a href=\"https:\/\/jamstack.org\/generators\/\">site generator<\/a>. I like Hugo because it\u2019s extremely fast and makes the most out of vanilla HTML, JS, and CSS. That way, there is no need for a JS framework.<\/p>\n\n\n\n<p>If you don\u2019t have it yet, you need to <a href=\"https:\/\/gohugo.io\/getting-started\/quick-start\/\">install Hugo<\/a>. Then start with a blank Hugo site:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">hugo <span class=\"hljs-keyword\">new<\/span> site site-name\n\ncd site-name<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Adding Decap CMS<\/h2>\n\n\n\n<p>When choosing a CMS for a website with a lot of media, consider the media library and what you want from it. For more complex sites, I recommend using a dedicated image and video API, such as Cloudinary, which is what we\u2019ll use here. However, the default media library that comes with Decap CMS is sufficient for simple sites.<\/p>\n\n\n\n<p>Decap CMS is the most popular open-source git-based CMS. It\u2019s integrated with the Cloudinary Media Library widget and is easy to set up. Find more details at <a href=\"https:\/\/decapcms.org\/docs\/add-to-your-site\/\">Add Decap CMS to your site<\/a>.<\/p>\n\n\n\n<p>All we have to do to install Decap is add two files to our Hugo project. See the <a href=\"https:\/\/decapcms.org\/docs\/site-generator-overview\/\">Site Generator Overview<\/a> for details on other SSGs.<\/p>\n\n\n\n<p>Add <code>index.html<\/code> and <code>config.yml<\/code> to the static\/admin folder:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">static<\/span>\/admin\n\n\u251c index.html\n\n\u2514 config.yml<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><code>index.html<\/code> is the page that will serve the CMS React app.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-meta\">&lt;!doctype <span class=\"hljs-meta-keyword\">html<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">html<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">head<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">meta<\/span> <span class=\"hljs-attr\">charset<\/span>=<span class=\"hljs-string\">\"utf-8\"<\/span> \/&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">meta<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"viewport\"<\/span> <span class=\"hljs-attr\">content<\/span>=<span class=\"hljs-string\">\"width=device-width, initial-scale=1.0\"<\/span> \/&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">meta<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"robots\"<\/span> <span class=\"hljs-attr\">content<\/span>=<span class=\"hljs-string\">\"noindex\"<\/span> \/&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">title<\/span>&gt;<\/span>Content Manager<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">title<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">head<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">body<\/span>&gt;<\/span><span class=\"hljs-comment\">&lt;!-- Include the script that builds the page and powers Decap CMS --&gt;<\/span>\n\n\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">\"https:\/\/unpkg.com\/decap-cms@^3.0.0\/dist\/decap-cms.js\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">body<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">html<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><code>config.yml<\/code> is the configuration file for Decap CMS. We\u2019ll use the <a href=\"https:\/\/decapcms.org\/docs\/git-gateway-backend\/\">git-gateway backend<\/a>, which allows you to add editors to your site CMS without giving them direct write access to your GitHub or GitLab repository. We\u2019ll also use the <code>local_backend<\/code> option to run the CMS locally.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">local_backend: <span class=\"hljs-keyword\">true<\/span> <span class=\"hljs-comment\"># enables us to run cms locally<\/span>\n\nbackend:\n\n\u00a0name: git-gateway\n\n\u00a0branch: master <span class=\"hljs-comment\"># Branch to update (optional; defaults to master)<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Decap Media Libraries<\/h2>\n\n\n\n<p>Decap has a default media library that works with media in the repository. However, git isn\u2019t a good place to store media, so I recommend using a digital asset manager like Cloudinary. Decap\u2019s Cloudinary integration allows us to access our Cloudinary cloud from image widgets in the CMS and easily retrieve asset URLs in various forms. This is what we\u2019ll use here.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Enable Cloudinary<\/h3>\n\n\n\n<p>We just have to add these lines to the <code>config.yml<\/code> file:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs shcb-wrap-lines\">media_library:\n\n\u00a0name: cloudinary\n\n\u00a0config:\n\n\u00a0\u00a0\u00a0cloud_name: your_cloud_name\n\n\u00a0\u00a0\u00a0api_key: your_api_key<\/code><\/span><\/pre>\n\n\n<p>With this configured, the image widget opens the <a href=\"https:\/\/cloudinary.com\/documentation\/media_library_widget\">Cloudinary Media Library widget<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Decap Collections<\/h2>\n\n\n\n<p>Collections are the way to define content types in Decap CMS. We\u2019ll define a blog folder collection for this example. Here, we configure the CMS to save markdown files to the content\/blog folder, which the site generator can render as blog posts.<\/p>\n\n\n\n<p>config.yml<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">collections:\n\n\u00a0- name: blog <span class=\"hljs-comment\"># Used in routes, e.g., \/admin\/collections\/blog<\/span>\n\n\u00a0\u00a0\u00a0label: Blog <span class=\"hljs-comment\"># Used in the UI<\/span>\n\nlabel_singular: post\n\n\u00a0\u00a0\u00a0folder: content\/blog <span class=\"hljs-comment\"># The path to the folder where the documents are stored<\/span>\n\n\u00a0\u00a0\u00a0create: <span class=\"hljs-keyword\">true<\/span> <span class=\"hljs-comment\"># Allow users to create new documents in this collection<\/span>\n\n\u00a0\u00a0\u00a0fields: &#91; <span class=\"hljs-comment\"># The fields for each document, usually in front matter<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0{label: Title, name: title, widget: string},\n\n\u00a0\u00a0\u00a0\u00a0\u00a0{label: Featured Image, name: image, widget: image},\n\n\u00a0\u00a0\u00a0\u00a0\u00a0{label: Body, name: body, widget: markdown},\n\n\u00a0\u00a0\u00a0]<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now run Hugo and Decap locally with these commands in two parallel terminals:<\/p>\n\n\n\n<p><code>npx decap-server hugo server<\/code><\/p>\n\n\n\n<p>Open <code>http:\/\/localhost:1313\/admin\/#\/<\/code> to access the CMS and click <strong>New post<\/strong>.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img width=\"1043\" height=\"764\" data-public-id=\"Web_Assets\/blog\/image_32767578b7\/image_32767578b7.png\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_1043,h_764,c_scale\/f_auto,q_auto\/v1706906501\/Web_Assets\/blog\/image_32767578b7\/image_32767578b7.png?_i=AA\" alt=\"Blog post view\" class=\"wp-post-32763 wp-image-32767\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1706906501\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1706906501\/Web_Assets\/blog\/image_32767578b7\/image_32767578b7.png?_i=AA 1043w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1706906501\/Web_Assets\/blog\/image_32767578b7\/image_32767578b7.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1706906501\/Web_Assets\/blog\/image_32767578b7\/image_32767578b7.png?_i=AA 768w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1706906501\/Web_Assets\/blog\/image_32767578b7\/image_32767578b7.png?_i=AA 1024w\" sizes=\"auto, (max-width: 1043px) 100vw, 1043px\" \/><\/figure>\n\n\n\n<p>The image input will now open the Cloudinary Media Library widget if you click <strong>Choose an image<\/strong>. If you\u2019re not authenticated, you\u2019ll be prompted to log in. If you get the same site error, you can log in to Cloudinary in another tab and refresh the CMS.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img width=\"1043\" height=\"764\" data-public-id=\"Web_Assets\/blog\/image_32767578b7\/image_32767578b7.png\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_1043,h_764,c_scale\/f_auto,q_auto\/v1706906501\/Web_Assets\/blog\/image_32767578b7\/image_32767578b7.png?_i=AA\" alt=\"Blog post view\" class=\"wp-post-32763 wp-image-32766 wp-image-32767\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1706906501\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1706906501\/Web_Assets\/blog\/image_32767578b7\/image_32767578b7.png?_i=AA 1043w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1706906501\/Web_Assets\/blog\/image_32767578b7\/image_32767578b7.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1706906501\/Web_Assets\/blog\/image_32767578b7\/image_32767578b7.png?_i=AA 768w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1706906501\/Web_Assets\/blog\/image_32767578b7\/image_32767578b7.png?_i=AA 1024w\" sizes=\"(max-width: 1043px) 100vw, 1043px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Configuring the Cloudinary Widget<\/h2>\n\n\n\n<p><em>Taken from the <\/em><a href=\"https:\/\/decapcms.org\/docs\/cloudinary\/#decap-cms-configuration-options\"><em>Decap CMS docs on Cloudinary library<\/em><\/a><em>.<\/em><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>output_filename_only<\/code>: <em>(default: false)<br><\/em>By default, the value provided for a selected image is a complete URL for the asset on Cloudinary\u2019s CDN. Setting output_filename_only to true will instead produce just the filename (e.g., image.jpg). This should be true if you\u2019ll be directly embedding Cloudinary transformation URLs in page templates. Refer to <a href=\"https:\/\/mj-cld-posts.netlify.app\/blog\/post-1\/#inserting-cloudinary-url-in-page-templates\">Inserting Cloudinary URL in page templates<\/a>.<\/li>\n\n\n\n<li><code>use_transformations<\/code>: <em>(default: true)<br><\/em>If true, it uses the derived URL when available (the URL will include image transformation segments). It has no effect if output_filename_only is set to true.<\/li>\n\n\n\n<li><code>use_secure_url<\/code>: <em>(default: true)<br><\/em>Controls whether an http or https URL is provided. It has no effect if output_filename_only is set to true.<\/li>\n\n\n\n<li><code>config<\/code>\n<ul class=\"wp-block-list\">\n<li><code>cloud_name<\/code><\/li>\n\n\n\n<li><code>api_key<\/code><\/li>\n\n\n\n<li><code>multiple<\/code> has no impact on images inside the <a href=\"https:\/\/mj-cld-posts.netlify.app\/docs\/widgets\/#markdown\">markdown widget<\/a>. Refer to <a href=\"https:\/\/cloudinary.com\/documentation\/media_library_widget#3_set_the_configuration_options\">Media Library documentation<\/a> for details on this property.<\/li>\n\n\n\n<li><code>max_files<\/code> has no impact on images inside the <a href=\"https:\/\/mj-cld-posts.netlify.app\/docs\/widgets\/#markdown\">markdown widget<\/a>. Refer to <a href=\"https:\/\/cloudinary.com\/documentation\/media_library_widget#3_set_the_configuration_options\">Media Library documentation<\/a> for details on this property.<\/li>\n\n\n\n<li><code>default_transformations<\/code> requires only the first <a href=\"https:\/\/mj-cld-posts.netlify.app\/blog\/post-1\/#image-transformations\">image transformation<\/a> to be used. Be sure to use the SDK Parameter column transformation names from the <a href=\"https:\/\/cloudinary.com\/documentation\/image_transformation_reference\">transformation reference<\/a>.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\"># Global example<\/span>\n\nmedia_library:\n\n\u00a0name: cloudinary\n\n\u00a0output_filename_only: <span class=\"hljs-keyword\">false<\/span>\n\n\u00a0config:\n\n\u00a0\u00a0\u00a0cloud_name: your_cloud_name\n\n\u00a0\u00a0\u00a0api_key: your_api_key\n\n\u00a0\u00a0\u00a0multiple: <span class=\"hljs-keyword\">true<\/span>\n\n\u00a0\u00a0\u00a0max_files: <span class=\"hljs-number\">3<\/span>\n\n\u00a0\u00a0\u00a0default_transformations:\n\n\u00a0\u00a0\u00a0\u00a0\u00a0- - fetch_format: auto\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0width: <span class=\"hljs-number\">160<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0quality: auto\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0crop: scale\n\n<span class=\"hljs-comment\"># You can use all settings globally and per field.<\/span>\n\n<span class=\"hljs-comment\"># If no config is set for a field, the global config is used.<\/span>\n\n<span class=\"hljs-comment\"># Example field in a collection<\/span>\n\nfields:\n\n- name: <span class=\"hljs-string\">'image'<\/span>\n\n\u00a0widget: <span class=\"hljs-string\">'image'<\/span>\n\n\u00a0media_library:\n\n\u00a0\u00a0\u00a0config:\n\n\u00a0\u00a0\u00a0\u00a0\u00a0default_transformations:\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0- - fetch_format: auto\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0width: <span class=\"hljs-number\">300<\/span>\u00a0\u00a0\u00a0\u00a0\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0quality: auto\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0crop: fill\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0effect: grayscale<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Constructing Cloudinary Transformation URLs<\/h2>\n\n\n\n<p>This is where we\u2019re looking for a balance between editor control, UX simplicity, developer control, and performance. The more control we give to editors, the more we have to trust them to make the right decisions. The more we control layouts, the fewer options we leave to editors, but we can optimize for performance.<\/p>\n\n\n\n<p>In general, we have three options:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Construct URLs in layout with filename only.<\/li>\n\n\n\n<li>Allow editors to transform assets through the Cloudinary widget.<\/li>\n\n\n\n<li>Apply default transformations and allow editors to add their own.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">In the Layout<\/h3>\n\n\n\n<p>Set <code>output_filename_only: true<\/code> and construct the URL with transformations in your HTML layouts. This is the safest option, but it gives editors no control over the image. The problem is that it won\u2019t output the subfolder, so we\u2019d have to hardcode it. Normally, that isn\u2019t a good idea, as an editor might easily change the media library&#8217;s folder.<\/p>\n\n\n\n<p>To avoid that, you can also set <code>use_transformations: false<\/code> in config to omit editor-set transformations from URLs. You&#8217;ll then have to deconstruct the URL and add the transformations in the layout.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Through the Widget<\/h3>\n\n\n\n<p>This is the most flexible option, but it requires editors to know what they are doing. Nothing extra has to be set in config, as this is the default. Consider educating editors on how to apply the transformations.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">How to Transform Assets in the Widget<\/h4>\n\n\n\n<p>Apply transformations by clicking an asset to open the edit screen and use advanced editing.<\/p>\n\n\n\n<p>Edit transformations by clicking advanced editing, then view derived images, then edit.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">With Default Transformations<\/h3>\n\n\n\n<p>Decap will apply the transformation you defined in config to the chosen assets. If an editor adds their own transformations, they\u2019ll get chained. You can also prevent the editor from adding transformations by setting <code>use_transformations: false<\/code>.<\/p>\n\n\n\n<p>Chaining is maybe the best of both worlds if you use good default transformations. I recommend using a set of general optimizers, such as <code>c_fill<\/code> , <code>w_auto<\/code>, <code>g_auto<\/code>, <code>q_auto<\/code>, and <code>dpr_auto\/f_auto<\/code>. This will make sure that the image is correctly cropped, resized, optimized for the viewport, and served in the best format.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Enable Editors to Adjust for Mobile and Desktop<\/h3>\n\n\n\n<p>Sometimes editors want to serve different images for mobile and desktop. We can add an optional image field for mobile (or desktop if mobile is the default) and set the default as a fallback. This presents a bit more work for editors, but it\u2019s still easy to do.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Caveats<\/h2>\n\n\n\n<p>If you change default transformations after images are added, you\u2019ll have to go through all the images and reapply them. If you want to avoid that, consider adding the transformations to the layout.<\/p>\n\n\n\n<p>Although Cloudinary stores metadata for assets, Decap CMS only returns the URL. So, if you want to use alt or title, you have to add it as a field in the collection. Thankfully, there are <a href=\"https:\/\/github.com\/decaporg\/decap-cms\/issues\/6998\">plans to add this feature<\/a> in the future.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>Decap CMS plus Cloudinary is an excellent combination for an editor-friendly media editing experience. Developers can control the quality and size of the images delivered and give editors the amount of control they need.<\/p>\n\n\n\n<p>Discover the ease of building visually stunning, responsive websites with Cloudinary. Tailor your images to fit into any web framework, ensuring an engaging visual experience on every device. <a href=\"https:\/\/cloudinary.com\/users\/register_free\">Join Cloudinary for free<\/a> today and bring versatility and responsiveness to your images with just a few clicks.<\/p>\n\n\n\n<p>Tune in for Part 2, where we\u2019ll explore how to serve these URLs optimally with Hugo.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>How and why you should empower editors with a simple interface to upload and transform images. Content managers and editors need a simple, intuitive way of handling images in a content management system (CMS). They should also be able to upload, adjust, and remove assets without impacting site performance with bad transformations. As a safeguard, [&hellip;]<\/p>\n","protected":false},"author":87,"featured_media":32765,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[59,134,165],"class_list":["post-32763","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-cms","tag-guest-post","tag-image-transformation"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Optimized Image and Delivery Using Cloudinary and Decap CMS<\/title>\n<meta name=\"description\" content=\"Set up a CMS for editors to upload images &amp; apply transformations. Allow developers to control the quality &amp; size of the delivered images.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Editor-Friendly Image Transformation and Optimized Delivery With Cloudinary and Decap CMS\" \/>\n<meta property=\"og:description\" content=\"Set up a CMS for editors to upload images &amp; apply transformations. Allow developers to control the quality &amp; size of the delivered images.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2024-02-02T15:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-03-29T22:24:11+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1706824112\/editor_friendly_image_transformation-blog\/editor_friendly_image_transformation-blog-jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"2000\" \/>\n\t<meta property=\"og:image:height\" content=\"1100\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"melindapham\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms\"},\"author\":{\"name\":\"melindapham\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\"},\"headline\":\"Editor-Friendly Image Transformation and Optimized Delivery With Cloudinary and Decap CMS\",\"datePublished\":\"2024-02-02T15:00:00+00:00\",\"dateModified\":\"2025-03-29T22:24:11+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms\"},\"wordCount\":1435,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1706824112\/editor_friendly_image_transformation-blog\/editor_friendly_image_transformation-blog.jpg?_i=AA\",\"keywords\":[\"CMS\",\"Guest Post\",\"Image Transformation\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2024\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms\",\"url\":\"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms\",\"name\":\"Optimized Image and Delivery Using Cloudinary and Decap CMS\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1706824112\/editor_friendly_image_transformation-blog\/editor_friendly_image_transformation-blog.jpg?_i=AA\",\"datePublished\":\"2024-02-02T15:00:00+00:00\",\"dateModified\":\"2025-03-29T22:24:11+00:00\",\"description\":\"Set up a CMS for editors to upload images & apply transformations. Allow developers to control the quality & size of the delivered images.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1706824112\/editor_friendly_image_transformation-blog\/editor_friendly_image_transformation-blog.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1706824112\/editor_friendly_image_transformation-blog\/editor_friendly_image_transformation-blog.jpg?_i=AA\",\"width\":2000,\"height\":1100},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Editor-Friendly Image Transformation and Optimized Delivery With Cloudinary and Decap CMS\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\",\"name\":\"melindapham\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"caption\":\"melindapham\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Optimized Image and Delivery Using Cloudinary and Decap CMS","description":"Set up a CMS for editors to upload images & apply transformations. Allow developers to control the quality & size of the delivered images.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms","og_locale":"en_US","og_type":"article","og_title":"Editor-Friendly Image Transformation and Optimized Delivery With Cloudinary and Decap CMS","og_description":"Set up a CMS for editors to upload images & apply transformations. Allow developers to control the quality & size of the delivered images.","og_url":"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms","og_site_name":"Cloudinary Blog","article_published_time":"2024-02-02T15:00:00+00:00","article_modified_time":"2025-03-29T22:24:11+00:00","og_image":[{"width":2000,"height":1100,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1706824112\/editor_friendly_image_transformation-blog\/editor_friendly_image_transformation-blog-jpg?_i=AA","type":"image\/jpeg"}],"author":"melindapham","twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms"},"author":{"name":"melindapham","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9"},"headline":"Editor-Friendly Image Transformation and Optimized Delivery With Cloudinary and Decap CMS","datePublished":"2024-02-02T15:00:00+00:00","dateModified":"2025-03-29T22:24:11+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms"},"wordCount":1435,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1706824112\/editor_friendly_image_transformation-blog\/editor_friendly_image_transformation-blog.jpg?_i=AA","keywords":["CMS","Guest Post","Image Transformation"],"inLanguage":"en-US","copyrightYear":"2024","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms","url":"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms","name":"Optimized Image and Delivery Using Cloudinary and Decap CMS","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1706824112\/editor_friendly_image_transformation-blog\/editor_friendly_image_transformation-blog.jpg?_i=AA","datePublished":"2024-02-02T15:00:00+00:00","dateModified":"2025-03-29T22:24:11+00:00","description":"Set up a CMS for editors to upload images & apply transformations. Allow developers to control the quality & size of the delivered images.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1706824112\/editor_friendly_image_transformation-blog\/editor_friendly_image_transformation-blog.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1706824112\/editor_friendly_image_transformation-blog\/editor_friendly_image_transformation-blog.jpg?_i=AA","width":2000,"height":1100},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/editor-friendly-image-transformation-optimized-delivery-cloudinary-decap-cms#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Editor-Friendly Image Transformation and Optimized Delivery With Cloudinary and Decap CMS"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9","name":"melindapham","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","caption":"melindapham"}}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1706824112\/editor_friendly_image_transformation-blog\/editor_friendly_image_transformation-blog.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/32763","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/87"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=32763"}],"version-history":[{"count":6,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/32763\/revisions"}],"predecessor-version":[{"id":37290,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/32763\/revisions\/37290"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/32765"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=32763"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=32763"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=32763"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}