Problem/Motivation

Handling of query strings in URL aliases is broken - for example, it is possible to create an alias /?p=123 pointing to /node/123, but although the alias exists and can be listed/edited/deleted, it will not have an effect. Conversely, it is possible to create an alias /withquery pointing to /my/custom/module?needs=query, but the expected path will not be invoked.

Eight years of comment history on this issue indicate that the former case is attempted often, typically to avoid breakage of existing URLs when migrating from a non-Drupal platform. The latter case seems less requested, which stands to reason given the rare use of query strings in Drupal.

Proposed resolution

For the former case (/?p=123 -> /node/123), questions arise because unlike paths, which always are matched by string comparison, query string parameters are unordered. If /path?product=123&sort=asc should alias /node/4, shouldn't /path?sort=asc&product=123? What about /path?product=123?

The answers to such questions will be site-dependent and could require rules of arbitrary complexity. But, simple support that addresses most users' needs out of the box, as well as a service custom/contrib could implement more advanced rulesets on seems reasonable in core.

In Drupal 8, this alias processing is the purview of the installed InboundPathProcessorInterface implementations, especially Drupal\Core\PathProcessor\PathProcessorAlias. Some attempts at quick fixes in PathProcessorAlias show that simple / seemingly obvious logic like concatenating the query string to the path before sending it to the alias manager do not work reliably, because the path received by PathProcessorAlias has been subjected to arbitrary futzing-with by the other InboundPathProcessorInterface implementations. For example, PathProcessorFront rewrites the path of any URI whose path component is '/' to the site's configured frontpage, which can be anything. PathProcessorAlias receives this rewritten value that bears no relation to the path '/', so your alias /?p=123 will not work. Contrib is able to add additional unknown futzing before PathProcessorAlias as well. Unfortunately, the task of reconstructing a path suitable for alias lookups based solely on the Symfony Request is nontrivial, and involves selectively applying only certain InboundPathProcessors to the Request path. See the discussion in #99 for details.

The patch of #99 hardcodes the set of path processors on a site with no contrib modules that yield reliable alias-style matching into PathProcessorAlias, which works, but has some disadvantages:

  • Modules seeking to implement their own InboundPathProcessorInterface implementations that support alias-style matching, such as to support more complex query parameter matching rulesets, and likely also modules that want to redirect rather than rewrite the path, should be able to use the same logic to build the match string.
  • The set of PathProcessors that need to be applied for aliases to match may depend on the modules in use, for example it already depends on whether or not Language is. If PathProcessors used are hardcoded in PathProcessorAlias, contrib modules can't contribute to the process.

Therefore, the proposed solution is to create a list of InboundPathProcessors that are appropriate for building a path suitable for alias-style matching, a means for non-core to supplement this list, a manager class that applies this list in a stacked fashion, and a means for users besides PathProcessorAlias to call on that manager's services. This is implemented in very little code by extending PathProcessorManager and creating a new service_collector tag which only those path processors providing useful futzing for reliable alias-style matching can be registered with.

"Resolving" the latter case (/withquery -> /my/custom/module?needs=query) might be best done by just disallowing the creation of such things for now -- even if you arrange for the expected route/controller to run, it would be necessary to provide the custom code expecting the query string with the query parameters in all places it might look for them.

Remaining tasks

New tests

User interface changes

May want to add validation to the alias creation form to prevent the latter case, TBD.

API changes

Provides a new service, alias_processor_manager. Some modules (redirect?) may benefit from using it.

Original report by geilhufe

I am trying to create a path alias for "civicrm/contribute/transact?reset=1&id=4"

I have tried escaping the characters without result. It seems like the alias works all the way up the the "?" then basically doesn't pass any of the arguments past the "?".

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

revival’s picture

am having the same problem

pfaocle’s picture

Project: Drupal core » Path
Version: 7.x-dev »
Component: path.module » Code
Category: feature » bug
Status: Fixed » Active

Just noticed this myself, and I posted what I'm up to on this issue. Perhaps related?

pvasener’s picture

I also have the same problem. It seems that the alias in only valid for the part before the exclamation point. BTW, the link you provided above about another maybe-related issue is broken. Can you advise?

pfaocle’s picture

Oops: issue.

tobias’s picture

I'm struggling with this issue myself - esp using civicrm which produces attrocious URLs.. though it also happens when creating menus. Has anyone found a solution to this problem?

mfb’s picture

Project: Path » Drupal core
Version: » 7.x-dev
Component: Code » path.module
Category: bug » feature

Moving this over to a feature request on drupal core.

tobias’s picture

Hi,

Any news with this issue? It is severely hampering my abilities to create clean URLs for civicrm profile pages which I'd very much like to do.

Many thanks in advance for any insights,

Tobias

imrook’s picture

I have recently run into this problem and have a solution that meets my needs so I'll chime in with my two cents here. The part after the '?' character in the URL is called the query string. boombatower created an issue with a patch for this problem here. Some users complained that it didn't work -- I personally haven't tested it. chx doesn't seem too intent on adding the functionality at this time.

