Original issue:
I'm trying to redirect urls in the form of:
/home/?m=destinations&destid=6&resortid=152&hotelid=357
Where there is a hierarchy like:
destination > resort > hotel
When going to the above url, it redirects to the destination node where there is a separate rule like:
/home/?m=destinations&destid=6 -> node/x
So it appears there is a problem with multiple query parameters.
Adam
To explain hopefully a little more clearly...
Let's say I have two urls in an old system
http://myoldsite.com/view.php?list=fruit
That shows all fruit. AND
http://myoldsite.com/view.php?list=fruit&item=apple
That shows a specific fruit (here, an apple).
In the new Drupal site, I want my redirects to do this:
http://myoldsite.com/view.php?list=fruit goes to http://mynewsite.com/taxonomy/term/fruit
http://myoldsite.com/view.php?list=fruit&item=apple goes to http://mynewsite.com/node/apple
Currently, if you create your redirect to http://mynewsite.com/node/apple FIRST, then create the redirect to http://mynewsite.com/taxonomy/term/fruit, all attempts to hit /node/apple will take you to /taxonomy/term/fruit.
| Comment | File | Size | Author |
|---|
Comments
Comment #1
adam clarey commentedNearly found the issue, its because in this function 'redirect_load_by_source' it creates an array of potential redirect urls based on the arguments and query params. In my case above, the urls destination, resort and hotel will all be potential redirect links because of the rules that state if a child page cannot be found, go to the nearest parent page.
So with this array of potential urls it then does a sort in function '_redirect_uasort', here it orders based on language and rid where rid relates to the row position of the csv import and therefore assumes that when importing that rows will be in the order
destination -> node/x
resort -> node/y
hotel -> node/z
but if the order is reversed or random then it will select which ever row comes last as the final url to redirect to.
Which in my case is the incorrect url.
What i think is needed is ordering based on specificity, the url with the most matching query parameters would be selected to redirect to.
Don't you agree?
Comment #2
adam clarey commentedFound and fixed the problem
in redirect.module at line 1419
replace:
elseif (!empty($a->source_options['query']) != !empty($b->source_options['query'])) {
// Then sort by redirects that do not have query strings over ones that do.
return empty($a->source_options['query']);
}
with:
elseif(count($a->source_options['query']) != count($b->source_options['query'])){
return count($a->source_options['query']) < count($b->source_options['query']);
}
Now everything works fine no matter what order the redirects were created.
Comment #3
adam clarey commentedPatch attached
Comment #4
mariacha1 commentedComment #5
mariacha1 commentedThis works great for me, and the code looks fine.
Comment #6
pere orgaI've seen this behaviour in the past, it would be great to have a solution for this committed.
However the code style of the patch does not follow Drupal standards. And ideally we should not delete that comment but replace it for another one.
Comment #7
pere orgaThis is very related (if not duplicate) of #1447460: Problem with url-escaped characters
Comment #8
mfernea commentedHere is the modified patch. It's just about coding standards and comments.
Comment #9
mfernea commentedWe might have problems when some of the redirect don't have query parameters. We get notices.
Here's a better version of the patch.
Comment #10
dave reidComment #11
dave reidComment #12
mfernea commentedHere are the test only patch and the complete patch.
Comment #14
tomsegarra commentedI manually tested the patch from #12, and reviewed the (appropriate) unit test it contains, and all seems to be working properly.
Comment #15
alex_optim+1
Comment #16
pifagor commentedComment #19
pifagor commentedComment #21
Natallia commentedHere is the update of the latest patch from #12
Changes:
As this fragment
return $a_weight > $b_weight;isn't equivalent to
return ($a_weight > $b_weight) ? -1 : 1;for callback in uasort function, the correct variant has been added:
return ($a_weight > $b_weight) ? 1 : -1;Comment #22
Natallia commented