Early Bird Registration for DrupalCon Portland 2024 is open! Register by 23:59 UTC on 18 March 2024, to get $100 off your ticket.
We are developing a site which makes use of Commerce Multicurrency, but we need to be able to cache pages for anonymous users. As things stand, users will be presented with the cached page, regardless of which currency is set in the commerce_currency cookie. Is there a way to cache pages for each currency and return the appropriate page based on the value of commerce_currency?
Comment | File | Size | Author |
---|---|---|---|
#56 | commerce_multicurrency_geo.zip | 2.34 MB | alancooney |
#56 | cache_alter.patch | 1.56 KB | alancooney |
Comments
Comment #1
stefok CreditAttribution: stefok commentedi had same problem, and solved it with another module http://drupal.org/project/cache_actions (maybe not the best solution but better than site without enabled cache).
Create new rule with name like "clear cache after select currency"
Event -> After the user currency has set
Actions -> Clear cache bins (i have block + page)
Hope it will help ;)
Comment #2
HyperGlide CreditAttribution: HyperGlide commentedHello -- we have a similar issue with currency and caching.
In conversation with one developer not familiar with commerce_multi_currency suggested reloading the price field(s) for the conversions with AJAX.
Thoughts?
Comment #3
michaellenahan CreditAttribution: michaellenahan commented@stefok: thank you very much!
The exact solution you suggest works perfectly for me.
Some more detail, to make this issue more discoverable via Google, and a bit more newbie-friendly:
For anonymous users, the currency switcher drop-down was having no effect because "cache pages for anonymous users" was set in admin/config/development/performance.
Logged-in users were able to change currency without any problem.
The cache_actions module allows us to define a rule which will clear the cache after certain actions have occurred on the site.
I followed the instructions in #1 and it solved the problem for me.
Comment #4
Prague man CreditAttribution: Prague man commented@stefok: great issue, thank you!
Comment #5
stefok CreditAttribution: stefok commentedNP, i am glad to share working solution. But remember, this is just first aid and imho not usable on sites with thousands visitors per day, because it clear cache every time when non default currency is selected.
Comment #6
pokadan CreditAttribution: pokadan commenteduse cacheexclude to exclude specific pages?
Comment #7
das-peter CreditAttribution: das-peter commented@poka_dan Good idea :) Using CacheExclude to exclude pages, where prices are generated, from being cached in the page cache sounds like a viable approach.
Comment #8
mfgering CreditAttribution: mfgering commentedHow about another solution: modify the currency links to include a query parameter that should defeat a caching system?
The multi-currency module theme template creates currency links of the form commerce_currency_select/curr-code?destination=dest, for example: commerce_currency_select/AUD?destination=node/423 The currency module uses the destination parameter to redirect after changing the user currency. If the link is modified to include an embedded query parameter with a random or unique value, e.g. a timestamp, e.g. ?time=123456, the redirect will include it and (hopefully) defeat the caches. This parameter must be url-encoded, e.g. commerce_currency_select/AUD?destination=node/423%3Ftime%3D1361365080.
It appears to work. A slight modification to the multi-currency module's template, commerce-multicurrency-selector-menu.tpl.php seems to do the trick. I've tested this with a template override for our theme. But I think it might be a good option to include with the module, perhaps controlled by a module setting.
Comment #9
das-peter CreditAttribution: das-peter commented@mfgering: The effect will be gone as soon as you change the page using another link, as you'll loose the "random" url parameters. So that isn't a very sustainable approach.
To be sustainable you would need to implement something like the language path-prefix / sub-domain.
Comment #10
mfgering CreditAttribution: mfgering commented@das-peter: Thanks for pointing that out. The use case this satisfies is where the currency select form and the relevant prices are on the same page.
However, now I'm thinking even in that case a better solution might be to use the new currency code in the query parameter instead of a random or unique value. This way, the cached pages are indexed by the selected currency; ultimately there could be X versions of a given page in the cache, each with a different currency selection.
I'd like to understand your suggested approach. Do you mean we could encode the currency selection in the domain name, e.g. aud.foo.com and eur.foo.com?
Comment #11
das-peter CreditAttribution: das-peter commentedI don't know if this is a viable way, it just came to my mind because of the similarity between currency codes and language codes. So if you plan to do something like that checkout how the language prefix stuff works and maybe you're able to reproduce that for currencies as well.
Comment #12
codekarate CreditAttribution: codekarate commentedHere is my approach which appears to be working. It is just an additional function added to the commerce_multicurrency module that redirects the user based on the currency they have selected by adding a query string parameter to the URL. This was a quick fix and I know it will not work correctly if your site makes use of query strings in a lot of other places (potentially with things like views filters, etc). It can most definitely be improved upon and I welcome any suggestions to make it better. Note: It also will most likely not work if your Drupal site is in a subdirectory.
I just added this to the commerce_multicurrency.module file:
Comment #13
Lukas von BlarerIs there no way of altering the page cache and make it sensitive to the currency cookie?
As a temporary solution I will be using the CacheExclude approach. @poka_dan Thank you for pointing that out.
Comment #14
Lukas von BlarerI spent some time tying to figure out how to solve this. First I tried the approach described here: http://drupal.org/node/361832#comment-4204294 But it appears that this is not working in D7 anymore.
Then I tried to use this hook_url_inbound_alter() but I was always being redirected as soon I changed the path.
The only reliable solution I came up with was hacking drupal_page_set_cache() and drupal_page_get_cache() by appending the currency code to the cid.
What I am really confused about is that I couldn't find a way to alter the path or cid. Am I missing something?
Comment #15
rphillipsfeynman CreditAttribution: rphillipsfeynman commented#1 worked perfectly for me. Thanks
Comment #16
rphillipsfeynman CreditAttribution: rphillipsfeynman commented#1 worked perfectly for me. Thanks
Comment #17
heyyo CreditAttribution: heyyo commentedThe solution in #12 works great and cache every pages without clearing anything when switching currency
The only thing I changed is the test on the ajax call , which didn't work on my multilang website where all urls are prefixed with lang :
Replaced by:
I'm not sure what the performance impact to call hook_boot on each page.
I suppose we could also add a condition to return right away if the user is logged in, or in admin section.
Comment #18
Lukas von BlarerYes, #12 works but it is not a solution to the problem to redirect every single request to a URL with appended currency code. We have a caching problem. So we should try to solve the problems with caching and not just make it happen with a ugly workaround.
Comment #19
das-peter CreditAttribution: das-peter commentedThat's indeed an issue and actually one of the core hacks I apply to all our customers installations. We've often the need to build complex caching mechanisms and thus we need to alter the page cache cid. The proof of concept code/module is actually available here: https://github.com/das-peter/enhanced_page_cache
It allows you to exclude certain pages from page cache based on the path, too.
Comment #20
Lukas von BlarerThank you for that statement. The only way to get this working is to hack core?
Should we provide a patch with the module to ease the installation? Or a note in the readme.txt how to do it and where to get the patch?
Seriously... why is there no hook that allows us to alter anything? Is there a chance of getting one into core? Is there an issue report for this?
Comment #21
das-peter CreditAttribution: das-peter commentedIf "this" is referring to changing the page cache cid -> yes. Otherwise -> no, the idea of having a currency path prefix, similar to the language path prefix, still seems to be a possible approach to me (#9).
No I don't think so.
That's more likely.
I'm not joking, but feel free to check the code - it's open source :P
Well, I'm not convinced at all that such a change would made it into core. So as far as I remember I didn't even try. What means: no there's no such issue report - at least none from me.
Comment #22
heyyo CreditAttribution: heyyo commentedI found this Drupal issue #1303010: Page cache only uses URL as cache ID, not HTTP Accept headers or language
Comment #23
Lukas von BlarerJust for my case I am going to hack core rather than adding a basically unnecessary parameter to my URLs. But maybe we should provide an option for this as a temporary solution?
And show here the two options.
Well, I did look at the code and that was my conclusion. I just wanted it to be confirmed by someone else ;)
@heyyo Thank you for pointing that out. Sadly I think I cant really help in that discussion.
Comment #24
Lukas von BlarerI applied your patch and wrote the following code in my custom module to make this happen:
What do you guys think? Seems pretty decent to me, except hacking core...
Comment #25
Lukas von Blarer@das-peter The condition
if (!stripos($cid, '|currency='))
is there because i had double parameters at the end of the cid. Any idea why the hook is being called twice?Comment #26
andrea.brogi CreditAttribution: andrea.brogi commented#1 work for me.
Comment #27
tamnv CreditAttribution: tamnv commented#1 work for me. Thanks!
Comment #28
szeidler CreditAttribution: szeidler commentedIsn't #1 an approach, that creates a lot of side-effects, when two or more people using the currency switcher at the same time? If your commerce installation is dependent on the anonymous users currency selection and not just for displaying the price it would create a lot of confusion. Or am I completely wrong?
Comment #29
jantoine CreditAttribution: jantoine commentedThanks @das-peter and @Lukas von Blarer! #19 and #24 work great! One thing I had to do was manually update the system table setting the bootstrap column to 1 for my module as I was altering an existing module. See https://www.drupal.org/node/1958132#comment-7302018 for an explanation.
Comment #30
das-peter CreditAttribution: das-peter commented@jantoine Hmm, I thought if your module implements
hook_boot()
the module is registered automatically as "boot" module (see_system_update_bootstrap_status()
). Not sure if manually changing that flag in the DB will survive a cache-flush.Comment #31
N20 CreditAttribution: N20 commentedI applied the patch from #19 and enabled the module. In the module settings i added
commerce_currency_select/*
as excluded from pages to cache. This only works if i set the cache lifetime to 0 in the module settings.Hope there will be a solution without hacking core..
Comment #32
Dr.Osd CreditAttribution: Dr.Osd commented#1 works! Thanks to @stefok
Comment #33
vikas_gate6 CreditAttribution: vikas_gate6 commented#1 works! but some time currency will automatically change. Anybody have any solution or idea why this happen.
Comment #34
Dr.Osd CreditAttribution: Dr.Osd commented@vikas_gate6 if your currency reset to default, maybe you clean cookies..
Comment #35
vikas_gate6 CreditAttribution: vikas_gate6 commented@Dr.Osd thanks for reply. It's not reset to default currency it will take any of currency in the drop -down. And when i clear cookies from browser currency reset to default so i don't think cookies clear caused this issue.
Any other solution or idea.
Comment #36
zero4281 CreditAttribution: zero4281 commentedI ran into this same issue and disabling or circumventing the cache is not an option for me. After reading this thread I was left wondering why this module is using a Cookie and not the PHP Session. The Cookie is only referenced in a few places so I patched it in a few minutes. The two functions in question are commerce_multicurrency_set_user_currency_code and commerce_multicurrency_get_user_currency_code, both functions are in commerce_multicurrency.module.
All I had to do in commerce_multicurrency_get_user_currency_code was change $_COOKIE to $_SESSION. In commerce_multicurrency_set_user_currency_code I changed $_COOKIE to $_SESSION and I replaced this:
with this:
Everything still seems to be in working order for my configuration.
Comment #37
das-peter CreditAttribution: das-peter at Cando commented@zero4281 Are you aware that a session uses a cookie too? And that a session with data disables page caching¨?
Comment #38
zero4281 CreditAttribution: zero4281 commentedThank you for pointing that out! What I actually need is default currency by domain which you just patched into the latest dev. I'll be testing it with Domain Access shortly!
Comment #39
Dr.Osd CreditAttribution: Dr.Osd commentedAfter some time of using #1 I noticed a serious problem.
#1 works but not good. If you change currency from anonymous user, currency will be changed for all other anonymous users.
This makes #1 unusable.
Comment #40
RAWDESK CreditAttribution: RAWDESK commentedI've applied both Peter's patch and Lukas's custom module implementation but neither one of them or in combination worked for me.
Setting the enhanced page cache page exclusion option to product/* didn't prevent my product pages to be cached also.
Therefore i tried smthomas's approach at #12 and this miraculously seems to work perfectly, even on my faceted search pages (setted up with Search API) with tons of additional added query string parameters.
I have the impression that as long as the ?currency= parameter is putted first in the URL, which happens in my case, the multi currency pages are cached and shown correctly to anonymous users.
Comment #41
sergei_brill CreditAttribution: sergei_brill commentedThere another way how to alter the cid - just define your custom cache class where you will be able to generate your own cid. This module https://www.drupal.org/project/cookie_aware_page_cache does it and uses cookie parameter as part of cid. And it doesn't require to alter the drupal core. Let's test it. If it works, will ask commerce_multicurrency maintainer to mention the module in README.txt
Comment #42
roland.molnar CreditAttribution: roland.molnar at Technocrat commentedA good solution - which is working for me - is to use authcache.
In order to make it work, you need to do the following alongside of installing and configuring authcache:
Add the following code to your settings.php
This will use Commerce Multicurrency cookie and append it to the Authcache key so Authcache will serve different cached pages based on this cookie value (the user's currency).
You need to add your own sanitize function to make sure cache keys will get only allowed values (using an in_array() for example).
Unfortunately, this alone isn't enough, my testing showed that the currency switcher works well until the user adds something to the cart (= Commerce starts a session for the user). After starting a session, when a user changes currency, the current page doesn't change so need to refresh it or navigate to another page in order to see prices in the newly selected currency. I solved this by adding an extra redirect to the submit handler of the selector form:
You should do this in a custom module (replace MODULENAME to your module's name).
Comment #43
Dr.Osd CreditAttribution: Dr.Osd commentedMaybe #12 is the simplest solution, but in my case users have been redirected to home page when try to switch currency. (I have multilingual site).
Solution #42 need memcache on server and not be implemented on my hosting.
Solution #41 not easy to understand. @sergei_brill can you give more info please!?
Comment #44
RAWDESK CreditAttribution: RAWDESK commented@Dr.Osd,
I am using #12 and it's working on my multilingual site without redirection.
Before enabling i18n module i did have to implement a hook_preprocess_html to insert no-caching headers in the html.
see http://stackoverflow.com/questions/49547/making-sure-a-web-page-is-not-c...
It helped me solve a few other issues with multicurrency, especially on commerce cart checkout panes.
Maybe you can give it a try too.
Comment #45
heatoni CreditAttribution: heatoni commentedWith reference to #41 - the cookie_aware_page_cache module - I've now been using this for a little while to get around the commerce multi-currency caching issue for anonymous users and it seems to be a good solution since it caches and returns the correct variants of the page based on the selected currency cookie.
Getting it working involved adding the cookie "Drupal.visitor.commerce_currency" to the settings.php file as described in the documentation on the module page. I suspect there may be a problem with this when used with the APC cache, but don't know enough to say for sure - if you have problems getting it going, it might be worth playing with the other cache settings and remembering to clear the caches between changes.
You also need to test quite carefully as it's quite easy to convince yourself that it's working if the page you use to test with hasn't been opened before with the cookie set and isn't therefore in the cache - it could appear to work as it will return the right page, but if the page has been opened before and is cached with a different cookie setting you could potentially get the wrong one. (I hit this problem with a different home brew attempt to get around this issue, not the cookie_aware_page_cache, which has been working properly). If you're testing on your local dev environment, you'll need to check that it works with the same cache settings as the live environment too...
I hope that helps.
Comment #46
sergei_brill CreditAttribution: sergei_brill commentedI'm using the Cookie Aware Page Cache module on 2 sites for a few month. It works fine. Also there's a patch for the module which brings supports of Memcached. Looks like using the same way it is possible to add support of any cache backend.
Comment #47
Dr.Osd CreditAttribution: Dr.Osd commentedThis problem has haunted me for over a year and no one method does not work. What have I missed?
I tried to use Cookie Aware Page Cache on clear drupal installation, but no success. My settings.php have:
$conf['cache_backends'][] = 'sites/all/modules/cookie_aware_page_cache/CookieAwarePageCache.inc';
$conf['cache_class_cache_page'] = 'CookieAwarePageCache';
$conf['cookie_aware_page_cache_cookies'][] = 'Drupal.visitor.commerce_currency';
Comment #48
danielmrichards CreditAttribution: danielmrichards commentedI agree with the approach suggested in #36. IMO storing the selected currency in a session variable is a more practical solution than installing other contrib modules and/or creating custom page cache rules. Excluding product pages from being cached at all to enable the currency switcher to work is not a great solution especially for sites that experience heavy traffic.
Yes adding a session variable will disable page caching, but only for those users who select a currency and not use the site default. Provided your site is configured with the most popular currency as the default; performance impact should be minimal.
Attached is a patch along these lines.
Comment #49
seemas CreditAttribution: seemas at Adapt commentedI have made completely new solution that handles currency that is not default one using $_GET.
Possible to force it using "commerce_multicurrency_force_get" new variable:
Comment #50
seemas CreditAttribution: seemas at Adapt commentedA small fix that contains removing currency from url while user is logged in. This breaks Inline Form Editor ajax requests.
Comment #51
heatoni CreditAttribution: heatoni commentedI've just had another struggle with the cookie-aware page cache module to get it working again with Drupal Commerce Multicurrency after it apparently stopped working. I'm not sure why, but the name of the cookie appears differently to PHP within Drupal than it does to Firebug etc. If you use Firebug or Web Developer to see the name of the cookie that is set, it'll be "Drupal.visitor.commerce_currency", but if you stick var_dump($_COOKIE); in the PHP, you'll see that the web server sees the same cookie as "Drupal_visitor_commerce_currency". I don't know how, why or when it gets changed. It appears that it's just been Drupalled and I have had enough of my soul drained by this issue that I just don't want to know.
Anyway, if you're trying to get the cookie-aware page cache module to work with commerce multicurrency, try setting the name of the cookie in settings.php to "Drupal_visitor_commerce_currency" - note the underscores replacing the dots.
It's also worth noting that clearing the page cache doesn't work with the cookie-aware page cache module until you apply the patches mentioned at https://www.drupal.org/node/2730183.
Have a look at the contents of the cache_page table in MySQL if you want to make sure it's working. You should see the cid column showing the name and value of the cookie being prefixed to the page name so that a different cache record is held for each page and cookie combination that has been viewed which is exactly what we want.
Comment #52
Dr.Osd CreditAttribution: Dr.Osd commentedExcellent! Thanks Heatoni #51
Comment #53
AlfTheCat CreditAttribution: AlfTheCat commented@heatoni in #51,
Thank you! You totally nailed it!
Comment #54
iampumaHad the same issue with the currency switcher for anonymous users with page caching enabled, patch #48 works like a charm for me. Thanks.
Comment #55
romstach CreditAttribution: romstach commentedPatch in #48 is perfect.
Thank you
Comment #56
alancooney CreditAttribution: alancooney commentedFor those still struggling with this, I have attached some files:
- Cache_alter.patch to patch commerce kickstart
- Commerce_multicurrency_geo - Alters the cache by currency (adding |currency=XYZ to the cache id). It also automatically sets the correct currency using GeoLite2-City database (download it to libraries/geoip/GeoLite2-City.mmdb from http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz ) if it is downloaded there.
After installing, clear all caches and you're good to go.