But there is still hope. Here's why the problem occurs in the first place: Apache uses mod rewrite to rewrite a URL like

http://mysite.com/drupal/admin/build/menu

to become

http://mysite.com/drupal/index.php?q=admin/build/menu

. During the bootstrap phase, Drupal uses the value of the variable

$_GET['q']

to map a URL to a function call. Now look what happens with the following URL:

http://mysite.com/drupal/path_alias?myvar=1

Apache's mod_rewrite turns it into

http://mysite.com/drupal/index.php?q=path_alias&myvar=1

This is normally a good thing. The problem with Drupal is that the core doesn't look at any other variables besides

$_GET['q']

so it will only use

path_alias

for the lookup. Luckily Drupal provides a place where we can change that:

custom_url_rewrite()

Add the following code to your

settings.php

file:

<?php
function custom_url_rewrite($op, $result, $path) {
  global $user;

  if ($op == 'source') {
    // Get extra variables from URL
    if (isset($_SERVER['QUERY_STRING'])) {
      //Remove the 'q=' and change the first & into a ?
      $query = preg_replace('/^q=([^&]*)&(.*)$/', '\1?\2', $_SERVER['QUERY_STRING']);
    }
    // See if we have a url_alias for our new path
    $sql = 'SELECT src FROM {url_alias} WHERE dst="%s"';
    $row = db_result(db_query($sql, $query));
    if ($row) {
      // We found a node source path
      $result = $row;
    }
  }

  return $result;
?>
}

This will allow you to set a path alias for a node that contains a query string and Drupal will redirect to the correct page. Note that when Drupal generates a link to the node it will be urlencoded, but it will still work properly.

This code is actually written for 5.x In Drupal 6, the function is called custom_url_rewrite_inbound and the parameters have changed a bit. I haven't taken a look at 7 yet so I don't know anything about that.

tobias’s picture

very nice! I have implemented this and it seems to work very well for my site.

One issue I still run into is with a custom civicrm signup form which breaks upon submission when I use your hack with a "Cannot add or update a child row: a foreign key constraint fails" error. Not a big deal since I have already setup apache redirects for these signup forms.

But your hack will help with accessing other civicrm pages from the menu. Many, many thanks. You've addressed one of my major issues with civicrm. I'll be sure to spread the word in the civicrm forum if you have not done so already.

Cheers,

Tobias

imrook’s picture

One issue I still run into is with a custom civicrm signup form which breaks upon submission when I use your hack with a "Cannot add or update a child row: a foreign key constraint fails" error.

Since I'm not using CiviCRM, I'm not very surprised that this approach has some flaws with that module. I did think what I had was relevant and may be a good starting point for others, which it appears is correct. I'm glad I could help at least some with this issue. Since I'm not using CiviCRM, you can feel free to mention this method in that forum but beware that people will probably come back with posts citing all the things that still don't work correctly.

Damien Tournoud’s picture

Subscribing. We need a better solution for that issue.

imrook’s picture

I kinda thought this was too good to be true. I found a problem with the code in comment #8. If a user has "administer menu" permission and edits a node, the cached menu tree that is created will have all menu links pointing to the current node. If you are bittin by this, clear your menu cache with "DELETE FROM cache_menu;" Unfortunately, I haven't found a way to fix this in custom_url_rewrite and have resorted to hacking path.inc during the drupal_init_path() call. I'm interested to see if anyone can find a solution that works within custom_url_rewrite.

haggan’s picture

Is this drupal 6-7 specific or does this hack work on drupal 5.7? I cant get it to work, when I paste it into my settings.php my webpage is just blank...

tobias’s picture

this worked for me on drupal 5.3, except for the civicrm issue I explained above which is why I don't use it.

cheers,

tobias

sonicthoughts’s picture

Version: 7.x-dev » 5.6

Yes - please fix - you can't add any civicrm menus to drupal without a hack. I have found nothing that works with 5.6

StevenPatz’s picture

Version: 5.6 » 7.x-dev

features should go into the latest dev version and then backported.

dgeilhufe@yahoo.com’s picture

Theoretically resolved in Drupal 6:
http://drupal.org/node/90570

dgeilhufe@yahoo.com’s picture

Status: Active » Fixed

Fixed in Drupal 6.x / CiviCRM 2.1+

Anonymous’s picture

Project: Path » Drupal core
Version: » 7.x-dev
Component: Code » path.module
Category: bug » feature
Status: Active » Closed (fixed)

Automatically closed -- issue fixed for two weeks with no activity.

himtuna’s picture

thanks for that fix, I was realy getting annoyed from it.

Damien Tournoud’s picture

Status: Closed (fixed) » Active

How that is fixed?

sbydrupal’s picture

Drupal 6 version available ? thx.

jsimonis’s picture

I tried applying the patch, but it failed.

I'd really like to get this working so I can point /donate to the donation page.

Dave Reid’s picture

@jsimonis The path "donate" does not have a question mark in it...what problems are you having adding an alias for it?

babbage’s picture

I was trying to alias the following url in D6:
http://example.com/civicrm/event/register?id=1&reset=1

