Duplicate alias generation during entity translation

Created on 8 February 2025, 3 months ago

Problem/Motivation

Use of this module results in following bugs:

  1. Issue-1: If the URL Alias is not changed while adding a translation, it'll create a duplicate of pre-existing alias.
  2. Issue-2: If the URL Alias is changed while adding translation, it'll create a different alias for the same entity and now the old alias exists but is of no-use.

Steps to reproduce

  1. Enable "language" and "content_translation" modules
  2. Make any content type translatable
  3. Install and enable this module
  4. Add a Node in some language (let's say "en" for test).
  5. Check the URL Alias table, it'll have only one occurrence [Correct behavior]
  6. Translate to other language, now there will be a duplicate alias [Issue-1] and if the alias is changed while translating, it'll result in Issue-2

Proposed resolution

  1. Make URL Alias field, accessible only on source language.
  2. Check the aliases, if the copy already exists. do not allow the duplicate alias generation.

Remaining tasks

To find out the probable solution for Issue-2.

User interface changes

The URL Alias form field will only be visible on the source language on which the node was created.

📌 Task
Status

Active

Version

3.2

Component

Code

Created by

🇮🇳India keshav patel

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @keshav patel
  • 🇮🇳India keshav patel

    Issue-1 is handled and needs review , Issue-2 remains..
    Keeping issue on "Needs work".

  • Pipeline finished with Success
    3 months ago
    Total: 144s
    #418502
  • 🇮🇳India keshav patel

    Minor correction for #3
    Make URL Alias field, accessible only on source language. handles the issue-2 for us.
    Marking issue as "Needs review".

  • 🇩🇰Denmark xen

    There's obviously a challenge here, but I don't think the proposed solution is the right path.

    For starters, \Drupal shouldn't be used in OO code, the relevant services ought to be dependency injected. But directly querying the database to check for duplicate couples the storage class tightly to the database schema. $this->loadByProperties() ought to work for checking for duplicates.

    Secondly, hiding the path on translations hides the fact that the translation *does* have an alias. I'd rather skip that part and live with the fact that editing the path on the translation also edits the original language alias.

  • 🇮🇳India keshav patel

    Hello @xen , thanks for the feedback!

    Yes will update the MR to respect OOP.

    But the second part:

    hiding the path on translations hides the fact that the translation *does* have an alias. I'd rather skip that part and live with the fact that editing the path on the translation also edits the original language alias.

    I hid that field from translation pages by considering the scenarios duplicate aliases, multiple aliases and when using the "pathauto" module as well, like there are some points to take into consideration:
    1) The URL Alias field must set as untranslated when using this module.
    2) If kept translated this module can create duplicates or multiple aliases(distinct) for same "path".
    3) In case when "pathauto" exists and "Generate Automatic Alias" is checked, it'll create duplicates.

    I even tried to overcome the duplicate / multiple alias generation issue while keeping the URL alias field visible everywhere, but alias entity is generated before it reaches "NeutralPathAliasStorage.php".

    Also, please do let me know if anything else I can try here..

  • 🇩🇰Denmark xen

    > Yes will update the MR to respect OOP.

    Sounds good.

    > But the second part:

    Some observations and assumptions, do correct me if you think I'm wrong:

    > 1) The URL Alias field must set as untranslated when using this module.

    What do you mean specifically? I notice that path_entity_base_field_info() sets the pathbase field to translatable, but I don't know if that really affect us as we're dealing with alias.

    path_entity_translation_create() seems to be the cause of our woes, as it unsets the pid of the alias (but keep the alias) when creating a translation. Maybe disabling that will make things behave.

    I don't like just form_altering the field away with a general form_alter. I'd rather get closer to the source by overriding the field widget, if we must do it.

  • 🇮🇳India keshav patel

    @xen Till now we're done with the duplicate alias issue.

    Now we're left with, multiple aliases existence for the same entity i.e. same alias not getting updated.

    Regarding:

    What do you mean specifically? I notice that path_entity_base_field_info() sets the pathbase field to translatable, but I don't know if that really affect us as we're dealing with alias.

    path_entity_translation_create() seems to be the cause of our woes, as it unsets the pid of the alias (but keep the alias) when creating a translation. Maybe disabling that will make things behave.

    Yes, the hook path_entity_translation_create() is the culprit here, line: $translation->get($field_name)->pid = NULL; is to be taken of.

    Taking your suggestion, I removed the form alter implementation so that the Alias can be added / updated anywhere.

    With that, we're left with two test cases:

    URL Alias is: Translated and $translation->get($field_name)->pid = NULL; is commented

    -> When node is created (let's say alias: '/test') and on translation add, alias is changed (let's say to 'test-fr'), the alias does not get updated and the alias still remains as '/test'.
    -> That is, during create operation [translation add] the changed alias value is not saved even if it's updated.
    -> When translated are created. after that if the alias is updated on source or translation . that changes happen correctly and alias are reflected.

    URL Alias is: Un-translated and $translation->get($field_name)->pid = NULL; is commented

    -> Only one alias instance is present and is getting updated. [On Node create / edit, translation add / update]

    Considering this, we've to keep the URL alias as un-translated and Override path_entity_translation_create() hook.

  • Pipeline finished with Success
    about 1 month ago
    Total: 207s
    #453693
  • 🇮🇳India keshav patel

    I think we're good now, just needs a review if anything is left.

    Also, once this is merged. I think I'll be better to specify:

    Keep URL alias field untranslated.

    as requirement.

  • Pipeline finished with Success
    about 1 month ago
    Total: 173s
    #454687
  • 🇩🇰Denmark xen

    Great, looks good. A couple of things:

    1. Do we still need the existence check in save? As we've disabled path_entity_translation_create() the pid is no longer unset, so parent::save() should just save the existing entity.

    2. The comment on disabling the core hook needs to explain why we do it. Something like

    The core path_entity_translation_create() hook attempts to save an alias per translation by unsetting the pid of an existing alias. As we reset the language of the alias, this will just create duplicated (or conflicting) aliases, so we disable this behaviour.

    3. Could you squash the history down to one commit?

  • 🇮🇳India keshav patel

    Yes I checked that, we don't need existence check after unsetting the hook. I've updated the comment to be make it informative and squashed all the work in a single commit.

  • Pipeline finished with Success
    about 1 month ago
    Total: 326s
    #456454
  • 🇮🇳India keshav patel

    @xen ,

    I've added 📌 Update README file and projects description as per change introduced on #3505292 Active to cover the documentation part related to this task.

  • 🇮🇳India adwivedi008

    adwivedi008 changed the visibility of the branch 3505292-duplicate-alias-generation to hidden.

  • 🇮🇳India adwivedi008

    adwivedi008 changed the visibility of the branch 3505292-duplicate-alias-generation to active.

  • 🇩🇰Denmark xen

    Thanks, merged. Release forthcoming.

  • Issue was unassigned.
  • Status changed to Fixed 17 days ago
  • Automatically closed - issue fixed for 2 weeks with no activity.

Production build 0.71.5 2024