Problem/motivation
The LinkitFormatter plugin implementation contains logic of using a "substitute URL" when the link points to an existing entity. In such a case, the formatter plugin will substitute any given URL from the field item by the URL of the entity.
This is mainly happening within the viewElements method of the LinkitFormatter class as shown in the following excerpt:
public function viewElements(FieldItemListInterface $items, $langcode) {
$elements = parent::viewElements($items, $langcode);
$settings = $this->getSettings();
// Loop over the elements and substitute the URL.
foreach ($elements as $delta => &$item) {
/** @var \Drupal\link\LinkItemInterface $link_item */
$link_item = $items->get($delta);
$item_url = $this->buildUrl($link_item);
$item_url_attributes = $item_url->getOption('attributes');
if ($url = $this->getSubstitutedUrl($link_item)) {
if ($url instanceof CacheableDependencyInterface) {
$cacheable_url = $url;
}
// Keep query and fragment.
$parsed_url = parse_url($link_item->uri);
if (!empty($parsed_url['query'])) {
$parsed_query = [];
// ...
Link to the relevant code part:
https://git.drupalcode.org/project/linkit/-/blob/7.x/src/Plugin/Field/Fi...
I have an (admittedly edgy but valid) case where I store custom "query" values as options at the link field itself. The link field item allows to store such options as a serialized array besides the link uri.
Due to the currently implemented logic highlighted above, such previously stores "query" values may get lost, since the part that is trying to keep the "query" option is only looking at the uri itself, but not at the stored field item's options.
Steps to reproduce
This is coming from a custom code implementation where it fell into this trap, so it's hard to provide easy steps to reproduce here. I hope the problem description is enough for understanding the problem.
Proposed resolution
The logic that is trying to preserve the query arguments should additionally check for any stores "query" options at the field item. Or even better, load all options from the field item and put it back into the newly create Url object.
Issue fork linkit-3613627
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #3
mxh commentedCreated MR177 which suggests to add an additional merge of already existing query arguments from the "original" item url.
Comment #4
csakiistvanComment #5
csakiistvanEnvironment
Prerequisites
/alpha-target.linkfield on the article content type, with the Linkit widget and the Linkit formatter, using a Linkit profile whose node matcher usescanonicalsubstitution.Steps
uri.ddev drush crhrefin the Linkit link field.uriinstead of the options, for exampleentity:node/<TARGET NID>?from=uriwith empty options, and confirm that case still works.entity:node/<TARGET NID>?from=uri#secwithoptionsholdingutm_source=newsletterandfrom=options.Expected results
optionssurvive the URL substitution and appear on the rendered link.urikeep working, as does the fragment.uriwins.Actual results
As expected. Before the fix, the stored options were dropped: the link rendered as
<a href="/alpha-target" hreflang="en">, with no trace ofutm_sourceorpage. A query supplied in theuriwas kept (/alpha-target?from=uri), and with both sources present only theurione survived (/alpha-target?from=uri#sec).After applying MR !177, the same three cases render as
/alpha-target?utm_source=newsletter&page=2,/alpha-target?from=uriand/alpha-target?utm_source=newsletter&from=uri#sec. The stored options are preserved, the previous behaviour for URI queries and fragments is unchanged, and on the collidingfromkey theurivalue takes precedence.Testing produced with the assistance of an LLM.
Comment #6
idebr commentedLet's add some automated test coverage showcasing where the current logic fails