I wanted it to display as:
http://example.com/events/2009/conference/register

It wasn't working. Instead it was redirecting to the event configuration page. However, I stumbled upon a solution. If I set the url to alias as:
http://example.com/civicrm/event/register/?id=1&reset=1
...with an extra slash after the "register", it then redirects correctly to:
http://example.com/events/2009/conference/register?id=1

Which works! I don't know if the dropping of the &reset=1 is of significance, but so far it appears to work. So this seems to be a bug, but it's a pretty easy one to work around until it can be fixed.

jsimonis’s picture

Sorry, the page I was trying to alias to /donate is the contribution page in CiviCRM. Those pages all have a question mark in them, similar to those in comment #25 above.

luxx’s picture

I have faced similar issue and have been directed to rewrite urls via .htaccess http://httpd.apache.org/docs/1.3/mod/mod_rewrite.html

Dave Reid’s picture

Title: "?" not supported in a path alias? » Allows query strings in URL aliases

Marked #191917: Allows paths to contain query strings as a duplicate of this issue.

Dave Reid’s picture

Version: 7.x-dev » 8.x-dev

Also bumping version, since this is no longer viable for D7.

duncanc’s picture

We can alter the alias translation by using the custom_url_rewrite_inbound() function.

function custom_url_rewrite_inbound(&$result, $path, $lang) {

  $parts = explode('&', $result);
  
  if (count($parts) > 1) {
    $result = array_shift($parts);

    foreach ($parts as $part) {
      list($key, $value) = explode('=', $part);
      $_GET[$key] = $value;
    }
  }
}

This function examines the translated alias value ($result).

If it contains any query parameters (identified by '&') then new $_GET variables are created for those, and $result returned without those query parameters

How it works
Create alias 'signup' to Drupal path 'civicrm/profile/create&reset=1&gid=7'
$_GET['q'] will be 'signup', and the path module will translate this to 'civicrm/profile/create&reset=1&gid=7'
this function is called by the path module before returning and modifies the result to be 'civicrm/profile/create' which will eventually get back into $_GET['q'] and sets $_GET['gid'] to 7 and $_GET['reset'] to 1.

philipashlock’s picture

Version: 8.x-dev » 6.13

I'm running drupal 6.13 and was having this same issue trying to do URL aliasing for CiviCRM pages. Manually adding the additional slash to the original query string helped somewhat - it seemed to make everything work in Safari or in any browser if I was logged in as an administrator, but I needed to apply this custom function provided here to get it to work everywhere.

Is there a more official fix for this yet?

Dave Reid’s picture

Version: 6.13 » 8.x-dev

Please don't change the meta-data for feature requests in core.

philipashlock’s picture

As an update: It doesn't look like the custom function completely solved the problem - or maybe it just created a new one. I have aliases that look like this:

Alias > Source Path
full-membership > civicrm/contribute/transact/?reset=1&id=6
partial-membership > civicrm/contribute/transact/?reset=1&id=5
deferred-membership > civicrm/contribute/transact/?reset=1&id=8

Each of those aliases only direct to one of the source paths, but not the ones they're assigned to. For some reason they're all pointing to /?reset=1&id=5

duncanc’s picture

The code I posted expects the alias not to contain a '?', but to contain only '&' to separate the parameters. This kind of made sense at the time but isn't intuitive.

Try changing your aliases to be like this:
full-membership > civicrm/contribute/transact/&reset=1&id=6

Otherwise you will need to change the function to split on '?' before exploding the parameters on '&'.

yngens’s picture

I am drupalizing an old site with tons of pages ending with:

view.php?i=12345 (12345 - variable)

I need to either:

1) to find a workaround to make pathauto module generate url aliases with question and equal marks in them like 'view.php?i=[nid]'

2) or to redirect all the requests view.php?i=[nid] to node/[nid]

Second way seems easier to go just with writing in .htaccess proper redirection rule. But there I have problem - for some reason it does not redirect url requests with question marks. I guess, because all the requests go to 'index.php?q='

Could anyone advice me what would be best solution in my case? Thanks!

kenwest’s picture

I have used the code provided by duncanc at #30 (above) and extended it to handle both '?' and '&' characters in query arguments.

To do so, take his code and replace...

$parts = explode('&', $result);

...with...

$parts = preg_split('/[\?\&]/', $result);

Ken

(disclaimer: while I'm confident this change is OK, I'm not an experienced PHP developer, so you should apply this change with caution.)

kenwest’s picture

I found a problem with duncanc's code at #30.

