Problem/Motivation
Contextual links break the render cache: they are only added if the user has the "access contextual links" permission and can be different for each user.
Proposed resolution
Client-side solution
catch has indicated a long time ago, and in another issue, that the solution here is to indeed do something analogous to what Edit module is doing: only annotate the "thing" (Entity/View/Block/…) with some sort of identifier (probably in a data-contextual-id
attribute, that a piece of JS can look for, submit to the server to know if the user can access the contextual links for each thing, and what those actions are.
The JS would then only be added if the current user has the access contextual links
permission.
Consequences
For users that don't have permission to use contextual links, the overhead is limited to just <div data-contextual-id="<id>"></div>
(in the location where the contextual links would appear), and class="contextual-region"
. If the user has access to contextual links, the JS will be loaded and will fill in the div[data-contextual-id]
s.
These (<div data-contextual-id="<id>"></div>
& class="contextual-region"
end up in the render cache, and are served to everybody; hence allowing for full render cache compatibility.
Contextual Links before this patch worked when JS was disabled. Well, for an odd definition of "working": the links would appear, but they would be mostly-inappropriate pieces of unordered links. Now, JS is a hard requirement.
Server-side solution
Some people are arguing that the solution shouldn't require JavaScript. It should be possible to have more granular caching (possibly even per-user — though this effectively amounts to still breaking the render cache) and/or post-processing (e.g. retrieve rendered block from render cache and post-process it to insert the contextual links for the current user, if any).
On post-processing, catch said in #120:
If we end up establishing js-replacement as the standard approach to this (which I've been trying to encourage for well over a year now), adding a post-process layer to the render cache, explicitly limited to internal caching, would then allow for a PHP implementation of the replacement for sites that don't use *SI and don't want the js dependency.
On more granular caching, sdboyer said in #134 & #141:
frankly, when it comes to just throwing stuff on the page, we need to get more comfortable with saying, "don't do it that way, there's a right way to do things." that having been said, from a SCOTCH perspective, it's at least as useful if we have an explicit way of knowing that someone is lazily injecting HTML all over the place, rather than (re)writing a new block that works they way they actually want it to.
most important, though, is that injecting HTML all over is only a problem IF some aspect of that injection is made conditionally on something from unencapsulated global state. only at that point does it become cache-busty. it's perfectly fine for things to vary, so long as they vary in a manner we can predict from the outside by inspecting the data that's injected. as long as those data represent the entire range of variation, we're more or less in the clear.
i haven't just quite gotten to the caching mechanism yet, so i unfortunately can't point you to code (though i took a break from writing the contextual integration that supports it to write this response). it's rooted in the idea that by knowing what we inject into a block, we know its caching dimensions. blocks will be able to say "i'm uncacheable," or that the granularity level is less than that which the injected data might seem to imply (e.g., they require a user object, but vary merely by role, not by uid), but no more of the grand constants like CACHE_PER_ROLE, CACHE_PER_USER.
Both
It's also possible to have both the server-side and client-side solution, because both make more sense in different scenarios.
Remaining tasks
- Choose solution: client-side (implemented, almost RTBC'able), server-side (TBD), or both. An example of both could be the client-side approach implemented so far in this issue, plus a boolean cache split based on #1961884: Add support for 'permissions' and/or 'contexts' to render cache system. We can also choose to do the client-side portion in this issue, and the server-side portion as a follow up in that one.
User interface changes
None.
API changes
To be determined.
Original report by di3h3rd3r
The "Configure block" link of the "Active Forum Topics" and "New Forum Topics" blocks are visible to anonymous and authenticated users. Works as expected for admin user. I have tried the block in different regions with the links still showing up.