Add canonical link tags for item pages and bitstream downloads#5172
Add canonical link tags for item pages and bitstream downloads#5172bram-atmire wants to merge 1 commit into
Conversation
|
Hi @bram-atmire, |
|
Hi Bram! I tested the code from this PR and I can confirm that points 1 to 6 are working as you described, apart from the following two observations I made:
I can't say whether this is simply caused by my local setup or whether it is a genuine bug of this PR.
I would really love to see this PR being accepted and ideally backported to DSpace 9x because we are facing a lot of user requests regarding indexing on Google Scholar and it looks like this PR would solve a large portion of our indexing problems. Is there anything I can do to support this development effort? |
869a3cb to
7d4cc8c
Compare
|
Thanks for the thorough testing @tschammnut, and great to hear this would help with your Google Scholar indexing. I've pushed an update (rebased onto current 1. You're right, and this is expected behaviour rather than a bug. 2. Custom URLs as canonical Good catch. A custom URL ( 3. I wasn't able to tie this to the canonical code. The bitstream download component doesn't call On backporting: I'm planning to bring this to |
Adds <link rel="canonical"> to item page HTML heads and a Link HTTP
header with rel="canonical" to bitstream download responses. This helps
search engines identify the preferred URL for each page, preventing
self-competition between /items/{uuid}, /entities/{type}/{uuid}, and
/items/{uuid}/full routes.
Both features are configurable via seo.canonical.items and
seo.canonical.bitstreams settings (enabled by default).
Refs DSpace#4509
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
7d4cc8c to
044e3a8
Compare
Encouragement like this is often all it takes ;) |
References
Description
Adds
<link rel="canonical">to item page HTML heads and aLinkHTTP header withrel="canonical"to bitstream download responses, improving SEO by declaring preferred URLs.Instructions for Reviewers
List of changes in this PR:
SeoConfiginterface (src/config/seo-config.interface.ts) withcanonical.itemsandcanonical.bitstreamsboolean settings (both default totrue)HeadTagService: injectsLinkHeadService, adds<link rel="canonical">pointing to the UUID-based item view URL (viagetItemPageRoute(item, true)), and removes it on every route change. This covers both simple (/items/{uuid}) and full (/items/{uuid}/full) views; the canonical always points to the simple view. Entity pages (/entities/{type}/{uuid}) get their own canonical. Any custom URL (dspace.customurl) is deliberately ignored, because a custom URL can change with the item's metadata and is therefore not a stable canonical reference; the canonical always uses the UUID-based route. Handle URLs (/handle/{p}/{s}) already 301-redirect, so no canonical is needed there.BitstreamDownloadPageComponent: adds<link rel="canonical">to the HTML<head>(works for both SSR and client-side rendering) and appendsrel="canonical"to theLinkHTTP header (SSR only). ImplementsOnDestroyto clean up the tag.HeadTagServiceandBitstreamDownloadPageComponentcovering: tag added for Items, not added for non-Item DSOs, not added for non-DSO pages, removed on route change, respects configfalse, a custom URL still yielding the UUID-based canonical, and cleanup on destroy.main. Canonical URLs are built from the configuredui.baseUrlviaHardRedirectService.getBaseUrl()(main recently replacedgetCurrentOrigin()withgetBaseUrl()so theHostheader is no longer trusted).How to test:
npm run build:ssr && npm run serve:ssr<link rel="canonical" href="https://your-host/items/{uuid}">is present in the<head>/items/{uuid}/full), view source — canonical should still point to/items/{uuid}(without/full)/entities/{type}/{uuid}) — canonical should point to/entities/{type}/{uuid}curl -i https://localhost:4000/bitstreams/{uuid}/download— confirm theLinkheader containsrel="canonical"(use-ifor a GET;-Iissues a HEAD request, which does not render the SSR response and so does not emit the header)seo.canonical.items: falseorseo.canonical.bitstreams: falsein your config and verify the canonical tags are no longer addedNew configuration (in
config.ymlor environment config):Checklist
mainbranch of code (unless it is a backport or is fixing an issue specific to an older branch).npm run lintnpm run check-circ-deps)package.json), I've made sure their licenses align with the DSpace BSD License based on the Licensing of Contributions documentation.