When I try to edit a menu item where the URL has query arguments, the arguments get stripped. To avoid this I made the following change to modules/menu/menu.admin.inc (a change to core, unfortunately)

 /**
  * Validate form values for a menu link being added or edited.
  */
 function menu_edit_item_validate($form, &$form_state) {
   $item = &$form_state['values']['menu'];
-  $normal_path = drupal_get_normal_path($item['link_path']); 
+  /*
+   * drupal_get_normal_path() calls custom_url_rewrite_inbound()
+   * which will remove any query arguments from the URL.  So I'm
+   * replacing  the call  to  drupal_get_normal_path()  with the
+   * code from that function, sans custom_url_rewrite_inbound().
+   *
+   * $normal_path = drupal_get_normal_path($item['link_path']); 
+   */
+  $normal_path = $item['link_path'];
+  if ($src = drupal_lookup_path('source', $item['link_path'], )) {
+    $normal_path = $src;
+  }  
   if ($item['link_path'] != $normal_path) {
Dave Reid’s picture

Title: Allows query strings in URL aliases » Allow query strings in URL aliases
j0nathan’s picture

mrfelton’s picture

The code in #37 doesn't seem to work for me. The querystring still gets stripped off when saving a menu link.

Example. I create a menu item that points to node/1234?somequery=test#fragment and I end up with a menu item that points to node/1234. The entire querystring and fragment has been stripped out, just as without the change in #37.

brian_c’s picture

I appear to have gotten this working in D7 via hook_url_inbound_alter():


// implementation of hook_url_inbound_alter()
function HOOK_url_inbound_alter(&$path, $original_path, $path_language){
  // ensure vars from query string exist in $_GET (needed for URL Aliases with query components)
  parse_str( parse_url( $path, PHP_URL_QUERY ), $_GET );
}

Seems to be working fine, including for Exposed Filter Blocks (my use case was creating friendly URLs pointing to specific search result pages).

Please note you need to add a trailing slash to the path component when defining the URL Alias, as per comment #25, otherwise it won't validate.

So you need to use:

myalias => some/path/?foo=bar

instead of:

myalias => some/path?foo=bar

brian_c’s picture

Here's a better version of the code in #41, that won't overwrite values already present in $_GET (so values from the URL will always take precedence over the "defaults" provided by the URL Alias):

// implementation of hook_url_inbound_alter()
function HOOK_url_inbound_alter(&$path, $original_path, $path_language){
  // ensure vars from query string exist in $_GET
  // this is needed for URL Aliases with query components to work properly
  parse_str( parse_url( $path, PHP_URL_QUERY ), $vars );
  foreach( $vars as $key => $value ){
    // don't overwrite existing values (ie from the actual URL)
    if( !array_key_exists( $key, $_GET ) ){
      $_GET[$key] = $value;
    }
  }
}
brian_c’s picture

Sigh. The URL Alias works properly (in terms of feeding the right query params to the page), but I can't then add that alias as a Menu Link properly (even though that works fine for "normal" aliases)... the underlying path shows through when displaying the menu, instead of the friendly alias. Which was the whole point. :(

Edit: For the record, was able to fix this using THEME_menu_link() to intercept the link, overwriting [#href] to the desired alias, and unsetting ['#localized_options']['query'].

webchick’s picture

Category: feature » bug

This is not a feature request. This is a straight-up bug. It might even be a 'major' bug. As long as Drupal can generate paths with ?s in them, it ought to be able to alias them.

I hit this trying to create a path alias to /project/issues/search?projects=&status[]=1&status[]=13&status[]=8&status[]=14&status[]=15&status[]=2&issue_tags=Novice

webchick’s picture

Tagging for backport.

mrfelton’s picture

Priority: Normal » Major

@webchick - totally agree. Seems like a pretty major issue to me. Tagging the issue as such.

bfroehle’s picture

Obviously this could be easily done with a redirect.

In D7 the magic path alias to normal path is run in drupal_path_initialize(). If query strings were allowed in the path they'd have to be processed here and injected into $_GET.

missmobtown’s picture

Subscribe.

scott.whittaker’s picture

Subscribe

catch’s picture

Priority: Major » Normal

This is anything but a major bug, the issue has been around since 2007, and webchick marked the duplicate issue as a feature request in 2008: http://drupal.org/node/191917#comment-958209

I'm not sure drupal_path_initialize() is the right place to do this though. Or at least if we do it there, then we'd only be supporting aliases one way.

Trying to do it the other way would be a can of worms - since when you call url(), $_GET parameters go into $options, not in the url string, so there is no way to look it up at all.]

In fact I'm tempted to mark this won't fix, because of this:

If you provide only the path (e.g. "node/34"), it will be considered an internal link. In this case, it should be a system URL, and it will be replaced with the alias, if one exists. Additional query arguments for internal paths must be supplied in $options['query'], not included in $path.

system url = path resolvable to a menu router item. So we make it clear that aliases are only supported for that, not for any of the extra crap that can be added to a url.

bfroehle’s picture

In fact I'm tempted to mark this won't fix

I didn't come out and say it directly in #47, but I certainly agree. This would be a huge feature addition and very difficult (if not impossible) to engineer correctly. There are numerous other ways to accomplish something similar (including using path redirection or mod_rewrite directly).

mrfelton’s picture

Is asking people to use mod_rewrite so that they can create a menu item for a page that the created in Drupal really an acceptable solution? What percentage of Drupal user's do you think know what mod_rewrite is, let alone how to use it? Granted, it possible to do it with the path_redirect module, but this requires installation of a module for something that really should be a basic task, as well as setting up dummy redirect paths just so you can get something in the menu.

catch’s picture

Category: bug » feature
Issue tags: -Needs backport to D6, -Needs backport to D7

This issue isn't about menu items, it's about URL aliases.

The design of the URL alias system, url() etc. is very explicit that it only supports 'system paths', in the same way we don't allow separate router items to exist based on $_GET params either. So changing that is a feature request since it's currently by design.

If links like this don't work as menu items, that's a separate bug report but has nothing to do with this issue.

scott.whittaker’s picture

I don't think we need to support the entire gamut of url() functionality, but the ability for non-developers to create one-way path aliases is extremely useful, bordering on necessary. Same goes for allowing querystrings in menu items. Views filters especially can make some funky URLs that would be usefully served by allowing short semantic aliases.

joetsuihk’s picture

re #53 I think supporting extra $_GET params as destination in alias is a feature request, but not having error message when saving a system path with ? is a bug. At least, add more descriptive helping text in add URL alias page.

sbydrupal’s picture

Not a programmer. For #42, and #43, where shall we place the codes ? Thank you!

I think the purpose of we are using a CMS is to have such utility functions available without programming and getting into details of mod rewrite or core drupal function modifications. Url aliasing with ? seems to me is important for SEO purposes and I dont see why it should not be default functionality available. In many cases using views exposed filters, I don't see any other practical solution, otherwise, creating views for every possible filter combination which doesn't make sense.

brian_c’s picture

The code in #42 would need to go in a custom module, with 'HOOK' replaced with the name of the module. (Other than the name change, the code in #42 can be used exactly as is.)

The code (or rather, the approach outlined) in #43 would need to go in your theme's template.php file, with 'THEME' replaced with the name of your theme. It will need custom "hard coded" values to use... a less than ideal solution, but it worked for our limited needs with a small, fixed number of "aliased queries". Our code for #43 looks something like this:


function THEME_menu_link(array $variables) {
  
  // For aliases that use query strings (ie, pre-defined search queries), 
  // the menu system shows the unaliased path (ie, foo/search?subject[]=2),
  // so we do a manual override here.  This will break if the menu IDs change from the hard-coded values here.

  // hard-coded table of MLIDs => aliases
  $link_overrides =  array(
		844 => 'foo/bar',
		845 => 'some/other/alias',
		870 => 'yet/another/alias'
  );
  
  $element = $variables['element'];

  foreach( $link_overrides as $mlid => $href ){
    if( !empty( $element['#below'][$mlid] ) ){
      // override the HREF to use the alias we want
      $element['#below'][$mlid]['#href'] = $href;
      unset( $element['#below'][$mlid]['#localized_options']['query'] );
      $element['#below'][$mlid]['#original_link']['hidden'] = 1;
    }
  }

}

Hope this helps.

sbydrupal’s picture

Thx Brian!

Donsov’s picture

i need allow ?param=value in taxonomy_menu path alias i tried accept these hooks but they don't work

NicoDruif’s picture

subscribing, because I also encounterd this issue, because I want to use the rendered exposed filter url with arguments in it, in an path alias...

NicoDruif’s picture

I tried to create a custom module, following suggestions in comments #42 and #57, but it did not work out.

It still does not work, because my drupal 7.14 installation won't validate an alias with arguments, even with a trailing slash like:

bestemming/wenen/?field_bestemming_nid[]=75&sort_by=field_prijs_value&sort_order=ASC

Too bad! Any suggestions are very welcome!

I will now try a solution like suggested on http://drupal.org/node/210430...

NicoDruif’s picture

Well, at the end of the day I just ended up writing custom RewriteRules for every url I want to alias. Like:

#custom rewrite rules for exposed filters
  RewriteRule ^wenen/?$ ?q=node/75&field_bestemming_nid[]=75&sort_by=field_prijs_value&sort_order=ASC [L]

before the default drupal rewrite section

  # Pass all requests not referring directly to files in the filesystem to
  # index.php. Clean URLs are handled in drupal_environment_initialize().
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_URI} !=/favicon.ico
  RewriteRule ^ index.php [L]
globber’s picture

Having the same problem with Drupal 7.15.

urls look like this:
?q=browse&f[0]=vocabulary%3A9

sonicthoughts’s picture

Version: 8.x-dev » 7.15
jsimonis’s picture

Wish we could get this working. I'd like to create links to specific filters on our calendar, like http://www.rmcptk.org/calendar/month?field_location_tid%5B%5D=12

I tried URL aliases. Doesn't work. Tried linking straight to that page in the menu. Didn't work. I end up with extra characters in the address, which keeps it from working.

sonicthoughts’s picture

RESOLVED WORKAROUND: Use Global Redirect module.

NicoDruif’s picture

How does the Global Redirect module resolve this issue? What setup do you use? Thanks!

nchicong’s picture

Such feature should be supported in Drupal 7. @sonicthoughts, what settings did you have to get it work with Global Redirect?

sonicthoughts’s picture

No settings - there were no issues with query strings that I've come across.

svouthi’s picture

Version: 9.x-dev » 7.15

I am running Drupal 7.19 and have Global Redirect installed, but am experiencing the same issue on my e-commerce site.

My Views pages have Simple Hierarchical Select (shs) exposed filters, and instead of displaying the selected taxonomy terms in the results page urls, they display: ?shs_term_node_tid_depth=%. I would love to fix this.

So far, I've altered the Filter identifiers in Views for each of my exposed filters. I replaced the "shs_term_node_tid_depth" with my custom text, but that still leaves the leading "?" and "=%". It would be great to show the tiers of user selections automatically instead.

marcingy’s picture

Version: 7.15 » 9.x-dev

Features go into latest version of drupal first and then might be backported.

gaurishankar’s picture

Version: 7.15 » 7.22

Hey
After over viewing all the above suggestion i'm not getting solutions.
I have to alias www.example.com/manager?cust=5 to www.example.com/manager/anything
this aliases also takes internal value like ?cust=5.

Have you any exact solution in D7.

Many Many Thanks in advance for this solution.

StevenPatz’s picture

Version: 7.22 » 9.x-dev
Exploratus’s picture

Interested in a solution for clean exposed filters urls as well.

kenorb’s picture

pitxels’s picture

Global redirect module is working for me as well, but only on the menus not in the aliases

The trick on the menus was using absolute URLs. Hope that helps

edenb’s picture

Issue summary: View changes

I have Read all suggestions above.

My goal is to direct users that click on taxonomy term to a search page, which the relevant filter will be already filtered on.

I am using URL aliases,
and trying to direct taxonomy to: www.example.com/search-content?tid=777
I get: www.example.com/search-content%3Ftid%3D777

I have Global redirect installed, but it's still not working.
I also tried URL direct, but I get the same result with html code (%3F), instead punctuation ("?").

Is there any solution?
Or even any work around?

aparnapc’s picture

aparnapc’s picture

vishal.sirsodiya’s picture

I also have the same problem.

webchick’s picture

Version: 9.x-dev » 8.1.x-dev
Status: Active » Postponed
alcroito’s picture

In case if anyone is interested in the specific use case of rewriting paths with query parameters into a clean URL, there is a contributed module that addresses that.
https://www.drupal.org/project/query_parameters_to_url

It can turn something like
example-site.com/events?field_category_id[0]=100&field_category_id[1]=101&field_author_name[0]=John&field_author_surname[0]=Doe

into
example-site.com/events/p/field_category_id/100-101/field_author_name/John/field_author_surname/Doe

anderso’s picture

The "Query Parameters to URL" seems to work well - I just tested on a D7 site.

But it does not solve the problem of creating menu items with queries in the URL. I tried and Drupal returned a message that the menu system only stores system URLs, not aliases. Hence, the URL created by "Query Parameters to URL" cannot be used as a menu item.

For me, using "Query Parameters to URL" also caused infinite redirects. I needed to deactivate "Global Redirect" to get it to work and this of course creates new problems with duplicate content.

The only way I could get a menu item with a "?" query in the URL to work was to use an absolute URL as the link. And this causes other issues: 1) not being able to let the user's browser settings choose between HTTP and HTTPS and 2) updating issues and ekstra work if you work with a DEV, TEST and LIVE environment.

