Problem/Motivation
The breadcrumb block sets a cache context of URL, this is because we base the breadcrumb on the actual URL, including if it's a path alias.
However, this results in a per-path cache entry for 404s as well.
Proposed resolution
Consider not even attempting to create a breadcrumb if the path itself does not have a route associated. For 404s this would mean a single cache entry instead of one per path. Other pages would still be per-path.
Remaining tasks
Need to check if a valid breadcrumb gets made on a 404 - for example does admin/config/invalid-link include a breadcrumb to admin/config - if it does, then this would be behaviour change which might need more discussion. Although we could still default to no breadcrumb in that case.
User interface changes
API changes
Data model changes
| Comment | File | Size | Author |
|---|---|---|---|
| #48 | 2699627.patch | 10.67 KB | catch |
| #45 | 2699627.patch | 10.52 KB | catch |
| #45 | interdiff.txt | 2.05 KB | catch |
| #43 | 2699627.patch | 10.54 KB | catch |
| #42 | interdiff.txt | 2.28 KB | catch |
Comments
Comment #2
catchComment #3
catchComment #4
catchRight now we show a usable breadcrumb on 404 pages if there are valid paths before the final forward slash.
So I see a couple of ways of doing this:
1. Drop that feature, don't show a breadcrumb, use an is_a_404 cache context.
2. Add a cache context for path, that supports only a certain number of path parts as well as the is_a_404 cache context.
So for example:
admin/config/xyz
If we're on a 404, we know admin/config/xyz doesn't match a route. We can also tell whether admin/config does or does not.
If admin/config matches a route, add a cache context for path but only taking into account the first path parts - so it'll be admin/config for both admin/config/abc and admin/config/xyz
If there is no route match, there'll be no breadcrumb at all, so the is_a_404 page cache context since it'll be no breadcrumb for everything.
Comment #5
catchDiscussed in irc with Fabianx. For now at least, we think we should do the above #2 logic, but he suggested a dedicated cache context like url.path_based_breadcrumb which makes sense to me - can keep all the logic in one place that way and don't see separate contexts being useful elsewhere anyway.
Comment #6
catchHere's a start.
I don't think we want to perfectly replicate the logic in the breadcrumb builder itself, since that would require matching multiple paths to routes again which could get quite expensive, as well as duplicating a lot of complex logic.
So attached does the following:
- on 404s, strip the last segment of the path so admin/config/abc becomes admin/config and /abc becomes ''
- on all other pages treat it the same as now
In addition to that we could also follow #2699613: Set a shorter TTL for 404 responses in page_cache module and set a shorter max_age on the cache context metadata - haven't done this yet though.
Comment #7
catchAlso I wonder whether we can get away with always stripping the last part of the path including on non-404s. If we can that'd be a huge improvement.
See what the bot says about that.
Also bumping to critical, I think this is actually the critical part of [##2697795] since nothing will clear the breadcrumb cache from 404s.
Comment #10
catchComment #13
catchAll good test failures.
Comment #15
catchComment #16
catchRe-titling given the patch no longer deals with 404s.
Depending on the site this could save (tens of) thousands of cache entries.
Comment #17
dawehnerHere is a basic test.
I'm not entirely sure about the title change, given that it let's us think less of other potential solutions, but nevermind.
Comment #18
catchHow about this title?
Comment #19
dawehner+1
Comment #21
catchCombining #15 and #17.
Comment #22
dawehnerWhen I understand the problem of too many cached entries correctly, this is more about random URLs, so just dropping the last bit wouldn't help?
Comment #23
catchWell to take casey's example from the issue that spawned this:
The code here would make that:
Now if you have URLs like
Then it won't help much.
If all your URLs are of the structure:
then it'll help a lot.
My original idea here was to copy the logic from the breadcrumb builder and check up the path directory whether we're on a 404 or not, and then use the non-404 portion for the cache context. That would mean more efficient caching for the completely random URL case, but it's going to make the cache context itself much more expensive to calculate, and then I realised we can improve things for non-404 responses anyway with simpler/cheaper logic.
If we want to do something special for 404s, I'd rather keep the logic simple still, but add something like #2699613: Set a shorter TTL for 404 responses in page_cache module and set a shorter TTL for the breadcrumbs on 404s. That's still cheap to calculate compared to matching routes, but would prevent random URLs being cached forever.
Comment #24
wim leers+1
Nit: two spaces, should be one.
I don't see any logic changes in here to match the cache context: the path-based breadcrumb builder is not yet omitting the last path component?
This should be
url.path.breadcrumb, noturl.breadcrumb.Per https://www.drupal.org/developing/api/8/cache/contexts, that would mean that if something on the current page already varies by
url.path, thaturl.path.breadcrumbcan be optimized away. Because it is a more specific subset, with fewer variations: it is implied.And actually, none of this is breadcrumb-specific, I'd call it
url.path.parent.Comment #25
catch#24-2:
It already does:
url.path.parent makes sense. Updated patch for that.
Comment #27
catchForgot to update things for the new cache context name.
Comment #29
wim leersinterdiff doesn't match the patch: hence this patch failed tests.
Comment #30
catchOuch. See how this does.
Comment #32
catchCacheTagsIntegrationTest now needs no changes due to the context getting collapsed.
Comment #34
catchSorry. That should be it for easy-to-avoid test fails.
Comment #35
catchAnd for unrelated hunks in the patch.
Comment #36
catchAddding a unit test for the new cache context.
Comment #37
catchAnd the interdiff.
Comment #38
catchDouble checked and the only place we use url.path after this patch is in FormBuilder for the #action placeholder. That's only removable with #2503429: [PP-*] Allow both AJAX and non-AJAX forms to POST to dedicated URLs.
Comment #39
wim leers#8: No, there's one more place where we use the
url.pathcache context: in theRequestPathcondition plugin: https://api.drupal.org/api/drupal/core%21modules%21system%21src%21Plugin....This looks tantalizingly close to ready. Marking RTBC because 8.1.0 is imminent and AFAIK catch would like to see this land. There's only nits basically, all of which can be addressed in a follow-up.
Nit: we have a base class that does this stuff.
Also: the comment is still for
BookNavigationCacheContext.This is not breadcrumb-specific.
Comment does not match.
I'm still missing two edge cases:
Comment #40
catchI don't think this can land before 8.1.0. I mainly wanted to get some critical issues moving forward while we were in rc commit-freeze, also nice excuse to work on actual patches a bit more.
We need to decide if the new class + service definition makes this patch release ineligible. For me this isn't really an API addition/feature as such - it's a new implementation / minor refinement of an existing API.
#39 is all good feedback so marking CNW for that.
Comment #41
wim leersOk, even better. I'd have been okay with this landing because this is a very low-risk patch, and even if it broke something, it'd have minimal consequences.
+1 — it is making the cache context actually match. It's not an API addition. It's fixing a problem by adding one more implementation of an API.
Nevertheless, when this lands, we need:
Comment #42
catchShould address #39.
Comment #43
catchNeeded a rebase.
Comment #44
wim leersThis must omit "cache context".
I think just "Parent path" would actually be the best human-readable name.
Nit: Trailing space.
This has not yet been updated.
Prone? Prime? :P
Comment #45
catchAddressing #44.
Comment #46
wim leersI think this is ready now.
Comment #47
alexpottA few things to fix on commit. We still haven't agreed that tests should have documentation.
Also before we can commit we need a CR.
Comment #48
catchDraft CR at https://www.drupal.org/node/2713593
Updated patch including #47. Should be RTBC again assuming the bot is happy.
Comment #49
catchMoving back to RTBC.
Comment #50
alexpottCommitted 9c9b459 and pushed to 8.1.x and 8.2.x. Thanks!
Comment #53
wim leersUpdated the documentation at https://www.drupal.org/developing/api/8/cache/contexts.
The change record was already published: https://www.drupal.org/node/2713593.
Comment #54
jhodgdonI think this patch broke breadcrumbs for me... see #2719721: BreadcrumbBuilder::applies() mismatch with cacheability metadata. This is most likely the change that broke it...