Implement a different approach with the JS that allows for anonymous page caching and is faster.
I don't know exactly how this will be done. But I'm creating this to close out the other issues that relate to this so that we can start this conversation. I don't know if this will get fixed in the D7 version of this module, but I'm open to ideas.
| Comment | File | Size | Author |
|---|---|---|---|
| #21 | splash.d7.cache_patch.2.patch | 2.42 KB | Bastlynn |
| #11 | splash.d6.cache_patch.1.patch | 3.48 KB | Bastlynn |
| #9 | splashify.d7.cache_patch.1.patch | 1.46 KB | Bastlynn |
Comments
Comment #1
Bastlynn commentedWould switching hook_init() for hook_boot() fix it?Nevermind, tried it - undeclared function drupal_add_js() during boot.Comment #2
chrisroane commentedI've already looked into doing that. But because of the functions I need to access in hook_init() with how the php code is setup, it would cancel out any caching settingsn (since it has to use a bunch of functions for adding js and other things). I wish it was that easy.
Comment #3
Bastlynn commentedOk, this is going to sound Really silly. The problem is with Drupal (not Varnish's) caching turned on - then hook_init() never gets run, so Varnish never picks things up right? Hence the thought of hook_boot() if it had access to the functions then we'd be happy. Have I got my head wrapped around the problem correctly now?
The cache I was originally trying to work around was Varnish, the cache that's causing the problem as things stand is Drupal's own?
If so: hook_exit() ?
Comment #4
chrisroane commentedI haven't specifically worked with Varnish before, so I can't speak to that. But you are correct...when anonymous page caching is turned on in the drupal settings, hook_init() gets hit once before it is cached and then doesn't get hit again. So if you saw the splash page for the first time, it would always show up.
I got hook_boot() to work, but I needed to basically have the whole drupal stack load. That was the only way I could get it to work. And at that point, it would negate any kind of page caching on the site, which defeats the purpose. At that point it is better to say the module doesn't support anonymous page caching than pretend that it works fine with page caching on.
With that said, there may be ways around using hook_boot() that don't require the functions I am using in the hook_init() code. But I'm not sure right now.
Comment #5
Bastlynn commentedHm, I'm taking a further look into this. Hook_exit() and hook_footer() seem to be post page render, so we can't add more JS on those unless we use hook_footer to write our own JS.
I withdraw this idea, looks like by the time it gets to preprocess_page() the content and js is already rendered.Maybe use hook_theme_preprocess_page() to add the JS?
Otherwise, the prev thread mentioned using ajax, maybe write a settings js file whenever settings are updated and use ajax to pull those settings in?
Comment #6
Bastlynn commentedI did figure out how to get theme_preprocess to run, the page was cached with the output so splashify showed, but that didn't change anything. Since theme_preprocess isn't hidden by cache I think something else is going on.
I'm still really unclear why I'm seeing the behavior I'm seeing based on the cause you're describing. I'm still not getting why this doesn't work as expected under Drupal cache. Lemme explain:
Looking over the code in splash_init(), it gathers all the setting information - checks against the URL for URL specific settings and the splash=on/off value, then generates the correct who/what/when/where settings and passes them to JS settings. It does all this without taking input from the user - so the results of this process should be universal for all users.
Then the page gets cached, with those settings and the js that goes with splashify. All those js settings will now permanently be cached, but they're universal - should be ok. None of them are responsible for making a specific user see the flash based on their past experiences that's handled in js and js storage.
Then on page load, the splashify.js looks at the given settings and looks at the user's information in storage, *then* makes the decision to show the plash or not for this specific user. That's the decision point that matters for a single user and it's already in JS so it should be client side and safe from cache. I've confirmed that the JS does execute for every page load.
Wait... I think I may have found the problem. Tell me if this makes sense:
In hook_init(), PHP code sets js_nowtime = time(); and js_expiretime = time() + some value; Those values get passed in settings, and cached as any other js setting would. So based on this, under cache conditions, nowtimeSeconds will always be the first init time of the first visiting user, and js_expiretime based on the time given for that user. Neither the expire time, nor the nowtime update for any user display afterwards. So the behavior that user experiences is the behavior everyone sees, because as far as the script is concerned that's what time it is.
I think that's what's screwing this up. If so - then what we need to do is use the client side JS to figure out the now time and the expire time for this specific user, given a difference between the two that we pass in settings. I'm going to test this and see if it works. If so - then I'll get a patch to you.
Comment #7
Bastlynn commentedYep, looks like that was it. Removing the user information (time of arrival) from the hook_init calculations did it. Patch incoming shortly.
Comment #8
chrisroane commentedAh, interesting. It sounds like you have a good understanding of this. I'm kind of curious how you would solve this, if we are using both a client side time value in the JS and a server side time value (since timezones could be different). But it does sound promising.
I'm not too strong in JS, but if you have any ideas in how to make the JS fire sooner than before everything on the page loads, that would cover the other main issue with the JS. Basically we would want to fire the JS as soon as the Dom loads.
Comment #9
Bastlynn commentedTiming issues like this are something I've run into a lot. Caches and JS and other oddities are par for the course for me. Sorry for getting a little chattery on the thread but talking it out really helps me sort out issues like this. :)
Here's the patch for 7, I'm working on the one for 6 right now.
Comment #10
Bastlynn commentedRe: timezones, we actually don't have to worry about them at all. T
he timeframe for a user (daily, weekly, etc) is according to the user's own needs as a sliding window. Unless the computer is physically traveling time zones often and updating the timezone when it does - it won't be an issue: all time related math goes on the client side. It's a small enough edge case I feel comfortable saying the traveling user might not be surprised to see a splash page a little early.And I wasn't awake last night apparently, even better reason not to worry about timezone - the getDate() function in JS we're using gives milliseconds since epoch. So timezone neutral. TZ just isn't an issue here at all.
Comment #11
Bastlynn commentedAnd the D6 version, along with some minor tweaks the menu and permissions I needed to make to get this working on my dev site in 6. (Should be useful for the Backport thread too.)
Comment #12
Bastlynn commentedPutting this up to needs review, I think we'll be in shape for our site so I'll report any odd behaviors we encounter as well.
Comment #13
Bastlynn commentedAs for getting around the JS rule, we could do it by breaking the "law" of Drupal, but for a contrib module like this I'm not sure I would recommend it. The reason that the js loads when it does is because drupalBehaviors waits until doc.ready to kick everything off. Bheaviors also makes sure that js runs properly if there's an AHAH or AJAX (depending on the version) event on the page. Elsewise you can get some really odd trigger/retrigger style behaviors going on.
You could get around this by printing your JS outside of the drupal_add_js context, dropping it directly into output somehow on the page in the header, or immediately after the body tag. But seeign as how you can't predict the behavior of the page it'll be loaded on so you'll have the risk of odd AJAXy interactions and potential namespacing issues.... probably not a good idea to do it that way.
I'll see if drupal's JS has any fast-track location we can attach to instead of behaviors.
Comment #14
Bastlynn commentedEarly reports from my client site say: It works! :) With both Drupal caching and Varnish caching.
Comment #15
chrisroane commentedI applied the D7 patch to my local splashify site and confirmed that it is not working:
- If you have anonymous caching on, and go to the home page as an anonymous user, the splash page shows up. If you go to an interior page and then click the home link, the splash page shows up again. The splash should only show up when not coming from an internal link on the site. This is with the Always show splash option set.
- With the same settings above, except with the Once option selected....the splash page shows up over and over again.
This appears to have the same behavior as it did before the patch.
Comment #16
Bastlynn commentedDid you make sure to clear the cache? There's a JS change in this so if you've got the old JS in action that could muck with things.
Comment #17
chrisroane commentedYes, I cleared both browser and drupal cache and verified the new JS code is being loaded.
Looking at the PHP code and JS, for this to work with anonymous page caching...
- Right now in the hook_init() function, the code is generating the expiration date based on the PHP time() function and sending it to the JS with 'js_expire_after'. If we were to have this work in this case, wouldn't we have to do this time math in the JS instead?
I say this because the js_expire_after variable in the JS is what determines when to show the splash next. Does this sound right?
Comment #18
Bastlynn commentedRe: The internal URL issue, that may be something we need to move to the JS if it's not there. Basically anything that's dependent on the user's behavior (their storage settings, the time they arrived, the url they came from) needs to be in JS not in PHP.
Comment #19
Bastlynn commentedhook_init should run for the very first user, and it just returns the diff between the two which would remain stable across any further user interactions. The value being returned in js_expire_after isn't a timestamp, rather it's the number of seconds to add in JS to make the right expire timestamp.
Comment #20
chrisroane commentedAh, I understand now what you did. I cleared the cache again and this time it worked when having the Daily/Weekly....except it doesn't seem to reset if I clear my browser cache/cookies .
The only issue I can see is that when you have always selected, it displays the splash if you click an internal link back to the home page.
Comment #21
Bastlynn commentedTry this patch, I've moved the comparison of referrer to hostname into JS. I'm not sure what's up with the cookies - I didn't change anything that would have touched that, but I don't think jStorage uses cookies to store data.
Comment #22
chrisroane commentedAwesome! That patch fixed the problem. I want to do some more testing, including browser testing and if it looks good, I'll commit this and give ou credit. Thanks for your help on this. This is a major milestone.
Comment #23
Bastlynn commentedGreat! :) Since we're working on adapting this module to a live site, I'll get patches in for anything else as they come up. We're mostly D6, so I think I'll help with the backport next. :)
Comment #24
chrisroane commentedI verified that this worked and pushed everything to the dev branch. I gave you credit in the commit message, but when I pushed this change, I just did "git push" and forgot to use the full command. As a result, I don't see the commit message on the site...but I did verify the change is in the dev branch. I'm not sure if there is something else I need to do for everything to get added to the system?
One bug that I was able to replicate with page caching turned on was that if you are using multiple splash pages in the splashify settings, it caches the first page that comes up. I think this is the remaining but. If I get to it before you, I'll write some JS to get this working right and we should be set.
I noticed that with anonymous page caching turned on, it is very fast. So this partially fixes the speed issue I was concerned about.
Comment #25
chrisroane commentedn/m the commit issue. Last time I committed, the project splash page would update immediately. But it looks like this is not updated immediately, but I can see the commits in the log. I verified that I did give you credit for the code you added, so we should be good: http://drupalcode.org/project/splashify.git/shortlog/refs/heads/7.x-1.x
Comment #26
chrisroane commentedI updated the JS/PHP code so that the random option works with the new JS. I also found a bug with the sequential JS code in IE7 + IE8 that I fixed. I pushed this to the 7.x-1.x branch: http://drupalcode.org/project/splashify.git/commit/0545953bcf014bc0af622...
I'm very happy with where the code is at now. But I want to do more testing with other configuration options in Splashify to make sure we covered all cases. Once I go through this testing and verify everything is working, I'll make a new alpha5 tag and get this pushed.
I want to thank you again for spending the time in helping refactor the JS. I think this is a huge step forward!
Comment #27
chrisroane commentedI spent a lot of time testing and refactoring the JS code today. I improved the JS code in the following ways:
There was some strange things going on while using drupal behaviors. I understand why it would be useful with AJAX, but since the script only needs to be hit one time per page load, I thought it was overkill. I found out that I can access all of the drupal setting variables I set through the Drupal.settings variable without wrapping in the behavior/attach code....so that is what I did. This JS is hit sooner than the previous JS, since I no longer have to attach to the $(window).load() event. And I don't think this goes against drupal best practices....but correct me if I'm wrong.
I spent a lot of time trying to get the colorbox functionality to work correctly with the iframe option off. But the problem is that the JS is loaded again in the colorbox. So what happens is the colorbox loads multiple times (which slows things down). Having the iframe option on appears to set the referrer to the page that it is on, which prevents the JS from loading again.
The only thing I didn't spend a lot of time testing was the mobile options. But in any case, I think I am going to push this code to the next alpha release. Let me know if you have any thoughts to what I've done.
Comment #28
chrisroane commented