alcroito’s picture

1) Regarding menu items, indeed you are right, that it stores the initial url. I'm not sure if this can be fixed, but I'll look into it.
2) I am aware of issues with global redirect, and am trying to work on it. But more specific details would be welcome. Try downloading the latest DEV version of the module, some global redirect issues where fixed there.

Also I'm not sure if this is the best place to discuss about the module. This should be used for fixing the problem in core.

EDIT: I have added experimental code to the Dev version, to allow saving menu items with the encoded query parameters, which can be enabled in the configuration form of the module. Though I consider this a hack.

fjgarlin’s picture

I had the same problem and created a simple module (8 lines!) that does the trick for me. I found this thread from here.

Assuming the module is called "my_url_special_chars", the code is as follows:


/**
 * Implements hook_preprocess_html
 */
function my_url_special_chars_preprocess_html(){  
	//bring current url info
	$url = drupal_get_path_alias();
	$query = drupal_get_query_parameters();

	//url seems to be: "path?field=value" - (encoded) "path%3Ffield%3Dvalue"
	if (strpos($url, '?') !== FALSE and empty($query)){
		//we'll have $url['path'] = 'path' and $url['query'] = 'field=value'
		$url = parse_url($url);	
		
		//make $query associative array
		parse_str($url['query'], $query);		
		
		//go to where you were supposed to go from the beginning
		if ($url['path'] and is_array($query))
			drupal_goto($url['path'], array('query' => $query));
	}
}

