U4-8949 - Change media file doesn't update media urls inserted in RTE before update

Created by Rasmus Eeg Møller 07 Sep 2016, 09:25:16 Updated by Sebastiaan Janssen 21 Feb 2018, 12:43:33

Tags: Up For Grabs

Is duplicated by: U4-8950

Is duplicated by: U4-10125

Is duplicated by: U4-10624

Is duplicated by: U4-10684

Is duplicated by: U4-11000

Relates to: U4-11000

What did you do?

  1. Uploaded media file (any)
  2. Created document with RTE or Grid RTE
  3. Inserted link to uploaded file
  4. Save and Publish
  5. Change media file by uploading a new file to the same media item. Hit save
  6. Open the link to document, and watch that it still links to old file.

What did you expect to happen? I exspected the logic to parse the media link using the same template utillities as content links.

What actually happened? Keeps old media file url after media file change

Comments

Sebastiaan Janssen 07 Sep 2016, 09:29:34

FYI: this is going to be near impossible to do correctly currently. We don't know where (on which content items and in which properties) the media path is stored so in order to fix this we would need to go through each and every content item, media item and member to figure out if the media path has been stored. Then we need to figure out the datatype of the item and hope we can simply update it without breaking something else. Finally, we'd need to publish each found content item.

You could write an event handler to do this now, but beware of possibly severe performance impact.


Rasmus Eeg Møller 07 Sep 2016, 09:45:30

Based on the logic that used for content links: ParseInternalLinks Would it not be posible to resolve media url's the same way?

All media urls picked using the RTE link to file option, inserts the following in RTE: <a data-id="6060" href="/media/0000/sample.xlsx" title="Sample.xlsx">Download sample</a>

rte.cshtml used in Grid

Html.Raw(TemplateUtilities.ParseInternalLinks(Model.value.ToString()))

Changing or adding a new method for parsing internal media links could be done?


Stefan Kip 07 Sep 2016, 09:46:23

For the RTE and Grid RTE a 'simple' fix would be to do the same as with linked content; instead of , or am I missing something?


Sebastiaan Janssen 07 Sep 2016, 09:52:58

Stefan: yup, that would be the fix. And a huge breaking change. I'll earmark it for v8. :)


Sebastiaan Janssen 07 Sep 2016, 09:57:12

Just a little extra explanation is needed there: I wasn't aware we now store the media id as well, which is awesome... for people who are visiting your website. However.. content editor still see the old URL! So extra parsing would also be needed for the RTE. Which, by the looks of it might also actually be workable.. Interesting!

I'll mark it as Up For Grabs for now if someone would love to work on this, we currently don't have the time to dive into this for a while unfortunately.


Rasmus Eeg Møller 07 Sep 2016, 10:06:43

Note that we can't use use the same logic, we need to have a way to seperate localLink from a media localLink


Rasmus Eeg Møller 24 Oct 2016, 12:30:05

tempory fix:

using System.Text.RegularExpressions;
using Umbraco.Core;
 
namespace Umbraco.Web.Templates
{
    public static class TemplateUtillitiesExtensions
    {
        public static string ParseInternalMediaLinks(string value ) {
 
            if(UmbracoContext.Current == null) {
                return value;
            }
 
            var umbracoHelper = new UmbracoHelper(UmbracoContext.Current);
 
            //get all anchors and images with data-id, href's including media and get their values
            string pattern = @"\<(?:a|img)(?=.*?data-id\=\""([0-9]+))(?=.*?(?:(?:src|href)\=\"")(\/media\/\S+)\"")";
            foreach(Match match in Regex.Matches(value, pattern, RegexOptions.Multiline))
            {
                Group dataIdGrp = match.Groups[1];
                Group urlGrp = match.Groups[2];
 
                var image = umbracoHelper.TypedMedia(dataIdGrp.Value);
                if(image == null) continue;
 
                if(urlGrp.Value == image.Url) continue;
 
                value = value.Replace(urlGrp.Value, image.Url);
            }
 
            return value;
        }
    }
}


Silvan Egger 26 May 2017, 15:37:47

Since two years my customers complain about this issue. Umbraco really need's this to be fixed. I would really appreciate it, if someone could fix this.


Matthew 26 May 2017, 20:46:45

This is a REALLY annoying issue and would greatly improve Media usability if a solution were found.

My current workaround is to instruct users to make sure that the replacement media file has the exact same file name as the file it's replacing.


Matthew 06 Jul 2017, 13:55:58

Rather than keeping the links updated, have we considered renaming updated media files on the server to match the node name, thus not breaking existing links in the first place?

See http://issues.umbraco.org/issue/U4-10125


Lennard Fonteijn 18 Aug 2017, 20:42:31

@sebastiaan Since this one is up for grabs, is there any objection to utilizing the UDI in this case in a sort of macro-like fashion which is processed during the rendering of a view? Technically this will also give it the most recent URL/name/whatever, even if the paths into /media have changed due to a deploy. Since this is a huge issue for Umbraco Cloud deploys!


Daniël Knippers 07 Sep 2017, 12:31:49

In case people want to use a similar solution to Rasmus' solution but are on an Umbraco version using UDIs rather than IDs, you can use something like below, which can be put in a PropertyValueConverter which inherits from RteMacroRenderingValueConverter, it's not necessary to adjust Umbraco's source directly. This does not work on RTEs inside the Grid as far as I know unfortunately, you'd also need to create a GridValueConverter.

///

/// Makes sure a/img tags referencing an Umbraco Media item always use the correct (= most recent) URL, rather than the URL /// that was current when the a/img tag was inserted in the RTE. /// /// Input HTML string /// UmbracoHelper instance. Will be created if not provided. /// HTML where href/src attributes of a/img tags have been adjusted to contain the accurate media URL. private string EnsureCorrectMediaUrls(string html, UmbracoHelper umbracoHelper = null) { UmbracoHelper uh = umbracoHelper ?? new UmbracoHelper(UmbracoContext.Current);

return Regex.Replace(html, @"<(?:a|img) [^>]*?data-udi=""([^""]+)""[^>]*?>", m =>
{
    Udi udi;
    if (Udi.TryParse(m.Groups[1].Value, out udi))
    {
        IPublishedContent media = uh.TypedMedia(udi);
        if (media != null)
        {
            // Replace content of href or src attribute with correct URL
            return Regex.Replace(m.Value, @" (href|src)=""[^""]+""", hrefOrSrc =>
            {
                return $"{hrefOrSrc.Groups[1]}=\"{media.Url}\"";
            });
        }
    }

    // In case of unexpected input => return original
    return m.Value;
}, RegexOptions.IgnoreCase);

}


Lennard Fonteijn 18 Oct 2017, 07:25:58

@dknippers Thanks Daniƫl, this was exactly what I wanted to do when I asked @sebastiaan 2 months back in combination with the PropertyValueConverters you mentioned. Might just as well combine the version of @rasmuseeg with yours (so both work), formalize the solution with the PropertyValueConverter/Grid-variant, and submit a PR.


Priority: Normal

Type: Bug

State: Open

Assignee:

Difficulty: Normal

Category:

Backwards Compatible: True

Fix Submitted:

Affected versions: 7.4.3, 7.5.1, 7.5.2, 7.5.3, 7.5.4, 7.6.5

Due in version:

Sprint:

Story Points:

Cycle: