Problem/Motivation
In #2303525: Provide link tags to alternate languages (hreflang) in HTML head, when viewing a content entity, we added hreflang alternate links to the HTML head for each translation of that entity. However, alternate links will appear for unpublished translations as well. This behavior hurts SEO, as web crawlers will be made aware of links that cannot actually be viewed.
Proposed resolution
Do not include unpublished translations when providing rel="alternate" hreflang links in the HTML head.
Remaining tasks
Re-roll onto 8.7.x HEADFix deprecated use of format_string()Re-roll onto 8.8.x HEADRe-roll onto 8.9.xFix deprecated use of EntityInterface::urlInfo() in NodeTranslationUITest- Review and feedback
- RTBC and feedback
- Commit
User interface changes
None.
API changes
None.
Comment | File | Size | Author |
---|---|---|---|
#74 | 2521782-74-hreflang-links-to-unpublished-translations.patch | 5.67 KB | mparker17 |
Comments
Comment #1
paulmckibbenI've attached a patch that includes a fix and an updated test. I am unable to run the test locally due to mysql wait time issues that I can't seem to work around.
Comment #3
matsbla CreditAttribution: matsbla commentedI tested patch in #1 and looks like it fix the problem
Comment #4
BerdirInstead of a hardcoded check for nodes, why not check for access for each translation? That should result in the same and work for everything.
Comment #5
paulmckibben@berdir, thanks for the suggestion. I tried the following, but the unpublished translation link still appears. If I enter the URL of the unpublished translation as an anonymous user, I properly get access denied, so I'm not sure what I've done wrong. Here's the code:
Any advice?
Comment #6
swentel CreditAttribution: swentel commentedHmm yeah, calling $translation->access('view') will return true if the original entity has access, because in Node.php prepareLangcode() is looking for the current language.
Attached patch fixes that, but not sure if this is the right approach as it's technically an API change.
Comment #7
swentel CreditAttribution: swentel commentedNote, that the isPublished() check might be a go to fix this patch, but I think there's a still a bug with calling $translation->access('view')
Comment #9
Anonymous (not verified) CreditAttribution: Anonymous at XIO commentedComment #10
paulmckibbenSince the comments indicate the original approach/patch is "a go," I've rerolled my original patch against beta16.
Comment #13
paulmckibbenLast patch was created in the wrong repository (had a "docroot" directory) and would not apply. Rerolling the patch in a brand new clone of the core repo. Let's try this again!
Comment #15
paulmckibbenThe test code had a bug that caused the test to fail. Fixed the test code. New patch attached.
Comment #16
plachThanks for providing a patch, but in the current form it is dealing only with nodes, but it should support any content entity type instead. For instance:
We should check
$entity->access()
here.Comment #17
plachThe first PHP doc line should not exceed 80 chars.
Missing blank line separator before this and the description of when the exception is thrown.
Comment #18
paulmckibbenHi @plach, thanks for your review and feedback. Regarding #16, I tried the $entity->access() approach earlier and ran into trouble. Copying my comment #5 above:
I tried the following, but the unpublished translation link still appears. If I enter the URL of the unpublished translation as an anonymous user, I properly get access denied, so I'm not sure what I've done wrong. Here's the code:
Any advice?
Comment #19
paulmckibbenWell, I tried the entity->access() approach against Drupal 8.0.3, and this time it worked! Whatever happened #5 seems to have changed now.
I've addressed all comments. Please review. Thank you!
Comment #20
swentel CreditAttribution: swentel commentedThis check should go away, after that it's good to go.
Comment #21
paulmckibbenOops, missed that Node check... thanks, @swentel!
Updated patch and interdiff attached.
Comment #22
swentel CreditAttribution: swentel commentedLooks good to me now. My patches are completely unrelated, so RTBC
Comment #25
catchThis is deprecated, but I see it's just been copied from the existing test, so committing as is to 8.1.x and 8.0.x, thanks!
Comment #26
Wim LeersThis should set the access result's cacheability metadata on
$page
.The reason tests pass is probably that by default access is granted based on permissions, and
user.permissions
is a required render cache context.Comment #29
catchGood point. Rolled back for now.
Comment #34
caspervoogt CreditAttribution: caspervoogt at Plethora commentedI see the status is 'needs work' but reading through the comments it isn't clear to me what exactly remains to be done.. what's the status / what needs to be done to get this committed?
Comment #35
screon CreditAttribution: screon commentedSame question as above. I see the fix has been committed to 8.3.x but still needs work for 8.2.x?
Comment #36
cilefen CreditAttribution: cilefen commentedIt is comment #26. And it was reverted in 8.3.x and 8.2.x.
Comment #37
caspervoogt CreditAttribution: caspervoogt at Plethora commentedYup, the path from #26 was committed and then rolled back - that's why I was asking what actually remains to be done, since the status is "Needs work".
From #26: "The reason tests pass is probably that by default access is granted based on permissions, and user.permissions is a required render cache context."
I'm not really following this and would need to dive into the code to catch up.. am hoping some of the earlier contributors and provide some explanation of status.
Comment #38
cilefen CreditAttribution: cilefen commented#26 is the reason it was rolled back.
Comment #39
caspervoogt CreditAttribution: caspervoogt at Plethora commented@cilefen I get that... but what is lacking here is a summary of what specific action items still have to be done in order to get this patched on the 8.2 branch. I don't know what those steps would be.
Comment #40
cilefen CreditAttribution: cilefen commentedIs the question about what steps are required to accomplish the review items in #26?
Comment #41
caspervoogt CreditAttribution: caspervoogt at Plethora commentedYes. It says;
'This should set the access result's cacheability metadata on $page.'
The reason tests pass is probably that by default access is granted based on permissions, and user.permissions is a required render cache context.'
I can't tell whether this means that content_translation.module is OK, or whether there's a bug in the tests, or both. Sounds like the tests pass but shouldn't, i.e. the module code is not in fact setting cacheability, even though tests say that it is. Would be great if someone could confirm and explain in a bit of detail.
Comment #45
ckaotikConsidering there hasn't been any change in the past 5 months, I've removed the assignment to @paulmckibben.
I assume @wim-leers meant that we should add the cache metadata to the
$page
render array. I've attached a patch that should add that caching information. Whether the tests need to be updated or not is beyond me, though.Comment #46
Wim Leers#45: great! Thanks for getting this going again :) The patch looks good! But it'll need to bring back the test coverage changes that #21 was adding.
Comment #49
Nikolay Borisov CreditAttribution: Nikolay Borisov commentedI merged the simple test from #21 with the last patch from #45 and tested the Simple Test locally. Prepared it in its own patch.
Comment #50
Nikolay Borisov CreditAttribution: Nikolay Borisov commentedComment #51
Lan Anh CreditAttribution: Lan Anh commentedHis solution, worked well ! Well done!
Comment #52
borisson_I was going to rtbc this, but I noticed some whitespace that should be removed. Sorry for the nitpick.
Whitespace should be removed here.
Comment #53
yogeshmpawarComment #54
yogeshmpawarChanges done as per comment #52 & also added an interdiff.
Comment #55
borisson_Patch doesn't apply anymore and introduces some cs errors. (
[]
should be used instead ofarray()
).Comment #56
caspervoogt CreditAttribution: caspervoogt at Plethora commentedI just tested drupal-alternate_hreflang_unpublished_with_test-2521782-54.patch on it applied cleanly for me on dev and 8.5.0. Tested and working on 8.5.0 for me but I have not tested it on dev specifically. I've re-rolled it with array() converted to [].
Comment #57
savkaviktor16@gmail.com CreditAttribution: savkaviktor16@gmail.com at Skilld commentedRe-rolled
Comment #58
MerryHamster CreditAttribution: MerryHamster at Skilld commentedComment #59
MerryHamster CreditAttribution: MerryHamster at Skilld commentedHere is an only reroll to 8.6.x
Comment #60
MerryHamster CreditAttribution: MerryHamster at Skilld commentedComment #62
MerryHamster CreditAttribution: MerryHamster at Skilld commentedHere is an only reroll to 8.7.x
Comment #63
raphaeltbm CreditAttribution: raphaeltbm commentedI guess that some stuff from #2994800: Improve the alternate hreflang implementation shoud be considered.
Comment #64
Greg Sims CreditAttribution: Greg Sims as a volunteer commentedI performed the following from module_name_preprocess_html():
I found the rel="canonical", rel="shortlink" and rel="revision" tags. I was not able to find the rel="alternate" hreflang= even though the resulting page contains three such tags -- one for en, es and zh-hans.
Should hreflang be part of the $variables array as described above? Is there another way to access the hreflang tags from module_name_preprocess_html()? I would like to be able to unset() an hreflang that points to an unpublished translation.
Comment #65
Greg Sims CreditAttribution: Greg Sims as a volunteer commentedIt appears that updating the language code in $variables has no impact on the creation of the associated hreflang tag.
I found the hreflang tags here:
var_dump($variables['page']['#attached']['html_head_link']);
I changed the language code for Chinese to zh according to the standard:
This resulted in the following hreflang tag on this page:
<link rel="alternate" hreflang="zh-hans" href="https://stg.raystedman.org/zh/new-testament/ephesians" />
Please notice that the hreflang value does not conform to the value in $variables.
Comment #67
jkuma CreditAttribution: jkuma as a volunteer commentedThe patch on #62 fails on latest version of 8.7.x
Here is a re-roll for 8.7.x
Comment #69
maebug CreditAttribution: maebug commentedThe patch in #67 was not applying correctly for me on the latest version of 8.7.x, so I re-reolled it
Comment #71
mparker17Looks like the test failed on 8.8.x because the call to
\Drupal\Core\Entity\EntityInterface::urlInfo()
in NodeTranslationUITest became deprecated in8.8.x
... I'll look into fixing this.
Comment #72
mparker17Looks like the patch needs to be re-rolled as well; and the re-roll onto
8.8.x
and8.9.x
is complex because some other functions (e.g.:format_string()
) have been deprecated and replaced, leading to merge conflicts.This means I'm going to have to re-roll this in stages.
Attached is a re-roll of the patch from #69 onto the HEAD of
8.7.x
at time-of-writing, commit3fe90fe545
. I haven't made any changes yet, so no interdiff is necessary.I fully expect this to fail to patch on 8.8.x and 8.9.x so I'm going to leave the issue as "Needs work" for Testbot's sake.
Comment #73
mparker17Here's a patch where I've replaced calls to
format_string()
with calls tonew FormattableMarkup()
as per https://www.drupal.org/node/2302363Comment #74
mparker17I was hoping the change in #73 would allow git to rebase the patch onto 8.9.x automagically, because the removed lines would be the same as the lines in the patch; but git still presented me with a merge conflict in NodeTranslationUITest.php. Although, to resolve the merge conflict, I could simply delete the old code - I didn't need to make any changes to the code in the patch.
So here's the patch from #73 rebased onto 8.9.x - since there were no changes, there's no interdiff.
Still "needs work" until I can fix the deprecated use of EntityInterface::urlInfo()
Comment #75
mparker17Oops: I did change
urlInfo()
totoUrl()
in that patch; likely while I was trying to figure out why Git didn't want to rebase the patch without a merge conflict.That was the only change; although generating an interdiff is not possible since it would include all the changes from 8.7.x to 8.9.x as well.
So I'm setting this to "needs review" so Testbot can try it out.
Sorry for the noise and confusion.
Comment #76
mparker17Yay; tests are green again!
Comment #78
weseze CreditAttribution: weseze as a volunteer commentedUsing this in production and it works great.
Comment #79
mparker17@weseze, if you've tested it (i.e.: in production), and reviewed the patch (i.e.: by reading through it for problems), may I trouble you to change the status to "Reviewed & tested by the community"? (I cannot do that myself because I wrote the patch) Thank you!
Comment #80
weseze CreditAttribution: weseze as a volunteer commentedComment #81
badrange CreditAttribution: badrange commentedIf this gets merged on July 2 it will be merged on the fifth year anniversary of the patch!
Comment #85
catchCommitted/pushed to 9.1.x and cherry-picked back to 8.9.x, four years after the original fix was reverted but not quite in time to hit the five year birthday.
Comment #87
FiNeX CreditAttribution: FiNeX as a volunteer commentedHi, what if only one language is available? It looks that currently there is always at least one hreflang tag printed. Is this ok?