There might be another way to solve it, but this did the job for me. Basically I parse the URL and if I find a potential encoded query string I try to go there. That's it. It means that in URL alias patterns I can use "url?key=[term]".

I hope it helps.

arruk’s picture

#85 not working for me....

  1. created the module
  2. turned it on
  3. tried to add alias with ?field_myterm_tid=45 and ?field_myterm_tid[0]=45

Both terms report: ...is either invalid or you do not have access to it. Access is not the problem. This is for a views created page.

Any thoughts? Thank you :)

fjgarlin’s picture

Hi,

Can you dump what's on $url['path'] and $query before doing the drupal_goto?
I've tried this module with replacement patterns, not hardcoded ids, but it should still work anyway.

Let us know what's the output of the dump.
Thanks.

winstonchurchil99’s picture

I reviewed the #85, this version works fine with drupal 7, just don't use 'q' as query parameter.

<?php
/**
 * Implements hook_preprocess_html
 */
function yourmodulename_preprocess_html(){  

//bring current url info
    $url = request_uri();
    $query = drupal_get_query_parameters();
    
    //url seems to be: "path?field=value" - (encoded) "path%3Ffield%3Dvalue"
    if (strpos($url, '?') !== FALSE and empty($query)){
        //we'll have $url['path'] = 'path' and $url['query'] = 'field=value'
        $url = parse_url($url);
       
        //make $query associative array
        parse_str($url['query'], $query);

       
        //go to where you were supposed to go from the beginning
        if ($url['path'] and is_array($query))   drupal_goto($url['path'], array('query' => $query));
    }

}

?>
anbudhan’s picture

Hi I am trying to get data from drupal service api using postman.

https://btycc-prod..net/api/v1/entity_commerce_product?parameters[create...
can some one tell me how to get set the parameter to download lesserthan a specific date?
I tried https://bcc-prod.codeenigma.net/api/v1/entity_commerce_product?parameter... <=1428930969:

but it is not working. any help will be hugely appreciated

kenorb’s picture

@anbudhan This is not a help page, but feature report. Try asking your question at DA.

mbaynton’s picture

Anyone considering implementing this should be aware of #1553358: Figure out a new implementation for url aliases, especially starting around #1553358-40: Figure out a new implementation for url aliases wherein some consensus forms. At time of this post, these are both 8.1.x-dev issues and should be developed with knowledge of each other.

mbaynton’s picture

8 years and 92 comments later, here's a first stab at a solution. It's late but I'd like to see what testbot has to say about this -- seems there may be a quick enough solution to this that it might as well be handled under the current state of affairs, even if it would need significant rework in #1553358: Figure out a new implementation for url aliases. Still need to evaluate it wrt. multilanguage sites/aliases.

mbaynton’s picture

Hmph. Any way to let the bots in the cloud run the tests for me, without un-postponing it?

webchick’s picture

Version: 8.1.x-dev » 8.0.x-dev
Status: Postponed » Needs review

Temporarily putting to needs review on 8.0.x so testbot can take a crack at it. Way to completely kick ass, Mike! :D

Status: Needs review » Needs work

The last submitted patch, 92: 118072-92.patch, failed testing.

dawehner’s picture

+++ b/core/lib/Drupal/Core/PathProcessor/PathProcessorAlias.php
@@ -37,8 +37,17 @@ public function __construct(AliasManagerInterface $alias_manager) {
+    $uri_dealiased = $this->aliasManager->getPathByAlias($request->getRequestUri());
+    if($uri_dealiased !== $request->getRequestUri()) {
+      return $uri_dealiased;
+    } else {
+      return $path;
+    }

I would vote to use $path . '?' . $request->getQueryString()

mbaynton’s picture

I would vote to use $path . '?' . $request->getQueryString()

I don't think that'll work, because according to Symfony docs, "It builds a normalized query string, where keys/value pairs are alphabetized and have consistent escaping." So I have to know that when I want to alias /thing?query=abcd&page=1 I better actually create the alias as /thing?page=1&query=abcd.

I'm also unsure whether $path is a part of the thing that an alias match should even be attempted against, because $path can be pre-futzed in any unknown way before it's tested against the defined aliases. Since de-aliasing is itself a kind of futzing, it was implemented in the stack of path futzers, but perhaps became an unwitting participant in an overly complex system as a side-effect. If my browser goes to '/a/b/c/d' and I've defined an alias for '/a/b/c/d', is there ever a time when I wouldn't want it to match? If not, de-aliasing should look right at the request URI, with the only possible preprocessing being IRI decoding.

Will look into the test failures later today.

dawehner’s picture

Good point!

Well, your implementation won't work because the request URI includes the base path. Could we just use $this->server->get('QUERY_STRING')?

mbaynton’s picture

Status: Needs work » Needs review
FileSize
5.9 KB

@webchick, thanks for noticing my patch and setting this issue so it's testable!

@dawehner, thanks for the tip on $this->server->get('QUERY_STRING'). I wonder if this might cause wrong breadcrumbs from PathBasedBreadcrumbBuilder, but we'll deal with that later I think.

The complexity on this ended up ratcheting up a notch or two...of course. If someone sees a simpler way let me know. These obvious things to try don't work:

  • Solutions based on $path, such as $path . '?' . $this->server->get('QUERY_STRING'): doesn't work because it falls victim to the layers of futzing that already happened to $path. In the case of a url whose path looks like the frontpage, ie [drupal]/?p=123, the $path is rewritten to whatever the configured path for the frontpage is ('node' by default) by the time it is received at PathProcessorAlias, and you end up asking the AliasManager to de-alias node?p=123. For this issue's objective, that is bad futzing.
  • Solutions that use data from $request as a direct substitute for $path, such as substr($request->getRequestUri(), strlen($request->getBasePath())): doesn't work, mainly because the AliasManager expects any language identifiers to have been removed from the path if multilingual's on. That's usually handled by PathProcessorLanguage, which is good futzing for this issue, but is bypassed since not using $path. (This code is also no good because of internationalized uri incompatibility and the fact that it lets you define aliases including URL fragments that would actually impact the response, which is worse Internet abuse than the query parameter order being important that this issue enables.)

The only thing I could think to do then was to start with $request->getPathInfo() + $request->server->get('QUERY_STRING'), pull in the "good" futzers, and apply only them before de-aliasing. This works, more or less, with some subtleties I still need to address. I probably am accessing the other PathProcessor services wrong, those code patterns are still new to me. But this is a good stopping point to see if anyone sees a simple/obvious better way before finishing polish on this one (to include new tests.)

A general note about the objective/rationale of this patch: it intentionally processes query strings by string equality comparison; so ?var1=abc&var2=def does not yield the same response as ?var2=def&var1=abc. I justify this as acceptable because 1) it's sufficient to make lots of the above discussed use cases "just work", 2) it's simple, 3) if a particular site finds such things unacceptable, just refrain from creating aliases that utilize them, and 4) this change wouldn't prevent a contrib module sitting on top of it to define more complex rules about which query parameters have which impacts on path futzing.

This passed a subset of likely tests locally, crossing my fingers...

Status: Needs review » Needs work

The last submitted patch, 99: 118072-99.patch, failed testing.

mbaynton’s picture

Looks like some more unit tests would need updating, but simpletests all green.

dawehner’s picture

Issue tags: +Needs tests

We should certainly expand the test coverage for this new feature.

mbaynton’s picture

Just feeding the testbots -- this is still a WIP, but also a much improved rewrite from #99

mbaynton’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 103: 118072-103.patch, failed testing.

dawehner’s picture

To be honest I don't get why we can't just put the logic into the alias path processor and be done. The additional abstraction seems not necessary for me.

Do you mind explaining it a bit in the issue summary?

mbaynton’s picture

Issue summary: View changes
mbaynton’s picture

Issue summary: View changes
mbaynton’s picture

Question: handling query parameters irrespective of query string order could be accomplished at the AliasStorageInterface level, by just stipulating that lookupPathSource detects query strings in any aliases passed to it, and returns the corresponding path regardless of parameter order. In core's AliasStorage implementation you'd do this by just transforming any query string present in an alias to its normalized form in Drupal\Core\Path\AliasStorage::save, and again in lookupPathSource. But, would that kind of logic be appropriate for a storage class?

mbaynton’s picture

Issue summary: View changes
FileSize
10.18 KB

Here's a (first) patch that I expect will pass all existing tests. Writing a complete set of additional test coverage for this approach would presumably involve some unit tests of the new service, but I'm still wondering if @dawehner (or anyone) thinks the functionality I've split out to a new service is justified, now that I've written up my rationale in the issue summary. Depending on that I'll do the time investment on new unit tests or not.

mbaynton’s picture

Status: Needs work » Needs review

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

dawehner’s picture

Status: Needs review » Needs work

We should really have tests ... that's kind of important to not get stuck in one specific implementation.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

drupalninja99’s picture

Right now I get a 404 going from alias /test to /node/1?foo=bar even if the latter system path works on its own.

kiss.jozsef’s picture

Any update on this , or any other idea how to accomplish this ? i am getting 404 errors too

mbaynton’s picture

I resorted to just telling Apache to do the redirects via server / .htaccess configuration

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Spudley’s picture

I would like to add my voice to the others who are asking for this. It seems like a simple request to be able to make a path alias for /node/1?foo=bar. Please Drupal, can we fix this?

Falco010’s picture

Any update on this? Facing similar issues

mlncn’s picture

Also need this. We only need from /simple-alias to /internal-path/?query=this&otherquery=that. It seems that the approach in this issue is to handle both directions at once, so we'll try to support that, but wondering if it would be better to take the two needs separately? And i don't understand why this seemingly simpler case (just don't throw away the configured query string!) is being recommended against even being allowed in the present issue summary.

Version: 8.6.x-dev » 8.8.x-dev

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

StijnStroobants’s picture

Old topic, but it still looks relevant.
Are there any updates on this?

Pasqualle’s picture

Version: 8.9.x-dev » 9.2.x-dev

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

ankithashetty’s picture

++ on the feature request.
Even the pathauto module does not allow us to add tokens as query parameters.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

ressa’s picture

I agree @ankithashetty, this would still be a great feature to add to the Path module.

prudloff’s picture

FileSize
10.77 KB

I tried to reroll the patch for Drupal 10.1.

It applies correctly and does not crash but I think it does not do what we need so I have not tested it fully.
We need to create an alias from /foo to /node/42?foo and if I understand the patch correctly, it only handles the reverse scenario /?foo to /node/42?